home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / remind / part08 < prev    next >
Encoding:
Text File  |  1992-11-10  |  32.5 KB  |  1,034 lines

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