source: trunk/minix/commands/ash/var.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

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