var.c revision 264512
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
35static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: stable/10/bin/sh/var.c 264512 2014-04-15 18:24:24Z jilles $");
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#include <langinfo.h>
51
52#include "shell.h"
53#include "output.h"
54#include "expand.h"
55#include "nodes.h"	/* for other headers */
56#include "eval.h"	/* defines cmdenviron */
57#include "exec.h"
58#include "syntax.h"
59#include "options.h"
60#include "mail.h"
61#include "var.h"
62#include "memalloc.h"
63#include "error.h"
64#include "mystring.h"
65#include "parser.h"
66#include "builtins.h"
67#ifndef NO_HISTORY
68#include "myhistedit.h"
69#endif
70
71
72#define VTABSIZE 39
73
74
75struct varinit {
76	struct var *var;
77	int flags;
78	const char *text;
79	void (*func)(const char *);
80};
81
82
83#ifndef NO_HISTORY
84struct var vhistsize;
85struct var vterm;
86#endif
87struct var vifs;
88struct var vmail;
89struct var vmpath;
90struct var vpath;
91struct var vps1;
92struct var vps2;
93struct var vps4;
94static struct var voptind;
95struct var vdisvfork;
96
97int forcelocal;
98
99static const struct varinit varinit[] = {
100#ifndef NO_HISTORY
101	{ &vhistsize,	VUNSET,				"HISTSIZE=",
102	  sethistsize },
103#endif
104	{ &vifs,	0,				"IFS= \t\n",
105	  NULL },
106	{ &vmail,	VUNSET,				"MAIL=",
107	  NULL },
108	{ &vmpath,	VUNSET,				"MAILPATH=",
109	  NULL },
110	{ &vpath,	0,				"PATH=" _PATH_DEFPATH,
111	  changepath },
112	/*
113	 * vps1 depends on uid
114	 */
115	{ &vps2,	0,				"PS2=> ",
116	  NULL },
117	{ &vps4,	0,				"PS4=+ ",
118	  NULL },
119#ifndef NO_HISTORY
120	{ &vterm,	VUNSET,				"TERM=",
121	  setterm },
122#endif
123	{ &voptind,	0,				"OPTIND=1",
124	  getoptsreset },
125	{ &vdisvfork,	VUNSET,				"SH_DISABLE_VFORK=",
126	  NULL },
127	{ NULL,	0,				NULL,
128	  NULL }
129};
130
131static struct var *vartab[VTABSIZE];
132
133static const char *const locale_names[7] = {
134	"LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
135	"LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
136};
137static const int locale_categories[7] = {
138	LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
139};
140
141static int varequal(const char *, const char *);
142static struct var *find_var(const char *, struct var ***, int *);
143static int localevar(const char *);
144
145extern char **environ;
146
147/*
148 * This routine initializes the builtin variables and imports the environment.
149 * It is called when the shell is initialized.
150 */
151
152void
153initvar(void)
154{
155	char ppid[20];
156	const struct varinit *ip;
157	struct var *vp;
158	struct var **vpp;
159	char **envp;
160
161	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
162		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
163			continue;
164		vp->next = *vpp;
165		*vpp = vp;
166		vp->text = __DECONST(char *, ip->text);
167		vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
168		vp->func = ip->func;
169	}
170	/*
171	 * PS1 depends on uid
172	 */
173	if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
174		vps1.next = *vpp;
175		*vpp = &vps1;
176		vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
177		vps1.flags = VSTRFIXED|VTEXTFIXED;
178	}
179	fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
180	setvarsafe("PPID", ppid, 0);
181	for (envp = environ ; *envp ; envp++) {
182		if (strchr(*envp, '=')) {
183			setvareq(*envp, VEXPORT|VTEXTFIXED);
184		}
185	}
186	setvareq("OPTIND=1", VTEXTFIXED);
187}
188
189/*
190 * Safe version of setvar, returns 1 on success 0 on failure.
191 */
192
193int
194setvarsafe(const char *name, const char *val, int flags)
195{
196	struct jmploc jmploc;
197	struct jmploc *const savehandler = handler;
198	int err = 0;
199	int inton;
200
201	inton = is_int_on();
202	if (setjmp(jmploc.loc))
203		err = 1;
204	else {
205		handler = &jmploc;
206		setvar(name, val, flags);
207	}
208	handler = savehandler;
209	SETINTON(inton);
210	return err;
211}
212
213/*
214 * Set the value of a variable.  The flags argument is stored with the
215 * flags of the variable.  If val is NULL, the variable is unset.
216 */
217
218void
219setvar(const char *name, const char *val, int flags)
220{
221	const char *p;
222	size_t len;
223	size_t namelen;
224	size_t vallen;
225	char *nameeq;
226	int isbad;
227
228	isbad = 0;
229	p = name;
230	if (! is_name(*p))
231		isbad = 1;
232	p++;
233	for (;;) {
234		if (! is_in_name(*p)) {
235			if (*p == '\0' || *p == '=')
236				break;
237			isbad = 1;
238		}
239		p++;
240	}
241	namelen = p - name;
242	if (isbad)
243		error("%.*s: bad variable name", (int)namelen, name);
244	len = namelen + 2;		/* 2 is space for '=' and '\0' */
245	if (val == NULL) {
246		flags |= VUNSET;
247		vallen = 0;
248	} else {
249		vallen = strlen(val);
250		len += vallen;
251	}
252	INTOFF;
253	nameeq = ckmalloc(len);
254	memcpy(nameeq, name, namelen);
255	nameeq[namelen] = '=';
256	if (val)
257		memcpy(nameeq + namelen + 1, val, vallen + 1);
258	else
259		nameeq[namelen + 1] = '\0';
260	setvareq(nameeq, flags);
261	INTON;
262}
263
264static int
265localevar(const char *s)
266{
267	const char *const *ss;
268
269	if (*s != 'L')
270		return 0;
271	if (varequal(s + 1, "ANG"))
272		return 1;
273	if (strncmp(s + 1, "C_", 2) != 0)
274		return 0;
275	if (varequal(s + 3, "ALL"))
276		return 1;
277	for (ss = locale_names; *ss ; ss++)
278		if (varequal(s + 3, *ss + 3))
279			return 1;
280	return 0;
281}
282
283
284/*
285 * Sets/unsets an environment variable from a pointer that may actually be a
286 * pointer into environ where the string should not be manipulated.
287 */
288static void
289change_env(const char *s, int set)
290{
291	char *eqp;
292	char *ss;
293
294	INTOFF;
295	ss = savestr(s);
296	if ((eqp = strchr(ss, '=')) != NULL)
297		*eqp = '\0';
298	if (set && eqp != NULL)
299		(void) setenv(ss, eqp + 1, 1);
300	else
301		(void) unsetenv(ss);
302	ckfree(ss);
303	INTON;
304
305	return;
306}
307
308
309/*
310 * Same as setvar except that the variable and value are passed in
311 * the first argument as name=value.  Since the first argument will
312 * be actually stored in the table, it should not be a string that
313 * will go away.
314 */
315
316void
317setvareq(char *s, int flags)
318{
319	struct var *vp, **vpp;
320	int nlen;
321
322	if (aflag)
323		flags |= VEXPORT;
324	if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
325		mklocal(s);
326	vp = find_var(s, &vpp, &nlen);
327	if (vp != NULL) {
328		if (vp->flags & VREADONLY) {
329			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
330				ckfree(s);
331			error("%.*s: is read only", vp->name_len, s);
332		}
333		if (flags & VNOSET)
334			return;
335		INTOFF;
336
337		if (vp->func && (flags & VNOFUNC) == 0)
338			(*vp->func)(s + vp->name_len + 1);
339
340		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
341			ckfree(vp->text);
342
343		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
344		vp->flags |= flags;
345		vp->text = s;
346
347		/*
348		 * We could roll this to a function, to handle it as
349		 * a regular variable function callback, but why bother?
350		 *
351		 * Note: this assumes iflag is not set to 1 initially.
352		 * As part of initvar(), this is called before arguments
353		 * are looked at.
354		 */
355		if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
356		    iflag == 1)
357			chkmail(1);
358		if ((vp->flags & VEXPORT) && localevar(s)) {
359			change_env(s, 1);
360			(void) setlocale(LC_ALL, "");
361			updatecharset();
362		}
363		INTON;
364		return;
365	}
366	/* not found */
367	if (flags & VNOSET)
368		return;
369	INTOFF;
370	vp = ckmalloc(sizeof (*vp));
371	vp->flags = flags;
372	vp->text = s;
373	vp->name_len = nlen;
374	vp->next = *vpp;
375	vp->func = NULL;
376	*vpp = vp;
377	if ((vp->flags & VEXPORT) && localevar(s)) {
378		change_env(s, 1);
379		(void) setlocale(LC_ALL, "");
380		updatecharset();
381	}
382	INTON;
383}
384
385
386
387/*
388 * Process a linked list of variable assignments.
389 */
390
391void
392listsetvar(struct strlist *list, int flags)
393{
394	struct strlist *lp;
395
396	INTOFF;
397	for (lp = list ; lp ; lp = lp->next) {
398		setvareq(savestr(lp->text), flags);
399	}
400	INTON;
401}
402
403
404
405/*
406 * Find the value of a variable.  Returns NULL if not set.
407 */
408
409char *
410lookupvar(const char *name)
411{
412	struct var *v;
413
414	v = find_var(name, NULL, NULL);
415	if (v == NULL || v->flags & VUNSET)
416		return NULL;
417	return v->text + v->name_len + 1;
418}
419
420
421
422/*
423 * Search the environment of a builtin command.  If the second argument
424 * is nonzero, return the value of a variable even if it hasn't been
425 * exported.
426 */
427
428char *
429bltinlookup(const char *name, int doall)
430{
431	struct strlist *sp;
432	struct var *v;
433	char *result;
434
435	result = NULL;
436	for (sp = cmdenviron ; sp ; sp = sp->next) {
437		if (varequal(sp->text, name))
438			result = strchr(sp->text, '=') + 1;
439	}
440	if (result != NULL)
441		return result;
442
443	v = find_var(name, NULL, NULL);
444	if (v == NULL || v->flags & VUNSET ||
445	    (!doall && (v->flags & VEXPORT) == 0))
446		return NULL;
447	return v->text + v->name_len + 1;
448}
449
450
451/*
452 * Set up locale for a builtin (LANG/LC_* assignments).
453 */
454void
455bltinsetlocale(void)
456{
457	struct strlist *lp;
458	int act = 0;
459	char *loc, *locdef;
460	int i;
461
462	for (lp = cmdenviron ; lp ; lp = lp->next) {
463		if (localevar(lp->text)) {
464			act = 1;
465			break;
466		}
467	}
468	if (!act)
469		return;
470	loc = bltinlookup("LC_ALL", 0);
471	INTOFF;
472	if (loc != NULL) {
473		setlocale(LC_ALL, loc);
474		INTON;
475		updatecharset();
476		return;
477	}
478	locdef = bltinlookup("LANG", 0);
479	for (i = 0; locale_names[i] != NULL; i++) {
480		loc = bltinlookup(locale_names[i], 0);
481		if (loc == NULL)
482			loc = locdef;
483		if (loc != NULL)
484			setlocale(locale_categories[i], loc);
485	}
486	INTON;
487	updatecharset();
488}
489
490/*
491 * Undo the effect of bltinlocaleset().
492 */
493void
494bltinunsetlocale(void)
495{
496	struct strlist *lp;
497
498	INTOFF;
499	for (lp = cmdenviron ; lp ; lp = lp->next) {
500		if (localevar(lp->text)) {
501			setlocale(LC_ALL, "");
502			updatecharset();
503			return;
504		}
505	}
506	INTON;
507}
508
509/*
510 * Update the localeisutf8 flag.
511 */
512void
513updatecharset(void)
514{
515	char *charset;
516
517	charset = nl_langinfo(CODESET);
518	localeisutf8 = !strcmp(charset, "UTF-8");
519}
520
521void
522initcharset(void)
523{
524	updatecharset();
525	initial_localeisutf8 = localeisutf8;
526}
527
528/*
529 * Generate a list of exported variables.  This routine is used to construct
530 * the third argument to execve when executing a program.
531 */
532
533char **
534environment(void)
535{
536	int nenv;
537	struct var **vpp;
538	struct var *vp;
539	char **env, **ep;
540
541	nenv = 0;
542	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
543		for (vp = *vpp ; vp ; vp = vp->next)
544			if (vp->flags & VEXPORT)
545				nenv++;
546	}
547	ep = env = stalloc((nenv + 1) * sizeof *env);
548	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
549		for (vp = *vpp ; vp ; vp = vp->next)
550			if (vp->flags & VEXPORT)
551				*ep++ = vp->text;
552	}
553	*ep = NULL;
554	return env;
555}
556
557
558static int
559var_compare(const void *a, const void *b)
560{
561	const char *const *sa, *const *sb;
562
563	sa = a;
564	sb = b;
565	/*
566	 * This compares two var=value strings which creates a different
567	 * order from what you would probably expect.  POSIX is somewhat
568	 * ambiguous on what should be sorted exactly.
569	 */
570	return strcoll(*sa, *sb);
571}
572
573
574/*
575 * Command to list all variables which are set.  This is invoked from the
576 * set command when it is called without any options or operands.
577 */
578
579int
580showvarscmd(int argc __unused, char **argv __unused)
581{
582	struct var **vpp;
583	struct var *vp;
584	const char *s;
585	const char **vars;
586	int i, n;
587
588	/*
589	 * POSIX requires us to sort the variables.
590	 */
591	n = 0;
592	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
593		for (vp = *vpp; vp; vp = vp->next) {
594			if (!(vp->flags & VUNSET))
595				n++;
596		}
597	}
598
599	INTOFF;
600	vars = ckmalloc(n * sizeof(*vars));
601	i = 0;
602	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
603		for (vp = *vpp; vp; vp = vp->next) {
604			if (!(vp->flags & VUNSET))
605				vars[i++] = vp->text;
606		}
607	}
608
609	qsort(vars, n, sizeof(*vars), var_compare);
610	for (i = 0; i < n; i++) {
611		/*
612		 * Skip improper variable names so the output remains usable as
613		 * shell input.
614		 */
615		if (!isassignment(vars[i]))
616			continue;
617		s = strchr(vars[i], '=');
618		s++;
619		outbin(vars[i], s - vars[i], out1);
620		out1qstr(s);
621		out1c('\n');
622	}
623	ckfree(vars);
624	INTON;
625
626	return 0;
627}
628
629
630
631/*
632 * The export and readonly commands.
633 */
634
635int
636exportcmd(int argc __unused, char **argv)
637{
638	struct var **vpp;
639	struct var *vp;
640	char **ap;
641	char *name;
642	char *p;
643	char *cmdname;
644	int ch, values;
645	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
646
647	cmdname = argv[0];
648	values = 0;
649	while ((ch = nextopt("p")) != '\0') {
650		switch (ch) {
651		case 'p':
652			values = 1;
653			break;
654		}
655	}
656
657	if (values && *argptr != NULL)
658		error("-p requires no arguments");
659	if (*argptr != NULL) {
660		for (ap = argptr; (name = *ap) != NULL; ap++) {
661			if ((p = strchr(name, '=')) != NULL) {
662				p++;
663			} else {
664				vp = find_var(name, NULL, NULL);
665				if (vp != NULL) {
666					vp->flags |= flag;
667					if ((vp->flags & VEXPORT) && localevar(vp->text)) {
668						change_env(vp->text, 1);
669						(void) setlocale(LC_ALL, "");
670						updatecharset();
671					}
672					continue;
673				}
674			}
675			setvar(name, p, flag);
676		}
677	} else {
678		for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
679			for (vp = *vpp ; vp ; vp = vp->next) {
680				if (vp->flags & flag) {
681					if (values) {
682						/*
683						 * Skip improper variable names
684						 * so the output remains usable
685						 * as shell input.
686						 */
687						if (!isassignment(vp->text))
688							continue;
689						out1str(cmdname);
690						out1c(' ');
691					}
692					if (values && !(vp->flags & VUNSET)) {
693						outbin(vp->text,
694						    vp->name_len + 1, out1);
695						out1qstr(vp->text +
696						    vp->name_len + 1);
697					} else
698						outbin(vp->text, vp->name_len,
699						    out1);
700					out1c('\n');
701				}
702			}
703		}
704	}
705	return 0;
706}
707
708
709/*
710 * The "local" command.
711 */
712
713int
714localcmd(int argc __unused, char **argv __unused)
715{
716	char *name;
717
718	nextopt("");
719	if (! in_function())
720		error("Not in a function");
721	while ((name = *argptr++) != NULL) {
722		mklocal(name);
723	}
724	return 0;
725}
726
727
728/*
729 * Make a variable a local variable.  When a variable is made local, it's
730 * value and flags are saved in a localvar structure.  The saved values
731 * will be restored when the shell function returns.  We handle the name
732 * "-" as a special case.
733 */
734
735void
736mklocal(char *name)
737{
738	struct localvar *lvp;
739	struct var **vpp;
740	struct var *vp;
741
742	INTOFF;
743	lvp = ckmalloc(sizeof (struct localvar));
744	if (name[0] == '-' && name[1] == '\0') {
745		lvp->text = ckmalloc(sizeof optlist);
746		memcpy(lvp->text, optlist, sizeof optlist);
747		vp = NULL;
748	} else {
749		vp = find_var(name, &vpp, NULL);
750		if (vp == NULL) {
751			if (strchr(name, '='))
752				setvareq(savestr(name), VSTRFIXED | VNOLOCAL);
753			else
754				setvar(name, NULL, VSTRFIXED | VNOLOCAL);
755			vp = *vpp;	/* the new variable */
756			lvp->text = NULL;
757			lvp->flags = VUNSET;
758		} else {
759			lvp->text = vp->text;
760			lvp->flags = vp->flags;
761			vp->flags |= VSTRFIXED|VTEXTFIXED;
762			if (name[vp->name_len] == '=')
763				setvareq(savestr(name), VNOLOCAL);
764		}
765	}
766	lvp->vp = vp;
767	lvp->next = localvars;
768	localvars = lvp;
769	INTON;
770}
771
772
773/*
774 * Called after a function returns.
775 */
776
777void
778poplocalvars(void)
779{
780	struct localvar *lvp;
781	struct var *vp;
782
783	INTOFF;
784	while ((lvp = localvars) != NULL) {
785		localvars = lvp->next;
786		vp = lvp->vp;
787		if (vp == NULL) {	/* $- saved */
788			memcpy(optlist, lvp->text, sizeof optlist);
789			ckfree(lvp->text);
790			optschanged();
791		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
792			(void)unsetvar(vp->text);
793		} else {
794			if ((vp->flags & VTEXTFIXED) == 0)
795				ckfree(vp->text);
796			vp->flags = lvp->flags;
797			vp->text = lvp->text;
798		}
799		ckfree(lvp);
800	}
801	INTON;
802}
803
804
805int
806setvarcmd(int argc, char **argv)
807{
808	if (argc <= 2)
809		return unsetcmd(argc, argv);
810	else if (argc == 3)
811		setvar(argv[1], argv[2], 0);
812	else
813		error("too many arguments");
814	return 0;
815}
816
817
818/*
819 * The unset builtin command.
820 */
821
822int
823unsetcmd(int argc __unused, char **argv __unused)
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("vf")) != '\0') {
832		if (i == 'f')
833			flg_func = 1;
834		else
835			flg_var = 1;
836	}
837	if (flg_func == 0 && flg_var == 0)
838		flg_var = 1;
839
840	INTOFF;
841	for (ap = argptr; *ap ; ap++) {
842		if (flg_func)
843			ret |= unsetfunc(*ap);
844		if (flg_var)
845			ret |= unsetvar(*ap);
846	}
847	INTON;
848	return ret;
849}
850
851
852/*
853 * Unset the specified variable.
854 * Called with interrupts off.
855 */
856
857int
858unsetvar(const char *s)
859{
860	struct var **vpp;
861	struct var *vp;
862
863	vp = find_var(s, &vpp, NULL);
864	if (vp == NULL)
865		return (0);
866	if (vp->flags & VREADONLY)
867		return (1);
868	if (vp->text[vp->name_len + 1] != '\0')
869		setvar(s, nullstr, 0);
870	if ((vp->flags & VEXPORT) && localevar(vp->text)) {
871		change_env(s, 0);
872		setlocale(LC_ALL, "");
873		updatecharset();
874	}
875	vp->flags &= ~VEXPORT;
876	vp->flags |= VUNSET;
877	if ((vp->flags & VSTRFIXED) == 0) {
878		if ((vp->flags & VTEXTFIXED) == 0)
879			ckfree(vp->text);
880		*vpp = vp->next;
881		ckfree(vp);
882	}
883	return (0);
884}
885
886
887
888/*
889 * Returns true if the two strings specify the same variable.  The first
890 * variable name is terminated by '='; the second may be terminated by
891 * either '=' or '\0'.
892 */
893
894static int
895varequal(const char *p, const char *q)
896{
897	while (*p == *q++) {
898		if (*p++ == '=')
899			return 1;
900	}
901	if (*p == '=' && *(q - 1) == '\0')
902		return 1;
903	return 0;
904}
905
906/*
907 * Search for a variable.
908 * 'name' may be terminated by '=' or a NUL.
909 * vppp is set to the pointer to vp, or the list head if vp isn't found
910 * lenp is set to the number of characters in 'name'
911 */
912
913static struct var *
914find_var(const char *name, struct var ***vppp, int *lenp)
915{
916	unsigned int hashval;
917	int len;
918	struct var *vp, **vpp;
919	const char *p = name;
920
921	hashval = 0;
922	while (*p && *p != '=')
923		hashval = 2 * hashval + (unsigned char)*p++;
924	len = p - name;
925
926	if (lenp)
927		*lenp = len;
928	vpp = &vartab[hashval % VTABSIZE];
929	if (vppp)
930		*vppp = vpp;
931
932	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
933		if (vp->name_len != len)
934			continue;
935		if (memcmp(vp->text, name, len) != 0)
936			continue;
937		if (vppp)
938			*vppp = vpp;
939		return vp;
940	}
941	return NULL;
942}
943