home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2786 < prev    next >
Encoding:
Internet Message Format  |  1991-02-20  |  55.9 KB

  1. From: dfs@doe.carleton.ca (David F. Skoll)
  2. Newsgroups: alt.sources
  3. Subject: REMIND 2.3.0 1/4
  4. Message-ID: <dfs.666900962@data>
  5. Date: 18 Feb 91 18:16:02 GMT
  6.  
  7. Here is the next version of REMIND.  There have been many changes; I'm
  8. reposting the source rather that distributing patches.  Here's the
  9. synopsis of whats new:
  10.  
  11. Version 2.3 - Added the UNTIL keyword for forcing reminders to expire.
  12.  
  13. Added the "++" form of 'back' and the "--" form of 'delta' for
  14. ignoring OMIT information.
  15.  
  16. Added the CLEAR-OMIT-CONTEXT, PUSH-OMIT-CONTEXT and POP-OMIT-CONTEXT
  17. keywords for isolating personal or peculiar reminders from the global
  18. OMIT context.
  19.  
  20. Speeded up the parsing of tokens.
  21.  
  22. Changed the source to recognize and exploit ANSI-C compilers which
  23. accept function prototypes.
  24.  
  25. Added the "-n" option to output the next occurrence of each reminder
  26. in SimpleCalendar format
  27.  
  28. Modified the calendar and SimpleCalendar formats so that the % escape
  29. substitutions ARE performed.
  30.  
  31. Remind source code can also be obtained via FTP from alfred.ccs.carleton.ca
  32. (134.117.1.1) in pub/remind-2.3.0.tar.Z.
  33.  
  34. --
  35. David F. Skoll
  36.  
  37. #!/bin/sh
  38. # This is Remind 2.3.0, a shell archive (shar 3.32)
  39. # made 02/18/1991 18:12 UTC by dfs@data
  40. # Source directory /enterprise/transporter/dfs/work/.rem/work
  41. #
  42. # existing files will NOT be overwritten
  43. #
  44. # This shar contains:
  45. # length  mode       name
  46. # ------ ---------- ------------------------------------------
  47. #    997 -rw------- COPYRIGHT
  48. #   1339 -rw------- Makefile
  49. #   1206 -rw------- README.DOS
  50. #   2180 -rw------- README.UNIX
  51. #   1388 -rw------- WHATSNEW.23
  52. #   4966 -rw------- cache.c
  53. #    785 -rw------- cache.h
  54. #  13183 -rw------- calendar.c
  55. #   2313 -rw------- defines.h
  56. #  11579 -rw------- dorem.c
  57. #   8427 -rw------- dosubst.c
  58. #   8388 -rw------- files.c
  59. #   1469 -rw------- globals.h
  60. #   6305 -rw------- init.c
  61. #    852 -rwx------ kall
  62. #  20411 -rw------- main.c
  63. #   8719 -rw------- nextdate.c
  64. #  10630 -rw------- omits.c
  65. #   2210 -rw------- protos.h
  66. #   1568 -rw------- remind-all.csh
  67. #   1589 -rw------- remind-all.sh
  68. #  40229 -rw------- remind.1
  69. #    940 -rw------- remind.mak
  70. #   2975 -rw------- test.rem
  71. #   7484 -rw------- timed.c
  72. #
  73. if touch 2>&1 | fgrep 'amc' > /dev/null
  74.  then TOUCH=touch
  75.  else TOUCH=true
  76. fi
  77. # ============= COPYRIGHT ==============
  78. if test X"$1" != X"-c" -a -f 'COPYRIGHT'; then
  79.     echo "File already exists: skipping 'COPYRIGHT'"
  80. else
  81. echo "x - extracting COPYRIGHT (Text)"
  82. sed 's/^X//' << 'SHAR_EOF' > COPYRIGHT &&
  83. XTHE REMIND COPYRIGHT
  84. X
  85. XREMIND refers to the entire set of files and documentation in the
  86. XREMIND package.
  87. X
  88. XREMIND is Copyright (C) 1990, 1991 by David Skoll, except for the file
  89. Xremind-all.sh, which is Copyright (C) 1990 by Bill Aten.
  90. X
  91. XYou may use REMIND for free, and may freely distribute it, providing
  92. Xyou do not charge the recipients to whom you distribute REMIND.
  93. X
  94. XYou may modify REMIND.  However, you must clearly indicate such
  95. Xmodifications when you distribute REMIND, and must tell the
  96. Xrecipients of the modified version that it is modified.  Place that
  97. Xnotice in the WHATSNEW.xx file.
  98. X
  99. XYou may incorporate parts of REMIND into your own programs, providing
  100. Xyou do not sell these programs.  You must clearly indicate that the parts
  101. Xof REMIND you have incorporated are Copyright (C) 1990 by David Skoll.
  102. X
  103. XI will attempt to support REMIND as much as possible.  However, you use
  104. Xit at your own risk.  I am not responsible for any damages caused by
  105. Xthe use or misuse of REMIND.
  106. X--
  107. XDavid F. Skoll
  108. SHAR_EOF
  109. $TOUCH -am 0218130591 COPYRIGHT &&
  110. chmod 0600 COPYRIGHT ||
  111. echo "restore of COPYRIGHT failed"
  112. set `wc -c COPYRIGHT`;Wc_c=$1
  113. if test "$Wc_c" != "997"; then
  114.     echo original size 997, current size $Wc_c
  115. fi
  116. fi
  117. # ============= Makefile ==============
  118. if test X"$1" != X"-c" -a -f 'Makefile'; then
  119.     echo "File already exists: skipping 'Makefile'"
  120. else
  121. echo "x - extracting Makefile (Text)"
  122. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  123. X# Makefile for REMIND - simple file
  124. X
  125. X#--------------- BEGINNING OF THINGS YOU CAN CHANGE --------------
  126. X
  127. X#If you have a BSD system:
  128. XCFLAGS= -O -DUNIX
  129. X
  130. X#If you have a SYSV system, comment previous line and uncomment next line:
  131. X#CFLAGS= -O -DUNIX -DSYSV
  132. X
  133. X#If your system does not include <malloc.h>, uncomment next line:
  134. X#CFLAGS += -DNO_MALLOC_H
  135. X
  136. X#If you have a SYSV system which does not implement the pid_t type,
  137. X#uncomment the next line:
  138. X#CFLAGS += -Dpid_t=int
  139. X
  140. X#If you want to use gcc:
  141. X#CC= gcc
  142. X
  143. X#Where do you want it installed?
  144. XBINDIR= /usr/local/bin
  145. XKALLDIR= /usr/share/bin
  146. XMANDIR= /usr/share/man
  147. XMANSECTION= 1
  148. X
  149. X#What program does the installation?
  150. XINSTALL= install
  151. X#INSTALL= cp
  152. X
  153. X#--------------- SHOULDN'T CHANGE STUFF BELOW HERE ---------------
  154. X
  155. Xall: dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o omits.o
  156. X    $(CC) -o remind dorem.o files.o main.o nextdate.o init.o dosubst.o timed.o calendar.o cache.o omits.o
  157. X
  158. Xdorem.o: dorem.c
  159. X
  160. Xfiles.o: files.c
  161. X
  162. Xmain.o:  main.c
  163. X
  164. Xomits.o: omits.c
  165. X
  166. Xnextdate.o: nextdate.c
  167. X
  168. Xinit.o: init.c
  169. X
  170. Xdosubst.o: dosubst.c
  171. X
  172. Xtimed.o: timed.c
  173. X
  174. Xcalendar.o: calendar.c
  175. X
  176. Xcache.o: cache.c
  177. X
  178. Xclean:
  179. X    rm -f *.o core *~ remind
  180. X
  181. Xinstall:
  182. X    $(INSTALL) remind $(BINDIR)
  183. X
  184. Xinstall.man:
  185. X    $(INSTALL) remind.1 $(MANDIR)/man$(MANSECTION)/remind.$(MANSECTION)
  186. X
  187. Xinstall.kall:
  188. X    $(INSTALL) kall $(KALLDIR)
  189. X
  190. SHAR_EOF
  191. $TOUCH -am 0218130591 Makefile &&
  192. chmod 0600 Makefile ||
  193. echo "restore of Makefile failed"
  194. set `wc -c Makefile`;Wc_c=$1
  195. if test "$Wc_c" != "1339"; then
  196.     echo original size 1339, current size $Wc_c
  197. fi
  198. fi
  199. # ============= README.DOS ==============
  200. if test X"$1" != X"-c" -a -f 'README.DOS'; then
  201.     echo "File already exists: skipping 'README.DOS'"
  202. else
  203. echo "x - extracting README.DOS (Text)"
  204. sed 's/^X//' << 'SHAR_EOF' > README.DOS &&
  205. XREMIND 2.3 for MS-DOS
  206. X
  207. XFirst, read the files COPYRIGHT and WHATSNEW.23.
  208. X
  209. XREMIND was originally written for MS-DOS.  To compile it, you need the
  210. XMicrosoft C compiler (at least version 5.1) and the Microsoft MAKE
  211. Xutility.
  212. X
  213. XBefore compiling the software, check if it includes patches.  These are
  214. Xfiles called patch.xx.  If there are patches, apply them all by typing
  215. X
  216. Xcat patch.* | patch
  217. X
  218. Xon a Unix machine.  Then copy the software to your MS-DOS machine.
  219. X
  220. XTo compile the software, simply go to the source directory and type:
  221. X
  222. XMAKE REMIND.MAK
  223. X
  224. XThe file test.rem contains test reminders for verifying that REMIND's
  225. Xdate calculation routines are working correctly.  The file test.out
  226. Xcontains the result of running:  remind -dv test.rem 16 feb 1991
  227. X
  228. XNote that the MS-DOS version of REMIND operates slightly differently from
  229. Xthe UNIX version:  MS-DOS has no concept of file access date.  Thus, to
  230. Ximplement the "ONCE" keyword, REMIND will change the modification date
  231. Xof the top-level reminder file after it has run.  This is equivalent to
  232. Xperforming a "touch" of the file after running REMIND.
  233. X
  234. XAlso, the MS-DOS version does not queue AT reminders for timed activation.
  235. X--
  236. XDavid F. Skoll <dfs@doe.carleton.ca>
  237. X
  238. SHAR_EOF
  239. $TOUCH -am 0218130591 README.DOS &&
  240. chmod 0600 README.DOS ||
  241. echo "restore of README.DOS failed"
  242. set `wc -c README.DOS`;Wc_c=$1
  243. if test "$Wc_c" != "1206"; then
  244.     echo original size 1206, current size $Wc_c
  245. fi
  246. fi
  247. # ============= README.UNIX ==============
  248. if test X"$1" != X"-c" -a -f 'README.UNIX'; then
  249.     echo "File already exists: skipping 'README.UNIX'"
  250. else
  251. echo "x - extracting README.UNIX (Text)"
  252. sed 's/^X//' << 'SHAR_EOF' > README.UNIX &&
  253. XREMIND version 2.3 for UNIX
  254. X
  255. XFirst, read the files COPYRIGHT and WHATSNEW.23
  256. X
  257. XBefore compiling the software, check if it includes patches.  These
  258. Xare files called patch.xx.  If there are patches, apply them all by
  259. Xtyping
  260. X
  261. Xcat patch.* | patch
  262. X
  263. XNext, examine the Makefile and change any parameters which need to be
  264. Xchanged for your system.  As it stands, the Makefile is set up for a
  265. XBSD system.
  266. X
  267. XTo compile REMIND, just go to the source directory and type "make".
  268. XThis creates the executable file "remind".  You can type "make CC=gcc"
  269. Xif you want to use the Gnu C Compiler, or you can edit the Makefile to
  270. Xmake gcc the default.
  271. X
  272. XThe file test.rem contains test reminders for verifying that REMIND's
  273. Xdate calculation routines are working correctly.  The file test.out
  274. Xcontains the result of running: remind -dv test.rem 16 feb 1991
  275. X
  276. XREMIND has been compiled on Sun3s and Sun4s under Sun OS 4.0, on an
  277. XIBM PC under MS-DOS and on a 386 Xenix system to name a few.  REMIND
  278. Xshould compile on most systems without difficulty.
  279. X
  280. XOnce remind has been compiled, install it in your favourite system
  281. Xdirectory.  Type "make install" to install the executable, and "make
  282. Xinstall.man" to install the manpage.  If you want to install the "kall"
  283. Xscript, type "make install.kall"
  284. X
  285. XTwo shell scripts, "remind-all.csh" and "remind-all.sh" are provided.
  286. XThese allow automatic mailing of reminders to all users who create a
  287. X$HOME/.reminders file.  These two scripts are equivalent; one is a
  288. X"sh" script and the other is a "csh" script.  Pick the one you want to
  289. Xuse, and follow the instructions in the opening comments of the
  290. Xscript.
  291. X
  292. XA shell script called "kall" is provided which kills processes
  293. Xspecified by command name rather than process ID.  You may have to
  294. Xedit it to work on your system, since the output of "ps" is not
  295. Xportable.  You can use this script to kill all background remind
  296. Xprocesses in your .logout script by using "kall remind" Note that this
  297. Xversion of "kall" is different from the version of kall distributed
  298. Xwith 2.2 - the new version requires an exact match of command name,
  299. Xnot just a command name which contains the specified
  300. Xstring.
  301. X
  302. X--
  303. XDavid F. Skoll <dfs@doe.carleton.ca>
  304. SHAR_EOF
  305. $TOUCH -am 0218130591 README.UNIX &&
  306. chmod 0600 README.UNIX ||
  307. echo "restore of README.UNIX failed"
  308. set `wc -c README.UNIX`;Wc_c=$1
  309. if test "$Wc_c" != "2180"; then
  310.     echo original size 2180, current size $Wc_c
  311. fi
  312. fi
  313. # ============= WHATSNEW.23 ==============
  314. if test X"$1" != X"-c" -a -f 'WHATSNEW.23'; then
  315.     echo "File already exists: skipping 'WHATSNEW.23'"
  316. else
  317. echo "x - extracting WHATSNEW.23 (Text)"
  318. sed 's/^X//' << 'SHAR_EOF' > WHATSNEW.23 &&
  319. XA BRIEF HISTORY OF REMIND:
  320. X
  321. XVersion 1.0 - never publicly released.
  322. X
  323. XVersion 2.0 - first public release.  Included advanced date specifications,
  324. Xcharacter substitution, and the RUN keyword.
  325. X
  326. XVersion 2.1 - Added the "repeat" token for repeating reminders with a period
  327. Xother than 7 days.  Also fixed some bugs from version 2.0
  328. X
  329. XVersion 2.2 - Added the AT keyword, the timed reminders daemon, and the
  330. Xcalendar facility.
  331. X
  332. XVersion 2.2 - Patch 3  - Added the MSG or RUN tokens in an OMIT command; also
  333. Xallowed RUN-type reminders to be explicitly included in the calendar by
  334. Xusing the %" escape sequence.
  335. X
  336. XVersion 2.2 - Patch 5 - Added the BEFORE, AFTER and SKIP tokens to make the
  337. Xhandling of holidays more sensible.  Also corrected a few more bugs.
  338. X
  339. XVersion 2.3 - Added the UNTIL keyword for forcing reminders to expire.
  340. X
  341. XAdded the "++" form of 'back' and the "--" form of 'delta' for
  342. Xignoring OMIT information.
  343. X
  344. XAdded the CLEAR-OMIT-CONTEXT, PUSH-OMIT-CONTEXT and POP-OMIT-CONTEXT
  345. Xkeywords for isolating personal or peculiar reminders from the global
  346. XOMIT context.
  347. X
  348. XSpeeded up the parsing of tokens.
  349. X
  350. XChanged the source to recognize and exploit ANSI-C compilers which
  351. Xaccept function prototypes.
  352. X
  353. XAdded the "-n" option to output the next occurrence of each reminder
  354. Xin SimpleCalendar format
  355. X
  356. XModified the calendar and SimpleCalendar formats so that the % escape
  357. Xsubstitutions ARE performed.
  358. X
  359. SHAR_EOF
  360. $TOUCH -am 0218130591 WHATSNEW.23 &&
  361. chmod 0600 WHATSNEW.23 ||
  362. echo "restore of WHATSNEW.23 failed"
  363. set `wc -c WHATSNEW.23`;Wc_c=$1
  364. if test "$Wc_c" != "1388"; then
  365.     echo original size 1388, current size $Wc_c
  366. fi
  367. fi
  368. # ============= cache.c ==============
  369. if test X"$1" != X"-c" -a -f 'cache.c'; then
  370.     echo "File already exists: skipping 'cache.c'"
  371. else
  372. echo "x - extracting cache.c (Text)"
  373. sed 's/^X//' << 'SHAR_EOF' > cache.c &&
  374. X/***************************************************************/
  375. X/*                                                             */
  376. X/* CACHE.C                                                     */
  377. X/*                                                             */
  378. X/* Contains routines for caching reminder file to improve      */
  379. X/* calendar performance.                                       */
  380. X/*                                                             */
  381. X/* By David Skoll - 15 November 1990                           */
  382. X/***************************************************************/
  383. X
  384. X#include <stdio.h>
  385. X#ifndef NO_MALLOC_H
  386. X#include <malloc.h>
  387. X#endif
  388. X#include <string.h>
  389. X#include "defines.h"
  390. X#include "globals.h"
  391. X#include "protos.h"
  392. X#include "cache.h"
  393. X
  394. X/* Define a cached line */
  395. Xtypedef struct cached_line {
  396. X   char *text;
  397. X   struct cached_line *next;
  398. X} Centry;
  399. X
  400. XCentry Cache, *Current;
  401. X
  402. Xstatic int CacheDone, CacheFailed;
  403. X
  404. X/***************************************************************/
  405. X/*                                                             */
  406. X/*  InitCache                                                  */
  407. X/*                                                             */
  408. X/*  Initializes the caching system.                            */
  409. X/*                                                             */
  410. X/***************************************************************/
  411. X#ifdef __STDC__
  412. Xvoid InitCache(void)
  413. X#else
  414. Xvoid InitCache()
  415. X#endif
  416. X{
  417. X   CacheDone   = 0;
  418. X   CacheFailed = 0;
  419. X   Cache.next  = NULL;
  420. X   Current     = &Cache;
  421. X}
  422. X
  423. X/***************************************************************/
  424. X/*                                                             */
  425. X/* GetLine                                                     */
  426. X/*                                                             */
  427. X/* This function either reads a line from the file, or gets    */
  428. X/* it from memory if it is cached.                             */
  429. X/*                                                             */
  430. X/* Returns 0 if more data to be read; otherwise, non-zero.     */
  431. X/*                                                             */
  432. X/*                                                             */
  433. X/***************************************************************/
  434. X#ifdef __STDC__
  435. Xint GetLine(void)
  436. X#else
  437. Xint GetLine()
  438. X#endif
  439. X{
  440. X   int ret;
  441. X   Token tok;
  442. X   char *s;
  443. X   Centry *c;
  444. X
  445. X   if (CacheFailed) return ReadLine();
  446. X
  447. X   if (!CacheDone) {
  448. X      ret = ReadLine();
  449. X      if (ret) {
  450. X         CacheDone = 1;
  451. X         strcpy(FileName, "* cache *");
  452. X     CurLine = 0;
  453. X         return ret;
  454. X      }
  455. X      /* Check if we should cache this line */
  456. X
  457. X      s = Line;
  458. X      tok = ParseToken(&s);
  459. X      if (tok.type == Clear_t || tok.type == Push_t ||
  460. X          tok.type == Pop_t || tok.type == Rem_t || tok.type == Omit_t) { 
  461. X         c = (Centry *) malloc(sizeof(Centry));
  462. X         if (c == NULL) {
  463. X            CacheFailed = 1;
  464. X            DestroyCache();
  465. X            return 0;
  466. X         }
  467. X         c->text = (char *) malloc(strlen(Line)+1);
  468. X         if (c->text == NULL) {
  469. X            CacheFailed = 1;
  470. X        DestroyCache();
  471. X            free(c);
  472. X        return 0;
  473. X         }
  474. X         /* Insert the cache entry */
  475. X         c->next = NULL;
  476. X         strcpy(c->text, Line);
  477. X         Current->next = c;
  478. X         Current = c;
  479. X      }
  480. X      return ret;
  481. X   } else { /* Over here, we've finished caching, so just return the line */
  482. X      if (Current == NULL) return 1;
  483. X      else {
  484. X         strcpy(Line, Current->text);
  485. X         Current = Current->next;
  486. X         return 0;
  487. X      }
  488. X   }
  489. X}
  490. X/***************************************************************/
  491. X/*                                                             */
  492. X/* ResetCache                                                  */
  493. X/* Reset the cache to beginning, or reopen file if caching     */
  494. X/* failed.                                                     */
  495. X/*                                                             */
  496. X/***************************************************************/
  497. X#ifdef __STDC__
  498. Xvoid ResetCache(void)
  499. X#else
  500. Xvoid ResetCache()
  501. X#endif
  502. X{
  503. X   /* Reset the OMIT context */
  504. X   ClearOmitContext();
  505. X
  506. X   /* Get rid of any spurious stacked OMIT contexts */
  507. X   FreeStackedOmits();
  508. X
  509. X   if (CacheFailed) OpenFile(FileName);
  510. X   else Current = Cache.next;
  511. X}
  512. X
  513. X/***************************************************************/
  514. X/*                                                             */
  515. X/* DestroyCache                                                */
  516. X/* Frees all memory used by the cache.                         */
  517. X/*                                                             */
  518. X/***************************************************************/
  519. X#ifdef __STDC__
  520. Xvoid DestroyCache(void)
  521. X#else
  522. Xvoid DestroyCache()
  523. X#endif
  524. X{
  525. X   Centry *p = &Cache;
  526. X   Centry *c = p->next;
  527. X
  528. X   while (c) {
  529. X      if (c->text) free(c->text);
  530. X      p = c;
  531. X      c = c->next;
  532. X      free(p);
  533. X   }
  534. X   Cache.next = NULL;
  535. X}
  536. X
  537. SHAR_EOF
  538. $TOUCH -am 0218130591 cache.c &&
  539. chmod 0600 cache.c ||
  540. echo "restore of cache.c failed"
  541. set `wc -c cache.c`;Wc_c=$1
  542. if test "$Wc_c" != "4966"; then
  543.     echo original size 4966, current size $Wc_c
  544. fi
  545. fi
  546. # ============= cache.h ==============
  547. if test X"$1" != X"-c" -a -f 'cache.h'; then
  548.     echo "File already exists: skipping 'cache.h'"
  549. else
  550. echo "x - extracting cache.h (Text)"
  551. sed 's/^X//' << 'SHAR_EOF' > cache.h &&
  552. X/***************************************************************/
  553. X/*                                                             */
  554. X/*  CACHE.H                                                    */
  555. X/*                                                             */
  556. X/*  Function prototypes, etc. for CACHE.C                      */
  557. X/*                                                             */
  558. X/*  By David Skoll - 15 November 1990                          */
  559. X/*                                                             */
  560. X/***************************************************************/
  561. X#ifdef __STDC__
  562. Xvoid InitCache(void);
  563. Xint GetLine(void);
  564. Xvoid ResetCache(void);
  565. Xvoid DestroyCache(void);
  566. X#else
  567. Xvoid InitCache();
  568. Xint GetLine();
  569. Xvoid ResetCache();
  570. Xvoid DestroyCache();
  571. X#endif
  572. SHAR_EOF
  573. $TOUCH -am 0218130591 cache.h &&
  574. chmod 0600 cache.h ||
  575. echo "restore of cache.h failed"
  576. set `wc -c cache.h`;Wc_c=$1
  577. if test "$Wc_c" != "785"; then
  578.     echo original size 785, current size $Wc_c
  579. fi
  580. fi
  581. # ============= calendar.c ==============
  582. if test X"$1" != X"-c" -a -f 'calendar.c'; then
  583.     echo "File already exists: skipping 'calendar.c'"
  584. else
  585. echo "x - extracting calendar.c (Text)"
  586. sed 's/^X//' << 'SHAR_EOF' > calendar.c &&
  587. X/***************************************************************/
  588. X/*                                                             */
  589. X/* CALENDAR.C                                                  */
  590. X/*                                                             */
  591. X/* Contains routines and data structures for producing a       */
  592. X/* calendar from a reminder file.                              */
  593. X/*                                                             */
  594. X/* By David Skoll - 14 November 1990                           */
  595. X/*                                                             */
  596. X/***************************************************************/
  597. X#include <stdio.h>
  598. X#ifndef NO_MALLOC_H
  599. X#include <malloc.h>
  600. X#endif
  601. X#include <ctype.h>
  602. X#include <string.h>
  603. X#ifndef UNIX
  604. X#include <stdlib.h>
  605. X#endif
  606. X#include "defines.h"
  607. X#include "globals.h"
  608. X#include "protos.h"
  609. X#include "cache.h"
  610. X
  611. X/* Convert (monday-sunday) sequence to (sunday-saturday) */
  612. X#define DayOfWeek(julian) ((((julian) % 7) + 1) % 7)
  613. X
  614. X/* To center an item of length l in a field of length f, how many spaces? */
  615. X#define PreCenter(f, l) (((f)-(l))/2)
  616. X
  617. X/* How many spaces AFTEr the centered item? */
  618. X#define PostCenter(f, l) ((f)-(l)-((f)-(l))/2)
  619. X
  620. X/* Define the structure of a calendar entry */
  621. Xtypedef struct CalEntry_t {
  622. X   int tim;
  623. X   char *text, *current;
  624. X   struct CalEntry_t *next;
  625. X} CalEntry;
  626. X
  627. X/* Have a main calendar entry for each weekday */
  628. XCalEntry entry[7];
  629. Xint used[7];  /* These hold the day of the month for corresponding
  630. X                 entry - 0 if not used */
  631. X
  632. X/* Static integers for various stuff */
  633. Xstatic int TotalWidth;
  634. X
  635. X/* Make function prototypes local - they're not used anywhere else */
  636. X#ifdef __STDC__
  637. XCalEntry *CreateCalEntry(int type);
  638. Xvoid AddCalEntry(CalEntry *e);
  639. Xvoid EmitOneCalendarLine(void);
  640. Xvoid InitCalendar(int m, int y);
  641. Xvoid FinishCalendar(void);
  642. Xvoid DoEntries(void);
  643. X#else
  644. XCalEntry *CreateCalEntry();
  645. Xvoid AddCalEntry();
  646. Xvoid EmitOneCalendarLine();
  647. Xvoid InitCalendar();
  648. Xvoid FinishCalendar();
  649. Xvoid DoEntries();
  650. X#endif
  651. X
  652. X/***************************************************************/
  653. X/*                                                             */
  654. X/* DoCalendar - main loop for the calendar command.            */
  655. X/*                                                             */
  656. X/***************************************************************/
  657. X#ifndef __STDC__
  658. Xvoid DoCalendar()
  659. X#else
  660. Xvoid DoCalendar(void)
  661. X#endif
  662. X{
  663. X   int y, m, d, init;
  664. X
  665. X   TotalWidth = 7*CalWidth + 8;
  666. X
  667. X   /* Move back until beginning of month */
  668. X   FromJulian(JulianToday, &d, &m, &y);
  669. X   JulianToday -= (d-1);
  670. X
  671. X   init = 0;
  672. X   InitCache();
  673. X   while (Calendar) {
  674. X      FromJulian(JulianToday, &d, &m, &y);
  675. X      CurDay = d;
  676. X      CurMon = m;
  677. X      CurYear = y;
  678. X      if (init == 0 || CurDay == 1) { InitCalendar(m, y); init = 1; }
  679. X      DoEntries();
  680. X      if (d == DaysInMonth(m, y)) Calendar--;
  681. X      JulianToday++;
  682. X      if (Calendar) ResetCache();
  683. X   }
  684. X   if (CurDay != DaysInMonth(CurMon, CurYear)) FinishCalendar();
  685. X   DestroyCache();
  686. X   FreeStackedOmits();
  687. X}
  688. X
  689. X/***************************************************************/
  690. X/*                                                             */
  691. X/* PrintChars:  Print n of the specified character             */
  692. X/* CopyChars:  Copy n of the character to the output buffer    */
  693. X/*                                                             */
  694. X/***************************************************************/
  695. X#ifdef __STDC__
  696. Xvoid PrintChars(int n, int c)
  697. X#else
  698. Xvoid PrintChars(n, c)
  699. Xint n, c;
  700. X#endif
  701. X{
  702. X   while(n--) putchar(c);
  703. X}
  704. X
  705. X#ifdef __STDC__
  706. Xchar *CopyChars(int n, int c, char *dst)
  707. X#else
  708. Xchar *CopyChars(n, c, dst)
  709. Xint n, c;
  710. Xchar *dst;
  711. X#endif
  712. X{
  713. X   while(n--) *dst++ = (char) c;
  714. X   return dst;
  715. X}
  716. X
  717. X/***************************************************************/
  718. X/*                                                             */
  719. X/* InitCalendar                                                */
  720. X/* Print the calendar header                                   */
  721. X/*                                                             */
  722. X/***************************************************************/
  723. X#ifdef __STDC__
  724. Xvoid InitCalendar(int m, int y)
  725. X#else
  726. Xvoid InitCalendar(m, y)
  727. Xint y, m;
  728. X#endif
  729. X{
  730. X   int i;
  731. X
  732. X   if (SimpleCalendar) return;
  733. X
  734. X   for (i=0; i<7; i++) {
  735. X      entry[i].next = NULL;
  736. X      used[i] = 0;
  737. X   }
  738. X
  739. X   /* Emit the calendar title */
  740. X   putchar('+');
  741. X   PrintChars(TotalWidth-2, '-');
  742. X   putchar('+');
  743. X   putchar('\n');
  744. X   sprintf(TmpBuf, "%s %d", MonthName[m], y);
  745. X   putchar('|');
  746. X   PrintChars(PreCenter(TotalWidth-2, strlen(TmpBuf)), ' ');
  747. X   printf("%s", TmpBuf);
  748. X   PrintChars(PostCenter(TotalWidth-2, strlen(TmpBuf)), ' ');
  749. X   putchar('|');
  750. X   putchar('\n');
  751. X   putchar('+');
  752. X   for (i=0; i<7; i++) {
  753. X      PrintChars(CalWidth, '-');
  754. X      putchar('+');
  755. X   }
  756. X   putchar('\n');
  757. X
  758. X   /* Put the weekdays in */
  759. X   /* Argh! Do sunday first, then take care of rest */
  760. X   i = 6;
  761. X   putchar('|');
  762. X   PrintChars(PreCenter(CalWidth, strlen(DayName[i])), ' ');
  763. X   printf(DayName[i]);
  764. X   PrintChars(PostCenter(CalWidth, strlen(DayName[i])), ' ');
  765. X
  766. X   for (i=0; i<6; i++) {
  767. X      putchar('|');
  768. X      PrintChars(PreCenter(CalWidth, strlen(DayName[i])), ' ');
  769. X      printf(DayName[i]);
  770. X      PrintChars(PostCenter(CalWidth, strlen(DayName[i])), ' ');
  771. X   }
  772. X   putchar('|');
  773. X   putchar('\n');
  774. X   putchar('+');
  775. X   for (i=0; i<7; i++) {
  776. X      PrintChars(CalWidth, '-');
  777. X      putchar('+');
  778. X   }
  779. X   putchar('\n');
  780. X}
  781. X
  782. X/***************************************************************/
  783. X/*                                                             */
  784. X/* FinishCalendar                                              */
  785. X/* Just print a form feed.                                     */
  786. X/*                                                             */
  787. X/***************************************************************/
  788. X#ifdef __STDC__
  789. Xvoid FinishCalendar(void)
  790. X#else
  791. Xvoid FinishCalendar()
  792. X#endif
  793. X{
  794. X   if (SimpleCalendar) return;
  795. X   putchar('\f');
  796. X}
  797. X
  798. X/***************************************************************/
  799. X/*                                                             */
  800. X/* DoEntries                                                   */
  801. X/* Create all the calendar entries for this week               */
  802. X/*                                                             */
  803. X/***************************************************************/
  804. X#ifdef __STDC__
  805. Xvoid DoEntries(void)
  806. X#else
  807. Xvoid DoEntries()
  808. X#endif
  809. X{
  810. X   int i;
  811. X   CalEntry *e;
  812. X
  813. X   while (1) {
  814. X      used[DayOfWeek(JulianToday)] = CurDay;
  815. X      if (GetLine()) break;
  816. X      i = ProcessLine();
  817. X      if (i>0) if (e = CreateCalEntry(i)) AddCalEntry(e);
  818. X   }
  819. X
  820. X   /* Now figure out if we should print the calendar */
  821. X   if ((DayOfWeek(JulianToday) == 6 ) || CurDay == DaysInMonth(CurMon, CurYear))
  822. X      EmitOneCalendarLine();
  823. X   if (CurDay == DaysInMonth(CurMon, CurYear)) FinishCalendar();
  824. X}
  825. X
  826. X/***************************************************************/
  827. X/*                                                             */
  828. X/* AddCalEntry                                                 */
  829. X/* Add a calendar entry for the appropriate weekday.           */
  830. X/*                                                             */
  831. X/***************************************************************/
  832. X#ifdef __STDC__
  833. Xvoid AddCalEntry(CalEntry *e)
  834. X#else
  835. Xvoid AddCalEntry(e)
  836. XCalEntry *e;
  837. X#endif
  838. X{
  839. X   CalEntry *curr, *prev;
  840. X
  841. X   prev = &entry[DayOfWeek(JulianToday)];
  842. X   curr = prev->next;
  843. X   while (curr) {
  844. X      if (e->tim == -1 || (e->tim >= curr->tim && curr->tim != -1)) {
  845. X         prev = curr;
  846. X         curr = prev->next;
  847. X      } else {
  848. X         prev->next = e;
  849. X     e->next    = curr;
  850. X         break;
  851. X      }
  852. X   }
  853. X   if (!curr) {
  854. X      prev->next = e;
  855. X      e->next = NULL;
  856. X   }
  857. X}
  858. X
  859. X#ifdef __STDC__
  860. Xvoid CopyWord(char **src, char **dst, int l)
  861. X#else
  862. Xvoid CopyWord(src, dst, l)
  863. Xchar **src, **dst;
  864. Xint l;
  865. X#endif
  866. X{
  867. X   while(**src && !isspace(**src) && l--) *(*dst)++ = *(*src)++;
  868. X}
  869. X
  870. X#ifdef __STDC__
  871. Xint WordLen(char *src)
  872. X#else
  873. Xint WordLen(src)
  874. Xchar *src;
  875. X#endif
  876. X{
  877. X   int len = 0;
  878. X   while (*src && !isspace(*src)) { len++; src++; }
  879. X   return len;
  880. X}
  881. X/***************************************************************/
  882. X/*                                                             */
  883. X/* CreateCalEntry                                              */
  884. X/*                                                             */
  885. X/* Allocates and creates a calendar entry.                     */
  886. X/*                                                             */
  887. X/* Type = 1: MSG  type = 2: RUN                                */
  888. X/*                                                             */
  889. X/*                                                             */
  890. X/***************************************************************/
  891. X#ifdef __STDC__
  892. XCalEntry *CreateCalEntry(int type)
  893. X#else
  894. XCalEntry *CreateCalEntry(type)
  895. Xint type;
  896. X#endif
  897. X{
  898. X   CalEntry *e;
  899. X   char *s, *t;
  900. X   int column, l;
  901. X   enum Token_t tok;
  902. X   
  903. X   if (type == 1) tok = Msg_t; else tok = Run_t;
  904. X   
  905. X   if (!SimpleCalendar) {
  906. X      e = (CalEntry *) malloc(sizeof(CalEntry));
  907. X
  908. X      if (e == NULL) {
  909. X         fprintf(stderr, "remind: Can't malloc to create calendar entry.\n");
  910. X         exit(1);
  911. X      }
  912. X      e->next = NULL;
  913. X      e->tim  = CalTime;
  914. X   }
  915. X
  916. X   DoSubst(WorkBuf, TmpBuf, CurDay, CurMon, CurYear, JulianToday, tok, CalTime, 1);
  917. X
  918. X   /* If the buffer contains zero-length string; forget it. */
  919. X   if (!*TmpBuf) {
  920. X      if (!SimpleCalendar) free(e);
  921. X      return (NULL);
  922. X   }
  923. X
  924. X   /* If we're doing a simple calendar, just spit out the text and end */
  925. X   if (SimpleCalendar) {
  926. X      printf("%04d/%02d/%02d: ", CurYear, 1+CurMon, CurDay);
  927. X      Output(TmpBuf);
  928. X      return (NULL);
  929. X   }
  930. X
  931. X   /* Now copy from TmpBuf to WorkBuf, splitting words as needed */
  932. X   s = TmpBuf;
  933. X   t = WorkBuf;
  934. X   column = 0;
  935. X   while (*s) {
  936. X      l = WordLen(s);
  937. X      if (column == 0 && l >= CalWidth) {
  938. X         CopyWord(&s, &t, CalWidth);
  939. X         *t++ = '\n';
  940. X         while (isspace(*s)) s++;
  941. X      }
  942. X      else if (column != 0 && column+l > CalWidth) {
  943. X         *t++ = '\n';
  944. X         column = 0;
  945. X         if (l >= CalWidth) {
  946. X            CopyWord(&s, &t, CalWidth);
  947. X            *t++ = '\n';
  948. X            while (isspace(*s)) s++;
  949. X         } else {
  950. X            CopyWord(&s, &t, l);
  951. X            *t++ = ' ';
  952. X            while (isspace(*s)) s++;
  953. X            column = l+1;
  954. X            if (column >= CalWidth) {
  955. X              *(t-1) = '\n';
  956. X              column = 0;
  957. X            }
  958. X
  959. X         }
  960. X      }
  961. X      else {
  962. X         column += l+1;
  963. X     CopyWord(&s, &t, l);
  964. X         while (isspace(*s)) s++;
  965. X         *t++ = ' ';
  966. X     if (column > CalWidth) {
  967. X           *(t-1) = '\n';
  968. X           column = 0;
  969. X         }
  970. X      }
  971. X   }
  972. X   *t = 0;
  973. X   if (*(t-1) == '\n') *(t-1) = 0;
  974. X
  975. X   /* Finally, copy the string to the calendar entry */
  976. X   e->text = (char *) malloc(strlen(WorkBuf)+1);
  977. X
  978. X   if (!e->text) {
  979. X      fprintf(stderr, "remind: Can't malloc memory for calendar text!\n");
  980. X      exit(1);
  981. X   }
  982. X   strcpy(e->text, WorkBuf);
  983. X   e->current = e->text;
  984. X
  985. X   return e;
  986. X}
  987. X
  988. X/***************************************************************/
  989. X/*                                                             */
  990. X/* EmitOneCalendarLine                                         */
  991. X/* This is the biggie - we print out one line.                 */
  992. X/*                                                             */
  993. X/***************************************************************/
  994. X#ifdef __STDC__
  995. Xvoid EmitOneCalendarLine(void)
  996. X#else
  997. Xvoid EmitOneCalendarLine()
  998. X#endif
  999. X{
  1000. X   int i, nlines, emit, j;
  1001. X   char *s, *dst;
  1002. X   CalEntry *e;
  1003. X   char pend[7];  /* Reminders with following blanks pending */
  1004. X
  1005. X   if (SimpleCalendar) return;
  1006. X
  1007. X   nlines = 0;
  1008. X   for (i=0; i<7; i++) pend[i] = 0;
  1009. X   putchar('|');
  1010. X   /* First, emit the days of the month */
  1011. X   for (i=0; i<7; i++) {
  1012. X      if (!used[i]) PrintChars(CalWidth, ' ');
  1013. X      else {
  1014. X         sprintf(TmpBuf, "%d", used[i]);
  1015. X         printf(TmpBuf);
  1016. X         PrintChars(CalWidth-strlen(TmpBuf), ' ');
  1017. X      }
  1018. X      putchar('|');
  1019. X   }
  1020. X   putchar('\n');
  1021. X
  1022. X   /* Now cycle through all the reminders until there are none left */
  1023. X   emit = 1;
  1024. X   while(emit) {
  1025. X      dst = WorkBuf;
  1026. X      *dst++ = '|';
  1027. X      emit = 0;
  1028. X      for (i=0; i<7; i++) {
  1029. X         if (pend[i] || !used[i] || !entry[i].next) {
  1030. X            dst = CopyChars(CalWidth, ' ', dst);
  1031. X        *dst++ = '|';
  1032. X        if(pend[i]) {pend[i] = 0; emit = 1;}
  1033. X            continue;
  1034. X         }
  1035. X         s = entry[i].next->current;
  1036. X     j = 0;
  1037. X     emit = 1;
  1038. X     while (*s && *s != '\n') {
  1039. X        *dst++ = *s++;
  1040. X        j++;
  1041. X     }
  1042. X     dst = CopyChars(CalWidth - j, ' ', dst);
  1043. X         if (*s == '\n') entry[i].next->current = s+1;
  1044. X         else {
  1045. X            e = entry[i].next;
  1046. X        entry[i].next = e->next;
  1047. X            free(e->text);
  1048. X            free(e);
  1049. X        if (!entry[i].next) used[i] = 0;
  1050. X        else pend[i] = 1;
  1051. X         }
  1052. X         *dst++ = '|';
  1053. X      }
  1054. X      *dst = 0;
  1055. X      if(emit) printf("%s\n", WorkBuf);
  1056. X      nlines += emit;
  1057. X   }
  1058. X   while(nlines++ < 6) printf("%s\n", WorkBuf);
  1059. X
  1060. X   putchar('+');
  1061. X   for (i=0; i<7; i++) {
  1062. X      PrintChars(CalWidth, '-');
  1063. X      putchar('+');
  1064. X   }
  1065. X   putchar('\n');
  1066. X   for (i=0; i<7; i++) used[i] = 0;
  1067. X}
  1068. SHAR_EOF
  1069. $TOUCH -am 0218130591 calendar.c &&
  1070. chmod 0600 calendar.c ||
  1071. echo "restore of calendar.c failed"
  1072. set `wc -c calendar.c`;Wc_c=$1
  1073. if test "$Wc_c" != "13183"; then
  1074.     echo original size 13183, current size $Wc_c
  1075. fi
  1076. fi
  1077. # ============= defines.h ==============
  1078. if test X"$1" != X"-c" -a -f 'defines.h'; then
  1079.     echo "File already exists: skipping 'defines.h'"
  1080. else
  1081. echo "x - extracting defines.h (Text)"
  1082. sed 's/^X//' << 'SHAR_EOF' > defines.h &&
  1083. X/***************************************************************/
  1084. X/*                                                             */
  1085. X/*  DEFINES.H                                                  */
  1086. X/*                                                             */
  1087. X/*  Contains macros and #defines for REMIND program.           */
  1088. X/*                                                             */
  1089. X/*  By David Skoll - 30 Sept 1990.                             */
  1090. X/*                                                             */
  1091. X/***************************************************************/
  1092. X
  1093. X/* User-definable variables.  BASE *must* be a year for which the
  1094. X   first of January is a Monday!!!  FOMITSIZE and POMITSIZE control
  1095. X   the number of fully-specified (dd-mm-yy) and partially-specified
  1096. X   (dd-mm) holidays. */
  1097. X#define BASE 1990
  1098. X#define FOMITSIZE 150
  1099. X#define POMITSIZE 75
  1100. X
  1101. X/* Useful macros */
  1102. X
  1103. X#define upper(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c)-32) : (c) )
  1104. X#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
  1105. X#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
  1106. X#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
  1107. X#define TimeLess(h1, m1, h2, m2) (((h1) < (h2)) || (((h1) == (h2)) && ((m1) < (m2))))
  1108. X#define MAX(x, y) ((x) < (y) ? (y) : (x))
  1109. X#define MIN(x, y) ((x) < (y) ? (x) : (y))
  1110. X#ifndef ABS
  1111. X#define ABS(x) ((x) < 0 ? (-(x)) : (x))
  1112. X#endif
  1113. X
  1114. X/* Bit masks for constraint map */
  1115. X#define DAY_M 1
  1116. X#define MONTH_M 2
  1117. X#define YEAR_M 4
  1118. X#define WKDAY_M 8
  1119. X
  1120. Xenum Token_t { Unknown_t, Year_t, Month_t, Day_t, WkDay_t, Msg_t, Run_t,
  1121. X           Omit_t, Banner_t, Rem_t, Delta_t, Back_t, Once_t, Include_t,
  1122. X               Repeat_t, At_t, Time_t, Skip_t, Until_t, Push_t, Pop_t,
  1123. X           Clear_t, Eol_t };
  1124. X
  1125. X/* Define the Token structure */
  1126. X
  1127. Xtypedef struct {
  1128. X   char *str;
  1129. X   enum Token_t type;
  1130. X   int val;
  1131. X   char len;    /* Minimum length to match */
  1132. X} Token;
  1133. X
  1134. X#ifdef UNIX
  1135. X/* Define the structure of an AT entry */
  1136. Xtypedef struct AtEntry_t{
  1137. X   int time;      /* Time in minutes after midnight - 0 to 1439 */
  1138. X   int firsttime; /* Time of first triggering */
  1139. X   int repeat;    /* Repeat period */
  1140. X   int delta;     /* Delta time */
  1141. X   enum Token_t type;    /* Run_t or Msg_t */
  1142. X   char *text;
  1143. X   struct AtEntry_t *next;
  1144. X} AtEntry;
  1145. X#endif
  1146. X
  1147. SHAR_EOF
  1148. $TOUCH -am 0218130591 defines.h &&
  1149. chmod 0600 defines.h ||
  1150. echo "restore of defines.h failed"
  1151. set `wc -c defines.h`;Wc_c=$1
  1152. if test "$Wc_c" != "2313"; then
  1153.     echo original size 2313, current size $Wc_c
  1154. fi
  1155. fi
  1156. # ============= dorem.c ==============
  1157. if test X"$1" != X"-c" -a -f 'dorem.c'; then
  1158.     echo "File already exists: skipping 'dorem.c'"
  1159. else
  1160. echo "x - extracting dorem.c (Text)"
  1161. sed 's/^X//' << 'SHAR_EOF' > dorem.c &&
  1162. X#include <stdio.h>
  1163. X#ifndef UNIX
  1164. X#include <stdlib.h>
  1165. X#endif
  1166. X#include <string.h>
  1167. X#include <ctype.h>
  1168. X#include "defines.h"
  1169. X#include "globals.h"
  1170. X#include "protos.h"
  1171. X
  1172. X/***************************************************************/
  1173. X/*                                                             */
  1174. X/*  int DoRem(char **s)                                        */
  1175. X/*                                                             */
  1176. X/*  Process a reminder.  Return 0 if reminder not emitted,     */
  1177. X/*  positive if emitted, or negative if in the past and        */
  1178. X/*  will never be emitted.                                     */
  1179. X/*                                                             */
  1180. X/***************************************************************/
  1181. X#ifdef __STDC__
  1182. Xint DoRem(char **s)
  1183. X#else
  1184. Xint DoRem(s)
  1185. Xchar **s;
  1186. X
  1187. X#endif
  1188. X{
  1189. X   int d, m, y, wd, cons, delta, back, omit, done, jul, once, repeat, skip;
  1190. X   int ud, um, uy; /* Date of UNTIL */
  1191. X   int uj;
  1192. X   int tim, tdelta, trep;
  1193. X   int d2, m2, y2;
  1194. X   Token tok;
  1195. X   int trigger;
  1196. X   char NeedNewToken;
  1197. X
  1198. X   uj = ud = um = uy = d = m = y = tim = tdelta = trep = -1;
  1199. X   back = delta = repeat = cons = wd = omit = once = skip = 0;
  1200. X
  1201. X
  1202. X   done = 0;
  1203. X   NeedNewToken = 1;
  1204. X   while (!done) {
  1205. X      if (NeedNewToken) tok = ParseToken(s);
  1206. X      NeedNewToken = 1;
  1207. X      switch (tok.type) {
  1208. X
  1209. X         case Until_t:
  1210. X        NeedNewToken = 0;
  1211. X        while (!done) {
  1212. X           tok = ParseToken(s);
  1213. X           switch (tok.type) {
  1214. X              case Year_t:
  1215. X             if (uy != -1) {
  1216. X                Eprint("Year duplicated in UNTIL.\n");
  1217. X            return 0;
  1218. X             }
  1219. X             uy = tok.val;
  1220. X             break;
  1221. X
  1222. X              case Month_t:
  1223. X             if (um != -1) {
  1224. X                Eprint("Month duplicated in UNTIL.\n");
  1225. X            return 0;
  1226. X             }
  1227. X             um = tok.val;
  1228. X             break;
  1229. X
  1230. X              case Day_t:
  1231. X             if (ud != -1) {
  1232. X                Eprint("Day duplicated in UNTIL.\n");
  1233. X            return 0;
  1234. X             }
  1235. X             ud = tok.val;
  1236. X             break;
  1237. X
  1238. X                  default:
  1239. X             done = 1; break;
  1240. X           }
  1241. X        }
  1242. X        if (uy == -1 || um == -1 || ud == -1) {
  1243. X           Eprint("Year, month and day must all be specified after UNTIL\n");
  1244. X           return 0;
  1245. X            }
  1246. X            if (CheckDate(ud, um, uy)) {
  1247. X               Eprint("Invalid date for UNTIL.\n");
  1248. X               return 0;
  1249. X            }
  1250. X        uj = Julian(ud, um, uy);
  1251. X        done = 0; break;
  1252. X
  1253. X         case Omit_t:
  1254. X        NeedNewToken = 0;
  1255. X              while (!done) {
  1256. X           tok = ParseToken(s);
  1257. X           switch(tok.type) {
  1258. X              case WkDay_t:
  1259. X                 if (omit & (1 << tok.val)) {
  1260. X                Eprint("%s duplicated.\n", tok.str);
  1261. X                return 0;
  1262. X                    }
  1263. X                    omit |= 1 << tok.val;
  1264. X                    break;
  1265. X
  1266. X              default: done = 1; break;
  1267. X               }
  1268. X              }
  1269. X        done = 0;
  1270. X        break;
  1271. X
  1272. X     case At_t:
  1273. X        NeedNewToken = 0;
  1274. X              while (!done) {
  1275. X               tok = ParseToken(s);
  1276. X               switch(tok.type) {
  1277. X
  1278. X                  case Time_t:
  1279. X                        if (tim != -1) {
  1280. X                    Eprint("Time specified twice.\n");
  1281. X                       return 0;
  1282. X                    }
  1283. X                    else tim = tok.val;
  1284. X                        break;
  1285. X
  1286. X                  case Repeat_t:
  1287. X                        if (trep != -1) {
  1288. X                        Eprint("Time repeat factor specified twice.\n");
  1289. X                        return 0;
  1290. X                       }
  1291. X                       trep = tok.val;
  1292. X                       if (trep <= 0) {
  1293. X                       Eprint("Invalid value for timerepeat factor: %d\n", repeat);
  1294. X                       return 0;
  1295. X                       }
  1296. X                       break;
  1297. X
  1298. X                  case Delta_t:
  1299. X                 if (tdelta != -1) {
  1300. X                    Eprint("Time delta specified twice.\n");
  1301. X                        return 0;
  1302. X                     }
  1303. X                  tdelta = ABS(tok.val);
  1304. X                     break;
  1305. X
  1306. X              default: done = 1; break;
  1307. X               }
  1308. X              }
  1309. X        done = 0; break;
  1310. X
  1311. X     case Eol_t:
  1312. X        Eprint("Missing MSG or RUN in reminder.\n");
  1313. X        return 0;
  1314. X
  1315. X     case Run_t:
  1316. X     case Msg_t: done = 1; break;
  1317. X
  1318. X     case Skip_t:
  1319. X        if (skip) {
  1320. X           Eprint("Can only have one of BEFORE, AFTER or SKIP.\n");
  1321. X           return 0;
  1322. X            }
  1323. X        skip = tok.val;
  1324. X        break;
  1325. X
  1326. X     case Unknown_t:
  1327. X        Eprint("Unknown token %s in reminder.\n", tok.str);
  1328. X        return 0;
  1329. X
  1330. X         case Repeat_t:
  1331. X            if (repeat) {
  1332. X               Eprint("Repeat factor specified twice.\n");
  1333. X               return 0;
  1334. X            }
  1335. X            repeat = tok.val;
  1336. X            if (repeat <= 0) {
  1337. X               Eprint("Invalid value for repeat factor: %d\n", repeat);
  1338. X               return 0;
  1339. X            }
  1340. X            break;
  1341. X
  1342. X     case WkDay_t:
  1343. X        if (wd & (1 << tok.val)) {
  1344. X           Eprint("%s duplicated.\n", tok.str);
  1345. X           return 0;
  1346. X        }
  1347. X        wd |= 1 << tok.val;
  1348. X        cons |= WKDAY_M;
  1349. X        break;
  1350. X
  1351. X     case Year_t:
  1352. X        if (y != -1) {
  1353. X           Eprint("Year specified twice.\n");
  1354. X           return 0;
  1355. X        }
  1356. X        y = tok.val;
  1357. X        cons |= YEAR_M;
  1358. X        break;
  1359. X
  1360. X     case Month_t:
  1361. X        if (m != -1) {
  1362. X           Eprint("Month specified twice.\n");
  1363. X           return 0;
  1364. X        }
  1365. X        m = tok.val;
  1366. X        cons |= MONTH_M;
  1367. X        break;
  1368. X
  1369. X     case Day_t:
  1370. X        if (d != -1) {
  1371. X           Eprint("Day specified twice.\n");
  1372. X           return 0;
  1373. X        }
  1374. X        d = tok.val;
  1375. X        cons |= DAY_M;
  1376. X        break;
  1377. X
  1378. X     case Delta_t:
  1379. X        if (delta) {
  1380. X           Eprint("Delta specified twice.\n");
  1381. X           return 0;
  1382. X        }
  1383. X        delta = tok.val;
  1384. X        break;
  1385. X
  1386. X     case Back_t:
  1387. X        if (back) {
  1388. X           Eprint("Back specified twice.\n");
  1389. X           return 0;
  1390. X        }
  1391. X        back = tok.val;
  1392. X        break;
  1393. X
  1394. X     case Once_t:
  1395. X        if (once) {
  1396. X           Eprint("ONCE specified twice.  (How's that for an error message??)\n");
  1397. X           return 0;
  1398. X        }
  1399. X        once = 1;
  1400. X        break;
  1401. X
  1402. X     default:
  1403. X        Eprint("Can't use token %s here.\n", tok.str);
  1404. X        return 0;
  1405. X      }
  1406. X   }
  1407. X
  1408. X   /* Do some sanity checking on the reminder */
  1409. X   if (repeat && (d == -1 || m == -1 || y == -1)) {
  1410. X      Eprint("Can't use repeat counter unless you fully specify the date.\n");
  1411. X      return 0;
  1412. X   }
  1413. X
  1414. X   if (skip && (wd & omit)) {
  1415. X      Eprint("Conflict between weekday list and local OMIT\n");
  1416. X      return 0;
  1417. X   }
  1418. X
  1419. X   if (d != -1 && m != -1 && CheckDate(d, m, y)) {
  1420. X      Eprint("Illegal date specification.\n");
  1421. X      return 0;
  1422. X   }
  1423. X   if (y != -1 && (y < BASE || y > BASE + 85)) {
  1424. X      Eprint("Illegal date specification.\n");
  1425. X      return 0;
  1426. X   }
  1427. X
  1428. X   /* Print some helpful stuff if debugging */
  1429. X   if (Debug) {
  1430. X      if (back > 7) Eprint("Warning: 'back' > 7 could slow execution severely.\n");
  1431. X      if (delta > 30 && (omit || NumFullOmit || NumPartOmit))
  1432. X     Eprint("Warning: 'delta' > 30 with OMITs could slow execution severely.\n");
  1433. X   }
  1434. X
  1435. X   if (omit == 127) {
  1436. X      Eprint("Can't omit every day!\n");
  1437. X      return 0;
  1438. X   }
  1439. X
  1440. X   if (IgOnce) once = 0; 
  1441. X
  1442. X   /* Check if we can quickly determine reminder is not to be emitted */
  1443. X   if (once && !Debug && !Purge && (LastRun == JulianToday)) return 0;
  1444. X
  1445. X   /* Have we passed the UNTIL date ? */
  1446. X   if (uj != -1 && uj < JulianToday) {
  1447. X      if (Debug) Eprint("Reminder has expired.\n");
  1448. X      return -1;
  1449. X   }
  1450. X
  1451. X   jul = GetTriggerDate(d, m, y, wd, cons, back, repeat, omit, skip);
  1452. X   if (uj != -1 && uj < jul) {
  1453. X      if (Debug) Eprint("Reminder has expired.\n");
  1454. X      return -1;
  1455. X   }
  1456. X
  1457. X   if (Calendar) {
  1458. X      if (jul == JulianToday) {
  1459. X         while (isspace(**s)) (*s)++;
  1460. X         strcpy(WorkBuf, *s);
  1461. X         CalTime = tim;
  1462. X         if (tok.type == Run_t) return 2; else return 1;
  1463. X      } else return 0;
  1464. X   }
  1465. X
  1466. X   if (jul == -1) {
  1467. X      if (Debug) Eprint("Reminder has expired.\n");
  1468. X      return -1;
  1469. X   } else if (jul == -2) return 0;
  1470. X
  1471. X   FromJulian(jul, &d2, &m2, &y2);
  1472. X
  1473. X   /* If we're in "Next" mode, output this one in simple-calendar format */
  1474. X   if (Next) {
  1475. X      DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 1);
  1476. X      if (!*WorkBuf) return 0;
  1477. X      printf("%04d/%02d/%02d: ", y2, m2+1, d2);
  1478. X      printf("%s\n", WorkBuf);
  1479. X      return 0;
  1480. X   }
  1481. X       
  1482. X   /* Figure out if the reminder should be triggered */
  1483. X
  1484. X   trigger = MoveBack(jul, delta, omit);
  1485. X
  1486. X   if(Debug) {
  1487. X      Eprint("%sTrigger date: %s, %d %s, %d.\n", 
  1488. X              (trigger <= JulianToday ? "*" : ""), DayName[jul % 7], 
  1489. X          d2, MonthName[m2], y2);
  1490. X      return 0;
  1491. X   }
  1492. X   if (Purge || (once && (LastRun == JulianToday))) return 0;
  1493. X
  1494. X   while (isspace(**s)) (*s)++;
  1495. X
  1496. X   if (trigger <= JulianToday && !(tok.type == Run_t && IgRun)) { 
  1497. X      /* Trigger a reminder */
  1498. X#ifdef UNIX
  1499. X      if (QueueAts && (jul == JulianToday) && (tim != -1)) {
  1500. X         DoAt(tim, tdelta, trep, *s, tok.type);
  1501. X      }
  1502. X      if (!PrintAts && (jul == JulianToday) && tim != -1) return 0;
  1503. X#endif
  1504. X      if (tok.type == Msg_t) {
  1505. X         if (NumEmitted == 0) {
  1506. X            NumEmitted++;
  1507. X            DoSubst(Banner, WorkBuf, CurDay, CurMon, CurYear, 
  1508. X                    JulianToday, Msg_t, (int) (SystemTime()/ 60), 0);
  1509. X            printf("%s\n", WorkBuf);
  1510. X         }
  1511. X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 0);
  1512. X         printf("%s\n", WorkBuf);
  1513. X      }
  1514. X      else if (tok.type == Run_t) {
  1515. X         DoSubst(*s, WorkBuf, d2, m2, y2, jul, tok.type, tim, 0);
  1516. X         system(WorkBuf);
  1517. X      }
  1518. X      else Eprint("Error: Invalid token type %d\n", tok.type);
  1519. X      return 1;
  1520. X   } else return 0;
  1521. X
  1522. X}
  1523. X
  1524. X/***************************************************************/
  1525. X/*                                                             */
  1526. X/* GetTriggerDate                                              */
  1527. X/*                                                             */
  1528. X/* Gets the trigger date for a reminder, returns the julian    */
  1529. X/* date, or -1 if the reminder has expired.                    */
  1530. X/* Returns -2 if an error occurs.                              */
  1531. X/*                                                             */
  1532. X/***************************************************************/
  1533. X#ifdef __STDC__
  1534. Xint GetTriggerDate(int d, int m, int y, int wd, int cons, int back, int repeat, int omit, int skip)
  1535. X#else
  1536. Xint GetTriggerDate(d, m, y, wd, cons, back, repeat, omit, skip)
  1537. Xint d, m, y, wd, cons, back, repeat, omit, skip;
  1538. X#endif
  1539. X#define MAXATTEMPTS 25  /* Maximum number of attempts before giving up */
  1540. X
  1541. X{
  1542. X   int i, d2, m2, y2, jul;
  1543. X   int d1, m1, y1, julstart;
  1544. X   int nattempts = 0;
  1545. X
  1546. X   julstart = JulianToday;
  1547. X
  1548. X   /* If we have a skip factor of 3 (AFTER), then we must back up to
  1549. X      the beginning of the block of omitted days. */
  1550. X   if (skip == 3) while(julstart>=1 && IsOmitted(julstart-1, omit)) julstart--;
  1551. X
  1552. X   FromJulian(julstart, &d1, &m1, &y1);
  1553. X
  1554. X   /* Make a first stab at the date */
  1555. X   i = TryNextDate(&d2, &m2, &y2, d1, m1, y1, d, m, y, wd, cons, 0);
  1556. X   if (!i || repeat) jul = Julian(d2, m2, y2);
  1557. X
  1558. X   if (!repeat && !back && !skip) {
  1559. X      if (i) return -1; else return jul;
  1560. X   }
  1561. X
  1562. X   if (i && !repeat) return -1;
  1563. X
  1564. X   while (nattempts++ < MAXATTEMPTS) {
  1565. X      if (back) jul = MoveBack(jul, back, omit);
  1566. X      if (repeat) {
  1567. X         if (jul < julstart) {
  1568. X        jul += ((julstart - jul) / repeat) * repeat;
  1569. X        if (jul < julstart) jul += repeat;
  1570. X         }
  1571. X      }
  1572. X      if (skip == 2)      while (IsOmitted(jul, omit)) jul--;
  1573. X      else if (skip == 3) while (IsOmitted(jul, omit)) jul++;
  1574. X      if ((skip == 1 && IsOmitted(jul, omit)) || jul < JulianToday) {
  1575. X         if (!repeat) {
  1576. X            i = TryNextDate(&d2, &m2, &y2, d2, m2, y2, d, m, y, wd, cons, 1);
  1577. X            if (i) return -1;
  1578. X            jul = Julian(d2, m2, y2);
  1579. X         } else {
  1580. X            jul += repeat;
  1581. X        back = 0;  /* We've already handled the back! */
  1582. X         }
  1583. X      } else return jul;
  1584. X   }
  1585. X   Eprint("Couldn't compute a trigger date - check that date is sensible.\n");
  1586. X   return -2;
  1587. X}
  1588. SHAR_EOF
  1589. $TOUCH -am 0218130591 dorem.c &&
  1590. chmod 0600 dorem.c ||
  1591. echo "restore of dorem.c failed"
  1592. set `wc -c dorem.c`;Wc_c=$1
  1593. if test "$Wc_c" != "11579"; then
  1594.     echo original size 11579, current size $Wc_c
  1595. fi
  1596. fi
  1597. # ============= dosubst.c ==============
  1598. if test X"$1" != X"-c" -a -f 'dosubst.c'; then
  1599.     echo "File already exists: skipping 'dosubst.c'"
  1600. else
  1601. echo "x - extracting dosubst.c (Text)"
  1602. sed 's/^X//' << 'SHAR_EOF' > dosubst.c &&
  1603. X#include <ctype.h>
  1604. X#include <stdio.h>
  1605. X#include <string.h>
  1606. X#include "defines.h"
  1607. X#include "globals.h"
  1608. X#include "protos.h"
  1609. X
  1610. X/***************************************************************/
  1611. X/*                                                             */
  1612. X/*  DOSUBST.C                                                  */
  1613. X/*                                                             */
  1614. X/*  Performs line substitution for reminders.                  */
  1615. X/*                                                             */
  1616. X/*  If mode = 0, ignore %" escapes.                            */
  1617. X/*  If mode = 1, process %" escapes.  If a RUN type reminder   */
  1618. X/*     does not have %" escape, return the empty string.       */
  1619. X/*                                                             */
  1620. X/***************************************************************/
  1621. X
  1622. Xstatic char TODAY[] = "today";
  1623. Xstatic char TOMORROW[] = "tomorrow";
  1624. X
  1625. X#ifdef __STDC__
  1626. Xint DoSubst(char *src, char *dst, int d, int m, int y, int jul, enum Token_t t, int tim, int mode)
  1627. X#else
  1628. Xint DoSubst(src, dst, d, m, y, jul, t, tim, mode)
  1629. X     char *src;
  1630. X     char *dst;
  1631. X     int d;
  1632. X     int m;
  1633. X     int y;
  1634. X     int jul;
  1635. X     enum Token_t t;
  1636. X     int tim;
  1637. X     int mode;
  1638. X#endif
  1639. X{
  1640. X   int diff = jul - JulianToday;
  1641. X   char c;
  1642. X   char *od, *s;
  1643. X   int wkday = jul % 7;
  1644. X   char *plu, *pm;
  1645. X   int curtim = (int) (SystemTime() / 60);
  1646. X   int done;
  1647. X   int h;
  1648. X   int hh;
  1649. X   int min;
  1650. X   int tdiff;
  1651. X   int adiff, mdiff, hdiff;
  1652. X   char *mplu, *hplu, *when;
  1653. X   
  1654. X   if (mode == 1) {
  1655. X      s = src;
  1656. X      od = src;
  1657. X      while (*s) {
  1658. X         if (*s == '%' && *(s+1) == '\"') {
  1659. X        src = s+2;
  1660. X        break;
  1661. X     }
  1662. X     s++;
  1663. X      }
  1664. X      if (src == od && t == Run_t) {
  1665. X         *dst = 0;
  1666. X     return 0;
  1667. X      }
  1668. X      if (*src == '%' && *(src+1) == '\"') {
  1669. X         *dst = 0;
  1670. X     return 0;
  1671. X      }
  1672. X      if (tim != -1) {
  1673. X         sprintf(dst, "%02d:%02d ", (tim / 60), (tim % 60));
  1674. X     dst += strlen(dst);
  1675. X      }
  1676. X   }
  1677. X       
  1678. X   if (tim == -1) tim = curtim;
  1679. X   tdiff = tim - curtim;
  1680. X   adiff = ABS(tdiff);
  1681. X   mdiff = adiff % 60;
  1682. X   hdiff = adiff / 60;
  1683. X   mplu = (mdiff == 1 ? "" : "s");
  1684. X   hplu = (hdiff == 1 ? "" : "s");
  1685. X   when = (tdiff < 0 ? "ago" : "from now");
  1686. X   
  1687. X   h = tim / 60;
  1688. X   min = tim % 60;
  1689. X
  1690. X   if (h >= 12) pm = "pm"; else pm = "am";
  1691. X   if (h == 12) hh = 12; else hh = h % 12;
  1692. X
  1693. X   *dst = 0;
  1694. X   
  1695. X   switch(d) {
  1696. X      case 1:
  1697. X      case 21:
  1698. X      case 31: plu = "st"; break;
  1699. X      
  1700. X      case 2:
  1701. X      case 22: plu = "nd"; break;
  1702. X      
  1703. X      case 3:
  1704. X      case 23: plu = "rd"; break;
  1705. X      
  1706. X      default: plu = "th"; break;
  1707. X   }
  1708. X      
  1709. X   
  1710. X   while (c = *src++) {
  1711. X     if (c == '\n') continue;
  1712. X     else if (c != '%') { *dst++ = c; *dst = 0; }
  1713. X     else {
  1714. X         od = dst;
  1715. X         c = *src++;
  1716. X     done = 0;
  1717. X         if (diff <= 1) {
  1718. X            switch(upper(c)) {
  1719. X               case 'A':
  1720. X               case 'B':
  1721. X           case 'C':
  1722. X           case 'E':
  1723. X           case 'F':
  1724. X           case 'G':
  1725. X           case 'H':
  1726. X           case 'I':
  1727. X           case 'J':
  1728. X           case 'K':
  1729. X           case 'L':
  1730. X           case 'U':
  1731. X           case 'V': sprintf(dst, "%s", (diff ? TOMORROW : TODAY));
  1732. X                 dst += strlen(dst);
  1733. X                 done = 1;
  1734. X                  break;
  1735. X             
  1736. X               default: done = 0;
  1737. X            }
  1738. X     }         
  1739. X     
  1740. X     if (!done) switch(upper(c)) {
  1741. X        case 0: *dst = 0; return 0;
  1742. X
  1743. X        case '\"': if (mode == 1) {
  1744. X                  *dst = 0;
  1745. X              return 0;
  1746. X               }
  1747. X               break;
  1748. X        
  1749. X           case 'A':
  1750. X               sprintf(dst, "on %s, %d %s, %d", DayName[wkday], d,
  1751. X                      MonthName[m], y);
  1752. X               dst += strlen(dst);
  1753. X           break;
  1754. X           
  1755. X        case 'B':
  1756. X               sprintf(dst, "in %d days' time", diff);
  1757. X           dst += strlen(dst);
  1758. X               break;
  1759. X           
  1760. X        case 'C':
  1761. X               sprintf(dst, "on %s", DayName[wkday]);
  1762. X               dst += strlen(dst);
  1763. X           break;
  1764. X           
  1765. X        case 'D':
  1766. X           sprintf(dst, "%d", d);
  1767. X           dst += strlen(dst);
  1768. X               break;
  1769. X           
  1770. X        case 'E':
  1771. X           sprintf(dst, "on %02d/%02d/%04d", d, m+1, y);
  1772. X           dst += strlen(dst);
  1773. X               break;
  1774. X           
  1775. X        case 'F':
  1776. X           sprintf(dst, "on %02d/%02d/%04d", m+1, d, y);
  1777. X           dst += strlen(dst);
  1778. X               break;
  1779. X
  1780. X        case 'G':
  1781. X               sprintf(dst, "on %s, %d %s", DayName[wkday], d, MonthName[m]);
  1782. X           dst += strlen(dst);
  1783. X               break;
  1784. X           
  1785. X        case 'H':
  1786. X               sprintf(dst, "on %02d/%02d", d, m+1);
  1787. X           dst += strlen(dst);
  1788. X               break;
  1789. X
  1790. X        case 'I':
  1791. X               sprintf(dst, "on %02d/%02d", m+1, d);
  1792. X           dst += strlen(dst);
  1793. X               break;
  1794. X           
  1795. X        case 'J':
  1796. X               sprintf(dst, "on %s, %s %d%s, %d", DayName[wkday],
  1797. X                      MonthName[m], d, plu, y);
  1798. X               dst += strlen(dst);
  1799. X               break;
  1800. X        
  1801. X        case 'K':
  1802. X           sprintf(dst, "on %s, %s %d%s", DayName[wkday],
  1803. X                          MonthName[m], d, plu);
  1804. X           dst += strlen(dst);
  1805. X               break;
  1806. X                         
  1807. X            case 'L':
  1808. X           sprintf(dst, "on %04d/%02d/%02d", y, m+1, d);
  1809. X           dst += strlen(dst);
  1810. X               break;
  1811. X           
  1812. X        case 'M':
  1813. X           sprintf(dst, "%s", MonthName[m]);
  1814. X           dst += strlen(dst);
  1815. X               break;
  1816. X           
  1817. X        case 'N':
  1818. X           sprintf(dst, "%d", m+1);
  1819. X           dst += strlen(dst);
  1820. X               break;
  1821. X
  1822. X        case 'O':
  1823. X               if (RealToday == JulianToday) sprintf(dst, " (today)");
  1824. X               dst += strlen(dst);
  1825. X               break;
  1826. X           
  1827. X        case 'P':
  1828. X           sprintf(dst, (diff == 1 ? "" : "s"));
  1829. X           dst += strlen(dst);
  1830. X               break;
  1831. X           
  1832. X        case 'Q':
  1833. X           sprintf(dst, (diff == 1 ? "'s" : "s'"));
  1834. X           dst += strlen(dst);
  1835. X               break;
  1836. X           
  1837. X        case 'R':
  1838. X           sprintf(dst, "%02d", d);
  1839. X           dst += strlen(dst);
  1840. X               break;
  1841. X           
  1842. X        case 'S':
  1843. X           sprintf(dst, plu);
  1844. X           dst += strlen(dst);
  1845. X               break;
  1846. X           
  1847. X        case 'T':
  1848. X           sprintf(dst, "%02d", m+1);
  1849. X           dst += strlen(dst);
  1850. X               break;
  1851. X           
  1852. X        case 'U':
  1853. X           sprintf(dst, "on %s, %d%s %s, %d", DayName[wkday], d,
  1854. X                          plu, MonthName[m], y);
  1855. X           dst += strlen(dst);
  1856. X               break;
  1857. X           
  1858. X        case 'V':
  1859. X           sprintf(dst, "on %s, %d%s %s", DayName[wkday], d, plu,
  1860. X                          MonthName[m]);
  1861. X           dst += strlen(dst);
  1862. X               break;
  1863. X           
  1864. X        case 'W':
  1865. X           sprintf(dst, DayName[wkday]);
  1866. X           dst += strlen(dst);
  1867. X               break;
  1868. X           
  1869. X        case 'X':
  1870. X           sprintf(dst, "%d", diff);
  1871. X           dst += strlen(dst);
  1872. X               break;
  1873. X           
  1874. X        case 'Y':
  1875. X           sprintf(dst, "%d", y);
  1876. X           dst += strlen(dst);
  1877. X               break;
  1878. X           
  1879. X        case 'Z':
  1880. X           sprintf(dst, "%d", y % 100);
  1881. X           dst += strlen(dst);
  1882. X               break;
  1883. X
  1884. X        case '1':
  1885. X               if (tdiff == 0) 
  1886. X                  sprintf(dst, "now");
  1887. X               else if (hdiff == 0) 
  1888. X              sprintf(dst, "%d minute%s %s", mdiff, mplu, when);
  1889. X           else if (mdiff == 0)
  1890. X              sprintf(dst, "%d hour%s %s", hdiff, hplu, when);
  1891. X               else
  1892. X              sprintf(dst, "%d hour%s and %d minute%s %s", hdiff, hplu, mdiff, mplu, when);
  1893. X           dst += strlen(dst);
  1894. X               break;
  1895. X
  1896. X            case '2':
  1897. X               sprintf(dst, "at %d:%02d%s", hh, min, pm);
  1898. X           dst += strlen(dst);
  1899. X           break;
  1900. X
  1901. X        case '3': sprintf(dst, "at %02d:%02d", h, min);
  1902. X           dst += strlen(dst);
  1903. X           break;
  1904. X
  1905. X        case '4': sprintf(dst, "%d", tdiff);
  1906. X           dst += strlen(dst);
  1907. X           break;
  1908. X           
  1909. X        case '5': sprintf(dst, "%d", adiff);
  1910. X           dst += strlen(dst);
  1911. X           break;
  1912. X
  1913. X            case '6': sprintf(dst, when);
  1914. X           dst += strlen(dst);
  1915. X           break;
  1916. X
  1917. X        case '7': sprintf(dst, "%d", hdiff);
  1918. X           dst += strlen(dst);
  1919. X           break;
  1920. X
  1921. X        case '8': sprintf(dst, "%d", mdiff);
  1922. X           dst += strlen(dst);
  1923. X           break;
  1924. X
  1925. X        case '9': sprintf(dst, mplu);
  1926. X           dst += strlen(dst);
  1927. X           break;
  1928. X
  1929. X        case '0': sprintf(dst, hplu);
  1930. X           dst += strlen(dst);
  1931. X           break;
  1932. X
  1933. X            case '!': sprintf(dst, (tdiff >= 0 ? "is" : "was"));
  1934. X           dst += strlen(dst);
  1935. X           break;
  1936. X        
  1937. X            case '_': *dst++ = '\n'; *dst = 0;
  1938. X           break;
  1939. X
  1940. X            default:
  1941. X           *dst++ = c;
  1942. X           *dst = 0;
  1943. X     }
  1944. X     if (isupper(c)) *od = upper(*od);
  1945. X      }
  1946. X   }
  1947. X   if (t == Msg_t && mode == 0) *dst++ = '\n';
  1948. X   *dst = 0;
  1949. X   return 0;
  1950. X}   
  1951. SHAR_EOF
  1952. $TOUCH -am 0218130591 dosubst.c &&
  1953. chmod 0600 dosubst.c ||
  1954. echo "restore of dosubst.c failed"
  1955. set `wc -c dosubst.c`;Wc_c=$1
  1956. if test "$Wc_c" != "8427"; then
  1957.     echo original size 8427, current size $Wc_c
  1958. fi
  1959. fi
  1960. echo "End of part 1, continue with part 2"
  1961. exit 0
  1962.