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