var.c revision 258776
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: head/bin/sh/var.c 258776 2013-11-30 21:27:11Z 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 vppid;
92struct var vps1;
93struct var vps2;
94struct var vps4;
95struct var vvers;
96static struct var voptind;
97struct var vdisvfork;
98
99int forcelocal;
100
101static const struct varinit varinit[] = {
102#ifndef NO_HISTORY
103	{ &vhistsize,	VUNSET,				"HISTSIZE=",
104	  sethistsize },
105#endif
106	{ &vifs,	0,				"IFS= \t\n",
107	  NULL },
108	{ &vmail,	VUNSET,				"MAIL=",
109	  NULL },
110	{ &vmpath,	VUNSET,				"MAILPATH=",
111	  NULL },
112	{ &vpath,	0,				"PATH=" _PATH_DEFPATH,
113	  changepath },
114	{ &vppid,	VUNSET,				"PPID=",
115	  NULL },
116	/*
117	 * vps1 depends on uid
118	 */
119	{ &vps2,	0,				"PS2=> ",
120	  NULL },
121	{ &vps4,	0,				"PS4=+ ",
122	  NULL },
123#ifndef NO_HISTORY
124	{ &vterm,	VUNSET,				"TERM=",
125	  setterm },
126#endif
127	{ &voptind,	0,				"OPTIND=1",
128	  getoptsreset },
129	{ &vdisvfork,	VUNSET,				"SH_DISABLE_VFORK=",
130	  NULL },
131	{ NULL,	0,				NULL,
132	  NULL }
133};
134
135static struct var *vartab[VTABSIZE];
136
137static const char *const locale_names[7] = {
138	"LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
139	"LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
140};
141static const int locale_categories[7] = {
142	LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
143};
144
145static int varequal(const char *, const char *);
146static struct var *find_var(const char *, struct var ***, int *);
147static int localevar(const char *);
148
149extern char **environ;
150
151/*
152 * This routine initializes the builtin variables and imports the environment.
153 * It is called when the shell is initialized.
154 */
155
156void
157initvar(void)
158{
159	char ppid[20];
160	const struct varinit *ip;
161	struct var *vp;
162	struct var **vpp;
163	char **envp;
164
165	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
166		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
167			continue;
168		vp->next = *vpp;
169		*vpp = vp;
170		vp->text = __DECONST(char *, ip->text);
171		vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
172		vp->func = ip->func;
173	}
174	/*
175	 * PS1 depends on uid
176	 */
177	if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
178		vps1.next = *vpp;
179		*vpp = &vps1;
180		vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
181		vps1.flags = VSTRFIXED|VTEXTFIXED;
182	}
183	if ((vppid.flags & VEXPORT) == 0) {
184		fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
185		setvarsafe("PPID", ppid, 0);
186	}
187	for (envp = environ ; *envp ; envp++) {
188		if (strchr(*envp, '=')) {
189			setvareq(*envp, VEXPORT|VTEXTFIXED);
190		}
191	}
192}
193
194/*
195 * Safe version of setvar, returns 1 on success 0 on failure.
196 */
197
198int
199setvarsafe(const char *name, const char *val, int flags)
200{
201	struct jmploc jmploc;
202	struct jmploc *const savehandler = handler;
203	int err = 0;
204	int inton;
205
206	inton = is_int_on();
207	if (setjmp(jmploc.loc))
208		err = 1;
209	else {
210		handler = &jmploc;
211		setvar(name, val, flags);
212	}
213	handler = savehandler;
214	SETINTON(inton);
215	return err;
216}
217
218/*
219 * Set the value of a variable.  The flags argument is stored with the
220 * flags of the variable.  If val is NULL, the variable is unset.
221 */
222
223void
224setvar(const char *name, const char *val, int flags)
225{
226	const char *p;
227	size_t len;
228	size_t namelen;
229	size_t vallen;
230	char *nameeq;
231	int isbad;
232
233	isbad = 0;
234	p = name;
235	if (! is_name(*p))
236		isbad = 1;
237	p++;
238	for (;;) {
239		if (! is_in_name(*p)) {
240			if (*p == '\0' || *p == '=')
241				break;
242			isbad = 1;
243		}
244		p++;
245	}
246	namelen = p - name;
247	if (isbad)
248		error("%.*s: bad variable name", (int)namelen, name);
249	len = namelen + 2;		/* 2 is space for '=' and '\0' */
250	if (val == NULL) {
251		flags |= VUNSET;
252		vallen = 0;
253	} else {
254		vallen = strlen(val);
255		len += vallen;
256	}
257	nameeq = ckmalloc(len);
258	memcpy(nameeq, name, namelen);
259	nameeq[namelen] = '=';
260	if (val)
261		memcpy(nameeq + namelen + 1, val, vallen + 1);
262	else
263		nameeq[namelen + 1] = '\0';
264	setvareq(nameeq, flags);
265}
266
267static int
268localevar(const char *s)
269{
270	const char *const *ss;
271
272	if (*s != 'L')
273		return 0;
274	if (varequal(s + 1, "ANG"))
275		return 1;
276	if (strncmp(s + 1, "C_", 2) != 0)
277		return 0;
278	if (varequal(s + 3, "ALL"))
279		return 1;
280	for (ss = locale_names; *ss ; ss++)
281		if (varequal(s + 3, *ss + 3))
282			return 1;
283	return 0;
284}
285
286
287/*
288 * Sets/unsets an environment variable from a pointer that may actually be a
289 * pointer into environ where the string should not be manipulated.
290 */
291static void
292change_env(const char *s, int set)
293{
294	char *eqp;
295	char *ss;
296
297	ss = savestr(s);
298	if ((eqp = strchr(ss, '=')) != NULL)
299		*eqp = '\0';
300	if (set && eqp != NULL)
301		(void) setenv(ss, eqp + 1, 1);
302	else
303		(void) unsetenv(ss);
304	ckfree(ss);
305
306	return;
307}
308
309
310/*
311 * Same as setvar except that the variable and value are passed in
312 * the first argument as name=value.  Since the first argument will
313 * be actually stored in the table, it should not be a string that
314 * will go away.
315 */
316
317void
318setvareq(char *s, int flags)
319{
320	struct var *vp, **vpp;
321	int nlen;
322
323	if (aflag)
324		flags |= VEXPORT;
325	if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
326		mklocal(s);
327	vp = find_var(s, &vpp, &nlen);
328	if (vp != NULL) {
329		if (vp->flags & VREADONLY)
330			error("%.*s: is read only", vp->name_len, s);
331		if (flags & VNOSET)
332			return;
333		INTOFF;
334
335		if (vp->func && (flags & VNOFUNC) == 0)
336			(*vp->func)(s + vp->name_len + 1);
337
338		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
339			ckfree(vp->text);
340
341		vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
342		vp->flags |= flags;
343		vp->text = s;
344
345		/*
346		 * We could roll this to a function, to handle it as
347		 * a regular variable function callback, but why bother?
348		 *
349		 * Note: this assumes iflag is not set to 1 initially.
350		 * As part of initvar(), this is called before arguments
351		 * are looked at.
352		 */
353		if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
354		    iflag == 1)
355			chkmail(1);
356		if ((vp->flags & VEXPORT) && localevar(s)) {
357			change_env(s, 1);
358			(void) setlocale(LC_ALL, "");
359			updatecharset();
360		}
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