Merge branch 'vendor/GREP'
[dragonfly.git] / bin / sh / var.c
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  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)var.c    8.3 (Berkeley) 5/4/95
37  * $FreeBSD: src/bin/sh/var.c,v 1.56 2011/02/04 22:47:55 jilles Exp $
38  */
39
40 #include <unistd.h>
41 #include <stdlib.h>
42
43 /*
44  * Shell variables.
45  */
46
47 #include <locale.h>
48 #include <paths.h>
49
50 #include "shell.h"
51 #include "output.h"
52 #include "expand.h"
53 #include "nodes.h"      /* for other headers */
54 #include "eval.h"       /* defines cmdenviron */
55 #include "exec.h"
56 #include "syntax.h"
57 #include "options.h"
58 #include "mail.h"
59 #include "var.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "mystring.h"
63 #include "parser.h"
64 #ifndef NO_HISTORY
65 #include "myhistedit.h"
66 #endif
67
68
69 #define VTABSIZE 39
70
71
72 struct varinit {
73         struct var *var;
74         int flags;
75         const char *text;
76         void (*func)(const char *);
77 };
78
79
80 #ifndef NO_HISTORY
81 struct var vhistsize;
82 struct var vterm;
83 #endif
84 struct var vifs;
85 struct var vmail;
86 struct var vmpath;
87 struct var vpath;
88 struct var vppid;
89 struct var vps1;
90 struct var vps2;
91 struct var vps4;
92 struct var vvers;
93 static struct var voptind;
94
95 static const struct varinit varinit[] = {
96 #ifndef NO_HISTORY
97         { &vhistsize,   VUNSET,                         "HISTSIZE=",
98           sethistsize },
99 #endif
100         { &vifs,        0,                              "IFS= \t\n",
101           NULL },
102         { &vmail,       VUNSET,                         "MAIL=",
103           NULL },
104         { &vmpath,      VUNSET,                         "MAILPATH=",
105           NULL },
106         { &vpath,       0,                              "PATH=" _PATH_DEFPATH,
107           changepath },
108         { &vppid,       VUNSET,                         "PPID=",
109           NULL },
110         /*
111          * vps1 depends on uid
112          */
113         { &vps2,        0,                              "PS2=> ",
114           NULL },
115         { &vps4,        0,                              "PS4=+ ",
116           NULL },
117 #ifndef NO_HISTORY
118         { &vterm,       VUNSET,                         "TERM=",
119           setterm },
120 #endif
121         { &voptind,     0,                              "OPTIND=1",
122           getoptsreset },
123         { NULL, 0,                              NULL,
124           NULL }
125 };
126
127 static struct var *vartab[VTABSIZE];
128
129 static const char *const locale_names[7] = {
130         "LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
131         "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
132 };
133 static const int locale_categories[7] = {
134         LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
135 };
136
137 static struct var **hashvar(const char *);
138 static int varequal(const char *, const char *);
139 static int localevar(const char *);
140
141 /*
142  * Initialize the variable symbol tables and import the environment.
143  */
144
145 #ifdef mkinit
146 INCLUDE "var.h"
147 MKINIT char **environ;
148 INIT {
149         char **envp;
150
151         initvar();
152         for (envp = environ ; *envp ; envp++) {
153                 if (strchr(*envp, '=')) {
154                         setvareq(*envp, VEXPORT|VTEXTFIXED);
155                 }
156         }
157 }
158 #endif
159
160
161 /*
162  * This routine initializes the builtin variables.  It is called when the
163  * shell is initialized.
164  */
165
166 void
167 initvar(void)
168 {
169         char ppid[20];
170         const struct varinit *ip;
171         struct var *vp;
172         struct var **vpp;
173
174         for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
175                 if ((vp->flags & VEXPORT) == 0) {
176                         vpp = hashvar(ip->text);
177                         vp->next = *vpp;
178                         *vpp = vp;
179                         vp->text = __DECONST(char *, ip->text);
180                         vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
181                         vp->func = ip->func;
182                 }
183         }
184         /*
185          * PS1 depends on uid
186          */
187         if ((vps1.flags & VEXPORT) == 0) {
188                 vpp = hashvar("PS1=");
189                 vps1.next = *vpp;
190                 *vpp = &vps1;
191                 vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
192                 vps1.flags = VSTRFIXED|VTEXTFIXED;
193         }
194         if ((vppid.flags & VEXPORT) == 0) {
195                 fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
196                 setvarsafe("PPID", ppid, 0);
197         }
198 }
199
200 /*
201  * Safe version of setvar, returns 1 on success 0 on failure.
202  */
203
204 int
205 setvarsafe(const char *name, const char *val, int flags)
206 {
207         struct jmploc jmploc;
208         struct jmploc *const savehandler = handler;
209         int err = 0;
210         int inton;
211
212         inton = is_int_on();
213         if (setjmp(jmploc.loc))
214                 err = 1;
215         else {
216                 handler = &jmploc;
217                 setvar(name, val, flags);
218         }
219         handler = savehandler;
220         SETINTON(inton);
221         return err;
222 }
223
224 /*
225  * Set the value of a variable.  The flags argument is stored with the
226  * flags of the variable.  If val is NULL, the variable is unset.
227  */
228
229 void
230 setvar(const char *name, const char *val, int flags)
231 {
232         const char *p;
233         int len;
234         int namelen;
235         char *nameeq;
236         int isbad;
237
238         isbad = 0;
239         p = name;
240         if (!is_name(*p))
241                 isbad = 1;
242         p++;
243         for (;;) {
244                 if (!is_in_name(*p)) {
245                         if (*p == '\0' || *p == '=')
246                                 break;
247                         isbad = 1;
248                 }
249                 p++;
250         }
251         namelen = p - name;
252         if (isbad)
253                 error("%.*s: bad variable name", namelen, name);
254         len = namelen + 2;              /* 2 is space for '=' and '\0' */
255         if (val == NULL) {
256                 flags |= VUNSET;
257         } else {
258                 len += strlen(val);
259         }
260         nameeq = ckmalloc(len);
261         memcpy(nameeq, name, namelen);
262         nameeq[namelen] = '=';
263         if (val)
264                 scopy(val, nameeq + namelen + 1);
265         else
266                 nameeq[namelen + 1] = '\0';
267         setvareq(nameeq, flags);
268 }
269
270 static int
271 localevar(const char *s)
272 {
273         const char *const *ss;
274
275         if (*s != 'L')
276                 return 0;
277         if (varequal(s + 1, "ANG"))
278                 return 1;
279         if (strncmp(s + 1, "C_", 2) != 0)
280                 return 0;
281         if (varequal(s + 3, "ALL"))
282                 return 1;
283         for (ss = locale_names; *ss ; ss++)
284                 if (varequal(s + 3, *ss + 3))
285                         return 1;
286         return 0;
287 }
288
289 /*
290  * Sets/unsets an environment variable from a pointer that may actually be a
291  * pointer into environ where the string should not be manipulated.
292  */
293 static void
294 change_env(const char *s, int set)
295 {
296         char *eqp;
297         char *ss;
298
299         ss = savestr(s);
300         if ((eqp = strchr(ss, '=')) != NULL)
301                 *eqp = '\0';
302         if (set && eqp != NULL) {
303                 if (setenv(ss, eqp + 1, 1) != 0)
304                         error("setenv: cannot set %s=%s", ss, eqp + 1);
305         } else
306                 unsetenv(ss);
307         ckfree(ss);
308 }
309
310
311 /*
312  * Same as setvar except that the variable and value are passed in
313  * the first argument as name=value.  Since the first argument will
314  * be actually stored in the table, it should not be a string that
315  * will go away.
316  */
317
318 void
319 setvareq(char *s, int flags)
320 {
321         struct var *vp, **vpp;
322         int len;
323
324         if (aflag)
325                 flags |= VEXPORT;
326         vpp = hashvar(s);
327         for (vp = *vpp ; vp ; vp = vp->next) {
328                 if (varequal(s, vp->text)) {
329                         if (vp->flags & VREADONLY) {
330                                 len = strchr(s, '=') - s;
331                                 error("%.*s: is read only", len, s);
332                         }
333                         if (flags & VNOSET)
334                                 return;
335                         INTOFF;
336
337                         if (vp->func && (flags & VNOFUNC) == 0)
338                                 (*vp->func)(strchr(s, '=') + 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 init(), 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                                 setlocale(LC_ALL, "");
361                         }
362                         INTON;
363                         return;
364                 }
365         }
366         /* not found */
367         if (flags & VNOSET)
368                 return;
369         vp = ckmalloc(sizeof (*vp));
370         vp->flags = flags;
371         vp->text = s;
372         vp->next = *vpp;
373         vp->func = NULL;
374         INTOFF;
375         *vpp = vp;
376         if ((vp->flags & VEXPORT) && localevar(s)) {
377                 change_env(s, 1);
378                 setlocale(LC_ALL, "");
379         }
380         INTON;
381 }
382
383
384
385 /*
386  * Process a linked list of variable assignments.
387  */
388
389 void
390 listsetvar(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
407 char *
408 lookupvar(const char *name)
409 {
410         struct var *v;
411
412         for (v = *hashvar(name) ; v ; v = v->next) {
413                 if (varequal(v->text, name)) {
414                         if (v->flags & VUNSET)
415                                 return NULL;
416                         return strchr(v->text, '=') + 1;
417                 }
418         }
419         return NULL;
420 }
421
422
423
424 /*
425  * Search the environment of a builtin command.  If the second argument
426  * is nonzero, return the value of a variable even if it hasn't been
427  * exported.
428  */
429
430 char *
431 bltinlookup(const char *name, int doall)
432 {
433         struct strlist *sp;
434         struct var *v;
435         char *result;
436
437         result = NULL;
438         for (sp = cmdenviron ; sp ; sp = sp->next) {
439                 if (varequal(sp->text, name))
440                         result = strchr(sp->text, '=') + 1;
441         }
442         if (result != NULL)
443                 return result;
444         for (v = *hashvar(name) ; v ; v = v->next) {
445                 if (varequal(v->text, name)) {
446                         if ((v->flags & VUNSET)
447                          || (!doall && (v->flags & VEXPORT) == 0))
448                                 return NULL;
449                         return strchr(v->text, '=') + 1;
450                 }
451         }
452         return NULL;
453 }
454
455
456 /*
457  * Set up locale for a builtin (LANG/LC_* assignments).
458  */
459 void
460 bltinsetlocale(void)
461 {
462         struct strlist *lp;
463         int act = 0;
464         char *loc, *locdef;
465         int i;
466
467         for (lp = cmdenviron ; lp ; lp = lp->next) {
468                 if (localevar(lp->text)) {
469                         act = 1;
470                         break;
471                 }
472         }
473         if (!act)
474                 return;
475         loc = bltinlookup("LC_ALL", 0);
476         INTOFF;
477         if (loc != NULL) {
478                 setlocale(LC_ALL, loc);
479                 INTON;
480                 return;
481         }
482         locdef = bltinlookup("LANG", 0);
483         for (i = 0; locale_names[i] != NULL; i++) {
484                 loc = bltinlookup(locale_names[i], 0);
485                 if (loc == NULL)
486                         loc = locdef;
487                 if (loc != NULL)
488                         setlocale(locale_categories[i], loc);
489         }
490         INTON;
491 }
492
493 /*
494  * Undo the effect of bltinlocaleset().
495  */
496 void
497 bltinunsetlocale(void)
498 {
499         struct strlist *lp;
500
501         INTOFF;
502         for (lp = cmdenviron ; lp ; lp = lp->next) {
503                 if (localevar(lp->text)) {
504                         setlocale(LC_ALL, "");
505                         return;
506                 }
507         }
508         INTON;
509 }
510
511
512 /*
513  * Generate a list of exported variables.  This routine is used to construct
514  * the third argument to execve when executing a program.
515  */
516
517 char **
518 environment(void)
519 {
520         int nenv;
521         struct var **vpp;
522         struct var *vp;
523         char **env, **ep;
524
525         nenv = 0;
526         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
527                 for (vp = *vpp ; vp ; vp = vp->next)
528                         if (vp->flags & VEXPORT)
529                                 nenv++;
530         }
531         ep = env = stalloc((nenv + 1) * sizeof *env);
532         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
533                 for (vp = *vpp ; vp ; vp = vp->next)
534                         if (vp->flags & VEXPORT)
535                                 *ep++ = vp->text;
536         }
537         *ep = NULL;
538         return env;
539 }
540
541
542 static int
543 var_compare(const void *a, const void *b)
544 {
545         const char *const *sa, *const *sb;
546
547         sa = a;
548         sb = b;
549         /*
550          * This compares two var=value strings which creates a different
551          * order from what you would probably expect.  POSIX is somewhat
552          * ambiguous on what should be sorted exactly.
553          */
554         return strcoll(*sa, *sb);
555 }
556
557
558 /*
559  * Command to list all variables which are set.  This is invoked from the
560  * set command when it is called without any options or operands.
561  */
562
563 int
564 showvarscmd(int argc __unused, char **argv __unused)
565 {
566         struct var **vpp;
567         struct var *vp;
568         const char *s;
569         const char **vars;
570         int i, n;
571
572         /*
573          * POSIX requires us to sort the variables.
574          */
575         n = 0;
576         for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
577                 for (vp = *vpp; vp; vp = vp->next) {
578                         if (!(vp->flags & VUNSET))
579                                 n++;
580                 }
581         }
582
583         INTON;
584         vars = ckmalloc(n * sizeof(*vars));
585         i = 0;
586         for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
587                 for (vp = *vpp; vp; vp = vp->next) {
588                         if (!(vp->flags & VUNSET))
589                                 vars[i++] = vp->text;
590                 }
591         }
592
593         qsort(vars, n, sizeof(*vars), var_compare);
594         for (i = 0; i < n; i++) {
595                 s = strchr(vars[i], '=');
596                 s++;
597                 outbin(vars[i], s - vars[i], out1);
598                 out1qstr(s);
599                 out1c('\n');
600         }
601         ckfree(vars);
602         INTOFF;
603
604         return 0;
605 }
606
607
608
609 /*
610  * The export and readonly commands.
611  */
612
613 int
614 exportcmd(int argc, char **argv)
615 {
616         struct var **vpp;
617         struct var *vp;
618         char *name;
619         char *p;
620         char *cmdname;
621         int ch, values;
622         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
623
624         cmdname = argv[0];
625         optreset = optind = 1;
626         opterr = 0;
627         values = 0;
628         while ((ch = getopt(argc, argv, "p")) != -1) {
629                 switch (ch) {
630                 case 'p':
631                         values = 1;
632                         break;
633                 case '?':
634                 default:
635                         error("unknown option: -%c", optopt);
636                 }
637         }
638         argc -= optind;
639         argv += optind;
640
641         if (values && argc != 0)
642                 error("-p requires no arguments");
643         if (argc != 0) {
644                 while ((name = *argv++) != NULL) {
645                         if ((p = strchr(name, '=')) != NULL) {
646                                 p++;
647                         } else {
648                                 vpp = hashvar(name);
649                                 for (vp = *vpp ; vp ; vp = vp->next) {
650                                         if (varequal(vp->text, name)) {
651
652                                                 vp->flags |= flag;
653                                                 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
654                                                         change_env(vp->text, 1);
655                                                         setlocale(LC_ALL, "");
656                                                 }
657                                                 goto found;
658                                         }
659                                 }
660                         }
661                         setvar(name, p, flag);
662 found:;
663                 }
664         } else {
665                 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
666                         for (vp = *vpp ; vp ; vp = vp->next) {
667                                 if (vp->flags & flag) {
668                                         if (values) {
669                                                 out1str(cmdname);
670                                                 out1c(' ');
671                                         }
672                                         p = strchr(vp->text, '=');
673                                         if (values && !(vp->flags & VUNSET)) {
674                                                 p++;
675                                                 outbin(vp->text, p - vp->text,
676                                                     out1);
677                                                 out1qstr(p);
678                                         } else
679                                                 outbin(vp->text, p - vp->text,
680                                                     out1);
681                                         out1c('\n');
682                                 }
683                         }
684                 }
685         }
686         return 0;
687 }
688
689
690 /*
691  * The "local" command.
692  */
693
694 int
695 localcmd(int argc __unused, char **argv __unused)
696 {
697         char *name;
698
699         if (! in_function())
700                 error("Not in a function");
701         while ((name = *argptr++) != NULL) {
702                 mklocal(name);
703         }
704         return 0;
705 }
706
707
708 /*
709  * Make a variable a local variable.  When a variable is made local, it's
710  * value and flags are saved in a localvar structure.  The saved values
711  * will be restored when the shell function returns.  We handle the name
712  * "-" as a special case.
713  */
714
715 void
716 mklocal(char *name)
717 {
718         struct localvar *lvp;
719         struct var **vpp;
720         struct var *vp;
721
722         INTOFF;
723         lvp = ckmalloc(sizeof (struct localvar));
724         if (name[0] == '-' && name[1] == '\0') {
725                 lvp->text = ckmalloc(sizeof optlist);
726                 memcpy(lvp->text, optlist, sizeof optlist);
727                 vp = NULL;
728         } else {
729                 vpp = hashvar(name);
730                 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
731                 if (vp == NULL) {
732                         if (strchr(name, '='))
733                                 setvareq(savestr(name), VSTRFIXED);
734                         else
735                                 setvar(name, NULL, VSTRFIXED);
736                         vp = *vpp;      /* the new variable */
737                         lvp->text = NULL;
738                         lvp->flags = VUNSET;
739                 } else {
740                         lvp->text = vp->text;
741                         lvp->flags = vp->flags;
742                         vp->flags |= VSTRFIXED|VTEXTFIXED;
743                         if (strchr(name, '='))
744                                 setvareq(savestr(name), 0);
745                 }
746         }
747         lvp->vp = vp;
748         lvp->next = localvars;
749         localvars = lvp;
750         INTON;
751 }
752
753
754 /*
755  * Called after a function returns.
756  */
757
758 void
759 poplocalvars(void)
760 {
761         struct localvar *lvp;
762         struct var *vp;
763
764         while ((lvp = localvars) != NULL) {
765                 localvars = lvp->next;
766                 vp = lvp->vp;
767                 if (vp == NULL) {       /* $- saved */
768                         memcpy(optlist, lvp->text, sizeof optlist);
769                         ckfree(lvp->text);
770                         optschanged();
771                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
772                         unsetvar(vp->text);
773                 } else {
774                         if ((vp->flags & VTEXTFIXED) == 0)
775                                 ckfree(vp->text);
776                         vp->flags = lvp->flags;
777                         vp->text = lvp->text;
778                 }
779                 ckfree(lvp);
780         }
781 }
782
783
784 int
785 setvarcmd(int argc, char **argv)
786 {
787         if (argc <= 2)
788                 return unsetcmd(argc, argv);
789         else if (argc == 3)
790                 setvar(argv[1], argv[2], 0);
791         else
792                 error("too many arguments");
793         return 0;
794 }
795
796
797 /*
798  * The unset builtin command.
799  */
800
801 int
802 unsetcmd(int argc __unused, char **argv __unused)
803 {
804         char **ap;
805         int i;
806         int flg_func = 0;
807         int flg_var = 0;
808         int ret = 0;
809
810         while ((i = nextopt("vf")) != '\0') {
811                 if (i == 'f')
812                         flg_func = 1;
813                 else
814                         flg_var = 1;
815         }
816         if (flg_func == 0 && flg_var == 0)
817                 flg_var = 1;
818
819         for (ap = argptr; *ap ; ap++) {
820                 if (flg_func)
821                         ret |= unsetfunc(*ap);
822                 if (flg_var)
823                         ret |= unsetvar(*ap);
824         }
825         return ret;
826 }
827
828
829 /*
830  * Unset the specified variable.
831  */
832
833 int
834 unsetvar(const char *s)
835 {
836         struct var **vpp;
837         struct var *vp;
838
839         vpp = hashvar(s);
840         for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
841                 if (varequal(vp->text, s)) {
842                         if (vp->flags & VREADONLY)
843                                 return (1);
844                         INTOFF;
845                         if (*(strchr(vp->text, '=') + 1) != '\0')
846                                 setvar(s, nullstr, 0);
847                         if ((vp->flags & VEXPORT) && localevar(vp->text)) {
848                                 change_env(__DECONST(char *, s), 0);
849                                 setlocale(LC_ALL, "");
850                         }
851                         vp->flags &= ~VEXPORT;
852                         vp->flags |= VUNSET;
853                         if ((vp->flags & VSTRFIXED) == 0) {
854                                 if ((vp->flags & VTEXTFIXED) == 0)
855                                         ckfree(vp->text);
856                                 *vpp = vp->next;
857                                 ckfree(vp);
858                         }
859                         INTON;
860                         return (0);
861                 }
862         }
863         return (0);
864 }
865
866
867
868 /*
869  * Find the appropriate entry in the hash table from the name.
870  */
871
872 static struct var **
873 hashvar(const char *p)
874 {
875         unsigned int hashval;
876
877         hashval = ((unsigned char) *p) << 4;
878         while (*p && *p != '=')
879                 hashval += (unsigned char) *p++;
880         return &vartab[hashval % VTABSIZE];
881 }
882
883
884
885 /*
886  * Returns true if the two strings specify the same varable.  The first
887  * variable name is terminated by '='; the second may be terminated by
888  * either '=' or '\0'.
889  */
890
891 static int
892 varequal(const char *p, const char *q)
893 {
894         while (*p == *q++) {
895                 if (*p++ == '=')
896                         return 1;
897         }
898         if (*p == '=' && *(q - 1) == '\0')
899                 return 1;
900         return 0;
901 }