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