Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $ */
  2.  
  3. /*-
  4.  * Copyright (c) 1991, 1993
  5.  *  The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Kenneth Almquist.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *  This product includes software developed by the University of
  21.  *  California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #include <sys/cdefs.h>
  40. #ifndef lint
  41. #if 0
  42. static char sccsid[] = "@(#)var.c   8.3 (Berkeley) 5/4/95";
  43. #else
  44. __RCSID("$NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $");
  45. #endif
  46. #endif /* not lint */
  47.  
  48. #include <unistd.h>
  49. #include <stdlib.h>
  50. #include <paths.h>
  51.  
  52. /*
  53.  * Shell variables.
  54.  */
  55.  
  56. #include "shell.h"
  57. #include "output.h"
  58. #include "expand.h"
  59. #include "nodes.h"  /* for other headers */
  60. #include "eval.h"   /* defines cmdenviron */
  61. #include "exec.h"
  62. #include "syntax.h"
  63. #include "options.h"
  64. #include "mail.h"
  65. #include "var.h"
  66. #include "memalloc.h"
  67. #include "error.h"
  68. #include "mystring.h"
  69. #include "parser.h"
  70. #ifndef SMALL
  71. #include "myhistedit.h"
  72. #endif
  73.  
  74.  
  75. #define VTABSIZE 39
  76.  
  77.  
  78. struct varinit {
  79.     struct var *var;
  80.     int flags;
  81.     const char *text;
  82.     void (*func) (const char *);
  83. };
  84.  
  85.  
  86. #if ATTY
  87. struct var vatty;
  88. #endif
  89. #ifndef SMALL
  90. struct var vhistsize;
  91. struct var vterm;
  92. #endif
  93. struct var vifs;
  94. struct var vmail;
  95. struct var vmpath;
  96. struct var vpath;
  97. struct var vps1;
  98. struct var vps2;
  99. struct var vvers;
  100. struct var voptind;
  101.  
  102. const struct varinit varinit[] = {
  103. #if ATTY
  104.     { &vatty,   VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY=",
  105.       NULL },
  106. #endif
  107. #ifndef SMALL
  108.     { &vhistsize,   VSTRFIXED|VTEXTFIXED|VUNSET,    "HISTSIZE=",
  109.       sethistsize },
  110. #endif
  111.     { &vifs,    VSTRFIXED|VTEXTFIXED,       "IFS= \t\n",
  112.       NULL },
  113.     { &vmail,   VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
  114.       NULL },
  115.     { &vmpath,  VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
  116.       NULL },
  117.     { &vpath,   VSTRFIXED|VTEXTFIXED,       "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  118.       changepath },
  119.     /*
  120.      * vps1 depends on uid
  121.      */
  122.     { &vps2,    VSTRFIXED|VTEXTFIXED,       "PS2=> ",
  123.       NULL },
  124. #ifndef SMALL
  125.     { &vterm,   VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM=",
  126.       setterm },
  127. #endif
  128.     { &voptind, VSTRFIXED|VTEXTFIXED,       "OPTIND=1",
  129.       getoptsreset },
  130.     { NULL, 0,              NULL,
  131.       NULL }
  132. };
  133.  
  134. struct var *vartab[VTABSIZE];
  135.  
  136. STATIC struct var **hashvar (const char *);
  137. STATIC int varequal (const char *, const char *);
  138.  
  139. /*
  140.  * Initialize the varable symbol tables and import the environment
  141.  * Setting PWD added by herbert
  142.  */
  143.  
  144. #ifdef mkinit
  145. INCLUDE "cd.h"
  146. INCLUDE "var.h"
  147. INIT {
  148.     char **envp;
  149.     extern char **environ;
  150.     extern char *curdir;
  151.  
  152.     initvar();
  153.     for (envp = environ ; *envp ; envp++) {
  154.         if (strchr(*envp, '=')) {
  155.             setvareq(*envp, VEXPORT|VTEXTFIXED);
  156.         }
  157.     }
  158.  
  159.     getpwd();
  160.     setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
  161. }
  162. #endif
  163.  
  164.  
  165. /*
  166.  * This routine initializes the builtin variables.  It is called when the
  167.  * shell is initialized and again when a shell procedure is spawned.
  168.  */
  169.  
  170. void
  171. initvar() {
  172.     const struct varinit *ip;
  173.     struct var *vp;
  174.     struct var **vpp;
  175.     char ppid[30];
  176.  
  177.     for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
  178.         if ((vp->flags & VEXPORT) == 0) {
  179.             vpp = hashvar(ip->text);
  180.             vp->next = *vpp;
  181.             *vpp = vp;
  182.             vp->text = strdup(ip->text);
  183.             vp->flags = ip->flags;
  184.             vp->func = ip->func;
  185.         }
  186.     }
  187.     /*
  188.      * PS1 depends on uid
  189.      */
  190.     if ((vps1.flags & VEXPORT) == 0) {
  191.         vpp = hashvar("PS1=");
  192.         vps1.next = *vpp;
  193.         *vpp = &vps1;
  194.         vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
  195.         vps1.flags = VSTRFIXED|VTEXTFIXED;
  196.     }
  197.    
  198.     snprintf(ppid, 29, "%ld", (long)getppid());
  199.     setvar("PPID", ppid, VREADONLY|VNOFUNC);
  200. }
  201.  
  202. /*
  203.  * Safe version of setvar, returns 1 on success 0 on failure.
  204.  */
  205.  
  206. int
  207. setvarsafe(name, val, flags)
  208.     const char *name, *val;
  209.     int flags;
  210. {
  211.     struct jmploc jmploc;
  212.     struct jmploc *volatile savehandler = handler;
  213.     int err = 0;
  214. #ifdef __GNUC__
  215.     (void) &err;
  216. #endif
  217.  
  218.     if (setjmp(jmploc.loc))
  219.         err = 1;
  220.     else {
  221.         handler = &jmploc;
  222.         setvar(name, val, flags);
  223.     }
  224.     handler = savehandler;
  225.     return err;
  226. }
  227.  
  228. /*
  229.  * Set the value of a variable.  The flags argument is ored with the
  230.  * flags of the variable.  If val is NULL, the variable is unset.
  231.  */
  232.  
  233. void
  234. setvar(name, val, flags)
  235.     const char *name, *val;
  236.     int flags;
  237. {
  238.     const char *p;
  239.     const char *q;
  240.     char *d;
  241.     int len;
  242.     int namelen;
  243.     char *nameeq;
  244.     int isbad;
  245.  
  246.     isbad = 0;
  247.     p = name;
  248.     if (! is_name(*p))
  249.         isbad = 1;
  250.     p++;
  251.     for (;;) {
  252.         if (! is_in_name(*p)) {
  253.             if (*p == '\0' || *p == '=')
  254.                 break;
  255.             isbad = 1;
  256.         }
  257.         p++;
  258.     }
  259.     namelen = p - name;
  260.     if (isbad)
  261.         error("%.*s: bad variable name", namelen, name);
  262.     len = namelen + 2;      /* 2 is space for '=' and '\0' */
  263.     if (val == NULL) {
  264.         flags |= VUNSET;
  265.     } else {
  266.         len += strlen(val);
  267.     }
  268.     d = nameeq = ckmalloc(len);
  269.     q = name;
  270.     while (--namelen >= 0)
  271.         *d++ = *q++;
  272.     *d++ = '=';
  273.     *d = '\0';
  274.     if (val)
  275.         scopy(val, d);
  276.     setvareq(nameeq, flags);
  277. }
  278.  
  279.  
  280.  
  281. /*
  282.  * Same as setvar except that the variable and value are passed in
  283.  * the first argument as name=value.  Since the first argument will
  284.  * be actually stored in the table, it should not be a string that
  285.  * will go away.
  286.  */
  287.  
  288. void
  289. setvareq(s, flags)
  290.     char *s;
  291.     int flags;
  292. {
  293.     struct var *vp, **vpp;
  294.  
  295.     vpp = hashvar(s);
  296.     flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
  297.     for (vp = *vpp ; vp ; vp = vp->next) {
  298.         if (varequal(s, vp->text)) {
  299.             if (vp->flags & VREADONLY) {
  300.                 size_t len = strchr(s, '=') - s;
  301.                 error("%.*s: is read only", len, s);
  302.             }
  303.             INTOFF;
  304.  
  305.             if (vp->func && (flags & VNOFUNC) == 0)
  306.                 (*vp->func)(strchr(s, '=') + 1);
  307.  
  308.             if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
  309.                 ckfree(vp->text);
  310.  
  311.             vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
  312.             vp->flags |= flags;
  313.             vp->text = s;
  314.  
  315.             /*
  316.              * We could roll this to a function, to handle it as
  317.              * a regular variable function callback, but why bother?
  318.              */
  319.             if (iflag &&
  320.                 (vp == &vmpath || (vp == &vmail && ! mpathset())))
  321.                 chkmail(1);
  322.             INTON;
  323.             return;
  324.         }
  325.     }
  326.     /* not found */
  327.     vp = ckmalloc(sizeof (*vp));
  328.     vp->flags = flags;
  329.     vp->text = s;
  330.     vp->next = *vpp;
  331.     vp->func = NULL;
  332.     *vpp = vp;
  333. }
  334.  
  335.  
  336.  
  337. /*
  338.  * Process a linked list of variable assignments.
  339.  */
  340.  
  341. void
  342. listsetvar(list)
  343.     struct strlist *list;
  344.     {
  345.     struct strlist *lp;
  346.  
  347.     INTOFF;
  348.     for (lp = list ; lp ; lp = lp->next) {
  349.         setvareq(savestr(lp->text), 0);
  350.     }
  351.     INTON;
  352. }
  353.  
  354.  
  355.  
  356. /*
  357.  * Find the value of a variable.  Returns NULL if not set.
  358.  */
  359.  
  360. char *
  361. lookupvar(name)
  362.     const char *name;
  363.     {
  364.     struct var *v;
  365.  
  366.     for (v = *hashvar(name) ; v ; v = v->next) {
  367.         if (varequal(v->text, name)) {
  368.             if (v->flags & VUNSET)
  369.                 return NULL;
  370.             return strchr(v->text, '=') + 1;
  371.         }
  372.     }
  373.     return NULL;
  374. }
  375.  
  376.  
  377.  
  378. /*
  379.  * Search the environment of a builtin command.  If the second argument
  380.  * is nonzero, return the value of a variable even if it hasn't been
  381.  * exported.
  382.  */
  383.  
  384. char *
  385. bltinlookup(name, doall)
  386.     const char *name;
  387.     int doall;
  388. {
  389.     struct strlist *sp;
  390.     struct var *v;
  391.  
  392.     for (sp = cmdenviron ; sp ; sp = sp->next) {
  393.         if (varequal(sp->text, name))
  394.             return strchr(sp->text, '=') + 1;
  395.     }
  396.     for (v = *hashvar(name) ; v ; v = v->next) {
  397.         if (varequal(v->text, name)) {
  398.             if ((v->flags & VUNSET)
  399.              || (!doall && (v->flags & VEXPORT) == 0))
  400.                 return NULL;
  401.             return strchr(v->text, '=') + 1;
  402.         }
  403.     }
  404.     return NULL;
  405. }
  406.  
  407.  
  408.  
  409. /*
  410.  * Generate a list of exported variables.  This routine is used to construct
  411.  * the third argument to execve when executing a program.
  412.  */
  413.  
  414. char **
  415. environment() {
  416.     int nenv;
  417.     struct var **vpp;
  418.     struct var *vp;
  419.     char **env;
  420.     char **ep;
  421.  
  422.     nenv = 0;
  423.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  424.         for (vp = *vpp ; vp ; vp = vp->next)
  425.             if (vp->flags & VEXPORT)
  426.                 nenv++;
  427.     }
  428.     ep = env = stalloc((nenv + 1) * sizeof *env);
  429.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  430.         for (vp = *vpp ; vp ; vp = vp->next)
  431.             if (vp->flags & VEXPORT)
  432.                 *ep++ = vp->text;
  433.     }
  434.     *ep = NULL;
  435.     return env;
  436. }
  437.  
  438.  
  439. /*
  440.  * Called when a shell procedure is invoked to clear out nonexported
  441.  * variables.  It is also necessary to reallocate variables of with
  442.  * VSTACK set since these are currently allocated on the stack.
  443.  */
  444.  
  445. #ifdef mkinit
  446. MKINIT void shprocvar (void);
  447.  
  448. SHELLPROC {
  449.     shprocvar();
  450. }
  451. #endif
  452.  
  453. void
  454. shprocvar() {
  455.     struct var **vpp;
  456.     struct var *vp, **prev;
  457.  
  458.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  459.         for (prev = vpp ; (vp = *prev) != NULL ; ) {
  460.             if ((vp->flags & VEXPORT) == 0) {
  461.                 *prev = vp->next;
  462.                 if ((vp->flags & VTEXTFIXED) == 0)
  463.                     ckfree(vp->text);
  464.                 if ((vp->flags & VSTRFIXED) == 0)
  465.                     ckfree(vp);
  466.             } else {
  467.                 if (vp->flags & VSTACK) {
  468.                     vp->text = savestr(vp->text);
  469.                     vp->flags &=~ VSTACK;
  470.                 }
  471.                 prev = &vp->next;
  472.             }
  473.         }
  474.     }
  475.     initvar();
  476. }
  477.  
  478.  
  479.  
  480. /*
  481.  * Command to list all variables which are set.  Currently this command
  482.  * is invoked from the set command when the set command is called without
  483.  * any variables.
  484.  */
  485.  
  486. int
  487. showvarscmd(argc, argv)
  488.     int argc;
  489.     char **argv;
  490. {
  491.     struct var **vpp;
  492.     struct var *vp;
  493.  
  494.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  495.         for (vp = *vpp ; vp ; vp = vp->next) {
  496.             if ((vp->flags & VUNSET) == 0)
  497.                 out1fmt("%s\n", vp->text);
  498.         }
  499.     }
  500.     return 0;
  501. }
  502.  
  503.  
  504.  
  505. /*
  506.  * The export and readonly commands.
  507.  */
  508.  
  509. int
  510. exportcmd(argc, argv)
  511.     int argc;
  512.     char **argv;
  513. {
  514.     struct var **vpp;
  515.     struct var *vp;
  516.     char *name;
  517.     const char *p;
  518.     int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
  519.     int pflag;
  520.  
  521.     listsetvar(cmdenviron);
  522.     pflag = (nextopt("p") == 'p');
  523.     if (argc > 1 && !pflag) {
  524.         while ((name = *argptr++) != NULL) {
  525.             if ((p = strchr(name, '=')) != NULL) {
  526.                 p++;
  527.             } else {
  528.                 vpp = hashvar(name);
  529.                 for (vp = *vpp ; vp ; vp = vp->next) {
  530.                     if (varequal(vp->text, name)) {
  531.                         vp->flags |= flag;
  532.                         goto found;
  533.                     }
  534.                 }
  535.             }
  536.             setvar(name, p, flag);
  537. found:;
  538.         }
  539.     } else {
  540.         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  541.             for (vp = *vpp ; vp ; vp = vp->next) {
  542.                 if ((vp->flags & flag) == 0)
  543.                     continue;
  544.                 if (pflag) {
  545.                     out1fmt("%s %s\n", argv[0], vp->text);
  546.                 } else {
  547.                     for (p = vp->text ; *p != '=' ; p++)
  548.                         out1c(*p);
  549.                     out1c('\n');
  550.                 }
  551.             }
  552.         }
  553.     }
  554.     return 0;
  555. }
  556.  
  557.  
  558. /*
  559.  * The "local" command.
  560.  */
  561.  
  562. int
  563. localcmd(argc, argv)
  564.     int argc;
  565.     char **argv;
  566. {
  567.     char *name;
  568.  
  569.     if (! in_function())
  570.         error("Not in a function");
  571.     while ((name = *argptr++) != NULL) {
  572.         mklocal(name);
  573.     }
  574.     return 0;
  575. }
  576.  
  577.  
  578. /*
  579.  * Make a variable a local variable.  When a variable is made local, it's
  580.  * value and flags are saved in a localvar structure.  The saved values
  581.  * will be restored when the shell function returns.  We handle the name
  582.  * "-" as a special case.
  583.  */
  584.  
  585. void
  586. mklocal(name)
  587.     char *name;
  588.     {
  589.     struct localvar *lvp;
  590.     struct var **vpp;
  591.     struct var *vp;
  592.  
  593.     INTOFF;
  594.     lvp = ckmalloc(sizeof (struct localvar));
  595.     if (name[0] == '-' && name[1] == '\0') {
  596.         char *p;
  597.         p = ckmalloc(sizeof optlist);
  598.         lvp->text = memcpy(p, optlist, sizeof optlist);
  599.         vp = NULL;
  600.     } else {
  601.         vpp = hashvar(name);
  602.         for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
  603.         if (vp == NULL) {
  604.             if (strchr(name, '='))
  605.                 setvareq(savestr(name), VSTRFIXED);
  606.             else
  607.                 setvar(name, NULL, VSTRFIXED);
  608.             vp = *vpp;  /* the new variable */
  609.             lvp->text = NULL;
  610.             lvp->flags = VUNSET;
  611.         } else {
  612.             lvp->text = vp->text;
  613.             lvp->flags = vp->flags;
  614.             vp->flags |= VSTRFIXED|VTEXTFIXED;
  615.             if (strchr(name, '='))
  616.                 setvareq(savestr(name), 0);
  617.         }
  618.     }
  619.     lvp->vp = vp;
  620.     lvp->next = localvars;
  621.     localvars = lvp;
  622.     INTON;
  623. }
  624.  
  625.  
  626. /*
  627.  * Called after a function returns.
  628.  */
  629.  
  630. void
  631. poplocalvars() {
  632.     struct localvar *lvp;
  633.     struct var *vp;
  634.  
  635.     while ((lvp = localvars) != NULL) {
  636.         localvars = lvp->next;
  637.         vp = lvp->vp;
  638.         if (vp == NULL) {   /* $- saved */
  639.             memcpy(optlist, lvp->text, sizeof optlist);
  640.             ckfree(lvp->text);
  641.         } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
  642.             (void)unsetvar(vp->text);
  643.         } else {
  644.             if ((vp->flags & VTEXTFIXED) == 0)
  645.                 ckfree(vp->text);
  646.             vp->flags = lvp->flags;
  647.             vp->text = lvp->text;
  648.         }
  649.         ckfree(lvp);
  650.     }
  651. }
  652.  
  653.  
  654. int
  655. setvarcmd(argc, argv)
  656.     int argc;
  657.     char **argv;
  658. {
  659.     if (argc <= 2)
  660.         return unsetcmd(argc, argv);
  661.     else if (argc == 3)
  662.         setvar(argv[1], argv[2], 0);
  663.     else
  664.         error("List assignment not implemented");
  665.     return 0;
  666. }
  667.  
  668.  
  669. /*
  670.  * The unset builtin command.  We unset the function before we unset the
  671.  * variable to allow a function to be unset when there is a readonly variable
  672.  * with the same name.
  673.  */
  674.  
  675. int
  676. unsetcmd(argc, argv)
  677.     int argc;
  678.     char **argv;
  679. {
  680.     char **ap;
  681.     int i;
  682.     int flg_func = 0;
  683.     int flg_var = 0;
  684.     int ret = 0;
  685.  
  686.     while ((i = nextopt("vf")) != '\0') {
  687.         if (i == 'f')
  688.             flg_func = 1;
  689.         else
  690.             flg_var = 1;
  691.     }
  692.     if (flg_func == 0 && flg_var == 0)
  693.         flg_var = 1;
  694.  
  695.     for (ap = argptr; *ap ; ap++) {
  696.         if (flg_func)
  697.             ret |= unsetfunc(*ap);
  698.         if (flg_var)
  699.             ret |= unsetvar(*ap);
  700.     }
  701.     return ret;
  702. }
  703.  
  704.  
  705. /*
  706.  * Unset the specified variable.
  707.  */
  708.  
  709. int
  710. unsetvar(s)
  711.     const char *s;
  712.     {
  713.     struct var **vpp;
  714.     struct var *vp;
  715.  
  716.     vpp = hashvar(s);
  717.     for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
  718.         if (varequal(vp->text, s)) {
  719.             if (vp->flags & VREADONLY)
  720.                 return (1);
  721.             INTOFF;
  722.             if (*(strchr(vp->text, '=') + 1) != '\0')
  723.                 setvar(s, nullstr, 0);
  724.             vp->flags &= ~VEXPORT;
  725.             vp->flags |= VUNSET;
  726.             if ((vp->flags & VSTRFIXED) == 0) {
  727.                 if ((vp->flags & VTEXTFIXED) == 0)
  728.                     ckfree(vp->text);
  729.                 *vpp = vp->next;
  730.                 ckfree(vp);
  731.             }
  732.             INTON;
  733.             return (0);
  734.         }
  735.     }
  736.  
  737.     return (1);
  738. }
  739.  
  740.  
  741.  
  742. /*
  743.  * Find the appropriate entry in the hash table from the name.
  744.  */
  745.  
  746. STATIC struct var **
  747. hashvar(p)
  748.     const char *p;
  749.     {
  750.     unsigned int hashval;
  751.  
  752.     hashval = ((unsigned char) *p) << 4;
  753.     while (*p && *p != '=')
  754.         hashval += (unsigned char) *p++;
  755.     return &vartab[hashval % VTABSIZE];
  756. }
  757.  
  758.  
  759.  
  760. /*
  761.  * Returns true if the two strings specify the same varable.  The first
  762.  * variable name is terminated by '='; the second may be terminated by
  763.  * either '=' or '\0'.
  764.  */
  765.  
  766. STATIC int
  767. varequal(p, q)
  768.     const char *p, *q;
  769.     {
  770.     while (*p == *q++) {
  771.         if (*p++ == '=')
  772.             return 1;
  773.     }
  774.     if (*p == '=' && *(q - 1) == '\0')
  775.         return 1;
  776.     return 0;
  777. }
  778.