VirtualBox

source: kBuild/trunk/src/kash/var.c@ 2552

Last change on this file since 2552 was 2552, checked in by bird, 13 years ago

Path fix on windows.

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

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