var.c revision 216870
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1991, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Kenneth Almquist.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 4. Neither the name of the University nor the names of its contributors
171590Srgrimes *    may be used to endorse or promote products derived from this software
181590Srgrimes *    without specific prior written permission.
191590Srgrimes *
201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301590Srgrimes * SUCH DAMAGE.
311590Srgrimes */
321590Srgrimes
331590Srgrimes#ifndef lint
341590Srgrimes#if 0
351590Srgrimesstatic char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
361590Srgrimes#endif
371590Srgrimes#endif /* not lint */
381590Srgrimes#include <sys/cdefs.h>
391590Srgrimes__FBSDID("$FreeBSD: head/bin/sh/var.c 216870 2011-01-01 13:26:18Z jilles $");
401590Srgrimes
411590Srgrimes#include <unistd.h>
421590Srgrimes#include <stdlib.h>
431590Srgrimes#include <paths.h>
441590Srgrimes
451590Srgrimes/*
461590Srgrimes * Shell variables.
4718485Sbde */
481590Srgrimes
499992Sache#include <locale.h>
509992Sache
5111758Sache#include "shell.h"
521590Srgrimes#include "output.h"
531590Srgrimes#include "expand.h"
541590Srgrimes#include "nodes.h"	/* for other headers */
551590Srgrimes#include "eval.h"	/* defines cmdenviron */
561590Srgrimes#include "exec.h"
571590Srgrimes#include "syntax.h"
581590Srgrimes#include "options.h"
591590Srgrimes#include "mail.h"
601590Srgrimes#include "var.h"
611590Srgrimes#include "memalloc.h"
621590Srgrimes#include "error.h"
631590Srgrimes#include "mystring.h"
641590Srgrimes#include "parser.h"
651590Srgrimes#ifndef NO_HISTORY
668874Srgrimes#include "myhistedit.h"
671590Srgrimes#endif
681590Srgrimes
691590Srgrimes
701590Srgrimes#define VTABSIZE 39
711590Srgrimes
721590Srgrimes
731590Srgrimesstruct varinit {
741590Srgrimes	struct var *var;
751590Srgrimes	int flags;
761590Srgrimes	const char *text;
771590Srgrimes	void (*func)(const char *);
781590Srgrimes};
791590Srgrimes
801590Srgrimes
8118485Sbde#ifndef NO_HISTORY
821590Srgrimesstruct var vhistsize;
831590Srgrimesstruct var vterm;
841590Srgrimes#endif
851590Srgrimesstruct var vifs;
861590Srgrimesstruct var vmail;
871590Srgrimesstruct var vmpath;
881590Srgrimesstruct var vpath;
8911758Sachestruct var vppid;
9011758Sachestruct var vps1;
911590Srgrimesstruct var vps2;
921590Srgrimesstruct var vps4;
931590Srgrimesstruct var vvers;
941590Srgrimesstatic struct var voptind;
951590Srgrimes
961590Srgrimesstatic const struct varinit varinit[] = {
971590Srgrimes#ifndef NO_HISTORY
981590Srgrimes	{ &vhistsize,	VUNSET,				"HISTSIZE=",
991590Srgrimes	  sethistsize },
1001590Srgrimes#endif
1011590Srgrimes	{ &vifs,	0,				"IFS= \t\n",
1021590Srgrimes	  NULL },
1031590Srgrimes	{ &vmail,	VUNSET,				"MAIL=",
1041590Srgrimes	  NULL },
1051590Srgrimes	{ &vmpath,	VUNSET,				"MAILPATH=",
1061590Srgrimes	  NULL },
1071590Srgrimes	{ &vpath,	0,				"PATH=" _PATH_DEFPATH,
1081590Srgrimes	  changepath },
1091590Srgrimes	{ &vppid,	VUNSET,				"PPID=",
1101590Srgrimes	  NULL },
1111590Srgrimes	/*
1121590Srgrimes	 * vps1 depends on uid
1131590Srgrimes	 */
1141590Srgrimes	{ &vps2,	0,				"PS2=> ",
1151590Srgrimes	  NULL },
1161590Srgrimes	{ &vps4,	0,				"PS4=+ ",
1171590Srgrimes	  NULL },
1181590Srgrimes#ifndef NO_HISTORY
1191590Srgrimes	{ &vterm,	VUNSET,				"TERM=",
1201590Srgrimes	  setterm },
1211590Srgrimes#endif
1221590Srgrimes	{ &voptind,	0,				"OPTIND=1",
1231590Srgrimes	  getoptsreset },
1241590Srgrimes	{ NULL,	0,				NULL,
1251590Srgrimes	  NULL }
1261590Srgrimes};
1271590Srgrimes
1281590Srgrimesstatic struct var *vartab[VTABSIZE];
1291590Srgrimes
1301590Srgrimesstatic const char *const locale_names[7] = {
1311590Srgrimes	"LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
1321590Srgrimes	"LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
1331590Srgrimes};
1341590Srgrimesstatic const int locale_categories[7] = {
1351590Srgrimes	LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
1361590Srgrimes};
1371590Srgrimes
1381590Srgrimesstatic struct var **hashvar(const char *);
1391590Srgrimesstatic int varequal(const char *, const char *);
1401590Srgrimesstatic int localevar(const char *);
1411590Srgrimes
1421590Srgrimes/*
1435239Sats * Initialize the variable symbol tables and import the environment.
1445239Sats */
1451590Srgrimes
1461590Srgrimes#ifdef mkinit
1471590SrgrimesINCLUDE "var.h"
1481590SrgrimesMKINIT char **environ;
1491590SrgrimesINIT {
1501590Srgrimes	char **envp;
1519992Sache
1529992Sache	initvar();
1535239Sats	for (envp = environ ; *envp ; envp++) {
1541590Srgrimes		if (strchr(*envp, '=')) {
1551590Srgrimes			setvareq(*envp, VEXPORT|VTEXTFIXED);
1561590Srgrimes		}
1571590Srgrimes	}
1589992Sache}
1591590Srgrimes#endif
1601590Srgrimes
1611590Srgrimes
1621590Srgrimes/*
1631590Srgrimes * This routine initializes the builtin variables.  It is called when the
1641590Srgrimes * shell is initialized and again when a shell procedure is spawned.
1651590Srgrimes */
1661590Srgrimes
1671590Srgrimesvoid
1681590Srgrimesinitvar(void)
1691590Srgrimes{
1701590Srgrimes	char ppid[20];
1711590Srgrimes	const struct varinit *ip;
1721590Srgrimes	struct var *vp;
1731590Srgrimes	struct var **vpp;
1741590Srgrimes
1751590Srgrimes	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
1761590Srgrimes		if ((vp->flags & VEXPORT) == 0) {
1771590Srgrimes			vpp = hashvar(ip->text);
1781590Srgrimes			vp->next = *vpp;
1791590Srgrimes			*vpp = vp;
1801590Srgrimes			vp->text = __DECONST(char *, ip->text);
1811590Srgrimes			vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
1821590Srgrimes			vp->func = ip->func;
1831590Srgrimes		}
1841590Srgrimes	}
1851590Srgrimes	/*
1861590Srgrimes	 * PS1 depends on uid
1871590Srgrimes	 */
1881590Srgrimes	if ((vps1.flags & VEXPORT) == 0) {
1891590Srgrimes		vpp = hashvar("PS1=");
1901590Srgrimes		vps1.next = *vpp;
191		*vpp = &vps1;
192		vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
193		vps1.flags = VSTRFIXED|VTEXTFIXED;
194	}
195	if ((vppid.flags & VEXPORT) == 0) {
196		fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
197		setvarsafe("PPID", ppid, 0);
198	}
199}
200
201/*
202 * Safe version of setvar, returns 1 on success 0 on failure.
203 */
204
205int
206setvarsafe(const char *name, const char *val, int flags)
207{
208	struct jmploc jmploc;
209	struct jmploc *const savehandler = handler;
210	int err = 0;
211	int inton;
212
213	inton = is_int_on();
214	if (setjmp(jmploc.loc))
215		err = 1;
216	else {
217		handler = &jmploc;
218		setvar(name, val, flags);
219	}
220	handler = savehandler;
221	SETINTON(inton);
222	return err;
223}
224
225/*
226 * Set the value of a variable.  The flags argument is stored with the
227 * flags of the variable.  If val is NULL, the variable is unset.
228 */
229
230void
231setvar(const char *name, const char *val, int flags)
232{
233	const char *p;
234	int len;
235	int namelen;
236	char *nameeq;
237	int isbad;
238
239	isbad = 0;
240	p = name;
241	if (! is_name(*p))
242		isbad = 1;
243	p++;
244	for (;;) {
245		if (! is_in_name(*p)) {
246			if (*p == '\0' || *p == '=')
247				break;
248			isbad = 1;
249		}
250		p++;
251	}
252	namelen = p - name;
253	if (isbad)
254		error("%.*s: bad variable name", namelen, name);
255	len = namelen + 2;		/* 2 is space for '=' and '\0' */
256	if (val == NULL) {
257		flags |= VUNSET;
258	} else {
259		len += strlen(val);
260	}
261	nameeq = ckmalloc(len);
262	memcpy(nameeq, name, namelen);
263	nameeq[namelen] = '=';
264	if (val)
265		scopy(val, nameeq + namelen + 1);
266	else
267		nameeq[namelen + 1] = '\0';
268	setvareq(nameeq, flags);
269}
270
271static int
272localevar(const char *s)
273{
274	const char *const *ss;
275
276	if (*s != 'L')
277		return 0;
278	if (varequal(s + 1, "ANG"))
279		return 1;
280	if (strncmp(s + 1, "C_", 2) != 0)
281		return 0;
282	if (varequal(s + 3, "ALL"))
283		return 1;
284	for (ss = locale_names; *ss ; ss++)
285		if (varequal(s + 3, *ss + 3))
286			return 1;
287	return 0;
288}
289
290
291/*
292 * Sets/unsets an environment variable from a pointer that may actually be a
293 * pointer into environ where the string should not be manipulated.
294 */
295static void
296change_env(const char *s, int set)
297{
298	char *eqp;
299	char *ss;
300
301	ss = savestr(s);
302	if ((eqp = strchr(ss, '=')) != NULL)
303		*eqp = '\0';
304	if (set && eqp != NULL)
305		(void) setenv(ss, eqp + 1, 1);
306	else
307		(void) unsetenv(ss);
308	ckfree(ss);
309
310	return;
311}
312
313
314/*
315 * Same as setvar except that the variable and value are passed in
316 * the first argument as name=value.  Since the first argument will
317 * be actually stored in the table, it should not be a string that
318 * will go away.
319 */
320
321void
322setvareq(char *s, int flags)
323{
324	struct var *vp, **vpp;
325	int len;
326
327	if (aflag)
328		flags |= VEXPORT;
329	vpp = hashvar(s);
330	for (vp = *vpp ; vp ; vp = vp->next) {
331		if (varequal(s, vp->text)) {
332			if (vp->flags & VREADONLY) {
333				len = strchr(s, '=') - s;
334				error("%.*s: is read only", len, s);
335			}
336			if (flags & VNOSET)
337				return;
338			INTOFF;
339
340			if (vp->func && (flags & VNOFUNC) == 0)
341				(*vp->func)(strchr(s, '=') + 1);
342
343			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
344				ckfree(vp->text);
345
346			vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
347			vp->flags |= flags;
348			vp->text = s;
349
350			/*
351			 * We could roll this to a function, to handle it as
352			 * a regular variable function callback, but why bother?
353			 *
354			 * Note: this assumes iflag is not set to 1 initially.
355			 * As part of init(), this is called before arguments
356			 * are looked at.
357			 */
358			if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
359			    iflag == 1)
360				chkmail(1);
361			if ((vp->flags & VEXPORT) && localevar(s)) {
362				change_env(s, 1);
363				(void) setlocale(LC_ALL, "");
364			}
365			INTON;
366			return;
367		}
368	}
369	/* not found */
370	if (flags & VNOSET)
371		return;
372	vp = ckmalloc(sizeof (*vp));
373	vp->flags = flags;
374	vp->text = s;
375	vp->next = *vpp;
376	vp->func = NULL;
377	INTOFF;
378	*vpp = vp;
379	if ((vp->flags & VEXPORT) && localevar(s)) {
380		change_env(s, 1);
381		(void) setlocale(LC_ALL, "");
382	}
383	INTON;
384}
385
386
387
388/*
389 * Process a linked list of variable assignments.
390 */
391
392void
393listsetvar(struct strlist *list, int flags)
394{
395	struct strlist *lp;
396
397	INTOFF;
398	for (lp = list ; lp ; lp = lp->next) {
399		setvareq(savestr(lp->text), flags);
400	}
401	INTON;
402}
403
404
405
406/*
407 * Find the value of a variable.  Returns NULL if not set.
408 */
409
410char *
411lookupvar(const char *name)
412{
413	struct var *v;
414
415	for (v = *hashvar(name) ; v ; v = v->next) {
416		if (varequal(v->text, name)) {
417			if (v->flags & VUNSET)
418				return NULL;
419			return strchr(v->text, '=') + 1;
420		}
421	}
422	return NULL;
423}
424
425
426
427/*
428 * Search the environment of a builtin command.  If the second argument
429 * is nonzero, return the value of a variable even if it hasn't been
430 * exported.
431 */
432
433char *
434bltinlookup(const char *name, int doall)
435{
436	struct strlist *sp;
437	struct var *v;
438	char *result;
439
440	result = NULL;
441	for (sp = cmdenviron ; sp ; sp = sp->next) {
442		if (varequal(sp->text, name))
443			result = strchr(sp->text, '=') + 1;
444	}
445	if (result != NULL)
446		return result;
447	for (v = *hashvar(name) ; v ; v = v->next) {
448		if (varequal(v->text, name)) {
449			if ((v->flags & VUNSET)
450			 || (!doall && (v->flags & VEXPORT) == 0))
451				return NULL;
452			return strchr(v->text, '=') + 1;
453		}
454	}
455	return NULL;
456}
457
458
459/*
460 * Set up locale for a builtin (LANG/LC_* assignments).
461 */
462void
463bltinsetlocale(void)
464{
465	struct strlist *lp;
466	int act = 0;
467	char *loc, *locdef;
468	int i;
469
470	for (lp = cmdenviron ; lp ; lp = lp->next) {
471		if (localevar(lp->text)) {
472			act = 1;
473			break;
474		}
475	}
476	if (!act)
477		return;
478	loc = bltinlookup("LC_ALL", 0);
479	INTOFF;
480	if (loc != NULL) {
481		setlocale(LC_ALL, loc);
482		INTON;
483		return;
484	}
485	locdef = bltinlookup("LANG", 0);
486	for (i = 0; locale_names[i] != NULL; i++) {
487		loc = bltinlookup(locale_names[i], 0);
488		if (loc == NULL)
489			loc = locdef;
490		if (loc != NULL)
491			setlocale(locale_categories[i], loc);
492	}
493	INTON;
494}
495
496/*
497 * Undo the effect of bltinlocaleset().
498 */
499void
500bltinunsetlocale(void)
501{
502	struct strlist *lp;
503
504	INTOFF;
505	for (lp = cmdenviron ; lp ; lp = lp->next) {
506		if (localevar(lp->text)) {
507			setlocale(LC_ALL, "");
508			return;
509		}
510	}
511	INTON;
512}
513
514
515/*
516 * Generate a list of exported variables.  This routine is used to construct
517 * the third argument to execve when executing a program.
518 */
519
520char **
521environment(void)
522{
523	int nenv;
524	struct var **vpp;
525	struct var *vp;
526	char **env, **ep;
527
528	nenv = 0;
529	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
530		for (vp = *vpp ; vp ; vp = vp->next)
531			if (vp->flags & VEXPORT)
532				nenv++;
533	}
534	ep = env = stalloc((nenv + 1) * sizeof *env);
535	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
536		for (vp = *vpp ; vp ; vp = vp->next)
537			if (vp->flags & VEXPORT)
538				*ep++ = vp->text;
539	}
540	*ep = NULL;
541	return env;
542}
543
544
545/*
546 * Called when a shell procedure is invoked to clear out nonexported
547 * variables.  It is also necessary to reallocate variables of with
548 * VSTACK set since these are currently allocated on the stack.
549 */
550
551MKINIT void shprocvar(void);
552
553#ifdef mkinit
554SHELLPROC {
555	shprocvar();
556}
557#endif
558
559void
560shprocvar(void)
561{
562	struct var **vpp;
563	struct var *vp, **prev;
564
565	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
566		for (prev = vpp ; (vp = *prev) != NULL ; ) {
567			if ((vp->flags & VEXPORT) == 0) {
568				*prev = vp->next;
569				if ((vp->flags & VTEXTFIXED) == 0)
570					ckfree(vp->text);
571				if ((vp->flags & VSTRFIXED) == 0)
572					ckfree(vp);
573			} else {
574				if (vp->flags & VSTACK) {
575					vp->text = savestr(vp->text);
576					vp->flags &=~ VSTACK;
577				}
578				prev = &vp->next;
579			}
580		}
581	}
582	initvar();
583}
584
585
586static int
587var_compare(const void *a, const void *b)
588{
589	const char *const *sa, *const *sb;
590
591	sa = a;
592	sb = b;
593	/*
594	 * This compares two var=value strings which creates a different
595	 * order from what you would probably expect.  POSIX is somewhat
596	 * ambiguous on what should be sorted exactly.
597	 */
598	return strcoll(*sa, *sb);
599}
600
601
602/*
603 * Command to list all variables which are set.  Currently this command
604 * is invoked from the set command when the set command is called without
605 * any variables.
606 */
607
608int
609showvarscmd(int argc __unused, char **argv __unused)
610{
611	struct var **vpp;
612	struct var *vp;
613	const char *s;
614	const char **vars;
615	int i, n;
616
617	/*
618	 * POSIX requires us to sort the variables.
619	 */
620	n = 0;
621	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
622		for (vp = *vpp; vp; vp = vp->next) {
623			if (!(vp->flags & VUNSET))
624				n++;
625		}
626	}
627
628	INTON;
629	vars = ckmalloc(n * sizeof(*vars));
630	i = 0;
631	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
632		for (vp = *vpp; vp; vp = vp->next) {
633			if (!(vp->flags & VUNSET))
634				vars[i++] = vp->text;
635		}
636	}
637
638	qsort(vars, n, sizeof(*vars), var_compare);
639	for (i = 0; i < n; i++) {
640		s = strchr(vars[i], '=');
641		s++;
642		outbin(vars[i], s - vars[i], out1);
643		out1qstr(s);
644		out1c('\n');
645	}
646	ckfree(vars);
647	INTOFF;
648
649	return 0;
650}
651
652
653
654/*
655 * The export and readonly commands.
656 */
657
658int
659exportcmd(int argc, char **argv)
660{
661	struct var **vpp;
662	struct var *vp;
663	char *name;
664	char *p;
665	char *cmdname;
666	int ch, values;
667	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
668
669	cmdname = argv[0];
670	optreset = optind = 1;
671	opterr = 0;
672	values = 0;
673	while ((ch = getopt(argc, argv, "p")) != -1) {
674		switch (ch) {
675		case 'p':
676			values = 1;
677			break;
678		case '?':
679		default:
680			error("unknown option: -%c", optopt);
681		}
682	}
683	argc -= optind;
684	argv += optind;
685
686	if (values && argc != 0)
687		error("-p requires no arguments");
688	if (argc != 0) {
689		while ((name = *argv++) != NULL) {
690			if ((p = strchr(name, '=')) != NULL) {
691				p++;
692			} else {
693				vpp = hashvar(name);
694				for (vp = *vpp ; vp ; vp = vp->next) {
695					if (varequal(vp->text, name)) {
696
697						vp->flags |= flag;
698						if ((vp->flags & VEXPORT) && localevar(vp->text)) {
699							change_env(vp->text, 1);
700							(void) setlocale(LC_ALL, "");
701						}
702						goto found;
703					}
704				}
705			}
706			setvar(name, p, flag);
707found:;
708		}
709	} else {
710		for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
711			for (vp = *vpp ; vp ; vp = vp->next) {
712				if (vp->flags & flag) {
713					if (values) {
714						out1str(cmdname);
715						out1c(' ');
716					}
717					p = strchr(vp->text, '=');
718					if (values && !(vp->flags & VUNSET)) {
719						p++;
720						outbin(vp->text, p - vp->text,
721						    out1);
722						out1qstr(p);
723					} else
724						outbin(vp->text, p - vp->text,
725						    out1);
726					out1c('\n');
727				}
728			}
729		}
730	}
731	return 0;
732}
733
734
735/*
736 * The "local" command.
737 */
738
739int
740localcmd(int argc __unused, char **argv __unused)
741{
742	char *name;
743
744	if (! in_function())
745		error("Not in a function");
746	while ((name = *argptr++) != NULL) {
747		mklocal(name);
748	}
749	return 0;
750}
751
752
753/*
754 * Make a variable a local variable.  When a variable is made local, it's
755 * value and flags are saved in a localvar structure.  The saved values
756 * will be restored when the shell function returns.  We handle the name
757 * "-" as a special case.
758 */
759
760void
761mklocal(char *name)
762{
763	struct localvar *lvp;
764	struct var **vpp;
765	struct var *vp;
766
767	INTOFF;
768	lvp = ckmalloc(sizeof (struct localvar));
769	if (name[0] == '-' && name[1] == '\0') {
770		lvp->text = ckmalloc(sizeof optlist);
771		memcpy(lvp->text, optlist, sizeof optlist);
772		vp = NULL;
773	} else {
774		vpp = hashvar(name);
775		for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
776		if (vp == NULL) {
777			if (strchr(name, '='))
778				setvareq(savestr(name), VSTRFIXED);
779			else
780				setvar(name, NULL, VSTRFIXED);
781			vp = *vpp;	/* the new variable */
782			lvp->text = NULL;
783			lvp->flags = VUNSET;
784		} else {
785			lvp->text = vp->text;
786			lvp->flags = vp->flags;
787			vp->flags |= VSTRFIXED|VTEXTFIXED;
788			if (strchr(name, '='))
789				setvareq(savestr(name), 0);
790		}
791	}
792	lvp->vp = vp;
793	lvp->next = localvars;
794	localvars = lvp;
795	INTON;
796}
797
798
799/*
800 * Called after a function returns.
801 */
802
803void
804poplocalvars(void)
805{
806	struct localvar *lvp;
807	struct var *vp;
808
809	while ((lvp = localvars) != NULL) {
810		localvars = lvp->next;
811		vp = lvp->vp;
812		if (vp == NULL) {	/* $- saved */
813			memcpy(optlist, lvp->text, sizeof optlist);
814			ckfree(lvp->text);
815			optschanged();
816		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
817			(void)unsetvar(vp->text);
818		} else {
819			if ((vp->flags & VTEXTFIXED) == 0)
820				ckfree(vp->text);
821			vp->flags = lvp->flags;
822			vp->text = lvp->text;
823		}
824		ckfree(lvp);
825	}
826}
827
828
829int
830setvarcmd(int argc, char **argv)
831{
832	if (argc <= 2)
833		return unsetcmd(argc, argv);
834	else if (argc == 3)
835		setvar(argv[1], argv[2], 0);
836	else
837		error("too many arguments");
838	return 0;
839}
840
841
842/*
843 * The unset builtin command.  We unset the function before we unset the
844 * variable to allow a function to be unset when there is a readonly variable
845 * with the same name.
846 */
847
848int
849unsetcmd(int argc __unused, char **argv __unused)
850{
851	char **ap;
852	int i;
853	int flg_func = 0;
854	int flg_var = 0;
855	int ret = 0;
856
857	while ((i = nextopt("vf")) != '\0') {
858		if (i == 'f')
859			flg_func = 1;
860		else
861			flg_var = 1;
862	}
863	if (flg_func == 0 && flg_var == 0)
864		flg_var = 1;
865
866	for (ap = argptr; *ap ; ap++) {
867		if (flg_func)
868			ret |= unsetfunc(*ap);
869		if (flg_var)
870			ret |= unsetvar(*ap);
871	}
872	return ret;
873}
874
875
876/*
877 * Unset the specified variable.
878 */
879
880int
881unsetvar(const char *s)
882{
883	struct var **vpp;
884	struct var *vp;
885
886	vpp = hashvar(s);
887	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
888		if (varequal(vp->text, s)) {
889			if (vp->flags & VREADONLY)
890				return (1);
891			INTOFF;
892			if (*(strchr(vp->text, '=') + 1) != '\0')
893				setvar(s, nullstr, 0);
894			if ((vp->flags & VEXPORT) && localevar(vp->text)) {
895				change_env(s, 0);
896				setlocale(LC_ALL, "");
897			}
898			vp->flags &= ~VEXPORT;
899			vp->flags |= VUNSET;
900			if ((vp->flags & VSTRFIXED) == 0) {
901				if ((vp->flags & VTEXTFIXED) == 0)
902					ckfree(vp->text);
903				*vpp = vp->next;
904				ckfree(vp);
905			}
906			INTON;
907			return (0);
908		}
909	}
910
911	return (0);
912}
913
914
915
916/*
917 * Find the appropriate entry in the hash table from the name.
918 */
919
920static struct var **
921hashvar(const char *p)
922{
923	unsigned int hashval;
924
925	hashval = ((unsigned char) *p) << 4;
926	while (*p && *p != '=')
927		hashval += (unsigned char) *p++;
928	return &vartab[hashval % VTABSIZE];
929}
930
931
932
933/*
934 * Returns true if the two strings specify the same varable.  The first
935 * variable name is terminated by '='; the second may be terminated by
936 * either '=' or '\0'.
937 */
938
939static int
940varequal(const char *p, const char *q)
941{
942	while (*p == *q++) {
943		if (*p++ == '=')
944			return 1;
945	}
946	if (*p == '=' && *(q - 1) == '\0')
947		return 1;
948	return 0;
949}
950