VirtualBox

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

Last change on this file since 3544 was 3477, checked in by bird, 5 years ago

kash: Use kHlpAssert instead of assert.h (debugger stops on the assertion rather than at exit process code).

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