diff options
author | Paul Janzen <pjanzen@cvs.openbsd.org> | 1998-12-13 07:31:09 +0000 |
---|---|---|
committer | Paul Janzen <pjanzen@cvs.openbsd.org> | 1998-12-13 07:31:09 +0000 |
commit | 760c897652aa6def6b96dcc2b0fe49b2a2f3285f (patch) | |
tree | b8c2e41425055a9d8a25e1d78f26e697d98886b2 /usr.bin | |
parent | 769fe37ced22b9ae2be3b955a68ee7d1a2197715 (diff) |
Show periodic events the correct number of times.
Calculate special events (Easter) correctly regardless of which year
they occur in (thus fixing user/562).
Keep locales and special event names from propogating from one user
to the next during "calendar -a".
Set up a framework to handle special events other than Easter (for instance,
Jewish events, eventually).
Various other fixes.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/calendar/calendar.1 | 55 | ||||
-rw-r--r-- | usr.bin/calendar/calendar.c | 29 | ||||
-rw-r--r-- | usr.bin/calendar/calendar.h | 49 | ||||
-rw-r--r-- | usr.bin/calendar/day.c | 382 | ||||
-rw-r--r-- | usr.bin/calendar/io.c | 151 | ||||
-rw-r--r-- | usr.bin/calendar/ostern.c | 60 | ||||
-rw-r--r-- | usr.bin/calendar/paskha.c | 61 |
7 files changed, 468 insertions, 319 deletions
diff --git a/usr.bin/calendar/calendar.1 b/usr.bin/calendar/calendar.1 index dfab39bc117..aad57d92112 100644 --- a/usr.bin/calendar/calendar.1 +++ b/usr.bin/calendar/calendar.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: calendar.1,v 1.8 1998/11/08 04:37:51 pjanzen Exp $ +.\" $OpenBSD: calendar.1,v 1.9 1998/12/13 07:31:07 pjanzen Exp $ .\" .\" Copyright (c) 1989, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -40,7 +40,7 @@ .Nm calendar .Nd reminder service .Sh SYNOPSIS -.Nm calendar +.Nm .Op Fl a .Op Fl A Ar num .Op Fl B Ar num @@ -48,7 +48,7 @@ .Op Fl f Ar calendarfile .Sh DESCRIPTION The -.Nm calendar +.Nm utility checks the current directory or the directory specified by the .Ev CALENDAR_DIR environment variable for a file named @@ -60,7 +60,9 @@ On Fridays, events on Friday through Monday are displayed. The following options are available: .Bl -tag -width Ds .It Fl a -Process the ``calendar'' files of all users and mail the results +Process the +.Dq calendar +files of all users and mail the results to them. This requires super-user privileges. .It Fl A Ar num @@ -76,7 +78,9 @@ Use .Pa calendarfile as the default calendar file. .It Fl t Ar [[[cc]yy][mm]]dd -Act like the specified value is ``today'' instead of using the current date. +Act like the specified value is +.Dq today +instead of using the current date. .El .Pp To handle calendars in your national code table you can specify @@ -99,13 +103,17 @@ A month without a day matches the first of that month. Two numbers default to the month followed by the day. Lines with leading tabs default to the last entered date, allowing multiple line specifications for a single date. -``Easter'' (may be followed by a positive or negative integer) is -Easter for this year. -``Paskha'' (may be followed by a positive or negative integer) is +.Dq Easter +(may be followed by a positive or negative integer) is Easter for this year. +.Dq Paskha +(may be followed by a positive or negative integer) is Orthodox Easter for this year. -Weekdays may be followed by ``-4'' ... ``+5'' (aliases -last, first, second, third, fourth) for moving events like -``the last Monday in April''. +Weekdays may be followed by +.Dq -4 +.Li ... +.Dq +5 +(aliases last, first, second, third, fourth) for moving events like +.Dq the last Monday in April . .Pp By convention, dates followed by an asterisk .Pq Sq * @@ -117,7 +125,7 @@ if the line does not contain a <tab> character, it isn't printed out. If the first character in the line is a <tab> character, it is treated as the continuation of the previous description. .Pp -The ``calendar'' file is preprocessed by +The calendar file is preprocessed by .Xr cpp 1 , allowing the inclusion of shared files such as company holidays or meetings. @@ -159,13 +167,13 @@ Paskha\fB\et\fROrthodox Easter file in current directory .It Pa ~/.calendar file in home directory (which -.Nm calendar +.Nm .Xr chdir 1 's into if it exists) .It Pa ~/.calendar/calendar file to use if no calendar file exists in the current directory .It Pa ~/.calendar/nomail -.Nm calendar +.Nm will not send mail if this file exists .It Pa calendar.birthday births and deaths of famous (and not-so-famous) people @@ -186,8 +194,7 @@ so that roving holidays are set correctly for the current year) .It Pa calendar.music musical events, births, and deaths (strongly oriented toward rock n' roll) .It Pa calendar.usholiday -U.S. holidays (should be updated yearly by the local system administrator -so that roving holidays are set correctly for the current year) +U.S. holidays .It Pa calendar.german German calendar .It Pa calendar.russian @@ -211,19 +218,5 @@ A command appeared in .At v7 . .Sh BUGS -.Nm calendar +.Nm doesn't handle Jewish holidays or moon phases. -.br -When used with the -.Fl A -and -.Fl B -flags, -.Nm calendar -will only print the first instance of periodic events. When using the -.Fl A -and -.Fl B -flags to cross a year boundary, -.Nm calendar -will use calculate the date of easter in the current year, not the next year. diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c index 0a3dd8ef863..cef979181ef 100644 --- a/usr.bin/calendar/calendar.c +++ b/usr.bin/calendar/calendar.c @@ -1,4 +1,4 @@ -/* $OpenBSD: calendar.c,v 1.11 1998/11/04 11:32:02 pjanzen Exp $ */ +/* $OpenBSD: calendar.c,v 1.12 1998/12/13 07:31:07 pjanzen Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -43,7 +43,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #else -static char rcsid[] = "$OpenBSD: calendar.c,v 1.11 1998/11/04 11:32:02 pjanzen Exp $"; +static char rcsid[] = "$OpenBSD: calendar.c,v 1.12 1998/12/13 07:31:07 pjanzen Exp $"; #endif #endif /* not lint */ @@ -55,6 +55,7 @@ static char rcsid[] = "$OpenBSD: calendar.c,v 1.11 1998/11/04 11:32:02 pjanzen E #include <stdlib.h> #include <string.h> #include <time.h> +#include <tzfile.h> #include <unistd.h> #include "pathnames.h" @@ -67,15 +68,17 @@ time_t f_time = 0; int f_dayAfter = 0; /* days after current date */ int f_dayBefore = 0; /* days before current date */ +struct specialev spev[NUMEV]; + int main(argc, argv) int argc; char *argv[]; { - int ch; + int ch, i; char *caldir; - (void) setlocale(LC_ALL, ""); + (void)setlocale(LC_ALL, ""); while ((ch = getopt(argc, argv, "-af:t:A:B:")) != -1) switch (ch) { @@ -91,7 +94,7 @@ main(argc, argv) break; case 't': /* other date, undocumented, for tests */ - if ((f_time = Mktime (optarg)) <= 0) + if ((f_time = Mktime(optarg)) <= 0) errx(1, "specified date is outside allowed range"); break; @@ -116,15 +119,27 @@ main(argc, argv) if (f_time <= 0) (void)time(&f_time); - settime(f_time); + if (f_dayBefore) { + /* Move back in time and only look forwards */ + f_dayAfter += f_dayBefore; + f_time -= SECSPERDAY * f_dayBefore; + f_dayBefore = 0; + } + settime(&f_time); if (doall) { while ((pw = getpwent()) != NULL) { + (void)setlocale(LC_ALL, ""); (void)setegid(pw->pw_gid); (void)initgroups(pw->pw_name, pw->pw_gid); (void)seteuid(pw->pw_uid); - if (!chdir(pw->pw_dir)) + if (!chdir(pw->pw_dir)) { cal(); + /* Keep user settings from propogating */ + for (i = 0; i < NUMEV; i++) + if (spev[i].uname != NULL) + free(spev[i].uname); + } (void)seteuid(0); } } diff --git a/usr.bin/calendar/calendar.h b/usr.bin/calendar/calendar.h index cd0bed0acff..e16ae8677e0 100644 --- a/usr.bin/calendar/calendar.h +++ b/usr.bin/calendar/calendar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: calendar.h,v 1.3 1998/11/08 04:31:13 pjanzen Exp $ */ +/* $OpenBSD: calendar.h,v 1.4 1998/12/13 07:31:07 pjanzen Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -36,6 +36,7 @@ extern struct passwd *pw; extern int doall; +extern time_t f_time; extern struct iovec header[]; extern struct tm *tp; extern char *calendarFile; @@ -49,13 +50,24 @@ struct fixs { struct event { time_t when; char print_date[31]; - char *desc; + char **desc; + char *ldesc; struct event *next; }; struct match { - int year, month, day, var; - struct match *next; + time_t when; + char print_date[30]; + int var; + struct match *next; +}; + +struct specialev { + char *name; + int nlen; + char *uname; + int ulen; + int (*getev) __P((int)); }; void cal __P((void)); @@ -64,22 +76,35 @@ int getday __P((char *)); int getdayvar __P((char *)); int getfield __P((char *, char **, int *)); int getmonth __P((char *)); -int geteaster __P((char *, int)); -int getpaskha __P((char *, int)); -int easter __P((int)); +int easter __P((int)); +int paskha __P((int)); void insert __P((struct event **, struct event *)); struct match *isnow __P((char *)); FILE *opencal __P((void)); -void settime __P((time_t)); -time_t Mktime __P((char *)); +void settime __P((time_t *)); +time_t Mktime __P((char *)); void usage __P((void)); -void setnnames __P((void)); +int foy __P((int)); +void variable_weekday __P((int *, int, int)); +void setnnames __P((void)); /* some flags */ #define F_ISMONTH 0x01 /* month (Januar ...) */ #define F_ISDAY 0x02 /* day of week (Sun, Mon, ...) */ -#define F_ISDAYVAR 0x04 /* variables day of week, like SundayLast */ -#define F_EASTER 0x08 /* Easter or easter depending days */ +/*#define F_ISDAYVAR 0x04 variables day of week, like SundayLast */ +#define F_SPECIAL 0x08 /* Events that occur once a year but don't track + * calendar time--e.g. Easter or easter depending + * days */ extern int f_dayAfter; /* days after current date */ extern int f_dayBefore; /* days before current date */ + +/* Special events; see also setnnames() in day.c */ +/* '=' is not a valid character in a special event name */ +#define EASTER "easter" +#define EASTERNAMELEN (sizeof(EASTER) - 1) +#define PASKHA "paskha" +#define PASKHALEN (sizeof(PASKHA) - 1) + +#define NUMEV 2 /* Total number of such special events */ +extern struct specialev spev[NUMEV]; diff --git a/usr.bin/calendar/day.c b/usr.bin/calendar/day.c index 141f905d2f1..bab95fab490 100644 --- a/usr.bin/calendar/day.c +++ b/usr.bin/calendar/day.c @@ -1,4 +1,4 @@ -/* $OpenBSD: day.c,v 1.6 1998/11/08 04:31:13 pjanzen Exp $ */ +/* $OpenBSD: day.c,v 1.7 1998/12/13 07:31:07 pjanzen Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -43,7 +43,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #else -static char rcsid[] = "$OpenBSD: day.c,v 1.6 1998/11/08 04:31:13 pjanzen Exp $"; +static char rcsid[] = "$OpenBSD: day.c,v 1.7 1998/12/13 07:31:07 pjanzen Exp $"; #endif #endif /* not lint */ @@ -62,8 +62,12 @@ static char rcsid[] = "$OpenBSD: day.c,v 1.6 1998/11/08 04:31:13 pjanzen Exp $"; #include "pathnames.h" #include "calendar.h" +#define WEEKLY 1 +#define MONTHLY 2 +#define YEARLY 3 + struct tm *tp; -int *cumdays, offset, yrdays; +int *cumdays, offset; char dayname[10]; @@ -140,22 +144,39 @@ void setnnames(void) errx(1, "cannot allocate memory"); fnmonths[i].len = strlen(buf); } + /* Hardwired special events */ + spev[0].name = strdup(EASTER); + spev[0].nlen = EASTERNAMELEN; + spev[0].getev = easter; + spev[1].name = strdup(PASKHA); + spev[1].nlen = PASKHALEN; + spev[1].getev = paskha; + for (i = 0; i < NUMEV; i++) { + if (spev[i].name == NULL) + errx(1, "cannot allocate memory"); + spev[i].uname = NULL; + } } void settime(now) - time_t now; + time_t *now; { - tp = localtime(&now); - if (isleap(tp->tm_year + TM_YEAR_BASE)) { - yrdays = DAYSPERLYEAR; + tp = localtime(now); + tp->tm_sec = 0; + tp->tm_min = 0; + /* Avoid getting caught by a timezone shift; set time to noon */ + tp->tm_isdst = 0; + tp->tm_hour = 12; + *now = mktime(tp); + if (isleap(tp->tm_year + TM_YEAR_BASE)) cumdays = daytab[1]; - } else { - yrdays = DAYSPERNYEAR; + else cumdays = daytab[0]; - } /* Friday displays Monday's events */ offset = tp->tm_wday == 5 ? 3 : 1; + if (f_dayAfter) + offset = 0; /* Except not when range is set explicitly */ header[5].iov_base = dayname; (void) setlocale(LC_TIME, "C"); @@ -202,8 +223,8 @@ time_t Mktime (date) /* Year */ if (len >= 6) { - *(date + len - 4) = '\0'; - tm.tm_year = atoi(date); + *(date + len - 4) = '\0'; + tm.tm_year = atoi(date); /* tm_year up TM_YEAR_BASE ... */ if (tm.tm_year < 69) /* Y2K */ @@ -235,9 +256,13 @@ struct match * isnow(endp) char *endp; { - int day, flags = 0, month = 0, v1, v2; - int monthp, dayp, varp; - struct match *matches; + int day = 0, flags = 0, month = 0, v1, v2, i; + int monthp, dayp, varp = 0; + struct match *matches = NULL, *tmp, *tmp2; + int interval = YEARLY; /* how frequently the event repeats. */ + int vwd = 0; /* Variable weekday */ + time_t tdiff, ttmp; + struct tm tmtmp; /* * CONVENTION @@ -255,8 +280,8 @@ isnow(endp) return (NULL); /* Easter or Easter depending days */ - if (flags & F_EASTER) - day = v1 - 1; /* days since January 1 [0-365] */ + if (flags & F_SPECIAL) + vwd = v1; /* * 1. {Weekday,Day} XYZ ... @@ -265,24 +290,47 @@ isnow(endp) */ else if (flags & F_ISDAY || v1 > 12) { - /* found a day; day: 1-31 or weekday: 1-7 */ + /* found a day; day: 13-31 or weekday: 1-7 */ day = v1; /* {Day,Weekday} {Month,Monthname} ... */ - /* if no recognizable month, assume just a day alone - * in other words, find month or use current month */ - if (!(month = getfield(endp, &endp, &flags))) + /* if no recognizable month, assume just a day alone -- this is + * very unlikely and can only happen after the first 12 days. + * --find month or use current month */ + if (!(month = getfield(endp, &endp, &flags))) { month = tp->tm_mon + 1; + /* F_ISDAY is set only if a weekday was spelled out */ + /* F_ISDAY must be set if 0 < day < 8 */ + if ((day <= 7) && (day >= 1)) + interval = WEEKLY; + else + interval = MONTHLY; + } else if ((day <= 7) && (day >= 1)) + day += 10; + /* it's a weekday; make it the first one of the month */ + if (month == -1) { + month = tp->tm_mon + 1; + interval = MONTHLY; + } + if ((month > 12) || (month < 1)) + return (NULL); } /* 2. {Monthname} XYZ ... */ else if (flags & F_ISMONTH) { month = v1; - + if (month == -1) { + month = tp->tm_mon + 1; + interval = MONTHLY; + } /* Monthname {day,weekday} */ /* if no recognizable day, assume the first day in month */ if (!(day = getfield(endp, &endp, &flags))) day = 1; + /* If a weekday was spelled out without an ordering, + * assume the first of that day in the month */ + if ((flags & F_ISDAY) && (day >= 1) && (day <=7)) + day += 10; } /* Hm ... */ @@ -296,7 +344,10 @@ isnow(endp) if (flags & F_ISMONTH) { day = v1; month = v2; - varp = 0; + if (month == -1) { + month = tp->tm_mon + 1; + interval = MONTHLY; + } } /* {Month} {Weekday,Day} ... */ @@ -305,7 +356,8 @@ isnow(endp) month = v1; /* if no recognizable day, assume the first */ day = v2 ? v2 : 1; - varp = 0; + if ((flags & F_ISDAY) && (day >= 1) && (day <= 7)) + day += 10; } } @@ -315,85 +367,167 @@ isnow(endp) */ if (flags & F_ISDAY) { #if DEBUG - fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month); + fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month); #endif - varp = 1; - /* variable weekday, SundayLast, MondayFirst ... */ - if (day < 0 || day >= 10) { - - /* negative offset; last, -4 .. -1 */ - if (day < 0) { - v1 = day/10 - 1; /* offset -4 ... -1 */ - day = 10 + (day % 10); /* day 1 ... 7 */ - - /* which weekday the end of the month is (1-7) */ - v2 = (cumdays[month + 1] - tp->tm_yday + - tp->tm_wday + 371) % 7 + 1; - - /* and subtract enough days */ - day = cumdays[month + 1] - cumdays[month] + - (v1 + 1) * 7 - (v2 - day + 7) % 7; -#if DEBUG - fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2); -#endif + varp = 1; + /* variable weekday, SundayLast, MondayFirst ... */ + if (day < 0 || day >= 10) + vwd = day; + else { + day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); + interval = WEEKLY; + } + } else + /* Check for silliness. Note we still catch Feb 29 */ + if (!(flags & F_SPECIAL) && + (day > (cumdays[month + 1] - cumdays[month]) || day < 1)) { + if (!((month == 2 && day == 29) || + (interval == MONTHLY && day <= 31))) + return (NULL); } - /* first, second ... +1 ... +5 */ - else { - v1 = day/10; /* offset */ - day = day % 10; - - /* which weekday the first of the month is */ - v2 = (cumdays[month] - tp->tm_yday + - tp->tm_wday + 372) % 7 + 1; - - /* and add enough days */ - day = 1 + (v1 - 1) * 7 + (day - v2 + 7) % 7; + if (!(flags & F_SPECIAL)) { + monthp = month; + dayp = day; + day = cumdays[month] + day; #if DEBUG - fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2); + fprintf(stderr, "day2: day %d(%d) yday %d\n", dayp, day, tp->tm_yday); #endif - } - } - else - day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); - } - - if (!(flags & F_EASTER)) { - monthp = month; - dayp = day; - day = cumdays[month] + day; + /* Speed up processing for the most common situation: yearly events + * when the interval being checked is less than a month or so (this + * could be less than a year, but then we have to start worrying about + * leap years). Only one event can match, and it's easy to find. + * Note we can't check special events, because they can wander widely. + */ + if (((v1 = offset + f_dayAfter) < 50) && (interval == YEARLY)) { + memcpy(&tmtmp, tp, sizeof(struct tm)); + tmtmp.tm_mday = dayp; + tmtmp.tm_mon = monthp - 1; + v2 = day - tp->tm_yday; + if ((v2 > v1) || (v2 < 0)) { + if ((v2 += isleap(tp->tm_year + TM_YEAR_BASE) ? 366 : 365) + <= v1) + tmtmp.tm_year++; + else + return(NULL); + } + if ((tmp = malloc(sizeof(struct match))) == NULL) + errx(1, "cannot allocate memory"); + tmp->when = f_time + v2 * SECSPERDAY; + (void)mktime(&tmtmp); + if (strftime(tmp->print_date, + sizeof(tmp->print_date), + /* "%a %b %d", &tm); Skip weekdays */ + "%b %d", &tmtmp) == 0) + tmp->print_date[sizeof(tmp->print_date) - 1] = '\0'; + tmp->var = varp; + tmp->next = NULL; + return(tmp); + } } else { - for (v1 = 0; day > cumdays[v1]; v1++) - ; - monthp = v1 - 1; - dayp = day - cumdays[v1 - 1]; - varp = 1; + varp = 1; + /* Set up v1 to the event number and ... */ + v1 = vwd % (NUMEV + 1) - 1; + vwd /= (NUMEV + 1); + if (v1 < 0) { + v1 += NUMEV + 1; + vwd--; + } + dayp = monthp = 1; /* Why not */ } -#if DEBUG - fprintf(stderr, "day2: day %d(%d) yday %d\n", dayp, day, tp->tm_yday); -#endif - /* if today or today + offset days */ - if ((day >= tp->tm_yday - f_dayBefore && - day <= tp->tm_yday + offset + f_dayAfter) || - - /* if number of days left in this year + days to event in next year */ - (yrdays - tp->tm_yday + day <= offset + f_dayAfter || - /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */ - tp->tm_yday + day - f_dayBefore < 0 - )) { - if ((matches = malloc(sizeof(struct match))) == NULL) - errx(1,"cannot allocate memory"); - matches->month = monthp; - matches->day = dayp; - matches->var = varp; - matches->year = tp->tm_year; /* XXX */ - matches->next = NULL; - return (matches); + /* Compare to past and coming instances of the event. The i == 0 part + * of the loop corresponds to this specific instance. Note that we + * can leave things sort of higgledy-piggledy since a mktime() happens + * on this before anything gets printed. Also note that even though + * we've effectively gotten rid of f_dayBefore, we still have to check + * the one prior event for situations like "the 31st of every month" + * and "yearly" events which could happen twice in one year but not in + * the next */ + tmp2 = matches; + for (i = -1; i < 2; i++) { + memcpy(&tmtmp, tp, sizeof(struct tm)); + tmtmp.tm_mday = dayp; + tmtmp.tm_mon = month = monthp - 1; + do { + v2 = 0; + switch (interval) { + case WEEKLY: + tmtmp.tm_mday += 7 * i; + break; + case MONTHLY: + month += i; + tmtmp.tm_mon = month; + switch(tmtmp.tm_mon) { + case -1: + tmtmp.tm_mon = month = 11; + tmtmp.tm_year--; + break; + case 12: + tmtmp.tm_mon = month = 0; + tmtmp.tm_year++; + break; + } + if (vwd) { + v1 = vwd; + variable_weekday(&v1, tmtmp.tm_mon + 1, + tmtmp.tm_year + TM_YEAR_BASE); + tmtmp.tm_mday = v1; + } else + tmtmp.tm_mday = dayp; + break; + case YEARLY: + default: + tmtmp.tm_year += i; + if (flags & F_SPECIAL) { + tmtmp.tm_mon = 0; /* Gee, mktime() is nice */ + tmtmp.tm_mday = spev[v1].getev(tmtmp.tm_year + + vwd + TM_YEAR_BASE); + } else if (vwd) { + v1 = vwd; + variable_weekday(&v1, tmtmp.tm_mon + 1, + tmtmp.tm_year + TM_YEAR_BASE); + tmtmp.tm_mday = v1; + } else { + /* Need the following to keep Feb 29 from + * becoming Mar 1 */ + tmtmp.tm_mday = dayp; + tmtmp.tm_mon = monthp - 1; + } + break; + } + /* How many days apart are we */ + if ((ttmp = mktime(&tmtmp)) == -1) + warnx("time out of range: %s", endp); + else { + tdiff = difftime(ttmp, f_time)/ SECSPERDAY; + if (tdiff <= offset + f_dayAfter) { + if (tdiff >= 0) { + if ((tmp = malloc(sizeof(struct match))) == NULL) + errx(1, "cannot allocate memory"); + tmp->when = ttmp; + if (strftime(tmp->print_date, + sizeof(tmp->print_date), + /* "%a %b %d", &tm); Skip weekdays */ + "%b %d", &tmtmp) == 0) + tmp->print_date[sizeof(tmp->print_date) - 1] = '\0'; + tmp->var = varp; + tmp->next = NULL; + if (tmp2) + tmp2->next = tmp; + else + matches = tmp; + tmp2 = tmp; + v2 = (i == 1) ? 1 : 0; + } + } else + i = 2; /* No point checking in the future */ + } + } while (v2 != 0); } - return (NULL); + return (matches); } @@ -450,21 +584,17 @@ getdayvar(s) offset = strlen(s); - /* Sun+1 or Wednesday-2 * ^ ^ */ /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */ switch(*(s + offset - 2)) { case '-': - return(-(atoi(s + offset - 1))); - break; case '+': - return(atoi(s + offset - 1)); + return(atoi(s + offset - 2)); break; } - /* * some aliases: last, first, second, third, fourth */ @@ -481,7 +611,63 @@ getdayvar(s) else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth")) return(+4); - /* no offset detected */ return(0); } + + +int +foy(year) + int year; +{ + /* 0-6; what weekday Jan 1 is */ + year--; + return ((1 - year/100 + year/400 + (int)(365.25 * year)) % 7); +} + + + +void +variable_weekday(day, month, year) + int *day, month, year; +{ + int v1, v2; + int *cumdays; + int day1; + + if (isleap(year)) + cumdays = daytab[1]; + else + cumdays = daytab[0]; + day1 = foy(year); + /* negative offset; last, -4 .. -1 */ + if (*day < 0) { + v1 = *day/10 - 1; /* offset -4 ... -1 */ + *day = 10 + (*day % 10); /* day 1 ... 7 */ + + /* which weekday the end of the month is (1-7) */ + v2 = (cumdays[month + 1] + day1) % 7 + 1; + + /* and subtract enough days */ + *day = cumdays[month + 1] - cumdays[month] + + (v1 + 1) * 7 - (v2 - *day + 7) % 7; +#if DEBUG + fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2); +#endif + } + + /* first, second ... +1 ... +5 */ + else { + v1 = *day/10; /* offset */ + *day = *day % 10; + + /* which weekday the first of the month is (1-7) */ + v2 = (cumdays[month] + 1 + day1) % 7 + 1; + + /* and add enough days */ + *day = 1 + (v1 - 1) * 7 + (*day - v2 + 7) % 7; +#if DEBUG + fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2); +#endif + } +} diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c index 8f238772b23..cb19c8e9628 100644 --- a/usr.bin/calendar/io.c +++ b/usr.bin/calendar/io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: io.c,v 1.5 1998/11/08 04:31:13 pjanzen Exp $ */ +/* $OpenBSD: io.c,v 1.6 1998/12/13 07:31:08 pjanzen Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -43,7 +43,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #else -static char rcsid[] = "$OpenBSD: io.c,v 1.5 1998/11/08 04:31:13 pjanzen Exp $"; +static char rcsid[] = "$OpenBSD: io.c,v 1.6 1998/12/13 07:31:08 pjanzen Exp $"; #endif #endif /* not lint */ @@ -73,8 +73,6 @@ char *calendarFile = "calendar"; /* default calendar file */ char *calendarHome = ".calendar"; /* HOME */ char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */ -struct fixs neaster, npaskha; - struct iovec header[] = { {"From: ", 6}, {NULL, 0}, @@ -92,10 +90,10 @@ cal() register int printing; register char *p; FILE *fp; - int ch, l; + int ch, l, i; int var; char buf[2048 + 1]; - struct event *events, *cur_evt, *tmp; + struct event *events, *cur_evt, *ev1, *tmp; struct match *m; events = NULL; @@ -119,26 +117,29 @@ cal() setnnames(); continue; } - if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) { - if (neaster.name != NULL) - free(neaster.name); - if ((neaster.name = strdup(buf + 7)) == NULL) - errx(1, "cannot allocate memory"); - neaster.len = strlen(buf + 7); - continue; - } - if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) { - if (npaskha.name != NULL) - free(npaskha.name); - if ((npaskha.name = strdup(buf + 7)) == NULL) - errx(1, "cannot allocate memory"); - npaskha.len = strlen(buf + 7); + /* User defined names for special events */ + if ((p = strchr(buf, '='))) { + for (i = 0; i < NUMEV; i++) { + if (strncasecmp(buf, spev[i].name, spev[i].nlen) == 0 && + (p - buf == spev[i].nlen) && buf[spev[i].nlen + 1]) { + p++; + if (spev[i].uname != NULL) + free(spev[i].uname); + if ((spev[i].uname = strdup(p)) == NULL) + errx(1, "cannot allocate memory"); + spev[i].ulen = strlen(p); + i = NUMEV + 1; + } + } + if (i > NUMEV) continue; } if (buf[0] != '\t') { printing = (m = isnow(buf)) ? 1 : 0; - if ((p = strchr(buf, '\t')) == NULL) + if ((p = strchr(buf, '\t')) == NULL) { + printing = 0; continue; + } /* Need the following to catch hardwired "variable" * dates */ if (p > buf && p[-1] == '*') @@ -146,39 +147,26 @@ cal() else var = 0; if (printing) { - struct tm tm; struct match *foo; - char *dsc; - dsc = NULL; + ev1 = NULL; while (m) { cur_evt = (struct event *) malloc(sizeof(struct event)); if (cur_evt == NULL) errx(1, "cannot allocate memory"); - tm.tm_sec = 0; /* unused */ - tm.tm_min = 0; /* unused */ - tm.tm_hour = 12; /* unused */ - tm.tm_wday = 0; /* unused */ - tm.tm_mon = m->month - 1; - tm.tm_mday = m->day; - tm.tm_year = m->year; - tm.tm_isdst = tp->tm_isdst; /* unused */ - tm.tm_gmtoff = tp->tm_gmtoff; /* unused */ - tm.tm_zone = tp->tm_zone; /* unused */ - (void)strftime(cur_evt->print_date, - sizeof(cur_evt->print_date) - 1, - /* "%a %b %d", &tm); Skip weekdays */ - "%b %d", &tm); - strcat(cur_evt->print_date, - (var + m->var) ? "*" : " "); - cur_evt->when = mktime(&tm); - if (dsc) - cur_evt->desc = dsc; - else { - if ((cur_evt->desc = strdup(p)) == NULL) + cur_evt->when = m->when; + snprintf(cur_evt->print_date, + sizeof(cur_evt->print_date), "%s%c", + m->print_date, (var + m->var) ? '*' : ' '); + if (ev1) { + cur_evt->desc = ev1->desc; + cur_evt->ldesc = NULL; + } else { + if ((cur_evt->ldesc = strdup(p)) == NULL) errx(1, "cannot allocate memory"); - dsc = cur_evt->desc; + cur_evt->desc = &(cur_evt->ldesc); + ev1 = cur_evt; } insert(&events, cur_evt); foo = m; @@ -188,19 +176,23 @@ cal() } } else if (printing) { - if ((cur_evt->desc = realloc(cur_evt->desc, - (2 + strlen(cur_evt->desc) + strlen(buf)))) == NULL) + if ((ev1->ldesc = realloc(ev1->ldesc, + (2 + strlen(ev1->ldesc) + strlen(buf)))) == NULL) errx(1, "cannot allocate memory"); - strcat(cur_evt->desc, "\n"); - strcat(cur_evt->desc, buf); + strcat(ev1->ldesc, "\n"); + strcat(ev1->ldesc, buf); } } tmp = events; while (tmp) { - (void)fprintf(fp, "%s%s\n", tmp->print_date, tmp->desc); - /* Can't free descriptions since they may be shared */ - (void)realloc(tmp->desc, 0); + (void)fprintf(fp, "%s%s\n", tmp->print_date, *(tmp->desc)); + tmp = tmp->next; + } + tmp = events; + while (tmp) { events = tmp; + if (tmp->ldesc) + free(tmp->ldesc); tmp = tmp->next; free(events); } @@ -212,15 +204,15 @@ getfield(p, endp, flags) char *p, **endp; int *flags; { - int val, var; + int val, var, i; char *start, savech; for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p) ; - if (*p == '*') { /* `*' is current month */ + if (*p == '*') { /* `*' is every month */ *flags |= F_ISMONTH; *endp = p+1; - return (tp->tm_mon + 1); + return (-1); /* means 'every month' */ } if (isdigit(*p)) { val = strtol(p, &p, 10); /* if 0, it's failure */ @@ -250,7 +242,7 @@ getfield(p, endp, flags) /* variable weekday */ if ((var = getdayvar(start)) != 0) { - if (var <=5 && var >= -4) + if (var <= 5 && var >= -4) val += var * 10; #ifdef DEBUG printf("var: %d\n", var); @@ -258,18 +250,41 @@ getfield(p, endp, flags) } } - /* Easter */ - else if ((val = geteaster(start, tp->tm_year + TM_YEAR_BASE)) != 0) - *flags |= F_EASTER; - - /* Paskha */ - else if ((val = getpaskha(start, tp->tm_year + TM_YEAR_BASE)) != 0) - *flags |= F_EASTER; - - /* undefined rest */ + /* Try specials (Easter, Paskha, ...) */ else { - *p = savech; - return (0); + for (i = 0; i < NUMEV; i++) { + if (strncasecmp(start, spev[i].name, spev[i].nlen) == 0) { + start += spev[i].nlen; + val = i + 1; + i = NUMEV + 1; + } else if (spev[i].uname != NULL && + strncasecmp(start, spev[i].uname, spev[i].ulen) == 0) { + start += spev[i].ulen; + val = i + 1; + i = NUMEV + 1; + } + } + if (i > NUMEV) { + switch(*start) { + case '-': + case '+': + var = atoi(start); + if (var > 365 || var < -365) + return (0); /* Someone is just being silly */ + val += (NUMEV + 1) * var; + /* We add one to the matching event and multiply by + * (NUMEV + 1) so as not to return 0 if there's a match. + * val will overflow if there is an obscenely large + * number of special events. */ + break; + } + *flags |= F_SPECIAL; + } + if (!(*flags & F_SPECIAL)) { + /* undefined rest */ + *p = savech; + return (0); + } } for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p) ; diff --git a/usr.bin/calendar/ostern.c b/usr.bin/calendar/ostern.c index 088dbc9b96b..d76849ca04e 100644 --- a/usr.bin/calendar/ostern.c +++ b/usr.bin/calendar/ostern.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ostern.c,v 1.2 1998/11/05 04:44:08 pjanzen Exp $ */ +/* $OpenBSD: ostern.c,v 1.3 1998/12/13 07:31:08 pjanzen Exp $ */ /* * Copyright (c) 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin. @@ -25,19 +25,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ostern.c,v 1.2 1998/11/05 04:44:08 pjanzen Exp $ + * $Id: ostern.c,v 1.3 1998/12/13 07:31:08 pjanzen Exp $ */ #ifndef lint -static char rcsid[] = "$OpenBSD: ostern.c,v 1.2 1998/11/05 04:44:08 pjanzen Exp $"; +static char rcsid[] = "$OpenBSD: ostern.c,v 1.3 1998/12/13 07:31:08 pjanzen Exp $"; #endif /* not lint */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> - -#include "calendar.h" +#include <tzfile.h> /* return year day for Easter */ @@ -47,7 +46,6 @@ int easter (year) int e_a, e_b, e_c, e_d, e_e,e_f, e_g, e_h, e_i, e_k, e_l, e_m, e_n, e_p, e_q; - extern int *cumdays; /* silly, but it works */ e_a = year % 19; @@ -67,7 +65,9 @@ int easter (year) e_p = (e_h + e_l + 114 - (7 * e_m)) % 31; e_p = e_p + 1; - e_q = cumdays[3] + 1 + e_p; + e_q = 31 + 28 + e_p; + if (isleap(year)) + e_q++; if (e_n == 4) e_q += 31; @@ -78,49 +78,3 @@ int easter (year) return (e_q); } - -/* return year day for Easter or easter depending days - * Match: Easter([+-][0-9]+)? - * e.g: Easter-2 is Good Friday (2 days before Easter) - */ - -int -geteaster(s, year) - char *s; - int year; -{ - register int offset = 0; - extern struct fixs neaster; - -#define EASTER "easter" -#define EASTERNAMELEN (sizeof(EASTER) - 1) - - if (strncasecmp(s, EASTER, EASTERNAMELEN) == 0) - s += EASTERNAMELEN; - else if ( neaster.name != NULL - && strncasecmp(s, neaster.name, neaster.len) == 0 - ) - s += neaster.len; - else - return(0); - -#if DEBUG - printf("%s %d %d\n", s, year, EASTERNAMELEN); -#endif - - /* Easter+1 or Easter-2 - * ^ ^ */ - - switch(*s) { - - case '-': - case '+': - offset = atoi(s); - break; - - default: - offset = 0; - } - - return (easter(year) + offset); -} diff --git a/usr.bin/calendar/paskha.c b/usr.bin/calendar/paskha.c index 6844b59813e..d5f15865248 100644 --- a/usr.bin/calendar/paskha.c +++ b/usr.bin/calendar/paskha.c @@ -1,4 +1,4 @@ -/* $OpenBSD: paskha.c,v 1.1 1996/12/05 06:04:41 millert Exp $ */ +/* $OpenBSD: paskha.c,v 1.2 1998/12/13 07:31:08 pjanzen Exp $ */ /* * Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia. @@ -27,73 +27,34 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: paskha.c,v 1.1 1996/12/05 06:04:41 millert Exp $"; +static char rcsid[] = "$OpenBSD: paskha.c,v 1.2 1998/12/13 07:31:08 pjanzen Exp $"; #endif /* not lint */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> - -#include "calendar.h" - -#define PASKHA "paskha" -#define PASKHALEN (sizeof(PASKHA) - 1) +#include <tzfile.h> /* return year day for Orthodox Easter using Gauss formula */ -/* (old style result) */ +/* (new style result); subtract 13 for old style */ -static int +int paskha (R) -int R; /*year*/ + int R; /*year*/ { int a, b, c, d, e; static int x = 15; static int y = 6; - extern int *cumdays; + int cumdays; a = R % 19; b = R % 4; c = R % 7; d = (19*a + x) % 30; e = (2*b + 4*c + 6*d + y) % 7; - return (((cumdays[3] + 1) + 22) + (d + e)); -} - -/* return year day for Orthodox Easter depending days */ - -int -getpaskha(s, year) - char *s; - int year; -{ - int offset; - extern struct fixs npaskha; - - if (strncasecmp(s, PASKHA, PASKHALEN) == 0) - s += PASKHALEN; - else if ( npaskha.name != NULL - && strncasecmp(s, npaskha.name, npaskha.len) == 0 - ) - s += npaskha.len; - else - return 0; - - - /* Paskha+1 or Paskha-2 - * ^ ^ */ - - switch(*s) { - - case '-': - case '+': - offset = atoi(s); - break; - - default: - offset = 0; - break; - } - - return (paskha(year) + offset + 13/* new style */); + cumdays = 31 + 28; + if (isleap(R)) + cumdays++; + return ((cumdays + 22) + (d + e) + 13); } |