home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / var.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  12.9 KB  |  650 lines

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