RosettaCodeData/Task/Calendar/OCaml/calendar.ocaml

197 lines
4.0 KiB
Plaintext

#load "unix.cma"
let lang = "en" (* language: English *)
let usage () =
Printf.printf "Usage:\n%s\n" Sys.argv.(0)
let month_pattern =
[
[ 0; 4; 8 ];
[ 1; 5; 9 ];
[ 2; 6; 10 ];
[ 3; 7; 11 ];
(*
[ 0; 1; 2; 3; 4; 5 ];
[ 6; 7; 8; 9; 10; 11 ];
[ 0; 1; 2; 3 ];
[ 4; 5; 6; 7 ];
[ 8; 9; 10; 11 ];
*)
]
let month_langs = [
"en", [|
"January"; "February"; "March"; "April";
"May"; "June"; "July"; "August"; "September";
"October"; "November"; "December";
|];
"fr", [|
"janvier"; "février"; "mars"; "avril"; "mai";
"juin"; "juillet"; "août"; "septembre";
"octobre"; "novembre"; "décembre";
|];
]
let days_lang = [
"en", [| "Monday"; "Tuesday"; "Wednesday";
"Thursday"; "Friday"; "Saturday"; "Sunday" |];
"fr", [| "lundi"; "mardi"; "mercredi";
"jeudi"; "vendredi"; "samedi"; "dimanche" |];
]
let titles_lang = [
"en", "( Snoopy's best pic )";
"fr", "( Le meilleur profil de Snoopy )";
]
let days = List.assoc lang days_lang
let month = List.assoc lang month_langs
let title = List.assoc lang titles_lang
let monday_first = 6, [| 0; 1; 2; 3; 4; 5; 6 |]
let sunday_first = 0, [| 6; 0; 1; 2; 3; 4; 5 |]
let off, days_order = sunday_first
let off, days_order = monday_first
let shorten n s =
let len = String.length s in
if n >= len then s else
let n = if s.[n-1] = '\xC3' then n+1 else n in
if n >= len then s else
(String.sub s 0 n)
let pad size c s =
let len = String.length s in
let n1 = (size - len) / 2 in
let n2 = size - len - n1 in
String.make n1 c ^ s ^
String.make n2 c
let days = Array.map (shorten 2) days
let indices ofs =
(ofs / 7, ofs mod 7)
let t_same t1 t2 =
( t1.Unix.tm_year = t2.Unix.tm_year &&
t1.Unix.tm_mon = t2.Unix.tm_mon &&
t1.Unix.tm_mday = t2.Unix.tm_mday )
let current_year () =
let t = Unix.localtime (Unix.time ()) in
(t.Unix.tm_year + 1900)
let make_month t year month =
let empty_day = 0 in
let m = Array.make_matrix 6 7 empty_day in
let ofs = ref 0 in
for day = 1 to 31 do
let tm =
{ t with
Unix.tm_year = year - 1900;
Unix.tm_mon = month;
Unix.tm_mday = day;
}
in
let _, this = Unix.mktime tm in
if !ofs = 0 then ofs := (this.Unix.tm_wday + off) mod 7;
if t_same this tm then
let i, j = indices !ofs in
m.(i).(j) <- day;
incr ofs;
done;
(m)
let cal ~year =
let empty = [| [| |] |] in
let months = Array.make 12 empty in
let t = Unix.gmtime 0.0 in
for mon = 0 to 11 do
months.(mon) <- make_month t year mon;
done;
(months)
let print_month_label mp =
List.iter (fun i ->
let mon = pad 20 ' ' month.(i) in
Printf.printf " %s " mon
) mp;
print_newline ()
let print_day_label mp =
List.iter (fun _ ->
Array.iter (fun i ->
Printf.printf " %s" days.(i)
) days_order
; print_string " "
) mp;
print_newline ()
let print_mon m mp =
print_month_label mp;
print_day_label mp;
for w = 0 to pred 6 do
print_string begin
String.concat " " begin
List.map (fun i ->
let b = Buffer.create 132 in
for d = 0 to pred 7 do
match m.(i).(w).(d) with
| 0 -> Buffer.add_string b " "
| d -> Printf.kprintf (Buffer.add_string b) " %2d" d
done;
(Buffer.contents b)
) mp
end
end
; print_string "\n"
done
let print_cal ~y:m =
List.iter (fun mon_row ->
print_mon m mon_row
) month_pattern
let print_header lbl =
let n = List.length (List.hd month_pattern) in
let year_lbl = pad (23*n-7) ' ' lbl in
Printf.printf " %s\n" year_lbl
let print_calendar ~year =
print_header title;
print_header (string_of_int year);
print_cal (cal ~year)
let () =
let args = List.tl (Array.to_list Sys.argv) in
match args with
| [] ->
let year = current_year () in
print_calendar ~year
| ["--year"; _year] ->
let year = int_of_string _year in
print_calendar ~year
| _ ->
usage ()