Annotation of src/usr.bin/calendar/day.c, Revision 1.5
1.5 ! pjanzen 1: /* $OpenBSD: day.c,v 1.4 1998/03/30 06:59:26 deraadt 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.5 ! pjanzen 46: static char rcsid[] = "$OpenBSD: day.c,v 1.4 1998/03/30 06:59:26 deraadt 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:
65: struct tm *tp;
66: int *cumdays, offset, yrdays;
67: char dayname[10];
68:
69:
70: /* 1-based month, 0-based days, cumulative */
71: int daytab[][14] = {
72: { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
73: { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
74: };
75:
76: static char *days[] = {
77: "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
78: };
79:
80: static char *months[] = {
81: "jan", "feb", "mar", "apr", "may", "jun",
82: "jul", "aug", "sep", "oct", "nov", "dec", NULL,
83: };
84:
85: static struct fixs fndays[8]; /* full national days names */
86: static struct fixs ndays[8]; /* short national days names */
87:
88: static struct fixs fnmonths[13]; /* full national months names */
89: static struct fixs nmonths[13]; /* short national month names */
90:
91:
92: void setnnames(void)
93: {
94: char buf[80];
95: int i, l;
96: struct tm tm;
97:
98: for (i = 0; i < 7; i++) {
99: tm.tm_wday = i;
1.3 millert 100: l = strftime(buf, sizeof(buf), "%a", &tm);
101: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 102: ;
103: buf[l] = '\0';
104: if (ndays[i].name != NULL)
105: free(ndays[i].name);
106: if ((ndays[i].name = strdup(buf)) == NULL)
107: errx(1, "cannot allocate memory");
108: ndays[i].len = strlen(buf);
109:
1.3 millert 110: l = strftime(buf, sizeof(buf), "%A", &tm);
111: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 112: ;
113: buf[l] = '\0';
114: if (fndays[i].name != NULL)
115: free(fndays[i].name);
116: if ((fndays[i].name = strdup(buf)) == NULL)
117: errx(1, "cannot allocate memory");
118: fndays[i].len = strlen(buf);
119: }
120:
121: for (i = 0; i < 12; i++) {
122: tm.tm_mon = i;
1.3 millert 123: l = strftime(buf, sizeof(buf), "%b", &tm);
124: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 125: ;
126: buf[l] = '\0';
127: if (nmonths[i].name != NULL)
128: free(nmonths[i].name);
129: if ((nmonths[i].name = strdup(buf)) == NULL)
130: errx(1, "cannot allocate memory");
131: nmonths[i].len = strlen(buf);
132:
1.3 millert 133: l = strftime(buf, sizeof(buf), "%B", &tm);
134: for (; l > 0 && isspace((int)buf[l - 1]); l--)
1.1 millert 135: ;
136: buf[l] = '\0';
137: if (fnmonths[i].name != NULL)
138: free(fnmonths[i].name);
139: if ((fnmonths[i].name = strdup(buf)) == NULL)
140: errx(1, "cannot allocate memory");
141: fnmonths[i].len = strlen(buf);
142: }
143: }
144:
145: void
146: settime(now)
147: time_t now;
148: {
149: tp = localtime(&now);
1.4 deraadt 150: if (isleap(tp->tm_year + TM_YEAR_BASE)) {
1.1 millert 151: yrdays = DAYSPERLYEAR;
152: cumdays = daytab[1];
153: } else {
154: yrdays = DAYSPERNYEAR;
155: cumdays = daytab[0];
156: }
157: /* Friday displays Monday's events */
158: offset = tp->tm_wday == 5 ? 3 : 1;
159: header[5].iov_base = dayname;
160:
161: (void) setlocale(LC_TIME, "C");
162: header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
163: (void) setlocale(LC_TIME, "");
164:
165: setnnames();
166: }
167:
1.2 millert 168: /* convert [Year][Month]Day into unix time (since 1970)
169: * Year: two or four digits, Month: two digits, Day: two digits
1.1 millert 170: */
171: time_t Mktime (date)
172: char *date;
173: {
174: time_t t;
175: int len;
176: struct tm tm;
177:
178: (void)time(&t);
179: tp = localtime(&t);
180:
181: len = strlen(date);
1.2 millert 182: if (len < 2)
183: return((time_t)-1);
1.1 millert 184: tm.tm_sec = 0;
185: tm.tm_min = 0;
1.5 ! pjanzen 186: /* Avoid getting caught by a timezone shift; set time to noon */
! 187: tm.tm_isdst = 0;
! 188: tm.tm_hour = 12;
1.1 millert 189: tm.tm_wday = 0;
190: tm.tm_mday = tp->tm_mday;
191: tm.tm_mon = tp->tm_mon;
192: tm.tm_year = tp->tm_year;
193:
1.2 millert 194: /* Day */
195: tm.tm_mday = atoi(date + len - 2);
1.1 millert 196:
1.2 millert 197: /* Month */
1.1 millert 198: if (len >= 4) {
1.2 millert 199: *(date + len - 2) = '\0';
200: tm.tm_mon = atoi(date + len - 4) - 1;
1.1 millert 201: }
202:
203: /* Year */
1.5 ! pjanzen 204: if (len >= 6) {
1.2 millert 205: *(date + len - 4) = '\0';
206: tm.tm_year = atoi(date);
1.1 millert 207:
1.4 deraadt 208: /* tm_year up TM_YEAR_BASE ... */
1.5 ! pjanzen 209: if (tm.tm_year < 69) /* Y2K */
1.4 deraadt 210: tm.tm_year += 2000 - TM_YEAR_BASE;
211: else if (tm.tm_year < 100)
212: tm.tm_year += 1900 - TM_YEAR_BASE;
213: else if (tm.tm_year > TM_YEAR_BASE)
214: tm.tm_year -= TM_YEAR_BASE;
1.1 millert 215: }
216:
217: #if DEBUG
218: printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
219: asctime(&tm));
220: #endif
221: return(mktime(&tm));
222: }
223:
224: /*
225: * Possible date formats include any combination of:
226: * 3-charmonth (January, Jan, Jan)
227: * 3-charweekday (Friday, Monday, mon.)
228: * numeric month or day (1, 2, 04)
229: *
230: * Any character may separate them, or they may not be separated. Any line,
231: * following a line that is matched, that starts with "whitespace", is shown
232: * along with the matched line.
233: */
234: int
235: isnow(endp, monthp, dayp, varp)
236: char *endp;
237: int *monthp;
238: int *dayp;
239: int *varp;
240: {
241: int day, flags = 0, month = 0, v1, v2;
242:
243: /*
244: * CONVENTION
245: *
246: * Month: 1-12
247: * Monthname: Jan .. Dec
248: * Day: 1-31
249: * Weekday: Mon-Sun
250: *
251: */
252:
253: /* read first field */
254: /* didn't recognize anything, skip it */
255: if (!(v1 = getfield(endp, &endp, &flags)))
256: return (0);
257:
258: /* Easter or Easter depending days */
259: if (flags & F_EASTER)
260: day = v1 - 1; /* days since January 1 [0-365] */
261:
262: /*
263: * 1. {Weekday,Day} XYZ ...
264: *
265: * where Day is > 12
266: */
267: else if (flags & F_ISDAY || v1 > 12) {
268:
269: /* found a day; day: 1-31 or weekday: 1-7 */
270: day = v1;
271:
272: /* {Day,Weekday} {Month,Monthname} ... */
273: /* if no recognizable month, assume just a day alone
274: * in other words, find month or use current month */
275: if (!(month = getfield(endp, &endp, &flags)))
276: month = tp->tm_mon + 1;
277: }
278:
279: /* 2. {Monthname} XYZ ... */
280: else if (flags & F_ISMONTH) {
281: month = v1;
282:
283: /* Monthname {day,weekday} */
284: /* if no recognizable day, assume the first day in month */
285: if (!(day = getfield(endp, &endp, &flags)))
286: day = 1;
287: }
288:
289: /* Hm ... */
290: else {
291: v2 = getfield(endp, &endp, &flags);
292:
293: /*
294: * {Day} {Monthname} ...
295: * where Day <= 12
296: */
297: if (flags & F_ISMONTH) {
298: day = v1;
299: month = v2;
300: *varp = 0;
301: }
302:
303: /* {Month} {Weekday,Day} ... */
304: else {
305: /* F_ISDAY set, v2 > 12, or no way to tell */
306: month = v1;
307: /* if no recognizable day, assume the first */
308: day = v2 ? v2 : 1;
309: *varp = 0;
310: }
311: }
312:
313: /* convert Weekday into *next* Day,
314: * e.g.: 'Sunday' -> 22
1.5 ! pjanzen 315: * 'SundayLast' -> ??
1.1 millert 316: */
317: if (flags & F_ISDAY) {
318: #if DEBUG
319: fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
320: #endif
321:
322: *varp = 1;
323: /* variable weekday, SundayLast, MondayFirst ... */
324: if (day < 0 || day >= 10) {
325:
326: /* negative offset; last, -4 .. -1 */
327: if (day < 0) {
328: v1 = day/10 - 1; /* offset -4 ... -1 */
1.5 ! pjanzen 329: day = 10 + (day % 10); /* day 1 ... 7 */
1.1 millert 330:
1.5 ! pjanzen 331: /* which weekday the end of the month is (1-7) */
! 332: v2 = (cumdays[month + 1] - tp->tm_yday +
! 333: tp->tm_wday + 371) % 7 + 1;
! 334:
! 335: /* and subtract enough days */
! 336: day = cumdays[month + 1] - cumdays[month] +
! 337: (v1 + 1) * 7 - (v2 - day + 7) % 7;
! 338: #if DEBUG
! 339: fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2);
! 340: #endif
1.1 millert 341: }
342:
343: /* first, second ... +1 ... +5 */
344: else {
1.5 ! pjanzen 345: v1 = day/10; /* offset */
1.1 millert 346: day = day % 10;
347:
1.5 ! pjanzen 348: /* which weekday the first of the month is */
! 349: v2 = (cumdays[month] - tp->tm_yday +
! 350: tp->tm_wday + 372) % 7 + 1;
! 351:
! 352: /* and add enough days */
! 353: day = 1 + (v1 - 1) * 7 + (day - v2 + 7) % 7;
! 354: #if DEBUG
! 355: fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2);
! 356: #endif
1.1 millert 357: }
358: }
359: }
360:
361: if (!(flags & F_EASTER)) {
362: *monthp = month;
363: *dayp = day;
364: day = cumdays[month] + day;
365: }
366: else {
367: for (v1 = 0; day > cumdays[v1]; v1++)
368: ;
369: *monthp = v1 - 1;
370: *dayp = day - cumdays[v1 - 1];
371: *varp = 1;
372: }
373:
374: #if DEBUG
375: fprintf(stderr, "day2: day %d(%d) yday %d\n", *dayp, day, tp->tm_yday);
376: #endif
377: /* if today or today + offset days */
378: if (day >= tp->tm_yday - f_dayBefore &&
379: day <= tp->tm_yday + offset + f_dayAfter)
380: return (1);
381:
382: /* if number of days left in this year + days to event in next year */
383: if (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||
384: /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */
385: tp->tm_yday + day - f_dayBefore < 0
386: )
387: return (1);
388: return (0);
389: }
390:
391:
392: int
393: getmonth(s)
394: register char *s;
395: {
396: register char **p;
397: struct fixs *n;
398:
399: for (n = fnmonths; n->name; ++n)
400: if (!strncasecmp(s, n->name, n->len))
401: return ((n - fnmonths) + 1);
402: for (n = nmonths; n->name; ++n)
403: if (!strncasecmp(s, n->name, n->len))
404: return ((n - nmonths) + 1);
405: for (p = months; *p; ++p)
406: if (!strncasecmp(s, *p, 3))
407: return ((p - months) + 1);
408: return (0);
409: }
410:
411:
412: int
413: getday(s)
414: register char *s;
415: {
416: register char **p;
417: struct fixs *n;
418:
419: for (n = fndays; n->name; ++n)
420: if (!strncasecmp(s, n->name, n->len))
421: return ((n - fndays) + 1);
422: for (n = ndays; n->name; ++n)
423: if (!strncasecmp(s, n->name, n->len))
424: return ((n - ndays) + 1);
425: for (p = days; *p; ++p)
426: if (!strncasecmp(s, *p, 3))
427: return ((p - days) + 1);
428: return (0);
429: }
430:
431: /* return offset for variable weekdays
432: * -1 -> last weekday in month
433: * +1 -> first weekday in month
434: * ... etc ...
435: */
436: int
437: getdayvar(s)
438: register char *s;
439: {
440: register int offset;
441:
442:
443: offset = strlen(s);
444:
445:
446: /* Sun+1 or Wednesday-2
447: * ^ ^ */
448:
449: /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
450: switch(*(s + offset - 2)) {
451: case '-':
452: return(-(atoi(s + offset - 1)));
453: break;
454: case '+':
455: return(atoi(s + offset - 1));
456: break;
457: }
458:
459:
460: /*
461: * some aliases: last, first, second, third, fourth
462: */
463:
464: /* last */
465: if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
466: return(-1);
467: else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
468: return(+1);
469: else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
470: return(+2);
471: else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
472: return(+3);
473: else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
474: return(+4);
475:
476:
477: /* no offset detected */
478: return(0);
479: }