Home | History | Annotate | Line # | Download | only in cal
cal.c revision 1.10
      1  1.10   mycroft /*	$NetBSD: cal.c,v 1.10 1998/07/28 19:26:09 mycroft 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.10   mycroft __RCSID("$NetBSD: cal.c,v 1.10 1998/07/28 19:26:09 mycroft 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.6     glass void	ascii_day __P((char *, int));
    129   1.6     glass void	center __P((char *, int, int));
    130   1.6     glass void	day_array __P((int, int, int *));
    131   1.6     glass int	day_in_week __P((int, int, int));
    132   1.6     glass int	day_in_year __P((int, int, int));
    133   1.6     glass void	j_yearly __P((int));
    134   1.6     glass void	monthly __P((int, int));
    135   1.7     lukem int	main __P((int, char **));
    136   1.6     glass void	trim_trailing_spaces __P((char *));
    137   1.6     glass void	usage __P((void));
    138   1.6     glass void	yearly __P((int));
    139   1.6     glass 
    140   1.6     glass int
    141   1.1       cgd main(argc, argv)
    142   1.1       cgd 	int argc;
    143   1.1       cgd 	char **argv;
    144   1.1       cgd {
    145   1.1       cgd 	struct tm *local_time;
    146   1.6     glass 	time_t now;
    147   1.1       cgd 	int ch, month, year, yflag;
    148   1.1       cgd 
    149   1.7     lukem 	yflag = year = 0;
    150   1.7     lukem 	while ((ch = getopt(argc, argv, "jy")) != -1)
    151   1.1       cgd 		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.1       cgd 		case '?':
    159   1.1       cgd 		default:
    160   1.1       cgd 			usage();
    161   1.1       cgd 		}
    162   1.1       cgd 	argc -= optind;
    163   1.1       cgd 	argv += optind;
    164   1.1       cgd 
    165   1.1       cgd 	month = 0;
    166   1.1       cgd 	switch(argc) {
    167   1.1       cgd 	case 2:
    168   1.6     glass 		if ((month = atoi(*argv++)) < 1 || month > 12)
    169   1.6     glass 			errx(1, "illegal month value: use 1-12");
    170   1.1       cgd 		/* FALLTHROUGH */
    171   1.1       cgd 	case 1:
    172   1.6     glass 		if ((year = atoi(*argv)) < 1 || year > 9999)
    173   1.6     glass 			errx(1, "illegal year value: use 1-9999");
    174   1.1       cgd 		break;
    175   1.1       cgd 	case 0:
    176   1.1       cgd 		(void)time(&now);
    177   1.1       cgd 		local_time = localtime(&now);
    178   1.8  christos 		year = local_time->tm_year + TM_YEAR_BASE;
    179   1.1       cgd 		if (!yflag)
    180   1.1       cgd 			month = local_time->tm_mon + 1;
    181   1.1       cgd 		break;
    182   1.1       cgd 	default:
    183   1.1       cgd 		usage();
    184   1.1       cgd 	}
    185   1.1       cgd 
    186   1.1       cgd 	if (month)
    187   1.1       cgd 		monthly(month, year);
    188   1.1       cgd 	else if (julian)
    189   1.1       cgd 		j_yearly(year);
    190   1.1       cgd 	else
    191   1.1       cgd 		yearly(year);
    192   1.1       cgd 	exit(0);
    193   1.1       cgd }
    194   1.1       cgd 
    195   1.1       cgd #define	DAY_LEN		3		/* 3 spaces per day */
    196   1.1       cgd #define	J_DAY_LEN	4		/* 4 spaces per day */
    197   1.1       cgd #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
    198   1.1       cgd #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
    199   1.1       cgd #define	HEAD_SEP	2		/* spaces between day headings */
    200   1.1       cgd #define	J_HEAD_SEP	2
    201   1.1       cgd 
    202   1.6     glass void
    203   1.1       cgd monthly(month, year)
    204   1.1       cgd 	int month, year;
    205   1.1       cgd {
    206   1.6     glass 	int col, row, len, days[MAXDAYS];
    207   1.6     glass 	char *p, lineout[30];
    208   1.1       cgd 
    209   1.1       cgd 	day_array(month, year, days);
    210  1.10   mycroft 	len = snprintf(lineout, sizeof(lineout), "%s %d",
    211  1.10   mycroft 	    month_names[month - 1], year);
    212   1.1       cgd 	(void)printf("%*s%s\n%s\n",
    213   1.1       cgd 	    ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
    214   1.1       cgd 	    lineout, julian ? j_day_headings : day_headings);
    215   1.1       cgd 	for (row = 0; row < 6; row++) {
    216   1.1       cgd 		for (col = 0, p = lineout; col < 7; col++,
    217   1.1       cgd 		    p += julian ? J_DAY_LEN : DAY_LEN)
    218   1.1       cgd 			ascii_day(p, days[row * 7 + col]);
    219   1.3       cgd 		*p = '\0';
    220   1.1       cgd 		trim_trailing_spaces(lineout);
    221   1.1       cgd 		(void)printf("%s\n", lineout);
    222   1.1       cgd 	}
    223   1.1       cgd }
    224   1.1       cgd 
    225   1.6     glass void
    226   1.1       cgd j_yearly(year)
    227   1.1       cgd 	int year;
    228   1.1       cgd {
    229   1.6     glass 	int col, *dp, i, month, row, which_cal;
    230   1.1       cgd 	int days[12][MAXDAYS];
    231   1.6     glass 	char *p, lineout[80];
    232   1.1       cgd 
    233  1.10   mycroft 	(void)snprintf(lineout, sizeof(lineout), "%d", year);
    234   1.1       cgd 	center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
    235   1.1       cgd 	(void)printf("\n\n");
    236   1.1       cgd 	for (i = 0; i < 12; i++)
    237   1.1       cgd 		day_array(i + 1, year, days[i]);
    238   1.1       cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    239   1.1       cgd 	lineout[sizeof(lineout) - 1] = '\0';
    240   1.1       cgd 	for (month = 0; month < 12; month += 2) {
    241   1.1       cgd 		center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
    242   1.1       cgd 		center(month_names[month + 1], J_WEEK_LEN, 0);
    243   1.1       cgd 		(void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
    244   1.1       cgd 		    j_day_headings);
    245   1.1       cgd 		for (row = 0; row < 6; row++) {
    246   1.1       cgd 			for (which_cal = 0; which_cal < 2; which_cal++) {
    247   1.1       cgd 				p = lineout + which_cal * (J_WEEK_LEN + 2);
    248   1.1       cgd 				dp = &days[month + which_cal][row * 7];
    249   1.1       cgd 				for (col = 0; col < 7; col++, p += J_DAY_LEN)
    250   1.1       cgd 					ascii_day(p, *dp++);
    251   1.1       cgd 			}
    252   1.3       cgd 			*p = '\0';
    253   1.1       cgd 			trim_trailing_spaces(lineout);
    254   1.1       cgd 			(void)printf("%s\n", lineout);
    255   1.1       cgd 		}
    256   1.1       cgd 	}
    257   1.1       cgd 	(void)printf("\n");
    258   1.1       cgd }
    259   1.1       cgd 
    260   1.6     glass void
    261   1.1       cgd yearly(year)
    262   1.1       cgd 	int year;
    263   1.1       cgd {
    264   1.6     glass 	int col, *dp, i, month, row, which_cal;
    265   1.1       cgd 	int days[12][MAXDAYS];
    266   1.6     glass 	char *p, lineout[80];
    267   1.1       cgd 
    268  1.10   mycroft 	(void)snprintf(lineout, sizeof(lineout), "%d", year);
    269   1.1       cgd 	center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
    270   1.1       cgd 	(void)printf("\n\n");
    271   1.1       cgd 	for (i = 0; i < 12; i++)
    272   1.1       cgd 		day_array(i + 1, year, days[i]);
    273   1.1       cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    274   1.1       cgd 	lineout[sizeof(lineout) - 1] = '\0';
    275   1.1       cgd 	for (month = 0; month < 12; month += 3) {
    276   1.1       cgd 		center(month_names[month], WEEK_LEN, HEAD_SEP);
    277   1.1       cgd 		center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
    278   1.1       cgd 		center(month_names[month + 2], WEEK_LEN, 0);
    279   1.1       cgd 		(void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
    280   1.1       cgd 		    "", day_headings, HEAD_SEP, "", day_headings);
    281   1.1       cgd 		for (row = 0; row < 6; row++) {
    282   1.1       cgd 			for (which_cal = 0; which_cal < 3; which_cal++) {
    283   1.1       cgd 				p = lineout + which_cal * (WEEK_LEN + 2);
    284   1.1       cgd 				dp = &days[month + which_cal][row * 7];
    285   1.1       cgd 				for (col = 0; col < 7; col++, p += DAY_LEN)
    286   1.1       cgd 					ascii_day(p, *dp++);
    287   1.1       cgd 			}
    288   1.3       cgd 			*p = '\0';
    289   1.1       cgd 			trim_trailing_spaces(lineout);
    290   1.1       cgd 			(void)printf("%s\n", lineout);
    291   1.1       cgd 		}
    292   1.1       cgd 	}
    293   1.1       cgd 	(void)printf("\n");
    294   1.1       cgd }
    295   1.1       cgd 
    296   1.1       cgd /*
    297   1.1       cgd  * day_array --
    298   1.1       cgd  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
    299   1.1       cgd  *	that you took the (maximum) 6 rows in a calendar and stretched them
    300   1.1       cgd  *	out end to end.  You would have 42 numbers or spaces.  This routine
    301   1.1       cgd  *	builds that array for any month from Jan. 1 through Dec. 9999.
    302   1.1       cgd  */
    303   1.6     glass void
    304   1.1       cgd day_array(month, year, days)
    305   1.1       cgd 	int month, year;
    306   1.6     glass 	int *days;
    307   1.1       cgd {
    308   1.6     glass 	int day, dw, dm;
    309   1.1       cgd 
    310   1.1       cgd 	if (month == 9 && year == 1752) {
    311   1.6     glass 		memmove(days,
    312   1.6     glass 			julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
    313   1.1       cgd 		return;
    314   1.1       cgd 	}
    315   1.6     glass 	memmove(days, empty, MAXDAYS * sizeof(int));
    316   1.1       cgd 	dm = days_in_month[leap_year(year)][month];
    317   1.1       cgd 	dw = day_in_week(1, month, year);
    318   1.1       cgd 	day = julian ? day_in_year(1, month, year) : 1;
    319   1.1       cgd 	while (dm--)
    320   1.1       cgd 		days[dw++] = day++;
    321   1.1       cgd }
    322   1.1       cgd 
    323   1.1       cgd /*
    324   1.1       cgd  * day_in_year --
    325   1.1       cgd  *	return the 1 based day number within the year
    326   1.1       cgd  */
    327   1.6     glass int
    328   1.1       cgd day_in_year(day, month, year)
    329   1.6     glass 	int day, month, year;
    330   1.1       cgd {
    331   1.6     glass 	int i, leap;
    332   1.1       cgd 
    333   1.1       cgd 	leap = leap_year(year);
    334   1.1       cgd 	for (i = 1; i < month; i++)
    335   1.1       cgd 		day += days_in_month[leap][i];
    336   1.6     glass 	return (day);
    337   1.1       cgd }
    338   1.1       cgd 
    339   1.1       cgd /*
    340   1.1       cgd  * day_in_week
    341   1.1       cgd  *	return the 0 based day number for any date from 1 Jan. 1 to
    342   1.1       cgd  *	31 Dec. 9999.  Assumes the Gregorian reformation eliminates
    343   1.1       cgd  *	3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
    344   1.1       cgd  *	missing days.
    345   1.1       cgd  */
    346   1.6     glass int
    347   1.1       cgd day_in_week(day, month, year)
    348   1.1       cgd 	int day, month, year;
    349   1.1       cgd {
    350   1.1       cgd 	long temp;
    351   1.1       cgd 
    352   1.1       cgd 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
    353   1.1       cgd 	    + day_in_year(day, month, year);
    354   1.1       cgd 	if (temp < FIRST_MISSING_DAY)
    355   1.6     glass 		return ((temp - 1 + SATURDAY) % 7);
    356   1.1       cgd 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
    357   1.6     glass 		return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
    358   1.6     glass 	return (THURSDAY);
    359   1.1       cgd }
    360   1.1       cgd 
    361   1.6     glass void
    362   1.1       cgd ascii_day(p, day)
    363   1.6     glass 	char *p;
    364   1.6     glass 	int day;
    365   1.1       cgd {
    366   1.6     glass 	int display, val;
    367   1.1       cgd 	static char *aday[] = {
    368   1.1       cgd 		"",
    369   1.1       cgd 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
    370   1.1       cgd 		" 8", " 9", "10", "11", "12", "13", "14",
    371   1.1       cgd 		"15", "16", "17", "18", "19", "20", "21",
    372   1.1       cgd 		"22", "23", "24", "25", "26", "27", "28",
    373   1.1       cgd 		"29", "30", "31",
    374   1.1       cgd 	};
    375   1.1       cgd 
    376   1.1       cgd 	if (day == SPACE) {
    377   1.1       cgd 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
    378   1.1       cgd 		return;
    379   1.1       cgd 	}
    380   1.1       cgd 	if (julian) {
    381   1.7     lukem 		if ((val = day / 100) != 0) {
    382   1.1       cgd 			day %= 100;
    383   1.1       cgd 			*p++ = val + '0';
    384   1.1       cgd 			display = 1;
    385   1.1       cgd 		} else {
    386   1.1       cgd 			*p++ = ' ';
    387   1.1       cgd 			display = 0;
    388   1.1       cgd 		}
    389   1.1       cgd 		val = day / 10;
    390   1.1       cgd 		if (val || display)
    391   1.1       cgd 			*p++ = val + '0';
    392   1.1       cgd 		else
    393   1.1       cgd 			*p++ = ' ';
    394   1.1       cgd 		*p++ = day % 10 + '0';
    395   1.1       cgd 	} else {
    396   1.1       cgd 		*p++ = aday[day][0];
    397   1.1       cgd 		*p++ = aday[day][1];
    398   1.1       cgd 	}
    399   1.1       cgd 	*p = ' ';
    400   1.1       cgd }
    401   1.1       cgd 
    402   1.6     glass void
    403   1.1       cgd trim_trailing_spaces(s)
    404   1.6     glass 	char *s;
    405   1.1       cgd {
    406   1.6     glass 	char *p;
    407   1.1       cgd 
    408   1.6     glass 	for (p = s; *p; ++p)
    409   1.6     glass 		continue;
    410   1.6     glass 	while (p > s && isspace(*--p))
    411   1.6     glass 		continue;
    412   1.1       cgd 	if (p > s)
    413   1.1       cgd 		++p;
    414   1.1       cgd 	*p = '\0';
    415   1.1       cgd }
    416   1.1       cgd 
    417   1.6     glass void
    418   1.1       cgd center(str, len, separate)
    419   1.1       cgd 	char *str;
    420   1.6     glass 	int len;
    421   1.1       cgd 	int separate;
    422   1.1       cgd {
    423   1.6     glass 
    424   1.1       cgd 	len -= strlen(str);
    425   1.1       cgd 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
    426   1.1       cgd 	if (separate)
    427   1.1       cgd 		(void)printf("%*s", separate, "");
    428   1.1       cgd }
    429   1.1       cgd 
    430   1.6     glass void
    431   1.1       cgd usage()
    432   1.1       cgd {
    433   1.6     glass 
    434   1.1       cgd 	(void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
    435   1.1       cgd 	exit(1);
    436   1.1       cgd }
    437