xref: /plan9/sys/src/cmd/cal.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier char	dayw[] =
63e12c5d1SDavid du Colombier {
73e12c5d1SDavid du Colombier 	" S  M Tu  W Th  F  S"
83e12c5d1SDavid du Colombier };
93e12c5d1SDavid du Colombier char	*smon[] =
103e12c5d1SDavid du Colombier {
113e12c5d1SDavid du Colombier 	"January", "February", "March", "April",
123e12c5d1SDavid du Colombier 	"May", "June", "July", "August",
133e12c5d1SDavid du Colombier 	"September", "October", "November", "December",
143e12c5d1SDavid du Colombier };
153e12c5d1SDavid du Colombier char	mon[] =
163e12c5d1SDavid du Colombier {
173e12c5d1SDavid du Colombier 	0,
183e12c5d1SDavid du Colombier 	31, 29, 31, 30,
193e12c5d1SDavid du Colombier 	31, 30, 31, 31,
203e12c5d1SDavid du Colombier 	30, 31, 30, 31,
213e12c5d1SDavid du Colombier };
223e12c5d1SDavid du Colombier char	string[432];
233e12c5d1SDavid du Colombier Biobuf	bout;
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier void	main(int argc, char *argv[]);
263e12c5d1SDavid du Colombier int	number(char *str);
273e12c5d1SDavid du Colombier void	pstr(char *str, int n);
283e12c5d1SDavid du Colombier void	cal(int m, int y, char *p, int w);
293e12c5d1SDavid du Colombier int	jan1(int yr);
303e12c5d1SDavid du Colombier int	curmo(void);
313e12c5d1SDavid du Colombier int	curyr(void);
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier void
main(int argc,char * argv[])343e12c5d1SDavid du Colombier main(int argc, char *argv[])
353e12c5d1SDavid du Colombier {
363e12c5d1SDavid du Colombier 	int y, i, j, m;
373e12c5d1SDavid du Colombier 
383e12c5d1SDavid du Colombier 	if(argc > 3) {
393e12c5d1SDavid du Colombier 		fprint(2, "usage: cal [month] [year]\n");
403e12c5d1SDavid du Colombier 		exits("usage");
413e12c5d1SDavid du Colombier 	}
423e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier /*
453e12c5d1SDavid du Colombier  * no arg, print current month
463e12c5d1SDavid du Colombier  */
473e12c5d1SDavid du Colombier 	if(argc == 1) {
483e12c5d1SDavid du Colombier 		m = curmo();
493e12c5d1SDavid du Colombier 		y = curyr();
503e12c5d1SDavid du Colombier 		goto xshort;
513e12c5d1SDavid du Colombier 	}
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier /*
543e12c5d1SDavid du Colombier  * one arg
553e12c5d1SDavid du Colombier  *	if looks like a month, print month
563e12c5d1SDavid du Colombier  *	else print year
573e12c5d1SDavid du Colombier  */
583e12c5d1SDavid du Colombier 	if(argc == 2) {
593e12c5d1SDavid du Colombier 		y = number(argv[1]);
603e12c5d1SDavid du Colombier 		if(y < 0)
613e12c5d1SDavid du Colombier 			y = -y;
623e12c5d1SDavid du Colombier 		if(y >= 1 && y <= 12) {
633e12c5d1SDavid du Colombier 			m = y;
643e12c5d1SDavid du Colombier 			y = curyr();
653e12c5d1SDavid du Colombier 			goto xshort;
663e12c5d1SDavid du Colombier 		}
673e12c5d1SDavid du Colombier 		goto xlong;
683e12c5d1SDavid du Colombier 	}
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier /*
713e12c5d1SDavid du Colombier  * two arg, month and year
723e12c5d1SDavid du Colombier  */
733e12c5d1SDavid du Colombier 	m = number(argv[1]);
743e12c5d1SDavid du Colombier 	if(m < 0)
753e12c5d1SDavid du Colombier 		m = -m;
763e12c5d1SDavid du Colombier 	y = number(argv[2]);
773e12c5d1SDavid du Colombier 	goto xshort;
783e12c5d1SDavid du Colombier 
793e12c5d1SDavid du Colombier /*
803e12c5d1SDavid du Colombier  *	print out just month
813e12c5d1SDavid du Colombier  */
823e12c5d1SDavid du Colombier xshort:
833e12c5d1SDavid du Colombier 	if(m < 1 || m > 12)
843e12c5d1SDavid du Colombier 		goto badarg;
853e12c5d1SDavid du Colombier 	if(y < 1 || y > 9999)
863e12c5d1SDavid du Colombier 		goto badarg;
873e12c5d1SDavid du Colombier 	Bprint(&bout, "   %s %ud\n", smon[m-1], y);
883e12c5d1SDavid du Colombier 	Bprint(&bout, "%s\n", dayw);
893e12c5d1SDavid du Colombier 	cal(m, y, string, 24);
903e12c5d1SDavid du Colombier 	for(i=0; i<6*24; i+=24)
913e12c5d1SDavid du Colombier 		pstr(string+i, 24);
923e12c5d1SDavid du Colombier 	exits(0);
933e12c5d1SDavid du Colombier 
943e12c5d1SDavid du Colombier /*
953e12c5d1SDavid du Colombier  *	print out complete year
963e12c5d1SDavid du Colombier  */
973e12c5d1SDavid du Colombier xlong:
983e12c5d1SDavid du Colombier 	y = number(argv[1]);
993e12c5d1SDavid du Colombier 	if(y<1 || y>9999)
1003e12c5d1SDavid du Colombier 		goto badarg;
1013e12c5d1SDavid du Colombier 	Bprint(&bout, "\n\n\n");
1023e12c5d1SDavid du Colombier 	Bprint(&bout, "                                %ud\n", y);
1033e12c5d1SDavid du Colombier 	Bprint(&bout, "\n");
1043e12c5d1SDavid du Colombier 	for(i=0; i<12; i+=3) {
1053e12c5d1SDavid du Colombier 		for(j=0; j<6*72; j++)
1063e12c5d1SDavid du Colombier 			string[j] = '\0';
1073e12c5d1SDavid du Colombier 		Bprint(&bout, "         %.3s", smon[i]);
1083e12c5d1SDavid du Colombier 		Bprint(&bout, "                    %.3s", smon[i+1]);
1093e12c5d1SDavid du Colombier 		Bprint(&bout, "                    %.3s\n", smon[i+2]);
1103e12c5d1SDavid du Colombier 		Bprint(&bout, "%s   %s   %s\n", dayw, dayw, dayw);
1113e12c5d1SDavid du Colombier 		cal(i+1, y, string, 72);
1123e12c5d1SDavid du Colombier 		cal(i+2, y, string+23, 72);
1133e12c5d1SDavid du Colombier 		cal(i+3, y, string+46, 72);
1143e12c5d1SDavid du Colombier 		for(j=0; j<6*72; j+=72)
1153e12c5d1SDavid du Colombier 			pstr(string+j, 72);
1163e12c5d1SDavid du Colombier 	}
1173e12c5d1SDavid du Colombier 	Bprint(&bout, "\n\n\n");
1183e12c5d1SDavid du Colombier 	exits(0);
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier badarg:
1213e12c5d1SDavid du Colombier 	Bprint(&bout, "cal: bad argument\n");
1223e12c5d1SDavid du Colombier }
1233e12c5d1SDavid du Colombier 
1243e12c5d1SDavid du Colombier struct
1253e12c5d1SDavid du Colombier {
1263e12c5d1SDavid du Colombier 	char*	word;
1273e12c5d1SDavid du Colombier 	int	val;
1283e12c5d1SDavid du Colombier } dict[] =
1293e12c5d1SDavid du Colombier {
1303e12c5d1SDavid du Colombier 	"jan",		1,
1313e12c5d1SDavid du Colombier 	"january",	1,
1323e12c5d1SDavid du Colombier 	"feb",		2,
133*7dd7cddfSDavid du Colombier 	"february",	2,
1343e12c5d1SDavid du Colombier 	"mar",		3,
1353e12c5d1SDavid du Colombier 	"march",	3,
1363e12c5d1SDavid du Colombier 	"apr",		4,
1373e12c5d1SDavid du Colombier 	"april",	4,
1383e12c5d1SDavid du Colombier 	"may",		5,
1393e12c5d1SDavid du Colombier 	"jun",		6,
1403e12c5d1SDavid du Colombier 	"june",		6,
1413e12c5d1SDavid du Colombier 	"jul",		7,
1423e12c5d1SDavid du Colombier 	"july",		7,
1433e12c5d1SDavid du Colombier 	"aug",		8,
1443e12c5d1SDavid du Colombier 	"august",	8,
1453e12c5d1SDavid du Colombier 	"sep",		9,
1463e12c5d1SDavid du Colombier 	"sept",		9,
1473e12c5d1SDavid du Colombier 	"september",	9,
1483e12c5d1SDavid du Colombier 	"oct",		10,
1493e12c5d1SDavid du Colombier 	"october",	10,
1503e12c5d1SDavid du Colombier 	"nov",		11,
1513e12c5d1SDavid du Colombier 	"november",	11,
1523e12c5d1SDavid du Colombier 	"dec",		12,
1533e12c5d1SDavid du Colombier 	"december",	12,
1543e12c5d1SDavid du Colombier 	0
1553e12c5d1SDavid du Colombier };
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier /*
1583e12c5d1SDavid du Colombier  * convert to a number.
1593e12c5d1SDavid du Colombier  * if its a dictionary word,
1603e12c5d1SDavid du Colombier  * return negative  number
1613e12c5d1SDavid du Colombier  */
1623e12c5d1SDavid du Colombier int
number(char * str)1633e12c5d1SDavid du Colombier number(char *str)
1643e12c5d1SDavid du Colombier {
1653e12c5d1SDavid du Colombier 	int n, c;
1663e12c5d1SDavid du Colombier 	char *s;
1673e12c5d1SDavid du Colombier 
1683e12c5d1SDavid du Colombier 	for(n=0; s=dict[n].word; n++)
1693e12c5d1SDavid du Colombier 		if(strcmp(s, str) == 0)
1703e12c5d1SDavid du Colombier 			return -dict[n].val;
1713e12c5d1SDavid du Colombier 	n = 0;
1723e12c5d1SDavid du Colombier 	s = str;
1733e12c5d1SDavid du Colombier 	while(c = *s++) {
1743e12c5d1SDavid du Colombier 		if(c<'0' || c>'9')
1753e12c5d1SDavid du Colombier 			return 0;
1763e12c5d1SDavid du Colombier 		n = n*10 + c-'0';
1773e12c5d1SDavid du Colombier 	}
1783e12c5d1SDavid du Colombier 	return n;
1793e12c5d1SDavid du Colombier }
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier void
pstr(char * str,int n)1823e12c5d1SDavid du Colombier pstr(char *str, int n)
1833e12c5d1SDavid du Colombier {
1843e12c5d1SDavid du Colombier 	int i;
1853e12c5d1SDavid du Colombier 	char *s;
1863e12c5d1SDavid du Colombier 
1873e12c5d1SDavid du Colombier 	s = str;
1883e12c5d1SDavid du Colombier 	i = n;
1893e12c5d1SDavid du Colombier 	while(i--)
1903e12c5d1SDavid du Colombier 		if(*s++ == '\0')
1913e12c5d1SDavid du Colombier 			s[-1] = ' ';
1923e12c5d1SDavid du Colombier 	i = n+1;
1933e12c5d1SDavid du Colombier 	while(i--)
1943e12c5d1SDavid du Colombier 		if(*--s != ' ')
1953e12c5d1SDavid du Colombier 			break;
1963e12c5d1SDavid du Colombier 	s[1] = '\0';
1973e12c5d1SDavid du Colombier 	Bprint(&bout, "%s\n", str);
1983e12c5d1SDavid du Colombier }
1993e12c5d1SDavid du Colombier 
2003e12c5d1SDavid du Colombier void
cal(int m,int y,char * p,int w)2013e12c5d1SDavid du Colombier cal(int m, int y, char *p, int w)
2023e12c5d1SDavid du Colombier {
2033e12c5d1SDavid du Colombier 	int d, i;
2043e12c5d1SDavid du Colombier 	char *s;
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier 	s = p;
2073e12c5d1SDavid du Colombier 	d = jan1(y);
2083e12c5d1SDavid du Colombier 	mon[2] = 29;
2093e12c5d1SDavid du Colombier 	mon[9] = 30;
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier 	switch((jan1(y+1)+7-d)%7) {
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier 	/*
2143e12c5d1SDavid du Colombier 	 *	non-leap year
2153e12c5d1SDavid du Colombier 	 */
2163e12c5d1SDavid du Colombier 	case 1:
2173e12c5d1SDavid du Colombier 		mon[2] = 28;
2183e12c5d1SDavid du Colombier 		break;
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	/*
2213e12c5d1SDavid du Colombier 	 *	1752
2223e12c5d1SDavid du Colombier 	 */
2233e12c5d1SDavid du Colombier 	default:
2243e12c5d1SDavid du Colombier 		mon[9] = 19;
2253e12c5d1SDavid du Colombier 		break;
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier 	/*
2283e12c5d1SDavid du Colombier 	 *	leap year
2293e12c5d1SDavid du Colombier 	 */
2303e12c5d1SDavid du Colombier 	case 2:
2313e12c5d1SDavid du Colombier 		;
2323e12c5d1SDavid du Colombier 	}
2333e12c5d1SDavid du Colombier 	for(i=1; i<m; i++)
2343e12c5d1SDavid du Colombier 		d += mon[i];
2353e12c5d1SDavid du Colombier 	d %= 7;
2363e12c5d1SDavid du Colombier 	s += 3*d;
2373e12c5d1SDavid du Colombier 	for(i=1; i<=mon[m]; i++) {
2383e12c5d1SDavid du Colombier 		if(i==3 && mon[m]==19) {
2393e12c5d1SDavid du Colombier 			i += 11;
2403e12c5d1SDavid du Colombier 			mon[m] += 11;
2413e12c5d1SDavid du Colombier 		}
2423e12c5d1SDavid du Colombier 		if(i > 9)
2433e12c5d1SDavid du Colombier 			*s = i/10+'0';
2443e12c5d1SDavid du Colombier 		s++;
2453e12c5d1SDavid du Colombier 		*s++ = i%10+'0';
2463e12c5d1SDavid du Colombier 		s++;
2473e12c5d1SDavid du Colombier 		if(++d == 7) {
2483e12c5d1SDavid du Colombier 			d = 0;
2493e12c5d1SDavid du Colombier 			s = p+w;
2503e12c5d1SDavid du Colombier 			p = s;
2513e12c5d1SDavid du Colombier 		}
2523e12c5d1SDavid du Colombier 	}
2533e12c5d1SDavid du Colombier }
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier /*
2563e12c5d1SDavid du Colombier  *	return day of the week
2573e12c5d1SDavid du Colombier  *	of jan 1 of given year
2583e12c5d1SDavid du Colombier  */
2593e12c5d1SDavid du Colombier int
jan1(int yr)2603e12c5d1SDavid du Colombier jan1(int yr)
2613e12c5d1SDavid du Colombier {
2623e12c5d1SDavid du Colombier 	int y, d;
2633e12c5d1SDavid du Colombier 
2643e12c5d1SDavid du Colombier /*
2653e12c5d1SDavid du Colombier  *	normal gregorian calendar
2663e12c5d1SDavid du Colombier  *	one extra day per four years
2673e12c5d1SDavid du Colombier  */
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier 	y = yr;
2703e12c5d1SDavid du Colombier 	d = 4+y+(y+3)/4;
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier /*
2733e12c5d1SDavid du Colombier  *	julian calendar
2743e12c5d1SDavid du Colombier  *	regular gregorian
2753e12c5d1SDavid du Colombier  *	less three days per 400
2763e12c5d1SDavid du Colombier  */
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier 	if(y > 1800) {
2793e12c5d1SDavid du Colombier 		d -= (y-1701)/100;
2803e12c5d1SDavid du Colombier 		d += (y-1601)/400;
2813e12c5d1SDavid du Colombier 	}
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier /*
2843e12c5d1SDavid du Colombier  *	great calendar changeover instant
2853e12c5d1SDavid du Colombier  */
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier 	if(y > 1752)
2883e12c5d1SDavid du Colombier 		d += 3;
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier 	return d%7;
2913e12c5d1SDavid du Colombier }
2923e12c5d1SDavid du Colombier 
2933e12c5d1SDavid du Colombier /*
2943e12c5d1SDavid du Colombier  * system dependent
2953e12c5d1SDavid du Colombier  * get current month and year
2963e12c5d1SDavid du Colombier  */
2973e12c5d1SDavid du Colombier int
curmo(void)2983e12c5d1SDavid du Colombier curmo(void)
2993e12c5d1SDavid du Colombier {
3003e12c5d1SDavid du Colombier 	Tm *tm;
3013e12c5d1SDavid du Colombier 
3023e12c5d1SDavid du Colombier 	tm = localtime(time(0));
3033e12c5d1SDavid du Colombier 	return tm->mon+1;
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier int
curyr(void)3073e12c5d1SDavid du Colombier curyr(void)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	Tm *tm;
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 	tm = localtime(time(0));
3123e12c5d1SDavid du Colombier 	return tm->year+1900;
3133e12c5d1SDavid du Colombier }
314