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