Home | History | Annotate | Line # | Download | only in cal
cal.c revision 1.14
      1  1.14      yamt /*	$NetBSD: cal.c,v 1.14 2002/10/25 20:06:56 yamt 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.14      yamt __RCSID("$NetBSD: cal.c,v 1.14 2002/10/25 20:06:56 yamt 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.14      yamt #include <errno.h>
     58  1.14      yamt #include <limits.h>
     59   1.1       cgd #include <stdio.h>
     60   1.6     glass #include <stdlib.h>
     61   1.4       cgd #include <string.h>
     62   1.6     glass #include <time.h>
     63   1.8  christos #include <tzfile.h>
     64   1.6     glass #include <unistd.h>
     65   1.1       cgd 
     66   1.1       cgd #define	THURSDAY		4		/* for reformation */
     67   1.1       cgd #define	SATURDAY 		6		/* 1 Jan 1 was a Saturday */
     68   1.1       cgd 
     69   1.5        ws #define	FIRST_MISSING_DAY 	639799		/* 3 Sep 1752 */
     70   1.1       cgd #define	NUMBER_MISSING_DAYS 	11		/* 11 day correction */
     71   1.1       cgd 
     72   1.1       cgd #define	MAXDAYS			42		/* max slots in a month array */
     73   1.1       cgd #define	SPACE			-1		/* used in day array */
     74   1.1       cgd 
     75   1.1       cgd static int days_in_month[2][13] = {
     76   1.1       cgd 	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     77   1.1       cgd 	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     78   1.1       cgd };
     79   1.1       cgd 
     80   1.1       cgd int sep1752[MAXDAYS] = {
     81   1.1       cgd 	SPACE,	SPACE,	1,	2,	14,	15,	16,
     82   1.1       cgd 	17,	18,	19,	20,	21,	22,	23,
     83   1.1       cgd 	24,	25,	26,	27,	28,	29,	30,
     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 }, j_sep1752[MAXDAYS] = {
     88   1.1       cgd 	SPACE,	SPACE,	245,	246,	258,	259,	260,
     89   1.1       cgd 	261,	262,	263,	264,	265,	266,	267,
     90   1.1       cgd 	268,	269,	270,	271,	272,	273,	274,
     91   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     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 }, empty[MAXDAYS] = {
     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 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
    100   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
    101   1.1       cgd };
    102   1.1       cgd 
    103   1.1       cgd char *month_names[12] = {
    104   1.1       cgd 	"January", "February", "March", "April", "May", "June",
    105   1.1       cgd 	"July", "August", "September", "October", "November", "December",
    106   1.1       cgd };
    107   1.1       cgd 
    108   1.1       cgd char *day_headings = " S  M Tu  W Th  F  S";
    109   1.1       cgd char *j_day_headings = "  S   M  Tu   W  Th   F   S";
    110   1.1       cgd 
    111   1.1       cgd /* leap year -- account for gregorian reformation in 1752 */
    112   1.1       cgd #define	leap_year(yr) \
    113   1.1       cgd 	((yr) <= 1752 ? !((yr) % 4) : \
    114   1.9        ws 	(!((yr) % 4) && ((yr) % 100)) || !((yr) % 400))
    115   1.1       cgd 
    116   1.1       cgd /* number of centuries since 1700, not inclusive */
    117   1.1       cgd #define	centuries_since_1700(yr) \
    118   1.1       cgd 	((yr) > 1700 ? (yr) / 100 - 17 : 0)
    119   1.1       cgd 
    120   1.1       cgd /* number of centuries since 1700 whose modulo of 400 is 0 */
    121   1.1       cgd #define	quad_centuries_since_1700(yr) \
    122   1.1       cgd 	((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
    123   1.1       cgd 
    124   1.1       cgd /* number of leap years between year 1 and this year, not inclusive */
    125   1.1       cgd #define	leap_years_since_year_1(yr) \
    126   1.1       cgd 	((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
    127   1.1       cgd 
    128   1.1       cgd int julian;
    129   1.1       cgd 
    130  1.14      yamt int	getnum(const char *);
    131  1.12     perry void	ascii_day(char *, int);
    132  1.12     perry void	center(char *, int, int);
    133  1.12     perry void	day_array(int, int, int *);
    134  1.12     perry int	day_in_week(int, int, int);
    135  1.12     perry int	day_in_year(int, int, int);
    136  1.14      yamt void	monthrange(int, int, int, int, int);
    137  1.12     perry int	main(int, char **);
    138  1.12     perry void	trim_trailing_spaces(char *);
    139  1.12     perry void	usage(void);
    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.14      yamt 	int ch, month, year, yflag;
    147  1.14      yamt 	int before, after;
    148  1.14      yamt 	int yearly = 0;
    149   1.1       cgd 
    150  1.14      yamt 	before = after = 0;
    151   1.7     lukem 	yflag = year = 0;
    152  1.14      yamt 	while ((ch = getopt(argc, argv, "A:B:jy3")) != -1) {
    153  1.12     perry 		switch (ch) {
    154  1.14      yamt 		case 'A':
    155  1.14      yamt 			after = getnum(optarg);
    156  1.14      yamt 			break;
    157  1.14      yamt 		case 'B':
    158  1.14      yamt 			before = getnum(optarg);
    159  1.14      yamt 			break;
    160   1.1       cgd 		case 'j':
    161   1.1       cgd 			julian = 1;
    162   1.1       cgd 			break;
    163   1.1       cgd 		case 'y':
    164   1.1       cgd 			yflag = 1;
    165   1.1       cgd 			break;
    166  1.13     perry 		case '3':
    167  1.14      yamt 			before = after = 1;
    168  1.13     perry 			break;
    169   1.1       cgd 		case '?':
    170   1.1       cgd 		default:
    171   1.1       cgd 			usage();
    172  1.12     perry 			/* NOTREACHED */
    173   1.1       cgd 		}
    174  1.12     perry 	}
    175  1.13     perry 
    176   1.1       cgd 	argc -= optind;
    177   1.1       cgd 	argv += optind;
    178   1.1       cgd 
    179   1.1       cgd 	month = 0;
    180  1.12     perry 	switch (argc) {
    181   1.1       cgd 	case 2:
    182   1.6     glass 		if ((month = atoi(*argv++)) < 1 || month > 12)
    183   1.6     glass 			errx(1, "illegal month value: use 1-12");
    184   1.1       cgd 		/* FALLTHROUGH */
    185   1.1       cgd 	case 1:
    186   1.6     glass 		if ((year = atoi(*argv)) < 1 || year > 9999)
    187   1.6     glass 			errx(1, "illegal year value: use 1-9999");
    188   1.1       cgd 		break;
    189   1.1       cgd 	case 0:
    190   1.1       cgd 		(void)time(&now);
    191   1.1       cgd 		local_time = localtime(&now);
    192   1.8  christos 		year = local_time->tm_year + TM_YEAR_BASE;
    193   1.1       cgd 		if (!yflag)
    194   1.1       cgd 			month = local_time->tm_mon + 1;
    195   1.1       cgd 		break;
    196   1.1       cgd 	default:
    197   1.1       cgd 		usage();
    198   1.1       cgd 	}
    199   1.1       cgd 
    200  1.14      yamt 	if (!month) {
    201  1.14      yamt 		/* yearly */
    202  1.14      yamt 		month = 1;
    203  1.14      yamt 		before = 0;
    204  1.14      yamt 		after = 11;
    205  1.14      yamt 		yearly = 1;
    206  1.14      yamt 	}
    207  1.14      yamt 
    208  1.14      yamt 	monthrange(month, year, before, after, yearly);
    209  1.13     perry 
    210   1.1       cgd 	exit(0);
    211   1.1       cgd }
    212   1.1       cgd 
    213   1.1       cgd #define	DAY_LEN		3		/* 3 spaces per day */
    214   1.1       cgd #define	J_DAY_LEN	4		/* 4 spaces per day */
    215   1.1       cgd #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
    216   1.1       cgd #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
    217   1.1       cgd #define	HEAD_SEP	2		/* spaces between day headings */
    218   1.1       cgd #define	J_HEAD_SEP	2
    219  1.14      yamt #define	MONTH_PER_ROW	3		/* how many monthes in a row */
    220  1.14      yamt #define	J_MONTH_PER_ROW	2
    221   1.1       cgd 
    222   1.6     glass void
    223  1.14      yamt monthrange(int month, int year, int before, int after, int yearly)
    224   1.1       cgd {
    225  1.14      yamt 	int startmonth, startyear;
    226  1.14      yamt 	int endmonth, endyear;
    227  1.14      yamt 	int i, row;
    228  1.14      yamt 	int days[3][MAXDAYS];
    229  1.14      yamt 	char lineout[80];
    230  1.14      yamt 	int inayear;
    231  1.14      yamt 	int newyear;
    232  1.14      yamt 	int day_len, week_len, head_sep;
    233  1.14      yamt 	int month_per_row;
    234  1.14      yamt 	int skip;
    235  1.14      yamt 
    236  1.14      yamt 	if (julian) {
    237  1.14      yamt 		day_len = J_DAY_LEN;
    238  1.14      yamt 		week_len = J_WEEK_LEN;
    239  1.14      yamt 		head_sep = J_HEAD_SEP;
    240  1.14      yamt 		month_per_row = J_MONTH_PER_ROW;
    241  1.14      yamt 	}
    242  1.14      yamt 	else {
    243  1.14      yamt 		day_len = DAY_LEN;
    244  1.14      yamt 		week_len = WEEK_LEN;
    245  1.14      yamt 		head_sep = HEAD_SEP;
    246  1.14      yamt 		month_per_row = MONTH_PER_ROW;
    247  1.14      yamt 	}
    248  1.14      yamt 
    249  1.14      yamt 	month--;
    250  1.14      yamt 
    251  1.14      yamt 	startyear = year - (before + 12 - 1 - month) / 12;
    252  1.14      yamt 	startmonth = 12 - 1 - ((before + 12 - 1 - month) % 12);
    253  1.14      yamt 	endyear = year + (month + after) / 12;
    254  1.14      yamt 	endmonth = (month + after) % 12;
    255   1.1       cgd 
    256  1.14      yamt 	if (startyear < 0 || endyear > 9999) {
    257  1.14      yamt 		errx(1, "year should be in 1-9999\n");
    258   1.1       cgd 	}
    259   1.1       cgd 
    260  1.14      yamt 	year = startyear;
    261  1.14      yamt 	month = startmonth;
    262  1.14      yamt 	inayear = newyear = (year != endyear || yearly);
    263  1.14      yamt 	if (inayear) {
    264  1.14      yamt 		skip = month % month_per_row;
    265  1.14      yamt 		month -= skip;
    266  1.14      yamt 	}
    267  1.14      yamt 	else {
    268  1.14      yamt 		skip = 0;
    269  1.14      yamt 	}
    270  1.14      yamt 
    271  1.14      yamt 	do {
    272  1.14      yamt 		if (newyear) {
    273  1.14      yamt 			(void)snprintf(lineout, sizeof(lineout), "%d", year);
    274  1.14      yamt 			center(lineout, week_len * month_per_row +
    275  1.14      yamt 			    head_sep * (month_per_row - 1), 0);
    276  1.14      yamt 			(void)printf("\n\n");
    277  1.14      yamt 			newyear = 0;
    278  1.14      yamt 		}
    279  1.14      yamt 
    280  1.14      yamt 		for (i = 0; i < skip; i++)
    281  1.14      yamt 			center("", week_len, head_sep);
    282  1.14      yamt 
    283  1.14      yamt 		for (; i < month_per_row; i++) {
    284  1.14      yamt 			int sep;
    285  1.14      yamt 
    286  1.14      yamt 			if (year == endyear && month + i > endmonth)
    287  1.14      yamt 				break;
    288  1.14      yamt 
    289  1.14      yamt 			sep = (i == month_per_row - 1) ? 0 : head_sep;
    290  1.14      yamt 			day_array(month + i + 1, year, days[i]);
    291  1.14      yamt 			if (inayear) {
    292  1.14      yamt 				center(month_names[month + i], week_len, sep);
    293  1.14      yamt 			}
    294  1.14      yamt 			else {
    295  1.14      yamt 				snprintf(lineout, sizeof(lineout), "%s %d",
    296  1.14      yamt 				    month_names[month + i], year);
    297  1.14      yamt 				center(lineout, week_len, sep);
    298   1.1       cgd 			}
    299   1.1       cgd 		}
    300  1.14      yamt 		printf("\n");
    301  1.14      yamt 
    302  1.14      yamt 		for (i = 0; i < skip; i++)
    303  1.14      yamt 			center("", week_len, head_sep);
    304  1.14      yamt 
    305  1.14      yamt 		for (; i < month_per_row; i++) {
    306  1.14      yamt 			int sep;
    307  1.14      yamt 
    308  1.14      yamt 			if (year == endyear && month + i > endmonth)
    309  1.14      yamt 				break;
    310  1.14      yamt 
    311  1.14      yamt 			sep = (i == month_per_row - 1) ? 0 : head_sep;
    312  1.14      yamt 			printf("%s%*s",
    313  1.14      yamt 			    (julian) ? j_day_headings : day_headings, sep, "");
    314  1.14      yamt 		}
    315  1.14      yamt 		printf("\n");
    316   1.1       cgd 
    317  1.14      yamt 		memset(lineout, ' ', sizeof(lineout));
    318   1.1       cgd 		for (row = 0; row < 6; row++) {
    319  1.14      yamt 			char *p;
    320  1.14      yamt 			for (i = 0; i < skip; i++) {
    321  1.14      yamt 				p = lineout + i * (week_len + 2);
    322  1.14      yamt 				memset(p, ' ', week_len);
    323  1.14      yamt 			}
    324  1.14      yamt 			for (; i < month_per_row; i++) {
    325  1.14      yamt 				int col, *dp;
    326  1.14      yamt 
    327  1.14      yamt 				if (year == endyear && month + i > endmonth)
    328  1.14      yamt 					break;
    329  1.14      yamt 
    330  1.14      yamt 				p = lineout + i * (week_len + 2);
    331  1.14      yamt 				dp = &days[i][row * 7];
    332  1.14      yamt 				for (col = 0; col < 7; col++, p += day_len)
    333   1.1       cgd 					ascii_day(p, *dp++);
    334   1.1       cgd 			}
    335   1.3       cgd 			*p = '\0';
    336   1.1       cgd 			trim_trailing_spaces(lineout);
    337   1.1       cgd 			(void)printf("%s\n", lineout);
    338   1.1       cgd 		}
    339  1.13     perry 
    340  1.14      yamt 		skip = 0;
    341  1.14      yamt 		month += month_per_row;
    342  1.14      yamt 		if (month >= 12) {
    343  1.14      yamt 			month -= 12;
    344  1.14      yamt 			year++;
    345  1.14      yamt 			newyear = 1;
    346  1.13     perry 		}
    347  1.14      yamt 	} while (year < endyear || (year == endyear && month <= endmonth));
    348  1.13     perry }
    349  1.13     perry 
    350   1.1       cgd /*
    351   1.1       cgd  * day_array --
    352   1.1       cgd  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
    353   1.1       cgd  *	that you took the (maximum) 6 rows in a calendar and stretched them
    354   1.1       cgd  *	out end to end.  You would have 42 numbers or spaces.  This routine
    355   1.1       cgd  *	builds that array for any month from Jan. 1 through Dec. 9999.
    356   1.1       cgd  */
    357   1.6     glass void
    358  1.12     perry day_array(int month, int year, int *days)
    359   1.1       cgd {
    360   1.6     glass 	int day, dw, dm;
    361   1.1       cgd 
    362   1.1       cgd 	if (month == 9 && year == 1752) {
    363   1.6     glass 		memmove(days,
    364   1.6     glass 			julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
    365   1.1       cgd 		return;
    366   1.1       cgd 	}
    367   1.6     glass 	memmove(days, empty, MAXDAYS * sizeof(int));
    368   1.1       cgd 	dm = days_in_month[leap_year(year)][month];
    369   1.1       cgd 	dw = day_in_week(1, month, year);
    370   1.1       cgd 	day = julian ? day_in_year(1, month, year) : 1;
    371   1.1       cgd 	while (dm--)
    372   1.1       cgd 		days[dw++] = day++;
    373   1.1       cgd }
    374   1.1       cgd 
    375   1.1       cgd /*
    376   1.1       cgd  * day_in_year --
    377   1.1       cgd  *	return the 1 based day number within the year
    378   1.1       cgd  */
    379   1.6     glass int
    380  1.12     perry day_in_year(int day, int month, int year)
    381   1.1       cgd {
    382   1.6     glass 	int i, leap;
    383   1.1       cgd 
    384   1.1       cgd 	leap = leap_year(year);
    385   1.1       cgd 	for (i = 1; i < month; i++)
    386   1.1       cgd 		day += days_in_month[leap][i];
    387   1.6     glass 	return (day);
    388   1.1       cgd }
    389   1.1       cgd 
    390   1.1       cgd /*
    391   1.1       cgd  * day_in_week
    392   1.1       cgd  *	return the 0 based day number for any date from 1 Jan. 1 to
    393   1.1       cgd  *	31 Dec. 9999.  Assumes the Gregorian reformation eliminates
    394   1.1       cgd  *	3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
    395   1.1       cgd  *	missing days.
    396   1.1       cgd  */
    397   1.6     glass int
    398  1.12     perry day_in_week(int day, int month, int year)
    399   1.1       cgd {
    400   1.1       cgd 	long temp;
    401   1.1       cgd 
    402   1.1       cgd 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
    403   1.1       cgd 	    + day_in_year(day, month, year);
    404   1.1       cgd 	if (temp < FIRST_MISSING_DAY)
    405   1.6     glass 		return ((temp - 1 + SATURDAY) % 7);
    406   1.1       cgd 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
    407   1.6     glass 		return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
    408   1.6     glass 	return (THURSDAY);
    409   1.1       cgd }
    410   1.1       cgd 
    411   1.6     glass void
    412  1.12     perry ascii_day(char *p, int day)
    413   1.1       cgd {
    414   1.6     glass 	int display, val;
    415   1.1       cgd 	static char *aday[] = {
    416   1.1       cgd 		"",
    417   1.1       cgd 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
    418   1.1       cgd 		" 8", " 9", "10", "11", "12", "13", "14",
    419   1.1       cgd 		"15", "16", "17", "18", "19", "20", "21",
    420   1.1       cgd 		"22", "23", "24", "25", "26", "27", "28",
    421   1.1       cgd 		"29", "30", "31",
    422   1.1       cgd 	};
    423   1.1       cgd 
    424   1.1       cgd 	if (day == SPACE) {
    425   1.1       cgd 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
    426   1.1       cgd 		return;
    427   1.1       cgd 	}
    428   1.1       cgd 	if (julian) {
    429   1.7     lukem 		if ((val = day / 100) != 0) {
    430   1.1       cgd 			day %= 100;
    431   1.1       cgd 			*p++ = val + '0';
    432   1.1       cgd 			display = 1;
    433   1.1       cgd 		} else {
    434   1.1       cgd 			*p++ = ' ';
    435   1.1       cgd 			display = 0;
    436   1.1       cgd 		}
    437   1.1       cgd 		val = day / 10;
    438   1.1       cgd 		if (val || display)
    439   1.1       cgd 			*p++ = val + '0';
    440   1.1       cgd 		else
    441   1.1       cgd 			*p++ = ' ';
    442   1.1       cgd 		*p++ = day % 10 + '0';
    443   1.1       cgd 	} else {
    444   1.1       cgd 		*p++ = aday[day][0];
    445   1.1       cgd 		*p++ = aday[day][1];
    446   1.1       cgd 	}
    447   1.1       cgd 	*p = ' ';
    448   1.1       cgd }
    449   1.1       cgd 
    450   1.6     glass void
    451  1.12     perry trim_trailing_spaces(char *s)
    452   1.1       cgd {
    453   1.6     glass 	char *p;
    454   1.1       cgd 
    455   1.6     glass 	for (p = s; *p; ++p)
    456   1.6     glass 		continue;
    457  1.11  christos 	while (p > s && isspace((unsigned char)*--p))
    458   1.6     glass 		continue;
    459   1.1       cgd 	if (p > s)
    460   1.1       cgd 		++p;
    461   1.1       cgd 	*p = '\0';
    462   1.1       cgd }
    463   1.1       cgd 
    464   1.6     glass void
    465  1.12     perry center(char *str, int len, int separate)
    466   1.1       cgd {
    467   1.6     glass 
    468   1.1       cgd 	len -= strlen(str);
    469   1.1       cgd 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
    470   1.1       cgd 	if (separate)
    471   1.1       cgd 		(void)printf("%*s", separate, "");
    472   1.1       cgd }
    473   1.1       cgd 
    474  1.14      yamt int
    475  1.14      yamt getnum(const char *p)
    476  1.14      yamt {
    477  1.14      yamt 	long result;
    478  1.14      yamt 	char *ep;
    479  1.14      yamt 
    480  1.14      yamt 	errno = 0;
    481  1.14      yamt 	result = strtoul(p, &ep, 10);
    482  1.14      yamt 	if (p[0] == '\0' || *ep != '\0')
    483  1.14      yamt 		goto error;
    484  1.14      yamt 	if (errno == ERANGE && result == ULONG_MAX)
    485  1.14      yamt 		goto error;
    486  1.14      yamt 	if (result > INT_MAX)
    487  1.14      yamt 		goto error;
    488  1.14      yamt 
    489  1.14      yamt 	return (int)result;
    490  1.14      yamt 
    491  1.14      yamt error:
    492  1.14      yamt 	errx(1, "bad number: %s", p);
    493  1.14      yamt 	/*NOTREACHED*/
    494  1.14      yamt }
    495  1.14      yamt 
    496   1.6     glass void
    497  1.12     perry usage(void)
    498   1.1       cgd {
    499   1.6     glass 
    500  1.14      yamt 	(void)fprintf(stderr,
    501  1.14      yamt 	    "usage: cal [-jy3] [-B before] [-A after] [[month] year]\n");
    502   1.1       cgd 	exit(1);
    503   1.1       cgd }
    504