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