From b6a741ffa7be0926049c663e218864288e9161c1 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 17 May 2007 14:38:17 +0000 Subject: [PATCH] hush: consolidated variable expansion for assignments and "normal" one. -435 bytes. Tested against testsuite. --- shell/hush.c | 126 ++++++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 87 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 0a035cad4..9f0cc641e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -444,8 +444,9 @@ static void delete_finished_bg_job(struct pipe *pi); int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ #endif /* local variable support */ -static char **do_variable_expansion(char **argv); -static char *insert_var_value(char *inp); +static char **expand_variables_to_list(char **argv); +/* 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 int set_local_var(const char *s, int flg_export); 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", getpid(), argv[i]); // FIXME: vfork case?? - p = insert_var_value(argv[i]); + p = expand_variables_to_string(argv[i]); putenv(p == argv[i] ? xstrdup(p) : p); } argv += i; @@ -1282,7 +1283,7 @@ static void pseudo_exec_argv(char **argv) _exit(EXIT_SUCCESS); } - argv = do_variable_expansion(argv); + argv = expand_variables_to_list(argv); /* * Check if the command matches any of the builtins. @@ -1667,7 +1668,7 @@ static int run_pipe_real(struct pipe *pi) export_me = 1; } free(name); - p = insert_var_value(argv[i]); + p = expand_variables_to_string(argv[i]); set_local_var(p, export_me); if (p != argv[i]) 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 */ } 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]) { //sp: child->sp--; putenv(p); @@ -1698,7 +1699,7 @@ static int run_pipe_real(struct pipe *pi) setup_redirects(child, squirrel); debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); //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); free(argv_expanded); restore_redirects(squirrel); @@ -1714,7 +1715,7 @@ static int run_pipe_real(struct pipe *pi) save_nofork_data(&nofork_save); argv_expanded = argv + i; //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]); rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); free(argv_expanded); @@ -1991,7 +1992,7 @@ static int run_list_real(struct pipe *pi) if (!pi->next->progs->argv) continue; /* 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_varname = pi->progs->argv[0]; pi->progs->argv[0] = NULL; @@ -2251,8 +2252,7 @@ static int xglob(o_string *dest, int flags, glob_t *pglob) return gr; } - -/* do_variable_expansion() takes a list of strings, expands +/* expand_variables_to_list() takes a list of strings, expands * all variable references within and returns a pointer to * a list of expanded strings, possibly with larger number * 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! */ /* NB: another bug is that we cannot detect empty strings yet: * "" 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; int i; const char *val; @@ -2392,7 +2395,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg) arg = ++p; 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; val = NULL; 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; } } - } 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) { strcpy(pos, 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; } -static char **do_variable_expansion(char **argv) +static char **expand_variables(char **argv, char or_mask) { int n; int count = 1; @@ -2515,9 +2521,9 @@ static char **do_variable_expansion(char **argv) n = 0; v = argv; 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(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); list[n] = NULL; @@ -2538,80 +2544,26 @@ static char **do_variable_expansion(char **argv) return list; } +static char **expand_variables_to_list(char **argv) +{ + return expand_variables(argv, 0); +} -static char *insert_var_value(char *inp) +static char *expand_variables_to_string(const char *str) { - int res_str_len = 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); - } + char *argv[2], **list; - 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; + 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 */ static const char *get_local_var(const char *s) { @@ -3195,7 +3147,7 @@ static char* make_string(char **inp) int len = 0; for (n = 0; inp[n]; n++) { - p = insert_var_value(inp[n]); + p = expand_variables_to_string(inp[n]); val_len = strlen(p); str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', */ str[len++] = ' '; -- 2.25.1