dfs@doe.carleton.ca (David F. Skoll) (11/02/90)
REMIND is a sophisticated reminder service, with many more features than the Unix calendar command. It includes the ability to specify holidays, advance warning of reminders, sophisticated date specifications, and the ability to format output in a convenient way. REMIND was written originally for MS-DOS and then ported to Unix. It has been compiled on a Sun 3 and a Sun 4, as well as under Microsoft C (5.1) for MS-DOS. It should work with minimal modifications on most Unix systems. ----------------- CUT HERE ------------------------ #!/bin/sh # This is Remind 2.0, a shell archive (shar 3.32) # made 11/01/1990 18:55 UTC by dfs@yar # Source directory /enterprise/navigation/dfs/work/.rem/merged # # existing files will NOT be overwritten # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 368 -rw------- Makefile # 643 -rw------- README.DOS # 897 -rw------- README.UNIX # 1609 -rw------- defines.h # 5618 -rw------- dorem.c # 9292 -rw------- dosubst.c # 7981 -rw------- files.c # 1315 -rw------- globals.h # 3904 -rw------- init.c # 18810 -rw------- main.c # 8674 -rw------- nextdate.c # 1377 -rw------- protos.h # 22384 -rw------- remind.1 # 665 -rw------- remind.mak # if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= Makefile ============== if test X"$1" != X"-c" -a -f 'Makefile'; then echo "File already exists: skipping 'Makefile'" else sed 's/^X//' << 'SHAR_EOF' > Makefile && X# Makefile for REMIND - simple file X X#WARNING: Don't remove the -DUNIX XCFLAGS= -O -DUNIX X Xall: dorem.o files.o main.o nextdate.o init.o dosubst.o X $(LINK.c) -o remind dorem.o files.o main.o nextdate.o init.o dosubst.o X Xdorem.o: dorem.c X Xfiles.o: files.c X Xmain.o: main.c X Xnextdate.o: nextdate.c X Xinit.o: init.c X Xdosubst.o: dosubst.c X Xclean: X rm -f *.o core *~ remind X SHAR_EOF $TOUCH -am 1101133790 Makefile && chmod 0600 Makefile || echo "restore of Makefile failed" set `wc -c Makefile`;Wc_c=$1 if test "$Wc_c" != "368"; then echo original size 368, current size $Wc_c fi fi # ============= README.DOS ============== if test X"$1" != X"-c" -a -f 'README.DOS'; then echo "File already exists: skipping 'README.DOS'" else sed 's/^X//' << 'SHAR_EOF' > README.DOS && XREMIND 2.0 for MS-DOS X XREMIND was originally written for MS-DOS. To compile it, you need Xthe Microsoft C compiler (at least version 5.1) and the Microsoft XMAKE utility. X XTo compile the software, simply go to the source directory and type: X XMAKE REMIND.MAK X XNote that the MS-DOS version of REMIND operates slightly differently from Xthe UNIX version: MS-DOS has no concept of file access date. Thus, to Ximplement the "ONCE" keyword, REMIND will change the modification date Xof the top-level reminder file after it has run. This is equivalent to Xperforming a "touch" of the file after running REMIND. X-- XDavid F. Skoll <dfs@doe.carleton.ca> X SHAR_EOF $TOUCH -am 1101134590 README.DOS && chmod 0600 README.DOS || echo "restore of README.DOS failed" set `wc -c README.DOS`;Wc_c=$1 if test "$Wc_c" != "643"; then echo original size 643, current size $Wc_c fi fi # ============= README.UNIX ============== if test X"$1" != X"-c" -a -f 'README.UNIX'; then echo "File already exists: skipping 'README.UNIX'" else sed 's/^X//' << 'SHAR_EOF' > README.UNIX && XREMIND version 2.0 for UNIX X XTo compile REMIND, just go to the source directory and type "make". XThis creates the executable file "remind". You can type "make CC=gcc" Xif you want to use the Gnu C Compiler. X XThe Makefile is very simply and naive. X XREMIND has only been compiled on Sun3s and Sun4s under Sun OS 4.0. XHowever, it makes very few system calls and should work on most BSD systems. XIt shouldn't take too much hacking to get REMIND to work on almost any Xsystem. The troublesome files are main.c which gets the current system Xdate, and files.c which opens and closes files. X XOnce remind has been compiled, install it in your favourite system directory. XThe manual is in the file "remind.1". You can install it in the appropriate Xman page directory. Remember to change the file suffix if you install it Xin the "l" (local) or "n" (new) directory. X-- XDavid F. Skoll <dfs@doe.carleton.ca> SHAR_EOF $TOUCH -am 1101133690 README.UNIX && chmod 0600 README.UNIX || echo "restore of README.UNIX failed" set `wc -c README.UNIX`;Wc_c=$1 if test "$Wc_c" != "897"; then echo original size 897, current size $Wc_c fi fi # ============= defines.h ============== if test X"$1" != X"-c" -a -f 'defines.h'; then echo "File already exists: skipping 'defines.h'" else sed 's/^X//' << 'SHAR_EOF' > defines.h && X/***************************************************************/ X/* */ X/* DEFINES.H */ X/* */ X/* Contains macros and #defines for REMIND program. */ X/* */ X/* By David Skoll - 30 Sept 1990. */ X/* */ X/***************************************************************/ X X/* User-definable variables. BASE *must* be a year for which the X first of January is a Monday!!! FOMITSIZE and POMITSIZE control X the number of fully-specified (dd-mm-yy) and partially-specified X (dd-mm) holidays. */ X#define BASE 1990 X#define FOMITSIZE 100 X#define POMITSIZE 75 X X/* Useful macros */ X X#define upper(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c)-32) : (c) ) X#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 )) X#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 )) X#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y)) X X/* Bit masks for constraint map */ X#define DAY_M 1 X#define MONTH_M 2 X#define YEAR_M 4 X#define WKDAY_M 8 X Xenum Token_t { Unknown_t, Year_t, Month_t, Day_t, WkDay_t, Msg_t, Run_t, X Omit_t, Banner_t, Rem_t, Delta_t, Back_t, Once_t, Include_t, Eol_t }; X X/* Define the Token structure */ X Xtypedef struct { X char *str; X enum Token_t type; X int val; X} Token; X#ifndef UNIX X X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 defines.h && chmod 0600 defines.h || echo "restore of defines.h failed" set `wc -c defines.h`;Wc_c=$1 if test "$Wc_c" != "1609"; then echo original size 1609, current size $Wc_c fi fi # ============= dorem.c ============== if test X"$1" != X"-c" -a -f 'dorem.c'; then echo "File already exists: skipping 'dorem.c'" else sed 's/^X//' << 'SHAR_EOF' > dorem.c && X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif UNIX 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 UNIX Xint DoRem(s) Xchar **s; X X#endif UNIX X{ X int d, m, y, wd, cons, delta, back, omit, done, i, jul, once; X int d2, m2, y2; X Token tok; X int trigger; X X d = m = y = back = delta = -1; X 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 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 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("Software error: Token %s, type %d, val %d", X tok.str, tok.type, tok.val); 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 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 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 i = TryNextDate(&d2, &m2, &y2, CurDay, CurMon, CurYear, X d, m, y, wd, cons, 0); X if (i) { X if (Debug) Eprint("Reminder has expired.\n"); X return -1; X } 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 = Julian(d2, m2, y2); 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) { X if (Debug) Eprint("Reminder has expired.\n"); X return -1; X } X jul = Julian(d2, m2, y2); X jul = MoveBack(jul, back, d2, m2, y2, omit); X } X FromJulian(jul, &d2, &m2, &y2); X } 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 while (isspace(**s)) (*s)++; X if (trigger <= JulianToday && !(tok.type == Run_t && IgRun)) { /* Trigger a reminder */ X if (NumEmitted == 0 && !Purge && !Debug) { X DoSubst(Banner, WorkBuf, CurDay, CurMon, CurYear, JulianToday, Msg_t); X printf("%s\n", WorkBuf); X } X X DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type); X if (tok.type == Msg_t) printf("%s\n", WorkBuf); X else if (tok.type == Run_t) system(WorkBuf); X else Eprint("Error: Invalid token type %d\n", tok.type); X return 1; X } else return 0; X X} X#ifndef UNIX X X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 dorem.c && chmod 0600 dorem.c || echo "restore of dorem.c failed" set `wc -c dorem.c`;Wc_c=$1 if test "$Wc_c" != "5618"; then echo original size 5618, 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 sed 's/^X//' << 'SHAR_EOF' > dosubst.c && X#include <ctype.h> X#include <stdio.h> X#include "defines.h" X#include "globals.h" X#include "protos.h" 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) X#else UNIX Xint DoSubst(src, dst, d, m, y, jul, t) X char *src; X char *dst; X int d; X int m; X int y; X int jul; X enum Token_t t; X#endif UNIX X{ X int diff = jul - JulianToday; X char c; X char *od; X int wkday = jul % 7; X char *plu; X int done; X#ifndef UNIX X X#else UNIX X char *origDst = dst; X X#endif UNIX 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: plu = "rd"; break; X X default: plu = "th"; break; X } X X X while (c = *src++) { X#ifndef UNIX X if (c != '%') *dst++ = c; X else { X#else UNIX X if (c != '%') { *dst++ = c; *dst = 0; } X else { X#endif UNIX 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 'L': X case 'U': X#ifndef UNIX X case 'V': dst += sprintf(dst, "%s", (diff ? TOMORROW : TODAY)); X done = 1; X#else UNIX X case 'V': (void) sprintf(dst, "%s", (diff ? TOMORROW : TODAY)); X dst = origDst + strlen(origDst); X done = 1; X#endif UNIX 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#ifndef UNIX X dst += sprintf(dst, "on %s, %d %s, %d", DayName[wkday], d, X#else UNIX X (void) sprintf(dst, "on %s, %d %s, %d", DayName[wkday], d, X#endif UNIX X MonthName[m], y); X#ifdef UNIX X dst = origDst + strlen(origDst); X#endif UNIX X break; X X case 'B': X#ifndef UNIX X dst += sprintf(dst, "in %d days' time", diff); X break; X#else UNIX X (void) sprintf(dst, "in %d days' time", diff); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'C': X#ifndef UNIX X dst += sprintf(dst, "on %s", DayName[wkday]); X#else UNIX X (void) sprintf(dst, "on %s", DayName[wkday]); X dst = origDst + strlen(origDst); X#endif UNIX X break; X X case 'D': X#ifndef UNIX X dst += sprintf(dst, "%d", d); X break; X#else UNIX X (void) sprintf(dst, "%d", d); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'E': X#ifndef UNIX X dst += sprintf(dst, "on %02d/%02d/%04d", d, m+1, y); X break; X#else UNIX X (void) sprintf(dst, "on %02d/%02d/%04d", d, m+1, y); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'F': X#ifndef UNIX X dst += sprintf(dst, "on %02d/%02d/%04d", m+1, d, y); X break; X#else UNIX X (void) sprintf(dst, "on %02d/%02d/%04d", m+1, d, y); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'G': X#ifndef UNIX X dst += sprintf(dst, "on %s, %d %s", DayName[wkday], d, MonthName[m]); X break; X#else UNIX X (void) sprintf(dst, "on %s, %d %s", DayName[wkday], d, MonthName[m]); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'H': X#ifndef UNIX X dst += sprintf(dst, "on %02d/%02d", d, m+1); X break; X#else UNIX X (void) sprintf(dst, "on %02d/%02d", d, m+1); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'I': X#ifndef UNIX X dst += sprintf(dst, "on %02d/%02d", m+1, d); X break; X#else UNIX X (void) sprintf(dst, "on %02d/%02d", m+1, d); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'J': X#ifndef UNIX X dst += sprintf(dst, "on %s, %s %d%s, %d", DayName[wkday], X#else UNIX X (void) sprintf(dst, "on %s, %s %d%s, %d", DayName[wkday], X#endif UNIX X MonthName[m], d, plu, y); X#ifdef UNIX X dst = origDst + strlen(origDst); X#endif UNIX X break; X X case 'K': X#ifndef UNIX X dst += sprintf(dst, "on %s, %s %d%s", DayName[wkday], X#else UNIX X (void) sprintf(dst, "on %s, %s %d%s", DayName[wkday], X#endif UNIX X MonthName[m], d, plu); X#ifndef UNIX X break; X#else UNIX X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'L': X#ifndef UNIX X dst += sprintf(dst, "on %04d/%02d/%02d", y, m+1, d); X break; X#else UNIX X (void) sprintf(dst, "on %04d/%02d/%02d", y, m+1, d); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'M': X#ifndef UNIX X dst += sprintf(dst, "%s", MonthName[m]); X break; X#else UNIX X (void) sprintf(dst, "%s", MonthName[m]); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'N': X#ifndef UNIX X dst += sprintf(dst, "%d", m+1); X break; X#else UNIX X (void) sprintf(dst, "%d", m+1); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'O': X#ifndef UNIX X if (RealToday == JulianToday) dst += sprintf(dst, " (today)"); X#else UNIX X if (RealToday == JulianToday) (void) sprintf(dst, " (today)"); X dst = origDst + strlen(origDst); X#endif UNIX X break; X X case 'P': X#ifndef UNIX X dst += sprintf(dst, (diff == 1 ? "" : "s")); X break; X#else UNIX X (void) sprintf(dst, (diff == 1 ? "" : "s")); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'Q': X#ifndef UNIX X dst += sprintf(dst, (diff == 1 ? "'s" : "s'")); X break; X#else UNIX X (void) sprintf(dst, (diff == 1 ? "'s" : "s'")); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'R': X#ifndef UNIX X dst += sprintf(dst, "%02d", d); X break; X#else UNIX X (void) sprintf(dst, "%02d", d); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'S': X#ifndef UNIX X dst += sprintf(dst, plu); X break; X#else UNIX X (void) sprintf(dst, plu); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'T': X#ifndef UNIX X dst += sprintf(dst, "%02d", m+1); X break; X#else UNIX X (void) sprintf(dst, "%02d", m+1); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'U': X#ifndef UNIX X dst += sprintf(dst, "on %s, %d%s %s, %d", DayName[wkday], d, X#else UNIX X (void) sprintf(dst, "on %s, %d%s %s, %d", DayName[wkday], d, X#endif UNIX X plu, MonthName[m], y); X#ifndef UNIX X break; X#else UNIX X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'V': X#ifndef UNIX X dst += sprintf(dst, "on %s, %d%s %s", DayName[wkday], d, plu, X#else UNIX X (void) sprintf(dst, "on %s, %d%s %s", DayName[wkday], d, plu, X#endif UNIX X MonthName[m]); X#ifndef UNIX X break; X#else UNIX X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'W': X#ifndef UNIX X dst += sprintf(dst, DayName[wkday]); X break; X#else UNIX X (void) sprintf(dst, DayName[wkday]); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'X': X#ifndef UNIX X dst += sprintf(dst, "%d", diff); X break; X#else UNIX X (void) sprintf(dst, "%d", diff); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'Y': X#ifndef UNIX X dst += sprintf(dst, "%d", y); X break; X#else UNIX X (void) sprintf(dst, "%d", y); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X case 'Z': X#ifndef UNIX X dst += sprintf(dst, "%d", y % 100); X break; X#else UNIX X (void) sprintf(dst, "%d", y % 100); X dst = origDst + strlen(origDst); X break; X#endif UNIX X X default: X *dst++ = c; X#ifndef UNIX X } X#else UNIX X *dst = 0; X } X#endif UNIX X if (isupper(c)) *od = upper(*od); X } X } X if (t == Msg_t) *dst++ = '\n'; X *dst = 0; X return 0; X} X#ifndef UNIX X X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 dosubst.c && chmod 0600 dosubst.c || echo "restore of dosubst.c failed" set `wc -c dosubst.c`;Wc_c=$1 if test "$Wc_c" != "9292"; then echo original size 9292, 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 sed 's/^X//' << 'SHAR_EOF' > files.c && X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif UNIX X#include <string.h> X#include <malloc.h> X#ifndef UNIX X#include <dos.h> X#endif UNIX X#include <fcntl.h> X#ifdef UNIX X#include <sys/types.h> X#include <sys/stat.h> X#include <time.h> X#endif UNIX X#include "defines.h" X#include "globals.h" X#include "protos.h" X X#ifndef UNIX Xstatic int PopFile(void); X#else UNIX Xstatic int PopFile(); X#endif UNIX 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 UNIX Xvoid OpenFile(s) X char *s; X X#endif UNIX X{ X unsigned date, time; X#ifndef UNIX X unsigned handle; X#endif UNIX 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 UNIX 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 UNIX 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 UNIX X t1 = localtime(&(t.st_atime)); X#endif UNIX X X#ifndef UNIX X if (y < BASE) LastRun = 0; else LastRun = Julian(d, m-1, y); X _dos_close(handle); X#else UNIX 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 UNIX 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 UNIX Xvoid DoInclude(s) X char **s; X X#endif UNIX 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 UNIX X stack[SP].offset = ftell(fp); X#endif UNIX 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 UNIX Xstatic int PopFile() X#endif UNIX X{ X#ifndef UNIX X unsigned handle, date, time; X struct dostime_t t; X#endif UNIX 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 UNIX X if (!SP) return -1; X X#endif UNIX 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 UNIX X if (fseek(fp, stack[SP].offset, 0)) { X#endif UNIX 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 X Fresh = 1; X while (!done) { X CurLine++; X if (fgets(Line, 256, fp) == NULL) { X if (ferror(fp)) Eprint("Error reading %s", FileName); X if (PopFile()) return 1; X } else { X /* Remove the newline */ X if (*Line && (*(Line + strlen(Line)-1)=='\n')) X *(Line + strlen(Line)-1) = 0; X done = 1; X } X } X return 0; X} X X#ifndef UNIX X/***************************************************************/ X/* */ X/* TopLevel - Returns 1 if current file is top level, 0 */ X/* if it is INCLUDEd. */ X/* */ X/***************************************************************/ Xint TopLevel(void) { return (SP == 0); } X X#else UNIX Xint TopLevel() X{ X return (SP == 0); X} X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 files.c && chmod 0600 files.c || echo "restore of files.c failed" set `wc -c files.c`;Wc_c=$1 if test "$Wc_c" != "7981"; then echo original size 7981, 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 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 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; X#ifndef UNIX Xextern int IgOnce; X#else UNIX Xextern int IgOnce; X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 globals.h && chmod 0600 globals.h || echo "restore of globals.h failed" set `wc -c globals.h`;Wc_c=$1 if test "$Wc_c" != "1315"; then echo original size 1315, 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 sed 's/^X//' << 'SHAR_EOF' > init.c && X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif UNIX X#include <string.h> X#include "defines.h" X#include "globals.h" X#include "protos.h" X Xstatic char ErrMsg[] = "\n\t\tREMIND version 2.0 (C) 1990 by David Skoll.\n\nUsage: REMIND [-p | -d] [-v] [-o] [-r] filename [date]\n\n"; Xstatic char DPMsg[] = "Debug and Purge options conflict - Purge chosen.\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 UNIX Xvoid initialize(argc, argv) X int argc; X char *argv[]; X#endif UNIX X{ X int i; X char *s; X int d, m, y; X Token tok; X X Debug = 0; X Purge = 0; X Verbose = 0; X IgOnce = 0; X IgRun = 0; X X if(argc == 1) { X fprintf(stderr, ErrMsg); 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 (Debug) { X Debug = 0; X fprintf(stderr, DPMsg); X } X break; X X case 'D': Debug = 1; X if (Purge) { X Debug = 0; X fprintf(stderr, DPMsg); X } X break; X X case 'V': Verbose = 1; break; X X case 'O': IgOnce = 1; break; X X case 'R': IgRun = 1; break; X X default: fprintf(stderr, "Unknown option '%c' ignored.\n", *s); X } X } X i++; X if (i >= argc) { X fprintf(stderr, ErrMsg); 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 UNIX X fprintf(stderr, "\nFile %s last accessed on %s, %d %s, %d\n", FileName, X#endif UNIX X DayName[LastRun % 7], d, MonthName[m], y); X } X return; X} X#ifndef UNIX X X#endif UNIX SHAR_EOF $TOUCH -am 1024164690 init.c && chmod 0600 init.c || echo "restore of init.c failed" set `wc -c init.c`;Wc_c=$1 if test "$Wc_c" != "3904"; then echo original size 3904, current size $Wc_c fi fi echo "End of part 1, continue with part 2" exit 0