1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/* var.c: provide "public" functions for adding and removing variables from the symbol table */
#include "rc.h"
static void colonassign(char *, List *, bool);
static void listassign(char *, List *, bool);
static int hasalias(char *);
static char *const aliases[] = {
"home", "HOME", "path", "PATH", "cdpath", "CDPATH"
};
/* assign a variable in List form to a name, stacking if appropriate */
extern void varassign(char *name, List *def, bool stack) {
Variable *new;
List *newdef = listcpy(def, ealloc); /* important to do the listcpy first; get_var_place() frees old values */
new = get_var_place(name, stack);
new->def = newdef;
new->extdef = NULL;
set_exportable(name, TRUE);
#if READLINE
if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP")))
rl_reset_terminal(NULL);
#endif
}
/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
extern bool varassign_string(char *extdef) {
static bool aliasset[arraysize(aliases)] = {
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
};
char *name = get_name(extdef);
Variable *new;
int i;
if (name == NULL)
return FALSE; /* add it to bozo env */
if ((i = hasalias(name)) != -1) {
aliasset[i] = TRUE;
i ^= 1; /* set i to the "opposite" case subscript and */
if (i&1 && aliasset[i]) /* don't alias variables that are already set in upper case */
return TRUE;
}
new = get_var_place(name, FALSE);
new->def = NULL;
new->extdef = ealloc(strlen(extdef) + 1);
strcpy(new->extdef, extdef);
if (i != -1)
alias(name, varlookup(name), FALSE);
set_exportable(name, TRUE);
return TRUE;
}
/*
Return a List based on a name lookup. If the list is in external (string) form,
convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n).
Also check to see if $status is being dereferenced. (we lazily evaluate the List
associated with $status)
*/
extern List *varlookup(char *name) {
Variable *look;
List *ret, *l;
int sub;
if (streq(name, "apids"))
return sgetapids();
if (streq(name, "status"))
return sgetstatus();
if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
for (l = varlookup("*"); l != NULL && sub != 0; --sub)
l = l->n;
if (l == NULL)
return NULL;
ret = nnew(List);
ret->w = l->w;
ret->m = NULL;
ret->n = NULL;
return ret;
}
look = lookup_var(name);
if (look == NULL)
return NULL; /* not found */
if (look->def != NULL)
return look->def;
if (look->extdef == NULL)
return NULL; /* variable was set to null, e.g., a=() echo foo */
ret = parse_var(look->extdef);
if (ret == NULL) {
look->extdef = NULL;
return NULL;
}
return look->def = ret;
}
/* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
extern char *varlookup_string(char *name) {
Variable *look;
look = lookup_var(name);
if (look == NULL)
return NULL;
if (look->extdef != NULL)
return look->extdef;
if (look->def == NULL)
return NULL;
return look->extdef = mprint("%F=%W", name, look->def);
}
/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
extern void varrm(char *name, bool stack) {
int i = hasalias(name);
if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
varassign("*", varlookup("0"), FALSE);
return;
}
delete_var(name, stack);
if (i != -1)
delete_var(aliases[i^1], stack);
}
/* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
extern void starassign(char *dollarzero, char **a, bool stack) {
List *s, *var;
var = nnew(List);
var->w = dollarzero;
if (*a == NULL) {
var->n = NULL;
varassign("*", var, stack);
return;
}
var->n = s = nnew(List);
while (1) {
s->w = *a++;
if (*a == NULL) {
s->n = NULL;
break;
} else
s = s->n = nnew(List);
}
varassign("*", var, stack);
}
/* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
static void colonassign(char *name, List *def, bool stack) {
List dud;
if (def == NULL) {
varassign(name, NULL, stack);
return;
}
dud.w = nprint("%-L", def, ":");
dud.n = NULL;
varassign(name, &dud, stack);
}
/* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
static void listassign(char *name, List *def, bool stack) {
List *val, *r;
char *v, *w;
if (def == NULL) {
varassign(name, NULL, stack);
return;
}
v = def->w;
r = val = nnew(List);
while ((w = strchr(v, ':')) != NULL) {
*w = '\0';
r->w = ncpy(v);
*w = ':';
v = w + 1;
r = r->n = nnew(List);
}
r->w = ncpy(v);
r->n = NULL;
varassign(name, val, stack);
}
/* check to see if a particular variable is aliased; return -1 on failure, or the index */
static int hasalias(char *name) {
int i;
for (i = 0; i < arraysize(aliases); i++)
if (streq(name, aliases[i]))
return i;
return -1;
}
/* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
extern void alias(char *name, List *s, bool stack) {
static void (*vectors[])(char *, List *, bool) = {
varassign, varassign, colonassign, listassign, colonassign, listassign
};
int i = hasalias(name);
if (i != -1)
(*vectors[i])(aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
}
extern void prettyprint_var(int fd, char *name, List *s) {
int i;
static const char * const keywords[] = {
"if", "in", "fn", "for", "else", "switch", "while", "case"
};
if (s == NULL) {
fprint(fd, "%S=()\n", name);
return;
}
if (streq(name, "*")) {
s = s->n;
if (s == NULL)
return; /* Don't print $0, and if $* is not set, skip it */
}
for (i = 0; i < arraysize(keywords); i++)
if (streq(keywords[i], name)) {
fprint(fd, "%#S=", name);
goto value;
}
fprint(fd, "%S=", name);
value:
fprint(fd, s->n == NULL ? "%L\n" : "(%L)\n", s, " ");
}
|