dfs@doe.carleton.ca (David F. Skoll) (02/19/91)
#!/bin/sh # This is part 02 of Remind 2.3.0 if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= files.c ============== if test X"$1" != X"-c" -a -f 'files.c'; then echo "File already exists: skipping 'files.c'" else echo "x - extracting files.c (Text)" sed 's/^X//' << 'SHAR_EOF' > files.c && X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif X#include <string.h> X#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 SHAR_EOF $TOUCH -am 0218130591 files.c && chmod 0600 files.c || echo "restore of files.c failed" set `wc -c files.c`;Wc_c=$1 if test "$Wc_c" != "8388"; then echo original size 8388, current size $Wc_c fi fi # ============= globals.h ============== if test X"$1" != X"-c" -a -f 'globals.h'; then echo "File already exists: skipping 'globals.h'" else echo "x - extracting globals.h (Text)" sed 's/^X//' << 'SHAR_EOF' > globals.h && X/***************************************************************/ X/* */ X/* GLOBALS.H */ X/* */ X/* Global variables for REMIND. */ X/* */ X/* By David Skoll - 30 Sept. 1990 */ X/* */ X/***************************************************************/ X Xextern char *MonthName[]; Xextern char *DayName[]; Xextern Token keywd[]; Xextern int MonthDays[]; Xextern int MonthIndex[2][12]; Xextern int FullOmitArray[]; Xextern int PartOmitArray[]; Xextern char Line[]; Xextern char WorkBuf[]; Xextern char TmpBuf[]; Xextern 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; SHAR_EOF $TOUCH -am 0218130591 globals.h && chmod 0600 globals.h || echo "restore of globals.h failed" set `wc -c globals.h`;Wc_c=$1 if test "$Wc_c" != "1469"; then echo original size 1469, current size $Wc_c fi fi # ============= init.c ============== if test X"$1" != X"-c" -a -f 'init.c'; then echo "File already exists: skipping 'init.c'" else echo "x - extracting init.c (Text)" sed 's/^X//' << 'SHAR_EOF' > init.c && X#include <stdio.h> X#ifndef UNIX X#include <stdlib.h> X#endif X#include <string.h> X#include "defines.h" X#include "globals.h" X#include "protos.h" X X#define PATCHLEVEL 0 X Xstatic char DPMsg[] = "Debug and Purge options conflict - Purge chosen.\n"; Xstatic char DPCMsg[] = "Calendar overrides Debug and Purge options.\n"; 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} SHAR_EOF $TOUCH -am 0218130591 init.c && chmod 0600 init.c || echo "restore of init.c failed" set `wc -c init.c`;Wc_c=$1 if test "$Wc_c" != "6305"; then echo original size 6305, current size $Wc_c fi fi # ============= kall ============== if test X"$1" != X"-c" -a -f 'kall'; then echo "File already exists: skipping 'kall'" else echo "x - extracting kall (Text)" sed 's/^X//' << 'SHAR_EOF' > kall && X#!/bin/sh X# X# kall - kill all processes belonging to this user that match X# specified string. X Xsignal=`echo $1 | grep '^\-.*'` Xme=`basename $0` X Xif [ "$signal" != "" ]; then X shift Xelse X signal="-TERM" Xfi X Xif [ "$1" = "" ]; then X echo "usage: $me [-signal] string [string...]" X echo " kills all of your processes where command name matches" X echo " any of the given strings." X exit Xfi X Xmsg="0" X Xwhile [ "$1" != "" ]; do X X# NOTE: You may have to modify the next line, since PS is non-portable. X# The 'awk' command picks out the process IDs to pass them on to kill. X rprocs=`ps -cx | awk '{if(prog == $5) print $1}' prog=$1 -` X if [ "$rprocs" != "" ]; then X msg="1" X echo -n "${me}: Sending $signal signal to $1 process(es)" X echo '...' X kill $signal $rprocs X fi X shift Xdone X Xif [ $msg = "1" ]; then X echo "${me}: Done." Xfi SHAR_EOF $TOUCH -am 0218130591 kall && chmod 0700 kall || echo "restore of kall failed" set `wc -c kall`;Wc_c=$1 if test "$Wc_c" != "852"; then echo original size 852, current size $Wc_c fi fi # ============= main.c ============== if test X"$1" != X"-c" -a -f 'main.c'; then echo "File already exists: skipping 'main.c'" else echo "x - extracting main.c (Text)" sed 's/^X//' << 'SHAR_EOF' > main.c && 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} SHAR_EOF $TOUCH -am 0218130591 main.c && chmod 0600 main.c || echo "restore of main.c failed" set `wc -c main.c`;Wc_c=$1 if test "$Wc_c" != "20411"; then echo original size 20411, current size $Wc_c fi fi # ============= nextdate.c ============== if test X"$1" != X"-c" -a -f 'nextdate.c'; then echo "File already exists: skipping 'nextdate.c'" else echo "x - extracting nextdate.c (Text)" sed 's/^X//' << 'SHAR_EOF' > nextdate.c && X#include "defines.h" X#include "globals.h" X#include "protos.h" X X/***************************************************************/ X/* */ X/* int TryNextDate(int *retday, int *retmon, int *retyr, */ X/* int startday, int startmon, int startyr, */ X/* int conday, int conmon, int conyr, */ X/* int wkday, int cons, int inc) */ X/* */ X/* This function tries to find the next date satisfying */ X/* the given constraints. Returns */ X/* 0 for success. Returns non-zero if a constraint would */ X/* be violated. Note that if DAY and WEEKDAY are both */ X/* constrained, then MONTH and YEAR may be violated. */ X/* Otherwise, all constraints are honoured. */ X/* The starting point for the search is thisday, etc. */ X/* */ X/* If inc is non-zero, then the search begins from the day */ X/* after the specified date. Note that this function assumes */ X/* that the given date is valid. */ X/* */ X/***************************************************************/ X#ifdef __STDC__ Xint TryNextDate(int *retday, int *retmon, int *retyr, X int d, int m, int y, X int conday, int conmon, int conyr, X int wkday, int cons, int inc) X#else Xint TryNextDate(retday, retmon, retyr, d, m, y, conday, conmon, conyr, X wkday, cons, inc) X int *retday, *retmon, *retyr, d, m, y, conday, conmon, conyr, wkday, cons, inc; X X#endif X X{ X int jul, jul2; X int dd = d, mm = m, yy = y; X X if (inc) X { X d++; X if (d > DaysInMonth(m, y)) { X m++; d = 1; X if (m > 11) { X y++; m = 0; X } X } X } X X X switch (cons & 15) { X X case 0: /* No constraints - just use the start date */ X *retday = d; X *retmon = m; X *retyr = y; X return 0; X X case 1: /* Day constrained to be d */ X *retday = conday; X if (d > conday) { X m++; X if (m > 11) {y++; m=0;} X } X while (conday > DaysInMonth(m, y)) { X m++; X if (m > 11) {y++; m=0;} X } X *retmon = m; X *retyr = y; X return 0; X X case 2: /* Month constrained to be m */ X *retmon = conmon; X if (m > conmon) {y++; d = 1;} X else if (m < conmon) d = 1; X *retday = d; X *retyr = y; X return 0; X X case 3: /* Month and day constrained */ X *retmon = conmon; X *retday = conday; X if (m > conmon || (m == conmon && d > conday)) y++; X while (conday > DaysInMonth(conmon, y)) y++; X *retyr = y; X return 0; X X case 4: /* Year alone constrained */ X if (y > conyr) return 1; X *retyr = conyr; X if (y < conyr) { X *retmon = 0; X *retday = 1; X } X else { X *retmon = m; X *retday = d; X } X return 0; X X case 5: /* Year and day constrained */ X if (y > conyr) return 1; X *retyr = conyr; X *retday = conday; X if (y < conyr) { X *retmon = 0; X return 0; X } X if (d > conday) { X m++; X if (m > 11) return 1; X } X while (conday > DaysInMonth(m, y)) { X m++; X if (m > 11) return 1; X } X *retmon = m; X return 0; X X case 6: /* Year and month constrained */ X if (y > conyr || (y == conyr && m > conmon)) return 1; X *retyr = conyr; X *retmon = conmon; X if (y < conyr || (y == conyr && m < conmon)) { X *retday = 1; X return 0; X } X *retday = d; X return 0; X X case 7: /* Year, month and day constrained */ X *retday = conday; X *retmon = conmon; X *retyr = conyr; X if (y > conyr || (y == conyr && m > conmon) || X (y == conyr && m == conmon && d > conday)) return 1; X return 0; X X case 8: /* Only the weekday constrained. Let's go to Julian mode */ X jul = Julian(d, m, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X X case 9: /* GASP! day and weekday constrained .. bleah! */ X /* First, try last month. */ X jul2 = Julian(d, m, y); X if (m != 0 || y != BASE) X { X mm--; X if (mm < 0) {yy--; mm = 11;} X X /* If there are fewer days in month than required, it X can't possibly match. */ X if (conday <= DaysInMonth(mm, yy)) { X jul = Julian(conday, mm, yy); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { /* SUCCESS! */ X FromJulian(jul, retday, retmon, retyr); X return 0; X } X } X } X /* Didn't work - try this month */ X if (conday <= DaysInMonth(m, y)) { X jul = Julian(conday, m, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { /* SUCCESS! */ X FromJulian(jul, retday, retmon, retyr); X return 0; X } X } X /* Argh! Try next available month */ X mm = m; X yy = y; X do { X mm++; X if (mm > 11) {mm = 0; yy++;} X } while (conday > DaysInMonth(mm, yy)); X jul = Julian(conday, mm, yy); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X X case 10: /* Month and Weekday constrained */ X if (m < conmon) { X jul = Julian(1, conmon, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X } else if (m == conmon) { X jul = Julian(d, conmon, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X if (*retmon != conmon) { X jul = Julian(1, conmon, y+1); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X } X return 0; X } else { /* m > conmon */ X jul = Julian(1, conmon, y+1); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X } X X case 11: /* Day, Month and Weekday constrained */ X jul2 = Julian(d, m, y); X X /* Blip up to next valid year */ X while (conday > DaysInMonth(conmon, y)) y++; X X /* Try this year */ X jul = Julian(conday, conmon, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { X FromJulian(jul, retday, retmon, retyr); X return 0; X } X X /* Must be next year */ X jul = Julian(conday, conmon, y+1); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X X case 12: /* Weekday and year specified */ X if (y > conyr) return 1; X if (y == conyr) {mm = m; dd = d;} else {mm = 0; dd = 1;} X jul = Julian(dd, mm, conyr); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X if (*retyr == conyr) return 0; else return 1; X X case 13: /* Weekday, year and day specified */ X if (y > conyr+1 || (y > conyr && m>0)) return 1; X jul2 = Julian(d, m, y); X if (y > conyr ) { X jul = Julian(conday, 11, conyr); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { X FromJulian(jul, retday, retmon, retyr); X return 0; X } X } else if (y < conyr) { X jul = Julian(conday, 0, conyr); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X } X else { X /* Try last month */ X if (m > 0) { X mm = m - 1; X while (conday > DaysInMonth(mm, y)) mm--; X jul = Julian(conday, mm, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { X FromJulian(jul, retday, retmon, retyr); X return 0; X } X } X /* Try this month */ X if (conday <= DaysInMonth(m,y)) { X jul = Julian(conday, m, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X if (jul >= jul2) { X FromJulian(jul, retday, retmon, retyr); X return 0; X } X } X /* Try next month */ X if (m == 11) return 1; X m++; X while (conday > DaysInMonth(m, y)) m++; X jul = Julian(conday, m, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X return 0; X } X X case 14: /* Weekday, Month and Year specified */ X if (y > conyr || (y == conyr && m > conmon)) return 1; X if (conyr > y || (conyr == y && conmon > m)) { X jul = Julian(1, conmon, conyr); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X if (*retmon == conmon) return 0; else return 1; X } else { X jul = Julian(d, m, y); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X if (*retmon == conmon) return 0; else return 1; X X } X X case 15: /* Weekday, day, month and year specified */ X jul2 = Julian(d, m, y); X jul = Julian(conday, conmon, conyr); X while (!(wkday & (1 << (jul % 7)))) jul++; X FromJulian(jul, retday, retmon, retyr); X if (jul < jul2) return 1; X return 0; X } X} SHAR_EOF $TOUCH -am 0218130591 nextdate.c && chmod 0600 nextdate.c || echo "restore of nextdate.c failed" set `wc -c nextdate.c`;Wc_c=$1 if test "$Wc_c" != "8719"; then echo original size 8719, current size $Wc_c fi fi echo "End of part 2, continue with part 3" exit 0