[alt.sources] REMIND 2.2 02/05

dfs@doe.carleton.ca (David F. Skoll) (11/17/90)

#!/bin/sh
# This is part 02 of Remind-2.2
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= dorem.c ==============
if test X"$1" != X"-c" -a -f 'dorem.c'; then
	echo "File already exists: skipping 'dorem.c'"
else
echo "x - extracting dorem.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dorem.c &&
X#include <stdio.h>
X#ifndef UNIX
X#include <stdlib.h>
X#include <string.h>
X#endif
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#ifndef UNIX
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;
X   int tim, tdelta, trep;
X   int d2, m2, y2;
X   Token tok;
X   int trigger;
X
X   d = m = y = back = delta = tim = tdelta = trep = -1;
X   repeat = cons = wd = omit = once = 0;
X
X
X   done = 0;
X   while (!done) {
X      tok = ParseToken(s);
X      switch (tok.type) {
X	 case Eol_t:
X	    Eprint("Missing MSG or RUN in reminder.\n");
X	    return 0;
X
X         case At_t:
X	 case Omit_t:
X	 case Run_t:
X	 case Msg_t: done = 1; 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 Banner_t:
X	    Eprint("BANNER can't be used here.\n");
X	    return 0;
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 != -1) {
X	       Eprint("Delta specified twice.\n");
X	       return 0;
X	    }
X	    delta = tok.val;
X	    break;
X
X	 case Back_t:
X	    if (back != -1) {
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   if (tok.type == Omit_t) {
X      done = 0;
X      while (!done) {
X	 tok = ParseToken(s);
X	 switch(tok.type) {
X
X            case At_t:
X	    case Msg_t:
X	    case Run_t: done = 1; break;
X
X	    case Eol_t:
X	       Eprint("Missing MSG or RUN in reminder.\n");
X	       return 0;
X
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:
X	       Eprint("Only weekdays are valid after a local OMIT.\n");
X	       return 0;
X           }
X       }
X   }
X   if (tok.type == At_t) {
X      done = 0;
X      while (!done) {
X         tok = ParseToken(s);
X         switch(tok.type) {
X
X            case Msg_t:
X            case Run_t: done = 1; break;
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 = tok.val;
X	       break;
X	    
X	    default: Eprint("Can't use token %s in an AT.\n", tok.str);
X                     return 0;
X         }
X      }
X   }
X
X
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 (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   /* Tweak the back and delta values to their defaults */
X   if (back == -1) back = 0;
X   if (delta == -1) delta = 0;
X
X   jul = GetTriggerDate(d, m, y, wd, cons, back, repeat, omit);
X   if (Calendar) {
X      if (jul == JulianToday && tok.type == Msg_t) {
X         while (isspace(**s)) (*s)++;
X         strcpy(WorkBuf, *s);
X         CalTime = tim;
X	 return 1;
X      } else return 0;
X   }
X     
X   if (jul == -1) {
X      if (Debug) Eprint("Reminder has expired.\n");
X      return -1;
X   }
X   FromJulian(jul, &d2, &m2, &y2);
X
X   /* Figure out if the reminder should be triggered */
X   
X   trigger = MoveBack(jul, delta, d2, m2, y2, 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));
X            printf("%s\n", WorkBuf);
X         }
X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim);
X         printf("%s\n", WorkBuf);
X      }
X      else if (tok.type == Run_t) {
X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim);
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/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xint GetTriggerDate(int d, int m, int y, int wd, int cons, int back, int repeat, int omit)
X#else
Xint GetTriggerDate(d, m, y, wd, cons, back, repeat, omit)
Xint d, m, y, wd, cons, back, repeat, omit;
X#endif
X{
X   int i, d2, m2, y2, jul;
X
X   i = TryNextDate(&d2, &m2, &y2, CurDay, CurMon, CurYear,
X		   d, m, y, wd, cons, 0);
X
X   if (i && !repeat) return -1;
X
X   jul = Julian(d2, m2, y2);
X   if (repeat) {
X      if (back) jul = MoveBack(jul, back, d2, m2, y2, omit);
X
X      if (jul < JulianToday) {
X         jul += ((JulianToday - jul) / repeat) * repeat;
X         if (jul < JulianToday) jul += repeat;
X      }
X      return jul;
X
X   } else {
X      if (back) {
X         jul = MoveBack(jul, back, d2, m2, y2, omit);
X         while (jul < JulianToday) {
X            i = TryNextDate(&d2, &m2, &y2, d2, m2, y2,
X			 d, m, y, wd, cons, 1);
X	    if (i) return -1;
X            jul = Julian(d2, m2, y2);
X	    jul = MoveBack(jul, back, d2, m2, y2, omit);
X         }
X         
X      }
X   return jul;
X   }
X}
SHAR_EOF
$TOUCH -am 1115094090 dorem.c &&
chmod 0600 dorem.c ||
echo "restore of dorem.c failed"
set `wc -c dorem.c`;Wc_c=$1
if test "$Wc_c" != "8966"; then
	echo original size 8966, current size $Wc_c
fi
fi
# ============= dosubst.c ==============
if test X"$1" != X"-c" -a -f 'dosubst.c'; then
	echo "File already exists: skipping 'dosubst.c'"
else
echo "x - extracting dosubst.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dosubst.c &&
X#include <ctype.h>
X#include <stdio.h>
X#ifndef UNIX
X#include <string.h>
X#endif
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X
X#define ABS(x) ( ((x) < 0) ? (-(x)) : (x))
X
X/***************************************************************/
X/*                                                             */
X/*  DOSUBST.C                                                  */
X/*                                                             */
X/*  Performs line substitution for reminders.                  */
X/*                                                             */
X/***************************************************************/
X
Xstatic char TODAY[] = "today";
Xstatic char TOMORROW[] = "tomorrow";
X
X#ifndef UNIX
Xint DoSubst(char *src, char *dst, int d, int m, int y, int jul, enum Token_t t, int tim)
X#else
Xint DoSubst(src, dst, d, m, y, jul, t, tim)
X     char *src;
X     char *dst;
X     int d;
X     int m;
X     int y;
X     int jul;
X     enum Token_t t;
X     int tim;
X#endif
X{
X   int diff = jul - JulianToday;
X   char c;
X   char *od;
X   int wkday = jul % 7;
X   char *plu, *pm;
X   int curtim = (int) (SystemTime() / 60);
X   int done;
X   int h;
X   int hh;
X   int min;
X   int tdiff;
X   int adiff, mdiff, hdiff;
X   char *mplu, *hplu, *when;
X   
X   if (tim == -1) tim = curtim;
X   tdiff = tim - curtim;
X   adiff = ABS(tdiff);
X   mdiff = adiff % 60;
X   hdiff = adiff / 60;
X   mplu = (mdiff == 1 ? "" : "s");
X   hplu = (hdiff == 1 ? "" : "s");
X   when = (tdiff < 0 ? "ago" : "from now");
X   
X   h = tim / 60;
X   min = tim % 60;
X
X   if (h >= 12) pm = "pm"; else pm = "am";
X   if (h == 12) hh = 12; else hh = h % 12;
X
X   *dst = 0;
X   
X   switch(d) {
X      case 1:
X      case 21:
X      case 31: plu = "st"; break;
X      
X      case 2:
X      case 22: plu = "nd"; break;
X      
X      case 3:
X      case 23: plu = "rd"; break;
X      
X      default: plu = "th"; break;
X   }
X      
X   
X   while (c = *src++) {
X     if (c == '\n') continue;
X     else if (c != '%') { *dst++ = c; *dst = 0; }
X     else {
X         od = dst;
X         c = *src++;
X	 done = 0;
X         if (diff <= 1) {
X            switch(upper(c)) {
X               case 'A':
X               case 'B':
X	       case 'C':
X	       case 'E':
X	       case 'F':
X	       case 'G':
X	       case 'H':
X	       case 'I':
X	       case 'J':
X	       case 'K':
X	       case 'L':
X	       case 'U':
X	       case 'V': sprintf(dst, "%s", (diff ? TOMORROW : TODAY));
X		         dst += strlen(dst);
X		         done = 1;
X 		         break;
X		     
X               default: done = 0;
X            }
X	 }	     
X     
X	 if (!done) switch(upper(c)) {
X	    case 0: *dst = 0; return 0;
X	    
X   	    case 'A':
X               sprintf(dst, "on %s, %d %s, %d", DayName[wkday], d,
X		              MonthName[m], y);
X               dst += strlen(dst);
X	       break;
X	       
X	    case 'B':
X               sprintf(dst, "in %d days' time", diff);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'C':
X               sprintf(dst, "on %s", DayName[wkday]);
X               dst += strlen(dst);
X	       break;
X	       
X	    case 'D':
X	       sprintf(dst, "%d", d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'E':
X	       sprintf(dst, "on %02d/%02d/%04d", d, m+1, y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'F':
X	       sprintf(dst, "on %02d/%02d/%04d", m+1, d, y);
X	       dst += strlen(dst);
X               break;
X
X	    case 'G':
X               sprintf(dst, "on %s, %d %s", DayName[wkday], d, MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'H':
X               sprintf(dst, "on %02d/%02d", d, m+1);
X	       dst += strlen(dst);
X               break;
X
X	    case 'I':
X               sprintf(dst, "on %02d/%02d", m+1, d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'J':
X               sprintf(dst, "on %s, %s %d%s, %d", DayName[wkday],
X		              MonthName[m], d, plu, y);
X               dst += strlen(dst);
X               break;
X	    
X	    case 'K':
X	       sprintf(dst, "on %s, %s %d%s", DayName[wkday],
X	                      MonthName[m], d, plu);
X	       dst += strlen(dst);
X               break;
X	       		      
X            case 'L':
X	       sprintf(dst, "on %04d/%02d/%02d", y, m+1, d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'M':
X	       sprintf(dst, "%s", MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'N':
X	       sprintf(dst, "%d", m+1);
X	       dst += strlen(dst);
X               break;
X
X	    case 'O':
X               if (RealToday == JulianToday) sprintf(dst, " (today)");
X               dst += strlen(dst);
X               break;
X	       
X	    case 'P':
X	       sprintf(dst, (diff == 1 ? "" : "s"));
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Q':
X	       sprintf(dst, (diff == 1 ? "'s" : "s'"));
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'R':
X	       sprintf(dst, "%02d", d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'S':
X	       sprintf(dst, plu);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'T':
X	       sprintf(dst, "%02d", m+1);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'U':
X	       sprintf(dst, "on %s, %d%s %s, %d", DayName[wkday], d,
X	                      plu, MonthName[m], y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'V':
X	       sprintf(dst, "on %s, %d%s %s", DayName[wkday], d, plu,
X	                      MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'W':
X	       sprintf(dst, DayName[wkday]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'X':
X	       sprintf(dst, "%d", diff);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Y':
X	       sprintf(dst, "%d", y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Z':
X	       sprintf(dst, "%d", y % 100);
X	       dst += strlen(dst);
X               break;
X
X	    case '1':
X               if (tdiff == 0) 
X                  sprintf(dst, "now");
X               else if (hdiff == 0) 
X	          sprintf(dst, "%d minute%s %s", mdiff, mplu, when);
X	       else if (mdiff == 0)
X	          sprintf(dst, "%d hour%s %s", hdiff, hplu, when);
X               else
X	          sprintf(dst, "%d hour%s and %d minute%s %s", hdiff, hplu, mdiff, mplu, when);
X	       dst += strlen(dst);
X               break;
X
X            case '2':
X               sprintf(dst, "at %d:%02d%s", hh, min, pm);
X	       dst += strlen(dst);
X	       break;
X
X	    case '3': sprintf(dst, "at %02d:%02d", h, min);
X	       dst += strlen(dst);
X	       break;
X
X	    case '4': sprintf(dst, "%d", tdiff);
X	       dst += strlen(dst);
X	       break;
X	       
X	    case '5': sprintf(dst, "%d", adiff);
X	       dst += strlen(dst);
X	       break;
X
X            case '6': sprintf(dst, when);
X	       dst += strlen(dst);
X	       break;
X
X	    case '7': sprintf(dst, "%d", hdiff);
X	       dst += strlen(dst);
X	       break;
X
X	    case '8': sprintf(dst, "%d", mdiff);
X	       dst += strlen(dst);
X	       break;
X
X	    case '9': sprintf(dst, mplu);
X	       dst += strlen(dst);
X	       break;
X
X	    case '0': sprintf(dst, hplu);
X	       dst += strlen(dst);
X	       break;
X
X            case '!': sprintf(dst, (tdiff >= 0 ? "is" : "was"));
X	       dst += strlen(dst);
X	       break;
X	    
X            case '_': *dst++ = '\n'; *dst = 0;
X	       break;
X
X	    case '\"': break;  /* Ignore the %" marker */
X 
X            default:
X	       *dst++ = c;
X	       *dst = 0;
X	 }
X	 if (isupper(c)) *od = upper(*od);
X      }
X   }
X   if (t == Msg_t) *dst++ = '\n';
X   *dst = 0;
X   return 0;
X}   
SHAR_EOF
$TOUCH -am 1116095790 dosubst.c &&
chmod 0600 dosubst.c ||
echo "restore of dosubst.c failed"
set `wc -c dosubst.c`;Wc_c=$1
if test "$Wc_c" != "7683"; then
	echo original size 7683, current size $Wc_c
fi
fi
# ============= files.c ==============
if test X"$1" != X"-c" -a -f 'files.c'; then
	echo "File already exists: skipping 'files.c'"
else
echo "x - extracting files.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > files.c &&
X#include <stdio.h>
X#ifndef UNIX
X#include <stdlib.h>
X#endif
X#include <string.h>
X#include <malloc.h>
X#ifndef UNIX
X#include <dos.h>
X#endif
X#include <fcntl.h>
X#ifdef UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X#endif
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X
X#ifndef UNIX
Xstatic int PopFile(void);
X#else
Xstatic int PopFile();
X#endif
X
X/***************************************************************/
X/*                                                             */
X/*  FILES.C                                                    */
X/*                                                             */
X/*  All the routines for opening initial file, getting         */
X/*  and settting initial file's date, closing files,           */
X/*  handling INCLUDE commands, etc.                            */
X/*                                                             */
X/***************************************************************/
X
X/* Define the structure for saving info about a file */
Xtypedef struct {
X   long offset;
X   int  curline;
X   char *name;
X} FileSave;
X
X#define MAXINCLUDE 10
X/* Set up array of MAXINCLUDE file save areas */
Xstatic FileSave stack[MAXINCLUDE];
Xstatic int      SP;
X
Xstatic FILE *fp;
X
X/***************************************************************/
X/*                                                             */
X/*  OpenFile                                                   */
X/*                                                             */
X/*  Open the named file, initialize stack, get file date.      */
X/*  If there's a problem, print an error msg and die.          */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xvoid OpenFile(char *s)
X#else
Xvoid OpenFile(s)
X     char *s;
X     
X#endif
X{
X   unsigned date, time;
X#ifndef UNIX
X   unsigned handle;
X#endif
X   int d, m, y;
X#ifndef UNIX
X   
X   /* Get the file's modification date */
X   if(_dos_open(s, O_RDONLY, &handle)) {
X      fprintf(stderr, "remind: Can't open %s.\n", s);
X      exit(1);
X#else
X   struct stat t;
X   struct tm *t1;
X      
X   /* Get the file's access date */
X   if (stat(s, &t)) {
X     fprintf(stderr, "remind: Can't find file %s.\n", s);
X     exit(1);
X#endif
X   }
X#ifndef UNIX
X   _dos_getftime(handle, &date, &time);
X   d = date & 0x1F;
X   m = (date >> 5) & 0xF;
X   y = (date >> 9) + 1980;
X#else
X   t1 = localtime(&(t.st_atime));
X#endif
X   
X#ifndef UNIX
X   if (y < BASE) LastRun = 0; else LastRun = Julian(d, m-1, y);
X   _dos_close(handle);
X#else
X   y = t1->tm_year + 1900;
X   m = t1->tm_mon;
X   d = t1->tm_mday;
X   
X   if (y < BASE) LastRun = 0; else LastRun = Julian(d, m, y);
X#endif
X   fp = fopen(s, "r");
X   if (fp == NULL) {
X      fprintf(stderr, "remind: Can't open %s.\n", s);
X      exit(1);
X   }
X   
X   CurLine = 0;
X   strcpy(FileName, s);
X   SP = 0;
X   
X   return;
X}   
X
X/***************************************************************/
X/*                                                             */
X/*  DoInclude                                                  */
X/*                                                             */
X/*  Push the state of the current file and open a new file.    */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xvoid DoInclude(char **s)
X#else
Xvoid DoInclude(s)
X     char **s;
X     
X#endif
X{
X   Token tok;
X   tok = ParseToken(s);
X   
X   /* First, check if there's room on the stack */
X   if (SP == MAXINCLUDE) {
X      Eprint("Too many levels of INCLUDE\n");
X      return;
X   }
X   
X   /* Save current data */
X#ifndef UNIX
X   stack[SP].offset = ftell(fp) - 1L;
X#else
X   stack[SP].offset = ftell(fp);
X#endif
X   stack[SP].curline = CurLine;
X   stack[SP].name = (char *) malloc(strlen(FileName)+1);
X   if (stack[SP].name == NULL) {
X      Eprint("Out of memory for INCLUDE\n");
X      return;
X   }
X   strcpy(stack[SP].name, FileName);
X   
X   SP++;
X   
X   /* Close the current file */
X   fclose(fp);
X   
X   /* Open the new file */
X   fp = fopen(tok.str, "r");
X   if (fp == NULL) {
X      Eprint("Can't open %s for INCLUDE\n", tok.str);
X      PopFile();
X      return;
X   }
X   if (Debug || Purge) {
X      Eprint("INCLUDING file %s\n", tok.str);
X   }
X   
X   /* Set the global variables */
X   CurLine = 0;
X   strcpy(FileName, tok.str);
X   return;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  PopFile                                                    */
X/*                                                             */
X/*  Pop to the previous file, if there is one.  Return 0 for   */
X/*  OK, non-zero for no more files.  If we can't pop back      */
X/*  to a file, print an error message and die.                 */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xstatic int PopFile(void)
X#else
Xstatic int PopFile()
X#endif
X{
X#ifndef UNIX
X   unsigned handle, date, time;
X   struct dostime_t t;
X#endif
X
X   if (fp) fclose(fp);
X#ifndef UNIX
X   if (!SP) {
X      if (!Debug && !Purge && (JulianToday == RealToday)) {
X         if (_dos_open(FileName, O_RDONLY, &handle)) {
X            fprintf(stderr, "Could not reset date of %s", FileName);
X            return 1;
X         }
X	 _dos_gettime(&t);
X	 date = CurDay;
X	 date |= (CurMon + 1) << 5;
X	 date |= (CurYear - 1980) << 9;
X	 time = t.second / 2;
X	 time |= t.minute << 5;
X	 time |= t.hour << 11;
X	 _dos_setftime(handle, date, time);
X      }
X      return 1;
X   }
X      
X#else
X   if (!SP) return -1;
X         
X#endif
X   SP--;
X   fp = fopen(stack[SP].name, "r");
X   if (fp == NULL) {
X      Eprint("Argh! Can't return to %s from INCLUDE file %s", stack[SP].name, FileName);
X      exit(1);
X   }
X#ifndef UNIX
X   if (fseek(fp, stack[SP].offset, SEEK_SET)) {
X#else
X   if (fseek(fp, stack[SP].offset, 0)) {
X#endif
X      Eprint("Argh! Can't fseek %s after returning from INCLUDE file %s", stack[SP].name, FileName);
X      exit(1);
X   }
X   
X   if (Debug || Purge) {
X      Eprint("Returning to file %s\n", stack[SP].name);
X   }
X   CurLine = stack[SP].curline;
X   strcpy(FileName, stack[SP].name);
X   free(stack[SP].name);
X   return 0;
X}
X/***************************************************************/
X/*                                                             */
X/*  ReadLine                                                   */
X/*                                                             */
X/*  Reads a line from the file.  If EOF, pops to previous file */
X/*  if there was one.  Returns 0 if more input, non-zero       */
X/*  if no more input.  Updates CurLine.                        */
X/*                                                             */
X/***************************************************************/
Xint ReadLine()
X{
X   int done = 0;
X   int len;
X   
X   Fresh = 1;
X   while (!done) {
X      CurLine++;
X      if (fgets(Line, 512, fp) == NULL) {
X         if (ferror(fp)) Eprint("Error reading %s", FileName);
X	 if (PopFile()) return 1;
X      } else {
X         len = strlen(Line);
X         /* Remove the newline */
X         if (*Line && (*(Line + len-1)=='\n')) {
X            *(Line + strlen(Line)-1) = 0;
X            len--;
X         }
X         done = 1;
X         while(*Line && (*(Line + len-1) == '\\') && len<512) {
X 	    *(Line + len-1) = '\n';
X            if (fgets(Line+len, 512-len,fp) == NULL) {
X               *(Line + len) = 0;
X  	       break;
X	    }
X
X	    CurLine++;
X	    len = strlen(Line);
X            /* Remove the newline */
X            if (*Line && (*(Line + len-1)=='\n')) {
X               *(Line + strlen(Line)-1) = 0;
X               len--;
X            }
X         }
X      }	 
X   }
X   return 0;
X}
X
X/***************************************************************/
X/*                                                             */
X/*  TopLevel - Returns 1 if current file is top level, 0       */
X/*  if it is INCLUDEd.                                         */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xint TopLevel(void) { return (SP == 0); }
X#else
Xint TopLevel()
X{
X  return (SP == 0);
X}
X#endif
SHAR_EOF
$TOUCH -am 1115093990 files.c &&
chmod 0600 files.c ||
echo "restore of files.c failed"
set `wc -c files.c`;Wc_c=$1
if test "$Wc_c" != "8338"; then
	echo original size 8338, current size $Wc_c
fi
fi
# ============= globals.h ==============
if test X"$1" != X"-c" -a -f 'globals.h'; then
	echo "File already exists: skipping 'globals.h'"
else
echo "x - extracting globals.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > globals.h &&
X/***************************************************************/
X/*                                                             */
X/*  GLOBALS.H                                                  */
X/*                                                             */
X/*  Global variables for REMIND.                               */
X/*                                                             */
X/*  By David Skoll - 30 Sept. 1990                             */
X/*                                                             */
X/***************************************************************/
X
Xextern char *MonthName[];
Xextern char *DayName[];
Xextern Token keywd[];
Xextern int   MonthDays[];
Xextern int   MonthIndex[2][12];
Xextern int   FullOmitArray[];
Xextern int   PartOmitArray[];
Xextern char  Line[];
Xextern char  WorkBuf[];
Xextern char  TmpBuf[];
Xextern int   Fresh;
Xextern int   Purge;
Xextern int   Debug;
Xextern int   Verbose;
Xextern char  FileName[];
Xextern int   CurLine;
Xextern int   NumEmitted;
Xextern int   NumRem;
Xextern int   NumFullOmit;
Xextern int   NumPartOmit;
Xextern int   JulianToday;
Xextern int   LastRun;
Xextern int   CurYear;
Xextern int   CurMon;
Xextern int   CurDay;
Xextern char  Banner[];
Xextern int   RealToday;
Xextern int   IgRun;
Xextern int   IgOnce;
Xextern int   NumAtsQueued;
Xextern int   QueueAts;
Xextern int   PrintAts;
Xextern int   Calendar;
Xextern int   CalTime;
Xextern int   CalWidth;
Xextern int   SimpleCalendar;
SHAR_EOF
$TOUCH -am 1115094990 globals.h &&
chmod 0600 globals.h ||
echo "restore of globals.h failed"
set `wc -c globals.h`;Wc_c=$1
if test "$Wc_c" != "1450"; then
	echo original size 1450, current size $Wc_c
fi
fi
# ============= init.c ==============
if test X"$1" != X"-c" -a -f 'init.c'; then
	echo "File already exists: skipping 'init.c'"
else
echo "x - extracting init.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > init.c &&
X#include <stdio.h>
X#ifndef UNIX
X#include <stdlib.h>
X#endif
X#include <string.h>
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X
X#define PATCHLEVEL 0
X
Xstatic char DPMsg[] = "Debug and Purge options conflict - Purge chosen.\n";
Xstatic char DPCMsg[] = "Calendar overrides Debug and Purge options.\n";
X/***************************************************************/
X/*                                                             */
X/*  void initialize(int argc, char *argv[])                    */
X/*                                                             */
X/*  Reads command line options, sets appropriate flags         */
X/*  and FileName.  Also exits with error if invoked            */
X/*  incorrectly.                                               */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
Xvoid initialize(int argc, char *argv[])
X#else
Xvoid initialize(argc, argv)
X     int argc;
X     char *argv[];
X#endif
X{
X   int i;
X   char *s;
X   int d, m, y, t;
X   Token tok;
X
X   Debug    = 0;
X   Purge    = 0;
X   Verbose  = 0;
X   IgOnce   = 0;
X   IgRun    = 0;
X   Calendar = 0;
X   PrintAts = 1;
X   QueueAts = 1;
X   CalWidth = 10;
X   SimpleCalendar = 0;
X
X   if(argc == 1) {
X     fprintf(stderr, "\nREMIND 2.2 Patch Level %d (C) 1990 by David Skoll.\n\n", PATCHLEVEL);
X#ifdef UNIX
X     fprintf(stderr, "Usage: remind [-d | -p | -c# [-w# | -s]] [-voraq] filename [date]\n\n");
X#else
X     fprintf(stderr, "Usage: remind [-d | -p | -c# [-w# | -s]] [-vor] filename [date]\n\n");
X#endif
X     fprintf(stderr, "-d   Debug reminder file\n-p   Purge reminder file\n");
X     fprintf(stderr, "-c#  Produce calendar for # months\n");
X     fprintf(stderr, "-w#  Make calendar # columns wide\n");
X     fprintf(stderr, "-s   Produce simple calendar listing\n");
X     fprintf(stderr, "-v   Verbose messages\n-o   Ignore ONCE directives\n");
X     fprintf(stderr, "-r   Ignore RUN directives\n");
X#ifdef UNIX
X     fprintf(stderr, "-a   Do not trigger current AT reminders in foreground\n");
X     fprintf(stderr, "-q   Do not queue current AT reminders\n\n");
X#endif
X     exit(1);
X   }
X
X   i = 1;
X   s = argv[i];
X
X   /* Process options */
X   while (*s == '-') {
X      while (*++s) {
X         switch(upper(*s)) {
X
X            case 'P':  Purge = 1;
X		     if (Calendar) {
X		        Debug = Purge = 0;
X			fprintf(stderr, DPCMsg);
X	             }
X                     if (Debug) {
X                        Debug = 0;
X                        fprintf(stderr, DPMsg);
X                     }
X		     break;
X		     
X            case 'D': Debug = 1;
X		     if (Calendar) {
X		        Debug = Purge = 0;
X			fprintf(stderr, DPCMsg);
X	             }
X	              if (Purge) {
X		         Debug = 0;
X			 fprintf(stderr, DPMsg);
X		      }
X		      break;
X
X            case 'C': Calendar = 1;
X		     if (Debug || Purge) {
X		        Debug = Purge = 0;
X			fprintf(stderr, DPCMsg);
X	             }
X                     t = atoi(s + 1);
X		     if (t > 0 && t <= 12) Calendar = t;
X                     /* Skip remaining chars on this option */
X	             while (*++s) ;
X	             s--;
X		     break;
X
X	    case 'W': CalWidth = (atoi(s+1)-9)/7;
X	             if (CalWidth < 10) CalWidth = 10;
X		     if (CalWidth > 40) CalWidth = 40;
X	             while (*++s) ;
X	             s--;
X		     break;
X
X            case 'S': SimpleCalendar = 1; break;
X
X	    case 'V': Verbose = 1; break;
X
X	    case 'O': IgOnce = 1; break;
X
X	    case 'R': IgRun = 1; break;
X#ifdef UNIX
X	    case 'A': PrintAts = 0; break;
X
X            case 'Q': QueueAts = 0; break;	      
X#endif	    
X	    default: fprintf(stderr, "Unknown option '%c' ignored.\n", *s);
X	 }			      
X      }
X      i++;
X      if (i >= argc) {
X	fprintf(stderr, "Missing filename - type 'remind' for usage information.\n");
X	 exit(1);
X      }
X      s = argv[i];
X   }	 
X   
X   /* Set FileName */
X   strcpy(FileName, argv[i++]);
X   
X   /* Get date, if supplied */
X   if (i < argc) {
X      *WorkBuf = 0;
X      while (i < argc) {
X         strcat(WorkBuf, argv[i++]);
X	 strcat(WorkBuf, " ");
X      }
X      /* Parse the date */
X      d = m = y = -1;
X      tok.type = Unknown_t;
X      s = WorkBuf;
X      while (tok.type != Eol_t) {
X         tok = ParseToken(&s);
X	 switch(tok.type) {
X	    
X	    case Eol_t: break;
X	    
X	    case Year_t: if (y == -1) 
X	                    y = tok.val;
X			 else {
X			    fprintf(stderr, "Year specified twice!\n");
X			    exit(1);
X			 }
X			 break;
X			 
X	    case Month_t: if (m == -1) 
X	                    m = tok.val;
X			 else {
X			    fprintf(stderr, "Month specified twice!\n");
X			    exit(1);
X			 }
X			 break;
X			 
X	    case Day_t: if (d == -1) 
X	                    d = tok.val;
X			 else {
X			    fprintf(stderr, "Day specified twice!\n");
X			    exit(1);
X			 }
X			 break;
X	   
X            default: fprintf(stderr, "Illegal token %s on command line.\n", tok.str);
X	             exit(1);
X   
X         }
X      } 
X      
X      if (d == -1 || m == -1 || y == -1) {
X         fprintf(stderr, "Date on command line must be fully specified.\n");
X	 exit(1);
X      }
X      if (CheckDate(d, m, y)) {
X         fprintf(stderr, "Illegal date on command line.\n");
X	 exit(1);
X      }
X      
X      CurDay = d;
X      CurMon = m;
X      CurYear = y;
X      JulianToday = Julian(d, m, y);
X   }
X   OpenFile(FileName);
X   if (Debug) {
X      FromJulian(LastRun, &d, &m, &y);
X#ifndef UNIX
X      fprintf(stderr, "\nFile %s last modified on %s, %d %s, %d\n", FileName,
X#else
X      fprintf(stderr, "\nFile %s last accessed on %s, %d %s, %d\n", FileName,
X#endif
X                       DayName[LastRun % 7], d, MonthName[m], y);
X   }	       
X   return;
X}
SHAR_EOF
$TOUCH -am 1116094290 init.c &&
chmod 0600 init.c ||
echo "restore of init.c failed"
set `wc -c init.c`;Wc_c=$1
if test "$Wc_c" != "5675"; then
	echo original size 5675, current size $Wc_c
fi
fi
echo "End of part 2, continue with part 3"
exit 0