|
|
1.1 root 1: /*
2: * Print calendar for specified year (and month).
3: * Allows month to be numeric or alphabetic.
4: */
5:
6: #include <stdio.h>
7: #include <ctype.h>
8: #include <time.h>
9:
10: #define GREGYEAR 1752 /* Year of start of Gregorian calendar */
11: #define GREGMON SEP /* Month of above */
12: #define GREGDAY 3 /* day of month of changeover */
13: #define GREGADJ 11 /* Adjustment of cal. (days) for Gregorian */
14: /* The calendar skipped 11 days after
15: * September 3, 1752 in England.
16: * That made the date jump 12 days
17: * forward rather than the usual 1.
18: * The original Gregorian reform was in
19: * 1582, at which time only 10 days were
20: * suppressed. France and Russia adopted
21: * the Gregorian calendar after 1752.
22: * My calculations, which don't make
23: * complete sense, suggest that the
24: * corrections would be:
25: * 12 days after 1800
26: * 13 days after 1900
27: * and 14 days after 2100
28: * because the Gregorian calendar skips
29: * leap years which fall on century years
30: * unless they are quadracents and not
31: * 4000 AD.
32: */
33: #define TMYBIAS 1900 /* bias of year field in struct tm */
34:
35: char *mnames[] = {
36: "January", "February", "March", "April", "May", "June",
37: "July", "August", "September", "October", "November", "December"
38: };
39:
40: /*
41: * Days per month array (non-leap).
42: * January is at dpm[1].
43: */
44: char dpm[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
45:
46: char dayhead[] = " Su Mo Tu We Th Fr Sa";
47:
48: #define DAYWIDTH (sizeof dayhead -1)
49: #define GAP 5 /* Gap between months */
50: #define CENTRE ((3*DAYWIDTH+2*GAP)/2+2) /* Centred 4 digit year pos. */
51: #define MPL 3 /* Months per line */
52: #define JAN 1
53: #define FEB 2
54: #define MAR 3
55: #define APR 4
56: #define MAY 5
57: #define JUN 6
58: #define JUL 7
59: #define AUG 8
60: #define SEP 9
61: #define OCT 10
62: #define NOV 11
63: #define DEC 12
64:
65:
66: char caldays[MPL][6][7], /* 3 per line, 6 lines, 7 days */
67: outbuf[BUFSIZ]; /* stdout setbuf */
68: int baseday; /* Weekday of current year's Jan. 1 */
69:
70: main(argc, argv)
71: register char *argv[];
72: {
73: int month;
74: unsigned year;
75: struct tm *now;
76: long intime;
77: long time();
78:
79: setbuf(stdout, outbuf);
80: intime = time(NULL);
81: now = localtime(&intime);
82: month = 0;
83: year = now->tm_year + TMYBIAS;
84: ++argv;
85: switch (argc) {
86: case 1:
87: month = now->tm_mon + 1;
88: break;
89: case 2:
90: if (isdigit(**argv))
91: year = atoi(*argv);
92: else
93: month = getmon(*argv);
94: break;
95: case 3:
96: if (!isdigit(*argv[0]))
97: month = getmon(*argv++);
98: else if (isdigit(*argv[1])) {
99: month = atoi(*argv++);
100: if (month == 0)
101: month = -1;
102: } else
103: month = getmon(argv[1]);
104: year = atoi(*argv);
105: break;
106: default:
107: usage();
108: }
109: if (month < 0 || month > 12 || year <= 0 || year > 9999)
110: usage();
111: cal(year, month);
112: exit(0);
113: }
114:
115: /*
116: * Produce a calendar for the specifed year and month.
117: * (If month is zero, then do whole year.)
118: * Setup baseday for fillcal to speed it up a lot.
119: */
120: cal(yr, mon)
121: {
122: register xmon, pos;
123: register wday;
124:
125: /*
126: * Start at 1 January, 1 which was a Saturday.
127: */
128: wday = 6;
129: for (pos=1; pos<yr; pos++) {
130: if (pos == GREGYEAR)
131: wday -= GREGADJ;
132: wday = (wday + (isleap(pos) ? 366 : 365)) % 7;
133: }
134: baseday = wday;
135: if (mon != 0) {
136: fillcal(0, mon, yr);
137: outcal(mon, 1);
138: } else {
139: printf("\n%*d\n", CENTRE, yr);
140: pos = 0;
141: for (xmon = 1; xmon <= 12; xmon++) {
142: fillcal(pos, xmon, yr);
143: if (++pos >= MPL) {
144: outcal(xmon-MPL+1, MPL);
145: pos = 0;
146: }
147: }
148: }
149: }
150:
151: /*
152: * Fill the caldays array element for the particular month
153: * and year specified.
154: */
155: fillcal(pos, month, year)
156: {
157: register i, j, day;
158: int wday, special, mdays;
159:
160: for (i=0; i<6; i++)
161: for (j=0; j<7; j++)
162: caldays[pos][i][j] = 0;
163: wday = baseday;
164: dpm[FEB] = isleap(year) ? 29 : 28;
165: special = (year==GREGYEAR);
166: for (i=1; i<month; i++) {
167: if (special && i==GREGMON)
168: wday -= GREGADJ;
169: wday = (wday + dpm[i]) % 7;
170: }
171: special = (special && month==GREGMON);
172: mdays = dpm[month];
173: i = 0;
174: j = wday;
175: for (day = 1; day <= mdays; day++) {
176: caldays[pos][i][j] = day;
177: if (special && day==GREGDAY)
178: day += GREGADJ;
179: if (++j >= 7) {
180: j = 0;
181: i++;
182: }
183: }
184: }
185:
186: /*
187: * Put out `n' months from caldays, starting at month `mon'.
188: */
189: outcal(mon, n)
190: {
191: register i, j, k;
192: int left, cent;
193: int val;
194: char *name;
195:
196: mon--;
197: lput('\n');
198: for (i=1; i<=n; i++) {
199: name = mnames[mon++];
200: cent = strlen(name);
201: left = (DAYWIDTH-cent)/2;
202: spaceover(left);
203: lputs(name);
204: spaceover(DAYWIDTH+GAP-left-cent);
205: }
206: lput('\n');
207: for (i=1; i<=n; i++) {
208: lputs(dayhead);
209: spaceover(GAP);
210: }
211: lput('\n');
212: for (j=0; j<6; j++) {
213: for (i=0; i<n; i++) {
214: for (k=0; k<7; k++) {
215: lput(' ');
216: val = caldays[i][j][k];
217: lput(val>=10 ? val/10 + '0' : ' ');
218: if (val)
219: lput(val%10 + '0');
220: else
221: lput(' ');
222: }
223: spaceover(GAP);
224: }
225: lput('\n');
226: }
227: }
228:
229: /*
230: * Put out calendar characters saving them up until a
231: * newline so that trailing blanks can be stripped.
232: */
233:
234: static char lline[100];
235: static char *lp = lline;
236: lput(c)
237: register c;
238: {
239: register char *cp;
240:
241: if (c != '\n')
242: *lp++ = c;
243: else {
244: for (cp = lp; *--cp == ' '; )
245: ;
246: *++cp = '\n';
247: *++cp = '\0';
248: printf("%s", lp = lline);
249: }
250: }
251:
252: /*
253: * Put out a string using `lput'.
254: */
255: lputs(s)
256: register char *s;
257: {
258: while (*s != '\0')
259: lput(*s++);
260: }
261:
262: spaceover(n)
263: register n;
264: {
265: if (n>0)
266: do {
267: lput(' ');
268: } while (--n);
269: }
270:
271: /*
272: * Return 1 on leap years; 0 otherwise.
273: */
274: isleap(yr)
275: register yr;
276: {
277: if (yr<=GREGYEAR)
278: return (yr%4 == 0);
279: if (yr%4000 == 0)
280: return (0);
281: if (yr%400==0 || (yr%100!=0 && yr%4==0))
282: return (1);
283: return (0);
284: }
285:
286: /*
287: * Return the month (1-12) from `mname' which is
288: * roman numeric, the name in ascii of a month, or wrong.
289: * Trailing '.' is accepted as are upper case letters.
290: */
291: struct months {
292: char *m_name;
293: int m_num;
294: } months[] = {
295: "i", JAN, "jan", JAN, "january", JAN,
296: "janvier", JAN, "ii", FEB, "feb", FEB,
297: "february", FEB, "fevrier", FEB, "iii", MAR,
298: "mar", MAR, "march", MAR, "mars", MAR,
299: "iv", APR, "apr", APR, "april", APR,
300: "avril", APR, "v", MAY, "may", MAY,
301: "mai", MAY, "vi", JUN, "jun", JUN,
302: "june", JUN, "juin", JUN, "vii", JUL,
303: "jul", JUL, "july", JUL, "juillet", JUL,
304: "viii", AUG, "iix", AUG, "aug", AUG,
305: "august", AUG, "aout", AUG, "ix", SEP,
306: "sep", SEP, "sept", SEP, "september", SEP,
307: "septembre", SEP, "x", OCT, "oct", OCT,
308: "october", OCT, "octobre", OCT, "xi", NOV,
309: "nov", NOV, "november", NOV, "novembre", NOV,
310: "xii", DEC, "dec", DEC, "december", DEC,
311: "decembre", DEC, NULL
312: };
313:
314: getmon(mname)
315: char *mname;
316: {
317: register struct months *mp;
318: register char *p1, *p2;
319:
320: for (p1 = mname; *p1 != '\0'; p1 += 1)
321: if (isupper(*p1))
322: *p1 = tolower(*p1);
323: if (*--p1 == '.')
324: *p1 = '\0';
325: for (mp = months; mp->m_name != NULL; mp++) {
326: p1 = mname;
327: p2 = mp->m_name;
328: while (*p1 == *p2 && *p1 != '\0' && *p2 != 0)
329: p1 += 1, p2 += 1;
330: if (*p1 == *p2)
331: return (mp->m_num);
332: }
333: return (-1);
334: }
335:
336: usage()
337: {
338: fprintf(stderr, "Usage: cal [month] [year]\n");
339: exit(1);
340: }
341:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.