Deleted Added
full compact
var.c (25905) var.c (36150)
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $Id: var.c,v 1.10 1997/04/28 03:06:39 steve Exp $
37 */
38
39#ifndef lint
35 */
36
37#ifndef lint
40static char const sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
38#if 0
39static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
40#endif
41static const char rcsid[] =
42 "$Id$";
41#endif /* not lint */
42
43#include <unistd.h>
44#include <stdlib.h>
45
46/*
47 * Shell variables.
48 */
49
50#include <locale.h>
51
52#include "shell.h"
53#include "output.h"
54#include "expand.h"
55#include "nodes.h" /* for other headers */
56#include "eval.h" /* defines cmdenviron */
57#include "exec.h"
58#include "syntax.h"
59#include "options.h"
60#include "mail.h"
61#include "var.h"
62#include "memalloc.h"
63#include "error.h"
64#include "mystring.h"
65#include "parser.h"
66#ifndef NO_HISTORY
67#include "myhistedit.h"
68#endif
69
70
71#define VTABSIZE 39
72
73
74struct varinit {
75 struct var *var;
76 int flags;
77 char *text;
78 void (*func) __P((const char *));
79};
80
81
82#if ATTY
83struct var vatty;
84#endif
85#ifndef NO_HISTORY
86struct var vhistsize;
87#endif
88struct var vifs;
89struct var vmail;
90struct var vmpath;
91struct var vpath;
92struct var vps1;
93struct var vps2;
94struct var vvers;
95#if ATTY
96struct var vterm;
97#endif
98struct var voptind;
99
100const struct varinit varinit[] = {
101#if ATTY
102 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
103 NULL },
104#endif
105#ifndef NO_HISTORY
106 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
107 sethistsize },
108#endif
109 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
110 NULL },
111 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
112 NULL },
113 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
114 NULL },
115 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin",
116 changepath },
117 /*
118 * vps1 depends on uid
119 */
120 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
121 NULL },
122#if ATTY
123 { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
124 NULL },
125#endif
126 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
127 getoptsreset },
128 { NULL, 0, NULL,
129 NULL }
130};
131
132struct var *vartab[VTABSIZE];
133
134STATIC struct var **hashvar __P((char *));
135STATIC int varequal __P((char *, char *));
136STATIC int localevar __P((char *));
137
138/*
139 * Initialize the varable symbol tables and import the environment
140 */
141
142#ifdef mkinit
143INCLUDE "var.h"
144INIT {
145 char **envp;
146 extern char **environ;
147
148 initvar();
149 for (envp = environ ; *envp ; envp++) {
150 if (strchr(*envp, '=')) {
151 setvareq(*envp, VEXPORT|VTEXTFIXED);
152 }
153 }
154}
155#endif
156
157
158/*
159 * This routine initializes the builtin variables. It is called when the
160 * shell is initialized and again when a shell procedure is spawned.
161 */
162
163void
164initvar() {
165 const struct varinit *ip;
166 struct var *vp;
167 struct var **vpp;
168
169 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
170 if ((vp->flags & VEXPORT) == 0) {
171 vpp = hashvar(ip->text);
172 vp->next = *vpp;
173 *vpp = vp;
174 vp->text = ip->text;
175 vp->flags = ip->flags;
176 vp->func = ip->func;
177 }
178 }
179 /*
180 * PS1 depends on uid
181 */
182 if ((vps1.flags & VEXPORT) == 0) {
183 vpp = hashvar("PS1=");
184 vps1.next = *vpp;
185 *vpp = &vps1;
186 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
187 vps1.flags = VSTRFIXED|VTEXTFIXED;
188 }
189}
190
191/*
192 * Safe version of setvar, returns 1 on success 0 on failure.
193 */
194
195int
196setvarsafe(name, val, flags)
197 char *name, *val;
198 int flags;
199{
200 struct jmploc jmploc;
201 struct jmploc *volatile savehandler = handler;
202 int err = 0;
203#if __GNUC__
204 /* Avoid longjmp clobbering */
205 (void) &err;
206#endif
207
208 if (setjmp(jmploc.loc))
209 err = 1;
210 else {
211 handler = &jmploc;
212 setvar(name, val, flags);
213 }
214 handler = savehandler;
215 return err;
216}
217
218/*
219 * Set the value of a variable. The flags argument is ored with the
220 * flags of the variable. If val is NULL, the variable is unset.
221 */
222
223void
224setvar(name, val, flags)
225 char *name, *val;
226 int flags;
227{
228 char *p, *q;
229 int len;
230 int namelen;
231 char *nameeq;
232 int isbad;
233
234 isbad = 0;
235 p = name;
236 if (! is_name(*p))
237 isbad = 1;
238 p++;
239 for (;;) {
240 if (! is_in_name(*p)) {
241 if (*p == '\0' || *p == '=')
242 break;
243 isbad = 1;
244 }
245 p++;
246 }
247 namelen = p - name;
248 if (isbad)
249 error("%.*s: bad variable name", namelen, name);
250 len = namelen + 2; /* 2 is space for '=' and '\0' */
251 if (val == NULL) {
252 flags |= VUNSET;
253 } else {
254 len += strlen(val);
255 }
256 p = nameeq = ckmalloc(len);
257 q = name;
258 while (--namelen >= 0)
259 *p++ = *q++;
260 *p++ = '=';
261 *p = '\0';
262 if (val)
263 scopy(val, p);
264 setvareq(nameeq, flags);
265}
266
267STATIC int
268localevar(s)
269 char *s;
270 {
271 static char *lnames[7] = {
272 "ALL", "COLLATE", "CTYPE", "MONETARY",
273 "NUMERIC", "TIME", NULL
274 };
275 char **ss;
276
277 if (*s != 'L')
278 return 0;
279 if (varequal(s + 1, "ANG"))
280 return 1;
281 if (strncmp(s + 1, "C_", 2) != 0)
282 return 0;
283 for (ss = lnames; *ss ; ss++)
284 if (varequal(s + 3, *ss))
285 return 1;
286 return 0;
287}
288
289/*
290 * Same as setvar except that the variable and value are passed in
291 * the first argument as name=value. Since the first argument will
292 * be actually stored in the table, it should not be a string that
293 * will go away.
294 */
295
296void
297setvareq(s, flags)
298 char *s;
299 int flags;
300{
301 struct var *vp, **vpp;
302
303 vpp = hashvar(s);
304 for (vp = *vpp ; vp ; vp = vp->next) {
305 if (varequal(s, vp->text)) {
306 if (vp->flags & VREADONLY) {
307 size_t len = strchr(s, '=') - s;
308 error("%.*s: is read only", len, s);
309 }
310 INTOFF;
311
312 if (vp->func && (flags & VNOFUNC) == 0)
313 (*vp->func)(strchr(s, '=') + 1);
314
315 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
316 ckfree(vp->text);
317
318 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
319 vp->flags |= flags;
320 vp->text = s;
321
322 /*
323 * We could roll this to a function, to handle it as
324 * a regular variable function callback, but why bother?
325 */
326 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
327 chkmail(1);
328 if ((vp->flags & VEXPORT) && localevar(s)) {
329 putenv(s);
330 (void) setlocale(LC_ALL, "");
331 }
332 INTON;
333 return;
334 }
335 }
336 /* not found */
337 vp = ckmalloc(sizeof (*vp));
338 vp->flags = flags;
339 vp->text = s;
340 vp->next = *vpp;
341 vp->func = NULL;
342 INTOFF;
343 *vpp = vp;
344 if ((vp->flags & VEXPORT) && localevar(s)) {
345 putenv(s);
346 (void) setlocale(LC_ALL, "");
347 }
348 INTON;
349}
350
351
352
353/*
354 * Process a linked list of variable assignments.
355 */
356
357void
358listsetvar(list)
359 struct strlist *list;
360 {
361 struct strlist *lp;
362
363 INTOFF;
364 for (lp = list ; lp ; lp = lp->next) {
365 setvareq(savestr(lp->text), 0);
366 }
367 INTON;
368}
369
370
371
372/*
373 * Find the value of a variable. Returns NULL if not set.
374 */
375
376char *
377lookupvar(name)
378 char *name;
379 {
380 struct var *v;
381
382 for (v = *hashvar(name) ; v ; v = v->next) {
383 if (varequal(v->text, name)) {
384 if (v->flags & VUNSET)
385 return NULL;
386 return strchr(v->text, '=') + 1;
387 }
388 }
389 return NULL;
390}
391
392
393
394/*
395 * Search the environment of a builtin command. If the second argument
396 * is nonzero, return the value of a variable even if it hasn't been
397 * exported.
398 */
399
400char *
401bltinlookup(name, doall)
402 char *name;
403 int doall;
404{
405 struct strlist *sp;
406 struct var *v;
407
408 for (sp = cmdenviron ; sp ; sp = sp->next) {
409 if (varequal(sp->text, name))
410 return strchr(sp->text, '=') + 1;
411 }
412 for (v = *hashvar(name) ; v ; v = v->next) {
413 if (varequal(v->text, name)) {
414 if ((v->flags & VUNSET)
415 || (!doall && (v->flags & VEXPORT) == 0))
416 return NULL;
417 return strchr(v->text, '=') + 1;
418 }
419 }
420 return NULL;
421}
422
423
424
425/*
426 * Generate a list of exported variables. This routine is used to construct
427 * the third argument to execve when executing a program.
428 */
429
430char **
431environment() {
432 int nenv;
433 struct var **vpp;
434 struct var *vp;
435 char **env, **ep;
436
437 nenv = 0;
438 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
439 for (vp = *vpp ; vp ; vp = vp->next)
440 if (vp->flags & VEXPORT)
441 nenv++;
442 }
443 ep = env = stalloc((nenv + 1) * sizeof *env);
444 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
445 for (vp = *vpp ; vp ; vp = vp->next)
446 if (vp->flags & VEXPORT)
447 *ep++ = vp->text;
448 }
449 *ep = NULL;
450 return env;
451}
452
453
454/*
455 * Called when a shell procedure is invoked to clear out nonexported
456 * variables. It is also necessary to reallocate variables of with
457 * VSTACK set since these are currently allocated on the stack.
458 */
459
460#ifdef mkinit
461MKINIT void shprocvar();
462
463SHELLPROC {
464 shprocvar();
465}
466#endif
467
468void
469shprocvar() {
470 struct var **vpp;
471 struct var *vp, **prev;
472
473 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
474 for (prev = vpp ; (vp = *prev) != NULL ; ) {
475 if ((vp->flags & VEXPORT) == 0) {
476 *prev = vp->next;
477 if ((vp->flags & VTEXTFIXED) == 0)
478 ckfree(vp->text);
479 if ((vp->flags & VSTRFIXED) == 0)
480 ckfree(vp);
481 } else {
482 if (vp->flags & VSTACK) {
483 vp->text = savestr(vp->text);
484 vp->flags &=~ VSTACK;
485 }
486 prev = &vp->next;
487 }
488 }
489 }
490 initvar();
491}
492
493
494
495/*
496 * Command to list all variables which are set. Currently this command
497 * is invoked from the set command when the set command is called without
498 * any variables.
499 */
500
501int
502showvarscmd(argc, argv)
503 int argc __unused;
504 char **argv __unused;
505{
506 struct var **vpp;
507 struct var *vp;
508
509 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
510 for (vp = *vpp ; vp ; vp = vp->next) {
511 if ((vp->flags & VUNSET) == 0)
512 out1fmt("%s\n", vp->text);
513 }
514 }
515 return 0;
516}
517
518
519
520/*
521 * The export and readonly commands.
522 */
523
524int
525exportcmd(argc, argv)
526 int argc;
527 char **argv;
528{
529 struct var **vpp;
530 struct var *vp;
531 char *name;
532 char *p;
533 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
534
535 listsetvar(cmdenviron);
536 if (argc > 1) {
537 while ((name = *argptr++) != NULL) {
538 if ((p = strchr(name, '=')) != NULL) {
539 p++;
540 } else {
541 vpp = hashvar(name);
542 for (vp = *vpp ; vp ; vp = vp->next) {
543 if (varequal(vp->text, name)) {
544 vp->flags |= flag;
545 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
546 putenv(vp->text);
547 (void) setlocale(LC_ALL, "");
548 }
549 goto found;
550 }
551 }
552 }
553 setvar(name, p, flag);
554found:;
555 }
556 } else {
557 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
558 for (vp = *vpp ; vp ; vp = vp->next) {
559 if (vp->flags & flag) {
560 for (p = vp->text ; *p != '=' ; p++)
561 out1c(*p);
562 out1c('\n');
563 }
564 }
565 }
566 }
567 return 0;
568}
569
570
571/*
572 * The "local" command.
573 */
574
575int
576localcmd(argc, argv)
577 int argc __unused;
578 char **argv __unused;
579{
580 char *name;
581
582 if (! in_function())
583 error("Not in a function");
584 while ((name = *argptr++) != NULL) {
585 mklocal(name);
586 }
587 return 0;
588}
589
590
591/*
592 * Make a variable a local variable. When a variable is made local, it's
593 * value and flags are saved in a localvar structure. The saved values
594 * will be restored when the shell function returns. We handle the name
595 * "-" as a special case.
596 */
597
598void
599mklocal(name)
600 char *name;
601 {
602 struct localvar *lvp;
603 struct var **vpp;
604 struct var *vp;
605
606 INTOFF;
607 lvp = ckmalloc(sizeof (struct localvar));
608 if (name[0] == '-' && name[1] == '\0') {
609 lvp->text = ckmalloc(sizeof optlist);
610 memcpy(lvp->text, optlist, sizeof optlist);
611 vp = NULL;
612 } else {
613 vpp = hashvar(name);
614 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
615 if (vp == NULL) {
616 if (strchr(name, '='))
617 setvareq(savestr(name), VSTRFIXED);
618 else
619 setvar(name, NULL, VSTRFIXED);
620 vp = *vpp; /* the new variable */
621 lvp->text = NULL;
622 lvp->flags = VUNSET;
623 } else {
624 lvp->text = vp->text;
625 lvp->flags = vp->flags;
626 vp->flags |= VSTRFIXED|VTEXTFIXED;
627 if (strchr(name, '='))
628 setvareq(savestr(name), 0);
629 }
630 }
631 lvp->vp = vp;
632 lvp->next = localvars;
633 localvars = lvp;
634 INTON;
635}
636
637
638/*
639 * Called after a function returns.
640 */
641
642void
643poplocalvars() {
644 struct localvar *lvp;
645 struct var *vp;
646
647 while ((lvp = localvars) != NULL) {
648 localvars = lvp->next;
649 vp = lvp->vp;
650 if (vp == NULL) { /* $- saved */
651 memcpy(optlist, lvp->text, sizeof optlist);
652 ckfree(lvp->text);
653 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
654 (void)unsetvar(vp->text);
655 } else {
656 if ((vp->flags & VTEXTFIXED) == 0)
657 ckfree(vp->text);
658 vp->flags = lvp->flags;
659 vp->text = lvp->text;
660 }
661 ckfree(lvp);
662 }
663}
664
665
666int
667setvarcmd(argc, argv)
668 int argc;
669 char **argv;
670{
671 if (argc <= 2)
672 return unsetcmd(argc, argv);
673 else if (argc == 3)
674 setvar(argv[1], argv[2], 0);
675 else
676 error("List assignment not implemented");
677 return 0;
678}
679
680
681/*
682 * The unset builtin command. We unset the function before we unset the
683 * variable to allow a function to be unset when there is a readonly variable
684 * with the same name.
685 */
686
687int
688unsetcmd(argc, argv)
689 int argc __unused;
690 char **argv __unused;
691{
692 char **ap;
693 int i;
694 int flg_func = 0;
695 int flg_var = 0;
696 int ret = 0;
697
698 while ((i = nextopt("vf")) != '\0') {
699 if (i == 'f')
700 flg_func = 1;
701 else
702 flg_var = 1;
703 }
704 if (flg_func == 0 && flg_var == 0)
705 flg_var = 1;
706
707 for (ap = argptr; *ap ; ap++) {
708 if (flg_func)
709 ret |= unsetfunc(*ap);
710 if (flg_var)
711 ret |= unsetvar(*ap);
712 }
713 return ret;
714}
715
716
717/*
718 * Unset the specified variable.
719 */
720
721int
722unsetvar(s)
723 char *s;
724 {
725 struct var **vpp;
726 struct var *vp;
727
728 vpp = hashvar(s);
729 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
730 if (varequal(vp->text, s)) {
731 if (vp->flags & VREADONLY)
732 return (1);
733 INTOFF;
734 if (*(strchr(vp->text, '=') + 1) != '\0')
735 setvar(s, nullstr, 0);
736 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
737 unsetenv(s);
738 setlocale(LC_ALL, "");
739 }
740 vp->flags &= ~VEXPORT;
741 vp->flags |= VUNSET;
742 if ((vp->flags & VSTRFIXED) == 0) {
743 if ((vp->flags & VTEXTFIXED) == 0)
744 ckfree(vp->text);
745 *vpp = vp->next;
746 ckfree(vp);
747 }
748 INTON;
749 return (0);
750 }
751 }
752
753 return (1);
754}
755
756
757
758/*
759 * Find the appropriate entry in the hash table from the name.
760 */
761
762STATIC struct var **
763hashvar(p)
764 char *p;
765 {
766 unsigned int hashval;
767
768 hashval = ((unsigned char) *p) << 4;
769 while (*p && *p != '=')
770 hashval += (unsigned char) *p++;
771 return &vartab[hashval % VTABSIZE];
772}
773
774
775
776/*
777 * Returns true if the two strings specify the same varable. The first
778 * variable name is terminated by '='; the second may be terminated by
779 * either '=' or '\0'.
780 */
781
782STATIC int
783varequal(p, q)
784 char *p, *q;
785 {
786 while (*p == *q++) {
787 if (*p++ == '=')
788 return 1;
789 }
790 if (*p == '=' && *(q - 1) == '\0')
791 return 1;
792 return 0;
793}
43#endif /* not lint */
44
45#include <unistd.h>
46#include <stdlib.h>
47
48/*
49 * Shell variables.
50 */
51
52#include <locale.h>
53
54#include "shell.h"
55#include "output.h"
56#include "expand.h"
57#include "nodes.h" /* for other headers */
58#include "eval.h" /* defines cmdenviron */
59#include "exec.h"
60#include "syntax.h"
61#include "options.h"
62#include "mail.h"
63#include "var.h"
64#include "memalloc.h"
65#include "error.h"
66#include "mystring.h"
67#include "parser.h"
68#ifndef NO_HISTORY
69#include "myhistedit.h"
70#endif
71
72
73#define VTABSIZE 39
74
75
76struct varinit {
77 struct var *var;
78 int flags;
79 char *text;
80 void (*func) __P((const char *));
81};
82
83
84#if ATTY
85struct var vatty;
86#endif
87#ifndef NO_HISTORY
88struct var vhistsize;
89#endif
90struct var vifs;
91struct var vmail;
92struct var vmpath;
93struct var vpath;
94struct var vps1;
95struct var vps2;
96struct var vvers;
97#if ATTY
98struct var vterm;
99#endif
100struct var voptind;
101
102const struct varinit varinit[] = {
103#if ATTY
104 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
105 NULL },
106#endif
107#ifndef NO_HISTORY
108 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
109 sethistsize },
110#endif
111 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
112 NULL },
113 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
114 NULL },
115 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
116 NULL },
117 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin",
118 changepath },
119 /*
120 * vps1 depends on uid
121 */
122 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
123 NULL },
124#if ATTY
125 { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
126 NULL },
127#endif
128 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
129 getoptsreset },
130 { NULL, 0, NULL,
131 NULL }
132};
133
134struct var *vartab[VTABSIZE];
135
136STATIC struct var **hashvar __P((char *));
137STATIC int varequal __P((char *, char *));
138STATIC int localevar __P((char *));
139
140/*
141 * Initialize the varable symbol tables and import the environment
142 */
143
144#ifdef mkinit
145INCLUDE "var.h"
146INIT {
147 char **envp;
148 extern char **environ;
149
150 initvar();
151 for (envp = environ ; *envp ; envp++) {
152 if (strchr(*envp, '=')) {
153 setvareq(*envp, VEXPORT|VTEXTFIXED);
154 }
155 }
156}
157#endif
158
159
160/*
161 * This routine initializes the builtin variables. It is called when the
162 * shell is initialized and again when a shell procedure is spawned.
163 */
164
165void
166initvar() {
167 const struct varinit *ip;
168 struct var *vp;
169 struct var **vpp;
170
171 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
172 if ((vp->flags & VEXPORT) == 0) {
173 vpp = hashvar(ip->text);
174 vp->next = *vpp;
175 *vpp = vp;
176 vp->text = ip->text;
177 vp->flags = ip->flags;
178 vp->func = ip->func;
179 }
180 }
181 /*
182 * PS1 depends on uid
183 */
184 if ((vps1.flags & VEXPORT) == 0) {
185 vpp = hashvar("PS1=");
186 vps1.next = *vpp;
187 *vpp = &vps1;
188 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
189 vps1.flags = VSTRFIXED|VTEXTFIXED;
190 }
191}
192
193/*
194 * Safe version of setvar, returns 1 on success 0 on failure.
195 */
196
197int
198setvarsafe(name, val, flags)
199 char *name, *val;
200 int flags;
201{
202 struct jmploc jmploc;
203 struct jmploc *volatile savehandler = handler;
204 int err = 0;
205#if __GNUC__
206 /* Avoid longjmp clobbering */
207 (void) &err;
208#endif
209
210 if (setjmp(jmploc.loc))
211 err = 1;
212 else {
213 handler = &jmploc;
214 setvar(name, val, flags);
215 }
216 handler = savehandler;
217 return err;
218}
219
220/*
221 * Set the value of a variable. The flags argument is ored with the
222 * flags of the variable. If val is NULL, the variable is unset.
223 */
224
225void
226setvar(name, val, flags)
227 char *name, *val;
228 int flags;
229{
230 char *p, *q;
231 int len;
232 int namelen;
233 char *nameeq;
234 int isbad;
235
236 isbad = 0;
237 p = name;
238 if (! is_name(*p))
239 isbad = 1;
240 p++;
241 for (;;) {
242 if (! is_in_name(*p)) {
243 if (*p == '\0' || *p == '=')
244 break;
245 isbad = 1;
246 }
247 p++;
248 }
249 namelen = p - name;
250 if (isbad)
251 error("%.*s: bad variable name", namelen, name);
252 len = namelen + 2; /* 2 is space for '=' and '\0' */
253 if (val == NULL) {
254 flags |= VUNSET;
255 } else {
256 len += strlen(val);
257 }
258 p = nameeq = ckmalloc(len);
259 q = name;
260 while (--namelen >= 0)
261 *p++ = *q++;
262 *p++ = '=';
263 *p = '\0';
264 if (val)
265 scopy(val, p);
266 setvareq(nameeq, flags);
267}
268
269STATIC int
270localevar(s)
271 char *s;
272 {
273 static char *lnames[7] = {
274 "ALL", "COLLATE", "CTYPE", "MONETARY",
275 "NUMERIC", "TIME", NULL
276 };
277 char **ss;
278
279 if (*s != 'L')
280 return 0;
281 if (varequal(s + 1, "ANG"))
282 return 1;
283 if (strncmp(s + 1, "C_", 2) != 0)
284 return 0;
285 for (ss = lnames; *ss ; ss++)
286 if (varequal(s + 3, *ss))
287 return 1;
288 return 0;
289}
290
291/*
292 * Same as setvar except that the variable and value are passed in
293 * the first argument as name=value. Since the first argument will
294 * be actually stored in the table, it should not be a string that
295 * will go away.
296 */
297
298void
299setvareq(s, flags)
300 char *s;
301 int flags;
302{
303 struct var *vp, **vpp;
304
305 vpp = hashvar(s);
306 for (vp = *vpp ; vp ; vp = vp->next) {
307 if (varequal(s, vp->text)) {
308 if (vp->flags & VREADONLY) {
309 size_t len = strchr(s, '=') - s;
310 error("%.*s: is read only", len, s);
311 }
312 INTOFF;
313
314 if (vp->func && (flags & VNOFUNC) == 0)
315 (*vp->func)(strchr(s, '=') + 1);
316
317 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
318 ckfree(vp->text);
319
320 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
321 vp->flags |= flags;
322 vp->text = s;
323
324 /*
325 * We could roll this to a function, to handle it as
326 * a regular variable function callback, but why bother?
327 */
328 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
329 chkmail(1);
330 if ((vp->flags & VEXPORT) && localevar(s)) {
331 putenv(s);
332 (void) setlocale(LC_ALL, "");
333 }
334 INTON;
335 return;
336 }
337 }
338 /* not found */
339 vp = ckmalloc(sizeof (*vp));
340 vp->flags = flags;
341 vp->text = s;
342 vp->next = *vpp;
343 vp->func = NULL;
344 INTOFF;
345 *vpp = vp;
346 if ((vp->flags & VEXPORT) && localevar(s)) {
347 putenv(s);
348 (void) setlocale(LC_ALL, "");
349 }
350 INTON;
351}
352
353
354
355/*
356 * Process a linked list of variable assignments.
357 */
358
359void
360listsetvar(list)
361 struct strlist *list;
362 {
363 struct strlist *lp;
364
365 INTOFF;
366 for (lp = list ; lp ; lp = lp->next) {
367 setvareq(savestr(lp->text), 0);
368 }
369 INTON;
370}
371
372
373
374/*
375 * Find the value of a variable. Returns NULL if not set.
376 */
377
378char *
379lookupvar(name)
380 char *name;
381 {
382 struct var *v;
383
384 for (v = *hashvar(name) ; v ; v = v->next) {
385 if (varequal(v->text, name)) {
386 if (v->flags & VUNSET)
387 return NULL;
388 return strchr(v->text, '=') + 1;
389 }
390 }
391 return NULL;
392}
393
394
395
396/*
397 * Search the environment of a builtin command. If the second argument
398 * is nonzero, return the value of a variable even if it hasn't been
399 * exported.
400 */
401
402char *
403bltinlookup(name, doall)
404 char *name;
405 int doall;
406{
407 struct strlist *sp;
408 struct var *v;
409
410 for (sp = cmdenviron ; sp ; sp = sp->next) {
411 if (varequal(sp->text, name))
412 return strchr(sp->text, '=') + 1;
413 }
414 for (v = *hashvar(name) ; v ; v = v->next) {
415 if (varequal(v->text, name)) {
416 if ((v->flags & VUNSET)
417 || (!doall && (v->flags & VEXPORT) == 0))
418 return NULL;
419 return strchr(v->text, '=') + 1;
420 }
421 }
422 return NULL;
423}
424
425
426
427/*
428 * Generate a list of exported variables. This routine is used to construct
429 * the third argument to execve when executing a program.
430 */
431
432char **
433environment() {
434 int nenv;
435 struct var **vpp;
436 struct var *vp;
437 char **env, **ep;
438
439 nenv = 0;
440 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
441 for (vp = *vpp ; vp ; vp = vp->next)
442 if (vp->flags & VEXPORT)
443 nenv++;
444 }
445 ep = env = stalloc((nenv + 1) * sizeof *env);
446 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
447 for (vp = *vpp ; vp ; vp = vp->next)
448 if (vp->flags & VEXPORT)
449 *ep++ = vp->text;
450 }
451 *ep = NULL;
452 return env;
453}
454
455
456/*
457 * Called when a shell procedure is invoked to clear out nonexported
458 * variables. It is also necessary to reallocate variables of with
459 * VSTACK set since these are currently allocated on the stack.
460 */
461
462#ifdef mkinit
463MKINIT void shprocvar();
464
465SHELLPROC {
466 shprocvar();
467}
468#endif
469
470void
471shprocvar() {
472 struct var **vpp;
473 struct var *vp, **prev;
474
475 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
476 for (prev = vpp ; (vp = *prev) != NULL ; ) {
477 if ((vp->flags & VEXPORT) == 0) {
478 *prev = vp->next;
479 if ((vp->flags & VTEXTFIXED) == 0)
480 ckfree(vp->text);
481 if ((vp->flags & VSTRFIXED) == 0)
482 ckfree(vp);
483 } else {
484 if (vp->flags & VSTACK) {
485 vp->text = savestr(vp->text);
486 vp->flags &=~ VSTACK;
487 }
488 prev = &vp->next;
489 }
490 }
491 }
492 initvar();
493}
494
495
496
497/*
498 * Command to list all variables which are set. Currently this command
499 * is invoked from the set command when the set command is called without
500 * any variables.
501 */
502
503int
504showvarscmd(argc, argv)
505 int argc __unused;
506 char **argv __unused;
507{
508 struct var **vpp;
509 struct var *vp;
510
511 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
512 for (vp = *vpp ; vp ; vp = vp->next) {
513 if ((vp->flags & VUNSET) == 0)
514 out1fmt("%s\n", vp->text);
515 }
516 }
517 return 0;
518}
519
520
521
522/*
523 * The export and readonly commands.
524 */
525
526int
527exportcmd(argc, argv)
528 int argc;
529 char **argv;
530{
531 struct var **vpp;
532 struct var *vp;
533 char *name;
534 char *p;
535 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
536
537 listsetvar(cmdenviron);
538 if (argc > 1) {
539 while ((name = *argptr++) != NULL) {
540 if ((p = strchr(name, '=')) != NULL) {
541 p++;
542 } else {
543 vpp = hashvar(name);
544 for (vp = *vpp ; vp ; vp = vp->next) {
545 if (varequal(vp->text, name)) {
546 vp->flags |= flag;
547 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
548 putenv(vp->text);
549 (void) setlocale(LC_ALL, "");
550 }
551 goto found;
552 }
553 }
554 }
555 setvar(name, p, flag);
556found:;
557 }
558 } else {
559 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
560 for (vp = *vpp ; vp ; vp = vp->next) {
561 if (vp->flags & flag) {
562 for (p = vp->text ; *p != '=' ; p++)
563 out1c(*p);
564 out1c('\n');
565 }
566 }
567 }
568 }
569 return 0;
570}
571
572
573/*
574 * The "local" command.
575 */
576
577int
578localcmd(argc, argv)
579 int argc __unused;
580 char **argv __unused;
581{
582 char *name;
583
584 if (! in_function())
585 error("Not in a function");
586 while ((name = *argptr++) != NULL) {
587 mklocal(name);
588 }
589 return 0;
590}
591
592
593/*
594 * Make a variable a local variable. When a variable is made local, it's
595 * value and flags are saved in a localvar structure. The saved values
596 * will be restored when the shell function returns. We handle the name
597 * "-" as a special case.
598 */
599
600void
601mklocal(name)
602 char *name;
603 {
604 struct localvar *lvp;
605 struct var **vpp;
606 struct var *vp;
607
608 INTOFF;
609 lvp = ckmalloc(sizeof (struct localvar));
610 if (name[0] == '-' && name[1] == '\0') {
611 lvp->text = ckmalloc(sizeof optlist);
612 memcpy(lvp->text, optlist, sizeof optlist);
613 vp = NULL;
614 } else {
615 vpp = hashvar(name);
616 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
617 if (vp == NULL) {
618 if (strchr(name, '='))
619 setvareq(savestr(name), VSTRFIXED);
620 else
621 setvar(name, NULL, VSTRFIXED);
622 vp = *vpp; /* the new variable */
623 lvp->text = NULL;
624 lvp->flags = VUNSET;
625 } else {
626 lvp->text = vp->text;
627 lvp->flags = vp->flags;
628 vp->flags |= VSTRFIXED|VTEXTFIXED;
629 if (strchr(name, '='))
630 setvareq(savestr(name), 0);
631 }
632 }
633 lvp->vp = vp;
634 lvp->next = localvars;
635 localvars = lvp;
636 INTON;
637}
638
639
640/*
641 * Called after a function returns.
642 */
643
644void
645poplocalvars() {
646 struct localvar *lvp;
647 struct var *vp;
648
649 while ((lvp = localvars) != NULL) {
650 localvars = lvp->next;
651 vp = lvp->vp;
652 if (vp == NULL) { /* $- saved */
653 memcpy(optlist, lvp->text, sizeof optlist);
654 ckfree(lvp->text);
655 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
656 (void)unsetvar(vp->text);
657 } else {
658 if ((vp->flags & VTEXTFIXED) == 0)
659 ckfree(vp->text);
660 vp->flags = lvp->flags;
661 vp->text = lvp->text;
662 }
663 ckfree(lvp);
664 }
665}
666
667
668int
669setvarcmd(argc, argv)
670 int argc;
671 char **argv;
672{
673 if (argc <= 2)
674 return unsetcmd(argc, argv);
675 else if (argc == 3)
676 setvar(argv[1], argv[2], 0);
677 else
678 error("List assignment not implemented");
679 return 0;
680}
681
682
683/*
684 * The unset builtin command. We unset the function before we unset the
685 * variable to allow a function to be unset when there is a readonly variable
686 * with the same name.
687 */
688
689int
690unsetcmd(argc, argv)
691 int argc __unused;
692 char **argv __unused;
693{
694 char **ap;
695 int i;
696 int flg_func = 0;
697 int flg_var = 0;
698 int ret = 0;
699
700 while ((i = nextopt("vf")) != '\0') {
701 if (i == 'f')
702 flg_func = 1;
703 else
704 flg_var = 1;
705 }
706 if (flg_func == 0 && flg_var == 0)
707 flg_var = 1;
708
709 for (ap = argptr; *ap ; ap++) {
710 if (flg_func)
711 ret |= unsetfunc(*ap);
712 if (flg_var)
713 ret |= unsetvar(*ap);
714 }
715 return ret;
716}
717
718
719/*
720 * Unset the specified variable.
721 */
722
723int
724unsetvar(s)
725 char *s;
726 {
727 struct var **vpp;
728 struct var *vp;
729
730 vpp = hashvar(s);
731 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
732 if (varequal(vp->text, s)) {
733 if (vp->flags & VREADONLY)
734 return (1);
735 INTOFF;
736 if (*(strchr(vp->text, '=') + 1) != '\0')
737 setvar(s, nullstr, 0);
738 if ((vp->flags & VEXPORT) && localevar(vp->text)) {
739 unsetenv(s);
740 setlocale(LC_ALL, "");
741 }
742 vp->flags &= ~VEXPORT;
743 vp->flags |= VUNSET;
744 if ((vp->flags & VSTRFIXED) == 0) {
745 if ((vp->flags & VTEXTFIXED) == 0)
746 ckfree(vp->text);
747 *vpp = vp->next;
748 ckfree(vp);
749 }
750 INTON;
751 return (0);
752 }
753 }
754
755 return (1);
756}
757
758
759
760/*
761 * Find the appropriate entry in the hash table from the name.
762 */
763
764STATIC struct var **
765hashvar(p)
766 char *p;
767 {
768 unsigned int hashval;
769
770 hashval = ((unsigned char) *p) << 4;
771 while (*p && *p != '=')
772 hashval += (unsigned char) *p++;
773 return &vartab[hashval % VTABSIZE];
774}
775
776
777
778/*
779 * Returns true if the two strings specify the same varable. The first
780 * variable name is terminated by '='; the second may be terminated by
781 * either '=' or '\0'.
782 */
783
784STATIC int
785varequal(p, q)
786 char *p, *q;
787 {
788 while (*p == *q++) {
789 if (*p++ == '=')
790 return 1;
791 }
792 if (*p == '=' && *(q - 1) == '\0')
793 return 1;
794 return 0;
795}