Home | History | Annotate | Line # | Download | only in cal
cal.c revision 1.28
      1  1.28  christos /*	$NetBSD: cal.c,v 1.28 2015/01/08 03:56:33 christos 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.18       agc  * 3. Neither the name of the University nor the names of its contributors
     19   1.1       cgd  *    may be used to endorse or promote products derived from this software
     20   1.1       cgd  *    without specific prior written permission.
     21   1.1       cgd  *
     22   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1       cgd  * SUCH DAMAGE.
     33   1.1       cgd  */
     34   1.1       cgd 
     35   1.7     lukem #include <sys/cdefs.h>
     36   1.1       cgd #ifndef lint
     37  1.24     lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
     38  1.24     lukem  The Regents of the University of California.  All rights reserved.");
     39   1.1       cgd #endif /* not lint */
     40   1.1       cgd 
     41   1.1       cgd #ifndef lint
     42   1.6     glass #if 0
     43   1.6     glass static char sccsid[] = "@(#)cal.c	8.4 (Berkeley) 4/2/94";
     44   1.6     glass #else
     45  1.28  christos __RCSID("$NetBSD: cal.c,v 1.28 2015/01/08 03:56:33 christos Exp $");
     46   1.6     glass #endif
     47   1.1       cgd #endif /* not lint */
     48   1.1       cgd 
     49   1.1       cgd #include <sys/types.h>
     50   1.6     glass 
     51   1.6     glass #include <ctype.h>
     52   1.6     glass #include <err.h>
     53  1.14      yamt #include <errno.h>
     54  1.14      yamt #include <limits.h>
     55   1.1       cgd #include <stdio.h>
     56   1.6     glass #include <stdlib.h>
     57   1.4       cgd #include <string.h>
     58  1.26       roy #include <term.h>
     59   1.6     glass #include <time.h>
     60   1.8  christos #include <tzfile.h>
     61   1.6     glass #include <unistd.h>
     62   1.1       cgd 
     63   1.1       cgd #define	SATURDAY 		6		/* 1 Jan 1 was a Saturday */
     64   1.1       cgd 
     65  1.17    atatat #define	FIRST_MISSING_DAY 	reform->first_missing_day
     66  1.17    atatat #define	NUMBER_MISSING_DAYS 	reform->missing_days
     67   1.1       cgd 
     68   1.1       cgd #define	MAXDAYS			42		/* max slots in a month array */
     69   1.1       cgd #define	SPACE			-1		/* used in day array */
     70   1.1       cgd 
     71   1.1       cgd static int days_in_month[2][13] = {
     72   1.1       cgd 	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     73   1.1       cgd 	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
     74   1.1       cgd };
     75   1.1       cgd 
     76  1.27     joerg static int empty[MAXDAYS] = {
     77   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     78   1.1       cgd 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     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 	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,	SPACE,
     83   1.1       cgd };
     84  1.27     joerg static int shift_days[2][4][MAXDAYS + 1];
     85   1.1       cgd 
     86  1.27     joerg static const char *month_names[12] = {
     87   1.1       cgd 	"January", "February", "March", "April", "May", "June",
     88   1.1       cgd 	"July", "August", "September", "October", "November", "December",
     89   1.1       cgd };
     90   1.1       cgd 
     91  1.27     joerg static const char *day_headings = " S  M Tu  W Th  F  S";
     92  1.27     joerg static const char *j_day_headings = "  S   M  Tu   W  Th   F   S";
     93   1.1       cgd 
     94  1.17    atatat /* leap years according to the julian calendar */
     95  1.17    atatat #define j_leap_year(y, m, d) \
     96  1.17    atatat 	(((m) > 2) && \
     97  1.17    atatat 	 !((y) % 4))
     98  1.17    atatat 
     99  1.17    atatat /* leap years according to the gregorian calendar */
    100  1.17    atatat #define g_leap_year(y, m, d) \
    101  1.17    atatat 	(((m) > 2) && \
    102  1.17    atatat 	 ((!((y) % 4) && ((y) % 100)) || \
    103  1.17    atatat 	  !((y) % 400)))
    104  1.17    atatat 
    105  1.17    atatat /* leap year -- account for gregorian reformation at some point */
    106   1.1       cgd #define	leap_year(yr) \
    107  1.17    atatat 	((yr) <= reform->year ? j_leap_year((yr), 3, 1) : \
    108  1.17    atatat 	g_leap_year((yr), 3, 1))
    109   1.1       cgd 
    110  1.17    atatat /* number of julian leap days that have passed by a given date */
    111  1.17    atatat #define j_leap_days(y, m, d) \
    112  1.17    atatat 	((((y) - 1) / 4) + j_leap_year(y, m, d))
    113  1.17    atatat 
    114  1.17    atatat /* number of gregorian leap days that have passed by a given date */
    115  1.17    atatat #define g_leap_days(y, m, d) \
    116  1.17    atatat 	((((y) - 1) / 4) - (((y) - 1) / 100) + (((y) - 1) / 400) + \
    117  1.17    atatat 	g_leap_year(y, m, d))
    118  1.17    atatat 
    119  1.17    atatat /*
    120  1.17    atatat  * Subtracting the gregorian leap day count (for a given date) from
    121  1.17    atatat  * the julian leap day count (for the same date) describes the number
    122  1.17    atatat  * of days from the date before the shift to the next date that
    123  1.17    atatat  * appears in the calendar.  Since we want to know the number of
    124  1.17    atatat  * *missing* days, not the number of days that the shift spans, we
    125  1.17    atatat  * subtract 2.
    126  1.17    atatat  *
    127  1.17    atatat  * Alternately...
    128  1.17    atatat  *
    129  1.17    atatat  * There's a reason they call the Dark ages the Dark Ages.  Part of it
    130  1.17    atatat  * is that we don't have that many records of that period of time.
    131  1.17    atatat  * One of the reasons for this is that a lot of the Dark Ages never
    132  1.17    atatat  * actually took place.  At some point in the first millenium A.D., a
    133  1.17    atatat  * ruler of some power decided that he wanted the number of the year
    134  1.17    atatat  * to be different than what it was, so he changed it to coincide
    135  1.17    atatat  * nicely with some event (a birthday or anniversary, perhaps a
    136  1.17    atatat  * wedding, or maybe a centennial for a largish city).  One of the
    137  1.17    atatat  * side effects of this upon the Gregorian reform is that two Julian
    138  1.17    atatat  * leap years (leap days celebrated during centennial years that are
    139  1.17    atatat  * not quatro-centennial years) were skipped.
    140  1.17    atatat  */
    141  1.17    atatat #define GREGORIAN_MAGIC 2
    142  1.17    atatat 
    143  1.17    atatat /* number of centuries since the reform, not inclusive */
    144  1.17    atatat #define	centuries_since_reform(yr) \
    145  1.17    atatat 	((yr) > reform->year ? ((yr) / 100) - (reform->year / 100) : 0)
    146  1.17    atatat 
    147  1.17    atatat /* number of centuries since the reform whose modulo of 400 is 0 */
    148  1.17    atatat #define	quad_centuries_since_reform(yr) \
    149  1.17    atatat 	((yr) > reform->year ? ((yr) / 400) - (reform->year / 400) : 0)
    150   1.1       cgd 
    151   1.1       cgd /* number of leap years between year 1 and this year, not inclusive */
    152   1.1       cgd #define	leap_years_since_year_1(yr) \
    153  1.17    atatat 	((yr) / 4 - centuries_since_reform(yr) + quad_centuries_since_reform(yr))
    154  1.17    atatat 
    155  1.27     joerg static struct reform {
    156  1.17    atatat 	const char *country;
    157  1.17    atatat 	int ambiguity, year, month, date;
    158  1.17    atatat 	long first_missing_day;
    159  1.17    atatat 	int missing_days;
    160  1.17    atatat 	/*
    161  1.17    atatat 	 * That's 2 for standard/julian display, 4 for months possibly
    162  1.17    atatat 	 * affected by the Gregorian shift, and MAXDAYS + 1 for the
    163  1.17    atatat 	 * days that get displayed, plus a crib slot.
    164  1.17    atatat 	 */
    165  1.17    atatat } *reform, reforms[] = {
    166  1.25     lukem 	{ "DEFAULT",		0, 1752,  9,  3, 0, 0 },
    167  1.25     lukem 	{ "Italy",		1, 1582, 10,  5, 0, 0 },
    168  1.25     lukem 	{ "Spain",		1, 1582, 10,  5, 0, 0 },
    169  1.25     lukem 	{ "Portugal",		1, 1582, 10,  5, 0, 0 },
    170  1.25     lukem 	{ "Poland",		1, 1582, 10,  5, 0, 0 },
    171  1.25     lukem 	{ "France",		2, 1582, 12, 10, 0, 0 },
    172  1.25     lukem 	{ "Luxembourg",		2, 1582, 12, 22, 0, 0 },
    173  1.25     lukem 	{ "Netherlands",	2, 1582, 12, 22, 0, 0 },
    174  1.25     lukem 	{ "Bavaria",		0, 1583, 10,  6, 0, 0 },
    175  1.25     lukem 	{ "Austria",		2, 1584,  1,  7, 0, 0 },
    176  1.25     lukem 	{ "Switzerland",	2, 1584,  1, 12, 0, 0 },
    177  1.25     lukem 	{ "Hungary",		0, 1587, 10, 22, 0, 0 },
    178  1.25     lukem 	{ "Germany",		0, 1700,  2, 19, 0, 0 },
    179  1.25     lukem 	{ "Norway",		0, 1700,  2, 19, 0, 0 },
    180  1.25     lukem 	{ "Denmark",		0, 1700,  2, 19, 0, 0 },
    181  1.25     lukem 	{ "Great Britain",	0, 1752,  9,  3, 0, 0 },
    182  1.25     lukem 	{ "England",		0, 1752,  9,  3, 0, 0 },
    183  1.25     lukem 	{ "America",		0, 1752,  9,  3, 0, 0 },
    184  1.25     lukem 	{ "Sweden",		0, 1753,  2, 18, 0, 0 },
    185  1.25     lukem 	{ "Finland",		0, 1753,  2, 18, 0, 0 },
    186  1.25     lukem 	{ "Japan",		0, 1872, 12, 20, 0, 0 },
    187  1.25     lukem 	{ "China",		0, 1911, 11,  7, 0, 0 },
    188  1.25     lukem 	{ "Bulgaria",		0, 1916,  4,  1, 0, 0 },
    189  1.25     lukem 	{ "U.S.S.R.",		0, 1918,  2,  1, 0, 0 },
    190  1.25     lukem 	{ "Serbia",		0, 1919,  1, 19, 0, 0 },
    191  1.25     lukem 	{ "Romania",		0, 1919,  1, 19, 0, 0 },
    192  1.25     lukem 	{ "Greece",		0, 1924,  3, 10, 0, 0 },
    193  1.25     lukem 	{ "Turkey",		0, 1925, 12, 19, 0, 0 },
    194  1.25     lukem 	{ "Egypt",		0, 1928,  9, 18, 0, 0 },
    195  1.25     lukem 	{ NULL,			0,    0,  0,  0, 0, 0 },
    196  1.17    atatat };
    197   1.1       cgd 
    198  1.27     joerg static int julian;
    199  1.27     joerg static int dow;
    200  1.27     joerg static int hilite;
    201  1.27     joerg static const char *md, *me;
    202  1.27     joerg 
    203  1.27     joerg static void	init_hilite(void);
    204  1.27     joerg static int	getnum(const char *);
    205  1.27     joerg static void	gregorian_reform(const char *);
    206  1.27     joerg static void	reform_day_array(int, int, int *, int *, int *,int *,int *,int *);
    207  1.27     joerg static int	ascii_day(char *, int);
    208  1.27     joerg static void	center(const char *, int, int);
    209  1.27     joerg static void	day_array(int, int, int *);
    210  1.27     joerg static int	day_in_week(int, int, int);
    211  1.27     joerg static int	day_in_year(int, int, int);
    212  1.27     joerg static void	monthrange(int, int, int, int, int);
    213  1.27     joerg static void	trim_trailing_spaces(char *);
    214  1.27     joerg __dead static void	usage(void);
    215   1.6     glass 
    216   1.6     glass int
    217  1.12     perry main(int argc, char **argv)
    218   1.1       cgd {
    219   1.1       cgd 	struct tm *local_time;
    220   1.6     glass 	time_t now;
    221  1.20     joerg 	int ch, yflag;
    222  1.20     joerg 	long month, year;
    223  1.17    atatat 	int before, after, use_reform;
    224  1.14      yamt 	int yearly = 0;
    225  1.20     joerg 	char *when, *eoi;
    226   1.1       cgd 
    227  1.14      yamt 	before = after = 0;
    228  1.17    atatat 	use_reform = yflag = year = 0;
    229  1.17    atatat 	when = NULL;
    230  1.28  christos 	while ((ch = getopt(argc, argv, "A:B:C:d:hjR:ry3")) != -1) {
    231  1.12     perry 		switch (ch) {
    232  1.14      yamt 		case 'A':
    233  1.14      yamt 			after = getnum(optarg);
    234  1.23  dholland 			if (after < 0)
    235  1.23  dholland 				errx(1, "Argument to -A must be positive");
    236  1.14      yamt 			break;
    237  1.14      yamt 		case 'B':
    238  1.14      yamt 			before = getnum(optarg);
    239  1.23  dholland 			if (before < 0)
    240  1.23  dholland 				errx(1, "Argument to -B must be positive");
    241  1.14      yamt 			break;
    242  1.28  christos 		case 'C':
    243  1.28  christos 			after = before = getnum(optarg);
    244  1.28  christos 			if (after < 0)
    245  1.28  christos 				errx(1, "Argument to -C must be positive");
    246  1.28  christos 			break;
    247  1.17    atatat 		case 'd':
    248  1.17    atatat 			dow = getnum(optarg);
    249  1.17    atatat 			if (dow < 0 || dow > 6)
    250  1.17    atatat 				errx(1, "illegal day of week value: use 0-6");
    251  1.17    atatat 			break;
    252  1.15    atatat 		case 'h':
    253  1.15    atatat 			init_hilite();
    254  1.15    atatat 			break;
    255   1.1       cgd 		case 'j':
    256   1.1       cgd 			julian = 1;
    257   1.1       cgd 			break;
    258  1.17    atatat 		case 'R':
    259  1.17    atatat 			when = optarg;
    260  1.17    atatat 			break;
    261  1.17    atatat 		case 'r':
    262  1.17    atatat 			use_reform = 1;
    263  1.17    atatat 			break;
    264   1.1       cgd 		case 'y':
    265   1.1       cgd 			yflag = 1;
    266   1.1       cgd 			break;
    267  1.13     perry 		case '3':
    268  1.14      yamt 			before = after = 1;
    269  1.13     perry 			break;
    270   1.1       cgd 		case '?':
    271   1.1       cgd 		default:
    272   1.1       cgd 			usage();
    273  1.12     perry 			/* NOTREACHED */
    274   1.1       cgd 		}
    275  1.12     perry 	}
    276  1.13     perry 
    277   1.1       cgd 	argc -= optind;
    278   1.1       cgd 	argv += optind;
    279   1.1       cgd 
    280  1.17    atatat 	if (when != NULL)
    281  1.17    atatat 		gregorian_reform(when);
    282  1.17    atatat 	if (reform == NULL)
    283  1.17    atatat 		gregorian_reform("DEFAULT");
    284  1.17    atatat 
    285   1.1       cgd 	month = 0;
    286  1.12     perry 	switch (argc) {
    287   1.1       cgd 	case 2:
    288  1.20     joerg 		month = strtol(*argv++, &eoi, 10);
    289  1.20     joerg 		if (month < 1 || month > 12 || *eoi != '\0')
    290   1.6     glass 			errx(1, "illegal month value: use 1-12");
    291  1.20     joerg 		year = strtol(*argv, &eoi, 10);
    292  1.20     joerg 		if (year < 1 || year > 9999 || *eoi != '\0')
    293  1.20     joerg 			errx(1, "illegal year value: use 1-9999");
    294  1.20     joerg 		break;
    295   1.1       cgd 	case 1:
    296  1.20     joerg 		year = strtol(*argv, &eoi, 10);
    297  1.21     joerg 		if (year < 1 || year > 9999 || (*eoi != '\0' && *eoi != '/' && *eoi != '-'))
    298   1.6     glass 			errx(1, "illegal year value: use 1-9999");
    299  1.21     joerg 		if (*eoi != '\0') {
    300  1.20     joerg 			month = strtol(eoi + 1, &eoi, 10);
    301  1.20     joerg 			if (month < 1 || month > 12 || *eoi != '\0')
    302  1.20     joerg 				errx(1, "illegal month value: use 1-12");
    303  1.20     joerg 		}
    304   1.1       cgd 		break;
    305   1.1       cgd 	case 0:
    306   1.1       cgd 		(void)time(&now);
    307   1.1       cgd 		local_time = localtime(&now);
    308  1.17    atatat 		if (use_reform)
    309  1.17    atatat 			year = reform->year;
    310  1.17    atatat 		else
    311  1.17    atatat 			year = local_time->tm_year + TM_YEAR_BASE;
    312  1.17    atatat 		if (!yflag) {
    313  1.17    atatat 			if (use_reform)
    314  1.17    atatat 				month = reform->month;
    315  1.17    atatat 			else
    316  1.17    atatat 				month = local_time->tm_mon + 1;
    317  1.17    atatat 		}
    318   1.1       cgd 		break;
    319   1.1       cgd 	default:
    320   1.1       cgd 		usage();
    321   1.1       cgd 	}
    322   1.1       cgd 
    323  1.14      yamt 	if (!month) {
    324  1.14      yamt 		/* yearly */
    325  1.14      yamt 		month = 1;
    326  1.14      yamt 		before = 0;
    327  1.14      yamt 		after = 11;
    328  1.14      yamt 		yearly = 1;
    329  1.14      yamt 	}
    330  1.14      yamt 
    331  1.14      yamt 	monthrange(month, year, before, after, yearly);
    332  1.13     perry 
    333   1.1       cgd 	exit(0);
    334   1.1       cgd }
    335   1.1       cgd 
    336   1.1       cgd #define	DAY_LEN		3		/* 3 spaces per day */
    337   1.1       cgd #define	J_DAY_LEN	4		/* 4 spaces per day */
    338   1.1       cgd #define	WEEK_LEN	20		/* 7 * 3 - one space at the end */
    339   1.1       cgd #define	J_WEEK_LEN	27		/* 7 * 4 - one space at the end */
    340   1.1       cgd #define	HEAD_SEP	2		/* spaces between day headings */
    341   1.1       cgd #define	J_HEAD_SEP	2
    342  1.14      yamt #define	MONTH_PER_ROW	3		/* how many monthes in a row */
    343  1.14      yamt #define	J_MONTH_PER_ROW	2
    344   1.1       cgd 
    345  1.27     joerg static void
    346  1.14      yamt monthrange(int month, int year, int before, int after, int yearly)
    347   1.1       cgd {
    348  1.14      yamt 	int startmonth, startyear;
    349  1.14      yamt 	int endmonth, endyear;
    350  1.14      yamt 	int i, row;
    351  1.14      yamt 	int days[3][MAXDAYS];
    352  1.15    atatat 	char lineout[256];
    353  1.14      yamt 	int inayear;
    354  1.14      yamt 	int newyear;
    355  1.14      yamt 	int day_len, week_len, head_sep;
    356  1.14      yamt 	int month_per_row;
    357  1.15    atatat 	int skip, r_off, w_off;
    358  1.14      yamt 
    359  1.14      yamt 	if (julian) {
    360  1.14      yamt 		day_len = J_DAY_LEN;
    361  1.14      yamt 		week_len = J_WEEK_LEN;
    362  1.14      yamt 		head_sep = J_HEAD_SEP;
    363  1.14      yamt 		month_per_row = J_MONTH_PER_ROW;
    364  1.14      yamt 	}
    365  1.14      yamt 	else {
    366  1.14      yamt 		day_len = DAY_LEN;
    367  1.14      yamt 		week_len = WEEK_LEN;
    368  1.14      yamt 		head_sep = HEAD_SEP;
    369  1.14      yamt 		month_per_row = MONTH_PER_ROW;
    370  1.14      yamt 	}
    371  1.14      yamt 
    372  1.14      yamt 	month--;
    373  1.14      yamt 
    374  1.14      yamt 	startyear = year - (before + 12 - 1 - month) / 12;
    375  1.14      yamt 	startmonth = 12 - 1 - ((before + 12 - 1 - month) % 12);
    376  1.14      yamt 	endyear = year + (month + after) / 12;
    377  1.14      yamt 	endmonth = (month + after) % 12;
    378   1.1       cgd 
    379  1.14      yamt 	if (startyear < 0 || endyear > 9999) {
    380  1.14      yamt 		errx(1, "year should be in 1-9999\n");
    381   1.1       cgd 	}
    382   1.1       cgd 
    383  1.14      yamt 	year = startyear;
    384  1.14      yamt 	month = startmonth;
    385  1.14      yamt 	inayear = newyear = (year != endyear || yearly);
    386  1.14      yamt 	if (inayear) {
    387  1.14      yamt 		skip = month % month_per_row;
    388  1.14      yamt 		month -= skip;
    389  1.14      yamt 	}
    390  1.14      yamt 	else {
    391  1.14      yamt 		skip = 0;
    392  1.14      yamt 	}
    393  1.14      yamt 
    394  1.14      yamt 	do {
    395  1.14      yamt 		if (newyear) {
    396  1.14      yamt 			(void)snprintf(lineout, sizeof(lineout), "%d", year);
    397  1.14      yamt 			center(lineout, week_len * month_per_row +
    398  1.14      yamt 			    head_sep * (month_per_row - 1), 0);
    399  1.14      yamt 			(void)printf("\n\n");
    400  1.14      yamt 			newyear = 0;
    401  1.14      yamt 		}
    402  1.14      yamt 
    403  1.14      yamt 		for (i = 0; i < skip; i++)
    404  1.14      yamt 			center("", week_len, head_sep);
    405  1.14      yamt 
    406  1.14      yamt 		for (; i < month_per_row; i++) {
    407  1.14      yamt 			int sep;
    408  1.14      yamt 
    409  1.14      yamt 			if (year == endyear && month + i > endmonth)
    410  1.14      yamt 				break;
    411  1.14      yamt 
    412  1.14      yamt 			sep = (i == month_per_row - 1) ? 0 : head_sep;
    413  1.14      yamt 			day_array(month + i + 1, year, days[i]);
    414  1.14      yamt 			if (inayear) {
    415  1.14      yamt 				center(month_names[month + i], week_len, sep);
    416  1.14      yamt 			}
    417  1.14      yamt 			else {
    418  1.14      yamt 				snprintf(lineout, sizeof(lineout), "%s %d",
    419  1.14      yamt 				    month_names[month + i], year);
    420  1.14      yamt 				center(lineout, week_len, sep);
    421   1.1       cgd 			}
    422   1.1       cgd 		}
    423  1.14      yamt 		printf("\n");
    424  1.14      yamt 
    425  1.14      yamt 		for (i = 0; i < skip; i++)
    426  1.14      yamt 			center("", week_len, head_sep);
    427  1.14      yamt 
    428  1.14      yamt 		for (; i < month_per_row; i++) {
    429  1.14      yamt 			int sep;
    430  1.14      yamt 
    431  1.14      yamt 			if (year == endyear && month + i > endmonth)
    432  1.14      yamt 				break;
    433  1.14      yamt 
    434  1.14      yamt 			sep = (i == month_per_row - 1) ? 0 : head_sep;
    435  1.17    atatat 			if (dow) {
    436  1.17    atatat 				printf("%s ", (julian) ?
    437  1.17    atatat 				    j_day_headings + 4 * dow :
    438  1.17    atatat 				    day_headings + 3 * dow);
    439  1.17    atatat 				printf("%.*s", dow * (julian ? 4 : 3) - 1,
    440  1.17    atatat 				       (julian) ? j_day_headings : day_headings);
    441  1.17    atatat 			} else
    442  1.17    atatat 				printf("%s", (julian) ? j_day_headings : day_headings);
    443  1.17    atatat 			printf("%*s", sep, "");
    444  1.14      yamt 		}
    445  1.14      yamt 		printf("\n");
    446   1.1       cgd 
    447   1.1       cgd 		for (row = 0; row < 6; row++) {
    448  1.19     lukem 			char *p = NULL;
    449  1.16      yamt 
    450  1.16      yamt 			memset(lineout, ' ', sizeof(lineout));
    451  1.14      yamt 			for (i = 0; i < skip; i++) {
    452  1.16      yamt 				/* nothing */
    453  1.14      yamt 			}
    454  1.15    atatat 			w_off = 0;
    455  1.14      yamt 			for (; i < month_per_row; i++) {
    456  1.14      yamt 				int col, *dp;
    457  1.14      yamt 
    458  1.14      yamt 				if (year == endyear && month + i > endmonth)
    459  1.14      yamt 					break;
    460  1.14      yamt 
    461  1.15    atatat 				p = lineout + i * (week_len + 2) + w_off;
    462  1.14      yamt 				dp = &days[i][row * 7];
    463  1.15    atatat 				for (col = 0; col < 7;
    464  1.15    atatat 				     col++, p += day_len + r_off) {
    465  1.15    atatat 					r_off = ascii_day(p, *dp++);
    466  1.15    atatat 					w_off += r_off;
    467  1.15    atatat 				}
    468   1.1       cgd 			}
    469   1.3       cgd 			*p = '\0';
    470   1.1       cgd 			trim_trailing_spaces(lineout);
    471   1.1       cgd 			(void)printf("%s\n", lineout);
    472   1.1       cgd 		}
    473  1.13     perry 
    474  1.14      yamt 		skip = 0;
    475  1.14      yamt 		month += month_per_row;
    476  1.14      yamt 		if (month >= 12) {
    477  1.14      yamt 			month -= 12;
    478  1.14      yamt 			year++;
    479  1.14      yamt 			newyear = 1;
    480  1.13     perry 		}
    481  1.14      yamt 	} while (year < endyear || (year == endyear && month <= endmonth));
    482  1.13     perry }
    483  1.13     perry 
    484   1.1       cgd /*
    485   1.1       cgd  * day_array --
    486   1.1       cgd  *	Fill in an array of 42 integers with a calendar.  Assume for a moment
    487   1.1       cgd  *	that you took the (maximum) 6 rows in a calendar and stretched them
    488   1.1       cgd  *	out end to end.  You would have 42 numbers or spaces.  This routine
    489   1.1       cgd  *	builds that array for any month from Jan. 1 through Dec. 9999.
    490   1.1       cgd  */
    491  1.27     joerg static void
    492  1.12     perry day_array(int month, int year, int *days)
    493   1.1       cgd {
    494   1.6     glass 	int day, dw, dm;
    495  1.15    atatat 	time_t t;
    496  1.15    atatat 	struct tm *tm;
    497  1.15    atatat 
    498  1.15    atatat 	t = time(NULL);
    499  1.15    atatat 	tm = localtime(&t);
    500  1.15    atatat 	tm->tm_year += TM_YEAR_BASE;
    501  1.15    atatat 	tm->tm_mon++;
    502  1.15    atatat 	tm->tm_yday++; /* jan 1 is 1 for us, not 0 */
    503   1.1       cgd 
    504  1.17    atatat 	for (dm = month + year * 12, dw = 0; dw < 4; dw++) {
    505  1.17    atatat 		if (dm == shift_days[julian][dw][MAXDAYS]) {
    506  1.17    atatat 			memmove(days, shift_days[julian][dw],
    507  1.17    atatat 				MAXDAYS * sizeof(int));
    508  1.17    atatat 			return;
    509  1.17    atatat 		}
    510   1.1       cgd 	}
    511  1.17    atatat 
    512   1.6     glass 	memmove(days, empty, MAXDAYS * sizeof(int));
    513   1.1       cgd 	dm = days_in_month[leap_year(year)][month];
    514   1.1       cgd 	dw = day_in_week(1, month, year);
    515   1.1       cgd 	day = julian ? day_in_year(1, month, year) : 1;
    516  1.15    atatat 	while (dm--) {
    517  1.15    atatat 		if (hilite && year == tm->tm_year &&
    518  1.15    atatat 		    (julian ? (day == tm->tm_yday) :
    519  1.15    atatat 		     (month == tm->tm_mon && day == tm->tm_mday)))
    520  1.17    atatat 			days[dw++] = SPACE - day++;
    521  1.15    atatat 		else
    522  1.15    atatat 			days[dw++] = day++;
    523  1.15    atatat 	}
    524   1.1       cgd }
    525   1.1       cgd 
    526   1.1       cgd /*
    527   1.1       cgd  * day_in_year --
    528   1.1       cgd  *	return the 1 based day number within the year
    529   1.1       cgd  */
    530  1.27     joerg static int
    531  1.12     perry day_in_year(int day, int month, int year)
    532   1.1       cgd {
    533   1.6     glass 	int i, leap;
    534   1.1       cgd 
    535   1.1       cgd 	leap = leap_year(year);
    536   1.1       cgd 	for (i = 1; i < month; i++)
    537   1.1       cgd 		day += days_in_month[leap][i];
    538   1.6     glass 	return (day);
    539   1.1       cgd }
    540   1.1       cgd 
    541   1.1       cgd /*
    542   1.1       cgd  * day_in_week
    543   1.1       cgd  *	return the 0 based day number for any date from 1 Jan. 1 to
    544  1.17    atatat  *	31 Dec. 9999.  Returns the day of the week of the first
    545  1.17    atatat  *	missing day for any given Gregorian shift.
    546   1.1       cgd  */
    547  1.27     joerg static int
    548  1.12     perry day_in_week(int day, int month, int year)
    549   1.1       cgd {
    550   1.1       cgd 	long temp;
    551   1.1       cgd 
    552   1.1       cgd 	temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
    553   1.1       cgd 	    + day_in_year(day, month, year);
    554   1.1       cgd 	if (temp < FIRST_MISSING_DAY)
    555  1.17    atatat 		return ((temp - dow + 6 + SATURDAY) % 7);
    556   1.1       cgd 	if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
    557  1.17    atatat 		return (((temp - dow + 6 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
    558  1.17    atatat 	return ((FIRST_MISSING_DAY - dow + 6 + SATURDAY) % 7);
    559   1.1       cgd }
    560   1.1       cgd 
    561  1.27     joerg static int
    562  1.12     perry ascii_day(char *p, int day)
    563   1.1       cgd {
    564  1.15    atatat 	int display, val, rc;
    565  1.15    atatat 	char *b;
    566  1.25     lukem 	static const char *aday[] = {
    567   1.1       cgd 		"",
    568   1.1       cgd 		" 1", " 2", " 3", " 4", " 5", " 6", " 7",
    569   1.1       cgd 		" 8", " 9", "10", "11", "12", "13", "14",
    570   1.1       cgd 		"15", "16", "17", "18", "19", "20", "21",
    571   1.1       cgd 		"22", "23", "24", "25", "26", "27", "28",
    572   1.1       cgd 		"29", "30", "31",
    573   1.1       cgd 	};
    574   1.1       cgd 
    575   1.1       cgd 	if (day == SPACE) {
    576   1.1       cgd 		memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
    577  1.15    atatat 		return (0);
    578   1.1       cgd 	}
    579  1.17    atatat 	if (day < SPACE) {
    580  1.15    atatat 		b = p;
    581  1.17    atatat 		day = SPACE - day;
    582  1.15    atatat 	} else
    583  1.15    atatat 		b = NULL;
    584   1.1       cgd 	if (julian) {
    585   1.7     lukem 		if ((val = day / 100) != 0) {
    586   1.1       cgd 			day %= 100;
    587   1.1       cgd 			*p++ = val + '0';
    588   1.1       cgd 			display = 1;
    589   1.1       cgd 		} else {
    590   1.1       cgd 			*p++ = ' ';
    591   1.1       cgd 			display = 0;
    592   1.1       cgd 		}
    593   1.1       cgd 		val = day / 10;
    594   1.1       cgd 		if (val || display)
    595   1.1       cgd 			*p++ = val + '0';
    596   1.1       cgd 		else
    597   1.1       cgd 			*p++ = ' ';
    598   1.1       cgd 		*p++ = day % 10 + '0';
    599   1.1       cgd 	} else {
    600   1.1       cgd 		*p++ = aday[day][0];
    601   1.1       cgd 		*p++ = aday[day][1];
    602   1.1       cgd 	}
    603  1.15    atatat 
    604  1.15    atatat 	rc = 0;
    605  1.15    atatat 	if (b != NULL) {
    606  1.26       roy 		const char *t;
    607  1.26       roy 		char h[64];
    608  1.15    atatat 		int l;
    609  1.15    atatat 
    610  1.15    atatat 		l = p - b;
    611  1.15    atatat 		memcpy(h, b, l);
    612  1.15    atatat 		p = b;
    613  1.15    atatat 
    614  1.15    atatat 		if (md != NULL) {
    615  1.15    atatat 			for (t = md; *t; rc++)
    616  1.15    atatat 				*p++ = *t++;
    617  1.15    atatat 			memcpy(p, h, l);
    618  1.15    atatat 			p += l;
    619  1.15    atatat 			for (t = me; *t; rc++)
    620  1.15    atatat 				*p++ = *t++;
    621  1.15    atatat 		} else {
    622  1.15    atatat 			for (t = &h[0]; l--; t++) {
    623  1.15    atatat 				*p++ = *t;
    624  1.15    atatat 				rc++;
    625  1.15    atatat 				*p++ = '\b';
    626  1.15    atatat 				rc++;
    627  1.15    atatat 				*p++ = *t;
    628  1.15    atatat 			}
    629  1.15    atatat 		}
    630  1.15    atatat 	}
    631  1.15    atatat 
    632   1.1       cgd 	*p = ' ';
    633  1.15    atatat 	return (rc);
    634   1.1       cgd }
    635   1.1       cgd 
    636  1.27     joerg static void
    637  1.12     perry trim_trailing_spaces(char *s)
    638   1.1       cgd {
    639   1.6     glass 	char *p;
    640   1.1       cgd 
    641   1.6     glass 	for (p = s; *p; ++p)
    642   1.6     glass 		continue;
    643  1.11  christos 	while (p > s && isspace((unsigned char)*--p))
    644   1.6     glass 		continue;
    645   1.1       cgd 	if (p > s)
    646   1.1       cgd 		++p;
    647   1.1       cgd 	*p = '\0';
    648   1.1       cgd }
    649   1.1       cgd 
    650  1.27     joerg static void
    651  1.25     lukem center(const char *str, int len, int separate)
    652   1.1       cgd {
    653   1.6     glass 
    654   1.1       cgd 	len -= strlen(str);
    655   1.1       cgd 	(void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
    656   1.1       cgd 	if (separate)
    657   1.1       cgd 		(void)printf("%*s", separate, "");
    658   1.1       cgd }
    659   1.1       cgd 
    660  1.17    atatat /*
    661  1.17    atatat  * gregorian_reform --
    662  1.17    atatat  *	Given a description of date on which the Gregorian Reform was
    663  1.17    atatat  *	applied.  The argument can be any of the "country" names
    664  1.17    atatat  *	listed in the reforms array (case insensitive) or a date of
    665  1.17    atatat  *	the form YYYY/MM/DD.  The date and month can be omitted if
    666  1.17    atatat  *	doing so would not select more than one different built-in
    667  1.17    atatat  *	reform point.
    668  1.17    atatat  */
    669  1.27     joerg static void
    670  1.17    atatat gregorian_reform(const char *p)
    671  1.17    atatat {
    672  1.17    atatat 	int year, month, date;
    673  1.17    atatat 	int i, days, diw, diy;
    674  1.17    atatat 	char c;
    675  1.17    atatat 
    676  1.17    atatat 	i = sscanf(p, "%d%*[/,-]%d%*[/,-]%d%c", &year, &month, &date, &c);
    677  1.17    atatat 	switch (i) {
    678  1.17    atatat 	case 4:
    679  1.17    atatat 		/*
    680  1.17    atatat 		 * If the character was sscanf()ed, then there's more
    681  1.17    atatat 		 * stuff than we need.
    682  1.17    atatat 		 */
    683  1.17    atatat 		errx(1, "date specifier %s invalid", p);
    684  1.17    atatat 	case 0:
    685  1.17    atatat 		/*
    686  1.17    atatat 		 * Not a form we can sscanf(), so void these, and we
    687  1.17    atatat 		 * can try matching "country" names later.
    688  1.17    atatat 		 */
    689  1.17    atatat 		year = month = date = -1;
    690  1.17    atatat 		break;
    691  1.17    atatat 	case 1:
    692  1.17    atatat 		month = 0;
    693  1.17    atatat 		/*FALLTHROUGH*/
    694  1.17    atatat 	case 2:
    695  1.17    atatat 		date = 0;
    696  1.17    atatat 		/*FALLTHROUGH*/
    697  1.17    atatat 	    case 3:
    698  1.17    atatat 		/*
    699  1.17    atatat 		 * At last, some sanity checking on the values we were
    700  1.17    atatat 		 * given.
    701  1.17    atatat 		 */
    702  1.17    atatat 		if (year < 1 || year > 9999)
    703  1.17    atatat 			errx(1, "%d: illegal year value: use 1-9999", year);
    704  1.17    atatat 		if (i > 1 && (month < 1 || month > 12))
    705  1.17    atatat 			errx(1, "%d: illegal month value: use 1-12", month);
    706  1.17    atatat 		if ((i == 3 && date < 1) || date < 0 ||
    707  1.17    atatat 		    date > days_in_month[1][month])
    708  1.17    atatat 			/*
    709  1.17    atatat 			 * What about someone specifying a leap day in
    710  1.17    atatat 			 * a non-leap year?  Well...that's a tricky
    711  1.17    atatat 			 * one.  We can't yet *say* whether the year
    712  1.17    atatat 			 * in question is a leap year.  What if the
    713  1.17    atatat 			 * date given was, for example, 1700/2/29?  is
    714  1.17    atatat 			 * that a valid leap day?
    715  1.17    atatat 			 *
    716  1.17    atatat 			 * So...we punt, and hope that saying 29 in
    717  1.17    atatat 			 * the case of February isn't too bad an idea.
    718  1.17    atatat 			 */
    719  1.17    atatat 			errx(1, "%d: illegal date value: use 1-%d", date,
    720  1.17    atatat 			     days_in_month[1][month]);
    721  1.17    atatat 		break;
    722  1.17    atatat 	}
    723  1.17    atatat 
    724  1.17    atatat 	/*
    725  1.17    atatat 	 * A complete date was specified, so use the other pope.
    726  1.17    atatat 	 */
    727  1.17    atatat 	if (date > 0) {
    728  1.17    atatat 		static struct reform Goestheveezl;
    729  1.17    atatat 
    730  1.17    atatat 		reform = &Goestheveezl;
    731  1.17    atatat 		reform->country = "Bompzidaize";
    732  1.17    atatat 		reform->year = year;
    733  1.17    atatat 		reform->month = month;
    734  1.17    atatat 		reform->date = date;
    735  1.17    atatat 	}
    736  1.17    atatat 
    737  1.17    atatat 	/*
    738  1.17    atatat 	 * No date information was specified, so let's try to match on
    739  1.17    atatat 	 * country name.
    740  1.17    atatat 	 */
    741  1.17    atatat 	else if (year == -1) {
    742  1.17    atatat 		for (reform = &reforms[0]; reform->year; reform++) {
    743  1.17    atatat 			if (strcasecmp(p, reform->country) == 0)
    744  1.17    atatat 				break;
    745  1.17    atatat 		}
    746  1.17    atatat 	}
    747  1.17    atatat 
    748  1.17    atatat 	/*
    749  1.17    atatat 	 * We have *some* date information, but not a complete date.
    750  1.17    atatat 	 * Let's see if we have enough to pick a single entry from the
    751  1.17    atatat 	 * list that's not ambiguous.
    752  1.17    atatat 	 */
    753  1.17    atatat 	else {
    754  1.17    atatat 		for (reform = &reforms[0]; reform->year; reform++) {
    755  1.17    atatat 			if ((year == 0 || year == reform->year) &&
    756  1.17    atatat 			    (month == 0 || month == reform->month) &&
    757  1.17    atatat 			    (date == 0 || month == reform->date))
    758  1.17    atatat 				break;
    759  1.17    atatat 		}
    760  1.17    atatat 
    761  1.17    atatat 		if (i <= reform->ambiguity)
    762  1.17    atatat 			errx(1, "%s: ambiguous short reform date specification", p);
    763  1.17    atatat 	}
    764  1.17    atatat 
    765  1.17    atatat 	/*
    766  1.17    atatat 	 * Oops...we reached the end of the list.
    767  1.17    atatat 	 */
    768  1.17    atatat 	if (reform->year == 0)
    769  1.17    atatat 		errx(1, "reform name %s invalid", p);
    770  1.17    atatat 
    771  1.17    atatat 	/*
    772  1.28  christos 	 *
    773  1.17    atatat 	 */
    774  1.17    atatat 	reform->missing_days =
    775  1.17    atatat 		j_leap_days(reform->year, reform->month, reform->date) -
    776  1.17    atatat 		g_leap_days(reform->year, reform->month, reform->date) -
    777  1.17    atatat 		GREGORIAN_MAGIC;
    778  1.17    atatat 
    779  1.17    atatat 	reform->first_missing_day =
    780  1.17    atatat 		(reform->year - 1) * 365 +
    781  1.17    atatat 		day_in_year(reform->date, reform->month, reform->year) +
    782  1.17    atatat 		date +
    783  1.17    atatat 		j_leap_days(reform->year, reform->month, reform->date);
    784  1.17    atatat 
    785  1.17    atatat 	/*
    786  1.17    atatat 	 * Once we know the day of the week of the first missing day,
    787  1.17    atatat 	 * skip back to the first of the month's day of the week.
    788  1.17    atatat 	 */
    789  1.17    atatat 	diw = day_in_week(reform->date, reform->month, reform->year);
    790  1.17    atatat 	diw = (diw + 8 - (reform->date % 7)) % 7;
    791  1.17    atatat 	diy = day_in_year(1, reform->month, reform->year);
    792  1.17    atatat 
    793  1.17    atatat 	/*
    794  1.17    atatat 	 * We might need all four of these (if you switch from Julian
    795  1.17    atatat 	 * to Gregorian at some point after 9900, you get a gap of 73
    796  1.17    atatat 	 * days, and that can affect four months), and it doesn't hurt
    797  1.17    atatat 	 * all that much to precompute them, so there.
    798  1.17    atatat 	 */
    799  1.17    atatat 	date = 1;
    800  1.17    atatat 	days = 0;
    801  1.17    atatat 	for (i = 0; i < 4; i++)
    802  1.17    atatat 		reform_day_array(reform->month + i, reform->year,
    803  1.17    atatat 				 &days, &date, &diw, &diy,
    804  1.17    atatat 				 shift_days[0][i],
    805  1.17    atatat 				 shift_days[1][i]);
    806  1.17    atatat }
    807  1.17    atatat 
    808  1.17    atatat /*
    809  1.17    atatat  * reform_day_array --
    810  1.17    atatat  *	Pre-calculates the given month's calendar (in both "standard"
    811  1.17    atatat  *	and "julian day" representations) with respect for days
    812  1.17    atatat  *	skipped during a reform period.
    813  1.17    atatat  */
    814  1.27     joerg static void
    815  1.17    atatat reform_day_array(int month, int year, int *done, int *date, int *diw, int *diy,
    816  1.17    atatat 	int *scal, int *jcal)
    817  1.17    atatat {
    818  1.17    atatat 	int mdays;
    819  1.17    atatat 
    820  1.17    atatat 	/*
    821  1.17    atatat 	 * If the reform was in the month of october or later, then
    822  1.17    atatat 	 * the month number from the caller could "overflow".
    823  1.17    atatat 	 */
    824  1.17    atatat 	if (month > 12) {
    825  1.17    atatat 		month -= 12;
    826  1.17    atatat 		year++;
    827  1.17    atatat 	}
    828  1.17    atatat 
    829  1.17    atatat 	/*
    830  1.17    atatat 	 * Erase months, and set crib number.  The crib number is used
    831  1.17    atatat 	 * later to determine if the month to be displayed is here or
    832  1.17    atatat 	 * should be built on the fly with the generic routine
    833  1.17    atatat 	 */
    834  1.17    atatat 	memmove(scal, empty, MAXDAYS * sizeof(int));
    835  1.17    atatat 	scal[MAXDAYS] = month + year * 12;
    836  1.17    atatat 	memmove(jcal, empty, MAXDAYS * sizeof(int));
    837  1.17    atatat 	jcal[MAXDAYS] = month + year * 12;
    838  1.17    atatat 
    839  1.17    atatat 	/*
    840  1.17    atatat 	 * It doesn't matter what the actual month is when figuring
    841  1.17    atatat 	 * out if this is a leap year or not, just so long as February
    842  1.17    atatat 	 * gets the right number of days in it.
    843  1.17    atatat 	 */
    844  1.17    atatat 	mdays = days_in_month[g_leap_year(year, 3, 1)][month];
    845  1.17    atatat 
    846  1.17    atatat 	/*
    847  1.17    atatat 	 * Bounce back to the first "row" in the day array, and fill
    848  1.17    atatat 	 * in any days that actually occur.
    849  1.17    atatat 	 */
    850  1.17    atatat 	for (*diw %= 7; (*date - *done) <= mdays; (*date)++, (*diy)++) {
    851  1.17    atatat 		/*
    852  1.17    atatat 		 * "date" doesn't get reset by the caller across calls
    853  1.17    atatat 		 * to this routine, so we can actually tell that we're
    854  1.17    atatat 		 * looking at April the 41st.  Much easier than trying
    855  1.17    atatat 		 * to calculate the absolute julian day for a given
    856  1.17    atatat 		 * date and then checking that.
    857  1.17    atatat 		 */
    858  1.17    atatat 		if (*date < reform->date ||
    859  1.17    atatat 		    *date >= reform->date + reform->missing_days) {
    860  1.17    atatat 			scal[*diw] = *date - *done;
    861  1.17    atatat 			jcal[*diw] = *diy;
    862  1.17    atatat 			(*diw)++;
    863  1.17    atatat 		}
    864  1.17    atatat 	}
    865  1.17    atatat 	*done += mdays;
    866  1.17    atatat }
    867  1.17    atatat 
    868  1.27     joerg static int
    869  1.14      yamt getnum(const char *p)
    870  1.14      yamt {
    871  1.25     lukem 	unsigned long result;
    872  1.14      yamt 	char *ep;
    873  1.14      yamt 
    874  1.14      yamt 	errno = 0;
    875  1.14      yamt 	result = strtoul(p, &ep, 10);
    876  1.14      yamt 	if (p[0] == '\0' || *ep != '\0')
    877  1.14      yamt 		goto error;
    878  1.14      yamt 	if (errno == ERANGE && result == ULONG_MAX)
    879  1.14      yamt 		goto error;
    880  1.14      yamt 	if (result > INT_MAX)
    881  1.14      yamt 		goto error;
    882  1.14      yamt 
    883  1.14      yamt 	return (int)result;
    884  1.14      yamt 
    885  1.14      yamt error:
    886  1.14      yamt 	errx(1, "bad number: %s", p);
    887  1.14      yamt 	/*NOTREACHED*/
    888  1.14      yamt }
    889  1.14      yamt 
    890  1.27     joerg static void
    891  1.15    atatat init_hilite(void)
    892  1.15    atatat {
    893  1.25     lukem 	const char *term;
    894  1.26       roy 	int errret;
    895  1.15    atatat 
    896  1.15    atatat 	hilite++;
    897  1.15    atatat 
    898  1.15    atatat 	if (!isatty(fileno(stdout)))
    899  1.15    atatat 		return;
    900  1.15    atatat 
    901  1.25     lukem 	term = getenv("TERM");
    902  1.25     lukem 	if (term == NULL)
    903  1.25     lukem 		term = "dumb";
    904  1.26       roy 	if (setupterm(term, fileno(stdout), &errret) != 0 && errret != 1)
    905  1.15    atatat 		return;
    906  1.15    atatat 
    907  1.26       roy 	if (hilite > 1)
    908  1.26       roy 		md = enter_reverse_mode;
    909  1.26       roy 	else
    910  1.26       roy 		md = enter_bold_mode;
    911  1.26       roy 	me = exit_attribute_mode;
    912  1.15    atatat 	if (me == NULL || md == NULL)
    913  1.15    atatat 		md = me = NULL;
    914  1.15    atatat }
    915  1.15    atatat 
    916  1.27     joerg static void
    917  1.12     perry usage(void)
    918   1.1       cgd {
    919   1.6     glass 
    920  1.14      yamt 	(void)fprintf(stderr,
    921  1.28  christos 	    "usage: cal [-3hjry] [-A after] [-B before] [-C context] [-d day-of-week] "
    922  1.17    atatat 	    "[-R reform-spec]\n           [[month] year]\n");
    923   1.1       cgd 	exit(1);
    924   1.1       cgd }
    925