BSD 4_4_Lite2 release
[unix-history] / usr / src / bin / sh / var.c
CommitLineData
8f1981e0 1/*-
d1b73048
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
8f1981e0
KB
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
ad787160
C
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.
8f1981e0
KB
35 */
36
37#ifndef lint
fd88f5c5 38static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
8f1981e0
KB
39#endif /* not lint */
40
13b3e634
CZ
41#include <unistd.h>
42#include <stdlib.h>
43
8f1981e0
KB
44/*
45 * Shell variables.
46 */
47
8f1981e0
KB
48#include "shell.h"
49#include "output.h"
50#include "expand.h"
51#include "nodes.h" /* for other headers */
52#include "eval.h" /* defines cmdenviron */
53#include "exec.h"
54#include "syntax.h"
55#include "options.h"
56#include "mail.h"
57#include "var.h"
58#include "memalloc.h"
59#include "error.h"
60#include "mystring.h"
13b3e634
CZ
61#ifndef NO_HISTORY
62#include "myhistedit.h"
63#endif
8f1981e0
KB
64
65
66#define VTABSIZE 39
67
68
69struct varinit {
70 struct var *var;
71 int flags;
72 char *text;
73};
74
75
76#if ATTY
77struct var vatty;
78#endif
13b3e634 79#ifndef NO_HISTORY
1da339d9 80struct var vhistsize;
13b3e634 81#endif
8f1981e0
KB
82struct var vifs;
83struct var vmail;
84struct var vmpath;
85struct var vpath;
86struct var vps1;
87struct var vps2;
88struct var vvers;
89#if ATTY
90struct var vterm;
91#endif
92
93const struct varinit varinit[] = {
94#if ATTY
95 {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="},
96#endif
13b3e634 97#ifndef NO_HISTORY
1da339d9 98 {&vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE="},
13b3e634 99#endif
8f1981e0
KB
100 {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"},
101 {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="},
102 {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="},
13b3e634 103 {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin"},
913003f6
MT
104 /*
105 * vps1 depends on uid
106 */
8f1981e0 107 {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "},
8f1981e0
KB
108#if ATTY
109 {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="},
110#endif
111 {NULL, 0, NULL}
112};
113
114struct var *vartab[VTABSIZE];
115
e6fa84d4 116STATIC int unsetvar __P((char *));
913003f6
MT
117STATIC struct var **hashvar __P((char *));
118STATIC int varequal __P((char *, char *));
8f1981e0
KB
119
120/*
121 * Initialize the varable symbol tables and import the environment
122 */
123
124#ifdef mkinit
125INCLUDE "var.h"
126INIT {
127 char **envp;
128 extern char **environ;
129
130 initvar();
131 for (envp = environ ; *envp ; envp++) {
132 if (strchr(*envp, '=')) {
133 setvareq(*envp, VEXPORT|VTEXTFIXED);
134 }
135 }
136}
137#endif
138
139
140/*
141 * This routine initializes the builtin variables. It is called when the
142 * shell is initialized and again when a shell procedure is spawned.
143 */
144
145void
146initvar() {
147 const struct varinit *ip;
148 struct var *vp;
149 struct var **vpp;
150
151 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
152 if ((vp->flags & VEXPORT) == 0) {
153 vpp = hashvar(ip->text);
154 vp->next = *vpp;
155 *vpp = vp;
156 vp->text = ip->text;
157 vp->flags = ip->flags;
158 }
159 }
913003f6
MT
160 /*
161 * PS1 depends on uid
162 */
163 if ((vps1.flags & VEXPORT) == 0) {
164 vpp = hashvar("PS1=");
165 vps1.next = *vpp;
166 *vpp = &vps1;
d08083e8 167 vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
913003f6
MT
168 vps1.flags = VSTRFIXED|VTEXTFIXED;
169 }
ddba57cd 170}
8f1981e0
KB
171
172/*
173 * Set the value of a variable. The flags argument is ored with the
174 * flags of the variable. If val is NULL, the variable is unset.
175 */
176
177void
178setvar(name, val, flags)
179 char *name, *val;
13b3e634
CZ
180 int flags;
181{
8f1981e0
KB
182 char *p, *q;
183 int len;
184 int namelen;
185 char *nameeq;
186 int isbad;
187
188 isbad = 0;
189 p = name;
190 if (! is_name(*p++))
191 isbad = 1;
192 for (;;) {
193 if (! is_in_name(*p)) {
194 if (*p == '\0' || *p == '=')
195 break;
196 isbad = 1;
197 }
198 p++;
199 }
200 namelen = p - name;
201 if (isbad)
c671e886 202 error("%.*s: bad variable name", namelen, name);
8f1981e0
KB
203 len = namelen + 2; /* 2 is space for '=' and '\0' */
204 if (val == NULL) {
205 flags |= VUNSET;
206 } else {
207 len += strlen(val);
208 }
209 p = nameeq = ckmalloc(len);
210 q = name;
211 while (--namelen >= 0)
212 *p++ = *q++;
213 *p++ = '=';
214 *p = '\0';
215 if (val)
216 scopy(val, p);
217 setvareq(nameeq, flags);
218}
219
220
221
222/*
223 * Same as setvar except that the variable and value are passed in
224 * the first argument as name=value. Since the first argument will
225 * be actually stored in the table, it should not be a string that
226 * will go away.
227 */
228
229void
230setvareq(s, flags)
231 char *s;
13b3e634
CZ
232 int flags;
233{
8f1981e0
KB
234 struct var *vp, **vpp;
235
236 vpp = hashvar(s);
237 for (vp = *vpp ; vp ; vp = vp->next) {
238 if (varequal(s, vp->text)) {
239 if (vp->flags & VREADONLY) {
240 int len = strchr(s, '=') - s;
241 error("%.*s: is read only", len, s);
242 }
243 INTOFF;
244 if (vp == &vpath)
245 changepath(s + 5); /* 5 = strlen("PATH=") */
246 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
247 ckfree(vp->text);
248 vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
249 vp->flags |= flags;
250 vp->text = s;
251 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
252 chkmail(1);
13b3e634 253#ifndef NO_HISTORY
1da339d9
MT
254 if (vp == &vhistsize)
255 sethistsize();
13b3e634 256#endif
8f1981e0
KB
257 INTON;
258 return;
259 }
260 }
261 /* not found */
262 vp = ckmalloc(sizeof (*vp));
263 vp->flags = flags;
264 vp->text = s;
265 vp->next = *vpp;
266 *vpp = vp;
267}
268
269
270
271/*
272 * Process a linked list of variable assignments.
273 */
274
275void
276listsetvar(list)
277 struct strlist *list;
278 {
279 struct strlist *lp;
280
281 INTOFF;
282 for (lp = list ; lp ; lp = lp->next) {
283 setvareq(savestr(lp->text), 0);
284 }
285 INTON;
286}
287
288
289
290/*
291 * Find the value of a variable. Returns NULL if not set.
292 */
293
294char *
295lookupvar(name)
296 char *name;
297 {
298 struct var *v;
299
300 for (v = *hashvar(name) ; v ; v = v->next) {
301 if (varequal(v->text, name)) {
302 if (v->flags & VUNSET)
303 return NULL;
304 return strchr(v->text, '=') + 1;
305 }
306 }
307 return NULL;
308}
309
310
311
312/*
313 * Search the environment of a builtin command. If the second argument
314 * is nonzero, return the value of a variable even if it hasn't been
315 * exported.
316 */
317
318char *
319bltinlookup(name, doall)
320 char *name;
13b3e634
CZ
321 int doall;
322{
8f1981e0
KB
323 struct strlist *sp;
324 struct var *v;
325
326 for (sp = cmdenviron ; sp ; sp = sp->next) {
327 if (varequal(sp->text, name))
328 return strchr(sp->text, '=') + 1;
329 }
330 for (v = *hashvar(name) ; v ; v = v->next) {
331 if (varequal(v->text, name)) {
13b3e634
CZ
332 if ((v->flags & VUNSET)
333 || (!doall && (v->flags & VEXPORT) == 0))
8f1981e0
KB
334 return NULL;
335 return strchr(v->text, '=') + 1;
336 }
337 }
338 return NULL;
339}
340
341
342
343/*
344 * Generate a list of exported variables. This routine is used to construct
345 * the third argument to execve when executing a program.
346 */
347
348char **
349environment() {
350 int nenv;
351 struct var **vpp;
352 struct var *vp;
353 char **env, **ep;
354
355 nenv = 0;
356 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
357 for (vp = *vpp ; vp ; vp = vp->next)
358 if (vp->flags & VEXPORT)
359 nenv++;
360 }
361 ep = env = stalloc((nenv + 1) * sizeof *env);
362 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
363 for (vp = *vpp ; vp ; vp = vp->next)
364 if (vp->flags & VEXPORT)
365 *ep++ = vp->text;
366 }
367 *ep = NULL;
368 return env;
369}
370
371
372/*
373 * Called when a shell procedure is invoked to clear out nonexported
374 * variables. It is also necessary to reallocate variables of with
375 * VSTACK set since these are currently allocated on the stack.
376 */
377
378#ifdef mkinit
379MKINIT void shprocvar();
380
381SHELLPROC {
382 shprocvar();
383}
384#endif
385
386void
387shprocvar() {
388 struct var **vpp;
389 struct var *vp, **prev;
390
391 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
392 for (prev = vpp ; (vp = *prev) != NULL ; ) {
393 if ((vp->flags & VEXPORT) == 0) {
394 *prev = vp->next;
395 if ((vp->flags & VTEXTFIXED) == 0)
396 ckfree(vp->text);
397 if ((vp->flags & VSTRFIXED) == 0)
398 ckfree(vp);
399 } else {
400 if (vp->flags & VSTACK) {
401 vp->text = savestr(vp->text);
402 vp->flags &=~ VSTACK;
403 }
404 prev = &vp->next;
405 }
406 }
407 }
408 initvar();
409}
410
411
412
413/*
414 * Command to list all variables which are set. Currently this command
415 * is invoked from the set command when the set command is called without
416 * any variables.
417 */
418
419int
13b3e634
CZ
420showvarscmd(argc, argv)
421 int argc;
422 char **argv;
423{
8f1981e0
KB
424 struct var **vpp;
425 struct var *vp;
426
427 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
428 for (vp = *vpp ; vp ; vp = vp->next) {
429 if ((vp->flags & VUNSET) == 0)
430 out1fmt("%s\n", vp->text);
431 }
432 }
433 return 0;
434}
435
436
437
438/*
439 * The export and readonly commands.
440 */
441
442int
13b3e634
CZ
443exportcmd(argc, argv)
444 int argc;
445 char **argv;
446{
8f1981e0
KB
447 struct var **vpp;
448 struct var *vp;
449 char *name;
450 char *p;
451 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
452
453 listsetvar(cmdenviron);
454 if (argc > 1) {
455 while ((name = *argptr++) != NULL) {
456 if ((p = strchr(name, '=')) != NULL) {
457 p++;
458 } else {
459 vpp = hashvar(name);
460 for (vp = *vpp ; vp ; vp = vp->next) {
461 if (varequal(vp->text, name)) {
462 vp->flags |= flag;
463 goto found;
464 }
465 }
466 }
467 setvar(name, p, flag);
468found:;
469 }
470 } else {
471 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
472 for (vp = *vpp ; vp ; vp = vp->next) {
473 if (vp->flags & flag) {
474 for (p = vp->text ; *p != '=' ; p++)
475 out1c(*p);
476 out1c('\n');
477 }
478 }
479 }
480 }
481 return 0;
482}
483
484
485/*
486 * The "local" command.
487 */
488
13b3e634
CZ
489int
490localcmd(argc, argv)
491 int argc;
492 char **argv;
493{
8f1981e0
KB
494 char *name;
495
496 if (! in_function())
497 error("Not in a function");
498 while ((name = *argptr++) != NULL) {
499 mklocal(name);
500 }
501 return 0;
502}
503
504
505/*
506 * Make a variable a local variable. When a variable is made local, it's
507 * value and flags are saved in a localvar structure. The saved values
508 * will be restored when the shell function returns. We handle the name
509 * "-" as a special case.
510 */
511
512void
513mklocal(name)
514 char *name;
515 {
516 struct localvar *lvp;
517 struct var **vpp;
518 struct var *vp;
519
520 INTOFF;
521 lvp = ckmalloc(sizeof (struct localvar));
522 if (name[0] == '-' && name[1] == '\0') {
1da339d9 523 lvp->text = ckmalloc(sizeof optlist);
13b3e634 524 memcpy(lvp->text, optlist, sizeof optlist);
8f1981e0
KB
525 vp = NULL;
526 } else {
527 vpp = hashvar(name);
528 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
529 if (vp == NULL) {
530 if (strchr(name, '='))
531 setvareq(savestr(name), VSTRFIXED);
532 else
533 setvar(name, NULL, VSTRFIXED);
534 vp = *vpp; /* the new variable */
535 lvp->text = NULL;
536 lvp->flags = VUNSET;
537 } else {
538 lvp->text = vp->text;
539 lvp->flags = vp->flags;
540 vp->flags |= VSTRFIXED|VTEXTFIXED;
541 if (strchr(name, '='))
542 setvareq(savestr(name), 0);
543 }
544 }
545 lvp->vp = vp;
546 lvp->next = localvars;
547 localvars = lvp;
548 INTON;
549}
550
551
552/*
553 * Called after a function returns.
554 */
555
556void
557poplocalvars() {
558 struct localvar *lvp;
559 struct var *vp;
560
561 while ((lvp = localvars) != NULL) {
562 localvars = lvp->next;
563 vp = lvp->vp;
564 if (vp == NULL) { /* $- saved */
13b3e634 565 memcpy(optlist, lvp->text, sizeof optlist);
8f1981e0
KB
566 ckfree(lvp->text);
567 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
e6fa84d4 568 (void)unsetvar(vp->text);
8f1981e0
KB
569 } else {
570 if ((vp->flags & VTEXTFIXED) == 0)
571 ckfree(vp->text);
572 vp->flags = lvp->flags;
573 vp->text = lvp->text;
574 }
575 ckfree(lvp);
576 }
577}
578
579
13b3e634
CZ
580int
581setvarcmd(argc, argv)
582 int argc;
583 char **argv;
584{
8f1981e0
KB
585 if (argc <= 2)
586 return unsetcmd(argc, argv);
587 else if (argc == 3)
588 setvar(argv[1], argv[2], 0);
589 else
590 error("List assignment not implemented");
591 return 0;
592}
593
594
595/*
596 * The unset builtin command. We unset the function before we unset the
597 * variable to allow a function to be unset when there is a readonly variable
598 * with the same name.
599 */
600
13b3e634
CZ
601int
602unsetcmd(argc, argv)
603 int argc;
604 char **argv;
605{
8f1981e0 606 char **ap;
e6fa84d4
MT
607 int i;
608 int flg_func = 0;
609 int flg_var = 0;
610 int ret = 0;
611
612 while ((i = nextopt("vf")) != '\0') {
613 if (i == 'f')
614 flg_func = 1;
615 else
616 flg_var = 1;
8f1981e0 617 }
e6fa84d4
MT
618 if (flg_func == 0 && flg_var == 0)
619 flg_var = 1;
620
621 for (ap = argptr; *ap ; ap++) {
622 if (flg_func)
623 ret |= unsetfunc(*ap);
624 if (flg_var)
625 ret |= unsetvar(*ap);
626 }
627 return ret;
8f1981e0
KB
628}
629
630
631/*
632 * Unset the specified variable.
633 */
634
e6fa84d4 635STATIC int
8f1981e0
KB
636unsetvar(s)
637 char *s;
638 {
639 struct var **vpp;
640 struct var *vp;
641
642 vpp = hashvar(s);
643 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
644 if (varequal(vp->text, s)) {
e6fa84d4
MT
645 if (vp->flags & VREADONLY)
646 return (1);
8f1981e0 647 INTOFF;
e6fa84d4 648 if (*(strchr(vp->text, '=') + 1) != '\0')
8f1981e0 649 setvar(s, nullstr, 0);
8f1981e0
KB
650 vp->flags &=~ VEXPORT;
651 vp->flags |= VUNSET;
652 if ((vp->flags & VSTRFIXED) == 0) {
653 if ((vp->flags & VTEXTFIXED) == 0)
654 ckfree(vp->text);
655 *vpp = vp->next;
656 ckfree(vp);
657 }
658 INTON;
e6fa84d4 659 return (0);
8f1981e0
KB
660 }
661 }
e6fa84d4
MT
662
663 return (1);
8f1981e0
KB
664}
665
666
667
668/*
669 * Find the appropriate entry in the hash table from the name.
670 */
671
672STATIC struct var **
673hashvar(p)
674 register char *p;
675 {
676 unsigned int hashval;
677
678 hashval = *p << 4;
679 while (*p && *p != '=')
680 hashval += *p++;
681 return &vartab[hashval % VTABSIZE];
682}
683
684
685
686/*
687 * Returns true if the two strings specify the same varable. The first
688 * variable name is terminated by '='; the second may be terminated by
689 * either '=' or '\0'.
690 */
691
692STATIC int
693varequal(p, q)
694 register char *p, *q;
695 {
696 while (*p == *q++) {
697 if (*p++ == '=')
698 return 1;
699 }
700 if (*p == '=' && *(q - 1) == '\0')
701 return 1;
702 return 0;
703}