diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-17 14:38:17 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-17 14:38:17 +0000 |
commit | b6a741ffa7be0926049c663e218864288e9161c1 (patch) | |
tree | 9da4bfbdb39cd7f6ba3df9f62e7358312952992b /shell/hush.c | |
parent | 96f67dc69d251168ea1c0adfaf6ff126d5dcbd36 (diff) | |
download | busybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.tar.gz busybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.tar.bz2 busybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.zip |
hush: consolidated variable expansion for assignments and "normal" one.
-435 bytes. Tested against testsuite.
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 126 |
1 files 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); | |||
444 | int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ | 444 | int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ |
445 | #endif | 445 | #endif |
446 | /* local variable support */ | 446 | /* local variable support */ |
447 | static char **do_variable_expansion(char **argv); | 447 | static char **expand_variables_to_list(char **argv); |
448 | static char *insert_var_value(char *inp); | 448 | /* used for expansion of right hand of assignments */ |
449 | static char *expand_variables_to_string(const char *str); | ||
449 | static const char *get_local_var(const char *var); | 450 | static const char *get_local_var(const char *var); |
450 | static int set_local_var(const char *s, int flg_export); | 451 | static int set_local_var(const char *s, int flg_export); |
451 | static void unset_local_var(const char *name); | 452 | static void unset_local_var(const char *name); |
@@ -1271,7 +1272,7 @@ static void pseudo_exec_argv(char **argv) | |||
1271 | debug_printf_exec("pid %d environment modification: %s\n", | 1272 | debug_printf_exec("pid %d environment modification: %s\n", |
1272 | getpid(), argv[i]); | 1273 | getpid(), argv[i]); |
1273 | // FIXME: vfork case?? | 1274 | // FIXME: vfork case?? |
1274 | p = insert_var_value(argv[i]); | 1275 | p = expand_variables_to_string(argv[i]); |
1275 | putenv(p == argv[i] ? xstrdup(p) : p); | 1276 | putenv(p == argv[i] ? xstrdup(p) : p); |
1276 | } | 1277 | } |
1277 | argv += i; | 1278 | argv += i; |
@@ -1282,7 +1283,7 @@ static void pseudo_exec_argv(char **argv) | |||
1282 | _exit(EXIT_SUCCESS); | 1283 | _exit(EXIT_SUCCESS); |
1283 | } | 1284 | } |
1284 | 1285 | ||
1285 | argv = do_variable_expansion(argv); | 1286 | argv = expand_variables_to_list(argv); |
1286 | 1287 | ||
1287 | /* | 1288 | /* |
1288 | * Check if the command matches any of the builtins. | 1289 | * Check if the command matches any of the builtins. |
@@ -1667,7 +1668,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1667 | export_me = 1; | 1668 | export_me = 1; |
1668 | } | 1669 | } |
1669 | free(name); | 1670 | free(name); |
1670 | p = insert_var_value(argv[i]); | 1671 | p = expand_variables_to_string(argv[i]); |
1671 | set_local_var(p, export_me); | 1672 | set_local_var(p, export_me); |
1672 | if (p != argv[i]) | 1673 | if (p != argv[i]) |
1673 | free(p); | 1674 | free(p); |
@@ -1675,7 +1676,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1675 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ | 1676 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ |
1676 | } | 1677 | } |
1677 | for (i = 0; is_assignment(argv[i]); i++) { | 1678 | for (i = 0; is_assignment(argv[i]); i++) { |
1678 | p = insert_var_value(argv[i]); | 1679 | p = expand_variables_to_string(argv[i]); |
1679 | if (p != argv[i]) { | 1680 | if (p != argv[i]) { |
1680 | //sp: child->sp--; | 1681 | //sp: child->sp--; |
1681 | putenv(p); | 1682 | putenv(p); |
@@ -1698,7 +1699,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1698 | setup_redirects(child, squirrel); | 1699 | setup_redirects(child, squirrel); |
1699 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); | 1700 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); |
1700 | //sp: if (child->sp) /* btw we can do it unconditionally... */ | 1701 | //sp: if (child->sp) /* btw we can do it unconditionally... */ |
1701 | argv_expanded = do_variable_expansion(argv + i); | 1702 | argv_expanded = expand_variables_to_list(argv + i); |
1702 | rcode = x->function(argv_expanded); | 1703 | rcode = x->function(argv_expanded); |
1703 | free(argv_expanded); | 1704 | free(argv_expanded); |
1704 | restore_redirects(squirrel); | 1705 | restore_redirects(squirrel); |
@@ -1714,7 +1715,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1714 | save_nofork_data(&nofork_save); | 1715 | save_nofork_data(&nofork_save); |
1715 | argv_expanded = argv + i; | 1716 | argv_expanded = argv + i; |
1716 | //sp: if (child->sp) | 1717 | //sp: if (child->sp) |
1717 | argv_expanded = do_variable_expansion(argv + i); | 1718 | argv_expanded = expand_variables_to_list(argv + i); |
1718 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | 1719 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); |
1719 | rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); | 1720 | rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); |
1720 | free(argv_expanded); | 1721 | free(argv_expanded); |
@@ -1991,7 +1992,7 @@ static int run_list_real(struct pipe *pi) | |||
1991 | if (!pi->next->progs->argv) | 1992 | if (!pi->next->progs->argv) |
1992 | continue; | 1993 | continue; |
1993 | /* create list of variable values */ | 1994 | /* create list of variable values */ |
1994 | for_list = do_variable_expansion(pi->next->progs->argv); | 1995 | for_list = expand_variables_to_list(pi->next->progs->argv); |
1995 | for_lcur = for_list; | 1996 | for_lcur = for_list; |
1996 | for_varname = pi->progs->argv[0]; | 1997 | for_varname = pi->progs->argv[0]; |
1997 | pi->progs->argv[0] = NULL; | 1998 | pi->progs->argv[0] = NULL; |
@@ -2251,8 +2252,7 @@ static int xglob(o_string *dest, int flags, glob_t *pglob) | |||
2251 | return gr; | 2252 | return gr; |
2252 | } | 2253 | } |
2253 | 2254 | ||
2254 | 2255 | /* expand_variables_to_list() takes a list of strings, expands | |
2255 | /* do_variable_expansion() takes a list of strings, expands | ||
2256 | * all variable references within and returns a pointer to | 2256 | * all variable references within and returns a pointer to |
2257 | * a list of expanded strings, possibly with larger number | 2257 | * a list of expanded strings, possibly with larger number |
2258 | * of strings. (Think VAR="a b"; echo $VAR). | 2258 | * 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) | |||
2371 | * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ | 2371 | * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ |
2372 | /* NB: another bug is that we cannot detect empty strings yet: | 2372 | /* NB: another bug is that we cannot detect empty strings yet: |
2373 | * "" or $empty"" expands to zero words, has to expand to empty word */ | 2373 | * "" or $empty"" expands to zero words, has to expand to empty word */ |
2374 | static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | 2374 | static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask) |
2375 | { | 2375 | { |
2376 | /* or_mask is either 0 (normal case) or 0x80 | ||
2377 | * (expansion of right-hand side of assignment == 1-element expand) */ | ||
2378 | |||
2376 | char first_ch, ored_ch; | 2379 | char first_ch, ored_ch; |
2377 | int i; | 2380 | int i; |
2378 | const char *val; | 2381 | const char *val; |
@@ -2392,7 +2395,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | |||
2392 | arg = ++p; | 2395 | arg = ++p; |
2393 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 2396 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
2394 | 2397 | ||
2395 | first_ch = arg[0]; | 2398 | first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ |
2396 | ored_ch |= first_ch; | 2399 | ored_ch |= first_ch; |
2397 | val = NULL; | 2400 | val = NULL; |
2398 | switch (first_ch & 0x7f) { | 2401 | switch (first_ch & 0x7f) { |
@@ -2427,7 +2430,10 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | |||
2427 | list[n++] = pos; | 2430 | list[n++] = pos; |
2428 | } | 2431 | } |
2429 | } | 2432 | } |
2430 | } else if (first_ch == ('@'|0x80)) { /* quoted $@ */ | 2433 | } else |
2434 | /* If or_mask is nonzero, we handle assignment 'a=....$@.....' | ||
2435 | * and in this case should theat it like '$*' */ | ||
2436 | if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ | ||
2431 | while (1) { | 2437 | while (1) { |
2432 | strcpy(pos, global_argv[i]); | 2438 | strcpy(pos, global_argv[i]); |
2433 | pos += strlen(global_argv[i]); | 2439 | pos += strlen(global_argv[i]); |
@@ -2490,7 +2496,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | |||
2490 | return n; | 2496 | return n; |
2491 | } | 2497 | } |
2492 | 2498 | ||
2493 | static char **do_variable_expansion(char **argv) | 2499 | static char **expand_variables(char **argv, char or_mask) |
2494 | { | 2500 | { |
2495 | int n; | 2501 | int n; |
2496 | int count = 1; | 2502 | int count = 1; |
@@ -2515,9 +2521,9 @@ static char **do_variable_expansion(char **argv) | |||
2515 | n = 0; | 2521 | n = 0; |
2516 | v = argv; | 2522 | v = argv; |
2517 | while (*v) | 2523 | while (*v) |
2518 | n = expand_vars_to_list(list, n, &pos, *v++); | 2524 | n = expand_vars_to_list(list, n, &pos, *v++, or_mask); |
2519 | 2525 | ||
2520 | if(n) debug_printf_expand("finalized list[%d]=%p '%s' " | 2526 | if (n) debug_printf_expand("finalized list[%d]=%p '%s' " |
2521 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | 2527 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], |
2522 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | 2528 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); |
2523 | list[n] = NULL; | 2529 | list[n] = NULL; |
@@ -2538,80 +2544,26 @@ static char **do_variable_expansion(char **argv) | |||
2538 | return list; | 2544 | return list; |
2539 | } | 2545 | } |
2540 | 2546 | ||
2547 | static char **expand_variables_to_list(char **argv) | ||
2548 | { | ||
2549 | return expand_variables(argv, 0); | ||
2550 | } | ||
2541 | 2551 | ||
2542 | static char *insert_var_value(char *inp) | 2552 | static char *expand_variables_to_string(const char *str) |
2543 | { | 2553 | { |
2544 | int res_str_len = 0; | 2554 | char *argv[2], **list; |
2545 | int len; | ||
2546 | int done = 0; | ||
2547 | int i; | ||
2548 | const char *p1; | ||
2549 | char *p, *p2; | ||
2550 | char *res_str = NULL; | ||
2551 | |||
2552 | while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { | ||
2553 | if (p != inp) { | ||
2554 | len = p - inp; | ||
2555 | res_str = xrealloc(res_str, (res_str_len + len)); | ||
2556 | strncpy((res_str + res_str_len), inp, len); | ||
2557 | res_str_len += len; | ||
2558 | } | ||
2559 | inp = ++p; | ||
2560 | p = strchr(inp, SPECIAL_VAR_SYMBOL); | ||
2561 | *p = '\0'; | ||
2562 | |||
2563 | switch (inp[0]) { | ||
2564 | case '$': | ||
2565 | /* FIXME: (echo $$) should still print pid of main shell */ | ||
2566 | p1 = utoa(getpid()); | ||
2567 | break; | ||
2568 | case '!': | ||
2569 | p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)""; | ||
2570 | break; | ||
2571 | case '?': | ||
2572 | p1 = utoa(last_return_code); | ||
2573 | break; | ||
2574 | case '#': | ||
2575 | p1 = utoa(global_argc ? global_argc-1 : 0); | ||
2576 | break; | ||
2577 | case '*': | ||
2578 | case '@': /* FIXME: we treat $@ as $* for now */ | ||
2579 | len = 1; | ||
2580 | for (i = 1; i < global_argc; i++) | ||
2581 | len += strlen(global_argv[i]) + 1; | ||
2582 | p1 = p2 = alloca(--len); | ||
2583 | for (i = 1; i < global_argc; i++) { | ||
2584 | strcpy(p2, global_argv[i]); | ||
2585 | p2 += strlen(global_argv[i]); | ||
2586 | *p2++ = ifs[0]; | ||
2587 | } | ||
2588 | *--p2 = '\0'; | ||
2589 | break; | ||
2590 | default: | ||
2591 | p1 = lookup_param(inp); | ||
2592 | } | ||
2593 | 2555 | ||
2594 | if (p1) { | 2556 | argv[0] = (char*)str; |
2595 | len = res_str_len + strlen(p1); | 2557 | argv[1] = NULL; |
2596 | res_str = xrealloc(res_str, 1 + len); | 2558 | list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */ |
2597 | strcpy(res_str + res_str_len, p1); | 2559 | /* To be removed / made conditional later. */ |
2598 | res_str_len = len; | 2560 | if (!list[0] || list[1]) |
2599 | } | 2561 | bb_error_msg_and_die("BUG in varexp"); |
2600 | *p = SPECIAL_VAR_SYMBOL; | 2562 | /* actually, just move string 2*sizeof(char*) bytes back */ |
2601 | inp = ++p; | 2563 | strcpy((char*)list, list[0]); |
2602 | done = 1; | 2564 | return (char*)list; |
2603 | } | ||
2604 | if (done) { | ||
2605 | res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); | ||
2606 | strcpy((res_str + res_str_len), inp); | ||
2607 | while ((p = strchr(res_str, '\n'))) { | ||
2608 | *p = ' '; | ||
2609 | } | ||
2610 | } | ||
2611 | return (res_str == NULL) ? inp : res_str; | ||
2612 | } | 2565 | } |
2613 | 2566 | ||
2614 | |||
2615 | /* This is used to get/check local shell variables */ | 2567 | /* This is used to get/check local shell variables */ |
2616 | static const char *get_local_var(const char *s) | 2568 | static const char *get_local_var(const char *s) |
2617 | { | 2569 | { |
@@ -3195,7 +3147,7 @@ static char* make_string(char **inp) | |||
3195 | int len = 0; | 3147 | int len = 0; |
3196 | 3148 | ||
3197 | for (n = 0; inp[n]; n++) { | 3149 | for (n = 0; inp[n]; n++) { |
3198 | p = insert_var_value(inp[n]); | 3150 | p = expand_variables_to_string(inp[n]); |
3199 | val_len = strlen(p); | 3151 | val_len = strlen(p); |
3200 | str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/ | 3152 | str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/ |
3201 | str[len++] = ' '; | 3153 | str[len++] = ' '; |