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

  1. Newsgroups: comp.sources.misc
  2. From: dfs@doe.carleton.ca (David F. Skoll)
  3. Subject:  v33i066:  remind - A replacement for calendar, Part09/12
  4. Message-ID: <1992Nov10.042005.1288@sparky.imd.sterling.com>
  5. X-Md4-Signature: e9fb3a1ea25840c7602d2cba6cf9d939
  6. Date: Tue, 10 Nov 1992 04:20:05 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 66
  11. Archive-name: remind/part09
  12. Environment: UNIX, MS-DOS
  13. Supersedes: remind: Volume 17, Issue 3-6
  14.  
  15. #!/bin/sh
  16. # This is part 09 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. # ============= trigger.c ==============
  22. if test X"$1" != X"-c" -a -f 'trigger.c'; then
  23.     echo "File already exists: skipping 'trigger.c'"
  24. else
  25. echo "x - extracting trigger.c (Text)"
  26. sed 's/^X//' << 'SHAR_EOF' > trigger.c &&
  27. X/***************************************************************/
  28. X/*                                                             */
  29. X/*  TRIGGER.C                                                  */
  30. X/*                                                             */
  31. X/*  Routines for figuring out the trigger date of a reminder   */
  32. X/*                                                             */
  33. X/*  This file is part of REMIND.                               */
  34. X/*  Copyright (C) 1991 by David F. Skoll.                      */
  35. X/*                                                             */
  36. X/***************************************************************/
  37. X
  38. X#include <stdio.h>
  39. X#include "config.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 "expr.h"
  48. X#include "protos.h"
  49. X#include "globals.h"
  50. X#include "err.h"
  51. X
  52. X#define GOT_DAY 1
  53. X#define GOT_MON 2
  54. X#define GOT_YR 4
  55. X#define GOT_WD 8
  56. X
  57. Xstatic int    JYear        ARGS((int jul));
  58. Xstatic int    JMonth        ARGS((int jul));
  59. Xstatic int NextSimpleTrig ARGS((int startdate, Trigger *trig, int *err));
  60. Xstatic int GetNextTriggerDate ARGS((Trigger *trig, int start, int *err, int *nextstart));
  61. X
  62. X/***************************************************************/
  63. X/*                                                             */
  64. X/*  NextSimpleTrig                                             */
  65. X/*                                                             */
  66. X/*  Compute the "simple" trigger date, taking into account     */
  67. X/*  ONLY the day of week, day, month and year components.      */
  68. X/*  Normally, returns -1 if the trigger has expired.  As a     */
  69. X/*  special case, if D, M, Y [WD] are specified, returns the   */
  70. X/*  Julian date, regardless of whether it's expired.  This is  */
  71. X/*  so that dates with a REP can be handled properly.          */
  72. X/*                                                             */
  73. X/***************************************************************/
  74. X#ifdef HAVE_PROTOS
  75. XPRIVATE int NextSimpleTrig(int startdate, Trigger *trig, int *err)
  76. X#else
  77. Xstatic int NextSimpleTrig(startdate, trig, err)
  78. Xint startdate;
  79. XTrigger *trig;
  80. Xint *err;
  81. X#endif
  82. X{
  83. X   int typ = 0;
  84. X   int d, m, y, j, d2, m2, y2;
  85. X
  86. X   *err = 0;
  87. X   FromJulian(startdate, &y, &m, &d);
  88. X   d2 = d;
  89. X   m2 = m;
  90. X   y2 = y;
  91. X
  92. X   if (trig->d != NO_DAY) typ |= GOT_DAY;
  93. X   if (trig->m != NO_MON) typ |= GOT_MON;
  94. X   if (trig->y != NO_YR) typ |= GOT_YR;
  95. X   if (trig->wd != NO_WD) typ |= GOT_WD;
  96. X   switch(typ) {
  97. X      case 0:
  98. X      case GOT_WD:
  99. X     if (trig->wd != NO_WD)
  100. X        while(! (trig->wd & (1 << (startdate%7)))) startdate++;
  101. X     return startdate;
  102. X
  103. X      case GOT_DAY:
  104. X     if (d > trig->d) {
  105. X        m++;
  106. X        if (m == 12) { m = 0; y++; }
  107. X     }
  108. X     while (trig->d > DaysInMonth(m, trig->y)) m++;
  109. X     j = Julian(y, m, trig->d);
  110. X     return j;
  111. X
  112. X      case GOT_MON:
  113. X     if (m == trig->m) return startdate;
  114. X     else if (m > trig->m) return Julian(y+1, trig->m, 1);
  115. X     else return Julian(y, trig->m, 1);
  116. X
  117. X      case GOT_YR:
  118. X     if (y == trig->y) return startdate;
  119. X     else if (y < trig->y) return Julian(trig->y, 0, 1);
  120. X     else return -1;
  121. X
  122. X      case GOT_DAY+GOT_MON:
  123. X     if (m > trig->m || m == trig->m && d > trig->d) y++;
  124. X     if (trig->d > MonthDays[trig->m]) {
  125. X        *err = E_BAD_DATE;
  126. X        return -1;
  127. X     }
  128. X
  129. X     /* Take care of Feb. 29 */
  130. X     while (trig->d > DaysInMonth(trig->m, y)) y++;
  131. X     return Julian(y, trig->m, trig->d);
  132. X
  133. X      case GOT_DAY+GOT_YR:
  134. X    if (y < trig->y) return Julian(trig->y, 0, trig->d);
  135. X    else if (y > trig->y) return -1;
  136. X
  137. X    if (d > trig->d) {
  138. X       m++;
  139. X       if (m == 12) return -1;
  140. X    }
  141. X    while (trig->d > DaysInMonth(m, trig->y)) m++;
  142. X    return Julian(trig->y, m, trig->d);
  143. X
  144. X      case GOT_MON+GOT_YR:
  145. X     if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
  146. X     if (y < trig->y) return Julian(trig->y, trig->m, 1);
  147. X     if (m == trig->m) return startdate;
  148. X     return Julian(trig->y, trig->m, 1);
  149. X
  150. X      case GOT_DAY+GOT_MON+GOT_YR:
  151. X     if (trig->d > DaysInMonth(trig->m, trig->y)) {
  152. X        *err = E_BAD_DATE;
  153. X        return -1;
  154. X     }
  155. X     return Julian(trig->y, trig->m, trig->d);
  156. X
  157. X      case GOT_YR+GOT_WD:
  158. X     if (y > trig->y) return -1;
  159. X     if (y < trig->y) j = Julian(trig->y, 0, 1);
  160. X     else j = startdate;
  161. X     while(! (trig->wd & (1 << (j%7)))) j++;
  162. X     if (JYear(j) > trig->y) return -1;
  163. X     return j;
  164. X
  165. X      case GOT_MON+GOT_WD:
  166. X     if (m == trig->m) {
  167. X        j = startdate;
  168. X        while(! (trig->wd & (1 << (j%7)))) j++;
  169. X        if (JMonth(j) == trig->m) return j;
  170. X     }
  171. X     if (m >= trig->m) j = Julian(y+1, trig->m, 1);
  172. X     else if (m < trig->m) j = Julian(y, trig->m, 1);
  173. X     while(! (trig->wd & (1 << (j%7)))) j++;
  174. X     return j; /* Guaranteed to be within the month */
  175. X
  176. X      case GOT_DAY+GOT_WD:
  177. X     if (m !=0 || y > BASE) {
  178. X        m2 = m-1;
  179. X        if (m2 < 0) { y2 = y-1; m2 = 11; }
  180. X
  181. X        /* If there are fewer days in previous month, no match */
  182. X        if (trig->d <= DaysInMonth(m2, y2)) {
  183. X           j = Julian(y2, m2, trig->d);
  184. X           while(! (trig->wd & (1 << (j%7)))) j++;
  185. X           if (j >= startdate) return j;
  186. X
  187. X        }
  188. X     }
  189. X
  190. X     /* Try this month */
  191. X     if (trig->d <= DaysInMonth(m, y)) {
  192. X        j = Julian(y, m, trig->d);
  193. X        while(! (trig->wd & (1 << (j%7)))) j++;
  194. X        if (j >= startdate) return j;
  195. X     }
  196. X
  197. X         /* Argh!  Try next avail. month */
  198. X     m2 = m+1;
  199. X     if (m2 > 11) { m2 = 0; y++; }
  200. X     while (trig->d > DaysInMonth(m2, y)) m2++;
  201. X     j = Julian(y, m2, trig->d);
  202. X     while(! (trig->wd & (1 << (j%7)))) j++;
  203. X     return j;
  204. X
  205. X      case GOT_WD+GOT_YR+GOT_DAY:
  206. X     if (y > trig->y+1 || y > trig->y && m>0) return -1;
  207. X     if (y > trig->y) {
  208. X        j = Julian(trig->y, 11, trig->d);
  209. X        while(! (trig->wd & (1 << (j%7)))) j++;
  210. X        if (j >= startdate) return j;
  211. X     } else if (y < trig->y) {
  212. X        j = Julian(trig->y, 0, trig->d);
  213. X        while(! (trig->wd & (1 << (j%7)))) j++;
  214. X        return j;
  215. X     } else {
  216. X        /* Try last month */
  217. X        if (m > 0) {
  218. X           m2 = m-1;
  219. X           while (trig->d > DaysInMonth(m2, trig->y)) m2--;
  220. X           j = Julian(trig->y, m2, trig->d);
  221. X           while(! (trig->wd & (1 << (j%7)))) j++;
  222. X           if (j >= startdate) return j;
  223. X        }
  224. X     }
  225. X     /* Try this month */
  226. X     if (trig->d <= DaysInMonth(m, trig->y)) {
  227. X        j = Julian(trig->y, m, trig->d);
  228. X        while(! (trig->wd & (1 << (j%7)))) j++;
  229. X        if (j >= startdate) return j;
  230. X     }
  231. X
  232. X     /* Must be next month */
  233. X     if (m == 11) return -1;
  234. X     m++;
  235. X     while (trig->d > DaysInMonth(m, trig->d)) m++;
  236. X     j = Julian(trig->y, m, trig->d);
  237. X     while(! (trig->wd & (1 << (j%7)))) j++;
  238. X     return j;
  239. X
  240. X      case GOT_DAY+GOT_MON+GOT_WD:
  241. X     /* Move up to the first valid year */
  242. X    while (trig->d > DaysInMonth(trig->m, y)) y++;
  243. X
  244. X    /* Try this year */
  245. X    j = Julian(y, trig->m, trig->d);
  246. X    while(! (trig->wd & (1 << (j%7)))) j++;
  247. X    if (j >= startdate) return j;
  248. X
  249. X    /* Must be next year */
  250. X    y = y + 1;
  251. X    while (trig->d > DaysInMonth(trig->m, y)) y++;
  252. X    j = Julian(y, trig->m, trig->d);
  253. X    while(! (trig->wd & (1 << (j%7)))) j++;
  254. X    return j;
  255. X
  256. X      case GOT_WD+GOT_MON+GOT_YR:
  257. X     if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
  258. X     if (trig->y > y || (trig->y == y && trig->m > m)) {
  259. X        j = Julian(trig->y, trig->m, 1);
  260. X        while(! (trig->wd & (1 << (j%7)))) j++;
  261. X        return j;
  262. X     } else {
  263. X        j = startdate;
  264. X        while(! (trig->wd & (1 << (j%7)))) j++;
  265. X        FromJulian(j, &y2, &m2, &d2);
  266. X        if (m2 == trig->m) return j; else return -1;
  267. X     }
  268. X
  269. X      case GOT_WD+GOT_DAY+GOT_MON+GOT_YR:
  270. X     j = Julian(trig->y, trig->m, trig->d);
  271. X     while(! (trig->wd & (1 << (j%7)))) j++;
  272. X     return j;
  273. X
  274. X      default:
  275. X    Eprint("NextSimpleTrig: Bad type %d", typ);
  276. X    *err = E_SWERR;
  277. X    return -1;
  278. X   }
  279. X}
  280. X
  281. X/***************************************************************/
  282. X/*                                                             */
  283. X/*  JMonth - Given a Julian date, what's the month?            */
  284. X/*                                                             */
  285. X/***************************************************************/
  286. X#ifdef HAVE_PROTOS
  287. XPRIVATE int JMonth(int jul)
  288. X#else
  289. Xstatic int JMonth(jul)
  290. Xint jul;
  291. X#endif
  292. X{
  293. X   int y, m, d;
  294. X   FromJulian(jul, &y, &m, &d);
  295. X   return m;
  296. X}
  297. X
  298. X/***************************************************************/
  299. X/*                                                             */
  300. X/*  JYear - Given a Julian date, what's the year?              */
  301. X/*                                                             */
  302. X/***************************************************************/
  303. X#ifdef HAVE_PROTOS
  304. XPRIVATE int JYear(int jul)
  305. X#else
  306. Xstatic int JYear(jul)
  307. Xint jul;
  308. X#endif
  309. X{
  310. X   int y, m, d;
  311. X   FromJulian(jul, &y, &m, &d);
  312. X   return y;
  313. X}
  314. X
  315. X/***************************************************************/
  316. X/*                                                             */
  317. X/*  GetNextTriggerDate                                         */
  318. X/*                                                             */
  319. X/*  Given a trigger, compute the next trigger date.            */
  320. X/*                                                             */
  321. X/*  Returns the Julian date of next trigger, -1 if             */
  322. X/*  expired, -2 if can't compute trigger date.                 */
  323. X/*                                                             */
  324. X/***************************************************************/
  325. X#ifdef HAVE_PROTOS
  326. XPRIVATE int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart)
  327. X#else
  328. Xstatic int GetNextTriggerDate(trig, start, err, nextstart)
  329. XTrigger *trig;
  330. Xint start;
  331. Xint *err;
  332. Xint *nextstart;
  333. X#endif
  334. X{
  335. X   int simple, mod;
  336. X
  337. X/* First:  Have we passed the UNTIL date? */
  338. X   if (trig->until != NO_UNTIL &&
  339. X       trig->until < start) return -1; /* expired */
  340. X
  341. X/* Next: If it's an "AFTER"-type skip, back up
  342. X   until we're at the start of a block of holidays */
  343. X   if (trig->skip == AFTER_SKIP)
  344. X      while (IsOmitted(start-1, trig->localomit)) start--;
  345. X
  346. X/* Find the next simple trigger */
  347. X   simple = NextSimpleTrig(start, trig, err);
  348. X
  349. X/* Problems? */
  350. X   if (*err || (simple == -1)) return -1;
  351. X
  352. X/* Suggested starting point for next attempt */
  353. X   *nextstart = simple+1;
  354. X
  355. X/* If there's a BACK, back up... */
  356. X   if (trig->back != NO_BACK) {
  357. X      mod = trig->back;
  358. X      if (mod < 0) simple += mod;
  359. X      else
  360. X     while(mod) {
  361. X        simple--;
  362. X        if (!IsOmitted(simple, trig->localomit)) mod--;
  363. X     }
  364. X   }
  365. X
  366. X/* If there's a REP, calculate the next occurrence */
  367. X   if (trig->rep != NO_REP) {
  368. X      if (simple < start) {
  369. X     mod = (start - simple) / trig->rep;
  370. X     simple = simple + mod * trig->rep;
  371. X     if (simple < start) simple += trig->rep;
  372. X      }
  373. X   }
  374. X
  375. X/* If it's a "BEFORE"-type skip, back up */
  376. X   if (trig->skip == BEFORE_SKIP)
  377. X      while(IsOmitted(simple, trig->localomit)) simple--;
  378. X
  379. X/* If it's an "AFTER"-type skip, jump ahead */
  380. X   if (trig->skip == AFTER_SKIP)
  381. X      while (IsOmitted(simple, trig->localomit)) simple++;
  382. X
  383. X/* Return the date */
  384. X   return simple;
  385. X}
  386. X
  387. X/***************************************************************/
  388. X/*                                                             */
  389. X/*  ComputeTrigger                                             */
  390. X/*                                                             */
  391. X/*  The main function.  Compute the next trigger date given    */
  392. X/*  today's date.                                              */
  393. X/*                                                             */
  394. X/***************************************************************/
  395. X#ifdef HAVE_PROTOS
  396. XPUBLIC int ComputeTrigger(int today, Trigger *trig, int *err)
  397. X#else
  398. Xint ComputeTrigger(today, trig, err)
  399. Xint today;
  400. XTrigger *trig;
  401. Xint *err;
  402. X#endif
  403. X{
  404. X   int nattempts = 0,
  405. X       start = today,
  406. X       nextstart,
  407. X       y, m, d,
  408. X       result;
  409. X
  410. X   LastTrigValid = 0;
  411. X/* Assume everything works */
  412. X   *err = OK;
  413. X
  414. X/* But check for obvious problems... */
  415. X   if (trig->localomit == 1 + 2 + 4 + 8 + 16 + 32 + 64) {
  416. X      *err = E_2MANY_LOCALOMIT;
  417. X      return -1;
  418. X   }
  419. X
  420. X   if (trig->rep != NO_REP &&
  421. X       (trig->d == NO_DAY ||
  422. X    trig->m == NO_MON ||
  423. X    trig->y == NO_YR)) {
  424. X      Eprint("Must fully specify date to use repeat.");
  425. X      *err = E_PARSE_ERR;
  426. X      return -1;
  427. X   }
  428. X       
  429. X   
  430. X   while (nattempts++ < TRIG_ATTEMPTS) {
  431. X      result = GetNextTriggerDate(trig, start, err, &nextstart);
  432. X
  433. X      /* If there's an error, die immediately */
  434. X      if (*err) return -1;
  435. X      if (result == -1) {
  436. X         if (DebugFlag & DB_PRTTRIG) {
  437. X        fprintf(ErrFp, "%s(%d): Expired\n",
  438. X           FileName, LineNo);
  439. X     }
  440. X         return -1;
  441. X      }
  442. X
  443. X      /* If result is >= today, great! */
  444. X      if (result >= today &&
  445. X         (trig->skip != SKIP_SKIP || !IsOmitted(result, trig->localomit))) {
  446. X     LastTriggerDate = result;  /* Save in global var */
  447. X     LastTrigValid = 1;
  448. X     if (DebugFlag & DB_PRTTRIG) {
  449. X        FromJulian(result, &y, &m, &d);
  450. X        fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n",
  451. X                FileName, LineNo,
  452. X            DayName[result % 7],
  453. X            d,
  454. X            MonthName[m],
  455. X            y);
  456. X     }
  457. X     return result;
  458. X      }
  459. X
  460. X      /* If it's a simple trigger, no point in rescanning */
  461. X      if (trig->back == NO_BACK &&
  462. X          trig->skip == NO_SKIP &&
  463. X      trig->rep == NO_REP) {
  464. X          if (DebugFlag & DB_PRTTRIG) {
  465. X         fprintf(ErrFp, "%s(%d): Expired\n",
  466. X                 FileName, LineNo);
  467. X         }
  468. X         return -1;
  469. X      }
  470. X      /* Keep scanning... unless there's no point in doing it.*/
  471. X      if (nextstart <= start) {
  472. X         if (DebugFlag & DB_PRTTRIG) {
  473. X        fprintf(ErrFp, "%s(%d): Expired\n",
  474. X                  FileName, LineNo);
  475. X         }
  476. X     return -1;
  477. X      }
  478. X      else start = nextstart;
  479. X
  480. X   }
  481. X
  482. X   /* We failed - too many attempts or trigger has expired*/
  483. X   *err = E_CANT_TRIG;
  484. X   return -1;
  485. X}
  486. SHAR_EOF
  487. $TOUCH -am 1109141292 trigger.c &&
  488. chmod 0600 trigger.c ||
  489. echo "restore of trigger.c failed"
  490. set `wc -c trigger.c`;Wc_c=$1
  491. if test "$Wc_c" != "13395"; then
  492.     echo original size 13395, current size $Wc_c
  493. fi
  494. fi
  495. # ============= userfns.c ==============
  496. if test X"$1" != X"-c" -a -f 'userfns.c'; then
  497.     echo "File already exists: skipping 'userfns.c'"
  498. else
  499. echo "x - extracting userfns.c (Text)"
  500. sed 's/^X//' << 'SHAR_EOF' > userfns.c &&
  501. X/***************************************************************/
  502. X/*                                                             */
  503. X/*  USERFNS.C                                                  */
  504. X/*                                                             */
  505. X/*  This file contains the routines to support user-defined    */
  506. X/*  functions.                                                 */
  507. X/*                                                             */
  508. X/*  This file is part of REMIND.                               */
  509. X/*  Copyright (C) 1992 by David F. Skoll.                      */
  510. X/*                                                             */
  511. X/***************************************************************/
  512. X#include "config.h"
  513. X#include <stdio.h>
  514. X#ifdef HAVE_STDLIB_H
  515. X#include <stdlib.h>
  516. X#endif
  517. X#ifdef HAVE_MALLOC_H
  518. X#include <malloc.h>
  519. X#endif
  520. X#include <ctype.h>
  521. X#include "types.h"
  522. X#include "globals.h"
  523. X#include "protos.h"
  524. X#include "err.h"
  525. X#include "expr.h"
  526. X
  527. X#define FUNC_HASH_SIZE 32   /* Size of User-defined function hash table */
  528. X
  529. X/* Define the data structure used to hold a user-defined function */
  530. Xtypedef struct _udf_struct {
  531. X   struct _udf_struct *next;
  532. X   char name[VAR_NAME_LEN+1];
  533. X   char *text;
  534. X   Var *locals;
  535. X   char IsCached;
  536. X   char IsActive;
  537. X   int nargs;
  538. X} UserFunc;
  539. X
  540. X/* The hash table */
  541. Xstatic UserFunc *FuncHash[FUNC_HASH_SIZE];
  542. X
  543. X/* We need access to the expression evaluation stack */
  544. Xextern Value ValStack[];
  545. Xextern int ValStackPtr;
  546. X
  547. XPRIVATE void DestroyUserFunc ARGS ((UserFunc *f));
  548. XPRIVATE void FUnset ARGS ((char *name));
  549. XPRIVATE void FSet ARGS ((UserFunc *f));
  550. XPRIVATE int SetUpLocalVars ARGS ((UserFunc *f));
  551. XPRIVATE void DestroyLocalVals ARGS ((UserFunc *f));
  552. X
  553. X/***************************************************************/
  554. X/*                                                             */
  555. X/*  DoFset                                                     */
  556. X/*                                                             */
  557. X/*  Define a user-defined function - the FSET command.         */
  558. X/*                                                             */
  559. X/***************************************************************/
  560. X#ifdef HAVE_PROTOS
  561. XPUBLIC int DoFset(ParsePtr p)
  562. X#else
  563. Xint DoFset(p)
  564. XParsePtr p;
  565. X#endif
  566. X{
  567. X   int r;
  568. X   int c;
  569. X   UserFunc *func;
  570. X   Var *v;
  571. X
  572. X   /* Get the function name */
  573. X   if(r=ParseIdentifier(p, TokBuffer)) return r;
  574. X
  575. X   /* Should be followed by '(' */
  576. X   c = ParseNonSpaceChar(p, &r, 0);
  577. X   if (r) return r;
  578. X   if (c != '(') return E_PARSE_ERR;
  579. X
  580. X   func = NEW(UserFunc);
  581. X   if (!func) return E_NO_MEM;
  582. X   StrnCpy(func->name, TokBuffer, VAR_NAME_LEN);
  583. X   func->locals = NULL;
  584. X   func->text = NULL;
  585. X   func->IsCached = 1;
  586. X   func->IsActive = 0;
  587. X   func->nargs = 0;
  588. X
  589. X   /* Get the local variables - we insert the local variables in REVERSE
  590. X      order, but that's OK, because we pop them off the stack in reverse
  591. X      order, too, so everything works out just fine. */
  592. X
  593. X   c=ParseNonSpaceChar(p, &r, 1);
  594. X   if (r) return r;
  595. X   if (c == ')') {
  596. X      (void) ParseNonSpaceChar(p, &r, 0);
  597. X   }
  598. X   else {
  599. X      while(1) {
  600. X     if (r=ParseIdentifier(p, TokBuffer)) return r;
  601. X     v = NEW(Var);
  602. X     func->nargs++;
  603. X     v->v.type = ERR_TYPE;
  604. X     if (!v) {
  605. X        DestroyUserFunc(func);
  606. X        return E_NO_MEM;
  607. X     }
  608. X     StrnCpy(v->name, TokBuffer, VAR_NAME_LEN);
  609. X     v->next = func->locals;
  610. X     func->locals = v;
  611. X     c = ParseNonSpaceChar(p, &r, 0);
  612. X     if (c == ')') break;
  613. X     else if (c != ',') {
  614. X        DestroyUserFunc(func);
  615. X        return E_PARSE_ERR;
  616. X     }
  617. X      }
  618. X   }
  619. X
  620. X   /* Copy the text over */
  621. X   if (p->isnested) {
  622. X      Eprint ("Can't nest function definition in expression.");
  623. X      DestroyUserFunc(func);
  624. X      return E_PARSE_ERR;
  625. X   }
  626. X
  627. X   /* A bit of trickery here - if the definition is already cached,
  628. X      no point in copying it. */
  629. X   if (CurLine != LineBuffer) {
  630. X      func->IsCached = 1;
  631. X      func->text = p->pos;
  632. X   } else {
  633. X      func->IsCached = 0;
  634. X      func->text = StrDup(p->pos);
  635. X      if (!func->text) {
  636. X     DestroyUserFunc(func);
  637. X     return E_NO_MEM;
  638. X      }
  639. X   }
  640. X
  641. X   /* If an old definition of this function exists, destroy it */
  642. X   FUnset(func->name);
  643. X
  644. X   /* Add the function definition */
  645. X   FSet(func);
  646. X   return OK;
  647. X}
  648. X
  649. X/***************************************************************/
  650. X/*                                                             */
  651. X/*  DestroyUserFunc                                            */
  652. X/*                                                             */
  653. X/*  Free up all the resources used by a user-defined function. */
  654. X/*                                                             */
  655. X/***************************************************************/
  656. X#ifdef HAVE_PROTOS
  657. XPRIVATE void DestroyUserFunc(UserFunc *f)
  658. X#else
  659. Xstatic void DestroyUserFunc(f)
  660. XUserFunc *f;
  661. X#endif
  662. X{
  663. X   Var *v, *prev;
  664. X
  665. X   /* Free the local variables first */
  666. X   v = f->locals;
  667. X   while(v) {
  668. X      DestroyValue(&(v->v));
  669. X      prev = v;
  670. X      v = v->next;
  671. X      free(prev);
  672. X   }
  673. X
  674. X   /* Free the function definition */
  675. X   if (f->text && !f->IsCached) free(f->text);
  676. X
  677. X   /* Free the data structure itself */
  678. X   free(f);
  679. X}
  680. X
  681. X/***************************************************************/
  682. X/*                                                             */
  683. X/*  FUnset                                                     */
  684. X/*                                                             */
  685. X/*  Delete the function definition with the given name, if     */
  686. X/*  it exists.                                                 */
  687. X/*                                                             */
  688. X/***************************************************************/
  689. X#ifdef HAVE_PROTOS
  690. XPRIVATE void FUnset(char *name)
  691. X#else
  692. Xstatic void FUnset(name)
  693. Xchar *name;
  694. X#endif
  695. X{
  696. X   UserFunc *cur, *prev;
  697. X   int h;
  698. X
  699. X   h = HashVal(name) % FUNC_HASH_SIZE;
  700. X
  701. X   cur = FuncHash[h];
  702. X   prev = NULL;
  703. X   while(cur) {
  704. X      if (StrinEq(name, cur->name, VAR_NAME_LEN)) break;
  705. X      prev = cur;
  706. X      cur = cur->next;
  707. X   }
  708. X   if (!cur) return;
  709. X   if (prev) prev->next = cur->next; else FuncHash[h] = cur->next;
  710. X   DestroyUserFunc(cur);
  711. X}
  712. X
  713. X/***************************************************************/
  714. X/*                                                             */
  715. X/*  FSet                                                       */
  716. X/*                                                             */
  717. X/*  Insert a user-defined function into the hash table.        */
  718. X/*                                                             */
  719. X/***************************************************************/
  720. X#ifdef HAVE_PROTOS
  721. XPRIVATE void FSet(UserFunc *f)
  722. X#else
  723. Xstatic void FSet(f)
  724. XUserFunc *f;
  725. X#endif
  726. X{
  727. X   int h = HashVal(f->name) % FUNC_HASH_SIZE;
  728. X   f->next = FuncHash[h];
  729. X   FuncHash[h] = f;
  730. X}
  731. X
  732. X/***************************************************************/
  733. X/*                                                             */
  734. X/*  CallUserFunc                                               */
  735. X/*                                                             */
  736. X/*  Call a user-defined function.                              */
  737. X/*                                                             */
  738. X/***************************************************************/
  739. X#ifdef HAVE_PROTOS
  740. XPUBLIC int CallUserFunc(char *name, int nargs)
  741. X#else
  742. Xint CallUserFunc(name, nargs)
  743. Xchar *name;
  744. Xint nargs;
  745. X#endif
  746. X{
  747. X   UserFunc *f;
  748. X   int h = HashVal(name) % FUNC_HASH_SIZE;
  749. X   int i;
  750. X   char *s;
  751. X
  752. X   /* Search for the function */
  753. X   f = FuncHash[h];
  754. X   while (f && !StrinEq(name, f->name, VAR_NAME_LEN)) f = f->next;
  755. X   if (!f) return E_UNDEF_FUNC;
  756. X
  757. X   /* Debugging stuff */
  758. X   if (DebugFlag & DB_PRTEXPR) {
  759. X      fprintf(ErrFp, "UserFN %s(", f->name);
  760. X      for (i=0; i<nargs; i++) {
  761. X         PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
  762. X         if (i<nargs-1) fprintf(ErrFp, ", ");
  763. X      }
  764. X      fprintf(ErrFp, ")\n");
  765. X   }
  766. X   /* Detect illegal recursive call */
  767. X   if (f->IsActive) return E_RECURSIVE;
  768. X
  769. X   /* Check number of args */
  770. X   if (nargs != f->nargs)
  771. X      return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
  772. X
  773. X   /* Found the function - set up a local variable frame */
  774. X   h = SetUpLocalVars(f);
  775. X   if (h) return h;
  776. X
  777. X   /* Evaluate the expression */
  778. X   f->IsActive = 1;
  779. X   s = f->text;
  780. X
  781. X   /* Skip the opening bracket, if there's one */
  782. X   while (isspace(*s)) s++;
  783. X   if (*s == BEG_OF_EXPR) s++;
  784. X   h = Evaluate(&s, f->locals);
  785. X   f->IsActive = 0;
  786. X   DestroyLocalVals(f);
  787. X   if (DebugFlag &DB_PRTEXPR) {
  788. X      fprintf(ErrFp, "Leaving UserFN %s() => ", name);
  789. X      if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
  790. X      else {
  791. X         PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  792. X         fprintf(ErrFp, "\n");
  793. X      }
  794. X   }
  795. X   return h;
  796. X}
  797. X
  798. X/***************************************************************/
  799. X/*                                                             */
  800. X/*  SetUpLocalVars                                             */
  801. X/*                                                             */
  802. X/*  Set up the local variables from the stack frame.           */
  803. X/*                                                             */
  804. X/***************************************************************/
  805. X#ifdef HAVE_PROTOS
  806. XPRIVATE int SetUpLocalVars(UserFunc *f)
  807. X#else
  808. Xstatic int SetUpLocalVars(f)
  809. XUserFunc *f;
  810. X#endif
  811. X{
  812. X   int i, r;
  813. X   Var *var;
  814. X
  815. X   for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
  816. X      if (r=PopValStack(&(var->v))) {
  817. X     DestroyLocalVals(f);
  818. X     return r;
  819. X      }
  820. X   }
  821. X   return OK;
  822. X}
  823. X
  824. X/***************************************************************/
  825. X/*                                                             */
  826. X/*  DestroyLocalVals                                           */
  827. X/*                                                             */
  828. X/*  Destroy the values of all local variables after evaluating */
  829. X/*  the function.                                              */
  830. X/*                                                             */
  831. X/***************************************************************/
  832. X#ifdef HAVE_PROTOS
  833. XPRIVATE void DestroyLocalVals(UserFunc *f)
  834. X#else
  835. Xstatic void DestroyLocalVals(f)
  836. XUserFunc *f;
  837. X#endif
  838. X{
  839. X   Var *v = f->locals;
  840. X
  841. X   while(v) {
  842. X      DestroyValue(&(v->v));
  843. X      v = v->next;
  844. X   }
  845. X}
  846. SHAR_EOF
  847. $TOUCH -am 1109141292 userfns.c &&
  848. chmod 0600 userfns.c ||
  849. echo "restore of userfns.c failed"
  850. set `wc -c userfns.c`;Wc_c=$1
  851. if test "$Wc_c" != "10178"; then
  852.     echo original size 10178, current size $Wc_c
  853. fi
  854. fi
  855. # ============= utils.c ==============
  856. if test X"$1" != X"-c" -a -f 'utils.c'; then
  857.     echo "File already exists: skipping 'utils.c'"
  858. else
  859. echo "x - extracting utils.c (Text)"
  860. sed 's/^X//' << 'SHAR_EOF' > utils.c &&
  861. X/***************************************************************/
  862. X/*                                                             */
  863. X/*  UTILS.C                                                    */
  864. X/*                                                             */
  865. X/*  Useful utility functions.                                  */
  866. X/*                                                             */
  867. X/*  This file is part of REMIND.                               */
  868. X/*  Copyright (C) 1991 by David F. Skoll.                      */
  869. X/*                                                             */
  870. X/***************************************************************/
  871. X
  872. X#include <string.h>
  873. X#include <stdio.h>
  874. X#include "config.h"
  875. X#ifdef HAVE_STDLIB_H
  876. X#include <stdlib.h>
  877. X#endif
  878. X#ifdef HAVE_MALLOC_H
  879. X#include <malloc.h>
  880. X#endif
  881. X
  882. X#define UPPER(c) ( ((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c) )
  883. X
  884. X/***************************************************************/
  885. X/*                                                             */
  886. X/*  StrEq                                                      */
  887. X/*                                                             */
  888. X/*  Are two strings equal?                                     */
  889. X/*                                                             */
  890. X/***************************************************************/
  891. X#ifdef HAVE_PROTOS
  892. XPUBLIC int StrEq(const char *s1, const char *s2)
  893. X#else
  894. Xint StrEq(s1, s2)
  895. Xchar *s1, *s2;
  896. X#endif
  897. X{
  898. X   while (*s1 && *s2) {
  899. X      if (*s1++ != *s2++) return 0;
  900. X   }
  901. X   if (*s1 || *s2) return 0 ; else return 1;
  902. X}
  903. X
  904. X/***************************************************************/
  905. X/*                                                             */
  906. X/*  StriEq                                                     */
  907. X/*                                                             */
  908. X/*  Are two strings equal, ignoring case?                      */
  909. X/*                                                             */
  910. X/***************************************************************/
  911. X#ifdef HAVE_PROTOS
  912. XPUBLIC int StriEq(const char *s1, const char *s2)
  913. X#else
  914. Xint StriEq(s1, s2)
  915. Xchar *s1, *s2;
  916. X#endif
  917. X{
  918. X   while (*s1 && *s2) {
  919. X      if (UPPER(*s1) != UPPER(*s2)) return 0;
  920. X      s1++;
  921. X      s2++;
  922. X   }
  923. X   if (*s1 || *s2) return 0 ; else return 1;
  924. X}
  925. X
  926. X/***************************************************************/
  927. X/*                                                             */
  928. X/*  StrinEq                                                    */
  929. X/*  Are two strings equal to a given number of chars?          */
  930. X/*                                                             */
  931. X/***************************************************************/
  932. X#ifdef HAVE_PROTOS
  933. XPUBLIC int StrinEq(const char *s1, const char *s2, int n)
  934. X#else
  935. Xint StrinEq(s1, s2, n)
  936. Xchar *s1, *s2;
  937. Xint n;
  938. X#endif
  939. X{
  940. X   while (*s1 && *s2 && n--) {
  941. X      if (UPPER(*s1) != UPPER(*s2)) return 0;
  942. X      s1++;
  943. X      s2++;
  944. X   }
  945. X   if (n && (*s1 || *s2)) return 0 ; else return 1;
  946. X}
  947. X
  948. X/***************************************************************/
  949. X/*                                                             */
  950. X/*  StrnCpy                                                    */
  951. X/*                                                             */
  952. X/*  Just like strncpy EXCEPT we ALWAYS copy the trailing 0.    */
  953. X/*                                                             */
  954. X/***************************************************************/
  955. X#ifdef HAVE_PROTOS
  956. XPUBLIC char *StrnCpy(char *dest, const char *source, int n)
  957. X#else
  958. Xchar *StrnCpy(dest, source, n)
  959. Xchar *dest, *source;
  960. Xint n;
  961. X#endif
  962. X{
  963. X   register char *odest = dest;
  964. X
  965. X   while (n-- && (*dest++ = *source++)) ;
  966. X   if (*(dest-1)) *dest = 0;
  967. X   return odest;
  968. X}
  969. X
  970. X/***************************************************************/
  971. X/*                                                             */
  972. X/*  StrMatch                                                   */
  973. X/*                                                             */
  974. X/*  Checks that two strings match (case-insensitive) to at     */
  975. X/*  least the specified number of characters, or the length    */
  976. X/*  of the first string, whichever is greater.                 */
  977. X/*                                                             */
  978. X/***************************************************************/
  979. X#ifdef HAVE_PROTOS
  980. XPUBLIC int StrMatch(const char *s1, const char *s2, int n)
  981. X#else
  982. Xint StrMatch(s1, s2, n)
  983. Xchar *s1, *s2;
  984. Xint n;
  985. X#endif
  986. X{
  987. X   int l;
  988. X   if ((l = strlen(s1)) < n) return 0;
  989. X   return StrinEq(s1, s2, l);
  990. X}
  991. X
  992. X/***************************************************************/
  993. X/*                                                             */
  994. X/*  StrinCmp - compare strings, case-insensitive               */
  995. X/*                                                             */
  996. X/***************************************************************/
  997. X#ifdef HAVE_PROTOS
  998. XPUBLIC int StrinCmp(const char *s1, const char *s2, int n)
  999. X#else
  1000. Xint StrinCmp(s1, s2, n)
  1001. Xchar *s1, *s2;
  1002. Xint n;
  1003. X#endif
  1004. X{
  1005. X   register int r;
  1006. X   while (n && *s1 && *s2) {
  1007. X      n--;
  1008. X      r = UPPER(*s1) - UPPER(*s2);
  1009. X      if (r) return r;
  1010. X      s1++;
  1011. X      s2++;
  1012. X   }
  1013. X   if (n) return (UPPER(*s1) - UPPER(*s2)); else return 0;
  1014. X}
  1015. X
  1016. X/***************************************************************/
  1017. X/*                                                             */
  1018. X/*  StrDup                                                     */
  1019. X/*                                                             */
  1020. X/*  Like ANSI strdup                                           */
  1021. X/*                                                             */
  1022. X/***************************************************************/
  1023. X#ifdef HAVE_PROTOS
  1024. XPUBLIC char *StrDup(const char *s)
  1025. X#else
  1026. Xchar *StrDup(s)
  1027. Xchar *s;
  1028. X#endif
  1029. X{
  1030. X   char *ret = (char *) malloc(strlen(s)+1);
  1031. X   if (!ret) return (char *) NULL;
  1032. X   strcpy(ret, s);
  1033. X   return ret;
  1034. X}
  1035. X
  1036. X/***************************************************************/
  1037. X/*                                                             */
  1038. X/*  StrCmpi                                                    */
  1039. X/*                                                             */
  1040. X/*  Compare strings, case insensitive.                         */
  1041. X/*                                                             */
  1042. X/***************************************************************/
  1043. X#ifdef HAVE_PROTOS
  1044. XPUBLIC int StrCmpi(char *s1, char *s2)
  1045. X#else
  1046. Xint StrCmpi(s1, s2)
  1047. Xchar *s1, *s2;
  1048. X#endif
  1049. X{
  1050. X   int r;
  1051. X   while (*s1 && *s2) {
  1052. X      r = UPPER(*s1) - UPPER(*s2);
  1053. X      if (r) return r;
  1054. X      s1++;
  1055. X      s2++;
  1056. X   }
  1057. X   return UPPER(*s1) - UPPER(*s2);
  1058. X}
  1059. X
  1060. X#ifdef NO_STRSTR
  1061. X#ifdef HAVE_PROTOS
  1062. XPUBLIC char *strstr(char *s1, char *s2)
  1063. X#else
  1064. Xchar *strstr(s1, s2)
  1065. Xchar *s1, *s2;
  1066. X#endif
  1067. X{
  1068. X   char *s = s1;
  1069. X   int len2 = strlen(s2);
  1070. X   int len1 = strlen(s1);
  1071. X
  1072. X   while (s-s1 <= len1-len2) {
  1073. X      if (!strncmp(s, s2, len2)) return s;
  1074. X      s++;
  1075. X   }
  1076. X   return NULL;
  1077. X}
  1078. X#endif
  1079. X
  1080. SHAR_EOF
  1081. $TOUCH -am 1109141292 utils.c &&
  1082. chmod 0600 utils.c ||
  1083. echo "restore of utils.c failed"
  1084. set `wc -c utils.c`;Wc_c=$1
  1085. if test "$Wc_c" != "6948"; then
  1086.     echo original size 6948, current size $Wc_c
  1087. fi
  1088. fi
  1089. # ============= var.c ==============
  1090. if test X"$1" != X"-c" -a -f 'var.c'; then
  1091.     echo "File already exists: skipping 'var.c'"
  1092. else
  1093. echo "x - extracting var.c (Text)"
  1094. sed 's/^X//' << 'SHAR_EOF' > var.c &&
  1095. X/***************************************************************/
  1096. X/*                                                             */
  1097. X/*  VAR.C                                                      */
  1098. X/*                                                             */
  1099. X/*  This file contains routines, structures, etc for           */
  1100. X/*  user- and system-defined variables.                        */
  1101. X/*                                                             */
  1102. X/*  This file is part of REMIND.                               */
  1103. X/*  Copyright (C) 1991 by David F. Skoll.                      */
  1104. X/*                                                             */
  1105. X/***************************************************************/
  1106. X
  1107. X#include <stdio.h>
  1108. X#include "config.h"
  1109. X#ifdef HAVE_STDLIB_H
  1110. X#include <stdlib.h>
  1111. X#endif
  1112. X#ifdef HAVE_MALLOC_H
  1113. X#include <malloc.h>
  1114. X#endif
  1115. X#include "types.h"
  1116. X#include "expr.h"
  1117. X#include "globals.h"
  1118. X#include "protos.h"
  1119. X#include "err.h"
  1120. X
  1121. X#define UPPER(c) ( ((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c) )
  1122. X
  1123. X/* The variable hash table */
  1124. X#define VAR_HASH_SIZE 64
  1125. Xstatic Var *VHashTbl[VAR_HASH_SIZE];
  1126. X
  1127. X/***************************************************************/
  1128. X/*                                                             */
  1129. X/*  HashVal                                                    */
  1130. X/*  Given a string, compute the hash value.                    */
  1131. X/*                                                             */
  1132. X/***************************************************************/
  1133. X#ifdef HAVE_PROTOS
  1134. XPUBLIC int HashVal(const char *str)
  1135. X#else
  1136. Xint HashVal(str)
  1137. Xchar *str;
  1138. X#endif
  1139. X{
  1140. X   register int i = 0;
  1141. X   register int j=1;
  1142. X   register int len=0;
  1143. X
  1144. X   while(*str && len < VAR_NAME_LEN) {
  1145. X      i += j * UPPER(*str);
  1146. X      str++;
  1147. X      len++;
  1148. X      j = 3-j;
  1149. X   }
  1150. X   return i;
  1151. X}
  1152. X
  1153. X/***************************************************************/
  1154. X/*                                                             */
  1155. X/*  FindVar                                                    */
  1156. X/*  Given a string, find the variable whose name is that       */
  1157. X/*  string.  If create is 1, create the variable.              */
  1158. X/*                                                             */
  1159. X/***************************************************************/
  1160. X#ifdef HAVE_PROTOS
  1161. XPUBLIC Var *FindVar(const char *str, int create)
  1162. X#else
  1163. XVar *FindVar(str, create)
  1164. Xchar *str;
  1165. Xint create;
  1166. X#endif
  1167. X{
  1168. X   register int h;
  1169. X   register Var *v;
  1170. X   register Var *prev;
  1171. X
  1172. X   h = HashVal(str) % VAR_HASH_SIZE;
  1173. X   v = VHashTbl[h];
  1174. X   prev = NULL;
  1175. X
  1176. X   while(v) {
  1177. X      if (StrinEq(str, v->name, VAR_NAME_LEN)) return v;
  1178. X      prev = v;
  1179. X      v = v-> next;
  1180. X   }
  1181. X   if (!create) return v;
  1182. X
  1183. X/* Create the variable */
  1184. X   v = NEW(Var);
  1185. X   if (!v) return v;
  1186. X   v->next = NULL;
  1187. X   v->v.type = INT_TYPE;
  1188. X   v->v.v.val = 0;
  1189. X   v->preserve = 0;
  1190. X   StrnCpy(v->name, str, VAR_NAME_LEN);
  1191. X
  1192. X   if (prev) prev->next = v; else VHashTbl[h] = v;
  1193. X   return v;
  1194. X}
  1195. X
  1196. X/***************************************************************/
  1197. X/*                                                             */
  1198. X/*  DeleteVar                                                  */
  1199. X/*  Given a string, find the variable whose name is that       */
  1200. X/*  string and delete it.                                      */
  1201. X/*                                                             */
  1202. X/***************************************************************/
  1203. X#ifdef HAVE_PROTOS
  1204. XPUBLIC int DeleteVar(const char *str)
  1205. X#else
  1206. Xint DeleteVar(str)
  1207. Xchar *str;
  1208. X#endif
  1209. X{
  1210. X   register int h;
  1211. X   register Var *v;
  1212. X   register Var *prev;
  1213. X
  1214. X   h = HashVal(str) % VAR_HASH_SIZE;
  1215. X   v = VHashTbl[h];
  1216. X   prev = NULL;
  1217. X
  1218. X   while(v) {
  1219. X      if (StrinEq(str, v->name, VAR_NAME_LEN)) break;
  1220. X      prev = v;
  1221. X      v = v-> next;
  1222. X   }
  1223. X   if (!v) return E_NOSUCH_VAR;
  1224. X   DestroyValue(&(v->v));
  1225. X   if (prev) prev->next = v->next; else VHashTbl[h] = v->next;
  1226. X   free(v);
  1227. X   return OK;
  1228. X}
  1229. X
  1230. X/***************************************************************/
  1231. X/*                                                             */
  1232. X/*  SetVar                                                     */
  1233. X/*                                                             */
  1234. X/*  Set the indicate variable to the specified value.          */
  1235. X/*                                                             */
  1236. X/***************************************************************/
  1237. X#ifdef HAVE_PROTOS
  1238. XPUBLIC int SetVar(const char *str, Value *val)
  1239. X#else
  1240. Xint SetVar(str, val)
  1241. Xchar *str;
  1242. XValue *val;
  1243. X#endif
  1244. X{
  1245. X   Var *v = FindVar(str, 1);
  1246. X
  1247. X   if (!v) return E_NO_MEM;  /* Only way FindVar can fail */
  1248. X
  1249. X   DestroyValue(&(v->v));
  1250. X   v->v = *val;
  1251. X   return OK;
  1252. X}
  1253. X
  1254. X/***************************************************************/
  1255. X/*                                                             */
  1256. X/*  GetVarValue                                                */
  1257. X/*                                                             */
  1258. X/*  Get a copy of the value of the variable.                   */
  1259. X/*                                                             */
  1260. X/***************************************************************/
  1261. X#ifdef HAVE_PROTOS
  1262. XPUBLIC int GetVarValue(const char *str, Value *val, Var *locals)
  1263. X#else
  1264. Xint GetVarValue(str, val, locals)
  1265. Xchar *str;
  1266. XValue *val;
  1267. XVar *locals;
  1268. X#endif
  1269. X{
  1270. X   Var *v;
  1271. X
  1272. X   /* Try searching local variables first */
  1273. X   v = locals;
  1274. X   while (v) {
  1275. X      if (StrinEq(str, v->name, VAR_NAME_LEN))
  1276. X     return CopyValue(val, &v->v);
  1277. X      v = v->next;
  1278. X   }
  1279. X
  1280. X   v=FindVar(str, 0);
  1281. X
  1282. X   if (!v) {
  1283. X     Eprint("Undefined variable: %s", str);
  1284. X     return E_NOSUCH_VAR;
  1285. X   }
  1286. X   return CopyValue(val, &v->v);
  1287. X}
  1288. X
  1289. X/***************************************************************/
  1290. X/*                                                             */
  1291. X/*  DoSet - set a variable.                                    */
  1292. X/*                                                             */
  1293. X/***************************************************************/
  1294. X#ifdef HAVE_PROTOS
  1295. XPUBLIC int DoSet (Parser *p)
  1296. X#else
  1297. Xint DoSet (p)
  1298. XParser *p;
  1299. X#endif
  1300. X{
  1301. X   Value v;
  1302. X   int r;
  1303. X
  1304. X   r = ParseIdentifier(p, TokBuffer);
  1305. X   if (r) return r;
  1306. X
  1307. X   r = EvaluateExpr(p, &v);
  1308. X   if (r) return r;
  1309. X
  1310. X   r = SetVar(TokBuffer, &v);
  1311. X
  1312. X   return r;
  1313. X}
  1314. X
  1315. X/***************************************************************/
  1316. X/*                                                             */
  1317. X/*  DoUnset - delete a bunch of variables.                     */
  1318. X/*                                                             */
  1319. X/***************************************************************/
  1320. X#ifdef HAVE_PROTOS
  1321. XPUBLIC int DoUnset (Parser *p)
  1322. X#else
  1323. Xint DoUnset (p)
  1324. XParser *p;
  1325. X#endif
  1326. X{
  1327. X   int r;
  1328. X
  1329. X   r = ParseToken(p, TokBuffer);
  1330. X   if (r) return r;
  1331. X   if (!*TokBuffer) return E_EOLN;
  1332. X
  1333. X   (void) DeleteVar(TokBuffer);  /* Ignore error - nosuchvar */
  1334. X
  1335. X/* Keep going... */
  1336. X   while(1) {
  1337. X      r = ParseToken(p, TokBuffer);
  1338. X      if (r) return r;
  1339. X      if (!*TokBuffer) return OK;
  1340. X      (void) DeleteVar(TokBuffer);
  1341. X   }
  1342. X}
  1343. X
  1344. X/***************************************************************/
  1345. X/*                                                             */
  1346. X/*  DoDump                                                     */
  1347. X/*                                                             */
  1348. X/*  Command file command to dump variable table.               */
  1349. X/*                                                             */
  1350. X/***************************************************************/
  1351. X#ifdef HAVE_PROTOS
  1352. XPUBLIC int DoDump(ParsePtr p)
  1353. X#else
  1354. Xint DoDump(p)
  1355. XParsePtr p;
  1356. X#endif
  1357. X{
  1358. X   int r;
  1359. X   Var *v;
  1360. X
  1361. X   r = ParseToken(p, TokBuffer);
  1362. X   if (r) return r;
  1363. X   if (!*TokBuffer || *TokBuffer == '#' || *TokBuffer == ';') {
  1364. X      DumpVarTable();
  1365. X      return OK;
  1366. X   }
  1367. X   fprintf(ErrFp, "%*s  %s\n\n", VAR_NAME_LEN, "Variable", "Value");
  1368. X   while(1) {
  1369. X      v = FindVar(TokBuffer, 0);
  1370. X      TokBuffer[VAR_NAME_LEN] = 0;
  1371. X      if (!v) fprintf(ErrFp, "%*s  *UNDEFINED*\n", VAR_NAME_LEN, TokBuffer);
  1372. X      else {
  1373. X         fprintf(ErrFp, "%*s  ", VAR_NAME_LEN, v->name);
  1374. X         PrintValue(&(v->v), ErrFp);
  1375. X     fprintf(ErrFp, "\n");
  1376. X      }
  1377. X      r = ParseToken(p, TokBuffer);
  1378. X      if (r) return r;
  1379. X      if (!*TokBuffer || *TokBuffer == '#' || *TokBuffer == ';') return OK;
  1380. X   }
  1381. X}
  1382. X
  1383. X/***************************************************************/
  1384. X/*                                                             */
  1385. X/*  DumpVarTable                                               */
  1386. X/*                                                             */
  1387. X/*  Dump the variable table to stderr.                         */
  1388. X/*                                                             */
  1389. X/***************************************************************/
  1390. X#ifdef HAVE_PROTOS
  1391. XPUBLIC void DumpVarTable(void)
  1392. X#else
  1393. Xvoid DumpVarTable()
  1394. X#endif
  1395. X{
  1396. X   register Var *v;
  1397. X   register int i;
  1398. X
  1399. X   fprintf(ErrFp, "%*s  %s\n\n", VAR_NAME_LEN, "Variable", "Value");
  1400. X
  1401. X   for (i=0; i<VAR_HASH_SIZE; i++) {
  1402. X      v = VHashTbl[i];
  1403. X      while(v) {
  1404. X         fprintf(ErrFp, "%*s  ", VAR_NAME_LEN, v->name);
  1405. X         PrintValue(&(v->v), ErrFp);
  1406. X         fprintf(ErrFp, "\n");
  1407. X     v = v->next;
  1408. X      }
  1409. X   }
  1410. X}
  1411. X
  1412. X/***************************************************************/
  1413. X/*                                                             */
  1414. X/*  DestroyVars                                                */
  1415. X/*                                                             */
  1416. X/*  Free all the memory used by variables, but don't delete    */
  1417. X/*  preserved variables.                                       */
  1418. X/*                                                             */
  1419. X/***************************************************************/
  1420. X#ifdef HAVE_PROTOS
  1421. XPUBLIC void DestroyVars(void)
  1422. X#else
  1423. Xvoid DestroyVars()
  1424. X#endif
  1425. X{
  1426. X   int i;
  1427. X   Var *v, *next, *prev;
  1428. X
  1429. X   for (i=0; i<VAR_HASH_SIZE; i++) {
  1430. X      v = VHashTbl[i];
  1431. X      VHashTbl[i] = NULL;
  1432. X      prev = NULL;
  1433. X      while(v) {
  1434. X         if (!v->preserve) {
  1435. X            DestroyValue(&(v->v));
  1436. X           next = v->next;
  1437. X        free(v);
  1438. X     } else {
  1439. X        if (prev) prev->next = v;
  1440. X        else VHashTbl[i] = v;
  1441. X        prev = v;
  1442. X        next = v->next;
  1443. X        v->next = NULL;
  1444. X         }
  1445. X     v = next;
  1446. X      }
  1447. X   }
  1448. X}
  1449. X
  1450. X/***************************************************************/
  1451. X/*                                                             */
  1452. X/*  PreserveVar                                                */
  1453. X/*                                                             */
  1454. X/*  Given the name of a variable, "preserve" it.               */
  1455. X/*                                                             */
  1456. X/***************************************************************/
  1457. X#ifdef HAVE_PROTOS
  1458. XPUBLIC int PreserveVar(char *name)
  1459. X#else
  1460. Xint PreserveVar(name)
  1461. Xchar *name;
  1462. X#endif
  1463. X{
  1464. X   Var *v;
  1465. X
  1466. X   v = FindVar(name, 1);
  1467. X   if (!v) return E_NO_MEM;
  1468. X   v->preserve = 1;
  1469. X   return OK;
  1470. X}
  1471. X
  1472. X/***************************************************************/
  1473. X/*                                                             */
  1474. X/*  DoPreserve - delete a bunch of variables.                  */
  1475. X/*                                                             */
  1476. X/***************************************************************/
  1477. X#ifdef HAVE_PROTOS
  1478. XPUBLIC int DoPreserve (Parser *p)
  1479. X#else
  1480. Xint DoPreserve (p)
  1481. XParser *p;
  1482. X#endif
  1483. X{
  1484. X   int r;
  1485. X
  1486. X   r = ParseToken(p, TokBuffer);
  1487. X   if (r) return r;
  1488. X   if (!*TokBuffer) return E_EOLN;
  1489. X
  1490. X   r = PreserveVar(TokBuffer);
  1491. X   if (r) return r;
  1492. X
  1493. X/* Keep going... */
  1494. X   while(1) {
  1495. X      r = ParseToken(p, TokBuffer);
  1496. X      if (r) return r;
  1497. X      if (!*TokBuffer) return OK;
  1498. X      r = PreserveVar(TokBuffer);
  1499. X      if (r) return r;
  1500. X   }
  1501. X}
  1502. X
  1503. SHAR_EOF
  1504. $TOUCH -am 1109141292 var.c &&
  1505. chmod 0600 var.c ||
  1506. echo "restore of var.c failed"
  1507. set `wc -c var.c`;Wc_c=$1
  1508. if test "$Wc_c" != "11570"; then
  1509.     echo original size 11570, current size $Wc_c
  1510. fi
  1511. fi
  1512. echo "End of part 9, continue with part 10"
  1513. exit 0
  1514.  
  1515. exit 0 # Just in case...
  1516.