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