rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

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 }