xref: /original-bsd/usr.bin/cal/cal.c (revision b5f15b9d)
1ed8e7804Sbostic /*
2*b5f15b9dSpendry  * Copyright (c) 1989, 1993, 1994
3a576e1b7Sbostic  *	The Regents of the University of California.  All rights reserved.
4ed8e7804Sbostic  *
5ed8e7804Sbostic  * This code is derived from software contributed to Berkeley by
6ed8e7804Sbostic  * Kim Letkeman.
7ed8e7804Sbostic  *
80a10ec2cSbostic  * %sccs.include.redist.c%
9ed8e7804Sbostic  */
10ed8e7804Sbostic 
11ced7fbbfSsam #ifndef lint
12a576e1b7Sbostic static char copyright[] =
13*b5f15b9dSpendry "@(#) Copyright (c) 1989, 1993, 1994\n\
14a576e1b7Sbostic 	The Regents of the University of California.  All rights reserved.\n";
15ed8e7804Sbostic #endif /* not lint */
16ed8e7804Sbostic 
17ed8e7804Sbostic #ifndef lint
18*b5f15b9dSpendry static char sccsid[] = "@(#)cal.c	8.4 (Berkeley) 04/02/94";
19ed8e7804Sbostic #endif /* not lint */
20ced7fbbfSsam 
2112b68e8bSsam #include <sys/types.h>
226ffb1990Spendry 
23ed8e7804Sbostic #include <ctype.h>
246ffb1990Spendry #include <err.h>
256ffb1990Spendry #include <stdio.h>
266ffb1990Spendry #include <stdlib.h>
276ffb1990Spendry #include <string.h>
286ffb1990Spendry #include <time.h>
296ffb1990Spendry #include <unistd.h>
3012b68e8bSsam 
31ed8e7804Sbostic #define	THURSDAY		4		/* for reformation */
32ed8e7804Sbostic #define	SATURDAY 		6		/* 1 Jan 1 was a Saturday */
33de432eacSbostic 
34ed8e7804Sbostic #define	FIRST_MISSING_DAY 	639787		/* 3 Sep 1752 */
35ed8e7804Sbostic #define	NUMBER_MISSING_DAYS 	11		/* 11 day correction */
36de432eacSbostic 
37de432eacSbostic #define	MAXDAYS			42		/* max slots in a month array */
38ad703e26Sbostic #define	SPACE			-1		/* used in day array */
39ed8e7804Sbostic 
40ed8e7804Sbostic static int days_in_month[2][13] = {
41ed8e7804Sbostic 	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
42ed8e7804Sbostic 	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
43dc686bb6Swnj };
44ed8e7804Sbostic 
45de432eacSbostic int sep1752[MAXDAYS] = {
46ed8e7804Sbostic 	SPACE,	SPACE,	1,	2,	14,	15,	16,
47ed8e7804Sbostic 	17,	18,	19,	20,	21,	22,	23,
48ed8e7804Sbostic 	24,	25,	26,	27,	28,	29,	30,
49ed8e7804Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
50ed8e7804Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
51ed8e7804Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
52de432eacSbostic }, j_sep1752[MAXDAYS] = {
53ad703e26Sbostic 	SPACE,	SPACE,	245,	246,	258,	259,	260,
54ad703e26Sbostic 	261,	262,	263,	264,	265,	266,	267,
55ad703e26Sbostic 	268,	269,	270,	271,	272,	273,	274,
56ad703e26Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
57ad703e26Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
58ad703e26Sbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
59de432eacSbostic }, empty[MAXDAYS] = {
60de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
61de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
62de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
63de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
64de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
65de432eacSbostic 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
66dc686bb6Swnj };
67ed8e7804Sbostic 
68de432eacSbostic char *month_names[12] = {
69ed8e7804Sbostic 	"January", "February", "March", "April", "May", "June",
70ed8e7804Sbostic 	"July", "August", "September", "October", "November", "December",
71ed8e7804Sbostic };
72ed8e7804Sbostic 
73de432eacSbostic char *day_headings = " S  M Tu  W Th  F  S";
74de432eacSbostic char *j_day_headings = "  S   M  Tu   W  Th   F   S";
75ed8e7804Sbostic 
76ed8e7804Sbostic /* leap year -- account for gregorian reformation in 1752 */
77ed8e7804Sbostic #define	leap_year(yr) \
78ed8e7804Sbostic 	((yr) <= 1752 ? !((yr) % 4) : \
79ed8e7804Sbostic 	!((yr) % 4) && ((yr) % 100) || !((yr) % 400))
80ed8e7804Sbostic 
81ed8e7804Sbostic /* number of centuries since 1700, not inclusive */
82ed8e7804Sbostic #define	centuries_since_1700(yr) \
83ed8e7804Sbostic 	((yr) > 1700 ? (yr) / 100 - 17 : 0)
84ed8e7804Sbostic 
85ed8e7804Sbostic /* number of centuries since 1700 whose modulo of 400 is 0 */
86ed8e7804Sbostic #define	quad_centuries_since_1700(yr) \
87ed8e7804Sbostic 	((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
88ed8e7804Sbostic 
89ed8e7804Sbostic /* number of leap years between year 1 and this year, not inclusive */
90ed8e7804Sbostic #define	leap_years_since_year_1(yr) \
91ed8e7804Sbostic 	((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
92ed8e7804Sbostic 
93ad703e26Sbostic int julian;
94ad703e26Sbostic 
956ffb1990Spendry void	ascii_day __P((char *, int));
966ffb1990Spendry void	center __P((char *, int, int));
976ffb1990Spendry void	day_array __P((int, int, int *));
986ffb1990Spendry int	day_in_week __P((int, int, int));
996ffb1990Spendry int	day_in_year __P((int, int, int));
1006ffb1990Spendry void	j_yearly __P((int));
1016ffb1990Spendry void	monthly __P((int, int));
1026ffb1990Spendry void	trim_trailing_spaces __P((char *));
1036ffb1990Spendry void	usage __P((void));
1046ffb1990Spendry void	yearly __P((int));
1056ffb1990Spendry 
1066ffb1990Spendry int
main(argc,argv)107dc686bb6Swnj main(argc, argv)
108ed8e7804Sbostic 	int argc;
109ed8e7804Sbostic 	char **argv;
110dc686bb6Swnj {
111ed8e7804Sbostic 	struct tm *local_time;
1126ffb1990Spendry 	time_t now;
1139ec34152Sbostic 	int ch, month, year, yflag;
114dc686bb6Swnj 
1159ec34152Sbostic 	yflag = 0;
116ad703e26Sbostic 	while ((ch = getopt(argc, argv, "jy")) != EOF)
1179ec34152Sbostic 		switch(ch) {
118ad703e26Sbostic 		case 'j':
119ad703e26Sbostic 			julian = 1;
120ad703e26Sbostic 			break;
1219ec34152Sbostic 		case 'y':
1229ec34152Sbostic 			yflag = 1;
1239ec34152Sbostic 			break;
1249ec34152Sbostic 		case '?':
1259ec34152Sbostic 		default:
1269ec34152Sbostic 			usage();
1279ec34152Sbostic 		}
1289ec34152Sbostic 	argc -= optind;
1299ec34152Sbostic 	argv += optind;
1309ec34152Sbostic 
131de432eacSbostic 	month = 0;
132ed8e7804Sbostic 	switch(argc) {
1339ec34152Sbostic 	case 2:
1346ffb1990Spendry 		if ((month = atoi(*argv++)) < 1 || month > 12)
1356ffb1990Spendry 			errx(1, "illegal month value: use 1-12");
136ed8e7804Sbostic 		/* FALLTHROUGH */
1379ec34152Sbostic 	case 1:
1386ffb1990Spendry 		if ((year = atoi(*argv)) < 1 || year > 9999)
1396ffb1990Spendry 			errx(1, "illegal year value: use 1-9999");
140ed8e7804Sbostic 		break;
1419ec34152Sbostic 	case 0:
142ed8e7804Sbostic 		(void)time(&now);
143ed8e7804Sbostic 		local_time = localtime(&now);
144ed8e7804Sbostic 		year = local_time->tm_year + 1900;
1459ec34152Sbostic 		if (!yflag)
1469ec34152Sbostic 			month = local_time->tm_mon + 1;
147ed8e7804Sbostic 		break;
148ed8e7804Sbostic 	default:
1499ec34152Sbostic 		usage();
150dc686bb6Swnj 	}
151de432eacSbostic 
152ed8e7804Sbostic 	if (month)
153ad703e26Sbostic 		monthly(month, year);
154ad703e26Sbostic 	else if (julian)
155ad703e26Sbostic 		j_yearly(year);
156ed8e7804Sbostic 	else
157ad703e26Sbostic 		yearly(year);
158ed8e7804Sbostic 	exit(0);
159dc686bb6Swnj }
160dc686bb6Swnj 
161ad703e26Sbostic #define	DAY_LEN		3		/* 3 spaces per day */
162ad703e26Sbostic #define	J_DAY_LEN	4		/* 4 spaces per day */
163ad703e26Sbostic #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
164ad703e26Sbostic #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
165ad703e26Sbostic #define	HEAD_SEP	2		/* spaces between day headings */
166de432eacSbostic #define	J_HEAD_SEP	2
167ad703e26Sbostic 
1686ffb1990Spendry void
monthly(month,year)169ad703e26Sbostic monthly(month, year)
170ed8e7804Sbostic 	int month, year;
171dc686bb6Swnj {
1726ffb1990Spendry 	int col, row, len, days[MAXDAYS];
1736ffb1990Spendry 	char *p, lineout[30];
174dc686bb6Swnj 
175ad703e26Sbostic 	day_array(month, year, days);
176ad703e26Sbostic 	len = sprintf(lineout, "%s %d", month_names[month - 1], year);
177ad703e26Sbostic 	(void)printf("%*s%s\n%s\n",
178ad703e26Sbostic 	    ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
179ad703e26Sbostic 	    lineout, julian ? j_day_headings : day_headings);
180ed8e7804Sbostic 	for (row = 0; row < 6; row++) {
181ad703e26Sbostic 		for (col = 0, p = lineout; col < 7; col++,
182ad703e26Sbostic 		    p += julian ? J_DAY_LEN : DAY_LEN)
183ed8e7804Sbostic 			ascii_day(p, days[row * 7 + col]);
184e81938bcSpendry 		*p = '\0';
185ed8e7804Sbostic 		trim_trailing_spaces(lineout);
186ed8e7804Sbostic 		(void)printf("%s\n", lineout);
187ed8e7804Sbostic 	}
188ed8e7804Sbostic }
189dc686bb6Swnj 
1906ffb1990Spendry void
j_yearly(year)191ad703e26Sbostic j_yearly(year)
192ed8e7804Sbostic 	int year;
193ed8e7804Sbostic {
1946ffb1990Spendry 	int col, *dp, i, month, row, which_cal;
195de432eacSbostic 	int days[12][MAXDAYS];
1966ffb1990Spendry 	char *p, lineout[80];
197dc686bb6Swnj 
198ad703e26Sbostic 	(void)sprintf(lineout, "%d", year);
199ad703e26Sbostic 	center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
200ad703e26Sbostic 	(void)printf("\n\n");
201ed8e7804Sbostic 	for (i = 0; i < 12; i++)
202de432eacSbostic 		day_array(i + 1, year, days[i]);
203ed8e7804Sbostic 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
204ed8e7804Sbostic 	lineout[sizeof(lineout) - 1] = '\0';
205ad703e26Sbostic 	for (month = 0; month < 12; month += 2) {
206ad703e26Sbostic 		center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
207ad703e26Sbostic 		center(month_names[month + 1], J_WEEK_LEN, 0);
208ad703e26Sbostic 		(void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
209ad703e26Sbostic 		    j_day_headings);
210ed8e7804Sbostic 		for (row = 0; row < 6; row++) {
211ad703e26Sbostic 			for (which_cal = 0; which_cal < 2; which_cal++) {
212ad703e26Sbostic 				p = lineout + which_cal * (J_WEEK_LEN + 2);
213ed8e7804Sbostic 				dp = &days[month + which_cal][row * 7];
214ad703e26Sbostic 				for (col = 0; col < 7; col++, p += J_DAY_LEN)
215ed8e7804Sbostic 					ascii_day(p, *dp++);
216ed8e7804Sbostic 			}
217e81938bcSpendry 			*p = '\0';
218ed8e7804Sbostic 			trim_trailing_spaces(lineout);
219ed8e7804Sbostic 			(void)printf("%s\n", lineout);
220ed8e7804Sbostic 		}
221ed8e7804Sbostic 	}
222ad703e26Sbostic 	(void)printf("\n");
223ad703e26Sbostic }
224ad703e26Sbostic 
2256ffb1990Spendry void
yearly(year)226ad703e26Sbostic yearly(year)
227ad703e26Sbostic 	int year;
228ad703e26Sbostic {
2296ffb1990Spendry 	int col, *dp, i, month, row, which_cal;
230de432eacSbostic 	int days[12][MAXDAYS];
2316ffb1990Spendry 	char *p, lineout[80];
232ad703e26Sbostic 
233ad703e26Sbostic 	(void)sprintf(lineout, "%d", year);
234ad703e26Sbostic 	center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
235ad703e26Sbostic 	(void)printf("\n\n");
236ad703e26Sbostic 	for (i = 0; i < 12; i++)
237de432eacSbostic 		day_array(i + 1, year, days[i]);
238ad703e26Sbostic 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
239ad703e26Sbostic 	lineout[sizeof(lineout) - 1] = '\0';
240ad703e26Sbostic 	for (month = 0; month < 12; month += 3) {
241ad703e26Sbostic 		center(month_names[month], WEEK_LEN, HEAD_SEP);
242ad703e26Sbostic 		center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
243ad703e26Sbostic 		center(month_names[month + 2], WEEK_LEN, 0);
244ad703e26Sbostic 		(void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
245ad703e26Sbostic 		    "", day_headings, HEAD_SEP, "", day_headings);
246ad703e26Sbostic 		for (row = 0; row < 6; row++) {
247ad703e26Sbostic 			for (which_cal = 0; which_cal < 3; which_cal++) {
248ad703e26Sbostic 				p = lineout + which_cal * (WEEK_LEN + 2);
249ad703e26Sbostic 				dp = &days[month + which_cal][row * 7];
250ad703e26Sbostic 				for (col = 0; col < 7; col++, p += DAY_LEN)
251ad703e26Sbostic 					ascii_day(p, *dp++);
252ad703e26Sbostic 			}
253e81938bcSpendry 			*p = '\0';
254ad703e26Sbostic 			trim_trailing_spaces(lineout);
255ad703e26Sbostic 			(void)printf("%s\n", lineout);
256ad703e26Sbostic 		}
257ad703e26Sbostic 	}
258ad703e26Sbostic 	(void)printf("\n");
259dc686bb6Swnj }
260dc686bb6Swnj 
261dc686bb6Swnj /*
262ad703e26Sbostic  * day_array --
263ed8e7804Sbostic  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
264ed8e7804Sbostic  *	that you took the (maximum) 6 rows in a calendar and stretched them
265ed8e7804Sbostic  *	out end to end.  You would have 42 numbers or spaces.  This routine
266ed8e7804Sbostic  *	builds that array for any month from Jan. 1 through Dec. 9999.
267dc686bb6Swnj  */
2686ffb1990Spendry void
day_array(month,year,days)269ad703e26Sbostic day_array(month, year, days)
270ad703e26Sbostic 	int month, year;
2716ffb1990Spendry 	int *days;
272ed8e7804Sbostic {
2736ffb1990Spendry 	int day, dw, dm;
274dc686bb6Swnj 
275ad703e26Sbostic 	if (month == 9 && year == 1752) {
2766ffb1990Spendry 		memmove(days,
2776ffb1990Spendry 			julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
278ad703e26Sbostic 		return;
279ed8e7804Sbostic 	}
2806ffb1990Spendry 	memmove(days, empty, MAXDAYS * sizeof(int));
281de432eacSbostic 	dm = days_in_month[leap_year(year)][month];
282de432eacSbostic 	dw = day_in_week(1, month, year);
283ad703e26Sbostic 	day = julian ? day_in_year(1, month, year) : 1;
284ad703e26Sbostic 	while (dm--)
285ad703e26Sbostic 		days[dw++] = day++;
286ed8e7804Sbostic }
287dc686bb6Swnj 
288ed8e7804Sbostic /*
289ed8e7804Sbostic  * day_in_year --
290ed8e7804Sbostic  *	return the 1 based day number within the year
291ed8e7804Sbostic  */
2926ffb1990Spendry int
day_in_year(day,month,year)293ed8e7804Sbostic day_in_year(day, month, year)
2946ffb1990Spendry 	int day, month, year;
295ed8e7804Sbostic {
2966ffb1990Spendry 	int i, leap;
297ed8e7804Sbostic 
298ed8e7804Sbostic 	leap = leap_year(year);
299ed8e7804Sbostic 	for (i = 1; i < month; i++)
300ed8e7804Sbostic 		day += days_in_month[leap][i];
301ed8e7804Sbostic 	return (day);
302ed8e7804Sbostic }
303ed8e7804Sbostic 
304ed8e7804Sbostic /*
305ed8e7804Sbostic  * day_in_week
306ed8e7804Sbostic  *	return the 0 based day number for any date from 1 Jan. 1 to
307ed8e7804Sbostic  *	31 Dec. 9999.  Assumes the Gregorian reformation eliminates
308ed8e7804Sbostic  *	3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
309ed8e7804Sbostic  *	missing days.
310ed8e7804Sbostic  */
3116ffb1990Spendry int
day_in_week(day,month,year)312ed8e7804Sbostic day_in_week(day, month, year)
313ed8e7804Sbostic 	int day, month, year;
314ed8e7804Sbostic {
315ed8e7804Sbostic 	long temp;
316ed8e7804Sbostic 
317ed8e7804Sbostic 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
318ed8e7804Sbostic 	    + day_in_year(day, month, year);
319ed8e7804Sbostic 	if (temp < FIRST_MISSING_DAY)
320ed8e7804Sbostic 		return ((temp - 1 + SATURDAY) % 7);
321ed8e7804Sbostic 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
322ed8e7804Sbostic 		return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
323ed8e7804Sbostic 	return (THURSDAY);
324ed8e7804Sbostic }
325ed8e7804Sbostic 
3266ffb1990Spendry void
ascii_day(p,day)327ed8e7804Sbostic ascii_day(p, day)
3286ffb1990Spendry 	char *p;
3296ffb1990Spendry 	int day;
330ed8e7804Sbostic {
3316ffb1990Spendry 	int display, val;
332de432eacSbostic 	static char *aday[] = {
333de432eacSbostic 		"",
334de432eacSbostic 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
335de432eacSbostic 		" 8", " 9", "10", "11", "12", "13", "14",
336de432eacSbostic 		"15", "16", "17", "18", "19", "20", "21",
337de432eacSbostic 		"22", "23", "24", "25", "26", "27", "28",
338de432eacSbostic 		"29", "30", "31",
339de432eacSbostic 	};
340ed8e7804Sbostic 
341ed8e7804Sbostic 	if (day == SPACE) {
342de432eacSbostic 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
343ad703e26Sbostic 		return;
344ad703e26Sbostic 	}
345b6dd8126Sbostic 	if (julian) {
346ad703e26Sbostic 		if (val = day / 100) {
347ad703e26Sbostic 			day %= 100;
348ad703e26Sbostic 			*p++ = val + '0';
349ad703e26Sbostic 			display = 1;
350de432eacSbostic 		} else {
351ed8e7804Sbostic 			*p++ = ' ';
352de432eacSbostic 			display = 0;
353ed8e7804Sbostic 		}
354ad703e26Sbostic 		val = day / 10;
355ad703e26Sbostic 		if (val || display)
356ad703e26Sbostic 			*p++ = val + '0';
357ad703e26Sbostic 		else
358ad703e26Sbostic 			*p++ = ' ';
359ed8e7804Sbostic 		*p++ = day % 10 + '0';
360b6dd8126Sbostic 	} else {
361b6dd8126Sbostic 		*p++ = aday[day][0];
362b6dd8126Sbostic 		*p++ = aday[day][1];
363b6dd8126Sbostic 	}
364ed8e7804Sbostic 	*p = ' ';
365ed8e7804Sbostic }
366ed8e7804Sbostic 
3676ffb1990Spendry void
trim_trailing_spaces(s)368ed8e7804Sbostic trim_trailing_spaces(s)
3696ffb1990Spendry 	char *s;
370ed8e7804Sbostic {
3716ffb1990Spendry 	char *p;
372ed8e7804Sbostic 
3736ffb1990Spendry 	for (p = s; *p; ++p)
3746ffb1990Spendry 		continue;
3756ffb1990Spendry 	while (p > s && isspace(*--p))
3766ffb1990Spendry 		continue;
377ed8e7804Sbostic 	if (p > s)
378ed8e7804Sbostic 		++p;
379ed8e7804Sbostic 	*p = '\0';
380dc686bb6Swnj }
3819ec34152Sbostic 
3826ffb1990Spendry void
center(str,len,separate)383ad703e26Sbostic center(str, len, separate)
384ad703e26Sbostic 	char *str;
3856ffb1990Spendry 	int len;
386ad703e26Sbostic 	int separate;
387ad703e26Sbostic {
3886ffb1990Spendry 
389ad703e26Sbostic 	len -= strlen(str);
390ad703e26Sbostic 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
391ad703e26Sbostic 	if (separate)
392ad703e26Sbostic 		(void)printf("%*s", separate, "");
393ad703e26Sbostic }
394ad703e26Sbostic 
3956ffb1990Spendry void
usage()3969ec34152Sbostic usage()
3979ec34152Sbostic {
3986ffb1990Spendry 
399ad703e26Sbostic 	(void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
4009ec34152Sbostic 	exit(1);
4019ec34152Sbostic }
402