Annotation of src/usr.bin/calendar/day.c, Revision 1.7
1.7 ! pjanzen 1: /* $OpenBSD: day.c,v 1.6 1998/11/08 04:31:13 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.7 ! pjanzen 46: static char rcsid[] = "$OpenBSD: day.c,v 1.6 1998/11/08 04:31:13 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;
! 407: v2 = day - tp->tm_yday;
! 408: if ((v2 > v1) || (v2 < 0)) {
! 409: if ((v2 += isleap(tp->tm_year + TM_YEAR_BASE) ? 366 : 365)
! 410: <= v1)
! 411: tmtmp.tm_year++;
! 412: else
! 413: return(NULL);
! 414: }
! 415: if ((tmp = malloc(sizeof(struct match))) == NULL)
! 416: errx(1, "cannot allocate memory");
! 417: tmp->when = f_time + v2 * SECSPERDAY;
! 418: (void)mktime(&tmtmp);
! 419: if (strftime(tmp->print_date,
! 420: sizeof(tmp->print_date),
! 421: /* "%a %b %d", &tm); Skip weekdays */
! 422: "%b %d", &tmtmp) == 0)
! 423: tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
! 424: tmp->var = varp;
! 425: tmp->next = NULL;
! 426: return(tmp);
! 427: }
1.1 millert 428: }
429: else {
1.7 ! pjanzen 430: varp = 1;
! 431: /* Set up v1 to the event number and ... */
! 432: v1 = vwd % (NUMEV + 1) - 1;
! 433: vwd /= (NUMEV + 1);
! 434: if (v1 < 0) {
! 435: v1 += NUMEV + 1;
! 436: vwd--;
! 437: }
! 438: dayp = monthp = 1; /* Why not */
1.1 millert 439: }
440:
1.7 ! pjanzen 441: /* Compare to past and coming instances of the event. The i == 0 part
! 442: * of the loop corresponds to this specific instance. Note that we
! 443: * can leave things sort of higgledy-piggledy since a mktime() happens
! 444: * on this before anything gets printed. Also note that even though
! 445: * we've effectively gotten rid of f_dayBefore, we still have to check
! 446: * the one prior event for situations like "the 31st of every month"
! 447: * and "yearly" events which could happen twice in one year but not in
! 448: * the next */
! 449: tmp2 = matches;
! 450: for (i = -1; i < 2; i++) {
! 451: memcpy(&tmtmp, tp, sizeof(struct tm));
! 452: tmtmp.tm_mday = dayp;
! 453: tmtmp.tm_mon = month = monthp - 1;
! 454: do {
! 455: v2 = 0;
! 456: switch (interval) {
! 457: case WEEKLY:
! 458: tmtmp.tm_mday += 7 * i;
! 459: break;
! 460: case MONTHLY:
! 461: month += i;
! 462: tmtmp.tm_mon = month;
! 463: switch(tmtmp.tm_mon) {
! 464: case -1:
! 465: tmtmp.tm_mon = month = 11;
! 466: tmtmp.tm_year--;
! 467: break;
! 468: case 12:
! 469: tmtmp.tm_mon = month = 0;
! 470: tmtmp.tm_year++;
! 471: break;
! 472: }
! 473: if (vwd) {
! 474: v1 = vwd;
! 475: variable_weekday(&v1, tmtmp.tm_mon + 1,
! 476: tmtmp.tm_year + TM_YEAR_BASE);
! 477: tmtmp.tm_mday = v1;
! 478: } else
! 479: tmtmp.tm_mday = dayp;
! 480: break;
! 481: case YEARLY:
! 482: default:
! 483: tmtmp.tm_year += i;
! 484: if (flags & F_SPECIAL) {
! 485: tmtmp.tm_mon = 0; /* Gee, mktime() is nice */
! 486: tmtmp.tm_mday = spev[v1].getev(tmtmp.tm_year +
! 487: vwd + TM_YEAR_BASE);
! 488: } else if (vwd) {
! 489: v1 = vwd;
! 490: variable_weekday(&v1, tmtmp.tm_mon + 1,
! 491: tmtmp.tm_year + TM_YEAR_BASE);
! 492: tmtmp.tm_mday = v1;
! 493: } else {
! 494: /* Need the following to keep Feb 29 from
! 495: * becoming Mar 1 */
! 496: tmtmp.tm_mday = dayp;
! 497: tmtmp.tm_mon = monthp - 1;
! 498: }
! 499: break;
! 500: }
! 501: /* How many days apart are we */
! 502: if ((ttmp = mktime(&tmtmp)) == -1)
! 503: warnx("time out of range: %s", endp);
! 504: else {
! 505: tdiff = difftime(ttmp, f_time)/ SECSPERDAY;
! 506: if (tdiff <= offset + f_dayAfter) {
! 507: if (tdiff >= 0) {
! 508: if ((tmp = malloc(sizeof(struct match))) == NULL)
! 509: errx(1, "cannot allocate memory");
! 510: tmp->when = ttmp;
! 511: if (strftime(tmp->print_date,
! 512: sizeof(tmp->print_date),
! 513: /* "%a %b %d", &tm); Skip weekdays */
! 514: "%b %d", &tmtmp) == 0)
! 515: tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
! 516: tmp->var = varp;
! 517: tmp->next = NULL;
! 518: if (tmp2)
! 519: tmp2->next = tmp;
! 520: else
! 521: matches = tmp;
! 522: tmp2 = tmp;
! 523: v2 = (i == 1) ? 1 : 0;
! 524: }
! 525: } else
! 526: i = 2; /* No point checking in the future */
! 527: }
! 528: } while (v2 != 0);
1.6 pjanzen 529: }
1.7 ! pjanzen 530: return (matches);
1.1 millert 531: }
532:
533:
534: int
535: getmonth(s)
536: register char *s;
537: {
538: register char **p;
539: struct fixs *n;
540:
541: for (n = fnmonths; n->name; ++n)
542: if (!strncasecmp(s, n->name, n->len))
543: return ((n - fnmonths) + 1);
544: for (n = nmonths; n->name; ++n)
545: if (!strncasecmp(s, n->name, n->len))
546: return ((n - nmonths) + 1);
547: for (p = months; *p; ++p)
548: if (!strncasecmp(s, *p, 3))
549: return ((p - months) + 1);
550: return (0);
551: }
552:
553:
554: int
555: getday(s)
556: register char *s;
557: {
558: register char **p;
559: struct fixs *n;
560:
561: for (n = fndays; n->name; ++n)
562: if (!strncasecmp(s, n->name, n->len))
563: return ((n - fndays) + 1);
564: for (n = ndays; n->name; ++n)
565: if (!strncasecmp(s, n->name, n->len))
566: return ((n - ndays) + 1);
567: for (p = days; *p; ++p)
568: if (!strncasecmp(s, *p, 3))
569: return ((p - days) + 1);
570: return (0);
571: }
572:
573: /* return offset for variable weekdays
574: * -1 -> last weekday in month
575: * +1 -> first weekday in month
576: * ... etc ...
577: */
578: int
579: getdayvar(s)
580: register char *s;
581: {
582: register int offset;
583:
584:
585: offset = strlen(s);
586:
587: /* Sun+1 or Wednesday-2
588: * ^ ^ */
589:
590: /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
591: switch(*(s + offset - 2)) {
592: case '-':
593: case '+':
1.7 ! pjanzen 594: return(atoi(s + offset - 2));
1.1 millert 595: break;
596: }
597:
598: /*
599: * some aliases: last, first, second, third, fourth
600: */
601:
602: /* last */
603: if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
604: return(-1);
605: else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
606: return(+1);
607: else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
608: return(+2);
609: else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
610: return(+3);
611: else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
612: return(+4);
613:
614: /* no offset detected */
615: return(0);
1.7 ! pjanzen 616: }
! 617:
! 618:
! 619: int
! 620: foy(year)
! 621: int year;
! 622: {
! 623: /* 0-6; what weekday Jan 1 is */
! 624: year--;
! 625: return ((1 - year/100 + year/400 + (int)(365.25 * year)) % 7);
! 626: }
! 627:
! 628:
! 629:
! 630: void
! 631: variable_weekday(day, month, year)
! 632: int *day, month, year;
! 633: {
! 634: int v1, v2;
! 635: int *cumdays;
! 636: int day1;
! 637:
! 638: if (isleap(year))
! 639: cumdays = daytab[1];
! 640: else
! 641: cumdays = daytab[0];
! 642: day1 = foy(year);
! 643: /* negative offset; last, -4 .. -1 */
! 644: if (*day < 0) {
! 645: v1 = *day/10 - 1; /* offset -4 ... -1 */
! 646: *day = 10 + (*day % 10); /* day 1 ... 7 */
! 647:
! 648: /* which weekday the end of the month is (1-7) */
! 649: v2 = (cumdays[month + 1] + day1) % 7 + 1;
! 650:
! 651: /* and subtract enough days */
! 652: *day = cumdays[month + 1] - cumdays[month] +
! 653: (v1 + 1) * 7 - (v2 - *day + 7) % 7;
! 654: #if DEBUG
! 655: fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2);
! 656: #endif
! 657: }
! 658:
! 659: /* first, second ... +1 ... +5 */
! 660: else {
! 661: v1 = *day/10; /* offset */
! 662: *day = *day % 10;
! 663:
! 664: /* which weekday the first of the month is (1-7) */
! 665: v2 = (cumdays[month] + 1 + day1) % 7 + 1;
! 666:
! 667: /* and add enough days */
! 668: *day = 1 + (v1 - 1) * 7 + (*day - v2 + 7) % 7;
! 669: #if DEBUG
! 670: fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2);
! 671: #endif
! 672: }
1.1 millert 673: }