home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / remind / src / var.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-14  |  20.2 KB  |  655 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  VAR.C                                                      */
  4. /*                                                             */
  5. /*  This file contains routines, structures, etc for           */
  6. /*  user- and system-defined variables.                        */
  7. /*                                                             */
  8. /*  This file is part of REMIND.                               */
  9. /*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  10. /*                                                             */
  11. /***************************************************************/
  12.  
  13. #include "config.h"
  14. #include <stdio.h>
  15. #include <string.h>
  16. #ifdef HAVE_STDLIB_H
  17. #include <stdlib.h>
  18. #endif
  19. #ifdef HAVE_MALLOC_H
  20. #include <malloc.h>
  21. #endif
  22. #include <ctype.h>
  23. #include "types.h"
  24. #include "expr.h"
  25. #include "globals.h"
  26. #include "protos.h"
  27. #include "err.h"
  28.  
  29. #define UPPER(c) (islower(c) ? toupper(c) : c)
  30.  
  31. /* The variable hash table */
  32. #define VAR_HASH_SIZE 64
  33. #define VARIABLE ErrMsg[E_VAR]
  34. #define VALUE    ErrMsg[E_VAL]
  35. #define UNDEF     ErrMsg[E_UNDEF]
  36.  
  37. static Var *VHashTbl[VAR_HASH_SIZE];
  38.  
  39. /***************************************************************/
  40. /*                                                             */
  41. /*  HashVal                                                    */
  42. /*  Given a string, compute the hash value.                    */
  43. /*                                                             */
  44. /***************************************************************/
  45. #ifdef HAVE_PROTOS
  46. PUBLIC unsigned int HashVal(const char *str)
  47. #else
  48. unsigned int HashVal(str)
  49. char *str;
  50. #endif
  51. {
  52.    register unsigned int i=0;
  53.    register unsigned int j=1;
  54.    register unsigned int len=0;
  55.  
  56.    while(*str && len < VAR_NAME_LEN) {
  57.       i += j * (unsigned int) UPPER(*str);
  58.       str++;
  59.       len++;
  60.       j = 3-j;
  61.    }
  62.    return i;
  63. }
  64.  
  65. /***************************************************************/
  66. /*                                                             */
  67. /*  FindVar                                                    */
  68. /*  Given a string, find the variable whose name is that       */
  69. /*  string.  If create is 1, create the variable.              */
  70. /*                                                             */
  71. /***************************************************************/
  72. #ifdef HAVE_PROTOS
  73. PUBLIC Var *FindVar(const char *str, int create)
  74. #else
  75. Var *FindVar(str, create)
  76. char *str;
  77. int create;
  78. #endif
  79. {
  80.    register int h;
  81.    register Var *v;
  82.    register Var *prev;
  83.  
  84.    h = HashVal(str) % VAR_HASH_SIZE;
  85.    v = VHashTbl[h];
  86.    prev = NULL;
  87.  
  88.    while(v) {
  89.       if (! StrinCmp(str, v->name, VAR_NAME_LEN)) return v;
  90.       prev = v;
  91.       v = v-> next;
  92.    }
  93.    if (!create) return v;
  94.  
  95. /* Create the variable */
  96.    v = NEW(Var);
  97.    if (!v) return v;
  98.    v->next = NULL;
  99.    v->v.type = INT_TYPE;
  100.    v->v.v.val = 0;
  101.    v->preserve = 0;
  102.    StrnCpy(v->name, str, VAR_NAME_LEN);
  103.  
  104.    if (prev) prev->next = v; else VHashTbl[h] = v;
  105.    return v;
  106. }
  107.  
  108. /***************************************************************/
  109. /*                                                             */
  110. /*  DeleteVar                                                  */
  111. /*  Given a string, find the variable whose name is that       */
  112. /*  string and delete it.                                      */
  113. /*                                                             */
  114. /***************************************************************/
  115. #ifdef HAVE_PROTOS
  116. PUBLIC int DeleteVar(const char *str)
  117. #else
  118. int DeleteVar(str)
  119. char *str;
  120. #endif
  121. {
  122.    register int h;
  123.    register Var *v;
  124.    register Var *prev;
  125.  
  126.    h = HashVal(str) % VAR_HASH_SIZE;
  127.    v = VHashTbl[h];
  128.    prev = NULL;
  129.  
  130.    while(v) {
  131.       if (! StrinCmp(str, v->name, VAR_NAME_LEN)) break;
  132.       prev = v;
  133.       v = v-> next;
  134.    }
  135.    if (!v) return E_NOSUCH_VAR;
  136.    DestroyValue(&(v->v));
  137.    if (prev) prev->next = v->next; else VHashTbl[h] = v->next;
  138.    free(v);
  139.    return OK;
  140. }
  141.  
  142. /***************************************************************/
  143. /*                                                             */
  144. /*  SetVar                                                     */
  145. /*                                                             */
  146. /*  Set the indicate variable to the specified value.          */
  147. /*                                                             */
  148. /***************************************************************/
  149. #ifdef HAVE_PROTOS
  150. PUBLIC int SetVar(const char *str, Value *val)
  151. #else
  152. int SetVar(str, val)
  153. char *str;
  154. Value *val;
  155. #endif
  156. {
  157.    Var *v = FindVar(str, 1);
  158.  
  159.    if (!v) return E_NO_MEM;  /* Only way FindVar can fail */
  160.  
  161.    DestroyValue(&(v->v));
  162.    v->v = *val;
  163.    return OK;
  164. }
  165.  
  166. /***************************************************************/
  167. /*                                                             */
  168. /*  GetVarValue                                                */
  169. /*                                                             */
  170. /*  Get a copy of the value of the variable.                   */
  171. /*                                                             */
  172. /***************************************************************/
  173. #ifdef HAVE_PROTOS
  174. PUBLIC int GetVarValue(const char *str, Value *val, Var *locals)
  175. #else
  176. int GetVarValue(str, val, locals)
  177. char *str;
  178. Value *val;
  179. Var *locals;
  180. #endif
  181. {
  182.    Var *v;
  183.  
  184.    /* Try searching local variables first */
  185.    v = locals;
  186.    while (v) {
  187.       if (! StrinCmp(str, v->name, VAR_NAME_LEN))
  188.      return CopyValue(val, &v->v);
  189.       v = v->next;
  190.    }
  191.  
  192.    v=FindVar(str, 0);
  193.  
  194.    if (!v) {
  195.      Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str);
  196.      return E_NOSUCH_VAR;
  197.    }
  198.    return CopyValue(val, &v->v);
  199. }
  200.  
  201. /***************************************************************/
  202. /*                                                             */
  203. /*  DoSet - set a variable.                                    */
  204. /*                                                             */
  205. /***************************************************************/
  206. #ifdef HAVE_PROTOS
  207. PUBLIC int DoSet (Parser *p)
  208. #else
  209. int DoSet (p)
  210. Parser *p;
  211. #endif
  212. {
  213.    Value v;
  214.    int r;
  215.  
  216.    r = ParseIdentifier(p, TokBuffer);
  217.    if (r) return r;
  218.  
  219.    r = EvaluateExpr(p, &v);
  220.    if (r) return r;
  221.  
  222.    if (*TokBuffer == '$') return SetSysVar(TokBuffer+1, &v);
  223.    else return SetVar(TokBuffer, &v);
  224. }
  225.  
  226. /***************************************************************/
  227. /*                                                             */
  228. /*  DoUnset - delete a bunch of variables.                     */
  229. /*                                                             */
  230. /***************************************************************/
  231. #ifdef HAVE_PROTOS
  232. PUBLIC int DoUnset (Parser *p)
  233. #else
  234. int DoUnset (p)
  235. Parser *p;
  236. #endif
  237. {
  238.    int r;
  239.  
  240.    r = ParseToken(p, TokBuffer);
  241.    if (r) return r;
  242.    if (!*TokBuffer) return E_EOLN;
  243.  
  244.    (void) DeleteVar(TokBuffer);  /* Ignore error - nosuchvar */
  245.  
  246. /* Keep going... */
  247.    while(1) {
  248.       r = ParseToken(p, TokBuffer);
  249.       if (r) return r;
  250.       if (!*TokBuffer) return OK;
  251.       (void) DeleteVar(TokBuffer);
  252.    }
  253. }
  254.  
  255. /***************************************************************/
  256. /*                                                             */
  257. /*  DoDump                                                     */
  258. /*                                                             */
  259. /*  Command file command to dump variable table.               */
  260. /*                                                             */
  261. /***************************************************************/
  262. #ifdef HAVE_PROTOS
  263. PUBLIC int DoDump(ParsePtr p)
  264. #else
  265. int DoDump(p)
  266. ParsePtr p;
  267. #endif
  268. {
  269.    int r;
  270.    Var *v;
  271.  
  272.    r = ParseToken(p, TokBuffer);
  273.    if (r) return r;
  274.    if (!*TokBuffer || *TokBuffer == '#' || *TokBuffer == ';') {
  275.       DumpVarTable();
  276.       return OK;
  277.    }
  278.    fprintf(ErrFp, "%*s  %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
  279.    while(1) {
  280.       if (*TokBuffer == '$') {
  281.          DumpSysVarByName(TokBuffer+1);
  282.       } else {
  283.          v = FindVar(TokBuffer, 0);
  284.          TokBuffer[VAR_NAME_LEN] = 0;
  285.          if (!v) fprintf(ErrFp, "%*s  %s\n", VAR_NAME_LEN, TokBuffer, UNDEF);
  286.          else {
  287.             fprintf(ErrFp, "%*s  ", VAR_NAME_LEN, v->name);
  288.             PrintValue(&(v->v), ErrFp);
  289.             fprintf(ErrFp, "\n");
  290.          }
  291.       }
  292.       r = ParseToken(p, TokBuffer);
  293.       if (r) return r;
  294.       if (!*TokBuffer || *TokBuffer == '#' || *TokBuffer == ';') return OK;
  295.    }
  296. }
  297.  
  298. /***************************************************************/
  299. /*                                                             */
  300. /*  DumpVarTable                                               */
  301. /*                                                             */
  302. /*  Dump the variable table to stderr.                         */
  303. /*                                                             */
  304. /***************************************************************/
  305. #ifdef HAVE_PROTOS
  306. PUBLIC void DumpVarTable(void)
  307. #else
  308. void DumpVarTable()
  309. #endif
  310. {
  311.    register Var *v;
  312.    register int i;
  313.  
  314.    fprintf(ErrFp, "%*s  %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
  315.  
  316.    for (i=0; i<VAR_HASH_SIZE; i++) {
  317.       v = VHashTbl[i];
  318.       while(v) {
  319.          fprintf(ErrFp, "%*s  ", VAR_NAME_LEN, v->name);
  320.          PrintValue(&(v->v), ErrFp);
  321.          fprintf(ErrFp, "\n");
  322.      v = v->next;
  323.       }
  324.    }
  325. }
  326.  
  327. /***************************************************************/
  328. /*                                                             */
  329. /*  DestroyVars                                                */
  330. /*                                                             */
  331. /*  Free all the memory used by variables, but don't delete    */
  332. /*  preserved variables unless ALL is non-zero.                */
  333. /*                                                             */
  334. /***************************************************************/
  335. #ifdef HAVE_PROTOS
  336. PUBLIC void DestroyVars(int all)
  337. #else
  338. void DestroyVars(all)
  339. int all;
  340. #endif
  341. {
  342.    int i;
  343.    Var *v, *next, *prev;
  344.  
  345.    for (i=0; i<VAR_HASH_SIZE; i++) {
  346.       v = VHashTbl[i];
  347.       VHashTbl[i] = NULL;
  348.       prev = NULL;
  349.       while(v) {
  350.          if (all || !v->preserve) {
  351.             DestroyValue(&(v->v));
  352.            next = v->next;
  353.         free(v);
  354.      } else {
  355.         if (prev) prev->next = v;
  356.         else VHashTbl[i] = v;
  357.         prev = v;
  358.         next = v->next;
  359.         v->next = NULL;
  360.          }
  361.      v = next;
  362.       }
  363.    }
  364. }
  365.  
  366. /***************************************************************/
  367. /*                                                             */
  368. /*  PreserveVar                                                */
  369. /*                                                             */
  370. /*  Given the name of a variable, "preserve" it.               */
  371. /*                                                             */
  372. /***************************************************************/
  373. #ifdef HAVE_PROTOS
  374. PUBLIC int PreserveVar(char *name)
  375. #else
  376. int PreserveVar(name)
  377. char *name;
  378. #endif
  379. {
  380.    Var *v;
  381.  
  382.    v = FindVar(name, 1);
  383.    if (!v) return E_NO_MEM;
  384.    v->preserve = 1;
  385.    return OK;
  386. }
  387.  
  388. /***************************************************************/
  389. /*                                                             */
  390. /*  DoPreserve - preserve a bunch of variables.                */
  391. /*                                                             */
  392. /***************************************************************/
  393. #ifdef HAVE_PROTOS
  394. PUBLIC int DoPreserve (Parser *p)
  395. #else
  396. int DoPreserve (p)
  397. Parser *p;
  398. #endif
  399. {
  400.    int r;
  401.  
  402.    r = ParseToken(p, TokBuffer);
  403.    if (r) return r;
  404.    if (!*TokBuffer) return E_EOLN;
  405.  
  406.    r = PreserveVar(TokBuffer);
  407.    if (r) return r;
  408.  
  409. /* Keep going... */
  410.    while(1) {
  411.       r = ParseToken(p, TokBuffer);
  412.       if (r) return r;
  413.       if (!*TokBuffer) return OK;
  414.       r = PreserveVar(TokBuffer);
  415.       if (r) return r;
  416.    }
  417. }
  418.  
  419. /***************************************************************/
  420. /*                                                             */
  421. /*  SYSTEM VARIABLES                                           */
  422. /*                                                             */
  423. /*  Interface for modifying and reading system variables.      */
  424. /*                                                             */
  425. /*  All system variables are of type "INT".                    */
  426. /*                                                             */
  427. /***************************************************************/
  428.  
  429. /* The structure of a system variable */
  430. typedef struct {
  431.    char *name;
  432.    char modifiable;
  433.    int type;
  434.    void *value;
  435.    int min;
  436.    int max;
  437. } SysVar;
  438.  
  439. /* If the type of a sys variable is STR_TYPE, then min is redefined
  440.    to be a flag indicating whether or not the value has been malloc'd. */
  441. #define been_malloced min
  442.  
  443. /* Flag for no min/max constraint */
  444. #define ANY 4532
  445. /* All of the system variables sorted alphabetically */
  446. static SysVar SysVarArr[] = {
  447.        /* name          mod    type        value        min/mal    max */
  448.    {   "CalcUTC",      1,    INT_TYPE,    &CalculateUTC,    0,    1   },
  449.    {   "CalMode",      0,    INT_TYPE,    &DoCalendar,    0,    0   },
  450.    {   "Daemon",      0,    INT_TYPE,    &Daemon,    0,    0   },
  451.    {   "DontFork",      0,    INT_TYPE,    &DontFork,    0,    0   },
  452.    {   "DontQueue",      0,    INT_TYPE,    &DontQueue,    0,    0   },
  453.    {   "DontTrigAts",      0,    INT_TYPE,    &DontIssueAts,    0,    0   },
  454.    {   "EndSent",      1,    STR_TYPE,    &EndSent,    0,    0   },
  455.    {   "EndSentIg",      1,    STR_TYPE,    &EndSentIg,    0,    0   },
  456.    {   "FirstIndent",      1,    INT_TYPE,    &FirstIndent,    0,    132 },
  457.    {   "FoldYear",      1,    INT_TYPE,    &FoldYear,    0,    1   },
  458.    {   "FormWidth",      1,    INT_TYPE,    &FormWidth,    20,    132 },
  459.    {   "HushMode",      0,    INT_TYPE,    &Hush,        0,    0   },
  460.    {   "IgnoreOnce",      0,    INT_TYPE,    &IgnoreOnce,    0,    0   },
  461.    {   "InfDelta",      0,    INT_TYPE,    &InfiniteDelta,    0,    0   },
  462.    {   "LatDeg",      1,    INT_TYPE,    &LatDeg,    -90,    90  },
  463.    {   "LatMin",      1,    INT_TYPE,    &LatMin,    -59,    59  },
  464.    {   "LatSec",      1,    INT_TYPE,    &LatSec,    -59,    59  },
  465.    {   "Location",      1,    STR_TYPE,    &Location,    0,    0   },
  466.    {   "LongDeg",      1,    INT_TYPE,    &LongDeg,    -180,    180  },
  467.    {   "LongMin",      1,    INT_TYPE,    &LongMin,    -59,    59  },
  468.    {   "LongSec",      1,    INT_TYPE,    &LongSec,    -59,    59  },
  469.    {   "MaxSatIter",      1,    INT_TYPE,    &MaxSatIter,    10,    ANY },
  470.    {   "MinsFromUTC",      1,    INT_TYPE,    &MinsFromUTC,    -13*60,    13*60 },
  471.    {   "NextMode",      0,    INT_TYPE,    &NextMode,    0,    0   },
  472.    {   "NumQueued",      0,    INT_TYPE,    &NumQueued,    0,    0   },
  473.    {   "NumTrig",      0,    INT_TYPE,    &NumTriggered,    0,    0   },
  474.    {   "PSCal",          0,    INT_TYPE,    &PsCal,        0,    0   },
  475.    {   "RunOff",      0,    INT_TYPE,    &RunDisabled,    0,    0   },
  476.    {   "SimpleCal",      0,    INT_TYPE,    &DoSimpleCalendar,    0,  0 },
  477.    {   "SortByDate",      0,    INT_TYPE,    &SortByDate,    0,    0},
  478.    {   "SortByPrio",      0,    INT_TYPE,    &SortByPrio,    0,    0},
  479.    {   "SortByTime",      0,    INT_TYPE,    &SortByTime,    0,    0},
  480.    {   "SubsIndent",      1,    INT_TYPE,    &SubsIndent,    0,    132}
  481. };
  482.  
  483. #define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
  484. PRIVATE SysVar *FindSysVar ARGS((const char *name));
  485. PRIVATE void DumpSysVar ARGS((const char *name, const SysVar *v));
  486. /***************************************************************/
  487. /*                                                             */
  488. /*  SetSysVar                                                  */
  489. /*                                                             */
  490. /*  Set a system variable to the indicated value.              */
  491. /*                                                             */
  492. /***************************************************************/
  493. #ifdef HAVE_PROTOS
  494. PUBLIC int SetSysVar(const char *name, Value *value)
  495. #else
  496. int SetSysVar(name, value)
  497. char *name;
  498. Value *value;
  499. #endif
  500. {
  501.    SysVar *v = FindSysVar(name);
  502.    if (!v) return E_NOSUCH_VAR;
  503.    if (v->type != value->type) return E_BAD_TYPE;
  504.    if (!v->modifiable) {
  505.       Eprint("%s: '$%s'", ErrMsg[E_CANT_MODIFY], name);
  506.       return E_CANT_MODIFY;
  507.    }
  508.  
  509. /* If it's a string variable, special measures must be taken */
  510.    if (v->type == STR_TYPE) {
  511.       if (v->been_malloced) free(*((char **)(v->value)));
  512.       v->been_malloced = 1;
  513.       *((char **) v->value) = value->v.str;
  514.       value->type = ERR_TYPE;  /* So that it's not accidentally freed */
  515.    } else {
  516.       if (v->max != ANY && value->v.val > v->max) return E_2HIGH;
  517.       if (v->min != ANY && value->v.val < v->min) return E_2LOW;
  518.       *((int *)v->value) = value->v.val;
  519.    }
  520.    return OK;
  521. }
  522.  
  523. /***************************************************************/
  524. /*                                                             */
  525. /*  GetSysVar                                                  */
  526. /*                                                             */
  527. /*  Get the value of a system variable                         */
  528. /*                                                             */
  529. /***************************************************************/
  530. #ifdef HAVE_PROTOS
  531. PUBLIC int GetSysVar(const char *name, Value *val)
  532. #else
  533. int GetSysVar(name, val)
  534. char *name;
  535. Value *val;
  536. #endif
  537. {
  538.    SysVar *v = FindSysVar(name);
  539.  
  540.    val->type = ERR_TYPE;
  541.    if (!v) return E_NOSUCH_VAR;
  542.    if (v->type == STR_TYPE) {
  543.       val->v.str = StrDup(*((char **) v->value));
  544.       if (!val->v.str) return E_NO_MEM;
  545.    } else {
  546.       val->v.val = *((int *) v->value);
  547.    }
  548.    val->type = v->type;
  549.    return OK;
  550. }
  551.  
  552. /***************************************************************/
  553. /*                                                             */
  554. /* FindSysVar                                                  */
  555. /*                                                             */
  556. /* Find a system var with specified name.                      */
  557. /*                                                             */
  558. /***************************************************************/
  559. #ifdef HAVE_PROTOS
  560. PRIVATE SysVar *FindSysVar(const char *name)
  561. #else
  562. static SysVar *FindSysVar(name)
  563. char *name;
  564. #endif
  565. {
  566.    int top=NUMSYSVARS-1, bottom=0;
  567.    int mid=(top + bottom) / 2;
  568.    int r;
  569.  
  570.    while (top >= bottom) {
  571.       r = StrCmpi(name, SysVarArr[mid].name);
  572.       if (!r) return &SysVarArr[mid];
  573.       else if (r>0) bottom = mid+1;
  574.       else        top = mid-1;
  575.       mid = (top+bottom) / 2;
  576.    }
  577.    return NULL;
  578. }
  579.    
  580. /***************************************************************/
  581. /*                                                             */
  582. /*  DumpSysVarByName                                           */
  583. /*                                                             */
  584. /*  Given the name of a system variable, display it.           */
  585. /*  If name is "", dump all system variables.                  */
  586. /*                                                             */
  587. /***************************************************************/
  588. #ifdef HAVE_PROTOS
  589. PUBLIC void DumpSysVarByName(const char *name)
  590. #else
  591. void DumpSysVarByName(name)
  592. char *name;
  593. #endif
  594. {
  595.    int i;
  596.    SysVar *v;
  597.  
  598.    if (!name || !*name) {
  599.       for (i=0; i<NUMSYSVARS; i++) DumpSysVar(name, SysVarArr + i);
  600.       return;
  601.    }
  602.    
  603.    v = FindSysVar(name);
  604.    DumpSysVar(name, v);
  605.    return;
  606. }
  607.  
  608. /***************************************************************/
  609. /*                                                             */
  610. /*  DumpSysVar                                                 */
  611. /*                                                             */
  612. /*  Dump the system variable.                                  */
  613. /*                                                             */
  614. /***************************************************************/
  615. #ifdef HAVE_PROTOS
  616. PRIVATE void DumpSysVar(const char *name, const SysVar *v)
  617. #else
  618. static void DumpSysVar(name, v)
  619. char *name;
  620. SysVar *v;
  621. #endif
  622. {
  623.    char buffer[VAR_NAME_LEN+10];
  624.  
  625.    if (name && !*name) name=NULL;
  626.    if (!v && !name) return;  /* Shouldn't happen... */
  627.    
  628.    buffer[0]='$'; buffer[1] = 0;
  629.    if (name) strcat(buffer, name); else strcat(buffer, v->name);
  630.    fprintf(ErrFp, "%*s  ", VAR_NAME_LEN, buffer);
  631.    if (v) {
  632.       if (v->type == STR_TYPE) {
  633.          char *s = *((char **)v->value);
  634.      int y;
  635.      putc('"', ErrFp);
  636.      for (y=0; y<MAX_PRT_LEN && *s; y++) putc(*s++, ErrFp);
  637.      putc('"', ErrFp);
  638.      if (*s) fprintf(ErrFp, "...");
  639.      putc('\n', ErrFp);
  640.       } else {
  641.          if (!v->modifiable) fprintf(ErrFp, "%d\n", *((int *)v->value));
  642.          else {
  643.             fprintf(ErrFp, "%-10d  ", *((int *)v->value));
  644.            if (v->min == ANY) fprintf(ErrFp, "(-Inf, ");
  645.         else                         fprintf(ErrFp, "[%d, ", v->min);
  646.         if (v->max == ANY) fprintf(ErrFp, "Inf)\n");
  647.         else                         fprintf(ErrFp, "%d]\n", v->max);
  648.          }
  649.       }
  650.    } else   fprintf(ErrFp, "%s\n", UNDEF);
  651.  
  652.    return;
  653. }
  654.  
  655.