diff options
| author | Byron Rakitzis <byron@archone.tamu.edu> | 1992-05-27 00:00:01 +0100 |
|---|---|---|
| committer | Toby Goodwin <toby@paccrat.org> | 2015-05-16 21:22:56 +0100 |
| commit | 26bb34cf036027dfa22dfae8d8fc2f6bfd6acb75 (patch) | |
| tree | 589705b2492ce4681760846d9ca45600f0af298d /var.c | |
release: rc-1.4
Diffstat (limited to 'var.c')
| -rw-r--r-- | var.c | 226 |
1 files changed, 226 insertions, 0 deletions
@@ -0,0 +1,226 @@ +/* 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; +#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */ + if (interactive && (streq(name, "TERM") || streq(name, "TERMCAP"))) { + extern void rl_reset_terminal(char *); + 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); + 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, "status")) + return sgetstatus(); + if (streq(name, "apids")) + return sgetapids(); + 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(name, 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 = list2str(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 = enew(List); + while ((w = strchr(v, ':')) != NULL) { + *w = '\0'; + r->w = ecpy(v); + *w = ':'; + v = w + 1; + r->n = enew(List); + r = r->n; + } + r->w = ecpy(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, " "); +} |