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