Annotation of src/usr.bin/calendar/day.c, Revision 1.4
1.4 ! deraadt 1: /* $OpenBSD: day.c,v 1.3 1998/02/23 05:48:42 millert 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.4 ! deraadt 46: static char rcsid[] = "$OpenBSD: day.c,v 1.3 1998/02/23 05:48:42 millert 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;
186: tm.tm_hour = 0;
187: tm.tm_wday = 0;
188: tm.tm_mday = tp->tm_mday;
189: tm.tm_mon = tp->tm_mon;
190: tm.tm_year = tp->tm_year;
191:
1.2 millert 192: /* Day */
193: tm.tm_mday = atoi(date + len - 2);
1.1 millert 194:
1.2 millert 195: /* Month */
1.1 millert 196: if (len >= 4) {
1.2 millert 197: *(date + len - 2) = '\0';
198: tm.tm_mon = atoi(date + len - 4) - 1;
1.1 millert 199: }
200:
201: /* Year */
202: if (len >= 7) {
1.2 millert 203: *(date + len - 4) = '\0';
204: tm.tm_year = atoi(date);
1.1 millert 205:
1.4 ! deraadt 206: /* tm_year up TM_YEAR_BASE ... */
! 207: if (tm.tm_year < 70)
! 208: tm.tm_year += 2000 - TM_YEAR_BASE;
! 209: else if (tm.tm_year < 100)
! 210: tm.tm_year += 1900 - TM_YEAR_BASE;
! 211: else if (tm.tm_year > TM_YEAR_BASE)
! 212: tm.tm_year -= TM_YEAR_BASE;
1.1 millert 213: }
214:
215: #if DEBUG
216: printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
217: asctime(&tm));
218: #endif
219: return(mktime(&tm));
220: }
221:
222: /*
223: * Possible date formats include any combination of:
224: * 3-charmonth (January, Jan, Jan)
225: * 3-charweekday (Friday, Monday, mon.)
226: * numeric month or day (1, 2, 04)
227: *
228: * Any character may separate them, or they may not be separated. Any line,
229: * following a line that is matched, that starts with "whitespace", is shown
230: * along with the matched line.
231: */
232: int
233: isnow(endp, monthp, dayp, varp)
234: char *endp;
235: int *monthp;
236: int *dayp;
237: int *varp;
238: {
239: int day, flags = 0, month = 0, v1, v2;
240:
241: /*
242: * CONVENTION
243: *
244: * Month: 1-12
245: * Monthname: Jan .. Dec
246: * Day: 1-31
247: * Weekday: Mon-Sun
248: *
249: */
250:
251: /* read first field */
252: /* didn't recognize anything, skip it */
253: if (!(v1 = getfield(endp, &endp, &flags)))
254: return (0);
255:
256: /* Easter or Easter depending days */
257: if (flags & F_EASTER)
258: day = v1 - 1; /* days since January 1 [0-365] */
259:
260: /*
261: * 1. {Weekday,Day} XYZ ...
262: *
263: * where Day is > 12
264: */
265: else if (flags & F_ISDAY || v1 > 12) {
266:
267: /* found a day; day: 1-31 or weekday: 1-7 */
268: day = v1;
269:
270: /* {Day,Weekday} {Month,Monthname} ... */
271: /* if no recognizable month, assume just a day alone
272: * in other words, find month or use current month */
273: if (!(month = getfield(endp, &endp, &flags)))
274: month = tp->tm_mon + 1;
275: }
276:
277: /* 2. {Monthname} XYZ ... */
278: else if (flags & F_ISMONTH) {
279: month = v1;
280:
281: /* Monthname {day,weekday} */
282: /* if no recognizable day, assume the first day in month */
283: if (!(day = getfield(endp, &endp, &flags)))
284: day = 1;
285: }
286:
287: /* Hm ... */
288: else {
289: v2 = getfield(endp, &endp, &flags);
290:
291: /*
292: * {Day} {Monthname} ...
293: * where Day <= 12
294: */
295: if (flags & F_ISMONTH) {
296: day = v1;
297: month = v2;
298: *varp = 0;
299: }
300:
301: /* {Month} {Weekday,Day} ... */
302: else {
303: /* F_ISDAY set, v2 > 12, or no way to tell */
304: month = v1;
305: /* if no recognizable day, assume the first */
306: day = v2 ? v2 : 1;
307: *varp = 0;
308: }
309: }
310:
311: /* convert Weekday into *next* Day,
312: * e.g.: 'Sunday' -> 22
313: * 'SunayLast' -> ??
314: */
315: if (flags & F_ISDAY) {
316: #if DEBUG
317: fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
318: #endif
319:
320: *varp = 1;
321: /* variable weekday, SundayLast, MondayFirst ... */
322: if (day < 0 || day >= 10) {
323:
324: /* negative offset; last, -4 .. -1 */
325: if (day < 0) {
326: v1 = day/10 - 1; /* offset -4 ... -1 */
327: day = 10 + (day % 10); /* day 1 ... 7 */
328:
329: /* day, eg '22th' */
330: v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
331:
332: /* (month length - day) / 7 + 1 */
333: if (((int)((cumdays[month+1] -
334: cumdays[month] - v2) / 7) + 1) == -v1)
335: /* bingo ! */
336: day = v2;
337:
338: /* set to yesterday */
339: else
340: day = tp->tm_mday - 1;
341: }
342:
343: /* first, second ... +1 ... +5 */
344: else {
345: v1 = day/10; /* offset: +1 (first Sunday) ... */
346: day = day % 10;
347:
348: /* day, eg '22th' */
349: v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
350:
351: /* Hurrah! matched */
352: if ( ((v2 - 1 + 7) / 7) == v1 )
353: day = v2;
354:
355: /* set to yesterday */
356: else
357: day = tp->tm_mday - 1;
358: }
359: }
360:
361: /* wired */
362: else {
363: day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
364: *varp = 1;
365: }
366: }
367:
368: if (!(flags & F_EASTER)) {
369: *monthp = month;
370: *dayp = day;
371: day = cumdays[month] + day;
372: }
373: else {
374: for (v1 = 0; day > cumdays[v1]; v1++)
375: ;
376: *monthp = v1 - 1;
377: *dayp = day - cumdays[v1 - 1];
378: *varp = 1;
379: }
380:
381: #if DEBUG
382: fprintf(stderr, "day2: day %d(%d) yday %d\n", *dayp, day, tp->tm_yday);
383: #endif
384: /* if today or today + offset days */
385: if (day >= tp->tm_yday - f_dayBefore &&
386: day <= tp->tm_yday + offset + f_dayAfter)
387: return (1);
388:
389: /* if number of days left in this year + days to event in next year */
390: if (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||
391: /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */
392: tp->tm_yday + day - f_dayBefore < 0
393: )
394: return (1);
395: return (0);
396: }
397:
398:
399: int
400: getmonth(s)
401: register char *s;
402: {
403: register char **p;
404: struct fixs *n;
405:
406: for (n = fnmonths; n->name; ++n)
407: if (!strncasecmp(s, n->name, n->len))
408: return ((n - fnmonths) + 1);
409: for (n = nmonths; n->name; ++n)
410: if (!strncasecmp(s, n->name, n->len))
411: return ((n - nmonths) + 1);
412: for (p = months; *p; ++p)
413: if (!strncasecmp(s, *p, 3))
414: return ((p - months) + 1);
415: return (0);
416: }
417:
418:
419: int
420: getday(s)
421: register char *s;
422: {
423: register char **p;
424: struct fixs *n;
425:
426: for (n = fndays; n->name; ++n)
427: if (!strncasecmp(s, n->name, n->len))
428: return ((n - fndays) + 1);
429: for (n = ndays; n->name; ++n)
430: if (!strncasecmp(s, n->name, n->len))
431: return ((n - ndays) + 1);
432: for (p = days; *p; ++p)
433: if (!strncasecmp(s, *p, 3))
434: return ((p - days) + 1);
435: return (0);
436: }
437:
438: /* return offset for variable weekdays
439: * -1 -> last weekday in month
440: * +1 -> first weekday in month
441: * ... etc ...
442: */
443: int
444: getdayvar(s)
445: register char *s;
446: {
447: register int offset;
448:
449:
450: offset = strlen(s);
451:
452:
453: /* Sun+1 or Wednesday-2
454: * ^ ^ */
455:
456: /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
457: switch(*(s + offset - 2)) {
458: case '-':
459: return(-(atoi(s + offset - 1)));
460: break;
461: case '+':
462: return(atoi(s + offset - 1));
463: break;
464: }
465:
466:
467: /*
468: * some aliases: last, first, second, third, fourth
469: */
470:
471: /* last */
472: if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
473: return(-1);
474: else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
475: return(+1);
476: else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
477: return(+2);
478: else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
479: return(+3);
480: else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
481: return(+4);
482:
483:
484: /* no offset detected */
485: return(0);
486: }