[comp.sources.misc] v17i004: remind - A replacement for calendar, Part02/04

dfs@doe.carleton.ca (David F. Skoll) (02/20/91)

Submitted-by: David F. Skoll <dfs@doe.carleton.ca>
Posting-number: Volume 17, Issue 4
Archive-name: remind/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 2 (of 4)."
# Contents:  calendar.c dorem.c main.c test.out
# Wrapped by kent@sparky on Tue Feb 19 10:16:40 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'calendar.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'calendar.c'\"
else
echo shar: Extracting \"'calendar.c'\" \(13183 characters\)
sed "s/^X//" >'calendar.c' <<'END_OF_FILE'
X/***************************************************************/
X/*                                                             */
X/* CALENDAR.C                                                  */
X/*                                                             */
X/* Contains routines and data structures for producing a       */
X/* calendar from a reminder file.                              */
X/*                                                             */
X/* By David Skoll - 14 November 1990                           */
X/*                                                             */
X/***************************************************************/
X#include <stdio.h>
X#ifndef NO_MALLOC_H
X#include <malloc.h>
X#endif
X#include <ctype.h>
X#include <string.h>
X#ifndef UNIX
X#include <stdlib.h>
X#endif
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X#include "cache.h"
X
X/* Convert (monday-sunday) sequence to (sunday-saturday) */
X#define DayOfWeek(julian) ((((julian) % 7) + 1) % 7)
X
X/* To center an item of length l in a field of length f, how many spaces? */
X#define PreCenter(f, l) (((f)-(l))/2)
X
X/* How many spaces AFTEr the centered item? */
X#define PostCenter(f, l) ((f)-(l)-((f)-(l))/2)
X
X/* Define the structure of a calendar entry */
Xtypedef struct CalEntry_t {
X   int tim;
X   char *text, *current;
X   struct CalEntry_t *next;
X} CalEntry;
X
X/* Have a main calendar entry for each weekday */
XCalEntry entry[7];
Xint used[7];  /* These hold the day of the month for corresponding
X                 entry - 0 if not used */
X
X/* Static integers for various stuff */
Xstatic int TotalWidth;
X
X/* Make function prototypes local - they're not used anywhere else */
X#ifdef __STDC__
XCalEntry *CreateCalEntry(int type);
Xvoid AddCalEntry(CalEntry *e);
Xvoid EmitOneCalendarLine(void);
Xvoid InitCalendar(int m, int y);
Xvoid FinishCalendar(void);
Xvoid DoEntries(void);
X#else
XCalEntry *CreateCalEntry();
Xvoid AddCalEntry();
Xvoid EmitOneCalendarLine();
Xvoid InitCalendar();
Xvoid FinishCalendar();
Xvoid DoEntries();
X#endif
X
X/***************************************************************/
X/*                                                             */
X/* DoCalendar - main loop for the calendar command.            */
X/*                                                             */
X/***************************************************************/
X#ifndef __STDC__
Xvoid DoCalendar()
X#else
Xvoid DoCalendar(void)
X#endif
X{
X   int y, m, d, init;
X
X   TotalWidth = 7*CalWidth + 8;
X
X   /* Move back until beginning of month */
X   FromJulian(JulianToday, &d, &m, &y);
X   JulianToday -= (d-1);
X
X   init = 0;
X   InitCache();
X   while (Calendar) {
X      FromJulian(JulianToday, &d, &m, &y);
X      CurDay = d;
X      CurMon = m;
X      CurYear = y;
X      if (init == 0 || CurDay == 1) { InitCalendar(m, y); init = 1; }
X      DoEntries();
X      if (d == DaysInMonth(m, y)) Calendar--;
X      JulianToday++;
X      if (Calendar) ResetCache();
X   }
X   if (CurDay != DaysInMonth(CurMon, CurYear)) FinishCalendar();
X   DestroyCache();
X   FreeStackedOmits();
X}
X
X/***************************************************************/
X/*                                                             */
X/* PrintChars:  Print n of the specified character             */
X/* CopyChars:  Copy n of the character to the output buffer    */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid PrintChars(int n, int c)
X#else
Xvoid PrintChars(n, c)
Xint n, c;
X#endif
X{
X   while(n--) putchar(c);
X}
X
X#ifdef __STDC__
Xchar *CopyChars(int n, int c, char *dst)
X#else
Xchar *CopyChars(n, c, dst)
Xint n, c;
Xchar *dst;
X#endif
X{
X   while(n--) *dst++ = (char) c;
X   return dst;
X}
X
X/***************************************************************/
X/*                                                             */
X/* InitCalendar                                                */
X/* Print the calendar header                                   */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid InitCalendar(int m, int y)
X#else
Xvoid InitCalendar(m, y)
Xint y, m;
X#endif
X{
X   int i;
X
X   if (SimpleCalendar) return;
X
X   for (i=0; i<7; i++) {
X      entry[i].next = NULL;
X      used[i] = 0;
X   }
X
X   /* Emit the calendar title */
X   putchar('+');
X   PrintChars(TotalWidth-2, '-');
X   putchar('+');
X   putchar('\n');
X   sprintf(TmpBuf, "%s %d", MonthName[m], y);
X   putchar('|');
X   PrintChars(PreCenter(TotalWidth-2, strlen(TmpBuf)), ' ');
X   printf("%s", TmpBuf);
X   PrintChars(PostCenter(TotalWidth-2, strlen(TmpBuf)), ' ');
X   putchar('|');
X   putchar('\n');
X   putchar('+');
X   for (i=0; i<7; i++) {
X      PrintChars(CalWidth, '-');
X      putchar('+');
X   }
X   putchar('\n');
X
X   /* Put the weekdays in */
X   /* Argh! Do sunday first, then take care of rest */
X   i = 6;
X   putchar('|');
X   PrintChars(PreCenter(CalWidth, strlen(DayName[i])), ' ');
X   printf(DayName[i]);
X   PrintChars(PostCenter(CalWidth, strlen(DayName[i])), ' ');
X
X   for (i=0; i<6; i++) {
X      putchar('|');
X      PrintChars(PreCenter(CalWidth, strlen(DayName[i])), ' ');
X      printf(DayName[i]);
X      PrintChars(PostCenter(CalWidth, strlen(DayName[i])), ' ');
X   }
X   putchar('|');
X   putchar('\n');
X   putchar('+');
X   for (i=0; i<7; i++) {
X      PrintChars(CalWidth, '-');
X      putchar('+');
X   }
X   putchar('\n');
X}
X
X/***************************************************************/
X/*                                                             */
X/* FinishCalendar                                              */
X/* Just print a form feed.                                     */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid FinishCalendar(void)
X#else
Xvoid FinishCalendar()
X#endif
X{
X   if (SimpleCalendar) return;
X   putchar('\f');
X}
X
X/***************************************************************/
X/*                                                             */
X/* DoEntries                                                   */
X/* Create all the calendar entries for this week               */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid DoEntries(void)
X#else
Xvoid DoEntries()
X#endif
X{
X   int i;
X   CalEntry *e;
X
X   while (1) {
X      used[DayOfWeek(JulianToday)] = CurDay;
X      if (GetLine()) break;
X      i = ProcessLine();
X      if (i>0) if (e = CreateCalEntry(i)) AddCalEntry(e);
X   }
X
X   /* Now figure out if we should print the calendar */
X   if ((DayOfWeek(JulianToday) == 6 ) || CurDay == DaysInMonth(CurMon, CurYear))
X      EmitOneCalendarLine();
X   if (CurDay == DaysInMonth(CurMon, CurYear)) FinishCalendar();
X}
X
X/***************************************************************/
X/*                                                             */
X/* AddCalEntry                                                 */
X/* Add a calendar entry for the appropriate weekday.           */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid AddCalEntry(CalEntry *e)
X#else
Xvoid AddCalEntry(e)
XCalEntry *e;
X#endif
X{
X   CalEntry *curr, *prev;
X
X   prev = &entry[DayOfWeek(JulianToday)];
X   curr = prev->next;
X   while (curr) {
X      if (e->tim == -1 || (e->tim >= curr->tim && curr->tim != -1)) {
X         prev = curr;
X         curr = prev->next;
X      } else {
X         prev->next = e;
X	 e->next    = curr;
X         break;
X      }
X   }
X   if (!curr) {
X      prev->next = e;
X      e->next = NULL;
X   }
X}
X
X#ifdef __STDC__
Xvoid CopyWord(char **src, char **dst, int l)
X#else
Xvoid CopyWord(src, dst, l)
Xchar **src, **dst;
Xint l;
X#endif
X{
X   while(**src && !isspace(**src) && l--) *(*dst)++ = *(*src)++;
X}
X
X#ifdef __STDC__
Xint WordLen(char *src)
X#else
Xint WordLen(src)
Xchar *src;
X#endif
X{
X   int len = 0;
X   while (*src && !isspace(*src)) { len++; src++; }
X   return len;
X}
X/***************************************************************/
X/*                                                             */
X/* CreateCalEntry                                              */
X/*                                                             */
X/* Allocates and creates a calendar entry.                     */
X/*                                                             */
X/* Type = 1: MSG  type = 2: RUN                                */
X/*                                                             */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
XCalEntry *CreateCalEntry(int type)
X#else
XCalEntry *CreateCalEntry(type)
Xint type;
X#endif
X{
X   CalEntry *e;
X   char *s, *t;
X   int column, l;
X   enum Token_t tok;
X   
X   if (type == 1) tok = Msg_t; else tok = Run_t;
X   
X   if (!SimpleCalendar) {
X      e = (CalEntry *) malloc(sizeof(CalEntry));
X
X      if (e == NULL) {
X         fprintf(stderr, "remind: Can't malloc to create calendar entry.\n");
X         exit(1);
X      }
X      e->next = NULL;
X      e->tim  = CalTime;
X   }
X
X   DoSubst(WorkBuf, TmpBuf, CurDay, CurMon, CurYear, JulianToday, tok, CalTime, 1);
X
X   /* If the buffer contains zero-length string; forget it. */
X   if (!*TmpBuf) {
X      if (!SimpleCalendar) free(e);
X      return (NULL);
X   }
X
X   /* If we're doing a simple calendar, just spit out the text and end */
X   if (SimpleCalendar) {
X      printf("%04d/%02d/%02d: ", CurYear, 1+CurMon, CurDay);
X      Output(TmpBuf);
X      return (NULL);
X   }
X
X   /* Now copy from TmpBuf to WorkBuf, splitting words as needed */
X   s = TmpBuf;
X   t = WorkBuf;
X   column = 0;
X   while (*s) {
X      l = WordLen(s);
X      if (column == 0 && l >= CalWidth) {
X         CopyWord(&s, &t, CalWidth);
X         *t++ = '\n';
X         while (isspace(*s)) s++;
X      }
X      else if (column != 0 && column+l > CalWidth) {
X         *t++ = '\n';
X         column = 0;
X         if (l >= CalWidth) {
X            CopyWord(&s, &t, CalWidth);
X            *t++ = '\n';
X            while (isspace(*s)) s++;
X         } else {
X            CopyWord(&s, &t, l);
X            *t++ = ' ';
X            while (isspace(*s)) s++;
X            column = l+1;
X            if (column >= CalWidth) {
X              *(t-1) = '\n';
X              column = 0;
X            }
X
X         }
X      }
X      else {
X         column += l+1;
X	 CopyWord(&s, &t, l);
X         while (isspace(*s)) s++;
X         *t++ = ' ';
X	 if (column > CalWidth) {
X           *(t-1) = '\n';
X           column = 0;
X         }
X      }
X   }
X   *t = 0;
X   if (*(t-1) == '\n') *(t-1) = 0;
X
X   /* Finally, copy the string to the calendar entry */
X   e->text = (char *) malloc(strlen(WorkBuf)+1);
X
X   if (!e->text) {
X      fprintf(stderr, "remind: Can't malloc memory for calendar text!\n");
X      exit(1);
X   }
X   strcpy(e->text, WorkBuf);
X   e->current = e->text;
X
X   return e;
X}
X
X/***************************************************************/
X/*                                                             */
X/* EmitOneCalendarLine                                         */
X/* This is the biggie - we print out one line.                 */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid EmitOneCalendarLine(void)
X#else
Xvoid EmitOneCalendarLine()
X#endif
X{
X   int i, nlines, emit, j;
X   char *s, *dst;
X   CalEntry *e;
X   char pend[7];  /* Reminders with following blanks pending */
X
X   if (SimpleCalendar) return;
X
X   nlines = 0;
X   for (i=0; i<7; i++) pend[i] = 0;
X   putchar('|');
X   /* First, emit the days of the month */
X   for (i=0; i<7; i++) {
X      if (!used[i]) PrintChars(CalWidth, ' ');
X      else {
X         sprintf(TmpBuf, "%d", used[i]);
X         printf(TmpBuf);
X         PrintChars(CalWidth-strlen(TmpBuf), ' ');
X      }
X      putchar('|');
X   }
X   putchar('\n');
X
X   /* Now cycle through all the reminders until there are none left */
X   emit = 1;
X   while(emit) {
X      dst = WorkBuf;
X      *dst++ = '|';
X      emit = 0;
X      for (i=0; i<7; i++) {
X         if (pend[i] || !used[i] || !entry[i].next) {
X            dst = CopyChars(CalWidth, ' ', dst);
X	    *dst++ = '|';
X	    if(pend[i]) {pend[i] = 0; emit = 1;}
X            continue;
X         }
X         s = entry[i].next->current;
X	 j = 0;
X	 emit = 1;
X	 while (*s && *s != '\n') {
X	    *dst++ = *s++;
X	    j++;
X	 }
X	 dst = CopyChars(CalWidth - j, ' ', dst);
X         if (*s == '\n') entry[i].next->current = s+1;
X         else {
X            e = entry[i].next;
X	    entry[i].next = e->next;
X            free(e->text);
X            free(e);
X	    if (!entry[i].next) used[i] = 0;
X	    else pend[i] = 1;
X         }
X         *dst++ = '|';
X      }
X      *dst = 0;
X      if(emit) printf("%s\n", WorkBuf);
X      nlines += emit;
X   }
X   while(nlines++ < 6) printf("%s\n", WorkBuf);
X
X   putchar('+');
X   for (i=0; i<7; i++) {
X      PrintChars(CalWidth, '-');
X      putchar('+');
X   }
X   putchar('\n');
X   for (i=0; i<7; i++) used[i] = 0;
X}
END_OF_FILE
if test 13183 -ne `wc -c <'calendar.c'`; then
    echo shar: \"'calendar.c'\" unpacked with wrong size!
fi
# end of 'calendar.c'
fi
if test -f 'dorem.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dorem.c'\"
else
echo shar: Extracting \"'dorem.c'\" \(11579 characters\)
sed "s/^X//" >'dorem.c' <<'END_OF_FILE'
X#include <stdio.h>
X#ifndef UNIX
X#include <stdlib.h>
X#endif
X#include <string.h>
X#include <ctype.h>
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X
X/***************************************************************/
X/*                                                             */
X/*  int DoRem(char **s)                                        */
X/*                                                             */
X/*  Process a reminder.  Return 0 if reminder not emitted,     */
X/*  positive if emitted, or negative if in the past and        */
X/*  will never be emitted.                                     */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint DoRem(char **s)
X#else
Xint DoRem(s)
Xchar **s;
X
X#endif
X{
X   int d, m, y, wd, cons, delta, back, omit, done, jul, once, repeat, skip;
X   int ud, um, uy; /* Date of UNTIL */
X   int uj;
X   int tim, tdelta, trep;
X   int d2, m2, y2;
X   Token tok;
X   int trigger;
X   char NeedNewToken;
X
X   uj = ud = um = uy = d = m = y = tim = tdelta = trep = -1;
X   back = delta = repeat = cons = wd = omit = once = skip = 0;
X
X
X   done = 0;
X   NeedNewToken = 1;
X   while (!done) {
X      if (NeedNewToken) tok = ParseToken(s);
X      NeedNewToken = 1;
X      switch (tok.type) {
X
X         case Until_t:
X	    NeedNewToken = 0;
X	    while (!done) {
X	       tok = ParseToken(s);
X	       switch (tok.type) {
X	          case Year_t:
X		     if (uy != -1) {
X		        Eprint("Year duplicated in UNTIL.\n");
X			return 0;
X		     }
X		     uy = tok.val;
X		     break;
X
X	          case Month_t:
X		     if (um != -1) {
X		        Eprint("Month duplicated in UNTIL.\n");
X			return 0;
X		     }
X		     um = tok.val;
X		     break;
X
X	          case Day_t:
X		     if (ud != -1) {
X		        Eprint("Day duplicated in UNTIL.\n");
X			return 0;
X		     }
X		     ud = tok.val;
X		     break;
X
X                  default:
X		     done = 1; break;
X	       }
X	    }
X	    if (uy == -1 || um == -1 || ud == -1) {
X	       Eprint("Year, month and day must all be specified after UNTIL\n");
X	       return 0;
X            }
X            if (CheckDate(ud, um, uy)) {
X               Eprint("Invalid date for UNTIL.\n");
X               return 0;
X            }
X	    uj = Julian(ud, um, uy);
X	    done = 0; break;
X
X         case Omit_t:
X	    NeedNewToken = 0;
X      	    while (!done) {
X	       tok = ParseToken(s);
X	       switch(tok.type) {
X	          case WkDay_t:
X	             if (omit & (1 << tok.val)) {
X		        Eprint("%s duplicated.\n", tok.str);
X		        return 0;
X	       	     }
X	       	     omit |= 1 << tok.val;
X	       	     break;
X
X	          default: done = 1; break;
X               }
X      	    }
X	    done = 0;
X	    break;
X
X	 case At_t:
X	    NeedNewToken = 0;
X      	    while (!done) {
X               tok = ParseToken(s);
X               switch(tok.type) {
X
X                  case Time_t:
X               	     if (tim != -1) {
X	                Eprint("Time specified twice.\n");
X   	                return 0;
X	       	     }
X	       	     else tim = tok.val;
X               	     break;
X
X                  case Repeat_t:
X               	     if (trep != -1) {
X                        Eprint("Time repeat factor specified twice.\n");
X                        return 0;
X               	    }
X               	    trep = tok.val;
X               	    if (trep <= 0) {
X                       Eprint("Invalid value for timerepeat factor: %d\n", repeat);
X                       return 0;
X               	    }
X               	    break;
X
X                  case Delta_t:
X	             if (tdelta != -1) {
X	                Eprint("Time delta specified twice.\n");
X                        return 0;
X	       	      }
X	              tdelta = ABS(tok.val);
X	       	      break;
X
X	          default: done = 1; break;
X               }
X      	    }
X	    done = 0; break;
X
X	 case Eol_t:
X	    Eprint("Missing MSG or RUN in reminder.\n");
X	    return 0;
X
X	 case Run_t:
X	 case Msg_t: done = 1; break;
X
X	 case Skip_t:
X	    if (skip) {
X	       Eprint("Can only have one of BEFORE, AFTER or SKIP.\n");
X	       return 0;
X            }
X	    skip = tok.val;
X	    break;
X
X	 case Unknown_t:
X	    Eprint("Unknown token %s in reminder.\n", tok.str);
X	    return 0;
X
X         case Repeat_t:
X            if (repeat) {
X               Eprint("Repeat factor specified twice.\n");
X               return 0;
X            }
X            repeat = tok.val;
X            if (repeat <= 0) {
X               Eprint("Invalid value for repeat factor: %d\n", repeat);
X               return 0;
X            }
X            break;
X
X	 case WkDay_t:
X	    if (wd & (1 << tok.val)) {
X	       Eprint("%s duplicated.\n", tok.str);
X	       return 0;
X	    }
X	    wd |= 1 << tok.val;
X	    cons |= WKDAY_M;
X	    break;
X
X	 case Year_t:
X	    if (y != -1) {
X	       Eprint("Year specified twice.\n");
X	       return 0;
X	    }
X	    y = tok.val;
X	    cons |= YEAR_M;
X	    break;
X
X	 case Month_t:
X	    if (m != -1) {
X	       Eprint("Month specified twice.\n");
X	       return 0;
X	    }
X	    m = tok.val;
X	    cons |= MONTH_M;
X	    break;
X
X	 case Day_t:
X	    if (d != -1) {
X	       Eprint("Day specified twice.\n");
X	       return 0;
X	    }
X	    d = tok.val;
X	    cons |= DAY_M;
X	    break;
X
X	 case Delta_t:
X	    if (delta) {
X	       Eprint("Delta specified twice.\n");
X	       return 0;
X	    }
X	    delta = tok.val;
X	    break;
X
X	 case Back_t:
X	    if (back) {
X	       Eprint("Back specified twice.\n");
X	       return 0;
X	    }
X	    back = tok.val;
X	    break;
X
X	 case Once_t:
X	    if (once) {
X	       Eprint("ONCE specified twice.  (How's that for an error message??)\n");
X	       return 0;
X	    }
X	    once = 1;
X	    break;
X
X	 default:
X	    Eprint("Can't use token %s here.\n", tok.str);
X	    return 0;
X      }
X   }
X
X   /* Do some sanity checking on the reminder */
X   if (repeat && (d == -1 || m == -1 || y == -1)) {
X      Eprint("Can't use repeat counter unless you fully specify the date.\n");
X      return 0;
X   }
X
X   if (skip && (wd & omit)) {
X      Eprint("Conflict between weekday list and local OMIT\n");
X      return 0;
X   }
X
X   if (d != -1 && m != -1 && CheckDate(d, m, y)) {
X      Eprint("Illegal date specification.\n");
X      return 0;
X   }
X   if (y != -1 && (y < BASE || y > BASE + 85)) {
X      Eprint("Illegal date specification.\n");
X      return 0;
X   }
X
X   /* Print some helpful stuff if debugging */
X   if (Debug) {
X      if (back > 7) Eprint("Warning: 'back' > 7 could slow execution severely.\n");
X      if (delta > 30 && (omit || NumFullOmit || NumPartOmit))
X	 Eprint("Warning: 'delta' > 30 with OMITs could slow execution severely.\n");
X   }
X
X   if (omit == 127) {
X      Eprint("Can't omit every day!\n");
X      return 0;
X   }
X
X   if (IgOnce) once = 0; 
X
X   /* Check if we can quickly determine reminder is not to be emitted */
X   if (once && !Debug && !Purge && (LastRun == JulianToday)) return 0;
X
X   /* Have we passed the UNTIL date ? */
X   if (uj != -1 && uj < JulianToday) {
X      if (Debug) Eprint("Reminder has expired.\n");
X      return -1;
X   }
X
X   jul = GetTriggerDate(d, m, y, wd, cons, back, repeat, omit, skip);
X   if (uj != -1 && uj < jul) {
X      if (Debug) Eprint("Reminder has expired.\n");
X      return -1;
X   }
X
X   if (Calendar) {
X      if (jul == JulianToday) {
X         while (isspace(**s)) (*s)++;
X         strcpy(WorkBuf, *s);
X         CalTime = tim;
X         if (tok.type == Run_t) return 2; else return 1;
X      } else return 0;
X   }
X
X   if (jul == -1) {
X      if (Debug) Eprint("Reminder has expired.\n");
X      return -1;
X   } else if (jul == -2) return 0;
X
X   FromJulian(jul, &d2, &m2, &y2);
X
X   /* If we're in "Next" mode, output this one in simple-calendar format */
X   if (Next) {
X      DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 1);
X      if (!*WorkBuf) return 0;
X      printf("%04d/%02d/%02d: ", y2, m2+1, d2);
X      printf("%s\n", WorkBuf);
X      return 0;
X   }
X       
X   /* Figure out if the reminder should be triggered */
X
X   trigger = MoveBack(jul, delta, omit);
X
X   if(Debug) {
X      Eprint("%sTrigger date: %s, %d %s, %d.\n", 
X              (trigger <= JulianToday ? "*" : ""), DayName[jul % 7], 
X	      d2, MonthName[m2], y2);
X      return 0;
X   }
X   if (Purge || (once && (LastRun == JulianToday))) return 0;
X
X   while (isspace(**s)) (*s)++;
X
X   if (trigger <= JulianToday && !(tok.type == Run_t && IgRun)) { 
X      /* Trigger a reminder */
X#ifdef UNIX
X      if (QueueAts && (jul == JulianToday) && (tim != -1)) {
X         DoAt(tim, tdelta, trep, *s, tok.type);
X      }
X      if (!PrintAts && (jul == JulianToday) && tim != -1) return 0;
X#endif
X      if (tok.type == Msg_t) {
X         if (NumEmitted == 0) {
X            NumEmitted++;
X            DoSubst(Banner, WorkBuf, CurDay, CurMon, CurYear, 
X                    JulianToday, Msg_t, (int) (SystemTime()/ 60), 0);
X            printf("%s\n", WorkBuf);
X         }
X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 0);
X         printf("%s\n", WorkBuf);
X      }
X      else if (tok.type == Run_t) {
X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 0);
X         system(WorkBuf);
X      }
X      else Eprint("Error: Invalid token type %d\n", tok.type);
X      return 1;
X   } else return 0;
X
X}
X
X/***************************************************************/
X/*                                                             */
X/* GetTriggerDate                                              */
X/*                                                             */
X/* Gets the trigger date for a reminder, returns the julian    */
X/* date, or -1 if the reminder has expired.                    */
X/* Returns -2 if an error occurs.                              */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint GetTriggerDate(int d, int m, int y, int wd, int cons, int back, int repeat, int omit, int skip)
X#else
Xint GetTriggerDate(d, m, y, wd, cons, back, repeat, omit, skip)
Xint d, m, y, wd, cons, back, repeat, omit, skip;
X#endif
X#define MAXATTEMPTS 25  /* Maximum number of attempts before giving up */
X
X{
X   int i, d2, m2, y2, jul;
X   int d1, m1, y1, julstart;
X   int nattempts = 0;
X
X   julstart = JulianToday;
X
X   /* If we have a skip factor of 3 (AFTER), then we must back up to
X      the beginning of the block of omitted days. */
X   if (skip == 3) while(julstart>=1 && IsOmitted(julstart-1, omit)) julstart--;
X
X   FromJulian(julstart, &d1, &m1, &y1);
X
X   /* Make a first stab at the date */
X   i = TryNextDate(&d2, &m2, &y2, d1, m1, y1, d, m, y, wd, cons, 0);
X   if (!i || repeat) jul = Julian(d2, m2, y2);
X
X   if (!repeat && !back && !skip) {
X      if (i) return -1; else return jul;
X   }
X
X   if (i && !repeat) return -1;
X
X   while (nattempts++ < MAXATTEMPTS) {
X      if (back) jul = MoveBack(jul, back, omit);
X      if (repeat) {
X         if (jul < julstart) {
X	    jul += ((julstart - jul) / repeat) * repeat;
X	    if (jul < julstart) jul += repeat;
X         }
X      }
X      if (skip == 2)      while (IsOmitted(jul, omit)) jul--;
X      else if (skip == 3) while (IsOmitted(jul, omit)) jul++;
X      if ((skip == 1 && IsOmitted(jul, omit)) || jul < JulianToday) {
X         if (!repeat) {
X            i = TryNextDate(&d2, &m2, &y2, d2, m2, y2, d, m, y, wd, cons, 1);
X            if (i) return -1;
X            jul = Julian(d2, m2, y2);
X         } else {
X            jul += repeat;
X	    back = 0;  /* We've already handled the back! */
X         }
X      } else return jul;
X   }
X   Eprint("Couldn't compute a trigger date - check that date is sensible.\n");
X   return -2;
X}
END_OF_FILE
if test 11579 -ne `wc -c <'dorem.c'`; then
    echo shar: \"'dorem.c'\" unpacked with wrong size!
fi
# end of 'dorem.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(20411 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/***************************************************************/
X/*                                                             */
X/*  REMIND - version 2.3                                       */
X/*                                                             */
X/*  By David Skoll - 11 February 1991                          */
X/*                                                             */
X/*  (C) 1990, 1991 by David Skoll - all rights reserved        */
X/*                                                             */
X/***************************************************************/
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X
X#ifndef UNIX
X#include <stdlib.h>
X#include <dos.h>
X#include <stdarg.h>
X#else
X#include <varargs.h>
X#include <sys/types.h>
X#ifdef SYSV
X#include <time.h>
X#else
X#include <sys/time.h>
X#endif
X#endif
X
X#include "defines.h"
X#include "protos.h"
X
X
X/* List of months */
Xchar *MonthName[] = {
X   "January", "February", "March", "April", "May", "June",
X   "July", "August", "September", "October", "November", "December"
X};
X
X/* List of weekdays */
Xchar *DayName[] = {
X   "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
X};
X
X/* List of recognized tokens - Keep them SORTED (case insensitive.) */
X
XToken keywd[] = {
X   { "AFTER",     Skip_t,    3, 3 },
X   { "April",     Month_t,  3, 3 },
X   { "AT",        At_t,      0, 2 },
X   { "August",    Month_t,  7, 3 },
X   { "BANNER",    Banner_t, 0, 3 },
X   { "BEFORE",    Skip_t,    2, 3 },
X   { "CLEAR-OMIT-CONTEXT", Clear_t, 0, 3},
X   { "December",  Month_t,  11, 3 },
X   { "February",  Month_t,  1, 3 },
X   { "Friday",    WkDay_t,  4, 3 },
X   { "INCLUDE",   Include_t, 0, 3 },
X   { "January",   Month_t,  0, 3 },
X   { "July",      Month_t,  6, 3 },
X   { "June",      Month_t,  5, 3 },
X   { "March",     Month_t,  2, 3 },
X   { "May",       Month_t,  4, 3 },
X   { "Monday",    WkDay_t,  0, 3 },
X   { "MSG",       Msg_t,    0, 3 },
X   { "November",  Month_t,  10, 3 },
X   { "October",   Month_t,  9, 3 },
X   { "OMIT",      Omit_t,   0, 3 },
X   { "ONCE",      Once_t,   0, 3 },
X   { "POP-OMIT-CONTEXT", Pop_t, 0, 3},
X   { "PUSH-OMIT-CONTEXT", Push_t, 0, 3 },
X   { "REM",       Rem_t,    0, 3 },
X   { "RUN",       Run_t,    0, 3 },
X   { "Saturday",  WkDay_t,  5, 3 },
X   { "September", Month_t,  8, 3 },
X   { "SKIP",      Skip_t,    1, 3 },
X   { "Sunday",    WkDay_t,  6, 3 },
X   { "Thursday",  WkDay_t,  3, 3 },
X   { "Tuesday",   WkDay_t,  1, 3 },
X   { "UNTIL",	  Until_t,   0, 3 },
X   { "Wednesday", WkDay_t,  2, 3 }
X};
X
X/* List of days in month - Feb MUST be 29 for CheckDate to work. */
Xint MonthDays[] = {
X   31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X};
X
X/* Index of the first day of each month.  First array is non-leap-year;
X   second is leap-year. */
Xint MonthIndex[2][12] = {
X   { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
X   { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
X};
X
X/* Global ommissions array */
Xint FullOmitArray[FOMITSIZE];
X
X/* Global partial omissions array */
Xint PartOmitArray[POMITSIZE];
X
X/* Define the working buffers */
Xchar Line[512], WorkBuf[512];
Xchar TmpBuf[512];
Xchar Fresh;  /* True if the contents of Line are fresh */
X
X/* Global variables */
Xchar Purge, Debug, Verbose, IgRun, IgOnce, Next;
Xint LastRun;
Xchar FileName[200];
Xint CurLine;
Xchar Banner[200] = "Reminders for %w, %d%s %m, %y%o:";
Xint NumEmitted, NumRem;
Xint NumFullOmit, NumPartOmit;
Xint JulianToday, RealToday;
Xint CurYear, CurMon, CurDay;
Xchar QueueAts, PrintAts;
Xint  NumAtsQueued;
Xint Calendar, CalTime, CalWidth, SimpleCalendar;
X
Xstatic int JulFirst; /* Julian date of 1 Jan Current_year */
Xstatic int FirstYear;
X
X/***************************************************************/
X/*                                                             */
X/* Output                                                      */
X/* Output a string with line separators.                       */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid Output(char *s)
X#else
Xvoid Output(s)
Xchar *s;
X#endif
X{
X   while (*s) {
X      if (*s == '\n') putchar('\\');
X      putchar(*s++);
X   }
X   putchar('\n');
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int MoveBack(...)                                          */
X/*                                                             */
X/*  Move back by specified number of days, skipping holidays   */
X/*  if the amound to move back is positive; otherwise, just    */
X/*  move back (-back) days, ignoring holidays.                 */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint MoveBack (int jul, int back, int omit)
X#else
Xint MoveBack (jul, back, omit)
X     int jul;
X     int back;
X     int omit;
X#endif
X{
X   if (back <= 0) return jul+back;
X   
X   if (!NumFullOmit && !NumPartOmit && !omit) return jul - back;
X   while (back) {
X      jul--;
X      if (!IsOmitted(jul, omit)) back--;
X   }
X   return jul;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int ProcessLine()                                          */
X/*                                                             */
X/*  Process the line in the "Line" buffer.                     */
X/*                                                             */
X/*  Normally returns 0.  Returns 1 only if we're in Calendar   */
X/*  mode and we hit a reminder which should be placed in the   */
X/*  calendar.                                                  */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint ProcessLine(void)
X#else
Xint ProcessLine()
X#endif
X{
X   char *s = Line;
X   Token tok;
X   int i;
X
X   while (isspace(*s)) s++;
X
X   /* Skip comments and blank lines */
X   if (*s == '#' || *s == 0) {
X      if (Purge && TopLevel()) Output(Line);
X      return 0;
X   }
X
X   tok = ParseToken(&s);
X   switch(tok.type) {
X      case Push_t:   PushOmitContext();
X      	   	     if (Purge && TopLevel()) Output(Line);
X		     break;
X
X      case Pop_t:    PopOmitContext();
X      	   	     if (Purge && TopLevel()) Output(Line);
X		     break;
X
X      case Clear_t:  ClearOmitContext();
X      	   	     if (Purge && TopLevel()) Output(Line);
X		     break;
X
X      case Banner_t: DoBanner(&s);
X		     if (Purge && TopLevel()) Output(Line);
X		     break;
X
X      case Omit_t:   i = DoGlobalOmit(&s);
X		     if (Calendar) return i;
X		     if (Purge && TopLevel())
X			if (i == -1) Eprint("Purged '%s'\n", Line);
X			else       Output(Line);
X		     break;
X
X      case Rem_t:    i = DoRem(&s);
X	             if (Calendar) return i;
X		     if (Purge && TopLevel())
X			if (i < 0) Eprint("Purged '%s'\n", Line);
X			else       Output(Line);
X		     NumRem++;
X		     break;
X
X      case Include_t: if (Purge && TopLevel()) Output(Line);
X		      DoInclude(&s);
X		      break;
X
X      default:       if (Purge && TopLevel()) Output(Line);
X		     Eprint("Unknown command '%s'\n", tok.str);
X   }
X   return 0;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  Standard: void Eprint(const char *f, ...)                  */
X/*  Unix: void Eprint(va_alist)                                */
X/*                                                             */
X/*  Prints an error message.                                   */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xvoid Eprint(const char *f, ...)
X#else
X/*VARARGS0*/
Xvoid Eprint(va_alist)
Xva_dcl
X#endif
X{
X#ifndef UNIX
X   va_list args;
X#else
X  va_list args;
X  char *f;
X#endif
X
X#ifndef UNIX
X   if (Verbose & Fresh) {
X#else
X  if (Verbose & Fresh) {
X#endif
X      fprintf(stderr, "\n--- %s\n", Line);
X      Fresh = 0;
X   }
X   if (Verbose) fprintf(stderr, "--- ");
X   fprintf(stderr, "%s(%d): ", FileName, CurLine);
X#ifndef UNIX
X   va_start(args, f);
X#else
X   va_start(args);
X   f = va_arg(args, char *);
X#endif
X   vfprintf(stderr, f, args);
X#ifdef UNIX
X   va_end(args);
X#endif
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int DoBanner(char **s)                                     */
X/*                                                             */
X/*  Sets the "Reminders for..." banner.                        */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint DoBanner(char **s)
X#else
Xint DoBanner(s)
X     char **s;
X#endif
X{
X   if (Purge || Next) return 0;
X   while (isspace(**s)) (*s)++;
X   strcpy(Banner, *s);
X   if (! *Banner)
X   {
X      if (Debug) Eprint("Empty banner.\n");
X      strcpy(Banner, "Reminders for %w, %d%s %m, %y%o:");
X   }
X   if (NumRem && Debug) Eprint("Warning: Banner after reminder.\n");
X   return 0;
X}
X
X/***************************************************************/
X/*                                                             */
X/* int CheckDate(int d, int m, int y)                          */
X/*                                                             */
X/* Checks that a date is valid - returns 0 for OK, 1 for BAD.  */
X/*                                                             */
X/* If y=-1, just checks that month & day are valid, giving     */
X/* benefit of the doubt for February 29.                       */
X/*                                                             */
X/* No point in checking if month is valid - months are named   */
X/* and thus a month out of range can never be entered into     */
X/* the system.                                                 */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint CheckDate(int d, int m, int y)
X#else
Xint CheckDate(d, m, y)
X     int d;
X     int m;
X     int y;
X#endif
X{
X   if (y == -1)
X      if (d > 0 && d <= MonthDays[m]) return 0; else return 1;
X   else
X      if (y < BASE || y > BASE + 85) return 1;
X      else if (d > 0 && d <= DaysInMonth(m, y)) return 0; else return 1;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int strncmpi(char *s1, char*s1, int n)                     */
X/*                                                             */
X/*  Compares first n chars of string ignoring case.            */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint strncmpi(char *s1, char *s2, int n)
X#else
Xint strncmpi(s1, s2, n)
X     char *s1;
X     char *s2;
X     int n;
X#endif
X{
X   register int u1, u2;
X   while (n)
X   {
X      if (!*s1 || !*s2) return upper(*s1) - upper(*s2);
X      u1 = upper(*s1);
X      u2 = upper(*s2);
X      if (u1 != u2) return (u1 - u2);
X      n--;
X      s1++;
X      s2++;
X   }
X   return 0;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  ParseToken(char **s);                                      */
X/*                                                             */
X/*  Parse the next token and adjust the character pointer.     */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
XToken ParseToken(char **s)
X#else
XToken ParseToken(s)
X     char **s;
X#endif
X{
X
X   Token tok;
X   char *t = TmpBuf;
X   int i, h, m;
X   int len;
X   int top, bot, mid;
X   char *colon = (char *) NULL;
X
X   *t = 0;
X   tok.str = TmpBuf;
X
X   /* Skip blank space */
X   while (isspace(**s)) (*s)++;
X
X   /* End of line ? */
X   if (**s == 0) {
X      tok.type = Eol_t;
X      tok.val = 0;
X      return tok;
X   }
X
X   /* Grab a space-delimited token */
X   while (**s != 0 && !isspace(**s)) {
X      *t++ = **s;
X      (*s)++;
X   }
X   *t = 0;
X   len = t - TmpBuf;
X
X   /* Check if it's a built-in token */
X   if (*TmpBuf >= 'A' && *TmpBuf <= 'z') {
X      top = sizeof(keywd)/sizeof(keywd[0])-1;
X      bot = 0;
X      mid = (top+bot)/2;
X      while (top >= bot && 
X              (i=strncmpi(TmpBuf, keywd[mid].str, MAX(len, (int) keywd[mid].len)))) {
X         if (i>0) bot = mid+1; else top = mid-1;
X	 mid = (top+bot)/2;
X      }
X      if (top >= bot) return keywd[mid];
X   }
X
X   tok.type = Unknown_t;
X
X   /* If it's a comment, ignore the rest of the line */
X   if (*(tok.str) == '#') {
X      tok.type = Eol_t;
X      return tok;
X   }
X
X   /* Check if it's a number (optional + / - / * ahead of number */
X   t = TmpBuf;
X   i = 1;  /* multiplication factor */
X   if (isdigit(*t)) {
X      while (*++t){
X         if (*t == ':') {
X            if (colon) return tok; else colon = t;
X         } else if (!isdigit(*t)) return tok;
X      }
X   }
X   else if (*t == '+' || *t == '-' || *t == '*') {
X      /* Check if it's a "++" or a "--" */
X      if ((*t == '+' && *(t+1) == '+') || (*t == '-' && *(t+1) == '-')) {
X         i = -1;
X         t++;
X      }
X      if (!isdigit(*++t)) return tok;
X      while (*++t) if (!isdigit(*t)) return tok;
X   }
X   else return tok;
X
X   /* OK, here we have a number - either a pure number, a delta, a time,
X      back or a repeat marker */
X
X   if (colon) { /* got a time here */
X      h = atoi(TmpBuf);
X      m = atoi(colon + 1);
X      if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
X         tok.type = Time_t;
X	 tok.val = 60*h+m;
X      }
X      else return tok;
X   }
X   else if (*TmpBuf == '+') {
X      tok.type = Delta_t;
X      if (i == 1) tok.val = atoi(TmpBuf + 1);
X      else        tok.val = -atoi(TmpBuf + 2);
X   }
X   else if (*TmpBuf == '-') {
X      tok.type = Back_t;
X      if (i == 1) tok.val = atoi(TmpBuf + 1);
X      else        tok.val = -atoi(TmpBuf + 2);
X   }
X   else if (*TmpBuf == '*') {
X      tok.type = Repeat_t;
X      tok.val = atoi(TmpBuf + 1);
X   }
X   else {
X      tok.val = atoi(TmpBuf);
X      if (tok.val > 0 && tok.val <= 31) tok.type = Day_t;
X      else if (tok.val >= 100) tok.type = Year_t;
X      else {
X	 tok.type = Year_t;
X	 tok.val += 1900;
X      }
X   }
X   return tok;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int FromJulian(int jul, int *d, int *m, int *y)            */
X/*                                                             */
X/*  Convert a date from Julian to normal form.  Returns        */
X/*  0 if conversion ok, -1 otherwise.                          */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint FromJulian(int jul, int *d, int *m, int *y)
X#else
Xint FromJulian(jul, d, m, y)
X     int jul;
X     int *d;
X     int *m;
X     int *y;
X#endif
X{
X   int t;
X
X   if (jul < 0) return -1;
X
X   if (jul >= JulFirst && JulFirst != -1) {
X      *y = FirstYear;
X      jul -= JulFirst;
X   } else *y = BASE;
X
X   *m = 0;
X
X   t = DaysInYear(*y);
X   while (jul >= t) {
X      jul -= t;
X      (*y)++;
X      t = DaysInYear(*y);
X   }
X
X   t = DaysInMonth(*m, *y);
X   while (jul >= t) {
X      jul -= t;
X      (*m)++;
X      t = DaysInMonth(*m, *y);
X   }
X   *d = jul + 1;
X   return 0;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int Julian(d, m, y)                                        */
X/*                                                             */
X/*  Converts a date to the number of days after Jan 1 1990.    */
X/*  Returns -1 if date is before Jan 1 1990.                   */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint Julian(int d, int m, int y)
X#else
Xint Julian(d, m, y)
X     int d;
X     int m;
X     int y;
X#endif
X{
X   int iy;
X   int jul = 0;
X
X   if (y < BASE) return -1;
X   if (JulFirst == -1 || y < FirstYear)
X      for (iy = BASE; iy < y; iy++) jul += DaysInYear(iy);
X   else {
X      jul = JulFirst;
X      for (iy = FirstYear; iy < y; iy++) jul += DaysInYear(iy);
X   }
X
X   return jul + MonthIndex[IsLeapYear(y)][m] + d - 1;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  int FindTodaysDate(int *d, int *m, int *y)                 */
X/*                                                             */
X/*  Obtains today's date.  Returns Julian date or -1 for       */
X/*  failure.                                                   */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint FindTodaysDate(int *d, int *m, int *y)
X#else
Xint FindTodaysDate(d, m, y)
X     int *d;
X     int *m;
X     int *y;
X#endif
X{
X#ifndef UNIX
X   struct dosdate_t buf;
X
X   _dos_getdate(&buf);
X
X   *d = buf.day;
X   *m = buf.month - 1;
X   *y = buf.year;
X#else
X  time_t tloc;
X  struct tm *t;
X
X   (void) time(&tloc);
X   t = localtime(&tloc);
X
X   *d = t->tm_mday;
X   *m = t->tm_mon;
X   *y = t->tm_year + 1900;
X
X#endif
X   if (CheckDate(*d, *m, *y)) return -1;
X   return Julian(*d, *m, *y);
X}
X/***************************************************************/
X/***************************************************************/
X/**                                                           **/
X/** MAIN PROGRAM ENTRY POINT                                  **/
X/**                                                           **/
X/***************************************************************/
X/***************************************************************/
X#ifdef __STDC__
Xint main(int argc, char *argv[])
X#else
Xint main(argc, argv)
X     int argc;
X     char *argv[];
X#endif
X{
X#ifdef UNIX
X#ifdef SYSV
X   pid_t pid;
X#else
X   int pid;
X#endif
X#endif
X
X   NumEmitted = 0;
X   NumRem = 0;
X   JulFirst = -1;  /* Initialize JulFirst so it's not used by Julian */
X      
X   JulianToday = FindTodaysDate(&CurDay, &CurMon, &CurYear);
X   if (JulianToday < 0) {
X      fprintf(stderr, "remind: System date is illegal - Ensure that year is at least %d.\n", BASE);
X      return 1;
X   }
X   
X   RealToday = JulianToday;
X   
X   initialize(argc, argv);
X
X   FirstYear = CurYear;
X   JulFirst = Julian(1, 0, CurYear);  /* Do expensive computation once */
X   FirstYear = CurYear;
X
X   if (Calendar) {
X      DoCalendar();
X      return 0;
X   }
X   while (1) {
X      if (ReadLine()) break;
X      ProcessLine();
X   }
X/* Get rid of any spurious OMIT contexts */
X   FreeStackedOmits();
X   if (NumEmitted == 0 && NumAtsQueued == 0 && !Purge && !Debug && !Next) 
X       printf("No reminders.\n");
X#ifdef UNIX
X   if (NumEmitted == 0 && NumAtsQueued != 0 && !Purge && !Debug)
X       printf("%d reminder%s queued for later today.\n", NumAtsQueued,
X              (NumAtsQueued == 1) ? "" : "s");
X
X   fflush(stdout); /* Flush output so we don't get 2 copies when directing */
X		   /* stdout to a file. */
X
X   if (NumAtsQueued) {
X      pid = fork();
X      if (pid == -1) Eprint("Can't fork to perform ATs!\n");
X      if (pid != 0) return 0;
X      HandleQueuedAts();
X   }
X#endif
X   return 0;
X}
X/***************************************************************/
X/*                                                             */
X/* SystemTime                                                  */
X/*                                                             */
X/* Returns current system time in seconds past midnight.       */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xlong SystemTime(void)
X#else
Xlong SystemTime()
X#endif
X{
X#ifdef UNIX
X  time_t tloc;
X  struct tm *t;
X
X   (void) time(&tloc);
X   t = localtime(&tloc);
X   return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec;
X
X#else
X   struct dostime_t tloc;
X   _dos_gettime(&tloc);
X   return (long) tloc.hour * 3600L + (long) tloc.minute * 60L + (long) tloc.second;
X#endif
X}
END_OF_FILE
if test 20411 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'test.out' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test.out'\"
else
echo shar: Extracting \"'test.out'\" \(6464 characters\)
sed "s/^X//" >'test.out' <<'END_OF_FILE'
X
XFile test.rem last accessed on Tuesday, 19 February, 1991
X
X--- REM MSG Every Day
X--- test.rem(19): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM 18 MSG Every 18th 
X--- test.rem(21): Trigger date: Monday, 18 February, 1991.
X
X--- REM 15 MSG Every 15th
X--- test.rem(22): Trigger date: Friday, 15 March, 1991.
X
X--- REM Feb MSG February
X--- test.rem(24): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM Jan MSG January
X--- test.rem(25): Trigger date: Wednesday, 1 January, 1992.
X
X--- REM March MSG March
X--- test.rem(26): Trigger date: Friday, 1 March, 1991.
X
X--- REM 13 Jan MSG 13 Jan
X--- test.rem(28): Trigger date: Monday, 13 January, 1992.
X
X--- REM 15 Feb MSG 15 Feb
X--- test.rem(29): Trigger date: Saturday, 15 February, 1992.
X
X--- REM 28 Feb MSG 28 Feb
X--- test.rem(30): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 29 Feb MSG 29 Feb
X--- test.rem(31): Trigger date: Saturday, 29 February, 1992.
X
X--- REM 5 Mar MSG 5 Mar
X--- test.rem(32): Trigger date: Tuesday, 5 March, 1991.
X
X--- REM 1990 MSG 1990
X--- test.rem(34): Reminder has expired.
X
X--- REM 1991 MSG 1991
X--- test.rem(35): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM 1992 MSG 1991
X--- test.rem(36): Trigger date: Wednesday, 1 January, 1992.
X
X--- REM 1 1990 MSG 1 1990
X--- test.rem(38): Reminder has expired.
X
X--- REM 29 1991 MSG 29 1991
X--- test.rem(39): Trigger date: Friday, 29 March, 1991.
X
X--- REM 29 1992 MSG 29 1992
X--- test.rem(40): Trigger date: Wednesday, 29 January, 1992.
X
X--- REM 16 1991 MSG 16 1991
X--- test.rem(41): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM Jan 1990 MSG Jan 1990
X--- test.rem(43): Reminder has expired.
X
X--- REM Feb 1991 MSG Feb 1991
X--- test.rem(44): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM Dec 1991 MSG Dec 1991
X--- test.rem(45): Trigger date: Sunday, 1 December, 1991.
X
X--- REM May 1992 MSG May 1992
X--- test.rem(46): Trigger date: Friday, 1 May, 1992.
X
X--- REM 1 Jan 1991 MSG 1 Jan 1991
X--- test.rem(48): Reminder has expired.
X
X--- REM 16 Feb 1991 MSG 16 Feb 1991
X--- test.rem(49): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM 29 Dec 1992 MSG 29 Dec 1992
X--- test.rem(50): Trigger date: Tuesday, 29 December, 1992.
X
X--- REM Sun MSG Sun
X--- test.rem(52): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Fri Sat Tue MSG Fri Sat Tue
X--- test.rem(53): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM Sun 16 MSG Sun 16
X--- test.rem(55): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Mon Tue Wed Thu Fri 1 MSG Mon Tue Wed Thu Fri 1
X--- test.rem(56): Trigger date: Friday, 1 March, 1991.
X
X--- REM Sun Feb MSG Sun Feb
X--- test.rem(58): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Mon Tue March MSG Mon Tue March
X--- test.rem(59): Trigger date: Monday, 4 March, 1991.
X
X--- REM Sun 16 Feb MSG Sun 16 Feb
X--- test.rem(61): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Mon Tue 10 March MSG Mon Tue 10 March
X--- test.rem(62): Trigger date: Monday, 11 March, 1991.
X
X--- REM Sat Sun 1991 MSG Sat Sun 1991
X--- test.rem(64): *Trigger date: Saturday, 16 February, 1991.
X
X--- REM Mon Tue 1992 MSG Mon Tue 1992
X--- test.rem(65): Trigger date: Monday, 6 January, 1992.
X
X--- REM Sun 16 1991 MSG Sun 16 1991
X--- test.rem(67): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Mon Tue Wed Thu Fri 1 1992 MSG Mon Tue Wed Thu Fri 1 1992
X--- test.rem(68): Trigger date: Wednesday, 1 January, 1992.
X
X--- REM Mon Feb 1991 MSG Mon Feb 1991
X--- test.rem(70): Trigger date: Monday, 18 February, 1991.
X
X--- REM Tue Jan 1992 MSG Tue Jan 1992
X--- test.rem(71): Trigger date: Tuesday, 7 January, 1992.
X
X--- REM Sun Mon 16 Feb 1991 MSG Sun Mon 16 Feb 1991
X--- test.rem(73): Trigger date: Sunday, 17 February, 1991.
X
X--- REM Tue 28 Jan 1992 MSG Tue 28 Jan 1992
X--- test.rem(74): Trigger date: Tuesday, 28 January, 1992.
X
X--- REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun
X--- test.rem(78): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun
X--- test.rem(79): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun (28 Feb omitted)
X--- test.rem(82): Trigger date: Wednesday, 27 February, 1991.
X
X--- REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun (28 Feb omitted)
X--- test.rem(83): Trigger date: Thursday, 28 February, 1991.
X
X--- REM Wed UNTIL 21 Feb 1991 MSG Wed UNTIL 21 Feb 1991
X--- test.rem(88): Trigger date: Wednesday, 20 February, 1991.
X
X--- REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted)
X--- test.rem(93): Trigger date: Wednesday, 27 February, 1991.
X
X--- REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted)
X--- test.rem(94): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted)
X--- test.rem(95): Trigger date: Wednesday, 27 February, 1991.
X
X--- REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted)
X--- test.rem(96): Trigger date: Friday, 28 February, 1992.
X
X--- REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
X--- test.rem(97): Trigger date: Friday, 1 March, 1991.
X
X--- REM 1 Mar -1 MSG 1 mar -1
X--- test.rem(101): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 1 Mar --1 MSG 1 mar --1
X--- test.rem(102): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 28 Feb BEFORE MSG 28 Feb BEFORE
X--- test.rem(103): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 28 Feb SKIP MSG 28 Feb SKIP 
X--- test.rem(104): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 28 Feb AFTER MSG 28 Feb AFTER
X--- test.rem(105): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted)
X--- test.rem(108): Trigger date: Wednesday, 27 February, 1991.
X
X--- REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted)
X--- test.rem(109): Trigger date: Thursday, 28 February, 1991.
X
X--- REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted)
X--- test.rem(110): Trigger date: Wednesday, 27 February, 1991.
X
X--- REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted)
X--- test.rem(111): Trigger date: Friday, 28 February, 1992.
X
X--- REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
X--- test.rem(112): Trigger date: Friday, 1 March, 1991.
X
X--- REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91
X--- test.rem(115): Trigger date: Wednesday, 13 March, 1991.
X
X--- REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1
X--- test.rem(119): Trigger date: Monday, 18 February, 1991.
X
X--- REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 (17Feb91 omitted)
X--- test.rem(122): *Trigger date: Monday, 18 February, 1991.
X
X--- REM 18 Feb 1991 ++1 MSG 18 Feb 1991 ++1 (17Feb91 omitted)
X--- test.rem(123): Trigger date: Monday, 18 February, 1991.
END_OF_FILE
if test 6464 -ne `wc -c <'test.out'`; then
    echo shar: \"'test.out'\" unpacked with wrong size!
fi
# end of 'test.out'
fi
echo shar: End of archive 2 \(of 4\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.