dfs@doe.carleton.ca (David F. Skoll) (02/20/91)
Submitted-by: David F. Skoll <dfs@doe.carleton.ca> Posting-number: Volume 17, Issue 5 Archive-name: remind/part03 #! /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 3 (of 4)." # Contents: cache.c dosubst.c files.c globals.h init.c omits.c # test.rem timed.c # Wrapped by kent@sparky on Tue Feb 19 10:16:40 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'cache.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cache.c'\" else echo shar: Extracting \"'cache.c'\" \(4966 characters\) sed "s/^X//" >'cache.c' <<'END_OF_FILE' X/***************************************************************/ X/* */ X/* CACHE.C */ X/* */ X/* Contains routines for caching reminder file to improve */ X/* calendar performance. */ X/* */ X/* By David Skoll - 15 November 1990 */ X/***************************************************************/ X X#include <stdio.h> X#ifndef NO_MALLOC_H X#include <malloc.h> X#endif X#include <string.h> X#include "defines.h" X#include "globals.h" X#include "protos.h" X#include "cache.h" X X/* Define a cached line */ Xtypedef struct cached_line { X char *text; X struct cached_line *next; X} Centry; X XCentry Cache, *Current; X Xstatic int CacheDone, CacheFailed; X X/***************************************************************/ X/* */ X/* InitCache */ X/* */ X/* Initializes the caching system. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid InitCache(void) X#else Xvoid InitCache() X#endif X{ X CacheDone = 0; X CacheFailed = 0; X Cache.next = NULL; X Current = &Cache; X} X X/***************************************************************/ X/* */ X/* GetLine */ X/* */ X/* This function either reads a line from the file, or gets */ X/* it from memory if it is cached. */ X/* */ X/* Returns 0 if more data to be read; otherwise, non-zero. */ X/* */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint GetLine(void) X#else Xint GetLine() X#endif X{ X int ret; X Token tok; X char *s; X Centry *c; X X if (CacheFailed) return ReadLine(); X X if (!CacheDone) { X ret = ReadLine(); X if (ret) { X CacheDone = 1; X strcpy(FileName, "* cache *"); X CurLine = 0; X return ret; X } X /* Check if we should cache this line */ X X s = Line; X tok = ParseToken(&s); X if (tok.type == Clear_t || tok.type == Push_t || X tok.type == Pop_t || tok.type == Rem_t || tok.type == Omit_t) { X c = (Centry *) malloc(sizeof(Centry)); X if (c == NULL) { X CacheFailed = 1; X DestroyCache(); X return 0; X } X c->text = (char *) malloc(strlen(Line)+1); X if (c->text == NULL) { X CacheFailed = 1; X DestroyCache(); X free(c); X return 0; X } X /* Insert the cache entry */ X c->next = NULL; X strcpy(c->text, Line); X Current->next = c; X Current = c; X } X return ret; X } else { /* Over here, we've finished caching, so just return the line */ X if (Current == NULL) return 1; X else { X strcpy(Line, Current->text); X Current = Current->next; X return 0; X } X } X} X/***************************************************************/ X/* */ X/* ResetCache */ X/* Reset the cache to beginning, or reopen file if caching */ X/* failed. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid ResetCache(void) X#else Xvoid ResetCache() X#endif X{ X /* Reset the OMIT context */ X ClearOmitContext(); X X /* Get rid of any spurious stacked OMIT contexts */ X FreeStackedOmits(); X X if (CacheFailed) OpenFile(FileName); X else Current = Cache.next; X} X X/***************************************************************/ X/* */ X/* DestroyCache */ X/* Frees all memory used by the cache. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid DestroyCache(void) X#else Xvoid DestroyCache() X#endif X{ X Centry *p = &Cache; X Centry *c = p->next; X X while (c) { X if (c->text) free(c->text); X p = c; X c = c->next; X free(p); X } X Cache.next = NULL; X} X END_OF_FILE if test 4966 -ne `wc -c <'cache.c'`; then echo shar: \"'cache.c'\" unpacked with wrong size! fi # end of 'cache.c' fi if test -f 'dosubst.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dosubst.c'\" else echo shar: Extracting \"'dosubst.c'\" \(8427 characters\) sed "s/^X//" >'dosubst.c' <<'END_OF_FILE' X#include <ctype.h> X#include <stdio.h> X#include <string.h> X#include "defines.h" X#include "globals.h" X#include "protos.h" X X/***************************************************************/ X/* */ X/* DOSUBST.C */ X/* */ X/* Performs line substitution for reminders. */ X/* */ X/* If mode = 0, ignore %" escapes. */ X/* If mode = 1, process %" escapes. If a RUN type reminder */ X/* does not have %" escape, return the empty string. */ X/* */ X/***************************************************************/ X Xstatic char TODAY[] = "today"; Xstatic char TOMORROW[] = "tomorrow"; X X#ifdef __STDC__ Xint DoSubst(char *src, char *dst, int d, int m, int y, int jul, enum Token_t t, int tim, int mode) X#else Xint DoSubst(src, dst, d, m, y, jul, t, tim, mode) 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 int mode; X#endif X{ X int diff = jul - JulianToday; X char c; X char *od, *s; 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 (mode == 1) { X s = src; X od = src; X while (*s) { X if (*s == '%' && *(s+1) == '\"') { X src = s+2; X break; X } X s++; X } X if (src == od && t == Run_t) { X *dst = 0; X return 0; X } X if (*src == '%' && *(src+1) == '\"') { X *dst = 0; X return 0; X } X if (tim != -1) { X sprintf(dst, "%02d:%02d ", (tim / 60), (tim % 60)); X dst += strlen(dst); X } X } 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 '\"': if (mode == 1) { X *dst = 0; X return 0; X } X break; 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 default: X *dst++ = c; X *dst = 0; X } X if (isupper(c)) *od = upper(*od); X } X } X if (t == Msg_t && mode == 0) *dst++ = '\n'; X *dst = 0; X return 0; X} END_OF_FILE if test 8427 -ne `wc -c <'dosubst.c'`; then echo shar: \"'dosubst.c'\" unpacked with wrong size! fi # end of 'dosubst.c' fi if test -f 'files.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'files.c'\" else echo shar: Extracting \"'files.c'\" \(8388 characters\) sed "s/^X//" >'files.c' <<'END_OF_FILE' X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif X#include <string.h> X#ifndef NO_MALLOC_H X#include <malloc.h> X#endif 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#ifdef __STDC__ 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#ifdef __STDC__ 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#ifdef __STDC__ 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#ifdef __STDC__ 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\n", 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\n", 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\n", 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\n", 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#ifdef __STDC__ Xint TopLevel(void) { return (SP == 0); } X#else Xint TopLevel() X{ X return (SP == 0); X} X#endif END_OF_FILE if test 8388 -ne `wc -c <'files.c'`; then echo shar: \"'files.c'\" unpacked with wrong size! fi # end of 'files.c' fi if test -f 'globals.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'globals.h'\" else echo shar: Extracting \"'globals.h'\" \(1469 characters\) sed "s/^X//" >'globals.h' <<'END_OF_FILE' 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 char Fresh; Xextern char Purge; Xextern char Debug; Xextern char Verbose; Xextern char Next; 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 char IgRun; Xextern char IgOnce; Xextern int NumAtsQueued; Xextern char QueueAts; Xextern char PrintAts; Xextern int Calendar; Xextern int CalTime; Xextern int CalWidth; Xextern int SimpleCalendar; END_OF_FILE if test 1469 -ne `wc -c <'globals.h'`; then echo shar: \"'globals.h'\" unpacked with wrong size! fi # end of 'globals.h' fi if test -f 'init.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'init.c'\" else echo shar: Extracting \"'init.c'\" \(6305 characters\) sed "s/^X//" >'init.c' <<'END_OF_FILE' 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"; Xstatic char NMsg[] = "Next overrides Calendar, Debug and Purge options.\n"; X 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#ifdef __STDC__ 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 Next = 0; X PrintAts = 1; X QueueAts = 1; X CalWidth = 10; X SimpleCalendar = 0; X X if(argc == 1) { X fprintf(stderr, "\nREMIND 2.3 Patch Level %d (C) 1990, 1991 by David Skoll.\n\n", PATCHLEVEL); X#ifdef UNIX X fprintf(stderr, "Usage: remind [-n | -d | -p | -c# [-w# | -s]] [-voraq] filename [date]\n\n"); X#else X fprintf(stderr, "Usage: remind [-n | -d | -p | -c# [-w# | -s]] [-vor] filename [date]\n\n"); X#endif X fprintf(stderr, "-n Output next occurrence of reminders in simple format\n"); 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 (used with -c)\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 'N': Next = 1; X if (Calendar || Debug || Purge) { X Calendar = Debug = Purge = 0; X fprintf(stderr, NMsg); X } X break; X X case 'P': Purge = 1; X if (Next) { X Calendar = Debug = Purge = 0; X fprintf(stderr, NMsg); X } 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 (Next) { X Calendar = Debug = Purge = 0; X fprintf(stderr, NMsg); X } 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 (Next) { X Calendar = Debug = Purge = 0; X fprintf(stderr, NMsg); X } 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} END_OF_FILE if test 6305 -ne `wc -c <'init.c'`; then echo shar: \"'init.c'\" unpacked with wrong size! fi # end of 'init.c' fi if test -f 'omits.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'omits.c'\" else echo shar: Extracting \"'omits.c'\" \(10630 characters\) sed "s/^X//" >'omits.c' <<'END_OF_FILE' X/***************************************************************/ X/* */ X/* OMITS.C */ X/* */ X/* By David Skoll - 12 February 1991 */ X/* */ X/* Handle all code related to global OMITs */ X/* */ X/***************************************************************/ X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif X X#ifndef NO_MALLOC_H X#include <malloc.h> X#endif X X#include "defines.h" X#include "protos.h" X#include "globals.h" X X/* Define an OMIT stack buffer */ Xtypedef struct omit_stack { X struct omit_stack *next; X int NumFullOmit; X int NumPartOmit; X int Omits[1]; X} OmitBuffer; X X/* Variables that we only want visible here */ Xstatic OmitBuffer *OmitStack = (OmitBuffer *) NULL; X X/***************************************************************/ X/* */ X/* int DoGlobalOmit(char **s) */ X/* */ X/* Add an entry to the global ommissions array. Either */ X/* a fully-specified date, or a mm-yy type date. */ X/* Return 0 if OK, -1 if date is in past, -2 if problem. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint DoGlobalOmit(char **s) X#else Xint DoGlobalOmit(s) X char **s; X#endif X{ X int d = -1, m = -1, y = -1; X int omit; X int *ptr; X Token tok; X char *olds = *s; X X tok.type = Unknown_t; X while(tok.type != Eol_t && tok.type != Run_t && tok.type != Msg_t) { X tok = ParseToken(s); X switch (tok.type) { X case Year_t: y = tok.val; break; X case Month_t: m = tok.val; break; X case Day_t: d = tok.val; break; X X case Delta_t: X case Eol_t: X case Msg_t: X case Run_t: break; X default: Eprint("Invalid token '%s' for OMIT command.\n", tok.str); X return -2; X } X } X X if (d == -1 || m == -1 || CheckDate(d, m, y)) { X Eprint("Invalid date specification.\n"); X return -2; X } X X if (y == -1) { /* Only mm-dd specified */ X if (NumPartOmit == POMITSIZE) { X Eprint("Too many partially-specified OMITs.\n"); X return -2; X } X omit = (m << 5) + d; X ptr = PartOmitArray + NumPartOmit; X NumPartOmit++; X while (ptr > PartOmitArray && *(ptr-1) > omit) { X *ptr = *(ptr-1); X ptr--; X } X *ptr = omit; X X /* Check if the bonehead already has it - if so, delete it */ X if (ptr > PartOmitArray && *(ptr-1) == *ptr) { X if (Debug) Eprint("Duplicated partially-specified OMIT.\n"); X NumPartOmit--; X while (ptr < NumPartOmit+PartOmitArray) { X *ptr = *(ptr + 1); X ptr++; X } X } X /* If we got a DELTA, a MSG or a RUN, then execute DoRem */ X if (tok.type == Delta_t || tok.type == Run_t || tok.type == Msg_t) X return DoRem(&olds); X } else { /* All three specified */ X if (NumFullOmit == FOMITSIZE) { X Eprint("Too many fully-specified OMITs.\n"); X return -2; X } X omit = Julian(d, m, y); X X ptr = FullOmitArray + NumFullOmit; X NumFullOmit++; X while (ptr > FullOmitArray && *(ptr-1) > omit) { X *ptr = *(ptr-1); X ptr--; X } X *ptr = omit; X X /* Check if the bonehead already has it - if so, delete it */ X if (ptr > FullOmitArray && *(ptr-1) == *ptr) { X if (Debug) Eprint("Duplicated fully-specified OMIT.\n"); X NumFullOmit--; X while (ptr < NumFullOmit+FullOmitArray) { X *ptr = *(ptr + 1); X ptr++; X } X } X if (omit < JulianToday) { X if (Debug) Eprint("Omit has expired.\n"); X return -1; X } X /* If we got a DELTA, a MSG or a RUN, then execute DoRem */ X if (tok.type == Delta_t || tok.type == Run_t || tok.type == Msg_t) X return DoRem(&olds); X } X return 0; X} X X/***************************************************************/ X/* */ X/* PushOmitContext */ X/* */ X/* Push the Global OMIT context onto a stack. */ X/* */ X/* Returns 0 for success, 1 for failure. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint PushOmitContext(void) X#else Xint PushOmitContext() X#endif X{ X OmitBuffer *new = (OmitBuffer *) malloc( sizeof(OmitBuffer) + X (NumFullOmit + NumPartOmit - 1) * sizeof(int)); X X if (!new) { X Eprint("Unable to allocate memory for PUSH-OMIT-CONTEXT.\n"); X return 1; X } X X new->NumFullOmit = NumFullOmit; X new->NumPartOmit = NumPartOmit; X X CopyInts(FullOmitArray, &(new->Omits[0]), NumFullOmit); X CopyInts(PartOmitArray, &(new->Omits[NumFullOmit]), NumPartOmit); X X new->next = OmitStack; X OmitStack = new; X X return 0; X} X X/***************************************************************/ X/* */ X/* PopOmitContext */ X/* */ X/* Restore the OMIT context from the stack. */ X/* */ X/* Returns 0 for success, 1 for failure. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint PopOmitContext(void) X#else Xint PopOmitContext() X#endif X{ X X OmitBuffer *temp; X X if (!OmitStack) { X Eprint("No saved contexts for POP-OMIT-CONTEXT.\n"); X return 1; X } X X NumFullOmit = OmitStack->NumFullOmit; X NumPartOmit = OmitStack->NumPartOmit; X X CopyInts(&(OmitStack->Omits[0]), FullOmitArray, NumFullOmit); X CopyInts(&(OmitStack->Omits[NumFullOmit]), PartOmitArray, NumPartOmit); X X temp = OmitStack->next; X free(OmitStack); X OmitStack = temp; X return 0; X} X X/***************************************************************/ X/* */ X/* ClearOmitContext */ X/* */ X/* Get rid of all global OMITS. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid ClearOmitContext(void) X#else Xvoid ClearOmitContext() X#endif X{ X NumFullOmit = NumPartOmit = 0; X} X X/***************************************************************/ X/* */ X/* CopyInts */ X/* */ X/* Copy integer values from one array to another. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid CopyInts(int *from, int *to, int count) X#else Xvoid CopyInts(from, to, count) Xint *from, *to, count; X#endif X{ X while (count--) *to++ = *from++; X} X X/***************************************************************/ X/* */ X/* FreeStackedOmits */ X/* */ X/* Get rid of all the stacked OMIT contexts */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid FreeStackedOmits(void) X#else Xvoid FreeStackedOmits() X#endif X{ X OmitBuffer *current = OmitStack, *next; X X if (current && Debug) Eprint("Warning - more PUSH-OMIT-CONTEXTs than POP-OMIT-CONTEXTs\n"); X X while (current) { X next = current->next; X free(current); X current = next; X } X X OmitStack = (OmitBuffer *) NULL; X} X X/***************************************************************/ X/* */ X/* IsOmitted */ X/* */ X/* Returns non-zero if the julian date should be omitted, 0 */ X/* otherwise. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint IsOmitted(int jul, int localomit) X#else Xint IsOmitted(jul, localomit) Xint jul, localomit; X#endif X{ X int d, m, y; X X /* Check if we should omit because of local omit */ X if (localomit & 1 << (jul % 7)) return 1; X X /* Check if we should omit because of fully-specified global omit */ X if (NumFullOmit && my_bsearch(jul, FullOmitArray, NumFullOmit)) return 1; X X /* Check if we should omit because of partially-specified global omits */ X if (NumPartOmit) { X FromJulian(jul, &d, &m, &y); X if (my_bsearch((m << 5)+d, PartOmitArray, NumPartOmit)) return 1; X } X X /* Looks cool - don't omit */ X return 0; X} X X/***************************************************************/ X/* */ X/* my_bsearch */ X/* */ X/* A simplified version of bsearch() for people whose library */ X/* does not have the full version. This only works when */ X/* searching a sorted array of integers. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint *my_bsearch(int key, int *array, int number) X#else Xint *my_bsearch(key, array, number) Xint key, *array, number; X#endif X{ X int top = number - 1; X int bot = 0; X int mid; X X while (top >= bot) { X mid = (top+bot)/2; X if (*(array+mid) == key) return array+mid; X else if (*(array+mid) > key) top = mid-1; X else bot = mid+1; X } X X /* Oh, well - unsuccessful search. Return NULL */ X return NULL; X} END_OF_FILE if test 10630 -ne `wc -c <'omits.c'`; then echo shar: \"'omits.c'\" unpacked with wrong size! fi # end of 'omits.c' fi if test -f 'test.rem' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'test.rem'\" else echo shar: Extracting \"'test.rem'\" \(2975 characters\) sed "s/^X//" >'test.rem' <<'END_OF_FILE' X# Test file for REMIND X# X# Use this file to test the date calculation routines X# of the REMIND program by typing: X# X# (UNIX version): X# remind -dv test.rem 16 FEB 1991 >& temp X# X# (DOS version): X# e2o remind -dv test.rem 16 FEB 1991 > temp X# X# and comparing the results with test.out. X# X# The only differences should be the date of last X# modification/access X X# Test each possible case of the basic reminders. X XREM MSG Every Day X XREM 18 MSG Every 18th XREM 15 MSG Every 15th X XREM Feb MSG February XREM Jan MSG January XREM March MSG March X XREM 13 Jan MSG 13 Jan XREM 15 Feb MSG 15 Feb XREM 28 Feb MSG 28 Feb XREM 29 Feb MSG 29 Feb XREM 5 Mar MSG 5 Mar X XREM 1990 MSG 1990 XREM 1991 MSG 1991 XREM 1992 MSG 1991 X XREM 1 1990 MSG 1 1990 XREM 29 1991 MSG 29 1991 XREM 29 1992 MSG 29 1992 XREM 16 1991 MSG 16 1991 X XREM Jan 1990 MSG Jan 1990 XREM Feb 1991 MSG Feb 1991 XREM Dec 1991 MSG Dec 1991 XREM May 1992 MSG May 1992 X XREM 1 Jan 1991 MSG 1 Jan 1991 XREM 16 Feb 1991 MSG 16 Feb 1991 XREM 29 Dec 1992 MSG 29 Dec 1992 X XREM Sun MSG Sun XREM Fri Sat Tue MSG Fri Sat Tue X XREM Sun 16 MSG Sun 16 XREM Mon Tue Wed Thu Fri 1 MSG Mon Tue Wed Thu Fri 1 X XREM Sun Feb MSG Sun Feb XREM Mon Tue March MSG Mon Tue March X XREM Sun 16 Feb MSG Sun 16 Feb XREM Mon Tue 10 March MSG Mon Tue 10 March X XREM Sat Sun 1991 MSG Sat Sun 1991 XREM Mon Tue 1992 MSG Mon Tue 1992 X XREM Sun 16 1991 MSG Sun 16 1991 XREM Mon Tue Wed Thu Fri 1 1992 MSG Mon Tue Wed Thu Fri 1 1992 X XREM Mon Feb 1991 MSG Mon Feb 1991 XREM Tue Jan 1992 MSG Tue Jan 1992 X XREM Sun Mon 16 Feb 1991 MSG Sun Mon 16 Feb 1991 XREM Tue 28 Jan 1992 MSG Tue 28 Jan 1992 X X# Try some Backs XCLEAR-OMIT-CONTEXT XREM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun XREM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun X XOMIT 28 Feb XREM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun (28 Feb omitted) XREM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun (28 Feb omitted) X XCLEAR-OMIT-CONTEXT X X# Try out UNTIL XREM Wed UNTIL 21 Feb 1991 MSG Wed UNTIL 21 Feb 1991 X X# Try playing with the OMIT context X XOMIT 28 Feb 1991 XREM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) XREM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) XREM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) XREM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) XREM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) X XPUSH-OMIT-CONTEXT XCLEAR-OMIT-CONTEXT XREM 1 Mar -1 MSG 1 mar -1 XREM 1 Mar --1 MSG 1 mar --1 XREM 28 Feb BEFORE MSG 28 Feb BEFORE XREM 28 Feb SKIP MSG 28 Feb SKIP XREM 28 Feb AFTER MSG 28 Feb AFTER X XPOP-OMIT-CONTEXT XREM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted) XREM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted) XREM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted) XREM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted) XREM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted) X X XREM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91 X X# Test BACK XCLEAR-OMIT-CONTEXT XREM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 X XOMIT 17 Feb 1991 XREM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 (17Feb91 omitted) XREM 18 Feb 1991 ++1 MSG 18 Feb 1991 ++1 (17Feb91 omitted) X XCLEAR-OMIT-CONTEXT X END_OF_FILE if test 2975 -ne `wc -c <'test.rem'`; then echo shar: \"'test.rem'\" unpacked with wrong size! fi # end of 'test.rem' fi if test -f 'timed.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'timed.c'\" else echo shar: Extracting \"'timed.c'\" \(7484 characters\) sed "s/^X//" >'timed.c' <<'END_OF_FILE' X#include <stdio.h> X#include <signal.h> X#include <string.h> X#ifndef NO_MALLOC_H X#include <malloc.h> X#endif X#include "defines.h" X#include "globals.h" X#include "protos.h" X X/***************************************************************/ X/* */ X/* TIMED.C */ X/* */ X/* Contains routines for triggering timed reminders */ X/* */ X/* By David Skoll - 12 Nov 1990 */ X/* */ X/* (C) 1990 by David Skoll */ X/* */ X/***************************************************************/ X X/* Global pointer to AT reminders */ X Xstatic AtEntry AtQueue = X{ X 0, 0, 0, 0, Unknown_t, NULL, NULL X}; X X/***************************************************************/ X/* */ X/* AddEntry */ X/* */ X/* Add an entry to the AT queue, keeping things sorted by */ X/* trigger time. */ X/* */ X/* Returns 0 for success, nonzero for failure */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint AddEntry(AtEntry *e) X#else Xint AddEntry(e) XAtEntry *e; X#endif X{ X AtEntry *current, *prev; X prev = &AtQueue; X current = prev->next; X while (current) { X if (e->firsttime < current->firsttime) { X prev->next = e; X e->next = current; X break; X } else { X prev = current; X current = prev->next; X } X } X if (!current) { X prev->next = e; X e->next = NULL; X } X} X X/***************************************************************/ X/* */ X/* DoAt */ X/* Creates an entry for an At reminder, puts it on the queue */ X/* Updates the global variable NumAtsQueued */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint DoAt(int tim, int tdelta, int trep, char *body, enum Token_t type) X#else Xint DoAt(tim, tdelta, trep, body, type) Xint tim, tdelta, trep; Xchar *body; Xenum Token_t type; X#endif X{ X AtEntry *e; X int curtime; X X curtime = (int) (SystemTime() / 60); X X /* If the trigger time is in the past, don't add to the at queue */ X if (tim < curtime) return 0; X X /* Allocate space for the entry */ X e = (AtEntry *) malloc(sizeof(AtEntry)); X if (e == (AtEntry *) NULL) { X Eprint("Can't malloc memory for AT!\n"); X return 1; X } X e->text = malloc(strlen(body)+1); X if (e->text == NULL) { X Eprint("Can't malloc memory for body of AT!\n"); X return 1; X } X strcpy(e->text, body); X X /* Find out the next trigger time */ X e->firsttime = FindNextTriggerTime(tim, trep, tdelta, curtime); X e->repeat = trep; X e->type = type; X e->time = tim; X e->delta = tdelta; X AddEntry(e); X NumAtsQueued++; X return 0; X} X X/***************************************************************/ X/* */ X/* int FindNextTriggerTime */ X/* */ X/* Returns the next time a queued AT should be triggered. */ X/* Returns -1 if the AT has expired. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint FindNextTriggerTime(int tim, int rep, int delta, int curtime) X#else Xint FindNextTriggerTime(tim, rep, delta, curtime) Xint tim, rep, delta, curtime; X#endif X{ X int trigger = tim; X X if (delta <= 0) X if (trigger < curtime) return -1; else return trigger; X X trigger -= delta; X if (rep == -1) rep = delta; X X if (trigger < curtime) trigger += ((curtime - trigger) / rep) * rep; X if (trigger < curtime) trigger += rep; X if (trigger > tim) trigger = tim; X if (trigger < curtime) return -1; else return trigger; X} X X/***************************************************************/ X/* */ X/* HandleQueuedAts */ X/* */ X/* Handles all the queued AT reminders. Sits in a sleep loop */ X/* to trigger reminders. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xvoid HandleQueuedAts(void) X#else Xvoid HandleQueuedAts() X#endif X{ X AtEntry *e; X long TimeToSleep; X unsigned SleepTime; X long now; X X signal(SIGINT, SigIntHandler); X X while (e = AtQueue.next) { X now = SystemTime(); X TimeToSleep = (long) e->firsttime * 60L - now; X if (TimeToSleep < 0L) TimeToSleep = 0L; X X /* Be paranoid and assume that unsigneds are only two bytes long - X therefore, do the sleeping in 30000-second chunks. */ X X while (TimeToSleep) { X if (TimeToSleep > 30000L) SleepTime = 30000; X else SleepTime = (unsigned) TimeToSleep; X sleep(SleepTime); X TimeToSleep -= (long) SleepTime; X } X X /* Over here, we trigger the reminder */ X DoSubst(e->text, WorkBuf, CurDay, CurMon, CurYear, JulianToday, e->type, e->time, 0); X if (e->type == Run_t) system(WorkBuf); X else printf("%s\n", WorkBuf); X X /* Remove the entry from the queue */ X AtQueue.next = e->next; X X /* Check if this reminder should be re-triggered */ X e->firsttime = FindNextTriggerTime(e->time, e->repeat, X e->delta, e->firsttime + 1); X X if (e->firsttime != -1) AddEntry(e); X else { X /* Not to be added - free the memory */ X free(e->text); X free(e); X } X } X} X X/***************************************************************/ X/* */ X/* SigIntHandler */ X/* */ X/* For debugging purposes, when sent a SIGINT, we print the */ X/* contents of the queue. */ X/* */ X/***************************************************************/ Xvoid SigIntHandler() X{ X AtEntry *e; X X printf("Contents of AT queue:\n"); X X e = AtQueue.next; X while (e) { X printf("Trigger: %02d:%02d Activate: %02d:%02d Rep: %d Delta: %d\n", X e->time / 60, e->time % 60, e->firsttime / 60, e->firsttime % 60, X e->repeat, e->delta); X printf("Text: %s %s\n\n", ((e->type == Msg_t) ? "MSG" : "RUN"), e->text); X e = e->next; X } X printf("\n"); X} END_OF_FILE if test 7484 -ne `wc -c <'timed.c'`; then echo shar: \"'timed.c'\" unpacked with wrong size! fi # end of 'timed.c' fi echo shar: End of archive 3 \(of 4\). cp /dev/null ark3isdone 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.