VirtualBox

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

最後變更 在這個檔案從3438是 3438,由 bird 提交於 5 年 前

kash: Hammering on threaded mode.

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

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