VirtualBox

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

Last change on this file since 1214 was 1214, checked in by bird, 17 years ago

some more cleanup.

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