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

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