Home | History | Annotate | Line # | Download | only in cal
cal.c revision 1.13
      1  1.13     perry /*	$NetBSD: cal.c,v 1.13 2002/06/22 21:14:18 perry Exp $	*/
      2   1.6     glass 
      3   1.1       cgd /*
      4   1.6     glass  * Copyright (c) 1989, 1993, 1994
      5   1.6     glass  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * This code is derived from software contributed to Berkeley by
      8   1.1       cgd  * Kim Letkeman.
      9   1.1       cgd  *
     10   1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11   1.1       cgd  * modification, are permitted provided that the following conditions
     12   1.1       cgd  * are met:
     13   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18   1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     19   1.1       cgd  *    must display the following acknowledgement:
     20   1.1       cgd  *	This product includes software developed by the University of
     21   1.1       cgd  *	California, Berkeley and its contributors.
     22   1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     23   1.1       cgd  *    may be used to endorse or promote products derived from this software
     24   1.1       cgd  *    without specific prior written permission.
     25   1.1       cgd  *
     26   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36   1.1       cgd  * SUCH DAMAGE.
     37   1.1       cgd  */
     38   1.1       cgd 
     39   1.7     lukem #include <sys/cdefs.h>
     40   1.1       cgd #ifndef lint
     41   1.7     lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
     42   1.7     lukem 	The Regents of the University of California.  All rights reserved.\n");
     43   1.1       cgd #endif /* not lint */
     44   1.1       cgd 
     45   1.1       cgd #ifndef lint
     46   1.6     glass #if 0
     47   1.6     glass static char sccsid[] = "@(#)cal.c	8.4 (Berkeley) 4/2/94";
     48   1.6     glass #else
     49  1.13     perry __RCSID("$NetBSD: cal.c,v 1.13 2002/06/22 21:14:18 perry Exp $");
     50   1.6     glass #endif
     51   1.1       cgd #endif /* not lint */
     52   1.1       cgd 
     53   1.1       cgd #include <sys/types.h>
     54   1.6     glass 
     55   1.6     glass #include <ctype.h>
     56   1.6     glass #include <err.h>
     57   1.1       cgd #include <stdio.h>
     58   1.6     glass #include <stdlib.h>
     59   1.4       cgd #include <string.h>
     60   1.6     glass #include <time.h>
     61   1.8  christos #include <tzfile.h>
     62   1.6     glass #include <unistd.h>
     63   1.1       cgd 
     64   1.1       cgd #define	THURSDAY		4		/* for reformation */
     65   1.1       cgd #define	SATURDAY 		6		/* 1 Jan 1 was a Saturday */
     66   1.1       cgd 
     67   1.5        ws #define	FIRST_MISSING_DAY 	639799		/* 3 Sep 1752 */
     68   1.1       cgd #define	NUMBER_MISSING_DAYS 	11		/* 11 day correction */
     69   1.1       cgd 
     70   1.1       cgd #define	MAXDAYS			42		/* max slots in a month array */
     71   1.1       cgd #define	SPACE			-1		/* used in day array */
     72   1.1       cgd 
     73   1.1       cgd static int days_in_month[2][13] = {
     74   1.1       cgd 	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     75   1.1       cgd 	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     76   1.1       cgd };
     77   1.1       cgd 
     78   1.1       cgd int sep1752[MAXDAYS] = {
     79   1.1       cgd 	SPACE,	SPACE,	1,	2,	14,	15,	16,
     80   1.1       cgd 	17,	18,	19,	20,	21,	22,	23,
     81   1.1       cgd 	24,	25,	26,	27,	28,	29,	30,
     82   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     83   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     84   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     85   1.1       cgd }, j_sep1752[MAXDAYS] = {
     86   1.1       cgd 	SPACE,	SPACE,	245,	246,	258,	259,	260,
     87   1.1       cgd 	261,	262,	263,	264,	265,	266,	267,
     88   1.1       cgd 	268,	269,	270,	271,	272,	273,	274,
     89   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     90   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     91   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     92   1.1       cgd }, empty[MAXDAYS] = {
     93   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     94   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     95   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     96   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     97   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     98   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     99   1.1       cgd };
    100   1.1       cgd 
    101   1.1       cgd char *month_names[12] = {
    102   1.1       cgd 	"January", "February", "March", "April", "May", "June",
    103   1.1       cgd 	"July", "August", "September", "October", "November", "December",
    104   1.1       cgd };
    105   1.1       cgd 
    106   1.1       cgd char *day_headings = " S  M Tu  W Th  F  S";
    107   1.1       cgd char *j_day_headings = "  S   M  Tu   W  Th   F   S";
    108   1.1       cgd 
    109   1.1       cgd /* leap year -- account for gregorian reformation in 1752 */
    110   1.1       cgd #define	leap_year(yr) \
    111   1.1       cgd 	((yr) <= 1752 ? !((yr) % 4) : \
    112   1.9        ws 	(!((yr) % 4) && ((yr) % 100)) || !((yr) % 400))
    113   1.1       cgd 
    114   1.1       cgd /* number of centuries since 1700, not inclusive */
    115   1.1       cgd #define	centuries_since_1700(yr) \
    116   1.1       cgd 	((yr) > 1700 ? (yr) / 100 - 17 : 0)
    117   1.1       cgd 
    118   1.1       cgd /* number of centuries since 1700 whose modulo of 400 is 0 */
    119   1.1       cgd #define	quad_centuries_since_1700(yr) \
    120   1.1       cgd 	((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
    121   1.1       cgd 
    122   1.1       cgd /* number of leap years between year 1 and this year, not inclusive */
    123   1.1       cgd #define	leap_years_since_year_1(yr) \
    124   1.1       cgd 	((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
    125   1.1       cgd 
    126   1.1       cgd int julian;
    127   1.1       cgd 
    128  1.12     perry void	ascii_day(char *, int);
    129  1.12     perry void	center(char *, int, int);
    130  1.12     perry void	day_array(int, int, int *);
    131  1.12     perry int	day_in_week(int, int, int);
    132  1.12     perry int	day_in_year(int, int, int);
    133  1.12     perry void	j_yearly(int);
    134  1.13     perry void	month3(int, int);
    135  1.12     perry void	monthly(int, int);
    136  1.12     perry int	main(int, char **);
    137  1.12     perry void	trim_trailing_spaces(char *);
    138  1.12     perry void	usage(void);
    139  1.12     perry void	yearly(int);
    140   1.6     glass 
    141   1.6     glass int
    142  1.12     perry main(int argc, char **argv)
    143   1.1       cgd {
    144   1.1       cgd 	struct tm *local_time;
    145   1.6     glass 	time_t now;
    146  1.13     perry 	int ch, month, year, yflag, threeflag;
    147   1.1       cgd 
    148   1.7     lukem 	yflag = year = 0;
    149  1.13     perry 	threeflag = 0;
    150  1.13     perry 	while ((ch = getopt(argc, argv, "jy3")) != -1) {
    151  1.12     perry 		switch (ch) {
    152   1.1       cgd 		case 'j':
    153   1.1       cgd 			julian = 1;
    154   1.1       cgd 			break;
    155   1.1       cgd 		case 'y':
    156   1.1       cgd 			yflag = 1;
    157   1.1       cgd 			break;
    158  1.13     perry 		case '3':
    159  1.13     perry 			threeflag = 1;
    160  1.13     perry 			break;
    161   1.1       cgd 		case '?':
    162   1.1       cgd 		default:
    163   1.1       cgd 			usage();
    164  1.12     perry 			/* NOTREACHED */
    165   1.1       cgd 		}
    166  1.12     perry 	}
    167  1.13     perry 
    168  1.13     perry 	if (threeflag && julian) {
    169  1.13     perry 		usage();
    170  1.13     perry 	}
    171  1.13     perry 
    172   1.1       cgd 	argc -= optind;
    173   1.1       cgd 	argv += optind;
    174   1.1       cgd 
    175   1.1       cgd 	month = 0;
    176  1.12     perry 	switch (argc) {
    177   1.1       cgd 	case 2:
    178   1.6     glass 		if ((month = atoi(*argv++)) < 1 || month > 12)
    179   1.6     glass 			errx(1, "illegal month value: use 1-12");
    180   1.1       cgd 		/* FALLTHROUGH */
    181   1.1       cgd 	case 1:
    182   1.6     glass 		if ((year = atoi(*argv)) < 1 || year > 9999)
    183   1.6     glass 			errx(1, "illegal year value: use 1-9999");
    184   1.1       cgd 		break;
    185   1.1       cgd 	case 0:
    186   1.1       cgd 		(void)time(&now);
    187   1.1       cgd 		local_time = localtime(&now);
    188   1.8  christos 		year = local_time->tm_year + TM_YEAR_BASE;
    189   1.1       cgd 		if (!yflag)
    190   1.1       cgd 			month = local_time->tm_mon + 1;
    191   1.1       cgd 		break;
    192   1.1       cgd 	default:
    193   1.1       cgd 		usage();
    194   1.1       cgd 	}
    195   1.1       cgd 
    196  1.13     perry 	if (threeflag)
    197  1.13     perry 		month3(month ? month : 1 , year);
    198  1.13     perry 	else if (month)
    199   1.1       cgd 		monthly(month, year);
    200   1.1       cgd 	else if (julian)
    201   1.1       cgd 		j_yearly(year);
    202   1.1       cgd 	else
    203   1.1       cgd 		yearly(year);
    204  1.13     perry 
    205   1.1       cgd 	exit(0);
    206   1.1       cgd }
    207   1.1       cgd 
    208   1.1       cgd #define	DAY_LEN		3		/* 3 spaces per day */
    209   1.1       cgd #define	J_DAY_LEN	4		/* 4 spaces per day */
    210   1.1       cgd #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
    211   1.1       cgd #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
    212   1.1       cgd #define	HEAD_SEP	2		/* spaces between day headings */
    213   1.1       cgd #define	J_HEAD_SEP	2
    214   1.1       cgd 
    215   1.6     glass void
    216  1.12     perry monthly(int month, int year)
    217   1.1       cgd {
    218   1.6     glass 	int col, row, len, days[MAXDAYS];
    219   1.6     glass 	char *p, lineout[30];
    220   1.1       cgd 
    221   1.1       cgd 	day_array(month, year, days);
    222  1.10   mycroft 	len = snprintf(lineout, sizeof(lineout), "%s %d",
    223  1.10   mycroft 	    month_names[month - 1], year);
    224   1.1       cgd 	(void)printf("%*s%s\n%s\n",
    225   1.1       cgd 	    ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
    226   1.1       cgd 	    lineout, julian ? j_day_headings : day_headings);
    227   1.1       cgd 	for (row = 0; row < 6; row++) {
    228   1.1       cgd 		for (col = 0, p = lineout; col < 7; col++,
    229   1.1       cgd 		    p += julian ? J_DAY_LEN : DAY_LEN)
    230   1.1       cgd 			ascii_day(p, days[row * 7 + col]);
    231   1.3       cgd 		*p = '\0';
    232   1.1       cgd 		trim_trailing_spaces(lineout);
    233   1.1       cgd 		(void)printf("%s\n", lineout);
    234   1.1       cgd 	}
    235   1.1       cgd }
    236   1.1       cgd 
    237   1.6     glass void
    238  1.12     perry j_yearly(int year)
    239   1.1       cgd {
    240   1.6     glass 	int col, *dp, i, month, row, which_cal;
    241   1.1       cgd 	int days[12][MAXDAYS];
    242   1.6     glass 	char *p, lineout[80];
    243   1.1       cgd 
    244  1.10   mycroft 	(void)snprintf(lineout, sizeof(lineout), "%d", year);
    245   1.1       cgd 	center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
    246   1.1       cgd 	(void)printf("\n\n");
    247   1.1       cgd 	for (i = 0; i < 12; i++)
    248   1.1       cgd 		day_array(i + 1, year, days[i]);
    249   1.1       cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    250   1.1       cgd 	lineout[sizeof(lineout) - 1] = '\0';
    251   1.1       cgd 	for (month = 0; month < 12; month += 2) {
    252   1.1       cgd 		center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
    253   1.1       cgd 		center(month_names[month + 1], J_WEEK_LEN, 0);
    254   1.1       cgd 		(void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
    255   1.1       cgd 		    j_day_headings);
    256   1.1       cgd 		for (row = 0; row < 6; row++) {
    257   1.1       cgd 			for (which_cal = 0; which_cal < 2; which_cal++) {
    258   1.1       cgd 				p = lineout + which_cal * (J_WEEK_LEN + 2);
    259   1.1       cgd 				dp = &days[month + which_cal][row * 7];
    260   1.1       cgd 				for (col = 0; col < 7; col++, p += J_DAY_LEN)
    261   1.1       cgd 					ascii_day(p, *dp++);
    262   1.1       cgd 			}
    263   1.3       cgd 			*p = '\0';
    264   1.1       cgd 			trim_trailing_spaces(lineout);
    265   1.1       cgd 			(void)printf("%s\n", lineout);
    266   1.1       cgd 		}
    267   1.1       cgd 	}
    268   1.1       cgd 	(void)printf("\n");
    269   1.1       cgd }
    270   1.1       cgd 
    271   1.6     glass void
    272  1.12     perry yearly(int year)
    273   1.1       cgd {
    274   1.6     glass 	int col, *dp, i, month, row, which_cal;
    275   1.1       cgd 	int days[12][MAXDAYS];
    276   1.6     glass 	char *p, lineout[80];
    277   1.1       cgd 
    278  1.10   mycroft 	(void)snprintf(lineout, sizeof(lineout), "%d", year);
    279   1.1       cgd 	center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
    280   1.1       cgd 	(void)printf("\n\n");
    281   1.1       cgd 	for (i = 0; i < 12; i++)
    282   1.1       cgd 		day_array(i + 1, year, days[i]);
    283   1.1       cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    284   1.1       cgd 	lineout[sizeof(lineout) - 1] = '\0';
    285   1.1       cgd 	for (month = 0; month < 12; month += 3) {
    286   1.1       cgd 		center(month_names[month], WEEK_LEN, HEAD_SEP);
    287   1.1       cgd 		center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
    288   1.1       cgd 		center(month_names[month + 2], WEEK_LEN, 0);
    289   1.1       cgd 		(void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
    290   1.1       cgd 		    "", day_headings, HEAD_SEP, "", day_headings);
    291   1.1       cgd 		for (row = 0; row < 6; row++) {
    292   1.1       cgd 			for (which_cal = 0; which_cal < 3; which_cal++) {
    293   1.1       cgd 				p = lineout + which_cal * (WEEK_LEN + 2);
    294   1.1       cgd 				dp = &days[month + which_cal][row * 7];
    295   1.1       cgd 				for (col = 0; col < 7; col++, p += DAY_LEN)
    296   1.1       cgd 					ascii_day(p, *dp++);
    297   1.1       cgd 			}
    298   1.3       cgd 			*p = '\0';
    299   1.1       cgd 			trim_trailing_spaces(lineout);
    300   1.1       cgd 			(void)printf("%s\n", lineout);
    301   1.1       cgd 		}
    302   1.1       cgd 	}
    303   1.1       cgd 	(void)printf("\n");
    304   1.1       cgd }
    305   1.1       cgd 
    306  1.13     perry void
    307  1.13     perry month3(int month, int year)
    308  1.13     perry {
    309  1.13     perry 	int col, *dp, i, row, which_cal;
    310  1.13     perry 	int days[12][MAXDAYS];
    311  1.13     perry 	char *p, lineout[80];
    312  1.13     perry 
    313  1.13     perry 	for (i = 0; i < 12; i++)
    314  1.13     perry 		day_array(i + 1, year, days[i]);
    315  1.13     perry 
    316  1.13     perry 	month--;
    317  1.13     perry 
    318  1.13     perry 	snprintf(lineout, sizeof(lineout), "%s %d",
    319  1.13     perry 	    month_names[month], year);
    320  1.13     perry 	center(lineout, WEEK_LEN, HEAD_SEP);
    321  1.13     perry 	snprintf(lineout, sizeof(lineout), "%s %d",
    322  1.13     perry 	    month_names[month+1], year);
    323  1.13     perry 	center(lineout, WEEK_LEN, HEAD_SEP);
    324  1.13     perry 	snprintf(lineout, sizeof(lineout), "%s %d",
    325  1.13     perry 	    month_names[month+2], year);
    326  1.13     perry 	center(lineout, WEEK_LEN, 0);
    327  1.13     perry 
    328  1.13     perry 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    329  1.13     perry 	lineout[sizeof(lineout) - 1] = '\0';
    330  1.13     perry 
    331  1.13     perry 	(void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
    332  1.13     perry 	    "", day_headings, HEAD_SEP, "", day_headings);
    333  1.13     perry 	for (row = 0; row < 6; row++) {
    334  1.13     perry 		for (which_cal = 0; which_cal < 3; which_cal++) {
    335  1.13     perry 			p = lineout + which_cal * (WEEK_LEN + 2);
    336  1.13     perry 			dp = &days[month + which_cal][row * 7];
    337  1.13     perry 			for (col = 0; col < 7; col++, p += DAY_LEN)
    338  1.13     perry 				ascii_day(p, *dp++);
    339  1.13     perry 		}
    340  1.13     perry 		*p = '\0';
    341  1.13     perry 		trim_trailing_spaces(lineout);
    342  1.13     perry 		(void)printf("%s\n", lineout);
    343  1.13     perry 	}
    344  1.13     perry }
    345  1.13     perry 
    346   1.1       cgd /*
    347   1.1       cgd  * day_array --
    348   1.1       cgd  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
    349   1.1       cgd  *	that you took the (maximum) 6 rows in a calendar and stretched them
    350   1.1       cgd  *	out end to end.  You would have 42 numbers or spaces.  This routine
    351   1.1       cgd  *	builds that array for any month from Jan. 1 through Dec. 9999.
    352   1.1       cgd  */
    353   1.6     glass void
    354  1.12     perry day_array(int month, int year, int *days)
    355   1.1       cgd {
    356   1.6     glass 	int day, dw, dm;
    357   1.1       cgd 
    358   1.1       cgd 	if (month == 9 && year == 1752) {
    359   1.6     glass 		memmove(days,
    360   1.6     glass 			julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
    361   1.1       cgd 		return;
    362   1.1       cgd 	}
    363   1.6     glass 	memmove(days, empty, MAXDAYS * sizeof(int));
    364   1.1       cgd 	dm = days_in_month[leap_year(year)][month];
    365   1.1       cgd 	dw = day_in_week(1, month, year);
    366   1.1       cgd 	day = julian ? day_in_year(1, month, year) : 1;
    367   1.1       cgd 	while (dm--)
    368   1.1       cgd 		days[dw++] = day++;
    369   1.1       cgd }
    370   1.1       cgd 
    371   1.1       cgd /*
    372   1.1       cgd  * day_in_year --
    373   1.1       cgd  *	return the 1 based day number within the year
    374   1.1       cgd  */
    375   1.6     glass int
    376  1.12     perry day_in_year(int day, int month, int year)
    377   1.1       cgd {
    378   1.6     glass 	int i, leap;
    379   1.1       cgd 
    380   1.1       cgd 	leap = leap_year(year);
    381   1.1       cgd 	for (i = 1; i < month; i++)
    382   1.1       cgd 		day += days_in_month[leap][i];
    383   1.6     glass 	return (day);
    384   1.1       cgd }
    385   1.1       cgd 
    386   1.1       cgd /*
    387   1.1       cgd  * day_in_week
    388   1.1       cgd  *	return the 0 based day number for any date from 1 Jan. 1 to
    389   1.1       cgd  *	31 Dec. 9999.  Assumes the Gregorian reformation eliminates
    390   1.1       cgd  *	3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
    391   1.1       cgd  *	missing days.
    392   1.1       cgd  */
    393   1.6     glass int
    394  1.12     perry day_in_week(int day, int month, int year)
    395   1.1       cgd {
    396   1.1       cgd 	long temp;
    397   1.1       cgd 
    398   1.1       cgd 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
    399   1.1       cgd 	    + day_in_year(day, month, year);
    400   1.1       cgd 	if (temp < FIRST_MISSING_DAY)
    401   1.6     glass 		return ((temp - 1 + SATURDAY) % 7);
    402   1.1       cgd 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
    403   1.6     glass 		return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
    404   1.6     glass 	return (THURSDAY);
    405   1.1       cgd }
    406   1.1       cgd 
    407   1.6     glass void
    408  1.12     perry ascii_day(char *p, int day)
    409   1.1       cgd {
    410   1.6     glass 	int display, val;
    411   1.1       cgd 	static char *aday[] = {
    412   1.1       cgd 		"",
    413   1.1       cgd 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
    414   1.1       cgd 		" 8", " 9", "10", "11", "12", "13", "14",
    415   1.1       cgd 		"15", "16", "17", "18", "19", "20", "21",
    416   1.1       cgd 		"22", "23", "24", "25", "26", "27", "28",
    417   1.1       cgd 		"29", "30", "31",
    418   1.1       cgd 	};
    419   1.1       cgd 
    420   1.1       cgd 	if (day == SPACE) {
    421   1.1       cgd 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
    422   1.1       cgd 		return;
    423   1.1       cgd 	}
    424   1.1       cgd 	if (julian) {
    425   1.7     lukem 		if ((val = day / 100) != 0) {
    426   1.1       cgd 			day %= 100;
    427   1.1       cgd 			*p++ = val + '0';
    428   1.1       cgd 			display = 1;
    429   1.1       cgd 		} else {
    430   1.1       cgd 			*p++ = ' ';
    431   1.1       cgd 			display = 0;
    432   1.1       cgd 		}
    433   1.1       cgd 		val = day / 10;
    434   1.1       cgd 		if (val || display)
    435   1.1       cgd 			*p++ = val + '0';
    436   1.1       cgd 		else
    437   1.1       cgd 			*p++ = ' ';
    438   1.1       cgd 		*p++ = day % 10 + '0';
    439   1.1       cgd 	} else {
    440   1.1       cgd 		*p++ = aday[day][0];
    441   1.1       cgd 		*p++ = aday[day][1];
    442   1.1       cgd 	}
    443   1.1       cgd 	*p = ' ';
    444   1.1       cgd }
    445   1.1       cgd 
    446   1.6     glass void
    447  1.12     perry trim_trailing_spaces(char *s)
    448   1.1       cgd {
    449   1.6     glass 	char *p;
    450   1.1       cgd 
    451   1.6     glass 	for (p = s; *p; ++p)
    452   1.6     glass 		continue;
    453  1.11  christos 	while (p > s && isspace((unsigned char)*--p))
    454   1.6     glass 		continue;
    455   1.1       cgd 	if (p > s)
    456   1.1       cgd 		++p;
    457   1.1       cgd 	*p = '\0';
    458   1.1       cgd }
    459   1.1       cgd 
    460   1.6     glass void
    461  1.12     perry center(char *str, int len, int separate)
    462   1.1       cgd {
    463   1.6     glass 
    464   1.1       cgd 	len -= strlen(str);
    465   1.1       cgd 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
    466   1.1       cgd 	if (separate)
    467   1.1       cgd 		(void)printf("%*s", separate, "");
    468   1.1       cgd }
    469   1.1       cgd 
    470   1.6     glass void
    471  1.12     perry usage(void)
    472   1.1       cgd {
    473   1.6     glass 
    474  1.13     perry 	(void)fprintf(stderr, "usage: cal [-jy3] [[month] year]\n");
    475   1.1       cgd 	exit(1);
    476   1.1       cgd }
    477