var.c revision 17525
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 353044Sdg * 3617525Sache * $Id: var.c,v 1.3 1995/05/30 00:07:24 rgrimes Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 401556Srgrimesstatic char sccsid[] = "@(#)var.c 8.1 (Berkeley) 5/31/93"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 431556Srgrimes/* 441556Srgrimes * Shell variables. 451556Srgrimes */ 461556Srgrimes 4717525Sache#include <locale.h> 4817525Sache 491556Srgrimes#include "shell.h" 501556Srgrimes#include "output.h" 511556Srgrimes#include "expand.h" 521556Srgrimes#include "nodes.h" /* for other headers */ 531556Srgrimes#include "eval.h" /* defines cmdenviron */ 541556Srgrimes#include "exec.h" 551556Srgrimes#include "syntax.h" 561556Srgrimes#include "options.h" 571556Srgrimes#include "mail.h" 581556Srgrimes#include "var.h" 591556Srgrimes#include "memalloc.h" 601556Srgrimes#include "error.h" 611556Srgrimes#include "mystring.h" 621556Srgrimes 631556Srgrimes 641556Srgrimes#define VTABSIZE 39 651556Srgrimes 661556Srgrimes 671556Srgrimesstruct varinit { 681556Srgrimes struct var *var; 691556Srgrimes int flags; 701556Srgrimes char *text; 711556Srgrimes}; 721556Srgrimes 731556Srgrimes 741556Srgrimes#if ATTY 751556Srgrimesstruct var vatty; 761556Srgrimes#endif 771556Srgrimesstruct var vhistsize; 781556Srgrimesstruct var vifs; 791556Srgrimesstruct var vmail; 801556Srgrimesstruct var vmpath; 811556Srgrimesstruct var vpath; 821556Srgrimesstruct var vps1; 831556Srgrimesstruct var vps2; 841556Srgrimesstruct var vvers; 851556Srgrimes#if ATTY 861556Srgrimesstruct var vterm; 871556Srgrimes#endif 881556Srgrimes 891556Srgrimesconst struct varinit varinit[] = { 901556Srgrimes#if ATTY 911556Srgrimes {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="}, 921556Srgrimes#endif 931556Srgrimes {&vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE="}, 941556Srgrimes {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"}, 951556Srgrimes {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="}, 961556Srgrimes {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="}, 971556Srgrimes {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=:/bin:/usr/bin"}, 988855Srgrimes /* 991556Srgrimes * vps1 depends on uid 1001556Srgrimes */ 1011556Srgrimes {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "}, 1021556Srgrimes#if ATTY 1031556Srgrimes {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="}, 1041556Srgrimes#endif 1051556Srgrimes {NULL, 0, NULL} 1061556Srgrimes}; 1071556Srgrimes 1081556Srgrimesstruct var *vartab[VTABSIZE]; 1091556Srgrimes 1101556SrgrimesSTATIC int unsetvar __P((char *)); 1111556SrgrimesSTATIC struct var **hashvar __P((char *)); 1121556SrgrimesSTATIC int varequal __P((char *, char *)); 11317525SacheSTATIC int localevar __P((char *)); 1141556Srgrimes 1151556Srgrimes/* 1161556Srgrimes * Initialize the varable symbol tables and import the environment 1171556Srgrimes */ 1181556Srgrimes 1191556Srgrimes#ifdef mkinit 1201556SrgrimesINCLUDE "var.h" 1211556SrgrimesINIT { 1221556Srgrimes char **envp; 1231556Srgrimes extern char **environ; 1241556Srgrimes 1251556Srgrimes initvar(); 1261556Srgrimes for (envp = environ ; *envp ; envp++) { 1271556Srgrimes if (strchr(*envp, '=')) { 1281556Srgrimes setvareq(*envp, VEXPORT|VTEXTFIXED); 1291556Srgrimes } 1301556Srgrimes } 1311556Srgrimes} 1321556Srgrimes#endif 1331556Srgrimes 1341556Srgrimes 1351556Srgrimes/* 1361556Srgrimes * This routine initializes the builtin variables. It is called when the 1371556Srgrimes * shell is initialized and again when a shell procedure is spawned. 1381556Srgrimes */ 1391556Srgrimes 1401556Srgrimesvoid 1411556Srgrimesinitvar() { 1421556Srgrimes const struct varinit *ip; 1431556Srgrimes struct var *vp; 1441556Srgrimes struct var **vpp; 1451556Srgrimes 1461556Srgrimes for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 1471556Srgrimes if ((vp->flags & VEXPORT) == 0) { 1481556Srgrimes vpp = hashvar(ip->text); 1491556Srgrimes vp->next = *vpp; 1501556Srgrimes *vpp = vp; 1511556Srgrimes vp->text = ip->text; 1521556Srgrimes vp->flags = ip->flags; 1531556Srgrimes } 1541556Srgrimes } 1551556Srgrimes /* 1561556Srgrimes * PS1 depends on uid 1571556Srgrimes */ 1581556Srgrimes if ((vps1.flags & VEXPORT) == 0) { 1591556Srgrimes vpp = hashvar("PS1="); 1601556Srgrimes vps1.next = *vpp; 1611556Srgrimes *vpp = &vps1; 1621556Srgrimes vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; 1631556Srgrimes vps1.flags = VSTRFIXED|VTEXTFIXED; 1641556Srgrimes } 1651556Srgrimes} 1661556Srgrimes 1671556Srgrimes/* 1681556Srgrimes * Set the value of a variable. The flags argument is ored with the 1691556Srgrimes * flags of the variable. If val is NULL, the variable is unset. 1701556Srgrimes */ 1711556Srgrimes 1721556Srgrimesvoid 1731556Srgrimessetvar(name, val, flags) 1741556Srgrimes char *name, *val; 1751556Srgrimes { 1761556Srgrimes char *p, *q; 1771556Srgrimes int len; 1781556Srgrimes int namelen; 1791556Srgrimes char *nameeq; 1801556Srgrimes int isbad; 1811556Srgrimes 1821556Srgrimes isbad = 0; 1831556Srgrimes p = name; 18417525Sache if (! is_name(*p)) 1851556Srgrimes isbad = 1; 18617525Sache p++; 1871556Srgrimes for (;;) { 1881556Srgrimes if (! is_in_name(*p)) { 1891556Srgrimes if (*p == '\0' || *p == '=') 1901556Srgrimes break; 1911556Srgrimes isbad = 1; 1921556Srgrimes } 1931556Srgrimes p++; 1941556Srgrimes } 1951556Srgrimes namelen = p - name; 1961556Srgrimes if (isbad) 1971556Srgrimes error("%.*s: bad variable name", namelen, name); 1981556Srgrimes len = namelen + 2; /* 2 is space for '=' and '\0' */ 1991556Srgrimes if (val == NULL) { 2001556Srgrimes flags |= VUNSET; 2011556Srgrimes } else { 2021556Srgrimes len += strlen(val); 2031556Srgrimes } 2041556Srgrimes p = nameeq = ckmalloc(len); 2051556Srgrimes q = name; 2061556Srgrimes while (--namelen >= 0) 2071556Srgrimes *p++ = *q++; 2081556Srgrimes *p++ = '='; 2091556Srgrimes *p = '\0'; 2101556Srgrimes if (val) 2111556Srgrimes scopy(val, p); 2121556Srgrimes setvareq(nameeq, flags); 2131556Srgrimes} 2141556Srgrimes 21517525SacheSTATIC int 21617525Sachelocalevar(s) 21717525Sache char *s; 21817525Sache { 21917525Sache static char *lnames[7] = { 22017525Sache "ALL", "COLLATE", "CTYPE", "MONETARY", 22117525Sache "NUMERIC", "TIME", NULL 22217525Sache }; 22317525Sache char **ss; 2241556Srgrimes 22517525Sache if (*s != 'L') 22617525Sache return 0; 22717525Sache if (varequal(s + 1, "ANG")) 22817525Sache return 1; 22917525Sache if (strncmp(s + 1, "C_", 2) != 0) 23017525Sache return 0; 23117525Sache for (ss = lnames; *ss ; ss++) 23217525Sache if (varequal(s + 3, *ss)) 23317525Sache return 1; 23417525Sache return 0; 23517525Sache} 2361556Srgrimes 2371556Srgrimes/* 2381556Srgrimes * Same as setvar except that the variable and value are passed in 2391556Srgrimes * the first argument as name=value. Since the first argument will 2401556Srgrimes * be actually stored in the table, it should not be a string that 2411556Srgrimes * will go away. 2421556Srgrimes */ 2431556Srgrimes 2441556Srgrimesvoid 2451556Srgrimessetvareq(s, flags) 2461556Srgrimes char *s; 2471556Srgrimes { 2481556Srgrimes struct var *vp, **vpp; 2491556Srgrimes 2501556Srgrimes vpp = hashvar(s); 2511556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) { 2521556Srgrimes if (varequal(s, vp->text)) { 2531556Srgrimes if (vp->flags & VREADONLY) { 2541556Srgrimes int len = strchr(s, '=') - s; 2551556Srgrimes error("%.*s: is read only", len, s); 2561556Srgrimes } 2571556Srgrimes INTOFF; 2581556Srgrimes if (vp == &vpath) 2591556Srgrimes changepath(s + 5); /* 5 = strlen("PATH=") */ 2601556Srgrimes if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 2611556Srgrimes ckfree(vp->text); 2621556Srgrimes vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET); 2631556Srgrimes vp->flags |= flags; 2641556Srgrimes vp->text = s; 2651556Srgrimes if (vp == &vmpath || (vp == &vmail && ! mpathset())) 2661556Srgrimes chkmail(1); 2671556Srgrimes if (vp == &vhistsize) 2681556Srgrimes sethistsize(); 26917525Sache if ((vp->flags & VEXPORT) && localevar(s)) { 27017525Sache putenv(s); 27117525Sache (void) setlocale(LC_ALL, ""); 27217525Sache } 2731556Srgrimes INTON; 2741556Srgrimes return; 2751556Srgrimes } 2761556Srgrimes } 2771556Srgrimes /* not found */ 2781556Srgrimes vp = ckmalloc(sizeof (*vp)); 2791556Srgrimes vp->flags = flags; 2801556Srgrimes vp->text = s; 2811556Srgrimes vp->next = *vpp; 28217525Sache INTOFF; 2831556Srgrimes *vpp = vp; 28417525Sache if ((vp->flags & VEXPORT) && localevar(s)) { 28517525Sache putenv(s); 28617525Sache (void) setlocale(LC_ALL, ""); 28717525Sache } 28817525Sache INTON; 2891556Srgrimes} 2901556Srgrimes 2911556Srgrimes 2921556Srgrimes 2931556Srgrimes/* 2941556Srgrimes * Process a linked list of variable assignments. 2951556Srgrimes */ 2961556Srgrimes 2971556Srgrimesvoid 2981556Srgrimeslistsetvar(list) 2991556Srgrimes struct strlist *list; 3001556Srgrimes { 3011556Srgrimes struct strlist *lp; 3021556Srgrimes 3031556Srgrimes INTOFF; 3041556Srgrimes for (lp = list ; lp ; lp = lp->next) { 3051556Srgrimes setvareq(savestr(lp->text), 0); 3061556Srgrimes } 3071556Srgrimes INTON; 3081556Srgrimes} 3091556Srgrimes 3101556Srgrimes 3111556Srgrimes 3121556Srgrimes/* 3131556Srgrimes * Find the value of a variable. Returns NULL if not set. 3141556Srgrimes */ 3151556Srgrimes 3161556Srgrimeschar * 3171556Srgrimeslookupvar(name) 3181556Srgrimes char *name; 3191556Srgrimes { 3201556Srgrimes struct var *v; 3211556Srgrimes 3221556Srgrimes for (v = *hashvar(name) ; v ; v = v->next) { 3231556Srgrimes if (varequal(v->text, name)) { 3241556Srgrimes if (v->flags & VUNSET) 3251556Srgrimes return NULL; 3261556Srgrimes return strchr(v->text, '=') + 1; 3271556Srgrimes } 3281556Srgrimes } 3291556Srgrimes return NULL; 3301556Srgrimes} 3311556Srgrimes 3321556Srgrimes 3331556Srgrimes 3341556Srgrimes/* 3351556Srgrimes * Search the environment of a builtin command. If the second argument 3361556Srgrimes * is nonzero, return the value of a variable even if it hasn't been 3371556Srgrimes * exported. 3381556Srgrimes */ 3391556Srgrimes 3401556Srgrimeschar * 3411556Srgrimesbltinlookup(name, doall) 3421556Srgrimes char *name; 3431556Srgrimes { 3441556Srgrimes struct strlist *sp; 3451556Srgrimes struct var *v; 3461556Srgrimes 3471556Srgrimes for (sp = cmdenviron ; sp ; sp = sp->next) { 3481556Srgrimes if (varequal(sp->text, name)) 3491556Srgrimes return strchr(sp->text, '=') + 1; 3501556Srgrimes } 3511556Srgrimes for (v = *hashvar(name) ; v ; v = v->next) { 3521556Srgrimes if (varequal(v->text, name)) { 3531556Srgrimes if (v->flags & VUNSET 3541556Srgrimes || ! doall && (v->flags & VEXPORT) == 0) 3551556Srgrimes return NULL; 3561556Srgrimes return strchr(v->text, '=') + 1; 3571556Srgrimes } 3581556Srgrimes } 3591556Srgrimes return NULL; 3601556Srgrimes} 3611556Srgrimes 3621556Srgrimes 3631556Srgrimes 3641556Srgrimes/* 3651556Srgrimes * Generate a list of exported variables. This routine is used to construct 3661556Srgrimes * the third argument to execve when executing a program. 3671556Srgrimes */ 3681556Srgrimes 3691556Srgrimeschar ** 3701556Srgrimesenvironment() { 3711556Srgrimes int nenv; 3721556Srgrimes struct var **vpp; 3731556Srgrimes struct var *vp; 3741556Srgrimes char **env, **ep; 3751556Srgrimes 3761556Srgrimes nenv = 0; 3771556Srgrimes for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 3781556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) 3791556Srgrimes if (vp->flags & VEXPORT) 3801556Srgrimes nenv++; 3811556Srgrimes } 3821556Srgrimes ep = env = stalloc((nenv + 1) * sizeof *env); 3831556Srgrimes for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 3841556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) 3851556Srgrimes if (vp->flags & VEXPORT) 3861556Srgrimes *ep++ = vp->text; 3871556Srgrimes } 3881556Srgrimes *ep = NULL; 3891556Srgrimes return env; 3901556Srgrimes} 3911556Srgrimes 3921556Srgrimes 3931556Srgrimes/* 3941556Srgrimes * Called when a shell procedure is invoked to clear out nonexported 3951556Srgrimes * variables. It is also necessary to reallocate variables of with 3961556Srgrimes * VSTACK set since these are currently allocated on the stack. 3971556Srgrimes */ 3981556Srgrimes 3991556Srgrimes#ifdef mkinit 4001556SrgrimesMKINIT void shprocvar(); 4011556Srgrimes 4021556SrgrimesSHELLPROC { 4031556Srgrimes shprocvar(); 4041556Srgrimes} 4051556Srgrimes#endif 4061556Srgrimes 4071556Srgrimesvoid 4081556Srgrimesshprocvar() { 4091556Srgrimes struct var **vpp; 4101556Srgrimes struct var *vp, **prev; 4111556Srgrimes 4121556Srgrimes for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 4131556Srgrimes for (prev = vpp ; (vp = *prev) != NULL ; ) { 4141556Srgrimes if ((vp->flags & VEXPORT) == 0) { 4151556Srgrimes *prev = vp->next; 4161556Srgrimes if ((vp->flags & VTEXTFIXED) == 0) 4171556Srgrimes ckfree(vp->text); 4181556Srgrimes if ((vp->flags & VSTRFIXED) == 0) 4191556Srgrimes ckfree(vp); 4201556Srgrimes } else { 4211556Srgrimes if (vp->flags & VSTACK) { 4221556Srgrimes vp->text = savestr(vp->text); 4231556Srgrimes vp->flags &=~ VSTACK; 4241556Srgrimes } 4251556Srgrimes prev = &vp->next; 4261556Srgrimes } 4271556Srgrimes } 4281556Srgrimes } 4291556Srgrimes initvar(); 4301556Srgrimes} 4311556Srgrimes 4321556Srgrimes 4331556Srgrimes 4341556Srgrimes/* 4351556Srgrimes * Command to list all variables which are set. Currently this command 4361556Srgrimes * is invoked from the set command when the set command is called without 4371556Srgrimes * any variables. 4381556Srgrimes */ 4391556Srgrimes 4401556Srgrimesint 4411556Srgrimesshowvarscmd(argc, argv) char **argv; { 4421556Srgrimes struct var **vpp; 4431556Srgrimes struct var *vp; 4441556Srgrimes 4451556Srgrimes for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 4461556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) { 4471556Srgrimes if ((vp->flags & VUNSET) == 0) 4481556Srgrimes out1fmt("%s\n", vp->text); 4491556Srgrimes } 4501556Srgrimes } 4511556Srgrimes return 0; 4521556Srgrimes} 4531556Srgrimes 4541556Srgrimes 4551556Srgrimes 4561556Srgrimes/* 4571556Srgrimes * The export and readonly commands. 4581556Srgrimes */ 4591556Srgrimes 4601556Srgrimesint 4611556Srgrimesexportcmd(argc, argv) char **argv; { 4621556Srgrimes struct var **vpp; 4631556Srgrimes struct var *vp; 4641556Srgrimes char *name; 4651556Srgrimes char *p; 4661556Srgrimes int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 4671556Srgrimes 4681556Srgrimes listsetvar(cmdenviron); 4691556Srgrimes if (argc > 1) { 4701556Srgrimes while ((name = *argptr++) != NULL) { 4711556Srgrimes if ((p = strchr(name, '=')) != NULL) { 4721556Srgrimes p++; 4731556Srgrimes } else { 4741556Srgrimes vpp = hashvar(name); 4751556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) { 4761556Srgrimes if (varequal(vp->text, name)) { 4771556Srgrimes vp->flags |= flag; 47817525Sache if ((vp->flags & VEXPORT) && localevar(vp->text)) { 47917525Sache putenv(vp->text); 48017525Sache (void) setlocale(LC_ALL, ""); 48117525Sache } 4821556Srgrimes goto found; 4831556Srgrimes } 4841556Srgrimes } 4851556Srgrimes } 4861556Srgrimes setvar(name, p, flag); 4871556Srgrimesfound:; 4881556Srgrimes } 4891556Srgrimes } else { 4901556Srgrimes for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 4911556Srgrimes for (vp = *vpp ; vp ; vp = vp->next) { 4921556Srgrimes if (vp->flags & flag) { 4931556Srgrimes for (p = vp->text ; *p != '=' ; p++) 4941556Srgrimes out1c(*p); 4951556Srgrimes out1c('\n'); 4961556Srgrimes } 4971556Srgrimes } 4981556Srgrimes } 4991556Srgrimes } 5001556Srgrimes return 0; 5011556Srgrimes} 5021556Srgrimes 5031556Srgrimes 5041556Srgrimes/* 5051556Srgrimes * The "local" command. 5061556Srgrimes */ 5071556Srgrimes 5081556Srgrimeslocalcmd(argc, argv) char **argv; { 5091556Srgrimes char *name; 5101556Srgrimes 5111556Srgrimes if (! in_function()) 5121556Srgrimes error("Not in a function"); 5131556Srgrimes while ((name = *argptr++) != NULL) { 5141556Srgrimes mklocal(name); 5151556Srgrimes } 5161556Srgrimes return 0; 5171556Srgrimes} 5181556Srgrimes 5191556Srgrimes 5201556Srgrimes/* 5211556Srgrimes * Make a variable a local variable. When a variable is made local, it's 5221556Srgrimes * value and flags are saved in a localvar structure. The saved values 5231556Srgrimes * will be restored when the shell function returns. We handle the name 5241556Srgrimes * "-" as a special case. 5251556Srgrimes */ 5261556Srgrimes 5271556Srgrimesvoid 5281556Srgrimesmklocal(name) 5291556Srgrimes char *name; 5301556Srgrimes { 5311556Srgrimes struct localvar *lvp; 5321556Srgrimes struct var **vpp; 5331556Srgrimes struct var *vp; 5341556Srgrimes 5351556Srgrimes INTOFF; 5361556Srgrimes lvp = ckmalloc(sizeof (struct localvar)); 5371556Srgrimes if (name[0] == '-' && name[1] == '\0') { 5381556Srgrimes lvp->text = ckmalloc(sizeof optlist); 5391556Srgrimes bcopy(optlist, lvp->text, sizeof optlist); 5401556Srgrimes vp = NULL; 5411556Srgrimes } else { 5421556Srgrimes vpp = hashvar(name); 5431556Srgrimes for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); 5441556Srgrimes if (vp == NULL) { 5451556Srgrimes if (strchr(name, '=')) 5461556Srgrimes setvareq(savestr(name), VSTRFIXED); 5471556Srgrimes else 5481556Srgrimes setvar(name, NULL, VSTRFIXED); 5491556Srgrimes vp = *vpp; /* the new variable */ 5501556Srgrimes lvp->text = NULL; 5511556Srgrimes lvp->flags = VUNSET; 5521556Srgrimes } else { 5531556Srgrimes lvp->text = vp->text; 5541556Srgrimes lvp->flags = vp->flags; 5551556Srgrimes vp->flags |= VSTRFIXED|VTEXTFIXED; 5561556Srgrimes if (strchr(name, '=')) 5571556Srgrimes setvareq(savestr(name), 0); 5581556Srgrimes } 5591556Srgrimes } 5601556Srgrimes lvp->vp = vp; 5611556Srgrimes lvp->next = localvars; 5621556Srgrimes localvars = lvp; 5631556Srgrimes INTON; 5641556Srgrimes} 5651556Srgrimes 5661556Srgrimes 5671556Srgrimes/* 5681556Srgrimes * Called after a function returns. 5691556Srgrimes */ 5701556Srgrimes 5711556Srgrimesvoid 5721556Srgrimespoplocalvars() { 5731556Srgrimes struct localvar *lvp; 5741556Srgrimes struct var *vp; 5751556Srgrimes 5761556Srgrimes while ((lvp = localvars) != NULL) { 5771556Srgrimes localvars = lvp->next; 5781556Srgrimes vp = lvp->vp; 5791556Srgrimes if (vp == NULL) { /* $- saved */ 5801556Srgrimes bcopy(lvp->text, optlist, sizeof optlist); 5811556Srgrimes ckfree(lvp->text); 5821556Srgrimes } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 5831556Srgrimes (void)unsetvar(vp->text); 5841556Srgrimes } else { 5851556Srgrimes if ((vp->flags & VTEXTFIXED) == 0) 5861556Srgrimes ckfree(vp->text); 5871556Srgrimes vp->flags = lvp->flags; 5881556Srgrimes vp->text = lvp->text; 5891556Srgrimes } 5901556Srgrimes ckfree(lvp); 5911556Srgrimes } 5921556Srgrimes} 5931556Srgrimes 5941556Srgrimes 5951556Srgrimessetvarcmd(argc, argv) char **argv; { 5961556Srgrimes if (argc <= 2) 5971556Srgrimes return unsetcmd(argc, argv); 5981556Srgrimes else if (argc == 3) 5991556Srgrimes setvar(argv[1], argv[2], 0); 6001556Srgrimes else 6011556Srgrimes error("List assignment not implemented"); 6021556Srgrimes return 0; 6031556Srgrimes} 6041556Srgrimes 6051556Srgrimes 6061556Srgrimes/* 6071556Srgrimes * The unset builtin command. We unset the function before we unset the 6081556Srgrimes * variable to allow a function to be unset when there is a readonly variable 6091556Srgrimes * with the same name. 6101556Srgrimes */ 6111556Srgrimes 6121556Srgrimesunsetcmd(argc, argv) char **argv; { 6131556Srgrimes char **ap; 6141556Srgrimes int i; 6151556Srgrimes int flg_func = 0; 6161556Srgrimes int flg_var = 0; 6171556Srgrimes int ret = 0; 6181556Srgrimes 6191556Srgrimes while ((i = nextopt("vf")) != '\0') { 6201556Srgrimes if (i == 'f') 6211556Srgrimes flg_func = 1; 6221556Srgrimes else 6231556Srgrimes flg_var = 1; 6241556Srgrimes } 6251556Srgrimes if (flg_func == 0 && flg_var == 0) 6261556Srgrimes flg_var = 1; 6278855Srgrimes 6281556Srgrimes for (ap = argptr; *ap ; ap++) { 6291556Srgrimes if (flg_func) 6301556Srgrimes ret |= unsetfunc(*ap); 6311556Srgrimes if (flg_var) 6321556Srgrimes ret |= unsetvar(*ap); 6331556Srgrimes } 6341556Srgrimes return ret; 6351556Srgrimes} 6361556Srgrimes 6371556Srgrimes 6381556Srgrimes/* 6391556Srgrimes * Unset the specified variable. 6401556Srgrimes */ 6411556Srgrimes 6421556SrgrimesSTATIC int 6431556Srgrimesunsetvar(s) 6441556Srgrimes char *s; 6451556Srgrimes { 6461556Srgrimes struct var **vpp; 6471556Srgrimes struct var *vp; 6481556Srgrimes 6491556Srgrimes vpp = hashvar(s); 6501556Srgrimes for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 6511556Srgrimes if (varequal(vp->text, s)) { 6521556Srgrimes if (vp->flags & VREADONLY) 6531556Srgrimes return (1); 6541556Srgrimes INTOFF; 6551556Srgrimes if (*(strchr(vp->text, '=') + 1) != '\0') 6561556Srgrimes setvar(s, nullstr, 0); 65717525Sache if ((vp->flags & VEXPORT) && localevar(vp->text)) { 65817525Sache unsetenv(s); 65917525Sache setlocale(LC_ALL, ""); 66017525Sache } 6611556Srgrimes vp->flags &=~ VEXPORT; 6621556Srgrimes vp->flags |= VUNSET; 6631556Srgrimes if ((vp->flags & VSTRFIXED) == 0) { 6641556Srgrimes if ((vp->flags & VTEXTFIXED) == 0) 6651556Srgrimes ckfree(vp->text); 6661556Srgrimes *vpp = vp->next; 6671556Srgrimes ckfree(vp); 6681556Srgrimes } 6691556Srgrimes INTON; 6701556Srgrimes return (0); 6711556Srgrimes } 6721556Srgrimes } 6731556Srgrimes 6741556Srgrimes return (1); 6751556Srgrimes} 6761556Srgrimes 6771556Srgrimes 6781556Srgrimes 6791556Srgrimes/* 6801556Srgrimes * Find the appropriate entry in the hash table from the name. 6811556Srgrimes */ 6821556Srgrimes 6831556SrgrimesSTATIC struct var ** 6841556Srgrimeshashvar(p) 6851556Srgrimes register char *p; 6861556Srgrimes { 6871556Srgrimes unsigned int hashval; 6881556Srgrimes 68917525Sache hashval = ((unsigned char)*p) << 4; 6901556Srgrimes while (*p && *p != '=') 69117525Sache hashval += (unsigned char)*p++; 6921556Srgrimes return &vartab[hashval % VTABSIZE]; 6931556Srgrimes} 6941556Srgrimes 6951556Srgrimes 6961556Srgrimes 6971556Srgrimes/* 6981556Srgrimes * Returns true if the two strings specify the same varable. The first 6991556Srgrimes * variable name is terminated by '='; the second may be terminated by 7001556Srgrimes * either '=' or '\0'. 7011556Srgrimes */ 7021556Srgrimes 7031556SrgrimesSTATIC int 7041556Srgrimesvarequal(p, q) 7051556Srgrimes register char *p, *q; 7061556Srgrimes { 7071556Srgrimes while (*p == *q++) { 7081556Srgrimes if (*p++ == '=') 7091556Srgrimes return 1; 7101556Srgrimes } 7111556Srgrimes if (*p == '=' && *(q - 1) == '\0') 7121556Srgrimes return 1; 7131556Srgrimes return 0; 7141556Srgrimes} 715