147147Sbostic /*-
260698Sbostic * Copyright (c) 1991, 1993
360698Sbostic * The Regents of the University of California. All rights reserved.
447147Sbostic *
547147Sbostic * This code is derived from software contributed to Berkeley by
647147Sbostic * Kenneth Almquist.
747147Sbostic *
847147Sbostic * %sccs.include.redist.c%
947147Sbostic */
1047147Sbostic
1147147Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 05/04/95";
1347147Sbostic #endif /* not lint */
1447147Sbostic
15*69272Schristos #include <unistd.h>
16*69272Schristos #include <stdlib.h>
17*69272Schristos
1847147Sbostic /*
1947147Sbostic * Shell variables.
2047147Sbostic */
2147147Sbostic
2247147Sbostic #include "shell.h"
2347147Sbostic #include "output.h"
2447147Sbostic #include "expand.h"
2547147Sbostic #include "nodes.h" /* for other headers */
2647147Sbostic #include "eval.h" /* defines cmdenviron */
2747147Sbostic #include "exec.h"
2847147Sbostic #include "syntax.h"
2947147Sbostic #include "options.h"
3047147Sbostic #include "mail.h"
3147147Sbostic #include "var.h"
3247147Sbostic #include "memalloc.h"
3347147Sbostic #include "error.h"
3447147Sbostic #include "mystring.h"
35*69272Schristos #ifndef NO_HISTORY
36*69272Schristos #include "myhistedit.h"
37*69272Schristos #endif
3847147Sbostic
3947147Sbostic
4047147Sbostic #define VTABSIZE 39
4147147Sbostic
4247147Sbostic
4347147Sbostic struct varinit {
4447147Sbostic struct var *var;
4547147Sbostic int flags;
4647147Sbostic char *text;
4747147Sbostic };
4847147Sbostic
4947147Sbostic
5047147Sbostic #if ATTY
5147147Sbostic struct var vatty;
5247147Sbostic #endif
53*69272Schristos #ifndef NO_HISTORY
5455224Smarc struct var vhistsize;
55*69272Schristos #endif
5647147Sbostic struct var vifs;
5747147Sbostic struct var vmail;
5847147Sbostic struct var vmpath;
5947147Sbostic struct var vpath;
6047147Sbostic struct var vps1;
6147147Sbostic struct var vps2;
6247147Sbostic struct var vvers;
6347147Sbostic #if ATTY
6447147Sbostic struct var vterm;
6547147Sbostic #endif
6647147Sbostic
6747147Sbostic const struct varinit varinit[] = {
6847147Sbostic #if ATTY
6947147Sbostic {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="},
7047147Sbostic #endif
71*69272Schristos #ifndef NO_HISTORY
7255224Smarc {&vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE="},
73*69272Schristos #endif
7447147Sbostic {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"},
7547147Sbostic {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="},
7647147Sbostic {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="},
77*69272Schristos {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin"},
7847985Smarc /*
7947985Smarc * vps1 depends on uid
8047985Smarc */
8147147Sbostic {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "},
8247147Sbostic #if ATTY
8347147Sbostic {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="},
8447147Sbostic #endif
8547147Sbostic {NULL, 0, NULL}
8647147Sbostic };
8747147Sbostic
8847147Sbostic struct var *vartab[VTABSIZE];
8947147Sbostic
9054325Smarc STATIC int unsetvar __P((char *));
9147985Smarc STATIC struct var **hashvar __P((char *));
9247985Smarc STATIC int varequal __P((char *, char *));
9347147Sbostic
9447147Sbostic /*
9547147Sbostic * Initialize the varable symbol tables and import the environment
9647147Sbostic */
9747147Sbostic
9847147Sbostic #ifdef mkinit
9947147Sbostic INCLUDE "var.h"
10047147Sbostic INIT {
10147147Sbostic char **envp;
10247147Sbostic extern char **environ;
10347147Sbostic
10447147Sbostic initvar();
10547147Sbostic for (envp = environ ; *envp ; envp++) {
10647147Sbostic if (strchr(*envp, '=')) {
10747147Sbostic setvareq(*envp, VEXPORT|VTEXTFIXED);
10847147Sbostic }
10947147Sbostic }
11047147Sbostic }
11147147Sbostic #endif
11247147Sbostic
11347147Sbostic
11447147Sbostic /*
11547147Sbostic * This routine initializes the builtin variables. It is called when the
11647147Sbostic * shell is initialized and again when a shell procedure is spawned.
11747147Sbostic */
11847147Sbostic
11947147Sbostic void
initvar()12047147Sbostic initvar() {
12147147Sbostic const struct varinit *ip;
12247147Sbostic struct var *vp;
12347147Sbostic struct var **vpp;
12447147Sbostic
12547147Sbostic for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12647147Sbostic if ((vp->flags & VEXPORT) == 0) {
12747147Sbostic vpp = hashvar(ip->text);
12847147Sbostic vp->next = *vpp;
12947147Sbostic *vpp = vp;
13047147Sbostic vp->text = ip->text;
13147147Sbostic vp->flags = ip->flags;
13247147Sbostic }
13347147Sbostic }
13447985Smarc /*
13547985Smarc * PS1 depends on uid
13647985Smarc */
13747985Smarc if ((vps1.flags & VEXPORT) == 0) {
13847985Smarc vpp = hashvar("PS1=");
13947985Smarc vps1.next = *vpp;
14047985Smarc *vpp = &vps1;
14153179Smarc vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
14247985Smarc vps1.flags = VSTRFIXED|VTEXTFIXED;
14347985Smarc }
14447147Sbostic }
14547147Sbostic
14647147Sbostic /*
14747147Sbostic * Set the value of a variable. The flags argument is ored with the
14847147Sbostic * flags of the variable. If val is NULL, the variable is unset.
14947147Sbostic */
15047147Sbostic
15147147Sbostic void
setvar(name,val,flags)15247147Sbostic setvar(name, val, flags)
15347147Sbostic char *name, *val;
154*69272Schristos int flags;
155*69272Schristos {
15647147Sbostic char *p, *q;
15747147Sbostic int len;
15847147Sbostic int namelen;
15947147Sbostic char *nameeq;
16047147Sbostic int isbad;
16147147Sbostic
16247147Sbostic isbad = 0;
16347147Sbostic p = name;
16447147Sbostic if (! is_name(*p++))
16547147Sbostic isbad = 1;
16647147Sbostic for (;;) {
16747147Sbostic if (! is_in_name(*p)) {
16847147Sbostic if (*p == '\0' || *p == '=')
16947147Sbostic break;
17047147Sbostic isbad = 1;
17147147Sbostic }
17247147Sbostic p++;
17347147Sbostic }
17447147Sbostic namelen = p - name;
17547147Sbostic if (isbad)
17653625Smarc error("%.*s: bad variable name", namelen, name);
17747147Sbostic len = namelen + 2; /* 2 is space for '=' and '\0' */
17847147Sbostic if (val == NULL) {
17947147Sbostic flags |= VUNSET;
18047147Sbostic } else {
18147147Sbostic len += strlen(val);
18247147Sbostic }
18347147Sbostic p = nameeq = ckmalloc(len);
18447147Sbostic q = name;
18547147Sbostic while (--namelen >= 0)
18647147Sbostic *p++ = *q++;
18747147Sbostic *p++ = '=';
18847147Sbostic *p = '\0';
18947147Sbostic if (val)
19047147Sbostic scopy(val, p);
19147147Sbostic setvareq(nameeq, flags);
19247147Sbostic }
19347147Sbostic
19447147Sbostic
19547147Sbostic
19647147Sbostic /*
19747147Sbostic * Same as setvar except that the variable and value are passed in
19847147Sbostic * the first argument as name=value. Since the first argument will
19947147Sbostic * be actually stored in the table, it should not be a string that
20047147Sbostic * will go away.
20147147Sbostic */
20247147Sbostic
20347147Sbostic void
setvareq(s,flags)20447147Sbostic setvareq(s, flags)
20547147Sbostic char *s;
206*69272Schristos int flags;
207*69272Schristos {
20847147Sbostic struct var *vp, **vpp;
20947147Sbostic
21047147Sbostic vpp = hashvar(s);
21147147Sbostic for (vp = *vpp ; vp ; vp = vp->next) {
21247147Sbostic if (varequal(s, vp->text)) {
21347147Sbostic if (vp->flags & VREADONLY) {
21447147Sbostic int len = strchr(s, '=') - s;
21547147Sbostic error("%.*s: is read only", len, s);
21647147Sbostic }
21747147Sbostic INTOFF;
21847147Sbostic if (vp == &vpath)
21947147Sbostic changepath(s + 5); /* 5 = strlen("PATH=") */
22047147Sbostic if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
22147147Sbostic ckfree(vp->text);
22247147Sbostic vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
22347147Sbostic vp->flags |= flags;
22447147Sbostic vp->text = s;
22547147Sbostic if (vp == &vmpath || (vp == &vmail && ! mpathset()))
22647147Sbostic chkmail(1);
227*69272Schristos #ifndef NO_HISTORY
22855224Smarc if (vp == &vhistsize)
22955224Smarc sethistsize();
230*69272Schristos #endif
23147147Sbostic INTON;
23247147Sbostic return;
23347147Sbostic }
23447147Sbostic }
23547147Sbostic /* not found */
23647147Sbostic vp = ckmalloc(sizeof (*vp));
23747147Sbostic vp->flags = flags;
23847147Sbostic vp->text = s;
23947147Sbostic vp->next = *vpp;
24047147Sbostic *vpp = vp;
24147147Sbostic }
24247147Sbostic
24347147Sbostic
24447147Sbostic
24547147Sbostic /*
24647147Sbostic * Process a linked list of variable assignments.
24747147Sbostic */
24847147Sbostic
24947147Sbostic void
listsetvar(list)25047147Sbostic listsetvar(list)
25147147Sbostic struct strlist *list;
25247147Sbostic {
25347147Sbostic struct strlist *lp;
25447147Sbostic
25547147Sbostic INTOFF;
25647147Sbostic for (lp = list ; lp ; lp = lp->next) {
25747147Sbostic setvareq(savestr(lp->text), 0);
25847147Sbostic }
25947147Sbostic INTON;
26047147Sbostic }
26147147Sbostic
26247147Sbostic
26347147Sbostic
26447147Sbostic /*
26547147Sbostic * Find the value of a variable. Returns NULL if not set.
26647147Sbostic */
26747147Sbostic
26847147Sbostic char *
lookupvar(name)26947147Sbostic lookupvar(name)
27047147Sbostic char *name;
27147147Sbostic {
27247147Sbostic struct var *v;
27347147Sbostic
27447147Sbostic for (v = *hashvar(name) ; v ; v = v->next) {
27547147Sbostic if (varequal(v->text, name)) {
27647147Sbostic if (v->flags & VUNSET)
27747147Sbostic return NULL;
27847147Sbostic return strchr(v->text, '=') + 1;
27947147Sbostic }
28047147Sbostic }
28147147Sbostic return NULL;
28247147Sbostic }
28347147Sbostic
28447147Sbostic
28547147Sbostic
28647147Sbostic /*
28747147Sbostic * Search the environment of a builtin command. If the second argument
28847147Sbostic * is nonzero, return the value of a variable even if it hasn't been
28947147Sbostic * exported.
29047147Sbostic */
29147147Sbostic
29247147Sbostic char *
bltinlookup(name,doall)29347147Sbostic bltinlookup(name, doall)
29447147Sbostic char *name;
295*69272Schristos int doall;
296*69272Schristos {
29747147Sbostic struct strlist *sp;
29847147Sbostic struct var *v;
29947147Sbostic
30047147Sbostic for (sp = cmdenviron ; sp ; sp = sp->next) {
30147147Sbostic if (varequal(sp->text, name))
30247147Sbostic return strchr(sp->text, '=') + 1;
30347147Sbostic }
30447147Sbostic for (v = *hashvar(name) ; v ; v = v->next) {
30547147Sbostic if (varequal(v->text, name)) {
306*69272Schristos if ((v->flags & VUNSET)
307*69272Schristos || (!doall && (v->flags & VEXPORT) == 0))
30847147Sbostic return NULL;
30947147Sbostic return strchr(v->text, '=') + 1;
31047147Sbostic }
31147147Sbostic }
31247147Sbostic return NULL;
31347147Sbostic }
31447147Sbostic
31547147Sbostic
31647147Sbostic
31747147Sbostic /*
31847147Sbostic * Generate a list of exported variables. This routine is used to construct
31947147Sbostic * the third argument to execve when executing a program.
32047147Sbostic */
32147147Sbostic
32247147Sbostic char **
environment()32347147Sbostic environment() {
32447147Sbostic int nenv;
32547147Sbostic struct var **vpp;
32647147Sbostic struct var *vp;
32747147Sbostic char **env, **ep;
32847147Sbostic
32947147Sbostic nenv = 0;
33047147Sbostic for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
33147147Sbostic for (vp = *vpp ; vp ; vp = vp->next)
33247147Sbostic if (vp->flags & VEXPORT)
33347147Sbostic nenv++;
33447147Sbostic }
33547147Sbostic ep = env = stalloc((nenv + 1) * sizeof *env);
33647147Sbostic for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
33747147Sbostic for (vp = *vpp ; vp ; vp = vp->next)
33847147Sbostic if (vp->flags & VEXPORT)
33947147Sbostic *ep++ = vp->text;
34047147Sbostic }
34147147Sbostic *ep = NULL;
34247147Sbostic return env;
34347147Sbostic }
34447147Sbostic
34547147Sbostic
34647147Sbostic /*
34747147Sbostic * Called when a shell procedure is invoked to clear out nonexported
34847147Sbostic * variables. It is also necessary to reallocate variables of with
34947147Sbostic * VSTACK set since these are currently allocated on the stack.
35047147Sbostic */
35147147Sbostic
35247147Sbostic #ifdef mkinit
35347147Sbostic MKINIT void shprocvar();
35447147Sbostic
35547147Sbostic SHELLPROC {
35647147Sbostic shprocvar();
35747147Sbostic }
35847147Sbostic #endif
35947147Sbostic
36047147Sbostic void
shprocvar()36147147Sbostic shprocvar() {
36247147Sbostic struct var **vpp;
36347147Sbostic struct var *vp, **prev;
36447147Sbostic
36547147Sbostic for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
36647147Sbostic for (prev = vpp ; (vp = *prev) != NULL ; ) {
36747147Sbostic if ((vp->flags & VEXPORT) == 0) {
36847147Sbostic *prev = vp->next;
36947147Sbostic if ((vp->flags & VTEXTFIXED) == 0)
37047147Sbostic ckfree(vp->text);
37147147Sbostic if ((vp->flags & VSTRFIXED) == 0)
37247147Sbostic ckfree(vp);
37347147Sbostic } else {
37447147Sbostic if (vp->flags & VSTACK) {
37547147Sbostic vp->text = savestr(vp->text);
37647147Sbostic vp->flags &=~ VSTACK;
37747147Sbostic }
37847147Sbostic prev = &vp->next;
37947147Sbostic }
38047147Sbostic }
38147147Sbostic }
38247147Sbostic initvar();
38347147Sbostic }
38447147Sbostic
38547147Sbostic
38647147Sbostic
38747147Sbostic /*
38847147Sbostic * Command to list all variables which are set. Currently this command
38947147Sbostic * is invoked from the set command when the set command is called without
39047147Sbostic * any variables.
39147147Sbostic */
39247147Sbostic
39347147Sbostic int
showvarscmd(argc,argv)394*69272Schristos showvarscmd(argc, argv)
395*69272Schristos int argc;
396*69272Schristos char **argv;
397*69272Schristos {
39847147Sbostic struct var **vpp;
39947147Sbostic struct var *vp;
40047147Sbostic
40147147Sbostic for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
40247147Sbostic for (vp = *vpp ; vp ; vp = vp->next) {
40347147Sbostic if ((vp->flags & VUNSET) == 0)
40447147Sbostic out1fmt("%s\n", vp->text);
40547147Sbostic }
40647147Sbostic }
40747147Sbostic return 0;
40847147Sbostic }
40947147Sbostic
41047147Sbostic
41147147Sbostic
41247147Sbostic /*
41347147Sbostic * The export and readonly commands.
41447147Sbostic */
41547147Sbostic
41647147Sbostic int
exportcmd(argc,argv)417*69272Schristos exportcmd(argc, argv)
418*69272Schristos int argc;
419*69272Schristos char **argv;
420*69272Schristos {
42147147Sbostic struct var **vpp;
42247147Sbostic struct var *vp;
42347147Sbostic char *name;
42447147Sbostic char *p;
42547147Sbostic int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
42647147Sbostic
42747147Sbostic listsetvar(cmdenviron);
42847147Sbostic if (argc > 1) {
42947147Sbostic while ((name = *argptr++) != NULL) {
43047147Sbostic if ((p = strchr(name, '=')) != NULL) {
43147147Sbostic p++;
43247147Sbostic } else {
43347147Sbostic vpp = hashvar(name);
43447147Sbostic for (vp = *vpp ; vp ; vp = vp->next) {
43547147Sbostic if (varequal(vp->text, name)) {
43647147Sbostic vp->flags |= flag;
43747147Sbostic goto found;
43847147Sbostic }
43947147Sbostic }
44047147Sbostic }
44147147Sbostic setvar(name, p, flag);
44247147Sbostic found:;
44347147Sbostic }
44447147Sbostic } else {
44547147Sbostic for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
44647147Sbostic for (vp = *vpp ; vp ; vp = vp->next) {
44747147Sbostic if (vp->flags & flag) {
44847147Sbostic for (p = vp->text ; *p != '=' ; p++)
44947147Sbostic out1c(*p);
45047147Sbostic out1c('\n');
45147147Sbostic }
45247147Sbostic }
45347147Sbostic }
45447147Sbostic }
45547147Sbostic return 0;
45647147Sbostic }
45747147Sbostic
45847147Sbostic
45947147Sbostic /*
46047147Sbostic * The "local" command.
46147147Sbostic */
46247147Sbostic
463*69272Schristos int
localcmd(argc,argv)464*69272Schristos localcmd(argc, argv)
465*69272Schristos int argc;
466*69272Schristos char **argv;
467*69272Schristos {
46847147Sbostic char *name;
46947147Sbostic
47047147Sbostic if (! in_function())
47147147Sbostic error("Not in a function");
47247147Sbostic while ((name = *argptr++) != NULL) {
47347147Sbostic mklocal(name);
47447147Sbostic }
47547147Sbostic return 0;
47647147Sbostic }
47747147Sbostic
47847147Sbostic
47947147Sbostic /*
48047147Sbostic * Make a variable a local variable. When a variable is made local, it's
48147147Sbostic * value and flags are saved in a localvar structure. The saved values
48247147Sbostic * will be restored when the shell function returns. We handle the name
48347147Sbostic * "-" as a special case.
48447147Sbostic */
48547147Sbostic
48647147Sbostic void
mklocal(name)48747147Sbostic mklocal(name)
48847147Sbostic char *name;
48947147Sbostic {
49047147Sbostic struct localvar *lvp;
49147147Sbostic struct var **vpp;
49247147Sbostic struct var *vp;
49347147Sbostic
49447147Sbostic INTOFF;
49547147Sbostic lvp = ckmalloc(sizeof (struct localvar));
49647147Sbostic if (name[0] == '-' && name[1] == '\0') {
49755224Smarc lvp->text = ckmalloc(sizeof optlist);
498*69272Schristos memcpy(lvp->text, optlist, sizeof optlist);
49947147Sbostic vp = NULL;
50047147Sbostic } else {
50147147Sbostic vpp = hashvar(name);
50247147Sbostic for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
50347147Sbostic if (vp == NULL) {
50447147Sbostic if (strchr(name, '='))
50547147Sbostic setvareq(savestr(name), VSTRFIXED);
50647147Sbostic else
50747147Sbostic setvar(name, NULL, VSTRFIXED);
50847147Sbostic vp = *vpp; /* the new variable */
50947147Sbostic lvp->text = NULL;
51047147Sbostic lvp->flags = VUNSET;
51147147Sbostic } else {
51247147Sbostic lvp->text = vp->text;
51347147Sbostic lvp->flags = vp->flags;
51447147Sbostic vp->flags |= VSTRFIXED|VTEXTFIXED;
51547147Sbostic if (strchr(name, '='))
51647147Sbostic setvareq(savestr(name), 0);
51747147Sbostic }
51847147Sbostic }
51947147Sbostic lvp->vp = vp;
52047147Sbostic lvp->next = localvars;
52147147Sbostic localvars = lvp;
52247147Sbostic INTON;
52347147Sbostic }
52447147Sbostic
52547147Sbostic
52647147Sbostic /*
52747147Sbostic * Called after a function returns.
52847147Sbostic */
52947147Sbostic
53047147Sbostic void
poplocalvars()53147147Sbostic poplocalvars() {
53247147Sbostic struct localvar *lvp;
53347147Sbostic struct var *vp;
53447147Sbostic
53547147Sbostic while ((lvp = localvars) != NULL) {
53647147Sbostic localvars = lvp->next;
53747147Sbostic vp = lvp->vp;
53847147Sbostic if (vp == NULL) { /* $- saved */
539*69272Schristos memcpy(optlist, lvp->text, sizeof optlist);
54047147Sbostic ckfree(lvp->text);
54147147Sbostic } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
54254325Smarc (void)unsetvar(vp->text);
54347147Sbostic } else {
54447147Sbostic if ((vp->flags & VTEXTFIXED) == 0)
54547147Sbostic ckfree(vp->text);
54647147Sbostic vp->flags = lvp->flags;
54747147Sbostic vp->text = lvp->text;
54847147Sbostic }
54947147Sbostic ckfree(lvp);
55047147Sbostic }
55147147Sbostic }
55247147Sbostic
55347147Sbostic
554*69272Schristos int
setvarcmd(argc,argv)555*69272Schristos setvarcmd(argc, argv)
556*69272Schristos int argc;
557*69272Schristos char **argv;
558*69272Schristos {
55947147Sbostic if (argc <= 2)
56047147Sbostic return unsetcmd(argc, argv);
56147147Sbostic else if (argc == 3)
56247147Sbostic setvar(argv[1], argv[2], 0);
56347147Sbostic else
56447147Sbostic error("List assignment not implemented");
56547147Sbostic return 0;
56647147Sbostic }
56747147Sbostic
56847147Sbostic
56947147Sbostic /*
57047147Sbostic * The unset builtin command. We unset the function before we unset the
57147147Sbostic * variable to allow a function to be unset when there is a readonly variable
57247147Sbostic * with the same name.
57347147Sbostic */
57447147Sbostic
575*69272Schristos int
unsetcmd(argc,argv)576*69272Schristos unsetcmd(argc, argv)
577*69272Schristos int argc;
578*69272Schristos char **argv;
579*69272Schristos {
58047147Sbostic char **ap;
58154325Smarc int i;
58254325Smarc int flg_func = 0;
58354325Smarc int flg_var = 0;
58454325Smarc int ret = 0;
58547147Sbostic
58654325Smarc while ((i = nextopt("vf")) != '\0') {
58754325Smarc if (i == 'f')
58854325Smarc flg_func = 1;
58954325Smarc else
59054325Smarc flg_var = 1;
59147147Sbostic }
59254325Smarc if (flg_func == 0 && flg_var == 0)
59354325Smarc flg_var = 1;
59454325Smarc
59554325Smarc for (ap = argptr; *ap ; ap++) {
59654325Smarc if (flg_func)
59754325Smarc ret |= unsetfunc(*ap);
59854325Smarc if (flg_var)
59954325Smarc ret |= unsetvar(*ap);
60054325Smarc }
60154325Smarc return ret;
60247147Sbostic }
60347147Sbostic
60447147Sbostic
60547147Sbostic /*
60647147Sbostic * Unset the specified variable.
60747147Sbostic */
60847147Sbostic
60954325Smarc STATIC int
unsetvar(s)61047147Sbostic unsetvar(s)
61147147Sbostic char *s;
61247147Sbostic {
61347147Sbostic struct var **vpp;
61447147Sbostic struct var *vp;
61547147Sbostic
61647147Sbostic vpp = hashvar(s);
61747147Sbostic for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
61847147Sbostic if (varequal(vp->text, s)) {
61954325Smarc if (vp->flags & VREADONLY)
62054325Smarc return (1);
62147147Sbostic INTOFF;
62254325Smarc if (*(strchr(vp->text, '=') + 1) != '\0')
62347147Sbostic setvar(s, nullstr, 0);
62447147Sbostic vp->flags &=~ VEXPORT;
62547147Sbostic vp->flags |= VUNSET;
62647147Sbostic if ((vp->flags & VSTRFIXED) == 0) {
62747147Sbostic if ((vp->flags & VTEXTFIXED) == 0)
62847147Sbostic ckfree(vp->text);
62947147Sbostic *vpp = vp->next;
63047147Sbostic ckfree(vp);
63147147Sbostic }
63247147Sbostic INTON;
63354325Smarc return (0);
63447147Sbostic }
63547147Sbostic }
63654325Smarc
63754325Smarc return (1);
63847147Sbostic }
63947147Sbostic
64047147Sbostic
64147147Sbostic
64247147Sbostic /*
64347147Sbostic * Find the appropriate entry in the hash table from the name.
64447147Sbostic */
64547147Sbostic
64647147Sbostic STATIC struct var **
hashvar(p)64747147Sbostic hashvar(p)
64847147Sbostic register char *p;
64947147Sbostic {
65047147Sbostic unsigned int hashval;
65147147Sbostic
65247147Sbostic hashval = *p << 4;
65347147Sbostic while (*p && *p != '=')
65447147Sbostic hashval += *p++;
65547147Sbostic return &vartab[hashval % VTABSIZE];
65647147Sbostic }
65747147Sbostic
65847147Sbostic
65947147Sbostic
66047147Sbostic /*
66147147Sbostic * Returns true if the two strings specify the same varable. The first
66247147Sbostic * variable name is terminated by '='; the second may be terminated by
66347147Sbostic * either '=' or '\0'.
66447147Sbostic */
66547147Sbostic
66647147Sbostic STATIC int
varequal(p,q)66747147Sbostic varequal(p, q)
66847147Sbostic register char *p, *q;
66947147Sbostic {
67047147Sbostic while (*p == *q++) {
67147147Sbostic if (*p++ == '=')
67247147Sbostic return 1;
67347147Sbostic }
67447147Sbostic if (*p == '=' && *(q - 1) == '\0')
67547147Sbostic return 1;
67647147Sbostic return 0;
67747147Sbostic }
678