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