var.c revision 259846
1184610Salfred/*-
2184610Salfred * Copyright (c) 1991, 1993
3189002Sed *	The Regents of the University of California.  All rights reserved.
4184610Salfred *
5184610Salfred * This code is derived from software contributed to Berkeley by
6184610Salfred * Kenneth Almquist.
7184610Salfred *
8184610Salfred * Redistribution and use in source and binary forms, with or without
9184610Salfred * modification, are permitted provided that the following conditions
10184610Salfred * are met:
11184610Salfred * 1. Redistributions of source code must retain the above copyright
12184610Salfred *    notice, this list of conditions and the following disclaimer.
13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer in the
15184610Salfred *    documentation and/or other materials provided with the distribution.
16184610Salfred * 4. Neither the name of the University nor the names of its contributors
17184610Salfred *    may be used to endorse or promote products derived from this software
18184610Salfred *    without specific prior written permission.
19184610Salfred *
20184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30184610Salfred * SUCH DAMAGE.
31187170Sthompsa */
32187170Sthompsa
33184610Salfred#ifndef lint
34184610Salfred#if 0
35184610Salfredstatic char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
36184610Salfred#endif
37184610Salfred#endif /* not lint */
38184610Salfred#include <sys/cdefs.h>
39184610Salfred__FBSDID("$FreeBSD: head/bin/sh/var.c 259846 2013-12-24 22:38:24Z jilles $");
40184610Salfred
41184610Salfred#include <unistd.h>
42184610Salfred#include <stdlib.h>
43184610Salfred#include <paths.h>
44184610Salfred
45184610Salfred/*
46184610Salfred * Shell variables.
47184610Salfred */
48184610Salfred
49184610Salfred#include <locale.h>
50184610Salfred#include <langinfo.h>
51184610Salfred
52184610Salfred#include "shell.h"
53184610Salfred#include "output.h"
54184610Salfred#include "expand.h"
55184610Salfred#include "nodes.h"	/* for other headers */
56184610Salfred#include "eval.h"	/* defines cmdenviron */
57184610Salfred#include "exec.h"
58184610Salfred#include "syntax.h"
59184610Salfred#include "options.h"
60184610Salfred#include "mail.h"
61184610Salfred#include "var.h"
62184610Salfred#include "memalloc.h"
63184610Salfred#include "error.h"
64184610Salfred#include "mystring.h"
65184610Salfred#include "parser.h"
66184610Salfred#include "builtins.h"
67184610Salfred#ifndef NO_HISTORY
68184610Salfred#include "myhistedit.h"
69184610Salfred#endif
70184610Salfred
71184610Salfred
72184610Salfred#define VTABSIZE 39
73184610Salfred
74184610Salfred
75184610Salfredstruct varinit {
76184610Salfred	struct var *var;
77184610Salfred	int flags;
78184610Salfred	const char *text;
79184610Salfred	void (*func)(const char *);
80184610Salfred};
81184610Salfred
82184610Salfred
83184610Salfred#ifndef NO_HISTORY
84184610Salfredstruct var vhistsize;
85184610Salfredstruct var vterm;
86184610Salfred#endif
87184610Salfredstruct var vifs;
88184610Salfredstruct var vmail;
89184610Salfredstruct var vmpath;
90184610Salfredstruct var vpath;
91184610Salfredstruct var vppid;
92184610Salfredstruct var vps1;
93184610Salfredstruct var vps2;
94184610Salfredstruct var vps4;
95184610Salfredstatic struct var voptind;
96184610Salfredstruct var vdisvfork;
97184610Salfred
98184610Salfredint forcelocal;
99184610Salfred
100184610Salfredstatic const struct varinit varinit[] = {
101184610Salfred#ifndef NO_HISTORY
102184610Salfred	{ &vhistsize,	VUNSET,				"HISTSIZE=",
103184610Salfred	  sethistsize },
104184610Salfred#endif
105184610Salfred	{ &vifs,	0,				"IFS= \t\n",
106184610Salfred	  NULL },
107184610Salfred	{ &vmail,	VUNSET,				"MAIL=",
108184610Salfred	  NULL },
109184610Salfred	{ &vmpath,	VUNSET,				"MAILPATH=",
110184610Salfred	  NULL },
111184610Salfred	{ &vpath,	0,				"PATH=" _PATH_DEFPATH,
112184610Salfred	  changepath },
113184610Salfred	{ &vppid,	VUNSET,				"PPID=",
114184610Salfred	  NULL },
115184610Salfred	/*
116184610Salfred	 * vps1 depends on uid
117184610Salfred	 */
118184610Salfred	{ &vps2,	0,				"PS2=> ",
119184610Salfred	  NULL },
120184610Salfred	{ &vps4,	0,				"PS4=+ ",
121184610Salfred	  NULL },
122184610Salfred#ifndef NO_HISTORY
123184610Salfred	{ &vterm,	VUNSET,				"TERM=",
124184610Salfred	  setterm },
125184610Salfred#endif
126184610Salfred	{ &voptind,	0,				"OPTIND=1",
127184610Salfred	  getoptsreset },
128184610Salfred	{ &vdisvfork,	VUNSET,				"SH_DISABLE_VFORK=",
129184610Salfred	  NULL },
130184610Salfred	{ NULL,	0,				NULL,
131184610Salfred	  NULL }
132184610Salfred};
133184610Salfred
134184610Salfredstatic struct var *vartab[VTABSIZE];
135184610Salfred
136184610Salfredstatic const char *const locale_names[7] = {
137184610Salfred	"LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
138184610Salfred	"LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
139184610Salfred};
140184610Salfredstatic const int locale_categories[7] = {
141184610Salfred	LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
142184610Salfred};
143184610Salfred
144184610Salfredstatic int varequal(const char *, const char *);
145184610Salfredstatic struct var *find_var(const char *, struct var ***, int *);
146184610Salfredstatic int localevar(const char *);
147184610Salfred
148184610Salfredextern char **environ;
149184610Salfred
150184610Salfred/*
151184610Salfred * This routine initializes the builtin variables and imports the environment.
152184610Salfred * It is called when the shell is initialized.
153184610Salfred */
154184610Salfred
155184610Salfredvoid
156184610Salfredinitvar(void)
157184610Salfred{
158184610Salfred	char ppid[20];
159184610Salfred	const struct varinit *ip;
160184610Salfred	struct var *vp;
161184610Salfred	struct var **vpp;
162184610Salfred	char **envp;
163184610Salfred
164184610Salfred	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
165184610Salfred		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
166184610Salfred			continue;
167184610Salfred		vp->next = *vpp;
168184610Salfred		*vpp = vp;
169184610Salfred		vp->text = __DECONST(char *, ip->text);
170184610Salfred		vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
171184610Salfred		vp->func = ip->func;
172184610Salfred	}
173184610Salfred	/*
174184610Salfred	 * PS1 depends on uid
175184610Salfred	 */
176184610Salfred	if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
177184610Salfred		vps1.next = *vpp;
178184610Salfred		*vpp = &vps1;
179184610Salfred		vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
180184610Salfred		vps1.flags = VSTRFIXED|VTEXTFIXED;
181184610Salfred	}
182184610Salfred	if ((vppid.flags & VEXPORT) == 0) {
183184610Salfred		fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
184184610Salfred		setvarsafe("PPID", ppid, 0);
185184610Salfred	}
186184610Salfred	for (envp = environ ; *envp ; envp++) {
187184610Salfred		if (strchr(*envp, '=')) {
188184610Salfred			setvareq(*envp, VEXPORT|VTEXTFIXED);
189184610Salfred		}
190184610Salfred	}
191184610Salfred	setvareq("OPTIND=1", VTEXTFIXED);
192184610Salfred}
193184610Salfred
194184610Salfred/*
195184610Salfred * Safe version of setvar, returns 1 on success 0 on failure.
196184610Salfred */
197184610Salfred
198184610Salfredint
199184610Salfredsetvarsafe(const char *name, const char *val, int flags)
200184610Salfred{
201184610Salfred	struct jmploc jmploc;
202184610Salfred	struct jmploc *const savehandler = handler;
203184610Salfred	int err = 0;
204184610Salfred	int inton;
205184610Salfred
206184610Salfred	inton = is_int_on();
207184610Salfred	if (setjmp(jmploc.loc))
208184610Salfred		err = 1;
209184610Salfred	else {
210184610Salfred		handler = &jmploc;
211184610Salfred		setvar(name, val, flags);
212184610Salfred	}
213184610Salfred	handler = savehandler;
214184610Salfred	SETINTON(inton);
215184610Salfred	return err;
216184610Salfred}
217184610Salfred
218184610Salfred/*
219184610Salfred * Set the value of a variable.  The flags argument is stored with the
220184610Salfred * flags of the variable.  If val is NULL, the variable is unset.
221184610Salfred */
222184610Salfred
223184610Salfredvoid
224184610Salfredsetvar(const char *name, const char *val, int flags)
225184610Salfred{
226184610Salfred	const char *p;
227184610Salfred	size_t len;
228184610Salfred	size_t namelen;
229184610Salfred	size_t vallen;
230184610Salfred	char *nameeq;
231184610Salfred	int isbad;
232184610Salfred
233184610Salfred	isbad = 0;
234184610Salfred	p = name;
235184610Salfred	if (! is_name(*p))
236184610Salfred		isbad = 1;
237184610Salfred	p++;
238184610Salfred	for (;;) {
239184610Salfred		if (! is_in_name(*p)) {
240184610Salfred			if (*p == '\0' || *p == '=')
241184610Salfred				break;
242184610Salfred			isbad = 1;
243184610Salfred		}
244184610Salfred		p++;
245184610Salfred	}
246184610Salfred	namelen = p - name;
247184610Salfred	if (isbad)
248184610Salfred		error("%.*s: bad variable name", (int)namelen, name);
249184610Salfred	len = namelen + 2;		/* 2 is space for '=' and '\0' */
250184610Salfred	if (val == NULL) {
251184610Salfred		flags |= VUNSET;
252184610Salfred		vallen = 0;
253184610Salfred	} else {
254184610Salfred		vallen = strlen(val);
255184610Salfred		len += vallen;
256184610Salfred	}
257184610Salfred	nameeq = ckmalloc(len);
258269564Shselasky	memcpy(nameeq, name, namelen);
259269564Shselasky	nameeq[namelen] = '=';
260269564Shselasky	if (val)
261269564Shselasky		memcpy(nameeq + namelen + 1, val, vallen + 1);
262184610Salfred	else
263269564Shselasky		nameeq[namelen + 1] = '\0';
264184610Salfred	setvareq(nameeq, flags);
265184610Salfred}
266269564Shselasky
267184610Salfredstatic int
268184610Salfredlocalevar(const char *s)
269269564Shselasky{
270184610Salfred	const char *const *ss;
271269564Shselasky
272184610Salfred	if (*s != 'L')
273184610Salfred		return 0;
274184610Salfred	if (varequal(s + 1, "ANG"))
275184610Salfred		return 1;
276192984Sthompsa	if (strncmp(s + 1, "C_", 2) != 0)
277184610Salfred		return 0;
278184610Salfred	if (varequal(s + 3, "ALL"))
279184610Salfred		return 1;
280184610Salfred	for (ss = locale_names; *ss ; ss++)
281184610Salfred		if (varequal(s + 3, *ss + 3))
282184610Salfred			return 1;
283184610Salfred	return 0;
284184610Salfred}
285184610Salfred
286192552Sthompsa
287184610Salfred/*
288184610Salfred * Sets/unsets an environment variable from a pointer that may actually be a
289184610Salfred * pointer into environ where the string should not be manipulated.
290184610Salfred */
291192984Sthompsastatic void
292184610Salfredchange_env(const char *s, int set)
293184610Salfred{
294184610Salfred	char *eqp;
295184610Salfred	char *ss;
296184610Salfred
297184610Salfred	ss = savestr(s);
298184610Salfred	if ((eqp = strchr(ss, '=')) != NULL)
299184610Salfred		*eqp = '\0';
300184610Salfred	if (set && eqp != NULL)
301184610Salfred		(void) setenv(ss, eqp + 1, 1);
302184610Salfred	else
303192552Sthompsa		(void) unsetenv(ss);
304184610Salfred	ckfree(ss);
305184610Salfred
306184610Salfred	return;
307192984Sthompsa}
308192984Sthompsa
309192984Sthompsa
310184610Salfred/*
311184610Salfred * Same as setvar except that the variable and value are passed in
312184610Salfred * the first argument as name=value.  Since the first argument will
313184610Salfred * be actually stored in the table, it should not be a string that
314192984Sthompsa * will go away.
315184610Salfred */
316184610Salfred
317184610Salfredvoid
318184610Salfredsetvareq(char *s, int flags)
319184610Salfred{
320184610Salfred	struct var *vp, **vpp;
321184610Salfred	int nlen;
322184610Salfred
323184610Salfred	if (aflag)
324184610Salfred		flags |= VEXPORT;
325184610Salfred	if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
326184610Salfred		mklocal(s);
327184610Salfred	vp = find_var(s, &vpp, &nlen);
328184610Salfred	if (vp != NULL) {
329184610Salfred		if (vp->flags & VREADONLY)
330184610Salfred			error("%.*s: is read only", vp->name_len, s);
331192984Sthompsa		if (flags & VNOSET)
332184610Salfred			return;
333184610Salfred		INTOFF;
334192984Sthompsa
335184610Salfred		if (vp->func && (flags & VNOFUNC) == 0)
336184610Salfred			(*vp->func)(s + vp->name_len + 1);
337184610Salfred
338184610Salfred		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
339184610Salfred			ckfree(vp->text);
340184610Salfred
341184610Salfred		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
342269564Shselasky		vp->flags |= flags;
343269564Shselasky		vp->text = s;
344184610Salfred
345184610Salfred		/*
346184610Salfred		 * We could roll this to a function, to handle it as
347184610Salfred		 * a regular variable function callback, but why bother?
348184610Salfred		 *
349184610Salfred		 * Note: this assumes iflag is not set to 1 initially.
350184610Salfred		 * As part of initvar(), this is called before arguments
351184610Salfred		 * are looked at.
352184610Salfred		 */
353184610Salfred		if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
354184610Salfred		    iflag == 1)
355193045Sthompsa			chkmail(1);
356184610Salfred		if ((vp->flags & VEXPORT) && localevar(s)) {
357269564Shselasky			change_env(s, 1);
358269564Shselasky			(void) setlocale(LC_ALL, "");
359184610Salfred			updatecharset();
360184610Salfred		}
361		INTON;
362		return;
363	}
364	/* not found */
365	if (flags & VNOSET)
366		return;
367	vp = ckmalloc(sizeof (*vp));
368	vp->flags = flags;
369	vp->text = s;
370	vp->name_len = nlen;
371	vp->next = *vpp;
372	vp->func = NULL;
373	INTOFF;
374	*vpp = vp;
375	if ((vp->flags & VEXPORT) && localevar(s)) {
376		change_env(s, 1);
377		(void) setlocale(LC_ALL, "");
378		updatecharset();
379	}
380	INTON;
381}
382
383
384
385/*
386 * Process a linked list of variable assignments.
387 */
388
389void
390listsetvar(struct strlist *list, int flags)
391{
392	struct strlist *lp;
393
394	INTOFF;
395	for (lp = list ; lp ; lp = lp->next) {
396		setvareq(savestr(lp->text), flags);
397	}
398	INTON;
399}
400
401
402
403/*
404 * Find the value of a variable.  Returns NULL if not set.
405 */
406
407char *
408lookupvar(const char *name)
409{
410	struct var *v;
411
412	v = find_var(name, NULL, NULL);
413	if (v == NULL || v->flags & VUNSET)
414		return NULL;
415	return v->text + v->name_len + 1;
416}
417
418
419
420/*
421 * Search the environment of a builtin command.  If the second argument
422 * is nonzero, return the value of a variable even if it hasn't been
423 * exported.
424 */
425
426char *
427bltinlookup(const char *name, int doall)
428{
429	struct strlist *sp;
430	struct var *v;
431	char *result;
432
433	result = NULL;
434	for (sp = cmdenviron ; sp ; sp = sp->next) {
435		if (varequal(sp->text, name))
436			result = strchr(sp->text, '=') + 1;
437	}
438	if (result != NULL)
439		return result;
440
441	v = find_var(name, NULL, NULL);
442	if (v == NULL || v->flags & VUNSET ||
443	    (!doall && (v->flags & VEXPORT) == 0))
444		return NULL;
445	return v->text + v->name_len + 1;
446}
447
448
449/*
450 * Set up locale for a builtin (LANG/LC_* assignments).
451 */
452void
453bltinsetlocale(void)
454{
455	struct strlist *lp;
456	int act = 0;
457	char *loc, *locdef;
458	int i;
459
460	for (lp = cmdenviron ; lp ; lp = lp->next) {
461		if (localevar(lp->text)) {
462			act = 1;
463			break;
464		}
465	}
466	if (!act)
467		return;
468	loc = bltinlookup("LC_ALL", 0);
469	INTOFF;
470	if (loc != NULL) {
471		setlocale(LC_ALL, loc);
472		INTON;
473		updatecharset();
474		return;
475	}
476	locdef = bltinlookup("LANG", 0);
477	for (i = 0; locale_names[i] != NULL; i++) {
478		loc = bltinlookup(locale_names[i], 0);
479		if (loc == NULL)
480			loc = locdef;
481		if (loc != NULL)
482			setlocale(locale_categories[i], loc);
483	}
484	INTON;
485	updatecharset();
486}
487
488/*
489 * Undo the effect of bltinlocaleset().
490 */
491void
492bltinunsetlocale(void)
493{
494	struct strlist *lp;
495
496	INTOFF;
497	for (lp = cmdenviron ; lp ; lp = lp->next) {
498		if (localevar(lp->text)) {
499			setlocale(LC_ALL, "");
500			updatecharset();
501			return;
502		}
503	}
504	INTON;
505}
506
507/*
508 * Update the localeisutf8 flag.
509 */
510void
511updatecharset(void)
512{
513	char *charset;
514
515	charset = nl_langinfo(CODESET);
516	localeisutf8 = !strcmp(charset, "UTF-8");
517}
518
519void
520initcharset(void)
521{
522	updatecharset();
523	initial_localeisutf8 = localeisutf8;
524}
525
526/*
527 * Generate a list of exported variables.  This routine is used to construct
528 * the third argument to execve when executing a program.
529 */
530
531char **
532environment(void)
533{
534	int nenv;
535	struct var **vpp;
536	struct var *vp;
537	char **env, **ep;
538
539	nenv = 0;
540	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
541		for (vp = *vpp ; vp ; vp = vp->next)
542			if (vp->flags & VEXPORT)
543				nenv++;
544	}
545	ep = env = stalloc((nenv + 1) * sizeof *env);
546	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
547		for (vp = *vpp ; vp ; vp = vp->next)
548			if (vp->flags & VEXPORT)
549				*ep++ = vp->text;
550	}
551	*ep = NULL;
552	return env;
553}
554
555
556static int
557var_compare(const void *a, const void *b)
558{
559	const char *const *sa, *const *sb;
560
561	sa = a;
562	sb = b;
563	/*
564	 * This compares two var=value strings which creates a different
565	 * order from what you would probably expect.  POSIX is somewhat
566	 * ambiguous on what should be sorted exactly.
567	 */
568	return strcoll(*sa, *sb);
569}
570
571
572/*
573 * Command to list all variables which are set.  This is invoked from the
574 * set command when it is called without any options or operands.
575 */
576
577int
578showvarscmd(int argc __unused, char **argv __unused)
579{
580	struct var **vpp;
581	struct var *vp;
582	const char *s;
583	const char **vars;
584	int i, n;
585
586	/*
587	 * POSIX requires us to sort the variables.
588	 */
589	n = 0;
590	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
591		for (vp = *vpp; vp; vp = vp->next) {
592			if (!(vp->flags & VUNSET))
593				n++;
594		}
595	}
596
597	INTOFF;
598	vars = ckmalloc(n * sizeof(*vars));
599	i = 0;
600	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
601		for (vp = *vpp; vp; vp = vp->next) {
602			if (!(vp->flags & VUNSET))
603				vars[i++] = vp->text;
604		}
605	}
606
607	qsort(vars, n, sizeof(*vars), var_compare);
608	for (i = 0; i < n; i++) {
609		/*
610		 * Skip improper variable names so the output remains usable as
611		 * shell input.
612		 */
613		if (!isassignment(vars[i]))
614			continue;
615		s = strchr(vars[i], '=');
616		s++;
617		outbin(vars[i], s - vars[i], out1);
618		out1qstr(s);
619		out1c('\n');
620	}
621	ckfree(vars);
622	INTON;
623
624	return 0;
625}
626
627
628
629/*
630 * The export and readonly commands.
631 */
632
633int
634exportcmd(int argc __unused, char **argv)
635{
636	struct var **vpp;
637	struct var *vp;
638	char **ap;
639	char *name;
640	char *p;
641	char *cmdname;
642	int ch, values;
643	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
644
645	cmdname = argv[0];
646	values = 0;
647	while ((ch = nextopt("p")) != '\0') {
648		switch (ch) {
649		case 'p':
650			values = 1;
651			break;
652		}
653	}
654
655	if (values && *argptr != NULL)
656		error("-p requires no arguments");
657	if (*argptr != NULL) {
658		for (ap = argptr; (name = *ap) != NULL; ap++) {
659			if ((p = strchr(name, '=')) != NULL) {
660				p++;
661			} else {
662				vp = find_var(name, NULL, NULL);
663				if (vp != NULL) {
664					vp->flags |= flag;
665					if ((vp->flags & VEXPORT) && localevar(vp->text)) {
666						change_env(vp->text, 1);
667						(void) setlocale(LC_ALL, "");
668						updatecharset();
669					}
670					continue;
671				}
672			}
673			setvar(name, p, flag);
674		}
675	} else {
676		for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
677			for (vp = *vpp ; vp ; vp = vp->next) {
678				if (vp->flags & flag) {
679					if (values) {
680						/*
681						 * Skip improper variable names
682						 * so the output remains usable
683						 * as shell input.
684						 */
685						if (!isassignment(vp->text))
686							continue;
687						out1str(cmdname);
688						out1c(' ');
689					}
690					if (values && !(vp->flags & VUNSET)) {
691						outbin(vp->text,
692						    vp->name_len + 1, out1);
693						out1qstr(vp->text +
694						    vp->name_len + 1);
695					} else
696						outbin(vp->text, vp->name_len,
697						    out1);
698					out1c('\n');
699				}
700			}
701		}
702	}
703	return 0;
704}
705
706
707/*
708 * The "local" command.
709 */
710
711int
712localcmd(int argc __unused, char **argv __unused)
713{
714	char *name;
715
716	nextopt("");
717	if (! in_function())
718		error("Not in a function");
719	while ((name = *argptr++) != NULL) {
720		mklocal(name);
721	}
722	return 0;
723}
724
725
726/*
727 * Make a variable a local variable.  When a variable is made local, it's
728 * value and flags are saved in a localvar structure.  The saved values
729 * will be restored when the shell function returns.  We handle the name
730 * "-" as a special case.
731 */
732
733void
734mklocal(char *name)
735{
736	struct localvar *lvp;
737	struct var **vpp;
738	struct var *vp;
739
740	INTOFF;
741	lvp = ckmalloc(sizeof (struct localvar));
742	if (name[0] == '-' && name[1] == '\0') {
743		lvp->text = ckmalloc(sizeof optlist);
744		memcpy(lvp->text, optlist, sizeof optlist);
745		vp = NULL;
746	} else {
747		vp = find_var(name, &vpp, NULL);
748		if (vp == NULL) {
749			if (strchr(name, '='))
750				setvareq(savestr(name), VSTRFIXED | VNOLOCAL);
751			else
752				setvar(name, NULL, VSTRFIXED | VNOLOCAL);
753			vp = *vpp;	/* the new variable */
754			lvp->text = NULL;
755			lvp->flags = VUNSET;
756		} else {
757			lvp->text = vp->text;
758			lvp->flags = vp->flags;
759			vp->flags |= VSTRFIXED|VTEXTFIXED;
760			if (name[vp->name_len] == '=')
761				setvareq(savestr(name), VNOLOCAL);
762		}
763	}
764	lvp->vp = vp;
765	lvp->next = localvars;
766	localvars = lvp;
767	INTON;
768}
769
770
771/*
772 * Called after a function returns.
773 */
774
775void
776poplocalvars(void)
777{
778	struct localvar *lvp;
779	struct var *vp;
780
781	while ((lvp = localvars) != NULL) {
782		localvars = lvp->next;
783		vp = lvp->vp;
784		if (vp == NULL) {	/* $- saved */
785			memcpy(optlist, lvp->text, sizeof optlist);
786			ckfree(lvp->text);
787			optschanged();
788		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
789			(void)unsetvar(vp->text);
790		} else {
791			if ((vp->flags & VTEXTFIXED) == 0)
792				ckfree(vp->text);
793			vp->flags = lvp->flags;
794			vp->text = lvp->text;
795		}
796		ckfree(lvp);
797	}
798}
799
800
801int
802setvarcmd(int argc, char **argv)
803{
804	if (argc <= 2)
805		return unsetcmd(argc, argv);
806	else if (argc == 3)
807		setvar(argv[1], argv[2], 0);
808	else
809		error("too many arguments");
810	return 0;
811}
812
813
814/*
815 * The unset builtin command.
816 */
817
818int
819unsetcmd(int argc __unused, char **argv __unused)
820{
821	char **ap;
822	int i;
823	int flg_func = 0;
824	int flg_var = 0;
825	int ret = 0;
826
827	while ((i = nextopt("vf")) != '\0') {
828		if (i == 'f')
829			flg_func = 1;
830		else
831			flg_var = 1;
832	}
833	if (flg_func == 0 && flg_var == 0)
834		flg_var = 1;
835
836	for (ap = argptr; *ap ; ap++) {
837		if (flg_func)
838			ret |= unsetfunc(*ap);
839		if (flg_var)
840			ret |= unsetvar(*ap);
841	}
842	return ret;
843}
844
845
846/*
847 * Unset the specified variable.
848 */
849
850int
851unsetvar(const char *s)
852{
853	struct var **vpp;
854	struct var *vp;
855
856	vp = find_var(s, &vpp, NULL);
857	if (vp == NULL)
858		return (0);
859	if (vp->flags & VREADONLY)
860		return (1);
861	INTOFF;
862	if (vp->text[vp->name_len + 1] != '\0')
863		setvar(s, nullstr, 0);
864	if ((vp->flags & VEXPORT) && localevar(vp->text)) {
865		change_env(s, 0);
866		setlocale(LC_ALL, "");
867		updatecharset();
868	}
869	vp->flags &= ~VEXPORT;
870	vp->flags |= VUNSET;
871	if ((vp->flags & VSTRFIXED) == 0) {
872		if ((vp->flags & VTEXTFIXED) == 0)
873			ckfree(vp->text);
874		*vpp = vp->next;
875		ckfree(vp);
876	}
877	INTON;
878	return (0);
879}
880
881
882
883/*
884 * Returns true if the two strings specify the same variable.  The first
885 * variable name is terminated by '='; the second may be terminated by
886 * either '=' or '\0'.
887 */
888
889static int
890varequal(const char *p, const char *q)
891{
892	while (*p == *q++) {
893		if (*p++ == '=')
894			return 1;
895	}
896	if (*p == '=' && *(q - 1) == '\0')
897		return 1;
898	return 0;
899}
900
901/*
902 * Search for a variable.
903 * 'name' may be terminated by '=' or a NUL.
904 * vppp is set to the pointer to vp, or the list head if vp isn't found
905 * lenp is set to the number of characters in 'name'
906 */
907
908static struct var *
909find_var(const char *name, struct var ***vppp, int *lenp)
910{
911	unsigned int hashval;
912	int len;
913	struct var *vp, **vpp;
914	const char *p = name;
915
916	hashval = 0;
917	while (*p && *p != '=')
918		hashval = 2 * hashval + (unsigned char)*p++;
919	len = p - name;
920
921	if (lenp)
922		*lenp = len;
923	vpp = &vartab[hashval % VTABSIZE];
924	if (vppp)
925		*vppp = vpp;
926
927	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
928		if (vp->name_len != len)
929			continue;
930		if (memcmp(vp->text, name, len) != 0)
931			continue;
932		if (vppp)
933			*vppp = vpp;
934		return vp;
935	}
936	return NULL;
937}
938