Home | History | Annotate | Line # | Download | only in cal
cal.c revision 1.6
      1  1.6  glass /*	$NetBSD: cal.c,v 1.6 1995/03/26 03:10:24 glass 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.1    cgd #ifndef lint
     40  1.6  glass static char copyright[] =
     41  1.6  glass "@(#) Copyright (c) 1989, 1993, 1994\n\
     42  1.6  glass 	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.6  glass static char rcsid[] = "$NetBSD: cal.c,v 1.6 1995/03/26 03:10:24 glass 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.6  glass #include <unistd.h>
     62  1.1    cgd 
     63  1.1    cgd #define	THURSDAY		4		/* for reformation */
     64  1.1    cgd #define	SATURDAY 		6		/* 1 Jan 1 was a Saturday */
     65  1.1    cgd 
     66  1.5     ws #define	FIRST_MISSING_DAY 	639799		/* 3 Sep 1752 */
     67  1.1    cgd #define	NUMBER_MISSING_DAYS 	11		/* 11 day correction */
     68  1.1    cgd 
     69  1.1    cgd #define	MAXDAYS			42		/* max slots in a month array */
     70  1.1    cgd #define	SPACE			-1		/* used in day array */
     71  1.1    cgd 
     72  1.1    cgd static int days_in_month[2][13] = {
     73  1.1    cgd 	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     74  1.1    cgd 	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     75  1.1    cgd };
     76  1.1    cgd 
     77  1.1    cgd int sep1752[MAXDAYS] = {
     78  1.1    cgd 	SPACE,	SPACE,	1,	2,	14,	15,	16,
     79  1.1    cgd 	17,	18,	19,	20,	21,	22,	23,
     80  1.1    cgd 	24,	25,	26,	27,	28,	29,	30,
     81  1.1    cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     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 }, j_sep1752[MAXDAYS] = {
     85  1.1    cgd 	SPACE,	SPACE,	245,	246,	258,	259,	260,
     86  1.1    cgd 	261,	262,	263,	264,	265,	266,	267,
     87  1.1    cgd 	268,	269,	270,	271,	272,	273,	274,
     88  1.1    cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     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 }, empty[MAXDAYS] = {
     92  1.1    cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     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 };
     99  1.1    cgd 
    100  1.1    cgd char *month_names[12] = {
    101  1.1    cgd 	"January", "February", "March", "April", "May", "June",
    102  1.1    cgd 	"July", "August", "September", "October", "November", "December",
    103  1.1    cgd };
    104  1.1    cgd 
    105  1.1    cgd char *day_headings = " S  M Tu  W Th  F  S";
    106  1.1    cgd char *j_day_headings = "  S   M  Tu   W  Th   F   S";
    107  1.1    cgd 
    108  1.1    cgd /* leap year -- account for gregorian reformation in 1752 */
    109  1.1    cgd #define	leap_year(yr) \
    110  1.1    cgd 	((yr) <= 1752 ? !((yr) % 4) : \
    111  1.1    cgd 	!((yr) % 4) && ((yr) % 100) || !((yr) % 400))
    112  1.1    cgd 
    113  1.1    cgd /* number of centuries since 1700, not inclusive */
    114  1.1    cgd #define	centuries_since_1700(yr) \
    115  1.1    cgd 	((yr) > 1700 ? (yr) / 100 - 17 : 0)
    116  1.1    cgd 
    117  1.1    cgd /* number of centuries since 1700 whose modulo of 400 is 0 */
    118  1.1    cgd #define	quad_centuries_since_1700(yr) \
    119  1.1    cgd 	((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
    120  1.1    cgd 
    121  1.1    cgd /* number of leap years between year 1 and this year, not inclusive */
    122  1.1    cgd #define	leap_years_since_year_1(yr) \
    123  1.1    cgd 	((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
    124  1.1    cgd 
    125  1.1    cgd int julian;
    126  1.1    cgd 
    127  1.6  glass void	ascii_day __P((char *, int));
    128  1.6  glass void	center __P((char *, int, int));
    129  1.6  glass void	day_array __P((int, int, int *));
    130  1.6  glass int	day_in_week __P((int, int, int));
    131  1.6  glass int	day_in_year __P((int, int, int));
    132  1.6  glass void	j_yearly __P((int));
    133  1.6  glass void	monthly __P((int, int));
    134  1.6  glass void	trim_trailing_spaces __P((char *));
    135  1.6  glass void	usage __P((void));
    136  1.6  glass void	yearly __P((int));
    137  1.6  glass 
    138  1.6  glass int
    139  1.1    cgd main(argc, argv)
    140  1.1    cgd 	int argc;
    141  1.1    cgd 	char **argv;
    142  1.1    cgd {
    143  1.1    cgd 	struct tm *local_time;
    144  1.6  glass 	time_t now;
    145  1.1    cgd 	int ch, month, year, yflag;
    146  1.1    cgd 
    147  1.1    cgd 	yflag = 0;
    148  1.1    cgd 	while ((ch = getopt(argc, argv, "jy")) != EOF)
    149  1.1    cgd 		switch(ch) {
    150  1.1    cgd 		case 'j':
    151  1.1    cgd 			julian = 1;
    152  1.1    cgd 			break;
    153  1.1    cgd 		case 'y':
    154  1.1    cgd 			yflag = 1;
    155  1.1    cgd 			break;
    156  1.1    cgd 		case '?':
    157  1.1    cgd 		default:
    158  1.1    cgd 			usage();
    159  1.1    cgd 		}
    160  1.1    cgd 	argc -= optind;
    161  1.1    cgd 	argv += optind;
    162  1.1    cgd 
    163  1.1    cgd 	month = 0;
    164  1.1    cgd 	switch(argc) {
    165  1.1    cgd 	case 2:
    166  1.6  glass 		if ((month = atoi(*argv++)) < 1 || month > 12)
    167  1.6  glass 			errx(1, "illegal month value: use 1-12");
    168  1.1    cgd 		/* FALLTHROUGH */
    169  1.1    cgd 	case 1:
    170  1.6  glass 		if ((year = atoi(*argv)) < 1 || year > 9999)
    171  1.6  glass 			errx(1, "illegal year value: use 1-9999");
    172  1.1    cgd 		break;
    173  1.1    cgd 	case 0:
    174  1.1    cgd 		(void)time(&now);
    175  1.1    cgd 		local_time = localtime(&now);
    176  1.1    cgd 		year = local_time->tm_year + 1900;
    177  1.1    cgd 		if (!yflag)
    178  1.1    cgd 			month = local_time->tm_mon + 1;
    179  1.1    cgd 		break;
    180  1.1    cgd 	default:
    181  1.1    cgd 		usage();
    182  1.1    cgd 	}
    183  1.1    cgd 
    184  1.1    cgd 	if (month)
    185  1.1    cgd 		monthly(month, year);
    186  1.1    cgd 	else if (julian)
    187  1.1    cgd 		j_yearly(year);
    188  1.1    cgd 	else
    189  1.1    cgd 		yearly(year);
    190  1.1    cgd 	exit(0);
    191  1.1    cgd }
    192  1.1    cgd 
    193  1.1    cgd #define	DAY_LEN		3		/* 3 spaces per day */
    194  1.1    cgd #define	J_DAY_LEN	4		/* 4 spaces per day */
    195  1.1    cgd #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
    196  1.1    cgd #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
    197  1.1    cgd #define	HEAD_SEP	2		/* spaces between day headings */
    198  1.1    cgd #define	J_HEAD_SEP	2
    199  1.1    cgd 
    200  1.6  glass void
    201  1.1    cgd monthly(month, year)
    202  1.1    cgd 	int month, year;
    203  1.1    cgd {
    204  1.6  glass 	int col, row, len, days[MAXDAYS];
    205  1.6  glass 	char *p, lineout[30];
    206  1.1    cgd 
    207  1.1    cgd 	day_array(month, year, days);
    208  1.1    cgd 	len = sprintf(lineout, "%s %d", month_names[month - 1], year);
    209  1.1    cgd 	(void)printf("%*s%s\n%s\n",
    210  1.1    cgd 	    ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
    211  1.1    cgd 	    lineout, julian ? j_day_headings : day_headings);
    212  1.1    cgd 	for (row = 0; row < 6; row++) {
    213  1.1    cgd 		for (col = 0, p = lineout; col < 7; col++,
    214  1.1    cgd 		    p += julian ? J_DAY_LEN : DAY_LEN)
    215  1.1    cgd 			ascii_day(p, days[row * 7 + col]);
    216  1.3    cgd 		*p = '\0';
    217  1.1    cgd 		trim_trailing_spaces(lineout);
    218  1.1    cgd 		(void)printf("%s\n", lineout);
    219  1.1    cgd 	}
    220  1.1    cgd }
    221  1.1    cgd 
    222  1.6  glass void
    223  1.1    cgd j_yearly(year)
    224  1.1    cgd 	int year;
    225  1.1    cgd {
    226  1.6  glass 	int col, *dp, i, month, row, which_cal;
    227  1.1    cgd 	int days[12][MAXDAYS];
    228  1.6  glass 	char *p, lineout[80];
    229  1.1    cgd 
    230  1.1    cgd 	(void)sprintf(lineout, "%d", year);
    231  1.1    cgd 	center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
    232  1.1    cgd 	(void)printf("\n\n");
    233  1.1    cgd 	for (i = 0; i < 12; i++)
    234  1.1    cgd 		day_array(i + 1, year, days[i]);
    235  1.1    cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    236  1.1    cgd 	lineout[sizeof(lineout) - 1] = '\0';
    237  1.1    cgd 	for (month = 0; month < 12; month += 2) {
    238  1.1    cgd 		center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
    239  1.1    cgd 		center(month_names[month + 1], J_WEEK_LEN, 0);
    240  1.1    cgd 		(void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
    241  1.1    cgd 		    j_day_headings);
    242  1.1    cgd 		for (row = 0; row < 6; row++) {
    243  1.1    cgd 			for (which_cal = 0; which_cal < 2; which_cal++) {
    244  1.1    cgd 				p = lineout + which_cal * (J_WEEK_LEN + 2);
    245  1.1    cgd 				dp = &days[month + which_cal][row * 7];
    246  1.1    cgd 				for (col = 0; col < 7; col++, p += J_DAY_LEN)
    247  1.1    cgd 					ascii_day(p, *dp++);
    248  1.1    cgd 			}
    249  1.3    cgd 			*p = '\0';
    250  1.1    cgd 			trim_trailing_spaces(lineout);
    251  1.1    cgd 			(void)printf("%s\n", lineout);
    252  1.1    cgd 		}
    253  1.1    cgd 	}
    254  1.1    cgd 	(void)printf("\n");
    255  1.1    cgd }
    256  1.1    cgd 
    257  1.6  glass void
    258  1.1    cgd yearly(year)
    259  1.1    cgd 	int year;
    260  1.1    cgd {
    261  1.6  glass 	int col, *dp, i, month, row, which_cal;
    262  1.1    cgd 	int days[12][MAXDAYS];
    263  1.6  glass 	char *p, lineout[80];
    264  1.1    cgd 
    265  1.1    cgd 	(void)sprintf(lineout, "%d", year);
    266  1.1    cgd 	center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
    267  1.1    cgd 	(void)printf("\n\n");
    268  1.1    cgd 	for (i = 0; i < 12; i++)
    269  1.1    cgd 		day_array(i + 1, year, days[i]);
    270  1.1    cgd 	(void)memset(lineout, ' ', sizeof(lineout) - 1);
    271  1.1    cgd 	lineout[sizeof(lineout) - 1] = '\0';
    272  1.1    cgd 	for (month = 0; month < 12; month += 3) {
    273  1.1    cgd 		center(month_names[month], WEEK_LEN, HEAD_SEP);
    274  1.1    cgd 		center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
    275  1.1    cgd 		center(month_names[month + 2], WEEK_LEN, 0);
    276  1.1    cgd 		(void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
    277  1.1    cgd 		    "", day_headings, HEAD_SEP, "", day_headings);
    278  1.1    cgd 		for (row = 0; row < 6; row++) {
    279  1.1    cgd 			for (which_cal = 0; which_cal < 3; which_cal++) {
    280  1.1    cgd 				p = lineout + which_cal * (WEEK_LEN + 2);
    281  1.1    cgd 				dp = &days[month + which_cal][row * 7];
    282  1.1    cgd 				for (col = 0; col < 7; col++, p += DAY_LEN)
    283  1.1    cgd 					ascii_day(p, *dp++);
    284  1.1    cgd 			}
    285  1.3    cgd 			*p = '\0';
    286  1.1    cgd 			trim_trailing_spaces(lineout);
    287  1.1    cgd 			(void)printf("%s\n", lineout);
    288  1.1    cgd 		}
    289  1.1    cgd 	}
    290  1.1    cgd 	(void)printf("\n");
    291  1.1    cgd }
    292  1.1    cgd 
    293  1.1    cgd /*
    294  1.1    cgd  * day_array --
    295  1.1    cgd  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
    296  1.1    cgd  *	that you took the (maximum) 6 rows in a calendar and stretched them
    297  1.1    cgd  *	out end to end.  You would have 42 numbers or spaces.  This routine
    298  1.1    cgd  *	builds that array for any month from Jan. 1 through Dec. 9999.
    299  1.1    cgd  */
    300  1.6  glass void
    301  1.1    cgd day_array(month, year, days)
    302  1.1    cgd 	int month, year;
    303  1.6  glass 	int *days;
    304  1.1    cgd {
    305  1.6  glass 	int day, dw, dm;
    306  1.1    cgd 
    307  1.1    cgd 	if (month == 9 && year == 1752) {
    308  1.6  glass 		memmove(days,
    309  1.6  glass 			julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
    310  1.1    cgd 		return;
    311  1.1    cgd 	}
    312  1.6  glass 	memmove(days, empty, MAXDAYS * sizeof(int));
    313  1.1    cgd 	dm = days_in_month[leap_year(year)][month];
    314  1.1    cgd 	dw = day_in_week(1, month, year);
    315  1.1    cgd 	day = julian ? day_in_year(1, month, year) : 1;
    316  1.1    cgd 	while (dm--)
    317  1.1    cgd 		days[dw++] = day++;
    318  1.1    cgd }
    319  1.1    cgd 
    320  1.1    cgd /*
    321  1.1    cgd  * day_in_year --
    322  1.1    cgd  *	return the 1 based day number within the year
    323  1.1    cgd  */
    324  1.6  glass int
    325  1.1    cgd day_in_year(day, month, year)
    326  1.6  glass 	int day, month, year;
    327  1.1    cgd {
    328  1.6  glass 	int i, leap;
    329  1.1    cgd 
    330  1.1    cgd 	leap = leap_year(year);
    331  1.1    cgd 	for (i = 1; i < month; i++)
    332  1.1    cgd 		day += days_in_month[leap][i];
    333  1.6  glass 	return (day);
    334  1.1    cgd }
    335  1.1    cgd 
    336  1.1    cgd /*
    337  1.1    cgd  * day_in_week
    338  1.1    cgd  *	return the 0 based day number for any date from 1 Jan. 1 to
    339  1.1    cgd  *	31 Dec. 9999.  Assumes the Gregorian reformation eliminates
    340  1.1    cgd  *	3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
    341  1.1    cgd  *	missing days.
    342  1.1    cgd  */
    343  1.6  glass int
    344  1.1    cgd day_in_week(day, month, year)
    345  1.1    cgd 	int day, month, year;
    346  1.1    cgd {
    347  1.1    cgd 	long temp;
    348  1.1    cgd 
    349  1.1    cgd 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
    350  1.1    cgd 	    + day_in_year(day, month, year);
    351  1.1    cgd 	if (temp < FIRST_MISSING_DAY)
    352  1.6  glass 		return ((temp - 1 + SATURDAY) % 7);
    353  1.1    cgd 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
    354  1.6  glass 		return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
    355  1.6  glass 	return (THURSDAY);
    356  1.1    cgd }
    357  1.1    cgd 
    358  1.6  glass void
    359  1.1    cgd ascii_day(p, day)
    360  1.6  glass 	char *p;
    361  1.6  glass 	int day;
    362  1.1    cgd {
    363  1.6  glass 	int display, val;
    364  1.1    cgd 	static char *aday[] = {
    365  1.1    cgd 		"",
    366  1.1    cgd 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
    367  1.1    cgd 		" 8", " 9", "10", "11", "12", "13", "14",
    368  1.1    cgd 		"15", "16", "17", "18", "19", "20", "21",
    369  1.1    cgd 		"22", "23", "24", "25", "26", "27", "28",
    370  1.1    cgd 		"29", "30", "31",
    371  1.1    cgd 	};
    372  1.1    cgd 
    373  1.1    cgd 	if (day == SPACE) {
    374  1.1    cgd 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
    375  1.1    cgd 		return;
    376  1.1    cgd 	}
    377  1.1    cgd 	if (julian) {
    378  1.1    cgd 		if (val = day / 100) {
    379  1.1    cgd 			day %= 100;
    380  1.1    cgd 			*p++ = val + '0';
    381  1.1    cgd 			display = 1;
    382  1.1    cgd 		} else {
    383  1.1    cgd 			*p++ = ' ';
    384  1.1    cgd 			display = 0;
    385  1.1    cgd 		}
    386  1.1    cgd 		val = day / 10;
    387  1.1    cgd 		if (val || display)
    388  1.1    cgd 			*p++ = val + '0';
    389  1.1    cgd 		else
    390  1.1    cgd 			*p++ = ' ';
    391  1.1    cgd 		*p++ = day % 10 + '0';
    392  1.1    cgd 	} else {
    393  1.1    cgd 		*p++ = aday[day][0];
    394  1.1    cgd 		*p++ = aday[day][1];
    395  1.1    cgd 	}
    396  1.1    cgd 	*p = ' ';
    397  1.1    cgd }
    398  1.1    cgd 
    399  1.6  glass void
    400  1.1    cgd trim_trailing_spaces(s)
    401  1.6  glass 	char *s;
    402  1.1    cgd {
    403  1.6  glass 	char *p;
    404  1.1    cgd 
    405  1.6  glass 	for (p = s; *p; ++p)
    406  1.6  glass 		continue;
    407  1.6  glass 	while (p > s && isspace(*--p))
    408  1.6  glass 		continue;
    409  1.1    cgd 	if (p > s)
    410  1.1    cgd 		++p;
    411  1.1    cgd 	*p = '\0';
    412  1.1    cgd }
    413  1.1    cgd 
    414  1.6  glass void
    415  1.1    cgd center(str, len, separate)
    416  1.1    cgd 	char *str;
    417  1.6  glass 	int len;
    418  1.1    cgd 	int separate;
    419  1.1    cgd {
    420  1.6  glass 
    421  1.1    cgd 	len -= strlen(str);
    422  1.1    cgd 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
    423  1.1    cgd 	if (separate)
    424  1.1    cgd 		(void)printf("%*s", separate, "");
    425  1.1    cgd }
    426  1.1    cgd 
    427  1.6  glass void
    428  1.1    cgd usage()
    429  1.1    cgd {
    430  1.6  glass 
    431  1.1    cgd 	(void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
    432  1.1    cgd 	exit(1);
    433  1.1    cgd }
    434