1 /*	$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami 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 #if 0
36 #ifndef lint
37 static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $");
40 #endif /* not lint */
41 #endif
42 
43 #include <stddef.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #ifdef PC_OS2_LIBPATHS
48 #define INCL_BASE
49 #include <os2.h>
50 
51 #ifndef LIBPATHSTRICT
52 #define LIBPATHSTRICT 3
53 #endif
54 
55 extern APIRET
56 #ifdef APIENTRY
57     APIENTRY
58 #endif
59     DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
60 #define QHINF_EXEINFO       1 /* NE exeinfo. */
61 #define QHINF_READRSRCTBL   2 /* Reads from the resource table. */
62 #define QHINF_READFILE      3 /* Reads from the executable file. */
63 #define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
64 #define QHINF_LIBPATH       5 /* Gets the entire libpath. */
65 #define QHINF_FIXENTRY      6 /* NE only */
66 #define QHINF_STE           7 /* NE only */
67 #define QHINF_MAPSEL        8 /* NE only */
68 
69 #endif
70 
71 
72 
73 /*
74  * Shell variables.
75  */
76 
77 #include "shell.h"
78 #include "output.h"
79 #include "expand.h"
80 #include "nodes.h"	/* for other headers */
81 #include "eval.h"	/* defines cmdenviron */
82 #include "exec.h"
83 #include "syntax.h"
84 #include "options.h"
85 #include "mail.h"
86 #include "var.h"
87 #include "memalloc.h"
88 #include "error.h"
89 #include "mystring.h"
90 #include "parser.h"
91 #include "show.h"
92 #ifndef SMALL
93 # include "myhistedit.h"
94 #endif
95 #include "shinstance.h"
96 
97 //#ifdef SMALL
98 //#define VTABSIZE 39
99 //#else
100 //#define VTABSIZE 517
101 //#endif
102 
103 
104 struct varinit {
105 	unsigned var_off;
106 	int flags;
107 	const char *text;
108 	void (*func)(shinstance *, const char *);
109 };
110 
111 
112 //#if ATTY
113 //struct var vatty;
114 //#endif
115 //#ifndef SMALL
116 //struct var vhistsize;
117 //struct var vterm;
118 //#endif
119 //struct var vifs;
120 //struct var vmail;
121 //struct var vmpath;
122 //struct var vpath;
123 //#ifdef _MSC_VER
124 //struct var vpath2;
125 //#endif
126 //struct var vps1;
127 //struct var vps2;
128 //struct var vps4;
129 //struct var vvers; - unused
130 //struct var voptind;
131 
132 #ifdef PC_OS2_LIBPATHS
133 //static struct var libpath_vars[4];
134 static const char * const libpath_envs[4] = {"LIBPATH=", "BEGINLIBPATH=", "ENDLIBPATH=", "LIBPATHSTRICT="};
135 #endif
136 
137 const struct varinit varinit[] = {
138 #if ATTY
139 	{ offsetof(shinstance, vatty),	VSTRFIXED|VTEXTFIXED|VUNSET,	"ATTY=",
140 	  NULL },
141 #endif
142 #ifndef SMALL
143 	{ offsetof(shinstance, vhistsize),	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE=",
144 	  sethistsize },
145 #endif
146 	{ offsetof(shinstance, vifs),	VSTRFIXED|VTEXTFIXED,		"IFS= \t\n",
147 	  NULL },
148 	{ offsetof(shinstance, vmail),	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL=",
149 	  NULL },
150 	{ offsetof(shinstance, vmpath),	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH=",
151 	  NULL },
152 	{ offsetof(shinstance, vpath),	VSTRFIXED|VTEXTFIXED,		"PATH=" _PATH_DEFPATH,
153 	  changepath },
154 	/*
155 	 * vps1 depends on uid
156 	 */
157 	{ offsetof(shinstance, vps2),	VSTRFIXED|VTEXTFIXED,		"PS2=> ",
158 	  NULL },
159 	{ offsetof(shinstance, vps4),	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",
160 	  NULL },
161 #ifndef SMALL
162 	{ offsetof(shinstance, vterm),	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM=",
163 	  setterm },
164 #endif
165 	{ offsetof(shinstance, voptind),	VSTRFIXED|VTEXTFIXED|VNOFUNC,	"OPTIND=1",
166 	  getoptsreset },
167 	{ 0,	0,				NULL,
168 	  NULL }
169 };
170 
171 //struct var *vartab[VTABSIZE];
172 
173 STATIC int strequal(const char *, const char *);
174 STATIC struct var *find_var(shinstance *, const char *, struct var ***, int *);
175 
176 /*
177  * Initialize the varable symbol tables and import the environment
178  */
179 
180 #ifdef mkinit
181 INCLUDE "var.h"
182 
183 INIT {
184 	char **envp;
185 
186 	initvar(psh);
187 	for (envp = sh_environ(psh) ; *envp ; envp++) {
188 		if (strchr(*envp, '=')) {
189 			setvareq(psh, *envp, VEXPORT|VTEXTFIXED);
190 		}
191 	}
192 }
193 #endif
194 
195 
196 /*
197  * This routine initializes the builtin variables.  It is called when the
198  * shell is initialized and again when a shell procedure is spawned.
199  */
200 
201 void
initvar(shinstance * psh)202 initvar(shinstance *psh)
203 {
204 	const struct varinit *ip;
205 	struct var *vp;
206 	struct var **vpp;
207 #ifdef PC_OS2_LIBPATHS
208 	char *psz = ckmalloc(psh, 2048);
209 	int rc;
210 	int i;
211 
212 	for (i = 0; i < 4; i++)
213 	{
214 		psh->libpath_vars[i].flags = VSTRFIXED | VOS2LIBPATH;
215 		psh->libpath_vars[i].func = NULL;
216 
217 		if (i > 0)
218 		{
219 			psz[0] = psz[1] = psz[2] = psz[3] = '\0';
220 			rc = DosQueryExtLIBPATH(psz, i);
221 		}
222 		else
223 		{
224 			rc = DosQueryHeaderInfo(NULLHANDLE, 0, psz, 2048, QHINF_LIBPATH);
225 			psh->libpath_vars[i].flags |= VREADONLY;
226 		}
227 		if (!rc && *psz)
228 		{
229 			int cch1 = strlen(libpath_envs[i]);
230 			int cch2 = strlen(psz) + 1;
231 			psh->libpath_vars[i].text = ckmalloc(psh, cch1 + cch2);
232 			memcpy(psh->libpath_vars[i].text, libpath_envs[i], cch1);
233 			memcpy(psh->libpath_vars[i].text + cch1, psz, cch2);
234 		}
235 		else
236 		{
237 			psh->libpath_vars[i].flags |= VUNSET | VTEXTFIXED;
238 			psh->libpath_vars[i].text = (char*)libpath_envs[i];
239 		}
240 		if (find_var(psh, psh->libpath_vars[i].text, &vpp, &psh->libpath_vars[i].name_len) != NULL)
241 			continue;
242 		psh->libpath_vars[i].next = *vpp;
243 		*vpp = &psh->libpath_vars[i];
244 	}
245 	ckfree(psh, psz);
246 #endif
247 
248 	for (ip = varinit; ip->text; ip++) {
249 		vp = (struct var *)((char *)psh + ip->var_off);
250 		if (find_var(psh, ip->text, &vpp, &vp->name_len) != NULL)
251 			continue;
252 		vp->next = *vpp;
253 		*vpp = vp;
254 		vp->text = sh_strdup(psh, ip->text);
255 		vp->flags = ip->flags;
256 		vp->func = ip->func;
257 	}
258 	/*
259 	 * PS1 depends on uid
260 	 */
261 	if (find_var(psh, "PS1", &vpp, &psh->vps1.name_len) == NULL) {
262 		psh->vps1.next = *vpp;
263 		*vpp = &psh->vps1;
264 #ifdef KBUILD_VERSION_MAJOR
265 		psh->vps1.text = sh_strdup(psh, sh_geteuid(psh) ? "PS1=kash$ " : "PS1=kash# ");
266 #else
267 		psh->vps1.text = sh_strdup(psh, sh_geteuid(psh) ? "PS1=$ " : "PS1=# ");
268 #endif
269 		psh->vps1.flags = VSTRFIXED|VTEXTFIXED;
270 	}
271 }
272 
273 /*
274  * Safe version of setvar, returns 1 on success 0 on failure.
275  */
276 
277 int
setvarsafe(shinstance * psh,const char * name,const char * val,int flags)278 setvarsafe(shinstance *psh, const char *name, const char *val, int flags)
279 {
280 	struct jmploc jmploc;
281 	struct jmploc *volatile savehandler = psh->handler;
282 	int err = 0;
283 #ifdef __GNUC__
284 	(void) &err;
285 #endif
286 
287 	if (setjmp(jmploc.loc))
288 		err = 1;
289 	else {
290 		psh->handler = &jmploc;
291 		setvar(psh, name, val, flags);
292 	}
293 	psh->handler = savehandler;
294 	return err;
295 }
296 
297 /*
298  * Set the value of a variable.  The flags argument is ored with the
299  * flags of the variable.  If val is NULL, the variable is unset.
300  */
301 
302 void
setvar(shinstance * psh,const char * name,const char * val,int flags)303 setvar(shinstance *psh, const char *name, const char *val, int flags)
304 {
305 	const char *p;
306 	const char *q;
307 	char *d;
308 	size_t len;
309 	int namelen;
310 	char *nameeq;
311 	int isbad;
312 
313 	isbad = 0;
314 	p = name;
315 	if (! is_name(*p))
316 		isbad = 1;
317 	p++;
318 	for (;;) {
319 		if (! is_in_name(*p)) {
320 			if (*p == '\0' || *p == '=')
321 				break;
322 			isbad = 1;
323 		}
324 		p++;
325 	}
326 	namelen = (int)(p - name);
327 	if (isbad)
328 		error(psh, "%.*s: bad variable name", namelen, name);
329 	len = namelen + 2;		/* 2 is space for '=' and '\0' */
330 	if (val == NULL) {
331 		flags |= VUNSET;
332 	} else {
333 		len += strlen(val);
334 	}
335 	d = nameeq = ckmalloc(psh, len);
336 	q = name;
337 	while (--namelen >= 0)
338 		*d++ = *q++;
339 	*d++ = '=';
340 	*d = '\0';
341 	if (val)
342 		scopy(val, d);
343 	setvareq(psh, nameeq, flags);
344 }
345 
346 
347 
348 /*
349  * Same as setvar except that the variable and value are passed in
350  * the first argument as name=value.  Since the first argument will
351  * be actually stored in the table, it should not be a string that
352  * will go away.
353  */
354 
355 void
setvareq(shinstance * psh,char * s,int flags)356 setvareq(shinstance *psh, char *s, int flags)
357 {
358 	struct var *vp, **vpp;
359 	int nlen;
360 
361 #if defined(_MSC_VER) || defined(_WIN32)
362 	/* On Windows PATH is often spelled 'Path', correct this here.  */
363 	if (   s[0] == 'P'
364 	    && s[1] == 'a'
365 	    && s[2] == 't'
366 	    && s[3] == 'h'
367 	    && (s[4] == '\0' || s[4] == '=') ) {
368 		s[1] = 'A';
369 		s[2] = 'T';
370 		s[3] = 'H';
371 	}
372 #endif
373 
374 	if (aflag(psh))
375 		flags |= VEXPORT;
376 	vp = find_var(psh, s, &vpp, &nlen);
377 	if (vp != NULL) {
378 		if (vp->flags & VREADONLY)
379 			error(psh, "%.*s: is read only", vp->name_len, s);
380 		if (flags & VNOSET)
381 			return;
382 		INTOFF;
383 
384 		if (vp->func && (flags & VNOFUNC) == 0)
385 			(*vp->func)(psh, s + vp->name_len + 1);
386 
387 		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
388 			ckfree(psh, vp->text);
389 
390 		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
391 		vp->flags |= flags & ~VNOFUNC;
392 		vp->text = s;
393 #ifdef PC_OS2_LIBPATHS
394 		if ((vp->flags & VOS2LIBPATH) && (vp->flags & VEXPORT))
395 			vp->flags &= ~VEXPORT;
396 #endif
397 
398 		/*
399 		 * We could roll this to a function, to handle it as
400 		 * a regular variable function callback, but why bother?
401 		 */
402 		if (vp == &psh->vmpath || (vp == &psh->vmail && ! mpathset(psh)))
403 			chkmail(psh, 1);
404 		INTON;
405 		return;
406 	}
407 	/* not found */
408 	if (flags & VNOSET)
409 		return;
410 
411 	vp = ckmalloc(psh, sizeof (*vp));
412 	vp->flags = flags & ~VNOFUNC;
413 	vp->text = s;
414 	vp->name_len = nlen;
415 	vp->next = *vpp;
416 	vp->func = NULL;
417 	*vpp = vp;
418 }
419 
420 
421 
422 /*
423  * Process a linked list of variable assignments.
424  */
425 
426 void
listsetvar(shinstance * psh,struct strlist * list,int flags)427 listsetvar(shinstance *psh, struct strlist *list, int flags)
428 {
429 	struct strlist *lp;
430 
431 	INTOFF;
432 	for (lp = list ; lp ; lp = lp->next) {
433 		setvareq(psh, savestr(psh, lp->text), flags);
434 	}
435 	INTON;
436 }
437 
438 void
listmklocal(shinstance * psh,struct strlist * list,int flags)439 listmklocal(shinstance *psh, struct strlist *list, int flags)
440 {
441 	struct strlist *lp;
442 
443 	for (lp = list ; lp ; lp = lp->next)
444 		mklocal(psh, lp->text, flags);
445 }
446 
447 
448 /*
449  * Find the value of a variable.  Returns NULL if not set.
450  */
451 
452 char *
lookupvar(shinstance * psh,const char * name)453 lookupvar(shinstance *psh, const char *name)
454 {
455 	struct var *v;
456 
457 	v = find_var(psh, name, NULL, NULL);
458 	if (v == NULL || v->flags & VUNSET)
459 		return NULL;
460 	return v->text + v->name_len + 1;
461 }
462 
463 
464 
465 /*
466  * Search the environment of a builtin command.  If the second argument
467  * is nonzero, return the value of a variable even if it hasn't been
468  * exported.
469  */
470 
471 char *
bltinlookup(shinstance * psh,const char * name,int doall)472 bltinlookup(shinstance *psh, const char *name, int doall)
473 {
474 	struct strlist *sp;
475 	struct var *v;
476 
477 	for (sp = psh->cmdenviron ; sp ; sp = sp->next) {
478 		if (strequal(sp->text, name))
479 			return strchr(sp->text, '=') + 1;
480 	}
481 
482 	v = find_var(psh, name, NULL, NULL);
483 
484 	if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
485 		return NULL;
486 	return v->text + v->name_len + 1;
487 }
488 
489 
490 
491 /*
492  * Generate a list of exported variables.  This routine is used to construct
493  * the third argument to execve when executing a program.
494  */
495 
496 char **
environment(shinstance * psh)497 environment(shinstance *psh)
498 {
499 	int nenv;
500 	struct var **vpp;
501 	struct var *vp;
502 	char **env;
503 	char **ep;
504 
505 	nenv = 0;
506 	for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) {
507 		for (vp = *vpp ; vp ; vp = vp->next)
508 			if (vp->flags & VEXPORT)
509 				nenv++;
510 	}
511 	ep = env = stalloc(psh, (nenv + 1) * sizeof *env);
512 	for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) {
513 		for (vp = *vpp ; vp ; vp = vp->next)
514 			if (vp->flags & VEXPORT)
515 				*ep++ = vp->text;
516 	}
517 	*ep = NULL;
518 
519 #ifdef PC_OS2_LIBPATHS
520 	/*
521 	 * Set the libpaths now as this is exec() time.
522 	 */
523 	for (nenv = 0; nenv < 3; nenv++)
524 		DosSetExtLIBPATH(strchr(psh->libpath_vars[nenv].text, '=') + 1, nenv);
525 #endif
526 
527 	return env;
528 }
529 
530 
531 /*
532  * Called when a shell procedure is invoked to clear out nonexported
533  * variables.  It is also necessary to reallocate variables of with
534  * VSTACK set since these are currently allocated on the stack.
535  */
536 
537 #ifdef mkinit
538 void shprocvar(shinstance *psh);
539 
540 SHELLPROC {
541 	shprocvar(psh);
542 }
543 #endif
544 
545 void
shprocvar(shinstance * psh)546 shprocvar(shinstance *psh)
547 {
548 	struct var **vpp;
549 	struct var *vp, **prev;
550 
551 	for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) {
552 		for (prev = vpp ; (vp = *prev) != NULL ; ) {
553 			if ((vp->flags & VEXPORT) == 0) {
554 				*prev = vp->next;
555 				if ((vp->flags & VTEXTFIXED) == 0)
556 					ckfree(psh, vp->text);
557 				if ((vp->flags & VSTRFIXED) == 0)
558 					ckfree(psh, vp);
559 			} else {
560 				if (vp->flags & VSTACK) {
561 					vp->text = savestr(psh, vp->text);
562 					vp->flags &=~ VSTACK;
563 				}
564 				prev = &vp->next;
565 			}
566 		}
567 	}
568 	initvar(psh);
569 }
570 
571 
572 
573 /*
574  * Command to list all variables which are set.  Currently this command
575  * is invoked from the set command when the set command is called without
576  * any variables.
577  */
578 
579 void
print_quoted(shinstance * psh,const char * p)580 print_quoted(shinstance *psh, const char *p)
581 {
582 	const char *q;
583 
584 	if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
585 		out1fmt(psh, "%s", p);
586 		return;
587 	}
588 	while (*p) {
589 		if (*p == '\'') {
590 			out1fmt(psh, "\\'");
591 			p++;
592 			continue;
593 		}
594 		q = strchr(p, '\'');
595 		if (!q) {
596 			out1fmt(psh, "'%s'", p );
597 			return;
598 		}
599 		out1fmt(psh, "'%.*s'", (int)(q - p), p );
600 		p = q;
601 	}
602 }
603 
604 static int
sort_var(const void * v_v1,const void * v_v2)605 sort_var(const void *v_v1, const void *v_v2)
606 {
607 	const struct var * const *v1 = v_v1;
608 	const struct var * const *v2 = v_v2;
609 
610 	/* XXX Will anyone notice we include the '=' of the shorter name? */
611 	return strcoll((*v1)->text, (*v2)->text);
612 }
613 
614 /*
615  * POSIX requires that 'set' (but not export or readonly) output the
616  * variables in lexicographic order - by the locale's collating order (sigh).
617  * Maybe we could keep them in an ordered balanced binary tree
618  * instead of hashed lists.
619  * For now just roll 'em through qsort for printing...
620  */
621 
622 int
showvars(shinstance * psh,const char * name,int flag,int show_value)623 showvars(shinstance *psh, const char *name, int flag, int show_value)
624 {
625 	struct var **vpp;
626 	struct var *vp;
627 	const char *p;
628 
629 	static struct var **list;	/* static in case we are interrupted */
630 	static int list_len;
631 	int count = 0;
632 
633 	if (!list) {
634 		list_len = 32;
635 		list = ckmalloc(psh, list_len * sizeof(*list));
636 	}
637 
638 	for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) {
639 		for (vp = *vpp ; vp ; vp = vp->next) {
640 			if (flag && !(vp->flags & flag))
641 				continue;
642 			if (vp->flags & VUNSET && !(show_value & 2))
643 				continue;
644 			if (count >= list_len) {
645 				list = ckrealloc(psh, list,
646 					(list_len << 1) * sizeof(*list));
647 				list_len <<= 1;
648 			}
649 			list[count++] = vp;
650 		}
651 	}
652 
653 	qsort(list, count, sizeof(*list), sort_var);
654 
655 	for (vpp = list; count--; vpp++) {
656 		vp = *vpp;
657 		if (name)
658 			out1fmt(psh, "%s ", name);
659 		for (p = vp->text ; *p != '=' ; p++)
660 			out1c(psh, *p);
661 		if (!(vp->flags & VUNSET) && show_value) {
662 			out1fmt(psh, "=");
663 			print_quoted(psh, ++p);
664 		}
665 		out1c(psh, '\n');
666 	}
667 	return 0;
668 }
669 
670 
671 
672 /*
673  * The export and readonly commands.
674  */
675 
676 int
exportcmd(shinstance * psh,int argc,char ** argv)677 exportcmd(shinstance *psh, int argc, char **argv)
678 {
679 	struct var *vp;
680 	char *name;
681 	const char *p;
682 	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
683 	int pflag;
684 
685 	pflag = nextopt(psh, "p") == 'p' ? 3 : 0;
686 	if (argc <= 1 || pflag) {
687 		showvars(psh, pflag ? argv[0] : 0, flag, pflag );
688 		return 0;
689 	}
690 
691 	while ((name = *psh->argptr++) != NULL) {
692 		if ((p = strchr(name, '=')) != NULL) {
693 			p++;
694 		} else {
695 			vp = find_var(psh, name, NULL, NULL);
696 			if (vp != NULL) {
697 				vp->flags |= flag;
698 				continue;
699 			}
700 		}
701 		setvar(psh, name, p, flag);
702 	}
703 	return 0;
704 }
705 
706 
707 /*
708  * The "local" command.
709  */
710 
711 int
localcmd(shinstance * psh,int argc,char ** argv)712 localcmd(shinstance *psh, int argc, char **argv)
713 {
714 	char *name;
715 
716 	if (! in_function(psh))
717 		error(psh, "Not in a function");
718 	while ((name = *psh->argptr++) != NULL) {
719 		mklocal(psh, name, 0);
720 	}
721 	return 0;
722 }
723 
724 
725 /*
726  * Make a variable a local variable.  When a variable is made local, it's
727  * value and flags are saved in a localvar structure.  The saved values
728  * will be restored when the shell function returns.  We handle the name
729  * "-" as a special case.
730  */
731 
732 void
mklocal(shinstance * psh,const char * name,int flags)733 mklocal(shinstance *psh, const char *name, int flags)
734 {
735 	struct localvar *lvp;
736 	struct var **vpp;
737 	struct var *vp;
738 
739 	INTOFF;
740 	lvp = ckmalloc(psh, sizeof (struct localvar));
741 	if (name[0] == '-' && name[1] == '\0') {
742 		char *p;
743 		p = ckmalloc(psh, sizeof_optlist);
744 		lvp->text = memcpy(p, psh->optlist, sizeof_optlist);
745 		vp = NULL;
746 	} else {
747 		vp = find_var(psh, name, &vpp, NULL);
748 		if (vp == NULL) {
749 			if (strchr(name, '='))
750 				setvareq(psh, savestr(psh, name), VSTRFIXED|flags);
751 			else
752 				setvar(psh, name, NULL, VSTRFIXED|flags);
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(psh, savestr(psh, name), flags);
762 		}
763 	}
764 	lvp->vp = vp;
765 	lvp->next = psh->localvars;
766 	psh->localvars = lvp;
767 	INTON;
768 }
769 
770 
771 /*
772  * Called after a function returns.
773  */
774 
775 void
poplocalvars(shinstance * psh)776 poplocalvars(shinstance *psh)
777 {
778 	struct localvar *lvp;
779 	struct var *vp;
780 
781 	while ((lvp = psh->localvars) != NULL) {
782 		psh->localvars = lvp->next;
783 		vp = lvp->vp;
784 		TRACE((psh, "poplocalvar %s", vp ? vp->text : "-"));
785 		if (vp == NULL) {	/* $- saved */
786 			memcpy(psh->optlist, lvp->text, sizeof_optlist);
787 			ckfree(psh, lvp->text);
788 		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
789 			(void)unsetvar(psh, vp->text, 0);
790 		} else {
791 			if (vp->func && (vp->flags & VNOFUNC) == 0)
792 				(*vp->func)(psh, lvp->text + vp->name_len + 1);
793 			if ((vp->flags & VTEXTFIXED) == 0)
794 				ckfree(psh, vp->text);
795 			vp->flags = lvp->flags;
796 			vp->text = lvp->text;
797 		}
798 		ckfree(psh, lvp);
799 	}
800 }
801 
802 
803 int
setvarcmd(shinstance * psh,int argc,char ** argv)804 setvarcmd(shinstance *psh, int argc, char **argv)
805 {
806 	if (argc <= 2)
807 		return unsetcmd(psh, argc, argv);
808 	else if (argc == 3)
809 		setvar(psh, argv[1], argv[2], 0);
810 	else
811 		error(psh, "List assignment not implemented");
812 	return 0;
813 }
814 
815 
816 /*
817  * The unset builtin command.  We unset the function before we unset the
818  * variable to allow a function to be unset when there is a readonly variable
819  * with the same name.
820  */
821 
822 int
unsetcmd(shinstance * psh,int argc,char ** argv)823 unsetcmd(shinstance *psh, int argc, char **argv)
824 {
825 	char **ap;
826 	int i;
827 	int flg_func = 0;
828 	int flg_var = 0;
829 	int ret = 0;
830 
831 	while ((i = nextopt(psh, "evf")) != '\0') {
832 		if (i == 'f')
833 			flg_func = 1;
834 		else
835 			flg_var = i;
836 	}
837 	if (flg_func == 0 && flg_var == 0)
838 		flg_var = 1;
839 
840 	for (ap = psh->argptr; *ap ; ap++) {
841 		if (flg_func)
842 			ret |= unsetfunc(psh, *ap);
843 		if (flg_var)
844 			ret |= unsetvar(psh, *ap, flg_var == 'e');
845 	}
846 	return ret;
847 }
848 
849 
850 /*
851  * Unset the specified variable.
852  */
853 
854 int
unsetvar(shinstance * psh,const char * s,int unexport)855 unsetvar(shinstance *psh, const char *s, int unexport)
856 {
857 	struct var **vpp;
858 	struct var *vp;
859 
860 	vp = find_var(psh, s, &vpp, NULL);
861 	if (vp == NULL)
862 		return 1;
863 
864 	if (vp->flags & VREADONLY)
865 		return (1);
866 
867 	INTOFF;
868 	if (unexport) {
869 		vp->flags &= ~VEXPORT;
870 	} else {
871 		if (vp->text[vp->name_len + 1] != '\0')
872 			setvar(psh, s, nullstr, 0);
873 		vp->flags &= ~VEXPORT;
874 		vp->flags |= VUNSET;
875 		if ((vp->flags & VSTRFIXED) == 0) {
876 			if ((vp->flags & VTEXTFIXED) == 0)
877 				ckfree(psh, vp->text);
878 			*vpp = vp->next;
879 			ckfree(psh, vp);
880 		}
881 	}
882 	INTON;
883 	return 0;
884 }
885 
886 
887 /*
888  * Returns true if the two strings specify the same varable.  The first
889  * variable name is terminated by '='; the second may be terminated by
890  * either '=' or '\0'.
891  */
892 
893 STATIC int
strequal(const char * p,const char * q)894 strequal(const char *p, const char *q)
895 {
896 	while (*p == *q++) {
897 		if (*p++ == '=')
898 			return 1;
899 	}
900 	if (*p == '=' && *(q - 1) == '\0')
901 		return 1;
902 	return 0;
903 }
904 
905 /*
906  * Search for a variable.
907  * 'name' may be terminated by '=' or a NUL.
908  * vppp is set to the pointer to vp, or the list head if vp isn't found
909  * lenp is set to the number of charactets in 'name'
910  */
911 
912 STATIC struct var *
find_var(shinstance * psh,const char * name,struct var *** vppp,int * lenp)913 find_var(shinstance *psh, const char *name, struct var ***vppp, int *lenp)
914 {
915 	unsigned int hashval;
916 	int len;
917 	struct var *vp, **vpp;
918 	const char *p = name;
919 
920 	hashval = 0;
921 	while (*p && *p != '=')
922 		hashval = 2 * hashval + (unsigned char)*p++;
923 	len = (int)(p - name);
924 
925 	if (lenp)
926 		*lenp = len;
927 	vpp = &psh->vartab[hashval % VTABSIZE];
928 	if (vppp)
929 		*vppp = vpp;
930 
931 	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
932 		if (vp->name_len != len)
933 			continue;
934 		if (memcmp(vp->text, name, len) != 0)
935 			continue;
936 		if (vppp)
937 			*vppp = vpp;
938 		return vp;
939 	}
940 	return NULL;
941 }
942