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