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