diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-14 16:23:23 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-14 16:23:23 +0000 |
commit | 764d59d48848121d89b31ddecf0130ce24a4d91b (patch) | |
tree | 5ab700c4cbc8e39405bb97e7ad1c73a083161cfe /shell/hush.c | |
parent | 03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea (diff) | |
download | busybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.tar.gz busybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.tar.bz2 busybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.zip |
hush: more fixes to variable expansion, more testcases
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c index 803970b57..87e003db4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1308,6 +1308,8 @@ static void pseudo_exec_argv(char **argv) | |||
1308 | _exit(EXIT_SUCCESS); | 1308 | _exit(EXIT_SUCCESS); |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | argv = do_variable_expansion(argv); | ||
1312 | |||
1311 | /* | 1313 | /* |
1312 | * Check if the command matches any of the builtins. | 1314 | * Check if the command matches any of the builtins. |
1313 | * Depending on context, this might be redundant. But it's | 1315 | * Depending on context, this might be redundant. But it's |
@@ -1316,7 +1318,7 @@ static void pseudo_exec_argv(char **argv) | |||
1316 | */ | 1318 | */ |
1317 | for (x = bltins; x->cmd; x++) { | 1319 | for (x = bltins; x->cmd; x++) { |
1318 | if (strcmp(argv[0], x->cmd) == 0) { | 1320 | if (strcmp(argv[0], x->cmd) == 0) { |
1319 | debug_printf("builtin exec %s\n", argv[0]); | 1321 | debug_printf_exec("running builtin '%s'\n", argv[0]); |
1320 | rcode = x->function(argv); | 1322 | rcode = x->function(argv); |
1321 | fflush(stdout); | 1323 | fflush(stdout); |
1322 | _exit(rcode); | 1324 | _exit(rcode); |
@@ -1334,6 +1336,7 @@ static void pseudo_exec_argv(char **argv) | |||
1334 | * to find ourself... */ | 1336 | * to find ourself... */ |
1335 | #if ENABLE_FEATURE_SH_STANDALONE | 1337 | #if ENABLE_FEATURE_SH_STANDALONE |
1336 | debug_printf("running applet %s\n", argv[0]); | 1338 | debug_printf("running applet %s\n", argv[0]); |
1339 | // FIXME: check NOEXEC bit, and EXEC if not set! | ||
1337 | run_applet_and_exit(argv[0], argv); | 1340 | run_applet_and_exit(argv[0], argv); |
1338 | // is it ok that run_applet_and_exit() does exit(), not _exit()? | 1341 | // is it ok that run_applet_and_exit() does exit(), not _exit()? |
1339 | // NB: IIRC on NOMMU we are after _vfork_, not fork! | 1342 | // NB: IIRC on NOMMU we are after _vfork_, not fork! |
@@ -1674,6 +1677,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1674 | } | 1677 | } |
1675 | 1678 | ||
1676 | if (single_fg && child->argv != NULL) { | 1679 | if (single_fg && child->argv != NULL) { |
1680 | char **argv_expanded, **free_me; | ||
1677 | char **argv = child->argv; | 1681 | char **argv = child->argv; |
1678 | 1682 | ||
1679 | for (i = 0; is_assignment(argv[i]); i++) | 1683 | for (i = 0; is_assignment(argv[i]); i++) |
@@ -1714,16 +1718,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1714 | putenv(xstrdup(p)); | 1718 | putenv(xstrdup(p)); |
1715 | } | 1719 | } |
1716 | } | 1720 | } |
1717 | if (child->sp) { | 1721 | free_me = NULL; |
1718 | char *str; | ||
1719 | |||
1720 | str = make_string(argv + i); | ||
1721 | debug_printf_exec(": parse_string_outer '%s'\n", str); | ||
1722 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); | ||
1723 | free(str); | ||
1724 | debug_printf_exec("run_pipe_real return %d\n", last_return_code); | ||
1725 | return last_return_code; | ||
1726 | } | ||
1727 | for (x = bltins; x->cmd; x++) { | 1722 | for (x = bltins; x->cmd; x++) { |
1728 | if (strcmp(argv[i], x->cmd) == 0) { | 1723 | if (strcmp(argv[i], x->cmd) == 0) { |
1729 | if (x->function == builtin_exec && argv[i+1] == NULL) { | 1724 | if (x->function == builtin_exec && argv[i+1] == NULL) { |
@@ -1739,7 +1734,11 @@ static int run_pipe_real(struct pipe *pi) | |||
1739 | // TODO: fflush(NULL)? | 1734 | // TODO: fflush(NULL)? |
1740 | setup_redirects(child, squirrel); | 1735 | setup_redirects(child, squirrel); |
1741 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); | 1736 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); |
1742 | rcode = x->function(argv + i); | 1737 | argv_expanded = argv + i; |
1738 | if (child->sp) /* btw we can do it unconditionally... */ | ||
1739 | free_me = argv_expanded = do_variable_expansion(argv + i); | ||
1740 | rcode = x->function(argv_expanded); | ||
1741 | free(free_me); | ||
1743 | restore_redirects(squirrel); | 1742 | restore_redirects(squirrel); |
1744 | debug_printf_exec("run_pipe_real return %d\n", rcode); | 1743 | debug_printf_exec("run_pipe_real return %d\n", rcode); |
1745 | return rcode; | 1744 | return rcode; |
@@ -1750,9 +1749,13 @@ static int run_pipe_real(struct pipe *pi) | |||
1750 | const struct bb_applet *a = find_applet_by_name(argv[i]); | 1749 | const struct bb_applet *a = find_applet_by_name(argv[i]); |
1751 | if (a && a->nofork) { | 1750 | if (a && a->nofork) { |
1752 | setup_redirects(child, squirrel); | 1751 | setup_redirects(child, squirrel); |
1753 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]); | ||
1754 | save_nofork_data(&nofork_save); | 1752 | save_nofork_data(&nofork_save); |
1755 | rcode = run_nofork_applet_prime(&nofork_save, a, argv + i); | 1753 | argv_expanded = argv + i; |
1754 | if (child->sp) | ||
1755 | free_me = argv_expanded = do_variable_expansion(argv + i); | ||
1756 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | ||
1757 | rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); | ||
1758 | free(free_me); | ||
1756 | restore_redirects(squirrel); | 1759 | restore_redirects(squirrel); |
1757 | debug_printf_exec("run_pipe_real return %d\n", rcode); | 1760 | debug_printf_exec("run_pipe_real return %d\n", rcode); |
1758 | return rcode; | 1761 | return rcode; |
@@ -2049,7 +2052,7 @@ static int run_list_real(struct pipe *pi) | |||
2049 | continue; | 2052 | continue; |
2050 | } | 2053 | } |
2051 | /* insert next value from for_lcur */ | 2054 | /* insert next value from for_lcur */ |
2052 | //vda: does it need escaping? | 2055 | /* vda: does it need escaping? */ |
2053 | pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); | 2056 | pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
2054 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; | 2057 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; |
2055 | } | 2058 | } |
@@ -2359,7 +2362,13 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg) | |||
2359 | default: | 2362 | default: |
2360 | *p = '\0'; | 2363 | *p = '\0'; |
2361 | arg[0] = first_ch & 0x7f; | 2364 | arg[0] = first_ch & 0x7f; |
2362 | val = lookup_param(arg); | 2365 | if (isdigit(arg[0])) { |
2366 | i = xatoi_u(arg); | ||
2367 | val = NULL; | ||
2368 | if (i < global_argc) | ||
2369 | val = global_argv[i]; | ||
2370 | } else | ||
2371 | val = lookup_param(arg); | ||
2363 | arg[0] = first_ch; | 2372 | arg[0] = first_ch; |
2364 | *p = SPECIAL_VAR_SYMBOL; | 2373 | *p = SPECIAL_VAR_SYMBOL; |
2365 | 2374 | ||
@@ -2380,7 +2389,7 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg) | |||
2380 | 2389 | ||
2381 | /* Store given string, finalizing the word and starting new one whenever | 2390 | /* Store given string, finalizing the word and starting new one whenever |
2382 | * we encounter ifs char(s). This is used for expanding variable values. | 2391 | * we encounter ifs char(s). This is used for expanding variable values. |
2383 | * End-of-string does NOT finalize word, because cases like echo -$VAR- */ | 2392 | * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ |
2384 | static int expand_on_ifs(char **list, int n, char **posp, const char *str) | 2393 | static int expand_on_ifs(char **list, int n, char **posp, const char *str) |
2385 | { | 2394 | { |
2386 | char *pos = *posp; | 2395 | char *pos = *posp; |
@@ -2390,15 +2399,14 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str) | |||
2390 | memcpy(pos, str, word_len); /* store non-ifs chars */ | 2399 | memcpy(pos, str, word_len); /* store non-ifs chars */ |
2391 | pos += word_len; | 2400 | pos += word_len; |
2392 | str += word_len; | 2401 | str += word_len; |
2393 | if (!*str) /* EOL - do not finalize word */ | ||
2394 | break; | ||
2395 | *pos++ = '\0'; | ||
2396 | if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' " | ||
2397 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2398 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2399 | list[n++] = pos; | ||
2400 | } | 2402 | } |
2401 | if (!*str) break; /* EOL, not ifs char */ | 2403 | if (!*str) /* EOL - do not finalize word */ |
2404 | break; | ||
2405 | *pos++ = '\0'; | ||
2406 | if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' " | ||
2407 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2408 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2409 | list[n++] = pos; | ||
2402 | str += strspn(str, ifs); /* skip ifs chars */ | 2410 | str += strspn(str, ifs); /* skip ifs chars */ |
2403 | } | 2411 | } |
2404 | *posp = pos; | 2412 | *posp = pos; |
@@ -2478,7 +2486,13 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | |||
2478 | default: | 2486 | default: |
2479 | *p = '\0'; | 2487 | *p = '\0'; |
2480 | arg[0] = first_ch & 0x7f; | 2488 | arg[0] = first_ch & 0x7f; |
2481 | val = lookup_param(arg); | 2489 | if (isdigit(arg[0])) { |
2490 | int i = xatoi_u(arg); | ||
2491 | val = NULL; | ||
2492 | if (i < global_argc) | ||
2493 | val = global_argv[i]; | ||
2494 | } else | ||
2495 | val = lookup_param(arg); | ||
2482 | arg[0] = first_ch; | 2496 | arg[0] = first_ch; |
2483 | *p = SPECIAL_VAR_SYMBOL; | 2497 | *p = SPECIAL_VAR_SYMBOL; |
2484 | if (!(first_ch & 0x80)) { /* unquoted var */ | 2498 | if (!(first_ch & 0x80)) { /* unquoted var */ |
@@ -3541,9 +3555,6 @@ static void update_ifs_map(void) | |||
3541 | * from builtin_source() */ | 3555 | * from builtin_source() */ |
3542 | static int parse_stream_outer(struct in_str *inp, int parse_flag) | 3556 | static int parse_stream_outer(struct in_str *inp, int parse_flag) |
3543 | { | 3557 | { |
3544 | // FIXME: '{ true | exit 3; echo $? }' is parsed as a whole, | ||
3545 | // as a result $? is replaced by 0, not 3! | ||
3546 | |||
3547 | struct p_context ctx; | 3558 | struct p_context ctx; |
3548 | o_string temp = NULL_O_STRING; | 3559 | o_string temp = NULL_O_STRING; |
3549 | int rcode; | 3560 | int rcode; |