* Copyright (c) 1991 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)var.c 5.3 (Berkeley) %G%";
#include "nodes.h" /* for other headers */
#include "eval.h" /* defines cmdenviron */
const struct varinit varinit
[] = {
{&vatty
, VSTRFIXED
|VTEXTFIXED
|VUNSET
, "ATTY="},
{&vifs
, VSTRFIXED
|VTEXTFIXED
, "IFS= \t\n"},
{&vmail
, VSTRFIXED
|VTEXTFIXED
|VUNSET
, "MAIL="},
{&vmpath
, VSTRFIXED
|VTEXTFIXED
|VUNSET
, "MAILPATH="},
{&vpath
, VSTRFIXED
|VTEXTFIXED
, "PATH=:/bin:/usr/bin"},
{&vps2
, VSTRFIXED
|VTEXTFIXED
, "PS2=> "},
{&vterm
, VSTRFIXED
|VTEXTFIXED
|VUNSET
, "TERM="},
struct var
*vartab
[VTABSIZE
];
STATIC
void unsetvar
__P((char *));
STATIC
struct var
**hashvar
__P((char *));
STATIC
int varequal
__P((char *, char *));
* Initialize the varable symbol tables and import the environment
for (envp
= environ
; *envp
; envp
++) {
if (strchr(*envp
, '=')) {
setvareq(*envp
, VEXPORT
|VTEXTFIXED
);
* This routine initializes the builtin variables. It is called when the
* shell is initialized and again when a shell procedure is spawned.
const struct varinit
*ip
;
for (ip
= varinit
; (vp
= ip
->var
) != NULL
; ip
++) {
if ((vp
->flags
& VEXPORT
) == 0) {
if ((vps1
.flags
& VEXPORT
) == 0) {
vps1
.text
= getuid() ? "PS1=$ " : "PS1=# ";
vps1
.flags
= VSTRFIXED
|VTEXTFIXED
;
* Set the value of a variable. The flags argument is ored with the
* flags of the variable. If val is NULL, the variable is unset.
if (*p
== '\0' || *p
== '=')
error("%.*s: is read only", namelen
, name
);
len
= namelen
+ 2; /* 2 is space for '=' and '\0' */
p
= nameeq
= ckmalloc(len
);
* Same as setvar except that the variable and value are passed in
* the first argument as name=value. Since the first argument will
* be actually stored in the table, it should not be a string that
for (vp
= *vpp
; vp
; vp
= vp
->next
) {
if (varequal(s
, vp
->text
)) {
if (vp
->flags
& VREADONLY
) {
int len
= strchr(s
, '=') - s
;
error("%.*s: is read only", len
, s
);
changepath(s
+ 5); /* 5 = strlen("PATH=") */
if ((vp
->flags
& (VTEXTFIXED
|VSTACK
)) == 0)
vp
->flags
&=~ (VTEXTFIXED
|VSTACK
|VUNSET
);
if (vp
== &vmpath
|| (vp
== &vmail
&& ! mpathset()))
vp
= ckmalloc(sizeof (*vp
));
* Process a linked list of variable assignments.
for (lp
= list
; lp
; lp
= lp
->next
) {
setvareq(savestr(lp
->text
), 0);
* Find the value of a variable. Returns NULL if not set.
for (v
= *hashvar(name
) ; v
; v
= v
->next
) {
if (varequal(v
->text
, name
)) {
return strchr(v
->text
, '=') + 1;
* Search the environment of a builtin command. If the second argument
* is nonzero, return the value of a variable even if it hasn't been
for (sp
= cmdenviron
; sp
; sp
= sp
->next
) {
if (varequal(sp
->text
, name
))
return strchr(sp
->text
, '=') + 1;
for (v
= *hashvar(name
) ; v
; v
= v
->next
) {
if (varequal(v
->text
, name
)) {
|| ! doall
&& (v
->flags
& VEXPORT
) == 0)
return strchr(v
->text
, '=') + 1;
* Generate a list of exported variables. This routine is used to construct
* the third argument to execve when executing a program.
for (vpp
= vartab
; vpp
< vartab
+ VTABSIZE
; vpp
++) {
for (vp
= *vpp
; vp
; vp
= vp
->next
)
ep
= env
= stalloc((nenv
+ 1) * sizeof *env
);
for (vpp
= vartab
; vpp
< vartab
+ VTABSIZE
; vpp
++) {
for (vp
= *vpp
; vp
; vp
= vp
->next
)
* Called when a shell procedure is invoked to clear out nonexported
* variables. It is also necessary to reallocate variables of with
* VSTACK set since these are currently allocated on the stack.
for (vpp
= vartab
; vpp
< vartab
+ VTABSIZE
; vpp
++) {
for (prev
= vpp
; (vp
= *prev
) != NULL
; ) {
if ((vp
->flags
& VEXPORT
) == 0) {
if ((vp
->flags
& VTEXTFIXED
) == 0)
if ((vp
->flags
& VSTRFIXED
) == 0)
if (vp
->flags
& VSTACK
) {
vp
->text
= savestr(vp
->text
);
* Command to list all variables which are set. Currently this command
* is invoked from the set command when the set command is called without
showvarscmd(argc
, argv
) char **argv
; {
for (vpp
= vartab
; vpp
< vartab
+ VTABSIZE
; vpp
++) {
for (vp
= *vpp
; vp
; vp
= vp
->next
) {
if ((vp
->flags
& VUNSET
) == 0)
out1fmt("%s\n", vp
->text
);
* The export and readonly commands.
exportcmd(argc
, argv
) char **argv
; {
int flag
= argv
[0][0] == 'r'? VREADONLY
: VEXPORT
;
while ((name
= *argptr
++) != NULL
) {
if ((p
= strchr(name
, '=')) != NULL
) {
for (vp
= *vpp
; vp
; vp
= vp
->next
) {
if (varequal(vp
->text
, name
)) {
for (vpp
= vartab
; vpp
< vartab
+ VTABSIZE
; vpp
++) {
for (vp
= *vpp
; vp
; vp
= vp
->next
) {
for (p
= vp
->text
; *p
!= '=' ; p
++)
localcmd(argc
, argv
) char **argv
; {
error("Not in a function");
while ((name
= *argptr
++) != NULL
) {
* Make a variable a local variable. When a variable is made local, it's
* value and flags are saved in a localvar structure. The saved values
* will be restored when the shell function returns. We handle the name
lvp
= ckmalloc(sizeof (struct localvar
));
if (name
[0] == '-' && name
[1] == '\0') {
lvp
->text
= ckmalloc(sizeof optval
);
bcopy(optval
, lvp
->text
, sizeof optval
);
for (vp
= *vpp
; vp
&& ! varequal(vp
->text
, name
) ; vp
= vp
->next
);
setvareq(savestr(name
), VSTRFIXED
);
setvar(name
, NULL
, VSTRFIXED
);
vp
= *vpp
; /* the new variable */
vp
->flags
|= VSTRFIXED
|VTEXTFIXED
;
setvareq(savestr(name
), 0);
* Called after a function returns.
while ((lvp
= localvars
) != NULL
) {
if (vp
== NULL
) { /* $- saved */
bcopy(lvp
->text
, optval
, sizeof optval
);
} else if ((lvp
->flags
& (VUNSET
|VSTRFIXED
)) == VUNSET
) {
if ((vp
->flags
& VTEXTFIXED
) == 0)
setvarcmd(argc
, argv
) char **argv
; {
return unsetcmd(argc
, argv
);
setvar(argv
[1], argv
[2], 0);
error("List assignment not implemented");
* The unset builtin command. We unset the function before we unset the
* variable to allow a function to be unset when there is a readonly variable
unsetcmd(argc
, argv
) char **argv
; {
for (ap
= argv
+ 1 ; *ap
; ap
++) {
* Unset the specified variable.
for (vp
= *vpp
; vp
; vpp
= &vp
->next
, vp
= *vpp
) {
if (varequal(vp
->text
, s
)) {
if (*(strchr(vp
->text
, '=') + 1) != '\0'
|| vp
->flags
& VREADONLY
) {
if ((vp
->flags
& VSTRFIXED
) == 0) {
if ((vp
->flags
& VTEXTFIXED
) == 0)
* Find the appropriate entry in the hash table from the name.
return &vartab
[hashval
% VTABSIZE
];
* Returns true if the two strings specify the same varable. The first
* variable name is terminated by '='; the second may be terminated by
if (*p
== '=' && *(q
- 1) == '\0')