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