[alt.sources] REMIND 2.2 01/05

dfs@doe.carleton.ca (David F. Skoll) (11/17/90)

This is REMIND version 2.2.  It has all the advanced date calculation
features of REMIND 2.1, as well as:

- The addition of a time field.

- The ability to run in the background and issue reminders at a specific
time.  You can be reminded in advance of the time, and have the reminder
repeatedly remind you with a specified interval.

- The addition of a "calendar" facility - REMIND will examine your reminder
file, and produce an annotated calendar for printout.

- The source code has been cleaned up so that REMIND compiles quietly
on an MS-DOS machine, and should work on SYSV machines with no modification.

Because so much code was modified, I'm posting the whole thing, rather than
patches.  So here goes...

--
David Skoll

---- CUT HERE ----
#!/bin/sh
# This is Remind-2.2, a shell archive (shar 3.32)
# made 11/16/1990 18:41 UTC by dfs@yar
# Source directory /enterprise/navigation/dfs/work/.rem/work
#
# existing files will NOT be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    991 -rw------- COPYRIGHT
#    577 -rw------- Makefile
#    934 -rw------- README.DOS
#   1522 -rw------- README.UNIX
#    417 -rw------- WHATSNEW.22
#   4759 -rw------- cache.c
#    782 -rw------- cache.h
#  13495 -rw------- calendar.c
#   2085 -rw------- defines.h
#   8966 -rw------- dorem.c
#   7683 -rw------- dosubst.c
#   8338 -rw------- files.c
#   1450 -rw------- globals.h
#   5675 -rw------- init.c
#  21719 -rw------- main.c
#   8637 -rw------- nextdate.c
#   1717 -rw------- protos.h
#   1568 -rwx------ remind-all.csh
#   1589 -rwx------ remind-all.sh
#  32451 -rw------- remind.1
#    847 -rw------- remind.mak
#   7436 -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 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 1116132790 COPYRIGHT &&
chmod 0600 COPYRIGHT ||
echo "restore of COPYRIGHT failed"
set `wc -c COPYRIGHT`;Wc_c=$1
if test "$Wc_c" != "991"; then
	echo original size 991, 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#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
Xall: dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o
X	$(LINK.c) -o remind dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o
X
Xdorem.o: dorem.c
X
Xfiles.o: files.c
X
Xmain.o:  main.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
SHAR_EOF
$TOUCH -am 1115153090 Makefile &&
chmod 0600 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "577"; then
	echo original size 577, 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.2 for MS-DOS
X
XFirst, read the files COPYRIGHT and WHATSNEW.22.
X
XREMIND was originally written for MS-DOS.  To compile it, you need
Xthe Microsoft C compiler (at least version 5.1) and the Microsoft
XMAKE utility.
X
XBefore compiling the software, check if it includes patches.  These
Xare files called patch.xx.  If there are patches, apply them all by typing
X
Xcat patch.* | patch
X
XTo compile the software, simply go to the source directory and type:
X
XMAKE REMIND.MAK
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@doe.carleton.ca>
X
SHAR_EOF
$TOUCH -am 1116132890 README.DOS &&
chmod 0600 README.DOS ||
echo "restore of README.DOS failed"
set `wc -c README.DOS`;Wc_c=$1
if test "$Wc_c" != "934"; then
	echo original size 934, 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.2 for UNIX
X
XFirst, read the files COPYRIGHT and WHATSNEW.22
X
XBefore compiling the software, check if it includes patches.  These
Xare files called patch.xx.  If there are patches, apply them all by typing
X
Xcat patch.* | patch
X
XThe Makefile is very simple and naive.  It is set up for a BSD system.
XIf you have a SYSV system, edit the Makefile.  Comment out the line
Xwhich reads:
X
X	CFLAGS= -O -DUNIX
X
Xand uncomment the line which reads:
X
X	CFLAGS= -O -DUNIX -DSYSV
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.
X
XREMIND has been compiled on Sun3s and Sun4s under Sun OS 4.0.  A previous
Xversion compiled successfully on a Xenix system.  REMIND should compile
Xon most systems, as it makes very few system calls.
X
XOnce remind has been compiled, install it in your favourite system directory.
XThe manual is in the file "remind.1".  You can install it in the appropriate
Xman page directory.  Remember to change the file suffix if you install it
Xin the "l" (local) or "n" (new) directory.
X
XTwo shell scripts, "remind-all.csh" and "remind-all.sh" are provided.  These
Xallow automatic mailing of reminders to all users who create a $HOME/.reminders
Xfile.  These two scripts are equivalent; one is a "sh" script and the other
Xis a "csh" script.  Pick the one you want to use, and follow the instructions
Xin the opening comments of the script.
X--
XDavid F. Skoll <dfs@doe.carleton.ca>
SHAR_EOF
$TOUCH -am 1116132890 README.UNIX &&
chmod 0600 README.UNIX ||
echo "restore of README.UNIX failed"
set `wc -c README.UNIX`;Wc_c=$1
if test "$Wc_c" != "1522"; then
	echo original size 1522, current size $Wc_c
fi
fi
# ============= WHATSNEW.22 ==============
if test X"$1" != X"-c" -a -f 'WHATSNEW.22'; then
	echo "File already exists: skipping 'WHATSNEW.22'"
else
echo "x - extracting WHATSNEW.22 (Text)"
sed 's/^X//' << 'SHAR_EOF' > WHATSNEW.22 &&
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.
SHAR_EOF
$TOUCH -am 1116132290 WHATSNEW.22 &&
chmod 0600 WHATSNEW.22 ||
echo "restore of WHATSNEW.22 failed"
set `wc -c WHATSNEW.22`;Wc_c=$1
if test "$Wc_c" != "417"; then
	echo original size 417, 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#include <malloc.h>
X#ifndef UNIX
X#include <string.h>
X#endif
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#ifndef UNIX
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#ifndef UNIX
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 == Rem_t) { /* Yup, this is a REM, so cache it */
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#ifndef UNIX
Xvoid ResetCache(void)
X#else
Xvoid ResetCache()
X#endif
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#ifndef UNIX
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}
SHAR_EOF
$TOUCH -am 1116133890 cache.c &&
chmod 0600 cache.c ||
echo "restore of cache.c failed"
set `wc -c cache.c`;Wc_c=$1
if test "$Wc_c" != "4759"; then
	echo original size 4759, 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#ifndef UNIX
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 1116093790 cache.h &&
chmod 0600 cache.h ||
echo "restore of cache.h failed"
set `wc -c cache.h`;Wc_c=$1
if test "$Wc_c" != "782"; then
	echo original size 782, 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#include <malloc.h>
X#include <ctype.h>
X#ifndef UNIX
X#include <string.h>
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#ifndef UNIX
XCalEntry *CreateCalEntry(void);
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#ifdef UNIX
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   while (d != 1) {
X      JulianToday--;
X      FromJulian(JulianToday, &d, &m, &y);
X   }
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}
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#ifndef UNIX
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#ifndef UNIX
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#ifndef UNIX
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#ifndef UNIX
Xvoid FinishCalendar(void)
X#else
Xvoid FinishCalendar()
X#endif
X{
X   if (SimpleCalendar) return;
X   putchar('\f');
X   putchar('\n');
X}
X
X/***************************************************************/
X/*                                                             */
X/* DoEntries                                                   */
X/* Create all the calendar entries for this week               */
X/*                                                             */
X/***************************************************************/
X#ifndef UNIX
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) if (e = CreateCalEntry()) 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#ifndef UNIX
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#ifndef UNIX
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#ifndef UNIX
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/***************************************************************/
X#ifndef UNIX
XCalEntry *CreateCalEntry(void)
X#else
XCalEntry *CreateCalEntry()
X#endif
X{
X   CalEntry *e;
X   char *s, *t;
X   int column, l;
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   /* Process the text:  First, look for %" marks.  Then, copy the time
X      and delete any newlines. */
X   s = WorkBuf;
X   t = WorkBuf;
X
X   while (*s) {
X      if (*s == '%' && *(s+1) == '\"') {
X         t = s+2;
X         break;
X      }
X      s++;
X   }
X
X   /* If we found one, look for another */
X   if (t != s) {
X      s = t;
X      while (*s) {
X         if (*s == '%' && *(s+1) == '\"') {
X            *s = 0;
X            break;
X         }
X         s++;
X      }
X   }
X
X   /* Use temporary buffer to create the text */
X   *TmpBuf = 0;
X
X   /* Copy over the text */
X   if(CalTime != -1) sprintf(TmpBuf, "%02d:%02d ", CalTime / 60, CalTime % 60);
X   s = TmpBuf + strlen(TmpBuf);
X   strcpy(s, t);
X   
X   /* If the buffer contains zero-length string; forget it. */
X   if (!*s) {
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#ifndef UNIX
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 1116095790 calendar.c &&
chmod 0600 calendar.c ||
echo "restore of calendar.c failed"
set `wc -c calendar.c`;Wc_c=$1
if test "$Wc_c" != "13495"; then
	echo original size 13495, 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 100
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
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, Eol_t };
X			   
X/* Define the Token structure */
X
Xtypedef struct {
X   char *str;
X   enum Token_t type;
X   int val;
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 1115094190 defines.h &&
chmod 0600 defines.h ||
echo "restore of defines.h failed"
set `wc -c defines.h`;Wc_c=$1
if test "$Wc_c" != "2085"; then
	echo original size 2085, current size $Wc_c
fi
fi
echo "End of part 1, continue with part 2"
exit 0