home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************/
- /* */
- /* REMIND - version 2.3 */
- /* */
- /* By David Skoll - 11 February 1991 */
- /* */
- /* (C) 1990, 1991 by David Skoll - all rights reserved */
- /* */
- /***************************************************************/
-
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
-
- #ifndef UNIX
- #include <stdlib.h>
- #include <dos.h>
- #include <stdarg.h>
- #else
- #include <varargs.h>
- #include <sys/types.h>
- #ifdef SYSV
- #include <time.h>
- #else
- #include <sys/time.h>
- #endif
- #endif
-
- #include "defines.h"
- #include "protos.h"
-
-
- /* List of months */
- char *MonthName[] = {
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
- };
-
- /* List of weekdays */
- char *DayName[] = {
- "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
- };
-
- /* List of recognized tokens - Keep them SORTED (case insensitive.) */
-
- Token keywd[] = {
- { "AFTER", Skip_t, 3, 3 },
- { "April", Month_t, 3, 3 },
- { "AT", At_t, 0, 2 },
- { "August", Month_t, 7, 3 },
- { "BANNER", Banner_t, 0, 3 },
- { "BEFORE", Skip_t, 2, 3 },
- { "CLEAR-OMIT-CONTEXT", Clear_t, 0, 3},
- { "December", Month_t, 11, 3 },
- { "February", Month_t, 1, 3 },
- { "Friday", WkDay_t, 4, 3 },
- { "INCLUDE", Include_t, 0, 3 },
- { "January", Month_t, 0, 3 },
- { "July", Month_t, 6, 3 },
- { "June", Month_t, 5, 3 },
- { "March", Month_t, 2, 3 },
- { "May", Month_t, 4, 3 },
- { "Monday", WkDay_t, 0, 3 },
- { "MSG", Msg_t, 0, 3 },
- { "November", Month_t, 10, 3 },
- { "October", Month_t, 9, 3 },
- { "OMIT", Omit_t, 0, 3 },
- { "ONCE", Once_t, 0, 3 },
- { "POP-OMIT-CONTEXT", Pop_t, 0, 3},
- { "PUSH-OMIT-CONTEXT", Push_t, 0, 3 },
- { "REM", Rem_t, 0, 3 },
- { "RUN", Run_t, 0, 3 },
- { "Saturday", WkDay_t, 5, 3 },
- { "September", Month_t, 8, 3 },
- { "SKIP", Skip_t, 1, 3 },
- { "Sunday", WkDay_t, 6, 3 },
- { "Thursday", WkDay_t, 3, 3 },
- { "Tuesday", WkDay_t, 1, 3 },
- { "UNTIL", Until_t, 0, 3 },
- { "Wednesday", WkDay_t, 2, 3 }
- };
-
- /* List of days in month - Feb MUST be 29 for CheckDate to work. */
- int MonthDays[] = {
- 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
-
- /* Index of the first day of each month. First array is non-leap-year;
- second is leap-year. */
- int MonthIndex[2][12] = {
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
- };
-
- /* Global ommissions array */
- int FullOmitArray[FOMITSIZE];
-
- /* Global partial omissions array */
- int PartOmitArray[POMITSIZE];
-
- /* Define the working buffers */
- char Line[512], WorkBuf[512];
- char TmpBuf[512];
- char Fresh; /* True if the contents of Line are fresh */
-
- /* Global variables */
- char Purge, Debug, Verbose, IgRun, IgOnce, Next;
- int LastRun;
- char FileName[200];
- int CurLine;
- char Banner[200] = "Reminders for %w, %d%s %m, %y%o:";
- int NumEmitted, NumRem;
- int NumFullOmit, NumPartOmit;
- int JulianToday, RealToday;
- int CurYear, CurMon, CurDay;
- char QueueAts, PrintAts;
- int NumAtsQueued;
- int Calendar, CalTime, CalWidth, SimpleCalendar;
-
- static int JulFirst; /* Julian date of 1 Jan Current_year */
- static int FirstYear;
-
- /***************************************************************/
- /* */
- /* Output */
- /* Output a string with line separators. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- void Output(char *s)
- #else
- void Output(s)
- char *s;
- #endif
- {
- while (*s) {
- if (*s == '\n') putchar('\\');
- putchar(*s++);
- }
- putchar('\n');
- }
-
- /***************************************************************/
- /* */
- /* int MoveBack(...) */
- /* */
- /* Move back by specified number of days, skipping holidays */
- /* if the amound to move back is positive; otherwise, just */
- /* move back (-back) days, ignoring holidays. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int MoveBack (int jul, int back, int omit)
- #else
- int MoveBack (jul, back, omit)
- int jul;
- int back;
- int omit;
- #endif
- {
- if (back <= 0) return jul+back;
-
- if (!NumFullOmit && !NumPartOmit && !omit) return jul - back;
- while (back) {
- jul--;
- if (!IsOmitted(jul, omit)) back--;
- }
- return jul;
- }
-
- /***************************************************************/
- /* */
- /* int ProcessLine() */
- /* */
- /* Process the line in the "Line" buffer. */
- /* */
- /* Normally returns 0. Returns 1 only if we're in Calendar */
- /* mode and we hit a reminder which should be placed in the */
- /* calendar. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int ProcessLine(void)
- #else
- int ProcessLine()
- #endif
- {
- char *s = Line;
- Token tok;
- int i;
-
- while (isspace(*s)) s++;
-
- /* Skip comments and blank lines */
- if (*s == '#' || *s == 0) {
- if (Purge && TopLevel()) Output(Line);
- return 0;
- }
-
- tok = ParseToken(&s);
- switch(tok.type) {
- case Push_t: PushOmitContext();
- if (Purge && TopLevel()) Output(Line);
- break;
-
- case Pop_t: PopOmitContext();
- if (Purge && TopLevel()) Output(Line);
- break;
-
- case Clear_t: ClearOmitContext();
- if (Purge && TopLevel()) Output(Line);
- break;
-
- case Banner_t: DoBanner(&s);
- if (Purge && TopLevel()) Output(Line);
- break;
-
- case Omit_t: i = DoGlobalOmit(&s);
- if (Calendar) return i;
- if (Purge && TopLevel())
- if (i == -1) Eprint("Purged '%s'\n", Line);
- else Output(Line);
- break;
-
- case Rem_t: i = DoRem(&s);
- if (Calendar) return i;
- if (Purge && TopLevel())
- if (i < 0) Eprint("Purged '%s'\n", Line);
- else Output(Line);
- NumRem++;
- break;
-
- case Include_t: if (Purge && TopLevel()) Output(Line);
- DoInclude(&s);
- break;
-
- default: if (Purge && TopLevel()) Output(Line);
- Eprint("Unknown command '%s'\n", tok.str);
- }
- return 0;
- }
-
- /***************************************************************/
- /* */
- /* Standard: void Eprint(const char *f, ...) */
- /* Unix: void Eprint(va_alist) */
- /* */
- /* Prints an error message. */
- /* */
- /***************************************************************/
- #ifndef UNIX
- void Eprint(const char *f, ...)
- #else
- /*VARARGS0*/
- void Eprint(va_alist)
- va_dcl
- #endif
- {
- #ifndef UNIX
- va_list args;
- #else
- va_list args;
- char *f;
- #endif
-
- #ifndef UNIX
- if (Verbose & Fresh) {
- #else
- if (Verbose & Fresh) {
- #endif
- fprintf(stderr, "\n--- %s\n", Line);
- Fresh = 0;
- }
- if (Verbose) fprintf(stderr, "--- ");
- fprintf(stderr, "%s(%d): ", FileName, CurLine);
- #ifndef UNIX
- va_start(args, f);
- #else
- va_start(args);
- f = va_arg(args, char *);
- #endif
- vfprintf(stderr, f, args);
- #ifdef UNIX
- va_end(args);
- #endif
- }
-
- /***************************************************************/
- /* */
- /* int DoBanner(char **s) */
- /* */
- /* Sets the "Reminders for..." banner. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int DoBanner(char **s)
- #else
- int DoBanner(s)
- char **s;
- #endif
- {
- if (Purge || Next) return 0;
- while (isspace(**s)) (*s)++;
- strcpy(Banner, *s);
- if (! *Banner)
- {
- if (Debug) Eprint("Empty banner.\n");
- strcpy(Banner, "Reminders for %w, %d%s %m, %y%o:");
- }
- if (NumRem && Debug) Eprint("Warning: Banner after reminder.\n");
- return 0;
- }
-
- /***************************************************************/
- /* */
- /* int CheckDate(int d, int m, int y) */
- /* */
- /* Checks that a date is valid - returns 0 for OK, 1 for BAD. */
- /* */
- /* If y=-1, just checks that month & day are valid, giving */
- /* benefit of the doubt for February 29. */
- /* */
- /* No point in checking if month is valid - months are named */
- /* and thus a month out of range can never be entered into */
- /* the system. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int CheckDate(int d, int m, int y)
- #else
- int CheckDate(d, m, y)
- int d;
- int m;
- int y;
- #endif
- {
- if (y == -1)
- if (d > 0 && d <= MonthDays[m]) return 0; else return 1;
- else
- if (y < BASE || y > BASE + 85) return 1;
- else if (d > 0 && d <= DaysInMonth(m, y)) return 0; else return 1;
- }
-
- /***************************************************************/
- /* */
- /* int strncmpi(char *s1, char*s1, int n) */
- /* */
- /* Compares first n chars of string ignoring case. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int strncmpi(char *s1, char *s2, int n)
- #else
- int strncmpi(s1, s2, n)
- char *s1;
- char *s2;
- int n;
- #endif
- {
- register int u1, u2;
- while (n)
- {
- if (!*s1 || !*s2) return upper(*s1) - upper(*s2);
- u1 = upper(*s1);
- u2 = upper(*s2);
- if (u1 != u2) return (u1 - u2);
- n--;
- s1++;
- s2++;
- }
- return 0;
- }
-
- /***************************************************************/
- /* */
- /* ParseToken(char **s); */
- /* */
- /* Parse the next token and adjust the character pointer. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- Token ParseToken(char **s)
- #else
- Token ParseToken(s)
- char **s;
- #endif
- {
-
- Token tok;
- char *t = TmpBuf;
- int i, h, m;
- int len;
- int top, bot, mid;
- char *colon = (char *) NULL;
-
- *t = 0;
- tok.str = TmpBuf;
-
- /* Skip blank space */
- while (isspace(**s)) (*s)++;
-
- /* End of line ? */
- if (**s == 0) {
- tok.type = Eol_t;
- tok.val = 0;
- return tok;
- }
-
- /* Grab a space-delimited token */
- while (**s != 0 && !isspace(**s)) {
- *t++ = **s;
- (*s)++;
- }
- *t = 0;
- len = t - TmpBuf;
-
- /* Check if it's a built-in token */
- if (*TmpBuf >= 'A' && *TmpBuf <= 'z') {
- top = sizeof(keywd)/sizeof(keywd[0])-1;
- bot = 0;
- mid = (top+bot)/2;
- while (top >= bot &&
- (i=strncmpi(TmpBuf, keywd[mid].str, MAX(len, (int) keywd[mid].len)))) {
- if (i>0) bot = mid+1; else top = mid-1;
- mid = (top+bot)/2;
- }
- if (top >= bot) return keywd[mid];
- }
-
- tok.type = Unknown_t;
-
- /* If it's a comment, ignore the rest of the line */
- if (*(tok.str) == '#') {
- tok.type = Eol_t;
- return tok;
- }
-
- /* Check if it's a number (optional + / - / * ahead of number */
- t = TmpBuf;
- i = 1; /* multiplication factor */
- if (isdigit(*t)) {
- while (*++t){
- if (*t == ':') {
- if (colon) return tok; else colon = t;
- } else if (!isdigit(*t)) return tok;
- }
- }
- else if (*t == '+' || *t == '-' || *t == '*') {
- /* Check if it's a "++" or a "--" */
- if ((*t == '+' && *(t+1) == '+') || (*t == '-' && *(t+1) == '-')) {
- i = -1;
- t++;
- }
- if (!isdigit(*++t)) return tok;
- while (*++t) if (!isdigit(*t)) return tok;
- }
- else return tok;
-
- /* OK, here we have a number - either a pure number, a delta, a time,
- back or a repeat marker */
-
- if (colon) { /* got a time here */
- h = atoi(TmpBuf);
- m = atoi(colon + 1);
- if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
- tok.type = Time_t;
- tok.val = 60*h+m;
- }
- else return tok;
- }
- else if (*TmpBuf == '+') {
- tok.type = Delta_t;
- if (i == 1) tok.val = atoi(TmpBuf + 1);
- else tok.val = -atoi(TmpBuf + 2);
- }
- else if (*TmpBuf == '-') {
- tok.type = Back_t;
- if (i == 1) tok.val = atoi(TmpBuf + 1);
- else tok.val = -atoi(TmpBuf + 2);
- }
- else if (*TmpBuf == '*') {
- tok.type = Repeat_t;
- tok.val = atoi(TmpBuf + 1);
- }
- else {
- tok.val = atoi(TmpBuf);
- if (tok.val > 0 && tok.val <= 31) tok.type = Day_t;
- else if (tok.val >= 100) tok.type = Year_t;
- else {
- tok.type = Year_t;
- tok.val += 1900;
- }
- }
- return tok;
- }
-
- /***************************************************************/
- /* */
- /* int FromJulian(int jul, int *d, int *m, int *y) */
- /* */
- /* Convert a date from Julian to normal form. Returns */
- /* 0 if conversion ok, -1 otherwise. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int FromJulian(int jul, int *d, int *m, int *y)
- #else
- int FromJulian(jul, d, m, y)
- int jul;
- int *d;
- int *m;
- int *y;
- #endif
- {
- int t;
-
- if (jul < 0) return -1;
-
- if (jul >= JulFirst && JulFirst != -1) {
- *y = FirstYear;
- jul -= JulFirst;
- } else *y = BASE;
-
- *m = 0;
-
- t = DaysInYear(*y);
- while (jul >= t) {
- jul -= t;
- (*y)++;
- t = DaysInYear(*y);
- }
-
- t = DaysInMonth(*m, *y);
- while (jul >= t) {
- jul -= t;
- (*m)++;
- t = DaysInMonth(*m, *y);
- }
- *d = jul + 1;
- return 0;
- }
-
- /***************************************************************/
- /* */
- /* int Julian(d, m, y) */
- /* */
- /* Converts a date to the number of days after Jan 1 1990. */
- /* Returns -1 if date is before Jan 1 1990. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int Julian(int d, int m, int y)
- #else
- int Julian(d, m, y)
- int d;
- int m;
- int y;
- #endif
- {
- int iy;
- int jul = 0;
-
- if (y < BASE) return -1;
- if (JulFirst == -1 || y < FirstYear)
- for (iy = BASE; iy < y; iy++) jul += DaysInYear(iy);
- else {
- jul = JulFirst;
- for (iy = FirstYear; iy < y; iy++) jul += DaysInYear(iy);
- }
-
- return jul + MonthIndex[IsLeapYear(y)][m] + d - 1;
- }
-
- /***************************************************************/
- /* */
- /* int FindTodaysDate(int *d, int *m, int *y) */
- /* */
- /* Obtains today's date. Returns Julian date or -1 for */
- /* failure. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- int FindTodaysDate(int *d, int *m, int *y)
- #else
- int FindTodaysDate(d, m, y)
- int *d;
- int *m;
- int *y;
- #endif
- {
- #ifndef UNIX
- struct dosdate_t buf;
-
- _dos_getdate(&buf);
-
- *d = buf.day;
- *m = buf.month - 1;
- *y = buf.year;
- #else
- time_t tloc;
- struct tm *t;
-
- (void) time(&tloc);
- t = localtime(&tloc);
-
- *d = t->tm_mday;
- *m = t->tm_mon;
- *y = t->tm_year + 1900;
-
- #endif
- if (CheckDate(*d, *m, *y)) return -1;
- return Julian(*d, *m, *y);
- }
- /***************************************************************/
- /***************************************************************/
- /** **/
- /** MAIN PROGRAM ENTRY POINT **/
- /** **/
- /***************************************************************/
- /***************************************************************/
- #ifdef __STDC__
- int main(int argc, char *argv[])
- #else
- int main(argc, argv)
- int argc;
- char *argv[];
- #endif
- {
- #ifdef UNIX
- #ifdef SYSV
- pid_t pid;
- #else
- int pid;
- #endif
- #endif
-
- NumEmitted = 0;
- NumRem = 0;
- JulFirst = -1; /* Initialize JulFirst so it's not used by Julian */
-
- JulianToday = FindTodaysDate(&CurDay, &CurMon, &CurYear);
- if (JulianToday < 0) {
- fprintf(stderr, "remind: System date is illegal - Ensure that year is at least %d.\n", BASE);
- return 1;
- }
-
- RealToday = JulianToday;
-
- initialize(argc, argv);
-
- FirstYear = CurYear;
- JulFirst = Julian(1, 0, CurYear); /* Do expensive computation once */
- FirstYear = CurYear;
-
- if (Calendar) {
- DoCalendar();
- return 0;
- }
- while (1) {
- if (ReadLine()) break;
- ProcessLine();
- }
- /* Get rid of any spurious OMIT contexts */
- FreeStackedOmits();
- if (NumEmitted == 0 && NumAtsQueued == 0 && !Purge && !Debug && !Next)
- printf("No reminders.\n");
- #ifdef UNIX
- if (NumEmitted == 0 && NumAtsQueued != 0 && !Purge && !Debug)
- printf("%d reminder%s queued for later today.\n", NumAtsQueued,
- (NumAtsQueued == 1) ? "" : "s");
-
- fflush(stdout); /* Flush output so we don't get 2 copies when directing */
- /* stdout to a file. */
-
- if (NumAtsQueued) {
- pid = fork();
- if (pid == -1) Eprint("Can't fork to perform ATs!\n");
- if (pid != 0) return 0;
- HandleQueuedAts();
- }
- #endif
- return 0;
- }
- /***************************************************************/
- /* */
- /* SystemTime */
- /* */
- /* Returns current system time in seconds past midnight. */
- /* */
- /***************************************************************/
- #ifdef __STDC__
- long SystemTime(void)
- #else
- long SystemTime()
- #endif
- {
- #ifdef UNIX
- time_t tloc;
- struct tm *t;
-
- (void) time(&tloc);
- t = localtime(&tloc);
- return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec;
-
- #else
- struct dostime_t tloc;
- _dos_gettime(&tloc);
- return (long) tloc.hour * 3600L + (long) tloc.minute * 60L + (long) tloc.second;
- #endif
- }
-