Annotation of src/usr.bin/calendar/day.c, Revision 1.8
1.8 ! pjanzen 1: /* $OpenBSD: day.c,v 1.7 1998/12/13 07:31:07 pjanzen Exp $ */
1.1 millert 2:
3: /*
4: * Copyright (c) 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: static const char copyright[] =
38: "@(#) Copyright (c) 1989, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
40: #endif /* not lint */
41:
42: #ifndef lint
43: #if 0
44: static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
45: #else
1.8 ! pjanzen 46: static char rcsid[] = "$OpenBSD: day.c,v 1.7 1998/12/13 07:31:07 pjanzen Exp $";
1.1 millert 47: #endif
48: #endif /* not lint */
49:
50: #include <sys/types.h>
51: #include <sys/uio.h>
52:
53: #include <ctype.h>
54: #include <err.h>
55: #include <locale.h>
56: #include <stdio.h>
57: #include <stdlib.h>
58: #include <string.h>
59: #include <time.h>
60: #include <tzfile.h>
61:
62: #include "pathnames.h"
63: #include "calendar.h"
64:
1.7 pjanzen 65: #define WEEKLY 1
66: #define MONTHLY 2
67: #define YEARLY 3
68:
1.1 millert 69: struct tm *tp;
1.7 pjanzen 70: int *cumdays, offset;
1.1 millert 71: char dayname[10];
72:
73:
74: /* 1-based month, 0-based days, cumulative */
75: int daytab[][14] = {
76: { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
77: { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
78: };
79:
80: static char *days[] = {
81: "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
82: };
83:
84: static char *months[] = {
85: "jan", "feb", "mar", "apr", "may", "jun",
86: "jul", "aug", "sep", "oct", "nov", "dec", NULL,
87: };
88:
89: static struct fixs fndays[8]; /* full national days names */
90: static struct fixs ndays[8]; /* short national days names */
91:
92: static struct fixs fnmonths[13]; /* full national months names */
93: static struct fixs nmonths[13]; /* short national month names */
94:
95:
96: void setnnames(void)
97: {
98: char buf[80];
99: int i, l;
100: struct tm tm;
101:
102: for (i = 0; i < 7; i++) {
103: tm.tm_wday = i;
1.3 millert 104: l = strftime(buf, sizeof(buf), "%a", &tm);
105: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 106: ;
107: buf[l] = '\0';
108: if (ndays[i].name != NULL)
109: free(ndays[i].name);
110: if ((ndays[i].name = strdup(buf)) == NULL)
111: errx(1, "cannot allocate memory");
112: ndays[i].len = strlen(buf);
113:
1.3 millert 114: l = strftime(buf, sizeof(buf), "%A", &tm);
115: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 116: ;
117: buf[l] = '\0';
118: if (fndays[i].name != NULL)
119: free(fndays[i].name);
120: if ((fndays[i].name = strdup(buf)) == NULL)
121: errx(1, "cannot allocate memory");
122: fndays[i].len = strlen(buf);
123: }
124:
125: for (i = 0; i < 12; i++) {
126: tm.tm_mon = i;
1.3 millert 127: l = strftime(buf, sizeof(buf), "%b", &tm);
128: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 129: ;
130: buf[l] = '\0';
131: if (nmonths[i].name != NULL)
132: free(nmonths[i].name);
133: if ((nmonths[i].name = strdup(buf)) == NULL)
134: errx(1, "cannot allocate memory");
135: nmonths[i].len = strlen(buf);
136:
1.3 millert 137: l = strftime(buf, sizeof(buf), "%B", &tm);
138: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 139: ;
140: buf[l] = '\0';
141: if (fnmonths[i].name != NULL)
142: free(fnmonths[i].name);
143: if ((fnmonths[i].name = strdup(buf)) == NULL)
144: errx(1, "cannot allocate memory");
145: fnmonths[i].len = strlen(buf);
146: }
1.7 pjanzen 147: /* Hardwired special events */
148: spev[0].name = strdup(EASTER);
149: spev[0].nlen = EASTERNAMELEN;
150: spev[0].getev = easter;
151: spev[1].name = strdup(PASKHA);
152: spev[1].nlen = PASKHALEN;
153: spev[1].getev = paskha;
154: for (i = 0; i < NUMEV; i++) {
155: if (spev[i].name == NULL)
156: errx(1, "cannot allocate memory");
157: spev[i].uname = NULL;
158: }
1.1 millert 159: }
160:
161: void
162: settime(now)
1.7 pjanzen 163: time_t *now;
1.1 millert 164: {
1.7 pjanzen 165: tp = localtime(now);
166: tp->tm_sec = 0;
167: tp->tm_min = 0;
168: /* Avoid getting caught by a timezone shift; set time to noon */
169: tp->tm_isdst = 0;
170: tp->tm_hour = 12;
171: *now = mktime(tp);
172: if (isleap(tp->tm_year + TM_YEAR_BASE))
1.1 millert 173: cumdays = daytab[1];
1.7 pjanzen 174: else
1.1 millert 175: cumdays = daytab[0];
176: /* Friday displays Monday's events */
177: offset = tp->tm_wday == 5 ? 3 : 1;
1.7 pjanzen 178: if (f_dayAfter)
179: offset = 0; /* Except not when range is set explicitly */
1.1 millert 180: header[5].iov_base = dayname;
181:
182: (void) setlocale(LC_TIME, "C");
183: header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
184: (void) setlocale(LC_TIME, "");
185:
186: setnnames();
187: }
188:
1.2 millert 189: /* convert [Year][Month]Day into unix time (since 1970)
190: * Year: two or four digits, Month: two digits, Day: two digits
1.1 millert 191: */
192: time_t Mktime (date)
193: char *date;
194: {
195: time_t t;
196: int len;
197: struct tm tm;
198:
199: (void)time(&t);
200: tp = localtime(&t);
201:
202: len = strlen(date);
1.2 millert 203: if (len < 2)
204: return((time_t)-1);
1.1 millert 205: tm.tm_sec = 0;
206: tm.tm_min = 0;
1.5 pjanzen 207: /* Avoid getting caught by a timezone shift; set time to noon */
208: tm.tm_isdst = 0;
209: tm.tm_hour = 12;
1.1 millert 210: tm.tm_wday = 0;
211: tm.tm_mday = tp->tm_mday;
212: tm.tm_mon = tp->tm_mon;
213: tm.tm_year = tp->tm_year;
214:
1.2 millert 215: /* Day */
216: tm.tm_mday = atoi(date + len - 2);
1.1 millert 217:
1.2 millert 218: /* Month */
1.1 millert 219: if (len >= 4) {
1.2 millert 220: *(date + len - 2) = '\0';
221: tm.tm_mon = atoi(date + len - 4) - 1;
1.1 millert 222: }
223:
224: /* Year */
1.5 pjanzen 225: if (len >= 6) {
1.7 pjanzen 226: *(date + len - 4) = '\0';
227: tm.tm_year = atoi(date);
1.1 millert 228:
1.4 deraadt 229: /* tm_year up TM_YEAR_BASE ... */
1.5 pjanzen 230: if (tm.tm_year < 69) /* Y2K */
1.4 deraadt 231: tm.tm_year += 2000 - TM_YEAR_BASE;
232: else if (tm.tm_year < 100)
233: tm.tm_year += 1900 - TM_YEAR_BASE;
234: else if (tm.tm_year > TM_YEAR_BASE)
235: tm.tm_year -= TM_YEAR_BASE;
1.1 millert 236: }
237:
238: #if DEBUG
239: printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
240: asctime(&tm));
241: #endif
242: return(mktime(&tm));
243: }
244:
245: /*
246: * Possible date formats include any combination of:
247: * 3-charmonth (January, Jan, Jan)
248: * 3-charweekday (Friday, Monday, mon.)
249: * numeric month or day (1, 2, 04)
250: *
251: * Any character may separate them, or they may not be separated. Any line,
252: * following a line that is matched, that starts with "whitespace", is shown
253: * along with the matched line.
254: */
1.6 pjanzen 255: struct match *
256: isnow(endp)
1.1 millert 257: char *endp;
258: {
1.7 pjanzen 259: int day = 0, flags = 0, month = 0, v1, v2, i;
260: int monthp, dayp, varp = 0;
261: struct match *matches = NULL, *tmp, *tmp2;
262: int interval = YEARLY; /* how frequently the event repeats. */
263: int vwd = 0; /* Variable weekday */
264: time_t tdiff, ttmp;
265: struct tm tmtmp;
1.1 millert 266:
267: /*
268: * CONVENTION
269: *
270: * Month: 1-12
271: * Monthname: Jan .. Dec
272: * Day: 1-31
273: * Weekday: Mon-Sun
274: *
275: */
276:
277: /* read first field */
278: /* didn't recognize anything, skip it */
279: if (!(v1 = getfield(endp, &endp, &flags)))
1.6 pjanzen 280: return (NULL);
1.1 millert 281:
282: /* Easter or Easter depending days */
1.7 pjanzen 283: if (flags & F_SPECIAL)
284: vwd = v1;
1.1 millert 285:
286: /*
287: * 1. {Weekday,Day} XYZ ...
288: *
289: * where Day is > 12
290: */
291: else if (flags & F_ISDAY || v1 > 12) {
292:
1.7 pjanzen 293: /* found a day; day: 13-31 or weekday: 1-7 */
1.1 millert 294: day = v1;
295:
296: /* {Day,Weekday} {Month,Monthname} ... */
1.7 pjanzen 297: /* if no recognizable month, assume just a day alone -- this is
298: * very unlikely and can only happen after the first 12 days.
299: * --find month or use current month */
300: if (!(month = getfield(endp, &endp, &flags))) {
1.1 millert 301: month = tp->tm_mon + 1;
1.7 pjanzen 302: /* F_ISDAY is set only if a weekday was spelled out */
303: /* F_ISDAY must be set if 0 < day < 8 */
304: if ((day <= 7) && (day >= 1))
305: interval = WEEKLY;
306: else
307: interval = MONTHLY;
308: } else if ((day <= 7) && (day >= 1))
309: day += 10;
310: /* it's a weekday; make it the first one of the month */
311: if (month == -1) {
312: month = tp->tm_mon + 1;
313: interval = MONTHLY;
314: }
315: if ((month > 12) || (month < 1))
316: return (NULL);
1.1 millert 317: }
318:
319: /* 2. {Monthname} XYZ ... */
320: else if (flags & F_ISMONTH) {
321: month = v1;
1.7 pjanzen 322: if (month == -1) {
323: month = tp->tm_mon + 1;
324: interval = MONTHLY;
325: }
1.1 millert 326: /* Monthname {day,weekday} */
327: /* if no recognizable day, assume the first day in month */
328: if (!(day = getfield(endp, &endp, &flags)))
329: day = 1;
1.7 pjanzen 330: /* If a weekday was spelled out without an ordering,
331: * assume the first of that day in the month */
332: if ((flags & F_ISDAY) && (day >= 1) && (day <=7))
333: day += 10;
1.1 millert 334: }
335:
336: /* Hm ... */
337: else {
338: v2 = getfield(endp, &endp, &flags);
339:
340: /*
341: * {Day} {Monthname} ...
342: * where Day <= 12
343: */
344: if (flags & F_ISMONTH) {
345: day = v1;
346: month = v2;
1.7 pjanzen 347: if (month == -1) {
348: month = tp->tm_mon + 1;
349: interval = MONTHLY;
350: }
1.1 millert 351: }
352:
353: /* {Month} {Weekday,Day} ... */
354: else {
355: /* F_ISDAY set, v2 > 12, or no way to tell */
356: month = v1;
357: /* if no recognizable day, assume the first */
358: day = v2 ? v2 : 1;
1.7 pjanzen 359: if ((flags & F_ISDAY) && (day >= 1) && (day <= 7))
360: day += 10;
1.1 millert 361: }
362: }
363:
364: /* convert Weekday into *next* Day,
365: * e.g.: 'Sunday' -> 22
1.5 pjanzen 366: * 'SundayLast' -> ??
1.1 millert 367: */
368: if (flags & F_ISDAY) {
369: #if DEBUG
1.7 pjanzen 370: fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
1.1 millert 371: #endif
372:
1.7 pjanzen 373: varp = 1;
374: /* variable weekday, SundayLast, MondayFirst ... */
375: if (day < 0 || day >= 10)
376: vwd = day;
377: else {
378: day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
379: interval = WEEKLY;
380: }
381: } else
382: /* Check for silliness. Note we still catch Feb 29 */
383: if (!(flags & F_SPECIAL) &&
384: (day > (cumdays[month + 1] - cumdays[month]) || day < 1)) {
385: if (!((month == 2 && day == 29) ||
386: (interval == MONTHLY && day <= 31)))
387: return (NULL);
1.1 millert 388: }
389:
1.7 pjanzen 390: if (!(flags & F_SPECIAL)) {
391: monthp = month;
392: dayp = day;
393: day = cumdays[month] + day;
1.5 pjanzen 394: #if DEBUG
1.7 pjanzen 395: fprintf(stderr, "day2: day %d(%d) yday %d\n", dayp, day, tp->tm_yday);
1.5 pjanzen 396: #endif
1.7 pjanzen 397: /* Speed up processing for the most common situation: yearly events
398: * when the interval being checked is less than a month or so (this
399: * could be less than a year, but then we have to start worrying about
400: * leap years). Only one event can match, and it's easy to find.
401: * Note we can't check special events, because they can wander widely.
402: */
403: if (((v1 = offset + f_dayAfter) < 50) && (interval == YEARLY)) {
404: memcpy(&tmtmp, tp, sizeof(struct tm));
405: tmtmp.tm_mday = dayp;
406: tmtmp.tm_mon = monthp - 1;
1.8 ! pjanzen 407: if (vwd) {
! 408: /* We want the event next year if it's late now
! 409: * this year. The 50-day limit means we don't have to
! 410: * worry if next year is or isn't a leap year.
! 411: */
! 412: if (tp->tm_yday > 300 && tmtmp.tm_mon <= 1)
! 413: variable_weekday(&vwd, tmtmp.tm_mon + 1,
! 414: tmtmp.tm_year + TM_YEAR_BASE + 1);
! 415: else
! 416: variable_weekday(&vwd, tmtmp.tm_mon + 1,
! 417: tmtmp.tm_year + TM_YEAR_BASE);
! 418: day = cumdays[tmtmp.tm_mon + 1] + vwd;
! 419: tmtmp.tm_mday = vwd;
! 420: }
1.7 pjanzen 421: v2 = day - tp->tm_yday;
422: if ((v2 > v1) || (v2 < 0)) {
423: if ((v2 += isleap(tp->tm_year + TM_YEAR_BASE) ? 366 : 365)
424: <= v1)
425: tmtmp.tm_year++;
426: else
427: return(NULL);
428: }
429: if ((tmp = malloc(sizeof(struct match))) == NULL)
430: errx(1, "cannot allocate memory");
431: tmp->when = f_time + v2 * SECSPERDAY;
432: (void)mktime(&tmtmp);
433: if (strftime(tmp->print_date,
434: sizeof(tmp->print_date),
435: /* "%a %b %d", &tm); Skip weekdays */
436: "%b %d", &tmtmp) == 0)
437: tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
438: tmp->var = varp;
439: tmp->next = NULL;
440: return(tmp);
441: }
1.1 millert 442: }
443: else {
1.7 pjanzen 444: varp = 1;
445: /* Set up v1 to the event number and ... */
446: v1 = vwd % (NUMEV + 1) - 1;
447: vwd /= (NUMEV + 1);
448: if (v1 < 0) {
449: v1 += NUMEV + 1;
450: vwd--;
451: }
452: dayp = monthp = 1; /* Why not */
1.1 millert 453: }
454:
1.7 pjanzen 455: /* Compare to past and coming instances of the event. The i == 0 part
456: * of the loop corresponds to this specific instance. Note that we
457: * can leave things sort of higgledy-piggledy since a mktime() happens
458: * on this before anything gets printed. Also note that even though
459: * we've effectively gotten rid of f_dayBefore, we still have to check
460: * the one prior event for situations like "the 31st of every month"
461: * and "yearly" events which could happen twice in one year but not in
462: * the next */
463: tmp2 = matches;
464: for (i = -1; i < 2; i++) {
465: memcpy(&tmtmp, tp, sizeof(struct tm));
466: tmtmp.tm_mday = dayp;
467: tmtmp.tm_mon = month = monthp - 1;
468: do {
469: v2 = 0;
470: switch (interval) {
471: case WEEKLY:
472: tmtmp.tm_mday += 7 * i;
473: break;
474: case MONTHLY:
475: month += i;
476: tmtmp.tm_mon = month;
477: switch(tmtmp.tm_mon) {
478: case -1:
479: tmtmp.tm_mon = month = 11;
480: tmtmp.tm_year--;
481: break;
482: case 12:
483: tmtmp.tm_mon = month = 0;
484: tmtmp.tm_year++;
485: break;
486: }
487: if (vwd) {
488: v1 = vwd;
489: variable_weekday(&v1, tmtmp.tm_mon + 1,
490: tmtmp.tm_year + TM_YEAR_BASE);
491: tmtmp.tm_mday = v1;
492: } else
493: tmtmp.tm_mday = dayp;
494: break;
495: case YEARLY:
496: default:
497: tmtmp.tm_year += i;
498: if (flags & F_SPECIAL) {
499: tmtmp.tm_mon = 0; /* Gee, mktime() is nice */
500: tmtmp.tm_mday = spev[v1].getev(tmtmp.tm_year +
501: vwd + TM_YEAR_BASE);
502: } else if (vwd) {
503: v1 = vwd;
504: variable_weekday(&v1, tmtmp.tm_mon + 1,
505: tmtmp.tm_year + TM_YEAR_BASE);
506: tmtmp.tm_mday = v1;
507: } else {
508: /* Need the following to keep Feb 29 from
509: * becoming Mar 1 */
510: tmtmp.tm_mday = dayp;
511: tmtmp.tm_mon = monthp - 1;
512: }
513: break;
514: }
515: /* How many days apart are we */
516: if ((ttmp = mktime(&tmtmp)) == -1)
517: warnx("time out of range: %s", endp);
518: else {
519: tdiff = difftime(ttmp, f_time)/ SECSPERDAY;
520: if (tdiff <= offset + f_dayAfter) {
521: if (tdiff >= 0) {
522: if ((tmp = malloc(sizeof(struct match))) == NULL)
523: errx(1, "cannot allocate memory");
524: tmp->when = ttmp;
525: if (strftime(tmp->print_date,
526: sizeof(tmp->print_date),
527: /* "%a %b %d", &tm); Skip weekdays */
528: "%b %d", &tmtmp) == 0)
529: tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
530: tmp->var = varp;
531: tmp->next = NULL;
532: if (tmp2)
533: tmp2->next = tmp;
534: else
535: matches = tmp;
536: tmp2 = tmp;
537: v2 = (i == 1) ? 1 : 0;
538: }
539: } else
540: i = 2; /* No point checking in the future */
541: }
542: } while (v2 != 0);
1.6 pjanzen 543: }
1.7 pjanzen 544: return (matches);
1.1 millert 545: }
546:
547:
548: int
549: getmonth(s)
550: register char *s;
551: {
552: register char **p;
553: struct fixs *n;
554:
555: for (n = fnmonths; n->name; ++n)
556: if (!strncasecmp(s, n->name, n->len))
557: return ((n - fnmonths) + 1);
558: for (n = nmonths; n->name; ++n)
559: if (!strncasecmp(s, n->name, n->len))
560: return ((n - nmonths) + 1);
561: for (p = months; *p; ++p)
562: if (!strncasecmp(s, *p, 3))
563: return ((p - months) + 1);
564: return (0);
565: }
566:
567:
568: int
569: getday(s)
570: register char *s;
571: {
572: register char **p;
573: struct fixs *n;
574:
575: for (n = fndays; n->name; ++n)
576: if (!strncasecmp(s, n->name, n->len))
577: return ((n - fndays) + 1);
578: for (n = ndays; n->name; ++n)
579: if (!strncasecmp(s, n->name, n->len))
580: return ((n - ndays) + 1);
581: for (p = days; *p; ++p)
582: if (!strncasecmp(s, *p, 3))
583: return ((p - days) + 1);
584: return (0);
585: }
586:
587: /* return offset for variable weekdays
588: * -1 -> last weekday in month
589: * +1 -> first weekday in month
590: * ... etc ...
591: */
592: int
593: getdayvar(s)
594: register char *s;
595: {
596: register int offset;
597:
598:
599: offset = strlen(s);
600:
601: /* Sun+1 or Wednesday-2
602: * ^ ^ */
603:
604: /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
605: switch(*(s + offset - 2)) {
606: case '-':
607: case '+':
1.7 pjanzen 608: return(atoi(s + offset - 2));
1.1 millert 609: break;
610: }
611:
612: /*
613: * some aliases: last, first, second, third, fourth
614: */
615:
616: /* last */
617: if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
618: return(-1);
619: else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
620: return(+1);
621: else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
622: return(+2);
623: else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
624: return(+3);
625: else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
626: return(+4);
627:
628: /* no offset detected */
629: return(0);
1.7 pjanzen 630: }
631:
632:
633: int
634: foy(year)
635: int year;
636: {
637: /* 0-6; what weekday Jan 1 is */
638: year--;
639: return ((1 - year/100 + year/400 + (int)(365.25 * year)) % 7);
640: }
641:
642:
643:
644: void
645: variable_weekday(day, month, year)
646: int *day, month, year;
647: {
648: int v1, v2;
649: int *cumdays;
650: int day1;
651:
652: if (isleap(year))
653: cumdays = daytab[1];
654: else
655: cumdays = daytab[0];
656: day1 = foy(year);
657: /* negative offset; last, -4 .. -1 */
658: if (*day < 0) {
659: v1 = *day/10 - 1; /* offset -4 ... -1 */
660: *day = 10 + (*day % 10); /* day 1 ... 7 */
661:
662: /* which weekday the end of the month is (1-7) */
663: v2 = (cumdays[month + 1] + day1) % 7 + 1;
664:
665: /* and subtract enough days */
666: *day = cumdays[month + 1] - cumdays[month] +
667: (v1 + 1) * 7 - (v2 - *day + 7) % 7;
668: #if DEBUG
669: fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2);
670: #endif
671: }
672:
673: /* first, second ... +1 ... +5 */
674: else {
675: v1 = *day/10; /* offset */
676: *day = *day % 10;
677:
678: /* which weekday the first of the month is (1-7) */
679: v2 = (cumdays[month] + 1 + day1) % 7 + 1;
680:
681: /* and add enough days */
682: *day = 1 + (v1 - 1) * 7 + (*day - v2 + 7) % 7;
683: #if DEBUG
684: fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2);
685: #endif
686: }
1.1 millert 687: }