REMIND 2.3.0 1/4

David F. Skoll dfs at doe.carleton.ca
Tue Feb 19 05:16:02 AEST 1991


Here is the next version of REMIND.  There have been many changes; I'm
reposting the source rather that distributing patches.  Here's the
synopsis of whats new:

Version 2.3 - Added the UNTIL keyword for forcing reminders to expire.

Added the "++" form of 'back' and the "--" form of 'delta' for
ignoring OMIT information.

Added the CLEAR-OMIT-CONTEXT, PUSH-OMIT-CONTEXT and POP-OMIT-CONTEXT
keywords for isolating personal or peculiar reminders from the global
OMIT context.

Speeded up the parsing of tokens.

Changed the source to recognize and exploit ANSI-C compilers which
accept function prototypes.

Added the "-n" option to output the next occurrence of each reminder
in SimpleCalendar format

Modified the calendar and SimpleCalendar formats so that the % escape
substitutions ARE performed.

Remind source code can also be obtained via FTP from alfred.ccs.carleton.ca
(134.117.1.1) in pub/remind-2.3.0.tar.Z.

--
David F. Skoll

#!/bin/sh
# This is Remind 2.3.0, a shell archive (shar 3.32)
# made 02/18/1991 18:12 UTC by dfs at data
# Source directory /enterprise/transporter/dfs/work/.rem/work
#
# existing files will NOT be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    997 -rw------- COPYRIGHT
#   1339 -rw------- Makefile
#   1206 -rw------- README.DOS
#   2180 -rw------- README.UNIX
#   1388 -rw------- WHATSNEW.23
#   4966 -rw------- cache.c
#    785 -rw------- cache.h
#  13183 -rw------- calendar.c
#   2313 -rw------- defines.h
#  11579 -rw------- dorem.c
#   8427 -rw------- dosubst.c
#   8388 -rw------- files.c
#   1469 -rw------- globals.h
#   6305 -rw------- init.c
#    852 -rwx------ kall
#  20411 -rw------- main.c
#   8719 -rw------- nextdate.c
#  10630 -rw------- omits.c
#   2210 -rw------- protos.h
#   1568 -rw------- remind-all.csh
#   1589 -rw------- remind-all.sh
#  40229 -rw------- remind.1
#    940 -rw------- remind.mak
#   2975 -rw------- test.rem
#   7484 -rw------- timed.c
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= COPYRIGHT ==============
if test X"$1" != X"-c" -a -f 'COPYRIGHT'; then
	echo "File already exists: skipping 'COPYRIGHT'"
else
echo "x - extracting COPYRIGHT (Text)"
sed 's/^X//' << 'SHAR_EOF' > COPYRIGHT &&
XTHE REMIND COPYRIGHT
X
XREMIND refers to the entire set of files and documentation in the
XREMIND package.
X
XREMIND is Copyright (C) 1990, 1991 by David Skoll, except for the file
Xremind-all.sh, which is Copyright (C) 1990 by Bill Aten.
X
XYou may use REMIND for free, and may freely distribute it, providing
Xyou do not charge the recipients to whom you distribute REMIND.
X
XYou may modify REMIND.  However, you must clearly indicate such
Xmodifications when you distribute REMIND, and must tell the
Xrecipients of the modified version that it is modified.  Place that
Xnotice in the WHATSNEW.xx file.
X
XYou may incorporate parts of REMIND into your own programs, providing
Xyou do not sell these programs.  You must clearly indicate that the parts
Xof REMIND you have incorporated are Copyright (C) 1990 by David Skoll.
X
XI will attempt to support REMIND as much as possible.  However, you use
Xit at your own risk.  I am not responsible for any damages caused by
Xthe use or misuse of REMIND.
X--
XDavid F. Skoll
SHAR_EOF
$TOUCH -am 0218130591 COPYRIGHT &&
chmod 0600 COPYRIGHT ||
echo "restore of COPYRIGHT failed"
set `wc -c COPYRIGHT`;Wc_c=$1
if test "$Wc_c" != "997"; then
	echo original size 997, current size $Wc_c
fi
fi
# ============= Makefile ==============
if test X"$1" != X"-c" -a -f 'Makefile'; then
	echo "File already exists: skipping 'Makefile'"
else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile for REMIND - simple file
X
X#--------------- BEGINNING OF THINGS YOU CAN CHANGE --------------
X
X#If you have a BSD system:
XCFLAGS= -O -DUNIX
X
X#If you have a SYSV system, comment previous line and uncomment next line:
X#CFLAGS= -O -DUNIX -DSYSV
X
X#If your system does not include <malloc.h>, uncomment next line:
X#CFLAGS += -DNO_MALLOC_H
X
X#If you have a SYSV system which does not implement the pid_t type,
X#uncomment the next line:
X#CFLAGS += -Dpid_t=int
X
X#If you want to use gcc:
X#CC= gcc
X
X#Where do you want it installed?
XBINDIR= /usr/local/bin
XKALLDIR= /usr/share/bin
XMANDIR= /usr/share/man
XMANSECTION= 1
X
X#What program does the installation?
XINSTALL= install
X#INSTALL= cp
X
X#--------------- SHOULDN'T CHANGE STUFF BELOW HERE ---------------
X
Xall: dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o omits.o
X	$(CC) -o remind dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o omits.o
X
Xdorem.o: dorem.c
X
Xfiles.o: files.c
X
Xmain.o:  main.c
X
Xomits.o: omits.c
X
Xnextdate.o: nextdate.c
X
Xinit.o: init.c
X
Xdosubst.o: dosubst.c
X
Xtimed.o: timed.c
X
Xcalendar.o: calendar.c
X
Xcache.o: cache.c
X
Xclean:
X	rm -f *.o core *~ remind
X
Xinstall:
X	$(INSTALL) remind $(BINDIR)
X
Xinstall.man:
X	$(INSTALL) remind.1 $(MANDIR)/man$(MANSECTION)/remind.$(MANSECTION)
X
Xinstall.kall:
X	$(INSTALL) kall $(KALLDIR)
X
SHAR_EOF
$TOUCH -am 0218130591 Makefile &&
chmod 0600 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "1339"; then
	echo original size 1339, current size $Wc_c
fi
fi
# ============= README.DOS ==============
if test X"$1" != X"-c" -a -f 'README.DOS'; then
	echo "File already exists: skipping 'README.DOS'"
else
echo "x - extracting README.DOS (Text)"
sed 's/^X//' << 'SHAR_EOF' > README.DOS &&
XREMIND 2.3 for MS-DOS
X
XFirst, read the files COPYRIGHT and WHATSNEW.23.
X
XREMIND was originally written for MS-DOS.  To compile it, you need the
XMicrosoft C compiler (at least version 5.1) and the Microsoft MAKE
Xutility.
X
XBefore compiling the software, check if it includes patches.  These are
Xfiles called patch.xx.  If there are patches, apply them all by typing
X
Xcat patch.* | patch
X
Xon a Unix machine.  Then copy the software to your MS-DOS machine.
X
XTo compile the software, simply go to the source directory and type:
X
XMAKE REMIND.MAK
X
XThe file test.rem contains test reminders for verifying that REMIND's
Xdate calculation routines are working correctly.  The file test.out
Xcontains the result of running:  remind -dv test.rem 16 feb 1991
X
XNote that the MS-DOS version of REMIND operates slightly differently from
Xthe UNIX version:  MS-DOS has no concept of file access date.  Thus, to
Ximplement the "ONCE" keyword, REMIND will change the modification date
Xof the top-level reminder file after it has run.  This is equivalent to
Xperforming a "touch" of the file after running REMIND.
X
XAlso, the MS-DOS version does not queue AT reminders for timed activation.
X--
XDavid F. Skoll <dfs at doe.carleton.ca>
X
SHAR_EOF
$TOUCH -am 0218130591 README.DOS &&
chmod 0600 README.DOS ||
echo "restore of README.DOS failed"
set `wc -c README.DOS`;Wc_c=$1
if test "$Wc_c" != "1206"; then
	echo original size 1206, current size $Wc_c
fi
fi
# ============= README.UNIX ==============
if test X"$1" != X"-c" -a -f 'README.UNIX'; then
	echo "File already exists: skipping 'README.UNIX'"
else
echo "x - extracting README.UNIX (Text)"
sed 's/^X//' << 'SHAR_EOF' > README.UNIX &&
XREMIND version 2.3 for UNIX
X
XFirst, read the files COPYRIGHT and WHATSNEW.23
X
XBefore compiling the software, check if it includes patches.  These
Xare files called patch.xx.  If there are patches, apply them all by
Xtyping
X
Xcat patch.* | patch
X
XNext, examine the Makefile and change any parameters which need to be
Xchanged for your system.  As it stands, the Makefile is set up for a
XBSD system.
X
XTo compile REMIND, just go to the source directory and type "make".
XThis creates the executable file "remind".  You can type "make CC=gcc"
Xif you want to use the Gnu C Compiler, or you can edit the Makefile to
Xmake gcc the default.
X
XThe file test.rem contains test reminders for verifying that REMIND's
Xdate calculation routines are working correctly.  The file test.out
Xcontains the result of running: remind -dv test.rem 16 feb 1991
X
XREMIND has been compiled on Sun3s and Sun4s under Sun OS 4.0, on an
XIBM PC under MS-DOS and on a 386 Xenix system to name a few.  REMIND
Xshould compile on most systems without difficulty.
X
XOnce remind has been compiled, install it in your favourite system
Xdirectory.  Type "make install" to install the executable, and "make
Xinstall.man" to install the manpage.  If you want to install the "kall"
Xscript, type "make install.kall"
X
XTwo shell scripts, "remind-all.csh" and "remind-all.sh" are provided.
XThese allow automatic mailing of reminders to all users who create a
X$HOME/.reminders file.  These two scripts are equivalent; one is a
X"sh" script and the other is a "csh" script.  Pick the one you want to
Xuse, and follow the instructions in the opening comments of the
Xscript.
X
XA shell script called "kall" is provided which kills processes
Xspecified by command name rather than process ID.  You may have to
Xedit it to work on your system, since the output of "ps" is not
Xportable.  You can use this script to kill all background remind
Xprocesses in your .logout script by using "kall remind" Note that this
Xversion of "kall" is different from the version of kall distributed
Xwith 2.2 - the new version requires an exact match of command name,
Xnot just a command name which contains the specified
Xstring.
X
X--
XDavid F. Skoll <dfs at doe.carleton.ca>
SHAR_EOF
$TOUCH -am 0218130591 README.UNIX &&
chmod 0600 README.UNIX ||
echo "restore of README.UNIX failed"
set `wc -c README.UNIX`;Wc_c=$1
if test "$Wc_c" != "2180"; then
	echo original size 2180, current size $Wc_c
fi
fi
# ============= WHATSNEW.23 ==============
if test X"$1" != X"-c" -a -f 'WHATSNEW.23'; then
	echo "File already exists: skipping 'WHATSNEW.23'"
else
echo "x - extracting WHATSNEW.23 (Text)"
sed 's/^X//' << 'SHAR_EOF' > WHATSNEW.23 &&
XA BRIEF HISTORY OF REMIND:
X
XVersion 1.0 - never publicly released.
X
XVersion 2.0 - first public release.  Included advanced date specifications,
Xcharacter substitution, and the RUN keyword.
X
XVersion 2.1 - Added the "repeat" token for repeating reminders with a period
Xother than 7 days.  Also fixed some bugs from version 2.0
X
XVersion 2.2 - Added the AT keyword, the timed reminders daemon, and the
Xcalendar facility.
X
XVersion 2.2 - Patch 3  - Added the MSG or RUN tokens in an OMIT command; also
Xallowed RUN-type reminders to be explicitly included in the calendar by
Xusing the %" escape sequence.
X
XVersion 2.2 - Patch 5 - Added the BEFORE, AFTER and SKIP tokens to make the
Xhandling of holidays more sensible.  Also corrected a few more bugs.
X
XVersion 2.3 - Added the UNTIL keyword for forcing reminders to expire.
X
XAdded the "++" form of 'back' and the "--" form of 'delta' for
Xignoring OMIT information.
X
XAdded the CLEAR-OMIT-CONTEXT, PUSH-OMIT-CONTEXT and POP-OMIT-CONTEXT
Xkeywords for isolating personal or peculiar reminders from the global
XOMIT context.
X
XSpeeded up the parsing of tokens.
X
XChanged the source to recognize and exploit ANSI-C compilers which
Xaccept function prototypes.
X
XAdded the "-n" option to output the next occurrence of each reminder
Xin SimpleCalendar format
X
XModified the calendar and SimpleCalendar formats so that the % escape
Xsubstitutions ARE performed.
X
SHAR_EOF
$TOUCH -am 0218130591 WHATSNEW.23 &&
chmod 0600 WHATSNEW.23 ||
echo "restore of WHATSNEW.23 failed"
set `wc -c WHATSNEW.23`;Wc_c=$1
if test "$Wc_c" != "1388"; then
	echo original size 1388, current size $Wc_c
fi
fi
# ============= cache.c ==============
if test X"$1" != X"-c" -a -f 'cache.c'; then
	echo "File already exists: skipping 'cache.c'"
else
echo "x - extracting cache.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > cache.c &&
X/***************************************************************/
X/*                                                             */
X/* CACHE.C                                                     */
X/*                                                             */
X/* Contains routines for caching reminder file to improve      */
X/* calendar performance.                                       */
X/*                                                             */
X/* By David Skoll - 15 November 1990                           */
X/***************************************************************/
X
X#include <stdio.h>
X#ifndef NO_MALLOC_H
X#include <malloc.h>
X#endif
X#include <string.h>
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X#include "cache.h"
X
X/* Define a cached line */
Xtypedef struct cached_line {
X   char *text;
X   struct cached_line *next;
X} Centry;
X
XCentry Cache, *Current;
X
Xstatic int CacheDone, CacheFailed;
X
X/***************************************************************/
X/*                                                             */
X/*  InitCache                                                  */
X/*                                                             */
X/*  Initializes the caching system.                            */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid InitCache(void)
X#else
Xvoid InitCache()
X#endif
X{
X   CacheDone   = 0;
X   CacheFailed = 0;
X   Cache.next  = NULL;
X   Current     = &Cache;
X}
X
X/***************************************************************/
X/*                                                             */
X/* GetLine                                                     */
X/*                                                             */
X/* This function either reads a line from the file, or gets    */
X/* it from memory if it is cached.                             */
X/*                                                             */
X/* Returns 0 if more data to be read; otherwise, non-zero.     */
X/*                                                             */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xint GetLine(void)
X#else
Xint GetLine()
X#endif
X{
X   int ret;
X   Token tok;
X   char *s;
X   Centry *c;
X
X   if (CacheFailed) return ReadLine();
X
X   if (!CacheDone) {
X      ret = ReadLine();
X      if (ret) {
X         CacheDone = 1;
X         strcpy(FileName, "* cache *");
X	 CurLine = 0;
X         return ret;
X      }
X      /* Check if we should cache this line */
X
X      s = Line;
X      tok = ParseToken(&s);
X      if (tok.type == Clear_t || tok.type == Push_t ||
X          tok.type == Pop_t || tok.type == Rem_t || tok.type == Omit_t) { 
X         c = (Centry *) malloc(sizeof(Centry));
X         if (c == NULL) {
X            CacheFailed = 1;
X            DestroyCache();
X            return 0;
X         }
X         c->text = (char *) malloc(strlen(Line)+1);
X         if (c->text == NULL) {
X            CacheFailed = 1;
X	    DestroyCache();
X            free(c);
X	    return 0;
X         }
X         /* Insert the cache entry */
X         c->next = NULL;
X         strcpy(c->text, Line);
X         Current->next = c;
X         Current = c;
X      }
X      return ret;
X   } else { /* Over here, we've finished caching, so just return the line */
X      if (Current == NULL) return 1;
X      else {
X         strcpy(Line, Current->text);
X         Current = Current->next;
X         return 0;
X      }
X   }
X}
X/***************************************************************/
X/*                                                             */
X/* ResetCache                                                  */
X/* Reset the cache to beginning, or reopen file if caching     */
X/* failed.                                                     */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid ResetCache(void)
X#else
Xvoid ResetCache()
X#endif
X{
X   /* Reset the OMIT context */
X   ClearOmitContext();
X
X   /* Get rid of any spurious stacked OMIT contexts */
X   FreeStackedOmits();
X
X   if (CacheFailed) OpenFile(FileName);
X   else Current = Cache.next;
X}
X
X/***************************************************************/
X/*                                                             */
X/* DestroyCache                                                */
X/* Frees all memory used by the cache.                         */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid DestroyCache(void)
X#else
Xvoid DestroyCache()
X#endif
X{
X   Centry *p = &Cache;
X   Centry *c = p->next;
X
X   while (c) {
X      if (c->text) free(c->text);
X      p = c;
X      c = c->next;
X      free(p);
X   }
X   Cache.next = NULL;
X}
X
SHAR_EOF
$TOUCH -am 0218130591 cache.c &&
chmod 0600 cache.c ||
echo "restore of cache.c failed"
set `wc -c cache.c`;Wc_c=$1
if test "$Wc_c" != "4966"; then
	echo original size 4966, current size $Wc_c
fi
fi
# ============= cache.h ==============
if test X"$1" != X"-c" -a -f 'cache.h'; then
	echo "File already exists: skipping 'cache.h'"
else
echo "x - extracting cache.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > cache.h &&
X/***************************************************************/
X/*                                                             */
X/*  CACHE.H                                                    */
X/*                                                             */
X/*  Function prototypes, etc. for CACHE.C                      */
X/*                                                             */
X/*  By David Skoll - 15 November 1990                          */
X/*                                                             */
X/***************************************************************/
X#ifdef __STDC__
Xvoid InitCache(void);
Xint GetLine(void);
Xvoid ResetCache(void);
Xvoid DestroyCache(void);
X#else
Xvoid InitCache();
Xint GetLine();
Xvoid ResetCache();
Xvoid DestroyCache();
X#endif
SHAR_EOF
$TOUCH -am 0218130591 cache.h &&
chmod 0600 cache.h ||
echo "restore of cache.h failed"
set `wc -c cache.h`;Wc_c=$1
if test "$Wc_c" != "785"; then
	echo original size 785, current size $Wc_c
fi
fi
# ============= calendar.c ==============
if test X"$1" != X"-c" -a -f 'calendar.c'; then
	echo "File already exists: skipping 'calendar.c'"
else
echo "x - extracting calendar.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calendar.c &&
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}
SHAR_EOF
$TOUCH -am 0218130591 calendar.c &&
chmod 0600 calendar.c ||
echo "restore of calendar.c failed"
set `wc -c calendar.c`;Wc_c=$1
if test "$Wc_c" != "13183"; then
	echo original size 13183, current size $Wc_c
fi
fi
# ============= defines.h ==============
if test X"$1" != X"-c" -a -f 'defines.h'; then
	echo "File already exists: skipping 'defines.h'"
else
echo "x - extracting defines.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > defines.h &&
X/***************************************************************/
X/*                                                             */
X/*  DEFINES.H                                                  */
X/*                                                             */
X/*  Contains macros and #defines for REMIND program.           */
X/*                                                             */
X/*  By David Skoll - 30 Sept 1990.                             */
X/*                                                             */
X/***************************************************************/
X
X/* User-definable variables.  BASE *must* be a year for which the
X   first of January is a Monday!!!  FOMITSIZE and POMITSIZE control
X   the number of fully-specified (dd-mm-yy) and partially-specified
X   (dd-mm) holidays. */
X#define BASE 1990
X#define FOMITSIZE 150
X#define POMITSIZE 75
X
X/* Useful macros */
X
X#define upper(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c)-32) : (c) )
X#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
X#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
X#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
X#define TimeLess(h1, m1, h2, m2) (((h1) < (h2)) || (((h1) == (h2)) && ((m1) < (m2))))
X#define MAX(x, y) ((x) < (y) ? (y) : (x))
X#define MIN(x, y) ((x) < (y) ? (x) : (y))
X#ifndef ABS
X#define ABS(x) ((x) < 0 ? (-(x)) : (x))
X#endif
X
X/* Bit masks for constraint map */
X#define DAY_M 1
X#define MONTH_M 2
X#define YEAR_M 4
X#define WKDAY_M 8
X
Xenum Token_t { Unknown_t, Year_t, Month_t, Day_t, WkDay_t, Msg_t, Run_t,
X	       Omit_t, Banner_t, Rem_t, Delta_t, Back_t, Once_t, Include_t,
X               Repeat_t, At_t, Time_t, Skip_t, Until_t, Push_t, Pop_t,
X	       Clear_t, Eol_t };
X
X/* Define the Token structure */
X
Xtypedef struct {
X   char *str;
X   enum Token_t type;
X   int val;
X   char len;	/* Minimum length to match */
X} Token;
X
X#ifdef UNIX
X/* Define the structure of an AT entry */
Xtypedef struct AtEntry_t{
X   int time;      /* Time in minutes after midnight - 0 to 1439 */
X   int firsttime; /* Time of first triggering */
X   int repeat;    /* Repeat period */
X   int delta;     /* Delta time */
X   enum Token_t type;    /* Run_t or Msg_t */
X   char *text;
X   struct AtEntry_t *next;
X} AtEntry;
X#endif
X
SHAR_EOF
$TOUCH -am 0218130591 defines.h &&
chmod 0600 defines.h ||
echo "restore of defines.h failed"
set `wc -c defines.h`;Wc_c=$1
if test "$Wc_c" != "2313"; then
	echo original size 2313, current size $Wc_c
fi
fi
# ============= dorem.c ==============
if test X"$1" != X"-c" -a -f 'dorem.c'; then
	echo "File already exists: skipping 'dorem.c'"
else
echo "x - extracting dorem.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dorem.c &&
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}
SHAR_EOF
$TOUCH -am 0218130591 dorem.c &&
chmod 0600 dorem.c ||
echo "restore of dorem.c failed"
set `wc -c dorem.c`;Wc_c=$1
if test "$Wc_c" != "11579"; then
	echo original size 11579, current size $Wc_c
fi
fi
# ============= dosubst.c ==============
if test X"$1" != X"-c" -a -f 'dosubst.c'; then
	echo "File already exists: skipping 'dosubst.c'"
else
echo "x - extracting dosubst.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dosubst.c &&
X#include <ctype.h>
X#include <stdio.h>
X#include <string.h>
X#include "defines.h"
X#include "globals.h"
X#include "protos.h"
X
X/***************************************************************/
X/*                                                             */
X/*  DOSUBST.C                                                  */
X/*                                                             */
X/*  Performs line substitution for reminders.                  */
X/*                                                             */
X/*  If mode = 0, ignore %" escapes.                            */
X/*  If mode = 1, process %" escapes.  If a RUN type reminder   */
X/*     does not have %" escape, return the empty string.       */
X/*                                                             */
X/***************************************************************/
X
Xstatic char TODAY[] = "today";
Xstatic char TOMORROW[] = "tomorrow";
X
X#ifdef __STDC__
Xint DoSubst(char *src, char *dst, int d, int m, int y, int jul, enum Token_t t, int tim, int mode)
X#else
Xint DoSubst(src, dst, d, m, y, jul, t, tim, mode)
X     char *src;
X     char *dst;
X     int d;
X     int m;
X     int y;
X     int jul;
X     enum Token_t t;
X     int tim;
X     int mode;
X#endif
X{
X   int diff = jul - JulianToday;
X   char c;
X   char *od, *s;
X   int wkday = jul % 7;
X   char *plu, *pm;
X   int curtim = (int) (SystemTime() / 60);
X   int done;
X   int h;
X   int hh;
X   int min;
X   int tdiff;
X   int adiff, mdiff, hdiff;
X   char *mplu, *hplu, *when;
X   
X   if (mode == 1) {
X      s = src;
X      od = src;
X      while (*s) {
X         if (*s == '%' && *(s+1) == '\"') {
X	    src = s+2;
X	    break;
X	 }
X	 s++;
X      }
X      if (src == od && t == Run_t) {
X         *dst = 0;
X	 return 0;
X      }
X      if (*src == '%' && *(src+1) == '\"') {
X         *dst = 0;
X	 return 0;
X      }
X      if (tim != -1) {
X         sprintf(dst, "%02d:%02d ", (tim / 60), (tim % 60));
X	 dst += strlen(dst);
X      }
X   }
X       
X   if (tim == -1) tim = curtim;
X   tdiff = tim - curtim;
X   adiff = ABS(tdiff);
X   mdiff = adiff % 60;
X   hdiff = adiff / 60;
X   mplu = (mdiff == 1 ? "" : "s");
X   hplu = (hdiff == 1 ? "" : "s");
X   when = (tdiff < 0 ? "ago" : "from now");
X   
X   h = tim / 60;
X   min = tim % 60;
X
X   if (h >= 12) pm = "pm"; else pm = "am";
X   if (h == 12) hh = 12; else hh = h % 12;
X
X   *dst = 0;
X   
X   switch(d) {
X      case 1:
X      case 21:
X      case 31: plu = "st"; break;
X      
X      case 2:
X      case 22: plu = "nd"; break;
X      
X      case 3:
X      case 23: plu = "rd"; break;
X      
X      default: plu = "th"; break;
X   }
X      
X   
X   while (c = *src++) {
X     if (c == '\n') continue;
X     else if (c != '%') { *dst++ = c; *dst = 0; }
X     else {
X         od = dst;
X         c = *src++;
X	 done = 0;
X         if (diff <= 1) {
X            switch(upper(c)) {
X               case 'A':
X               case 'B':
X	       case 'C':
X	       case 'E':
X	       case 'F':
X	       case 'G':
X	       case 'H':
X	       case 'I':
X	       case 'J':
X	       case 'K':
X	       case 'L':
X	       case 'U':
X	       case 'V': sprintf(dst, "%s", (diff ? TOMORROW : TODAY));
X		         dst += strlen(dst);
X		         done = 1;
X 		         break;
X		     
X               default: done = 0;
X            }
X	 }	     
X     
X	 if (!done) switch(upper(c)) {
X	    case 0: *dst = 0; return 0;
X
X	    case '\"': if (mode == 1) {
X		          *dst = 0;
X			  return 0;
X		       }
X		       break;
X	    
X   	    case 'A':
X               sprintf(dst, "on %s, %d %s, %d", DayName[wkday], d,
X		              MonthName[m], y);
X               dst += strlen(dst);
X	       break;
X	       
X	    case 'B':
X               sprintf(dst, "in %d days' time", diff);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'C':
X               sprintf(dst, "on %s", DayName[wkday]);
X               dst += strlen(dst);
X	       break;
X	       
X	    case 'D':
X	       sprintf(dst, "%d", d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'E':
X	       sprintf(dst, "on %02d/%02d/%04d", d, m+1, y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'F':
X	       sprintf(dst, "on %02d/%02d/%04d", m+1, d, y);
X	       dst += strlen(dst);
X               break;
X
X	    case 'G':
X               sprintf(dst, "on %s, %d %s", DayName[wkday], d, MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'H':
X               sprintf(dst, "on %02d/%02d", d, m+1);
X	       dst += strlen(dst);
X               break;
X
X	    case 'I':
X               sprintf(dst, "on %02d/%02d", m+1, d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'J':
X               sprintf(dst, "on %s, %s %d%s, %d", DayName[wkday],
X		              MonthName[m], d, plu, y);
X               dst += strlen(dst);
X               break;
X	    
X	    case 'K':
X	       sprintf(dst, "on %s, %s %d%s", DayName[wkday],
X	                      MonthName[m], d, plu);
X	       dst += strlen(dst);
X               break;
X	       		      
X            case 'L':
X	       sprintf(dst, "on %04d/%02d/%02d", y, m+1, d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'M':
X	       sprintf(dst, "%s", MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'N':
X	       sprintf(dst, "%d", m+1);
X	       dst += strlen(dst);
X               break;
X
X	    case 'O':
X               if (RealToday == JulianToday) sprintf(dst, " (today)");
X               dst += strlen(dst);
X               break;
X	       
X	    case 'P':
X	       sprintf(dst, (diff == 1 ? "" : "s"));
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Q':
X	       sprintf(dst, (diff == 1 ? "'s" : "s'"));
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'R':
X	       sprintf(dst, "%02d", d);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'S':
X	       sprintf(dst, plu);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'T':
X	       sprintf(dst, "%02d", m+1);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'U':
X	       sprintf(dst, "on %s, %d%s %s, %d", DayName[wkday], d,
X	                      plu, MonthName[m], y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'V':
X	       sprintf(dst, "on %s, %d%s %s", DayName[wkday], d, plu,
X	                      MonthName[m]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'W':
X	       sprintf(dst, DayName[wkday]);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'X':
X	       sprintf(dst, "%d", diff);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Y':
X	       sprintf(dst, "%d", y);
X	       dst += strlen(dst);
X               break;
X	       
X	    case 'Z':
X	       sprintf(dst, "%d", y % 100);
X	       dst += strlen(dst);
X               break;
X
X	    case '1':
X               if (tdiff == 0) 
X                  sprintf(dst, "now");
X               else if (hdiff == 0) 
X	          sprintf(dst, "%d minute%s %s", mdiff, mplu, when);
X	       else if (mdiff == 0)
X	          sprintf(dst, "%d hour%s %s", hdiff, hplu, when);
X               else
X	          sprintf(dst, "%d hour%s and %d minute%s %s", hdiff, hplu, mdiff, mplu, when);
X	       dst += strlen(dst);
X               break;
X
X            case '2':
X               sprintf(dst, "at %d:%02d%s", hh, min, pm);
X	       dst += strlen(dst);
X	       break;
X
X	    case '3': sprintf(dst, "at %02d:%02d", h, min);
X	       dst += strlen(dst);
X	       break;
X
X	    case '4': sprintf(dst, "%d", tdiff);
X	       dst += strlen(dst);
X	       break;
X	       
X	    case '5': sprintf(dst, "%d", adiff);
X	       dst += strlen(dst);
X	       break;
X
X            case '6': sprintf(dst, when);
X	       dst += strlen(dst);
X	       break;
X
X	    case '7': sprintf(dst, "%d", hdiff);
X	       dst += strlen(dst);
X	       break;
X
X	    case '8': sprintf(dst, "%d", mdiff);
X	       dst += strlen(dst);
X	       break;
X
X	    case '9': sprintf(dst, mplu);
X	       dst += strlen(dst);
X	       break;
X
X	    case '0': sprintf(dst, hplu);
X	       dst += strlen(dst);
X	       break;
X
X            case '!': sprintf(dst, (tdiff >= 0 ? "is" : "was"));
X	       dst += strlen(dst);
X	       break;
X	    
X            case '_': *dst++ = '\n'; *dst = 0;
X	       break;
X
X            default:
X	       *dst++ = c;
X	       *dst = 0;
X	 }
X	 if (isupper(c)) *od = upper(*od);
X      }
X   }
X   if (t == Msg_t && mode == 0) *dst++ = '\n';
X   *dst = 0;
X   return 0;
X}   
SHAR_EOF
$TOUCH -am 0218130591 dosubst.c &&
chmod 0600 dosubst.c ||
echo "restore of dosubst.c failed"
set `wc -c dosubst.c`;Wc_c=$1
if test "$Wc_c" != "8427"; then
	echo original size 8427, current size $Wc_c
fi
fi
echo "End of part 1, continue with part 2"
exit 0



More information about the Alt.sources mailing list