v17i004: remind - A replacement for calendar, Part02/04
David F. Skoll
dfs at doe.carleton.ca
Wed Feb 20 03:28:02 AEST 1991
Submitted-by: David F. Skoll <dfs at 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 at 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 at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.misc
mailing list