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