xref: /plan9/sys/src/cmd/cal.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 char	dayw[] =
6 {
7 	" S  M Tu  W Th  F  S"
8 };
9 char	*smon[] =
10 {
11 	"January", "February", "March", "April",
12 	"May", "June", "July", "August",
13 	"September", "October", "November", "December",
14 };
15 char	mon[] =
16 {
17 	0,
18 	31, 29, 31, 30,
19 	31, 30, 31, 31,
20 	30, 31, 30, 31,
21 };
22 char	string[432];
23 Biobuf	bout;
24 
25 void	main(int argc, char *argv[]);
26 int	number(char *str);
27 void	pstr(char *str, int n);
28 void	cal(int m, int y, char *p, int w);
29 int	jan1(int yr);
30 int	curmo(void);
31 int	curyr(void);
32 
33 void
main(int argc,char * argv[])34 main(int argc, char *argv[])
35 {
36 	int y, i, j, m;
37 
38 	if(argc > 3) {
39 		fprint(2, "usage: cal [month] [year]\n");
40 		exits("usage");
41 	}
42 	Binit(&bout, 1, OWRITE);
43 
44 /*
45  * no arg, print current month
46  */
47 	if(argc == 1) {
48 		m = curmo();
49 		y = curyr();
50 		goto xshort;
51 	}
52 
53 /*
54  * one arg
55  *	if looks like a month, print month
56  *	else print year
57  */
58 	if(argc == 2) {
59 		y = number(argv[1]);
60 		if(y < 0)
61 			y = -y;
62 		if(y >= 1 && y <= 12) {
63 			m = y;
64 			y = curyr();
65 			goto xshort;
66 		}
67 		goto xlong;
68 	}
69 
70 /*
71  * two arg, month and year
72  */
73 	m = number(argv[1]);
74 	if(m < 0)
75 		m = -m;
76 	y = number(argv[2]);
77 	goto xshort;
78 
79 /*
80  *	print out just month
81  */
82 xshort:
83 	if(m < 1 || m > 12)
84 		goto badarg;
85 	if(y < 1 || y > 9999)
86 		goto badarg;
87 	Bprint(&bout, "   %s %ud\n", smon[m-1], y);
88 	Bprint(&bout, "%s\n", dayw);
89 	cal(m, y, string, 24);
90 	for(i=0; i<6*24; i+=24)
91 		pstr(string+i, 24);
92 	exits(0);
93 
94 /*
95  *	print out complete year
96  */
97 xlong:
98 	y = number(argv[1]);
99 	if(y<1 || y>9999)
100 		goto badarg;
101 	Bprint(&bout, "\n\n\n");
102 	Bprint(&bout, "                                %ud\n", y);
103 	Bprint(&bout, "\n");
104 	for(i=0; i<12; i+=3) {
105 		for(j=0; j<6*72; j++)
106 			string[j] = '\0';
107 		Bprint(&bout, "         %.3s", smon[i]);
108 		Bprint(&bout, "                    %.3s", smon[i+1]);
109 		Bprint(&bout, "                    %.3s\n", smon[i+2]);
110 		Bprint(&bout, "%s   %s   %s\n", dayw, dayw, dayw);
111 		cal(i+1, y, string, 72);
112 		cal(i+2, y, string+23, 72);
113 		cal(i+3, y, string+46, 72);
114 		for(j=0; j<6*72; j+=72)
115 			pstr(string+j, 72);
116 	}
117 	Bprint(&bout, "\n\n\n");
118 	exits(0);
119 
120 badarg:
121 	Bprint(&bout, "cal: bad argument\n");
122 }
123 
124 struct
125 {
126 	char*	word;
127 	int	val;
128 } dict[] =
129 {
130 	"jan",		1,
131 	"january",	1,
132 	"feb",		2,
133 	"february",	2,
134 	"mar",		3,
135 	"march",	3,
136 	"apr",		4,
137 	"april",	4,
138 	"may",		5,
139 	"jun",		6,
140 	"june",		6,
141 	"jul",		7,
142 	"july",		7,
143 	"aug",		8,
144 	"august",	8,
145 	"sep",		9,
146 	"sept",		9,
147 	"september",	9,
148 	"oct",		10,
149 	"october",	10,
150 	"nov",		11,
151 	"november",	11,
152 	"dec",		12,
153 	"december",	12,
154 	0
155 };
156 
157 /*
158  * convert to a number.
159  * if its a dictionary word,
160  * return negative  number
161  */
162 int
number(char * str)163 number(char *str)
164 {
165 	int n, c;
166 	char *s;
167 
168 	for(n=0; s=dict[n].word; n++)
169 		if(strcmp(s, str) == 0)
170 			return -dict[n].val;
171 	n = 0;
172 	s = str;
173 	while(c = *s++) {
174 		if(c<'0' || c>'9')
175 			return 0;
176 		n = n*10 + c-'0';
177 	}
178 	return n;
179 }
180 
181 void
pstr(char * str,int n)182 pstr(char *str, int n)
183 {
184 	int i;
185 	char *s;
186 
187 	s = str;
188 	i = n;
189 	while(i--)
190 		if(*s++ == '\0')
191 			s[-1] = ' ';
192 	i = n+1;
193 	while(i--)
194 		if(*--s != ' ')
195 			break;
196 	s[1] = '\0';
197 	Bprint(&bout, "%s\n", str);
198 }
199 
200 void
cal(int m,int y,char * p,int w)201 cal(int m, int y, char *p, int w)
202 {
203 	int d, i;
204 	char *s;
205 
206 	s = p;
207 	d = jan1(y);
208 	mon[2] = 29;
209 	mon[9] = 30;
210 
211 	switch((jan1(y+1)+7-d)%7) {
212 
213 	/*
214 	 *	non-leap year
215 	 */
216 	case 1:
217 		mon[2] = 28;
218 		break;
219 
220 	/*
221 	 *	1752
222 	 */
223 	default:
224 		mon[9] = 19;
225 		break;
226 
227 	/*
228 	 *	leap year
229 	 */
230 	case 2:
231 		;
232 	}
233 	for(i=1; i<m; i++)
234 		d += mon[i];
235 	d %= 7;
236 	s += 3*d;
237 	for(i=1; i<=mon[m]; i++) {
238 		if(i==3 && mon[m]==19) {
239 			i += 11;
240 			mon[m] += 11;
241 		}
242 		if(i > 9)
243 			*s = i/10+'0';
244 		s++;
245 		*s++ = i%10+'0';
246 		s++;
247 		if(++d == 7) {
248 			d = 0;
249 			s = p+w;
250 			p = s;
251 		}
252 	}
253 }
254 
255 /*
256  *	return day of the week
257  *	of jan 1 of given year
258  */
259 int
jan1(int yr)260 jan1(int yr)
261 {
262 	int y, d;
263 
264 /*
265  *	normal gregorian calendar
266  *	one extra day per four years
267  */
268 
269 	y = yr;
270 	d = 4+y+(y+3)/4;
271 
272 /*
273  *	julian calendar
274  *	regular gregorian
275  *	less three days per 400
276  */
277 
278 	if(y > 1800) {
279 		d -= (y-1701)/100;
280 		d += (y-1601)/400;
281 	}
282 
283 /*
284  *	great calendar changeover instant
285  */
286 
287 	if(y > 1752)
288 		d += 3;
289 
290 	return d%7;
291 }
292 
293 /*
294  * system dependent
295  * get current month and year
296  */
297 int
curmo(void)298 curmo(void)
299 {
300 	Tm *tm;
301 
302 	tm = localtime(time(0));
303 	return tm->mon+1;
304 }
305 
306 int
curyr(void)307 curyr(void)
308 {
309 	Tm *tm;
310 
311 	tm = localtime(time(0));
312 	return tm->year+1900;
313 }
314