var.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)var.c       5.3 (Berkeley) 4/12/91";
00039 #endif /* not lint */
00040 
00041 /*
00042  * Shell variables.
00043  */
00044 
00045 #include "shell.h"
00046 #include "output.h"
00047 #include "expand.h"
00048 #include "nodes.h"      /* for other headers */
00049 #include "eval.h"       /* defines cmdenviron */
00050 #include "exec.h"
00051 #include "syntax.h"
00052 #include "options.h"
00053 #include "mail.h"
00054 #include "var.h"
00055 #include "memalloc.h"
00056 #include "error.h"
00057 #include "mystring.h"
00058 
00059 
00060 #define VTABSIZE 39
00061 
00062 
00063 struct varinit {
00064         struct var *var;
00065         int flags;
00066         char *text;
00067 };
00068 
00069 
00070 #if ATTY
00071 struct var vatty;
00072 #endif
00073 struct var vifs;
00074 struct var vmail;
00075 struct var vmpath;
00076 struct var vpath;
00077 struct var vps1;
00078 struct var vps2;
00079 struct var vpse;
00080 struct var vvers;
00081 #if ATTY
00082 struct var vterm;
00083 #endif
00084 
00085 const struct varinit varinit[] = {
00086 #if ATTY
00087         {&vatty,        VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY="},
00088 #endif
00089         {&vifs, VSTRFIXED|VTEXTFIXED,           "IFS= \t\n"},
00090         {&vmail,        VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL="},
00091         {&vmpath,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH="},
00092         {&vpath,        VSTRFIXED|VTEXTFIXED,           "PATH=:/bin:/usr/bin"},
00093         /* 
00094          * vps1 depends on uid
00095          */
00096         {&vps2, VSTRFIXED|VTEXTFIXED,           "PS2=> "},
00097         {&vpse, VSTRFIXED|VTEXTFIXED,           "PSE=* "},
00098 #if ATTY
00099         {&vterm,        VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM="},
00100 #endif
00101         {NULL,  0,                              NULL}
00102 };
00103 
00104 struct var *vartab[VTABSIZE];
00105 
00106 STATIC void unsetvar __P((char *));
00107 STATIC struct var **hashvar __P((char *));
00108 STATIC int varequal __P((char *, char *));
00109 
00110 /*
00111  * Initialize the varable symbol tables and import the environment
00112  */
00113 
00114 #ifdef mkinit
00115 INCLUDE "var.h"
00116 INIT {
00117         char **envp;
00118         extern char **environ;
00119 
00120         initvar();
00121         for (envp = environ ; *envp ; envp++) {
00122                 if (strchr(*envp, '=')) {
00123                         setvareq(*envp, VEXPORT|VTEXTFIXED);
00124                 }
00125         }
00126 }
00127 #endif
00128 
00129 
00130 /*
00131  * This routine initializes the builtin variables.  It is called when the
00132  * shell is initialized and again when a shell procedure is spawned.
00133  */
00134 
00135 void
00136 initvar() {
00137         const struct varinit *ip;
00138         struct var *vp;
00139         struct var **vpp;
00140 
00141         for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
00142                 if ((vp->flags & VEXPORT) == 0) {
00143                         vpp = hashvar(ip->text);
00144                         vp->next = *vpp;
00145                         *vpp = vp;
00146                         vp->text = ip->text;
00147                         vp->flags = ip->flags;
00148                 }
00149         }
00150         /*
00151          * PS1 depends on uid
00152          */
00153         if ((vps1.flags & VEXPORT) == 0) {
00154                 vpp = hashvar("PS1=");
00155                 vps1.next = *vpp;
00156                 *vpp = &vps1;
00157                 vps1.text = getuid() ? "PS1=$ " : "PS1=# ";
00158                 vps1.flags = VSTRFIXED|VTEXTFIXED;
00159         }
00160 }
00161 
00162 /*
00163  * Set the value of a variable.  The flags argument is ored with the
00164  * flags of the variable.  If val is NULL, the variable is unset.
00165  */
00166 
00167 void
00168 setvar(name, val, flags)
00169         char *name, *val;
00170         {
00171         char *p, *q;
00172         int len;
00173         int namelen;
00174         char *nameeq;
00175         int isbad;
00176 
00177         isbad = 0;
00178         p = name;
00179         if (! is_name(*p++))
00180                 isbad = 1;
00181         for (;;) {
00182                 if (! is_in_name(*p)) {
00183                         if (*p == '\0' || *p == '=')
00184                                 break;
00185                         isbad = 1;
00186                 }
00187                 p++;
00188         }
00189         namelen = p - name;
00190         if (isbad)
00191                 error("%.*s: is read only", namelen, name);
00192         len = namelen + 2;              /* 2 is space for '=' and '\0' */
00193         if (val == NULL) {
00194                 flags |= VUNSET;
00195         } else {
00196                 len += strlen(val);
00197         }
00198         p = nameeq = ckmalloc(len);
00199         q = name;
00200         while (--namelen >= 0)
00201                 *p++ = *q++;
00202         *p++ = '=';
00203         *p = '\0';
00204         if (val)
00205                 scopy(val, p);
00206         setvareq(nameeq, flags);
00207 }
00208 
00209 
00210 
00211 /*
00212  * Same as setvar except that the variable and value are passed in
00213  * the first argument as name=value.  Since the first argument will
00214  * be actually stored in the table, it should not be a string that
00215  * will go away.
00216  */
00217 
00218 void
00219 setvareq(s, flags)
00220         char *s;
00221         {
00222         struct var *vp, **vpp;
00223 
00224         vpp = hashvar(s);
00225         for (vp = *vpp ; vp ; vp = vp->next) {
00226                 if (varequal(s, vp->text)) {
00227                         if (vp->flags & VREADONLY) {
00228                                 int len = strchr(s, '=') - s;
00229                                 error("%.*s: is read only", len, s);
00230                         }
00231                         INTOFF;
00232                         if (vp == &vpath)
00233                                 changepath(s + 5);      /* 5 = strlen("PATH=") */
00234                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
00235                                 ckfree(vp->text);
00236                         vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
00237                         vp->flags |= flags;
00238                         vp->text = s;
00239                         if (vp == &vmpath || (vp == &vmail && ! mpathset()))
00240                                 chkmail(1);
00241                         INTON;
00242                         return;
00243                 }
00244         }
00245         /* not found */
00246         vp = ckmalloc(sizeof (*vp));
00247         vp->flags = flags;
00248         vp->text = s;
00249         vp->next = *vpp;
00250         *vpp = vp;
00251 }
00252 
00253 
00254 
00255 /*
00256  * Process a linked list of variable assignments.
00257  */
00258 
00259 void
00260 listsetvar(list)
00261         struct strlist *list;
00262         {
00263         struct strlist *lp;
00264 
00265         INTOFF;
00266         for (lp = list ; lp ; lp = lp->next) {
00267                 setvareq(savestr(lp->text), 0);
00268         }
00269         INTON;
00270 }
00271 
00272 
00273 
00274 /*
00275  * Find the value of a variable.  Returns NULL if not set.
00276  */
00277 
00278 char *
00279 lookupvar(name)
00280         char *name;
00281         {
00282         struct var *v;
00283 
00284         for (v = *hashvar(name) ; v ; v = v->next) {
00285                 if (varequal(v->text, name)) {
00286                         if (v->flags & VUNSET)
00287                                 return NULL;
00288                         return strchr(v->text, '=') + 1;
00289                 }
00290         }
00291         return NULL;
00292 }
00293 
00294 
00295 
00296 /*
00297  * Search the environment of a builtin command.  If the second argument
00298  * is nonzero, return the value of a variable even if it hasn't been
00299  * exported.
00300  */
00301 
00302 char *
00303 bltinlookup(name, doall)
00304         char *name;
00305         {
00306         struct strlist *sp;
00307         struct var *v;
00308 
00309         for (sp = cmdenviron ; sp ; sp = sp->next) {
00310                 if (varequal(sp->text, name))
00311                         return strchr(sp->text, '=') + 1;
00312         }
00313         for (v = *hashvar(name) ; v ; v = v->next) {
00314                 if (varequal(v->text, name)) {
00315                         if (v->flags & VUNSET
00316                          || ! doall && (v->flags & VEXPORT) == 0)
00317                                 return NULL;
00318                         return strchr(v->text, '=') + 1;
00319                 }
00320         }
00321         return NULL;
00322 }
00323 
00324 
00325 
00326 /*
00327  * Generate a list of exported variables.  This routine is used to construct
00328  * the third argument to execve when executing a program.
00329  */
00330 
00331 char **
00332 environment() {
00333         int nenv;
00334         struct var **vpp;
00335         struct var *vp;
00336         char **env, **ep;
00337 
00338         nenv = 0;
00339         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00340                 for (vp = *vpp ; vp ; vp = vp->next)
00341                         if (vp->flags & VEXPORT)
00342                                 nenv++;
00343         }
00344         ep = env = stalloc((nenv + 1) * sizeof *env);
00345         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00346                 for (vp = *vpp ; vp ; vp = vp->next)
00347                         if (vp->flags & VEXPORT)
00348                                 *ep++ = vp->text;
00349         }
00350         *ep = NULL;
00351         return env;
00352 }
00353 
00354 
00355 /*
00356  * Called when a shell procedure is invoked to clear out nonexported
00357  * variables.  It is also necessary to reallocate variables of with
00358  * VSTACK set since these are currently allocated on the stack.
00359  */
00360 
00361 #ifdef mkinit
00362 MKINIT void shprocvar();
00363 
00364 SHELLPROC {
00365         shprocvar();
00366 }
00367 #endif
00368 
00369 void
00370 shprocvar() {
00371         struct var **vpp;
00372         struct var *vp, **prev;
00373 
00374         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00375                 for (prev = vpp ; (vp = *prev) != NULL ; ) {
00376                         if ((vp->flags & VEXPORT) == 0) {
00377                                 *prev = vp->next;
00378                                 if ((vp->flags & VTEXTFIXED) == 0)
00379                                         ckfree(vp->text);
00380                                 if ((vp->flags & VSTRFIXED) == 0)
00381                                         ckfree(vp);
00382                         } else {
00383                                 if (vp->flags & VSTACK) {
00384                                         vp->text = savestr(vp->text);
00385                                         vp->flags &=~ VSTACK;
00386                                 }
00387                                 prev = &vp->next;
00388                         }
00389                 }
00390         }
00391         initvar();
00392 }
00393 
00394 
00395 
00396 /*
00397  * Command to list all variables which are set.  Currently this command
00398  * is invoked from the set command when the set command is called without
00399  * any variables.
00400  */
00401 
00402 int
00403 showvarscmd(argc, argv)  char **argv; {
00404         struct var **vpp;
00405         struct var *vp;
00406 
00407         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00408                 for (vp = *vpp ; vp ; vp = vp->next) {
00409                         if ((vp->flags & VUNSET) == 0)
00410                                 out1fmt("%s\n", vp->text);
00411                 }
00412         }
00413         return 0;
00414 }
00415 
00416 
00417 
00418 /*
00419  * The export and readonly commands.
00420  */
00421 
00422 int
00423 exportcmd(argc, argv)  char **argv; {
00424         struct var **vpp;
00425         struct var *vp;
00426         char *name;
00427         char *p;
00428         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
00429 
00430         listsetvar(cmdenviron);
00431         if (argc > 1) {
00432                 while ((name = *argptr++) != NULL) {
00433                         if ((p = strchr(name, '=')) != NULL) {
00434                                 p++;
00435                         } else {
00436                                 vpp = hashvar(name);
00437                                 for (vp = *vpp ; vp ; vp = vp->next) {
00438                                         if (varequal(vp->text, name)) {
00439                                                 vp->flags |= flag;
00440                                                 goto found;
00441                                         }
00442                                 }
00443                         }
00444                         setvar(name, p, flag);
00445 found:;
00446                 }
00447         } else {
00448                 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00449                         for (vp = *vpp ; vp ; vp = vp->next) {
00450                                 if (vp->flags & flag) {
00451                                         for (p = vp->text ; *p != '=' ; p++)
00452                                                 out1c(*p);
00453                                         out1c('\n');
00454                                 }
00455                         }
00456                 }
00457         }
00458         return 0;
00459 }
00460 
00461 
00462 /*
00463  * The "local" command.
00464  */
00465 
00466 localcmd(argc, argv)  char **argv; {
00467         char *name;
00468 
00469         if (! in_function())
00470                 error("Not in a function");
00471         while ((name = *argptr++) != NULL) {
00472                 mklocal(name);
00473         }
00474         return 0;
00475 }
00476 
00477 
00478 /*
00479  * Make a variable a local variable.  When a variable is made local, it's
00480  * value and flags are saved in a localvar structure.  The saved values
00481  * will be restored when the shell function returns.  We handle the name
00482  * "-" as a special case.
00483  */
00484 
00485 void
00486 mklocal(name)
00487         char *name;
00488         {
00489         struct localvar *lvp;
00490         struct var **vpp;
00491         struct var *vp;
00492 
00493         INTOFF;
00494         lvp = ckmalloc(sizeof (struct localvar));
00495         if (name[0] == '-' && name[1] == '\0') {
00496                 lvp->text = ckmalloc(sizeof optval);
00497                 bcopy(optval, lvp->text, sizeof optval);
00498                 vp = NULL;
00499         } else {
00500                 vpp = hashvar(name);
00501                 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
00502                 if (vp == NULL) {
00503                         if (strchr(name, '='))
00504                                 setvareq(savestr(name), VSTRFIXED);
00505                         else
00506                                 setvar(name, NULL, VSTRFIXED);
00507                         vp = *vpp;      /* the new variable */
00508                         lvp->text = NULL;
00509                         lvp->flags = VUNSET;
00510                 } else {
00511                         lvp->text = vp->text;
00512                         lvp->flags = vp->flags;
00513                         vp->flags |= VSTRFIXED|VTEXTFIXED;
00514                         if (strchr(name, '='))
00515                                 setvareq(savestr(name), 0);
00516                 }
00517         }
00518         lvp->vp = vp;
00519         lvp->next = localvars;
00520         localvars = lvp;
00521         INTON;
00522 }
00523 
00524 
00525 /*
00526  * Called after a function returns.
00527  */
00528 
00529 void
00530 poplocalvars() {
00531         struct localvar *lvp;
00532         struct var *vp;
00533 
00534         while ((lvp = localvars) != NULL) {
00535                 localvars = lvp->next;
00536                 vp = lvp->vp;
00537                 if (vp == NULL) {       /* $- saved */
00538                         bcopy(lvp->text, optval, sizeof optval);
00539                         ckfree(lvp->text);
00540                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
00541                         unsetvar(vp->text);
00542                 } else {
00543                         if ((vp->flags & VTEXTFIXED) == 0)
00544                                 ckfree(vp->text);
00545                         vp->flags = lvp->flags;
00546                         vp->text = lvp->text;
00547                 }
00548                 ckfree(lvp);
00549         }
00550 }
00551 
00552 
00553 setvarcmd(argc, argv)  char **argv; {
00554         if (argc <= 2)
00555                 return unsetcmd(argc, argv);
00556         else if (argc == 3)
00557                 setvar(argv[1], argv[2], 0);
00558         else
00559                 error("List assignment not implemented");
00560         return 0;
00561 }
00562 
00563 
00564 /*
00565  * The unset builtin command.  We unset the function before we unset the
00566  * variable to allow a function to be unset when there is a readonly variable
00567  * with the same name.
00568  */
00569 
00570 unsetcmd(argc, argv)  char **argv; {
00571         char **ap;
00572 
00573         for (ap = argv + 1 ; *ap ; ap++) {
00574                 unsetfunc(*ap);
00575                 unsetvar(*ap);
00576         }
00577         return 0;
00578 }
00579 
00580 
00581 /*
00582  * Unset the specified variable.
00583  */
00584 
00585 STATIC void
00586 unsetvar(s)
00587         char *s;
00588         {
00589         struct var **vpp;
00590         struct var *vp;
00591 
00592         vpp = hashvar(s);
00593         for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
00594                 if (varequal(vp->text, s)) {
00595                         INTOFF;
00596                         if (*(strchr(vp->text, '=') + 1) != '\0'
00597                          || vp->flags & VREADONLY) {
00598                                 setvar(s, nullstr, 0);
00599                         }
00600                         vp->flags &=~ VEXPORT;
00601                         vp->flags |= VUNSET;
00602                         if ((vp->flags & VSTRFIXED) == 0) {
00603                                 if ((vp->flags & VTEXTFIXED) == 0)
00604                                         ckfree(vp->text);
00605                                 *vpp = vp->next;
00606                                 ckfree(vp);
00607                         }
00608                         INTON;
00609                         return;
00610                 }
00611         }
00612 }
00613 
00614 
00615 
00616 /*
00617  * Find the appropriate entry in the hash table from the name.
00618  */
00619 
00620 STATIC struct var **
00621 hashvar(p)
00622         register char *p;
00623         {
00624         unsigned int hashval;
00625 
00626         hashval = *p << 4;
00627         while (*p && *p != '=')
00628                 hashval += *p++;
00629         return &vartab[hashval % VTABSIZE];
00630 }
00631 
00632 
00633 
00634 /*
00635  * Returns true if the two strings specify the same varable.  The first
00636  * variable name is terminated by '='; the second may be terminated by
00637  * either '=' or '\0'.
00638  */
00639 
00640 STATIC int
00641 varequal(p, q)
00642         register char *p, *q;
00643         {
00644         while (*p == *q++) {
00645                 if (*p++ == '=')
00646                         return 1;
00647         }
00648         if (*p == '=' && *(q - 1) == '\0')
00649                 return 1;
00650         return 0;
00651 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6