ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/cal.b/
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; i<m; i++)
d += mon[i];
d %= 7;
lines := array[6] of string;
l := 0;
s := "";
for(i = 0; i < d; i++)
s += " ";
for(i=1; i<=mon[m]; i++) {
if(i==3 && mon[m]==19) {
i += 11;
mon[m] += 11;
}
s += sys->sprint("%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;
}