home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / sources / misc / 4070 < prev    next >
Encoding:
Text File  |  1992-11-09  |  32.8 KB  |  1,040 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: dfs@doe.carleton.ca (David F. Skoll)
  4. Subject:  v33i065:  remind - A replacement for calendar, Part08/12
  5. Message-ID: <1992Nov10.041947.1209@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: 2efa42a2148a58c176c2c6116aaf76c1
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: Dept. of Electronics, Carleton University
  10. References: <csm-v33i058=remind.221714@sparky.IMD.Sterling.COM>
  11. Date: Tue, 10 Nov 1992 04:19:47 GMT
  12. Approved: kent@sparky.imd.sterling.com
  13. Lines: 1025
  14.  
  15. Submitted-by: dfs@doe.carleton.ca (David F. Skoll)
  16. Posting-number: Volume 33, Issue 65
  17. Archive-name: remind/part08
  18. Environment: UNIX, MS-DOS
  19. Supersedes: remind: Volume 17, Issue 3-6
  20.  
  21. #!/bin/sh
  22. # This is part 08 of Remind 03.00.00
  23. if touch 2>&1 | fgrep 'amc' > /dev/null
  24.  then TOUCH=touch
  25.  else TOUCH=true
  26. fi
  27. # ============= omit.c ==============
  28. if test X"$1" != X"-c" -a -f 'omit.c'; then
  29.     echo "File already exists: skipping 'omit.c'"
  30. else
  31. echo "x - extracting omit.c (Text)"
  32. sed 's/^X//' << 'SHAR_EOF' > omit.c &&
  33. X/***************************************************************/
  34. X/*                                                             */
  35. X/*  OMIT.C                                                     */
  36. X/*                                                             */
  37. X/*  This file handles all global OMIT commands, and maintains  */
  38. X/*  the data structures for OMITted dates.                     */
  39. X/*                                                             */
  40. X/*  This file is part of REMIND.                               */
  41. X/*  Copyright (C) 1992 by David F. Skoll.                      */
  42. X/*                                                             */
  43. X/***************************************************************/
  44. X#include "config.h"
  45. X#include <stdio.h>
  46. X#ifdef HAVE_STDLIB_H
  47. X#include <stdlib.h>
  48. X#endif
  49. X#ifdef HAVE_MALLOC_H
  50. X#include <malloc.h>
  51. X#endif
  52. X#include "types.h"
  53. X#include "protos.h"
  54. X#include "globals.h"
  55. X#include "err.h"
  56. X
  57. XPRIVATE int BexistsIntArray ARGS ((int array[], int num, int key));
  58. XPRIVATE void InsertIntoSortedArray ARGS ((int *array, int num, int key));
  59. X
  60. X/* Arrays for the global omits */
  61. Xstatic int FullOmitArray[MAX_FULL_OMITS];
  62. Xstatic int PartialOmitArray[MAX_PARTIAL_OMITS];
  63. X
  64. X/* How many of each omit types do we have? */
  65. Xstatic int NumFullOmits, NumPartialOmits;
  66. X
  67. X/* The structure for saving and restoring OMIT contexts */
  68. Xtypedef struct _omitcontext {
  69. X   struct _omitcontext *next;
  70. X   int numfull, numpart;
  71. X   int *fullsave;
  72. X   int *partsave;
  73. X} OmitContext;
  74. X
  75. X/* The stack of saved omit contexts */
  76. Xstatic OmitContext *SavedOmitContexts = NULL;
  77. X
  78. X/***************************************************************/
  79. X/*                                                             */
  80. X/*  ClearGlobalOmits                                           */
  81. X/*                                                             */
  82. X/*  Clear all the global OMIT context.                         */
  83. X/*                                                             */
  84. X/***************************************************************/
  85. X#ifdef HAVE_PROTOS
  86. XPUBLIC int ClearGlobalOmits(void)
  87. X#else
  88. Xint ClearGlobalOmits()
  89. X#endif
  90. X{
  91. X   NumFullOmits = NumPartialOmits = 0;
  92. X   return OK;
  93. X}
  94. X
  95. X/***************************************************************/
  96. X/*                                                             */
  97. X/*  DoClear                                                    */
  98. X/*                                                             */
  99. X/*  The command-line function CLEAR-OMIT-CONTEXT               */
  100. X/*                                                             */
  101. X/***************************************************************/
  102. X#ifdef HAVE_PROTOS
  103. XPUBLIC int DoClear(ParsePtr p)
  104. X#else
  105. Xint DoClear(p)
  106. XParsePtr p;
  107. X#endif
  108. X{
  109. X   ClearGlobalOmits();
  110. X   return VerifyEoln(p);
  111. X}
  112. X
  113. X/***************************************************************/
  114. X/*                                                             */
  115. X/*  DestroyOmitContexts                                        */
  116. X/*                                                             */
  117. X/*  Free all the memory used by saved OMIT contexts.           */
  118. X/*  As a side effect, return the number of OMIT contexts       */
  119. X/*  destroyed.                                                 */
  120. X/*                                                             */
  121. X/***************************************************************/
  122. X#ifdef HAVE_PROTOS
  123. XPUBLIC int DestroyOmitContexts(void)
  124. X#else
  125. Xint DestroyOmitContexts()
  126. X#endif
  127. X{
  128. X   OmitContext *c = SavedOmitContexts;
  129. X   OmitContext *d;
  130. X   int num = 0;
  131. X
  132. X   while (c) {
  133. X      num++;
  134. X      if (c->fullsave) free(c->fullsave);
  135. X      if (c->partsave) free(c->partsave);
  136. X      d = c->next;
  137. X      free(c);
  138. X      c = d;
  139. X   }
  140. X   SavedOmitContexts = NULL;
  141. X   return num;
  142. X}
  143. X
  144. X/***************************************************************/
  145. X/*                                                             */
  146. X/*  PushOmitContext                                            */
  147. X/*                                                             */
  148. X/*  Push the OMIT context on to the stack.                     */
  149. X/*                                                             */
  150. X/***************************************************************/
  151. X#ifdef HAVE_PROTOS
  152. XPUBLIC int PushOmitContext(ParsePtr p)
  153. X#else
  154. Xint PushOmitContext(p)
  155. XParsePtr p;
  156. X#endif
  157. X{
  158. X   register int i;
  159. X   OmitContext *context;
  160. X
  161. X/* Create the saved context */
  162. X   context = NEW(OmitContext);
  163. X   if (!context) return E_NO_MEM;
  164. X
  165. X   context->numfull = NumFullOmits;
  166. X   context->numpart = NumPartialOmits;
  167. X   context->fullsave = (int *) malloc(NumFullOmits * sizeof(int));
  168. X   if (NumFullOmits && !context->fullsave) {
  169. X      free(context);
  170. X      return E_NO_MEM;
  171. X   }
  172. X   context->partsave = (int *) malloc(NumPartialOmits * sizeof(int));
  173. X   if (NumPartialOmits && !context->partsave) {
  174. X      free(context->fullsave);
  175. X      free(context);
  176. X      return E_NO_MEM;
  177. X   }
  178. X      
  179. X/* Copy the context over */
  180. X   for (i=0; i<NumFullOmits; i++)
  181. X      *(context->fullsave + i) = FullOmitArray[i];
  182. X
  183. X   for (i=0; i<NumPartialOmits; i++)
  184. X      *(context->partsave + i) = PartialOmitArray[i];
  185. X
  186. X/* Add the context to the stack */
  187. X   context->next = SavedOmitContexts;
  188. X   SavedOmitContexts = context;
  189. X   return VerifyEoln(p);
  190. X}
  191. X
  192. X/***************************************************************/
  193. X/*                                                             */
  194. X/*  PopOmitContext                                             */
  195. X/*                                                             */
  196. X/*  Pop the OMIT context off of the stack.                     */
  197. X/*                                                             */
  198. X/***************************************************************/
  199. X#ifdef HAVE_PROTOS
  200. XPUBLIC int PopOmitContext(ParsePtr p)
  201. X#else
  202. Xint PopOmitContext(p)
  203. XParsePtr p;
  204. X#endif
  205. X{
  206. X
  207. X   register int i;
  208. X   OmitContext *c = SavedOmitContexts;
  209. X
  210. X   if (!c) return E_POP_NO_PUSH;
  211. X   NumFullOmits = c->numfull;
  212. X   NumPartialOmits = c->numpart;
  213. X
  214. X/* Copy the context over */
  215. X   for (i=0; i<NumFullOmits; i++)
  216. X      FullOmitArray[i] = *(c->fullsave + i);
  217. X
  218. X   for (i=0; i<NumPartialOmits; i++)
  219. X      PartialOmitArray[i] = *(c->partsave + i);
  220. X
  221. X/* Remove the context from the stack */
  222. X   SavedOmitContexts = c->next;
  223. X
  224. X/* Free memory used by the saved context */
  225. X   if (c->partsave) free(c->partsave);
  226. X   if (c->fullsave) free(c->fullsave);
  227. X   free(c);
  228. X
  229. X   return VerifyEoln(p);
  230. X}
  231. X
  232. X/***************************************************************/
  233. X/*                                                             */
  234. X/*  IsOmitted                                                  */
  235. X/*                                                             */
  236. X/*  Return non-zero if date is OMITted, zero if it is not.     */
  237. X/*                                                             */
  238. X/***************************************************************/
  239. X#ifdef HAVE_PROTOS
  240. XPUBLIC int IsOmitted(int jul, int localomit)
  241. X#else
  242. Xint IsOmitted(jul, localomit)
  243. Xint jul, localomit;
  244. X#endif
  245. X{
  246. X   int y, m, d;
  247. X
  248. X   /* Is it omitted because of local omits? */
  249. X   if (localomit & (1 << (jul % 7))) return 1;
  250. X
  251. X   /* Is it omitted because of fully-specified omits? */
  252. X   if (BexistsIntArray(FullOmitArray, NumFullOmits, jul)) return 1;
  253. X
  254. X   /* Get the syndrome */
  255. X   FromJulian(jul, &y, &m, &d);
  256. X   if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d))
  257. X      return 1;
  258. X
  259. X   /* Not omitted */
  260. X   return 0;
  261. X}
  262. X
  263. X/***************************************************************/
  264. X/*                                                             */
  265. X/*  BexistsIntArray                                            */
  266. X/*                                                             */
  267. X/*  Perform a binary search on an integer array.  Return 1 if  */
  268. X/*  element is found, 0 otherwise.                             */
  269. X/*                                                             */
  270. X/***************************************************************/
  271. X#ifdef HAVE_PROTOS
  272. XPRIVATE int BexistsIntArray(int array[], int num, int key)
  273. X#else
  274. Xstatic int BexistsIntArray(array, num, key)
  275. Xint array[], num, key;
  276. X#endif
  277. X{
  278. X   int top=num-1, bot=0, mid;
  279. X
  280. X   while (top >= bot) {
  281. X      mid = (top+bot)/2;
  282. X      if (array[mid] == key) return 1;
  283. X      else if (array[mid] > key) top = mid-1;
  284. X      else bot=mid+1;
  285. X   }
  286. X   return 0;
  287. X}
  288. X
  289. X/***************************************************************/
  290. X/*                                                             */
  291. X/*  InsertIntoSortedArray                                      */
  292. X/*                                                             */
  293. X/*  Insert a key into a sorted array.  We assume that there is */
  294. X/*  room in the array for it.                                  */
  295. X/*                                                             */
  296. X/***************************************************************/
  297. X#ifdef HAVE_PROTOS
  298. XPRIVATE void InsertIntoSortedArray(int *array, int num, int key)
  299. X#else
  300. Xstatic void InsertIntoSortedArray(array, num, key)
  301. Xint *array, num, key;
  302. X#endif
  303. X{
  304. X   /* num is number of elements CURRENTLY in the array. */
  305. X   int *cur = array+num;
  306. X
  307. X   while (cur > array && *(cur-1) > key) {
  308. X      *cur = *(cur-1);
  309. X      cur--;
  310. X   }
  311. X   *cur = key;
  312. X}
  313. X
  314. X/***************************************************************/
  315. X/*                                                             */
  316. X/*  DoOmit                                                     */
  317. X/*                                                             */
  318. X/*  Do a global OMIT command.                                  */
  319. X/*                                                             */
  320. X/***************************************************************/
  321. X#ifdef HAVE_PROTOS
  322. XPUBLIC int DoOmit(ParsePtr p)
  323. X#else
  324. Xint DoOmit(p)
  325. XParsePtr p;
  326. X#endif
  327. X{
  328. X   int y = NO_YR, m = NO_MON, d = NO_DAY, r;
  329. X   Token tok;
  330. X   int parsing=1;
  331. X   int syndrome;
  332. X   
  333. X/* Parse the OMIT.  We need a month and day; year is optional. */
  334. X   while(parsing) {
  335. X      if (r=ParseToken(p, TokBuffer)) return r;
  336. X      FindToken(TokBuffer, &tok);
  337. X      switch (tok.type) {
  338. X         case T_Year:
  339. X        if (y != NO_YR) {
  340. X           Eprint("Year specified twice");
  341. X           return E_PARSE_ERR;
  342. X        }
  343. X        y = tok.val;
  344. X        break;
  345. X
  346. X         case T_Month:
  347. X        if (m != NO_MON) {
  348. X           Eprint("Month specified twice");
  349. X           return E_PARSE_ERR;
  350. X        }
  351. X        m = tok.val;
  352. X        break;
  353. X
  354. X         case T_Day:
  355. X        if (d != NO_DAY) {
  356. X           Eprint("Day specified twice");
  357. X           return E_PARSE_ERR;
  358. X        }
  359. X        d = tok.val;
  360. X        break;
  361. X     
  362. X     case T_Delta:
  363. X        break;
  364. X
  365. X     case T_Empty:
  366. X     case T_Comment:
  367. X     case T_RemType:
  368. X        parsing = 0;
  369. X        break;
  370. X
  371. X     default:
  372. X        Eprint("Unknown token '%s' in OMIT command", TokBuffer);
  373. X        return E_PARSE_ERR;
  374. X      }
  375. X   }
  376. X   if (m == NO_MON || d == NO_DAY) {
  377. X      Eprint("Must specify month and day in OMIT command");
  378. X      return E_PARSE_ERR;
  379. X   }
  380. X   if (y == NO_YR) {
  381. X      if (NumPartialOmits == MAX_PARTIAL_OMITS) {
  382. X         Eprint("Too many partial OMITs");
  383. X     return E_NO_MEM;
  384. X      }
  385. X      if (d > MonthDays[m]) return E_BAD_DATE;
  386. X      syndrome = (m<<5) + d;
  387. X      if (!BexistsIntArray(PartialOmitArray, NumPartialOmits, syndrome)) {
  388. X         InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
  389. X         NumPartialOmits++;
  390. X      }
  391. X   } else {
  392. X      if (NumFullOmits == MAX_FULL_OMITS) {
  393. X         Eprint("Too many full OMITs");
  394. X     return E_NO_MEM;
  395. X      }
  396. X      if (d > DaysInMonth(m, y)) return E_BAD_DATE;
  397. X      syndrome = Julian(y, m, d);
  398. X      if (!BexistsIntArray(FullOmitArray, NumFullOmits, syndrome)) {
  399. X         InsertIntoSortedArray(FullOmitArray, NumFullOmits, syndrome);
  400. X         NumFullOmits++;
  401. X      }
  402. X   }
  403. X   if (tok.type == T_RemType) return E_PARSE_AS_REM;
  404. X   return OK;
  405. X
  406. X}
  407. SHAR_EOF
  408. $TOUCH -am 1109141292 omit.c &&
  409. chmod 0600 omit.c ||
  410. echo "restore of omit.c failed"
  411. set `wc -c omit.c`;Wc_c=$1
  412. if test "$Wc_c" != "11727"; then
  413.     echo original size 11727, current size $Wc_c
  414. fi
  415. fi
  416. # ============= queue.c ==============
  417. if test X"$1" != X"-c" -a -f 'queue.c'; then
  418.     echo "File already exists: skipping 'queue.c'"
  419. else
  420. echo "x - extracting queue.c (Text)"
  421. sed 's/^X//' << 'SHAR_EOF' > queue.c &&
  422. X/***************************************************************/
  423. X/*                                                             */
  424. X/*  QUEUE.C                                                    */
  425. X/*                                                             */
  426. X/*  Queue up reminders for subsequent execution.               */
  427. X/*                                                             */
  428. X/*  This file is part of REMIND.                               */
  429. X/*  Copyright (C) 1992 by David F. Skoll.                      */
  430. X/*                                                             */
  431. X/***************************************************************/
  432. X#include <stdio.h>
  433. X#include <signal.h>
  434. X#include <sys/types.h>
  435. X#include <sys/stat.h>
  436. X#include "config.h"
  437. X#ifdef HAVE_STDLIB_H
  438. X#include <stdlib.h>
  439. X#endif
  440. X#ifdef HAVE_MALLOC_H
  441. X#include <malloc.h>
  442. X#endif
  443. X#include "globals.h"
  444. X#include "err.h"
  445. X#include "types.h"
  446. X#include "protos.h"
  447. X
  448. X/* List structure for holding queued reminders */
  449. Xtypedef struct _queuedrem {
  450. X   struct _queuedrem *next;
  451. X   int typ;
  452. X   int RunDisabled;
  453. X   char *text;
  454. X   TimeTrig tt;
  455. X} QueuedRem;
  456. X
  457. X/* Global variables */
  458. X
  459. Xstatic QueuedRem *QueueHead;
  460. Xstatic time_t FileModTime;
  461. Xstatic struct stat StatBuf;
  462. X
  463. XPRIVATE void CheckInitialFile ARGS ((void));
  464. XPRIVATE int CalculateNextTime ARGS ((QueuedRem *q));
  465. XPRIVATE QueuedRem *FindNextReminder ARGS ((void));
  466. XPRIVATE void SigIntHandler ARGS ((void));
  467. X
  468. X/***************************************************************/
  469. X/*                                                             */
  470. X/*  QueueReminder                                              */
  471. X/*                                                             */
  472. X/*  Put the reminder on a queue for later, if queueing is      */
  473. X/*  enabled.                                                   */
  474. X/*                                                             */
  475. X/***************************************************************/
  476. X#ifdef HAVE_PROTOS
  477. XPUBLIC int QueueReminder(ParsePtr p, int typ, TimeTrig *tim)
  478. X#else
  479. Xint QueueReminder(p, typ, tim)
  480. XParsePtr p;
  481. Xint typ;
  482. XTimeTrig *tim;
  483. X#endif
  484. X{
  485. X   QueuedRem *qelem;
  486. X
  487. X   if (DontQueue ||
  488. X       tim->ttime == NO_TIME ||
  489. X       typ == CAL_TYPE ||
  490. X       tim->ttime < SystemTime() / 60 ||
  491. X       ((typ == RUN_TYPE) && RunDisabled)) return OK;
  492. X
  493. X   qelem = NEW(QueuedRem);
  494. X   if (!qelem) {
  495. X      Eprint("No memory to queue reminder.");
  496. X      return E_NO_MEM;
  497. X   }
  498. X   qelem->text = StrDup(p->pos);  /* Guaranteed that parser is not nested. */
  499. X   if (!qelem->text) {
  500. X      free(qelem);
  501. X      Eprint("No memory to queue reminder.");
  502. X      return E_NO_MEM;
  503. X   }
  504. X   qelem->typ = typ;
  505. X   qelem->tt = *tim;
  506. X   qelem->next = QueueHead;
  507. X   qelem->RunDisabled = RunDisabled;
  508. X   QueueHead = qelem;
  509. X   NumQueued++;
  510. X   return OK;
  511. X}
  512. X
  513. X/***************************************************************/
  514. X/*                                                             */
  515. X/*  HandleQueuedReminders                                      */
  516. X/*                                                             */
  517. X/*  Handle the issuing of queued reminders in the background   */
  518. X/*                                                             */
  519. X/***************************************************************/
  520. X#ifdef HAVE_PROTOS
  521. XPUBLIC void HandleQueuedReminders(void)
  522. X#else
  523. Xvoid HandleQueuedReminders()
  524. X#endif
  525. X{
  526. X   QueuedRem *q = QueueHead;
  527. X   long TimeToSleep;
  528. X   unsigned SleepTime;
  529. X   Parser p;
  530. X   Trigger trig;
  531. X
  532. X   /* Suppress the BANNER from being issued */
  533. X   NumTriggered = 1;
  534. X   
  535. X   /* If we are not connected to a tty, then we must close the
  536. X    * standard file descriptors. This is to prevent someone
  537. X    * doing:
  538. X    *        remind file | <filter> | >log
  539. X    * and have <filter> hung because the child (us) is still
  540. X    * connected to it. This means the only commands that will be
  541. X    * processed correctly are RUN commands, provided they mail
  542. X    * the result back or use their own resource (as a window).
  543. X    */
  544. X   if (!DontFork && (!isatty(1) || !isatty(2))) {
  545. X      close(1);
  546. X      close(2);
  547. X   }
  548. X
  549. X   /* If we're a daemon, get the mod time of initial file */
  550. X   if (Daemon) {
  551. X      if (stat(InitialFile, &StatBuf)) {
  552. X         fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
  553. X                      InitialFile);
  554. X         Daemon = 0;
  555. X      } else FileModTime = StatBuf.st_mtime;
  556. X   }
  557. X   
  558. X   /* Initialize the queue - initialize all the entries time of issue */
  559. X   
  560. X   while (q) {
  561. X      q->tt.nexttime = (int) (SystemTime()/60 - 1);
  562. X      q->tt.nexttime = CalculateNextTime(q);
  563. X      q = q->next;
  564. X   }
  565. X
  566. X   if (!DontFork || Daemon) signal(SIGINT, SigIntHandler);
  567. X
  568. X   /* Sit in a loop, issuing reminders when necessary */
  569. X   while(1) {
  570. X      q = FindNextReminder();
  571. X
  572. X      /* If no more reminders to issue, we're unless we're a daemon. */
  573. X      if (!q && !Daemon) exit(0);
  574. X
  575. X      if (Daemon && !q)
  576. X         TimeToSleep = (long) 60*Daemon;
  577. X      else
  578. X         TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime();
  579. X
  580. X      while (TimeToSleep > 0L) {
  581. X         SleepTime = (unsigned) ((TimeToSleep > 30000L) ? 30000 : TimeToSleep);
  582. X
  583. X     if (Daemon && SleepTime > 60*Daemon) SleepTime = 60*Daemon;
  584. X
  585. X     sleep(SleepTime);
  586. X
  587. X     if (Daemon && SleepTime) CheckInitialFile();
  588. X
  589. X     if (Daemon && !q)
  590. X        TimeToSleep = (long) 60*Daemon;
  591. X         else
  592. X        TimeToSleep = (long) q->tt.nexttime * 60L - SystemTime();
  593. X      }
  594. X
  595. X      /* Trigger the reminder */
  596. X      CreateParser(q->text, &p);
  597. X      trig.typ = q->typ;
  598. X      (void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
  599. X      fflush(stdout);
  600. X      
  601. X      /* Calculate the next trigger time */
  602. X      q->tt.nexttime = CalculateNextTime(q);
  603. X   }
  604. X}
  605. X   
  606. X
  607. X/***************************************************************/
  608. X/*                                                             */
  609. X/*  CalculateNextTime                                          */
  610. X/*                                                             */
  611. X/*  Calculate the next time when a reminder should be issued.  */
  612. X/*  Return NO_TIME if reminder expired.                        */
  613. X/*                                                             */
  614. X/***************************************************************/
  615. X#ifdef HAVE_PROTOS
  616. XPRIVATE int CalculateNextTime(QueuedRem *q)
  617. X#else
  618. Xstatic int CalculateNextTime(q)
  619. XQueuedRem *q;
  620. X#endif
  621. X{
  622. X   int tim = q->tt.ttime;
  623. X   int rep = q->tt.rep;
  624. X   int delta = q->tt.delta;
  625. X   int curtime = q->tt.nexttime+1;
  626. X
  627. X   if (delta == NO_DELTA)
  628. X      if (tim < curtime) return NO_TIME; else return tim;
  629. X
  630. X   tim -= delta;
  631. X   if (rep == NO_REP) rep = delta;
  632. X   if (tim < curtime) tim += ((curtime - tim) / rep) * rep;
  633. X   if (tim < curtime) tim += rep;
  634. X   if (tim > q->tt.ttime) tim = q->tt.ttime;
  635. X   if (tim < curtime) return NO_TIME; else return tim;
  636. X}
  637. X
  638. X/***************************************************************/
  639. X/*                                                             */
  640. X/*  FindNextReminder                                           */
  641. X/*                                                             */
  642. X/*  Find the next reminder to trigger                          */
  643. X/*                                                             */
  644. X/***************************************************************/
  645. X#ifdef HAVE_PROTOS
  646. XPRIVATE QueuedRem *FindNextReminder(void)
  647. X#else
  648. Xstatic QueuedRem *FindNextReminder()
  649. X#endif
  650. X{
  651. X   QueuedRem *q = QueueHead;
  652. X   QueuedRem *ans = NULL;
  653. X
  654. X   while (q) {
  655. X      if (q->tt.nexttime != NO_TIME) {
  656. X         if (!ans) ans = q;
  657. X     else if (q->tt.nexttime < ans->tt.nexttime) ans = q;
  658. X       }
  659. X      
  660. X      q = q->next;
  661. X   }
  662. X   return ans;
  663. X}
  664. X   
  665. X
  666. X/***************************************************************/
  667. X/*                                                             */
  668. X/* SigIntHandler                                               */
  669. X/*                                                             */
  670. X/* For debugging purposes, when sent a SIGINT, we print the    */
  671. X/* contents of the queue.  This does NOT work when the -f      */
  672. X/* command-line flag is supplied.                              */
  673. X/*                                                             */
  674. X/***************************************************************/
  675. X#ifdef HAVE_PROTOS
  676. XPRIVATE void SigIntHandler(void)
  677. X#else
  678. Xstatic void SigIntHandler()
  679. X#endif
  680. X{
  681. X   QueuedRem *q = QueueHead;
  682. X
  683. X#ifdef SYSV
  684. X   signal(SIGINT, SigIntHandler);
  685. X#endif
  686. X
  687. X   printf("Contents of AT queue:%s", NL);
  688. X
  689. X   while (q) {
  690. X      printf("Trigger: %02d:%02d  Activate: %02d:%02d  Rep: %d  Delta: %d%s",
  691. X              q->tt.ttime / 60, q->tt.ttime % 60,
  692. X          q->tt.nexttime / 60, q->tt.nexttime % 60,
  693. X              q->tt.rep, q->tt.delta, NL);
  694. X      printf("Text: %s %s%s%s", ((q->typ == MSG_TYPE) ? "MSG" : "RUN"),
  695. X              q->text,
  696. X              NL, NL);
  697. X      q = q->next;
  698. X   }
  699. X   printf(NL);
  700. X}
  701. X/***************************************************************/
  702. X/*                                                             */
  703. X/*  CheckInitialFile                                           */
  704. X/*                                                             */
  705. X/*  If the initial file has been modified, then restart the    */
  706. X/*  daemon.                                                    */
  707. X/*                                                             */
  708. X/***************************************************************/
  709. X#ifdef HAVE_PROTOS
  710. XPRIVATE void CheckInitialFile(void)
  711. X#else
  712. Xstatic void CheckInitialFile()
  713. X#endif
  714. X{
  715. X   /* If date has rolled around, or file has changed, spawn a new version. */
  716. X   time_t tim = FileModTime;
  717. X   int y, m, d;
  718. X
  719. X   if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
  720. X   if (tim != FileModTime ||
  721. X       RealToday != SystemDate(&y, &m, &d))
  722. X          execvp(ArgV[0], ArgV);
  723. X}
  724. X
  725. SHAR_EOF
  726. $TOUCH -am 1109141292 queue.c &&
  727. chmod 0600 queue.c ||
  728. echo "restore of queue.c failed"
  729. set `wc -c queue.c`;Wc_c=$1
  730. if test "$Wc_c" != "9705"; then
  731.     echo original size 9705, current size $Wc_c
  732. fi
  733. fi
  734. # ============= token.c ==============
  735. if test X"$1" != X"-c" -a -f 'token.c'; then
  736.     echo "File already exists: skipping 'token.c'"
  737. else
  738. echo "x - extracting token.c (Text)"
  739. sed 's/^X//' << 'SHAR_EOF' > token.c &&
  740. X/***************************************************************/
  741. X/*                                                             */
  742. X/*  TOKEN.C                                                    */
  743. X/*                                                             */
  744. X/*  Contains routines for parsing the reminder file and        */
  745. X/*  classifying the tokens parsed.                             */
  746. X/*                                                             */
  747. X/*  This file is part of REMIND.                               */
  748. X/*  Copyright (C) 1991 by David F. Skoll.                      */
  749. X/*                                                             */
  750. X/***************************************************************/
  751. X#include <stdio.h>
  752. X#include <ctype.h>
  753. X#include "config.h"
  754. X#ifdef HAVE_STDLIB_H
  755. X#include <stdlib.h>
  756. X#endif
  757. X#ifdef HAVE_MALLOC_H
  758. X#include <malloc.h>
  759. X#endif
  760. X#include "types.h"
  761. X#include "globals.h"
  762. X#include "protos.h"
  763. X#include "err.h"
  764. X
  765. X/* The macro PARSENUM parses a char pointer as an integer.  It simply
  766. X   executes 'return' if an initial non-numeric char is found. */
  767. X#define PARSENUM(var, string) \
  768. X   if (!isdigit(*(string))) return; \
  769. X   var = 0; \
  770. X   while (isdigit(*(string))) { \
  771. X      var *= 10; \
  772. X      var += *(string) - '0'; \
  773. X      string++; \
  774. X   }
  775. X
  776. X#define UPPER(c) ( ((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c) )
  777. X
  778. X/* The big array holding all recognized (literal) tokens in reminder file.
  779. X   Keep this array sorted, or software will not work. */
  780. XToken TokArray[] = {
  781. X   /* NAME          MINLEN      TYPE           VALUE */
  782. X
  783. X   { "after",         3,     T_Skip,     AFTER_SKIP },
  784. X   { "april",        3,    T_Month,    3 },
  785. X   { "at",        2,    T_At,        0 },
  786. X   { "august",        3,    T_Month,    7 },
  787. X   { "banner",        3,    T_Banner,    0 },
  788. X   { "before",         3,     T_Skip,     BEFORE_SKIP },
  789. X   { "cal",         3,     T_RemType,     CAL_TYPE },
  790. X   { "clear-omit-context", 5,   T_Clr,          0 },
  791. X   { "debug",           5,      T_Debug,        0 },
  792. X   { "december",     3,    T_Month,    11 },
  793. X   { "dumpvars",        4,      T_Dumpvars,     0 },
  794. X   { "else",         4,     T_Else,     0 },
  795. X   { "endif",         5,     T_EndIf,     0 },
  796. X   { "errmsg",          6,      T_ErrMsg,       0 },
  797. X   { "exit",        4,    T_Exit,        0 },
  798. X   { "february",     3,     T_Month,    1 },
  799. X   { "friday",         3,    T_WkDay,    4 },
  800. X   { "fset",        4,    T_Fset,        0 },
  801. X   { "if",        2,    T_If,        0 },
  802. X   { "iftrig",        6,    T_IfTrig,    0 },
  803. X   { "include",     3,     T_Include,     0 },
  804. X   { "january",     3,     T_Month,    0 },
  805. X   { "july",        3,    T_Month,    6 },
  806. X   { "june",        3,    T_Month,    5 },
  807. X   { "march",        3,    T_Month,    2 },
  808. X   { "may",        3,     T_Month,     4 },
  809. X   { "monday",         3,    T_WkDay,    0 },
  810. X   { "msg",         3,     T_RemType,     MSG_TYPE },
  811. X   { "november",     3,     T_Month,    10 },
  812. X   { "october",        3,     T_Month,    9 },
  813. X   { "omit",        3,    T_Omit,        0 },
  814. X   { "once",         3,     T_Once,        0 },
  815. X   { "pop-omit-context", 3,    T_Pop,        0 },
  816. X   { "preserve",        8,      T_Preserve,     0 },
  817. X   { "Push-omit-context", 4,     T_Push,        0 },
  818. X   { "rem",        3,    T_Rem,        0 },
  819. X   { "run",         3,     T_RemType,     RUN_TYPE },
  820. X   { "satisfy",        7,    T_RemType,      SAT_TYPE },
  821. X   { "saturday",    3,    T_WkDay,    5 },
  822. X   { "september",     3,     T_Month,     8 },
  823. X   { "set",        3,    T_Set,        0 },
  824. X   { "skip",         3,     T_Skip,     SKIP_SKIP },
  825. X   { "sunday",         3,    T_WkDay,    6 },
  826. X   { "thursday",    3,    T_WkDay,    3 },
  827. X   { "tuesday",        3,    T_WkDay,    1 },
  828. X   { "unset",         5,     T_UnSet,     0 },
  829. X   { "until",         3,     T_Until,    0 },
  830. X   { "wednesday",    3,    T_WkDay,    2 }
  831. X};
  832. X
  833. XPRIVATE int TokStrCmp ARGS((const Token *t, const char *s));
  834. X
  835. X/***************************************************************/
  836. X/*                                                             */
  837. X/*  FindInitialToken                                           */
  838. X/*                                                             */
  839. X/*  Find the initial token on the command line.  If it's a     */
  840. X/*  left square bracket, return a T_Illegal type.              */
  841. X/*                                                             */
  842. X/***************************************************************/
  843. X#ifdef HAVE_PROTOS
  844. XPUBLIC char *FindInitialToken(Token *tok, char *s)
  845. X#else
  846. Xchar *FindInitialToken(tok, s)
  847. XToken *tok;
  848. Xchar *s;
  849. X#endif
  850. X{
  851. X   char *t;
  852. X   int len=0;
  853. X   
  854. X   while (isspace(*s)) s++;
  855. X
  856. X   t = TokBuffer;
  857. X
  858. X   while (*s && !isspace(*s)) {
  859. X      if (len < TOKSIZE) {
  860. X         *t++ = *s++;
  861. X     len++;
  862. X      }else s++;
  863. X   }
  864. X
  865. X   *t = 0;
  866. X
  867. X   FindToken(TokBuffer, tok);
  868. X   return s;
  869. X}
  870. X     
  871. X
  872. X/***************************************************************/
  873. X/*                                                             */
  874. X/*  FindToken                                                  */
  875. X/*                                                             */
  876. X/*  Given a string, which token is it?                         */
  877. X/*                                                             */
  878. X/***************************************************************/
  879. X#ifdef HAVE_PROTOS
  880. XPUBLIC void FindToken(const char *s, Token *tok)
  881. X#else
  882. Xvoid FindToken(s, tok)
  883. Xchar *s;
  884. XToken *tok;
  885. X#endif
  886. X{
  887. X   register int top, bot, mid, r;
  888. X
  889. X   tok->type = T_Illegal;
  890. X   if (! *s) {
  891. X      tok->type = T_Empty;
  892. X      return;
  893. X   }
  894. X       
  895. X   if (*s == '#' || *s == ';') {
  896. X      tok->type = T_Comment;
  897. X      return;
  898. X   }
  899. X
  900. X   /* Quickly give up the search if first char not a letter */
  901. X   if ( ! ((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')) ) {
  902. X      FindNumericToken(s, tok);
  903. X      return;
  904. X   }
  905. X
  906. X   bot = 0;
  907. X   top = sizeof(TokArray) / sizeof(TokArray[0]) - 1;
  908. X
  909. X   while(top >= bot) {
  910. X      mid = (top + bot) / 2;
  911. X      r = TokStrCmp(&TokArray[mid], s);
  912. X      if (!r) {
  913. X     tok->type = TokArray[mid].type;
  914. X     tok->val  = TokArray[mid].val;
  915. X     return;
  916. X      }
  917. X      if (r > 0) top = mid-1; else bot=mid+1;
  918. X   }
  919. X   return;
  920. X}
  921. X
  922. X/***************************************************************/
  923. X/*                                                             */
  924. X/*  FindNumericToken                                           */
  925. X/*                                                             */
  926. X/*  Parse a numeric token:                                     */
  927. X/*  Year - number between 1990 and 2085, or 90-99.             */
  928. X/*  Day - number between 1 and 31                              */
  929. X/*  Delta - +[+]n                                              */
  930. X/*  Back - -[-]n                                               */
  931. X/*  Rep - *n                                                   */
  932. X/*                                                             */
  933. X/***************************************************************/
  934. X#ifdef HAVE_PROTOS
  935. XPUBLIC void FindNumericToken(const char *s, Token *t)
  936. X#else
  937. Xvoid FindNumericToken(s, t)
  938. Xchar *s;
  939. XToken *t;
  940. X#endif
  941. X{
  942. X   int mult = 1, hour, min;
  943. X
  944. X   t->type = T_Illegal;
  945. X   t->val = 0;
  946. X   if (isdigit(*s)) {
  947. X      PARSENUM(t->val, s);
  948. X
  949. X      /* If we hit a colon, we've probably got a time hr:min */
  950. X      if (*s == ':') {
  951. X     s++;
  952. X     hour = t->val;
  953. X     PARSENUM(min, s);
  954. X     if (*s || hour > 23 || min > 59) return;  /* Illegal time */
  955. X     t->val = hour*60 + min;  /* Convert to minutes past midnight */
  956. X     t->type = T_Time;
  957. X     return;
  958. X      }
  959. X
  960. X      /* If we hit a non-digit, error! */
  961. X      if (*s) return;
  962. X
  963. X      /* Special hack - convert years between 90 and 99 to 1990 and 1999 */
  964. X      if (t->val >= 90 && t->val <= 99) t->val += 1900;
  965. X
  966. X      /* Classify the number we've got */
  967. X      if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
  968. X      else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
  969. X      else t->type = T_Number;
  970. X      return;
  971. X   } else if (*s == '*') {
  972. X      s++;
  973. X      PARSENUM(t->val, s);
  974. X      if (*s) return;  /* Illegal token if followed by non-numeric char */
  975. X      t->type = T_Rep;
  976. X      return;
  977. X   } else if (*s == '+') {
  978. X      s++;
  979. X      if (*s == '+') { mult = -1; s++; }
  980. X      PARSENUM(t->val, s);
  981. X      if (*s) return;  /* Illegal token if followed by non-numeric char */
  982. X      t->type = T_Delta;
  983. X      t->val *= mult;
  984. X      return;
  985. X   } else if (*s == '-') {
  986. X      s++;
  987. X      if (*s == '-') { mult = -1; s++; }
  988. X      PARSENUM(t->val, s);
  989. X      if (*s) return;  /* Illegal token if followed by non-numeric char */
  990. X      t->type = T_Back;
  991. X      t->val *= mult;
  992. X      return;
  993. X   }
  994. X   return;  /* Unknown token type */
  995. X}
  996. X
  997. X
  998. X/***************************************************************/
  999. X/*                                                             */
  1000. X/*  TokStrCmp                                                  */
  1001. X/*                                                             */
  1002. X/*  Compare a token to a string.                               */
  1003. X/*                                                             */
  1004. X/***************************************************************/
  1005. X#ifdef HAVE_PROTOS
  1006. XPRIVATE int TokStrCmp(const Token *t, const char *s)
  1007. X#else
  1008. Xstatic int TokStrCmp(t, s)
  1009. XToken *t;
  1010. Xchar *s;
  1011. X#endif
  1012. X{
  1013. X   register int r;
  1014. X   register int l=0;
  1015. X   char *tk = t->name;
  1016. X   while(*tk && *s) {
  1017. X      r = UPPER(*tk) - UPPER(*s);
  1018. X      tk++;
  1019. X      s++;
  1020. X      l++;
  1021. X      if (r) return r;
  1022. X   }
  1023. X   if (l < t->MinLen) return 1;
  1024. X   if (!*s) return 0;
  1025. X   return (*tk - *s);
  1026. X}
  1027. SHAR_EOF
  1028. $TOUCH -am 1109141292 token.c &&
  1029. chmod 0600 token.c ||
  1030. echo "restore of token.c failed"
  1031. set `wc -c token.c`;Wc_c=$1
  1032. if test "$Wc_c" != "8965"; then
  1033.     echo original size 8965, current size $Wc_c
  1034. fi
  1035. fi
  1036. echo "End of part 8, continue with part 9"
  1037. exit 0
  1038.  
  1039. exit 0 # Just in case...
  1040.