VirtualBox

source: kBuild/trunk/src/ash/var.c@ 805

Last change on this file since 805 was 637, checked in by bird, 18 years ago

Path != PATH. stupid stupid windows idiots.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette