hush: consolidated variable expansion for assignments and "normal" one.

-435 bytes. Tested against testsuite.
This commit is contained in:
Denis Vlasenko
2007-05-17 14:38:17 +00:00
parent 96f67dc69d
commit b6a741ffa7

View File

@@ -444,8 +444,9 @@ static void delete_finished_bg_job(struct pipe *pi);
int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
#endif #endif
/* local variable support */ /* local variable support */
static char **do_variable_expansion(char **argv); static char **expand_variables_to_list(char **argv);
static char *insert_var_value(char *inp); /* used for expansion of right hand of assignments */
static char *expand_variables_to_string(const char *str);
static const char *get_local_var(const char *var); static const char *get_local_var(const char *var);
static int set_local_var(const char *s, int flg_export); static int set_local_var(const char *s, int flg_export);
static void unset_local_var(const char *name); static void unset_local_var(const char *name);
@@ -1271,7 +1272,7 @@ static void pseudo_exec_argv(char **argv)
debug_printf_exec("pid %d environment modification: %s\n", debug_printf_exec("pid %d environment modification: %s\n",
getpid(), argv[i]); getpid(), argv[i]);
// FIXME: vfork case?? // FIXME: vfork case??
p = insert_var_value(argv[i]); p = expand_variables_to_string(argv[i]);
putenv(p == argv[i] ? xstrdup(p) : p); putenv(p == argv[i] ? xstrdup(p) : p);
} }
argv += i; argv += i;
@@ -1282,7 +1283,7 @@ static void pseudo_exec_argv(char **argv)
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
argv = do_variable_expansion(argv); argv = expand_variables_to_list(argv);
/* /*
* Check if the command matches any of the builtins. * Check if the command matches any of the builtins.
@@ -1667,7 +1668,7 @@ static int run_pipe_real(struct pipe *pi)
export_me = 1; export_me = 1;
} }
free(name); free(name);
p = insert_var_value(argv[i]); p = expand_variables_to_string(argv[i]);
set_local_var(p, export_me); set_local_var(p, export_me);
if (p != argv[i]) if (p != argv[i])
free(p); free(p);
@@ -1675,7 +1676,7 @@ static int run_pipe_real(struct pipe *pi)
return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
} }
for (i = 0; is_assignment(argv[i]); i++) { for (i = 0; is_assignment(argv[i]); i++) {
p = insert_var_value(argv[i]); p = expand_variables_to_string(argv[i]);
if (p != argv[i]) { if (p != argv[i]) {
//sp: child->sp--; //sp: child->sp--;
putenv(p); putenv(p);
@@ -1698,7 +1699,7 @@ static int run_pipe_real(struct pipe *pi)
setup_redirects(child, squirrel); setup_redirects(child, squirrel);
debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
//sp: if (child->sp) /* btw we can do it unconditionally... */ //sp: if (child->sp) /* btw we can do it unconditionally... */
argv_expanded = do_variable_expansion(argv + i); argv_expanded = expand_variables_to_list(argv + i);
rcode = x->function(argv_expanded); rcode = x->function(argv_expanded);
free(argv_expanded); free(argv_expanded);
restore_redirects(squirrel); restore_redirects(squirrel);
@@ -1714,7 +1715,7 @@ static int run_pipe_real(struct pipe *pi)
save_nofork_data(&nofork_save); save_nofork_data(&nofork_save);
argv_expanded = argv + i; argv_expanded = argv + i;
//sp: if (child->sp) //sp: if (child->sp)
argv_expanded = do_variable_expansion(argv + i); argv_expanded = expand_variables_to_list(argv + i);
debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
free(argv_expanded); free(argv_expanded);
@@ -1991,7 +1992,7 @@ static int run_list_real(struct pipe *pi)
if (!pi->next->progs->argv) if (!pi->next->progs->argv)
continue; continue;
/* create list of variable values */ /* create list of variable values */
for_list = do_variable_expansion(pi->next->progs->argv); for_list = expand_variables_to_list(pi->next->progs->argv);
for_lcur = for_list; for_lcur = for_list;
for_varname = pi->progs->argv[0]; for_varname = pi->progs->argv[0];
pi->progs->argv[0] = NULL; pi->progs->argv[0] = NULL;
@@ -2251,8 +2252,7 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
return gr; return gr;
} }
/* expand_variables_to_list() takes a list of strings, expands
/* do_variable_expansion() takes a list of strings, expands
* all variable references within and returns a pointer to * all variable references within and returns a pointer to
* a list of expanded strings, possibly with larger number * a list of expanded strings, possibly with larger number
* of strings. (Think VAR="a b"; echo $VAR). * of strings. (Think VAR="a b"; echo $VAR).
@@ -2371,8 +2371,11 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str)
* 'echo -$*-'. If you play here, you must run testsuite afterwards! */ * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
/* NB: another bug is that we cannot detect empty strings yet: /* NB: another bug is that we cannot detect empty strings yet:
* "" or $empty"" expands to zero words, has to expand to empty word */ * "" or $empty"" expands to zero words, has to expand to empty word */
static int expand_vars_to_list(char **list, int n, char **posp, char *arg) static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask)
{ {
/* or_mask is either 0 (normal case) or 0x80
* (expansion of right-hand side of assignment == 1-element expand) */
char first_ch, ored_ch; char first_ch, ored_ch;
int i; int i;
const char *val; const char *val;
@@ -2392,7 +2395,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
arg = ++p; arg = ++p;
p = strchr(p, SPECIAL_VAR_SYMBOL); p = strchr(p, SPECIAL_VAR_SYMBOL);
first_ch = arg[0]; first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
ored_ch |= first_ch; ored_ch |= first_ch;
val = NULL; val = NULL;
switch (first_ch & 0x7f) { switch (first_ch & 0x7f) {
@@ -2427,7 +2430,10 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
list[n++] = pos; list[n++] = pos;
} }
} }
} else if (first_ch == ('@'|0x80)) { /* quoted $@ */ } else
/* If or_mask is nonzero, we handle assignment 'a=....$@.....'
* and in this case should theat it like '$*' */
if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
while (1) { while (1) {
strcpy(pos, global_argv[i]); strcpy(pos, global_argv[i]);
pos += strlen(global_argv[i]); pos += strlen(global_argv[i]);
@@ -2490,7 +2496,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
return n; return n;
} }
static char **do_variable_expansion(char **argv) static char **expand_variables(char **argv, char or_mask)
{ {
int n; int n;
int count = 1; int count = 1;
@@ -2515,9 +2521,9 @@ static char **do_variable_expansion(char **argv)
n = 0; n = 0;
v = argv; v = argv;
while (*v) while (*v)
n = expand_vars_to_list(list, n, &pos, *v++); n = expand_vars_to_list(list, n, &pos, *v++, or_mask);
if(n) debug_printf_expand("finalized list[%d]=%p '%s' " if (n) debug_printf_expand("finalized list[%d]=%p '%s' "
"strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
list[n] = NULL; list[n] = NULL;
@@ -2538,79 +2544,25 @@ static char **do_variable_expansion(char **argv)
return list; return list;
} }
static char **expand_variables_to_list(char **argv)
static char *insert_var_value(char *inp)
{ {
int res_str_len = 0; return expand_variables(argv, 0);
int len;
int done = 0;
int i;
const char *p1;
char *p, *p2;
char *res_str = NULL;
while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
if (p != inp) {
len = p - inp;
res_str = xrealloc(res_str, (res_str_len + len));
strncpy((res_str + res_str_len), inp, len);
res_str_len += len;
}
inp = ++p;
p = strchr(inp, SPECIAL_VAR_SYMBOL);
*p = '\0';
switch (inp[0]) {
case '$':
/* FIXME: (echo $$) should still print pid of main shell */
p1 = utoa(getpid());
break;
case '!':
p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
break;
case '?':
p1 = utoa(last_return_code);
break;
case '#':
p1 = utoa(global_argc ? global_argc-1 : 0);
break;
case '*':
case '@': /* FIXME: we treat $@ as $* for now */
len = 1;
for (i = 1; i < global_argc; i++)
len += strlen(global_argv[i]) + 1;
p1 = p2 = alloca(--len);
for (i = 1; i < global_argc; i++) {
strcpy(p2, global_argv[i]);
p2 += strlen(global_argv[i]);
*p2++ = ifs[0];
}
*--p2 = '\0';
break;
default:
p1 = lookup_param(inp);
}
if (p1) {
len = res_str_len + strlen(p1);
res_str = xrealloc(res_str, 1 + len);
strcpy(res_str + res_str_len, p1);
res_str_len = len;
}
*p = SPECIAL_VAR_SYMBOL;
inp = ++p;
done = 1;
}
if (done) {
res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
strcpy((res_str + res_str_len), inp);
while ((p = strchr(res_str, '\n'))) {
*p = ' ';
}
}
return (res_str == NULL) ? inp : res_str;
} }
static char *expand_variables_to_string(const char *str)
{
char *argv[2], **list;
argv[0] = (char*)str;
argv[1] = NULL;
list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
/* To be removed / made conditional later. */
if (!list[0] || list[1])
bb_error_msg_and_die("BUG in varexp");
/* actually, just move string 2*sizeof(char*) bytes back */
strcpy((char*)list, list[0]);
return (char*)list;
}
/* This is used to get/check local shell variables */ /* This is used to get/check local shell variables */
static const char *get_local_var(const char *s) static const char *get_local_var(const char *s)
@@ -3195,7 +3147,7 @@ static char* make_string(char **inp)
int len = 0; int len = 0;
for (n = 0; inp[n]; n++) { for (n = 0; inp[n]; n++) {
p = insert_var_value(inp[n]); p = expand_variables_to_string(inp[n]);
val_len = strlen(p); val_len = strlen(p);
str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/ str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/
str[len++] = ' '; str[len++] = ' ';