implement Cal; # # Copyright © 1995-2002 Lucent Technologies Inc. All rights reserved. # Limbo transliteration 2003 by Vita Nuova # This software is subject to the Plan 9 Open Source Licence. # include "sys.m"; sys: Sys; include "draw.m"; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "daytime.m"; daytime: Daytime; Tm: import daytime; Cal: module { init: fn(nil: ref Draw->Context, nil: list of string); }; dayw := " S M Tu W Th F S"; smon := array[] of { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; mon := array[] of { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, }; bout: ref Iobuf; init(nil: ref Draw->Context, args: list of string) { y, m: int; sys = load Sys Sys->PATH; bufio = load Bufio Bufio->PATH; daytime = load Daytime Daytime->PATH; argc := len args; if(argc > 3){ sys->fprint(sys->fildes(2), "usage: cal [month] [year]\n"); raise "fail:usage"; } bout = bufio->fopen(sys->fildes(1), Bufio->OWRITE); # # no arg, print current month # if(argc <= 1) { m = curmo(); y = curyr(); return xshort(m, y); } args = tl args; # # one arg # if looks like a month, print month # else print year # if(argc == 2) { y = number(hd args); if(y < 0) y = -y; if(y >= 1 && y <= 12) return xshort(y, curyr()); return xlong(y); } # # two arg, month and year # m = number(hd args); if(m < 0) m = -m; y = number(hd tl args); return xshort(m, y); } # # print out just month # xshort(m: int, y: int) { if(m < 1 || m > 12) badarg(); if(y < 1 || y > 9999) badarg(); bout.puts(sys->sprint(" %s %ud\n", smon[m-1], y)); bout.puts(sys->sprint("%s\n", dayw)); lines := cal(m, y); for(i := 0; i < len lines; i++){ bout.puts(lines[i]); bout.putc('\n'); } bout.flush(); } # # print out complete year # xlong(y: int) { if(y<1 || y>9999) badarg(); bout.puts("\n\n\n"); bout.puts(sys->sprint(" %ud\n", y)); bout.putc('\n'); months := array[3] of array of string; for(i:=0; i<12; i+=3) { bout.puts(sys->sprint(" %.3s", smon[i])); bout.puts(sys->sprint(" %.3s", smon[i+1])); bout.puts(sys->sprint(" %.3s\n", smon[i+2])); bout.puts(sys->sprint("%s %s %s\n", dayw, dayw, dayw)); for(j := 0; j < 3; j++) months[j] = cal(i+j+1, y); for(l := 0; l < 6; l++){ s := ""; for(j = 0; j < 3; j++) s += sys->sprint("%-20.20s ", months[j][l]); for(j = len s; j > 0 && s[j-1] == ' ';) j--; bout.puts(s[0:j]); bout.putc('\n'); } } bout.flush(); } badarg() { sys->fprint(sys->fildes(2), "cal: bad argument\n"); raise "fail:bad argument"; } dict := array[] of { ("january", 1), ("february", 2), ("march", 3), ("april", 4), ("may", 5), ("june", 6), ("july", 7), ("august", 8), ("sept", 9), ("september", 9), ("october", 10), ("november", 11), ("december", 12), }; # # convert to a number. # if its a dictionary word, # return negative number # number(s: string): int { if(len s >= 3){ for(n:=0; n < len dict; n++){ (word, val) := dict[n]; if(s == word || s == word[0:3]) return -val; } } n := 0; for(i := 0; i < len s; i++){ c := s[i]; if(c<'0' || c>'9') badarg(); n = n*10 + c-'0'; } return n; } pstr(str: string, n: int) { bout.puts(sys->sprint("%-*.*s\n", n, n, str)); } cal(m: int, y: int): array of string { d := jan1(y); mon[9] = 30; case (jan1(y+1)+7-d)%7 { # # non-leap year # 1 => mon[2] = 28; # # leap year # 2 => mon[2] = 29; # # 1752 # * => mon[2] = 29; mon[9] = 19; } for(i:=1; isprint("%2d", i); if(++d == 7) { d = 0; lines[l++] = s; s = ""; }else s[len s] = ' '; } if(s != nil){ while(s[len s-1] == ' ') s = s[:len s-1]; lines[l] = s; } return lines; } # # return day of the week # of jan 1 of given year # jan1(y: int): int { # # normal gregorian calendar # one extra day per four years # d := 4+y+(y+3)/4; # # julian calendar # regular gregorian # less three days per 400 # if(y > 1800) { d -= (y-1701)/100; d += (y-1601)/400; } # # great calendar changeover instant # if(y > 1752) d += 3; return d%7; } # # get current month and year # curmo(): int { tm := daytime->local(daytime->now()); return tm.mon+1; } curyr(): int { tm := daytime->local(daytime->now()); return tm.year+1900; }