aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-06-16 12:47:11 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-06-16 12:47:11 +0000
commit82dfec3e4e6d2b8354d901a525f9acff35369512 (patch)
treea3ebda0c5f23bdaae1aba29d57b6793abf696785 /shell
parent31e128636535a58be64636c8de93a6dad8b39ac0 (diff)
downloadbusybox-w32-82dfec3e4e6d2b8354d901a525f9acff35369512.tar.gz
busybox-w32-82dfec3e4e6d2b8354d901a525f9acff35369512.tar.bz2
busybox-w32-82dfec3e4e6d2b8354d901a525f9acff35369512.zip
hush: fix hush-bugs/glob_and_vars.tests testcase:
globbing is now done _after_ variable/`cmd` substitution function old new delta expand_strvec_to_strvec 7 353 +346 expand_variables 1348 1383 +35 add_string_to_strings - 28 +28 globhack 114 - -114 done_word 778 579 -199 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/1 up/down: 409/-313) Total: 96 bytes
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c109
-rw-r--r--shell/hush_test/hush-bugs/empty_for.right1
-rwxr-xr-xshell/hush_test/hush-bugs/empty_for.tests3
-rwxr-xr-xshell/hush_test/hush-bugs/glob_and_vars.tests2
-rw-r--r--shell/hush_test/hush-vars/glob_and_vars.right (renamed from shell/hush_test/hush-bugs/glob_and_vars.right)0
-rwxr-xr-xshell/hush_test/hush-vars/glob_and_vars.tests2
6 files changed, 70 insertions, 47 deletions
diff --git a/shell/hush.c b/shell/hush.c
index bc192b38b..7c5a44274 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -481,10 +481,6 @@ static int run_list(struct pipe *pi);
481static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN; 481static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN;
482static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN; 482static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN;
483static int run_pipe(struct pipe *pi); 483static int run_pipe(struct pipe *pi);
484/* extended glob support: */
485static char **globhack(const char *src, char **strings);
486static int glob_needed(const char *s);
487static int xglob(o_string *dest, char ***pglob);
488/* variable assignment: */ 484/* variable assignment: */
489static int is_assignment(const char *s); 485static int is_assignment(const char *s);
490/* data structure manipulation: */ 486/* data structure manipulation: */
@@ -591,6 +587,17 @@ static char **alloc_ptrs(char **argv)
591} 587}
592#endif 588#endif
593 589
590#ifdef DEBUG_EXPAND
591static void debug_print_strings(const char *prefix, char **vv)
592{
593 fprintf(stderr, "%s:\n", prefix);
594 while (*vv)
595 fprintf(stderr, " '%s'\n", *vv++);
596}
597#else
598#define debug_print_strings(prefix, vv) ((void)0)
599#endif
600
594 601
595/* Function prototypes for builtins */ 602/* Function prototypes for builtins */
596static int builtin_cd(char **argv); 603static int builtin_cd(char **argv);
@@ -2280,7 +2287,9 @@ static int run_list(struct pipe *pi)
2280 if (!pi->next->progs->argv) 2287 if (!pi->next->progs->argv)
2281 continue; 2288 continue;
2282 /* create list of variable values */ 2289 /* create list of variable values */
2290 debug_print_strings("for_list made from", pi->next->progs->argv);
2283 for_list = expand_strvec_to_strvec(pi->next->progs->argv); 2291 for_list = expand_strvec_to_strvec(pi->next->progs->argv);
2292 debug_print_strings("for_list", for_list);
2284 for_lcur = for_list; 2293 for_lcur = for_list;
2285 for_varname = pi->progs->argv[0]; 2294 for_varname = pi->progs->argv[0];
2286 pi->progs->argv[0] = NULL; 2295 pi->progs->argv[0] = NULL;
@@ -2465,13 +2474,10 @@ static int run_and_free_list(struct pipe *pi)
2465 return rcode; 2474 return rcode;
2466} 2475}
2467 2476
2468/* The API for glob is arguably broken. This routine pushes a non-matching 2477/* Remove non-backslashed backslashes and add to "strings" vector.
2469 * string into the output structure, removing non-backslashed backslashes.
2470 * If someone can prove me wrong, by performing this function within the
2471 * original glob(3) api, feel free to rewrite this routine into oblivion.
2472 * XXX broken if the last character is '\\', check that before calling. 2478 * XXX broken if the last character is '\\', check that before calling.
2473 */ 2479 */
2474static char **globhack(const char *src, char **strings) 2480static char **add_unq_string_to_strings(char **strings, const char *src)
2475{ 2481{
2476 int cnt; 2482 int cnt;
2477 const char *s; 2483 const char *s;
@@ -2503,33 +2509,20 @@ static int glob_needed(const char *s)
2503 return 0; 2509 return 0;
2504} 2510}
2505 2511
2506static int xglob(o_string *dest, char ***pglob) 2512static int xglob(char ***pglob, const char *pattern)
2507{ 2513{
2508 /* short-circuit for null word */ 2514 if (glob_needed(pattern)) {
2509 /* we can code this better when the debug_printf's are gone */
2510 if (dest->length == 0) {
2511 if (dest->nonnull) {
2512 /* bash man page calls this an "explicit" null */
2513 *pglob = globhack(dest->data, *pglob);
2514 }
2515 return 0;
2516 }
2517
2518 if (glob_needed(dest->data)) {
2519 glob_t globdata; 2515 glob_t globdata;
2520 int gr; 2516 int gr;
2521 2517
2522 memset(&globdata, 0, sizeof(globdata)); 2518 memset(&globdata, 0, sizeof(globdata));
2523 gr = glob(dest->data, 0, NULL, &globdata); 2519 gr = glob(pattern, 0, NULL, &globdata);
2524 debug_printf("glob returned %d\n", gr); 2520 debug_printf("glob returned %d\n", gr);
2525 if (gr == GLOB_NOSPACE) 2521 if (gr == GLOB_NOSPACE)
2526 bb_error_msg_and_die("out of memory during glob"); 2522 bb_error_msg_and_die("out of memory during glob");
2527 if (gr == GLOB_NOMATCH) { 2523 if (gr == GLOB_NOMATCH) {
2528 debug_printf("globhack returned %d\n", gr);
2529 /* quote removal, or more accurately, backslash removal */
2530 *pglob = globhack(dest->data, *pglob);
2531 globfree(&globdata); 2524 globfree(&globdata);
2532 return 0; 2525 goto literal;
2533 } 2526 }
2534 if (gr != 0) { /* GLOB_ABORTED ? */ 2527 if (gr != 0) { /* GLOB_ABORTED ? */
2535 bb_error_msg("glob(3) error %d", gr); 2528 bb_error_msg("glob(3) error %d", gr);
@@ -2540,7 +2533,10 @@ static int xglob(o_string *dest, char ***pglob)
2540 return gr; 2533 return gr;
2541 } 2534 }
2542 2535
2543 *pglob = globhack(dest->data, *pglob); 2536 literal:
2537 /* quote removal, or more accurately, backslash removal */
2538 *pglob = add_unq_string_to_strings(*pglob, pattern);
2539 debug_print_strings("after xglob", *pglob);
2544 return 0; 2540 return 0;
2545} 2541}
2546 2542
@@ -2733,7 +2729,7 @@ static char **expand_variables(char **argv, char or_mask)
2733 n = expand_vars_to_list(&output, n, *v++, or_mask); 2729 n = expand_vars_to_list(&output, n, *v++, or_mask);
2734 o_debug_list("expand_variables", &output, n); 2730 o_debug_list("expand_variables", &output, n);
2735 2731
2736 /* output.data (malloced) gets returned in "list" */ 2732 /* output.data (malloced in one block) gets returned in "list" */
2737 list = o_finalize_list(&output, n); 2733 list = o_finalize_list(&output, n);
2738 2734
2739#ifdef DEBUG_EXPAND 2735#ifdef DEBUG_EXPAND
@@ -2750,9 +2746,27 @@ static char **expand_variables(char **argv, char or_mask)
2750 2746
2751static char **expand_strvec_to_strvec(char **argv) 2747static char **expand_strvec_to_strvec(char **argv)
2752{ 2748{
2753 return expand_variables(argv, 0); 2749 char **exp;
2750 char **res = NULL;
2751
2752 debug_print_strings("expand_strvec_to_strvec: pre expand", argv);
2753 exp = argv = expand_variables(argv, 0);
2754 debug_print_strings("expand_strvec_to_strvec: post expand", argv);
2755 while (*argv) {
2756 int r = xglob(&res, *argv);
2757 if (r)
2758 bb_error_msg("xglob returned %d on '%s'", r, *argv);
2759//TODO: testcase for bad glob pattern behavior
2760 argv++;
2761 }
2762 free(exp);
2763 debug_print_strings("expand_strvec_to_strvec: res", res);
2764 return res;
2754} 2765}
2755 2766
2767/* used for expansion of right hand of assignments */
2768/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs
2769 * "v=/bin/c*" */
2756static char *expand_string_to_string(const char *str) 2770static char *expand_string_to_string(const char *str)
2757{ 2771{
2758 char *argv[2], **list; 2772 char *argv[2], **list;
@@ -2769,6 +2783,7 @@ static char *expand_string_to_string(const char *str)
2769 return (char*)list; 2783 return (char*)list;
2770} 2784}
2771 2785
2786/* used for eval */
2772static char* expand_strvec_to_string(char **argv) 2787static char* expand_strvec_to_string(char **argv)
2773{ 2788{
2774 char **list; 2789 char **list;
@@ -3106,7 +3121,6 @@ static int done_word(o_string *word, struct p_context *ctx)
3106{ 3121{
3107 struct child_prog *child = ctx->child; 3122 struct child_prog *child = ctx->child;
3108 char ***glob_target; 3123 char ***glob_target;
3109 int gr;
3110 3124
3111 debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); 3125 debug_printf_parse("done_word entered: '%s' %p\n", word->data, child);
3112 if (word->length == 0 && !word->nonnull) { 3126 if (word->length == 0 && !word->nonnull) {
@@ -3131,12 +3145,10 @@ static int done_word(o_string *word, struct p_context *ctx)
3131 } 3145 }
3132 glob_target = &child->argv; 3146 glob_target = &child->argv;
3133 } 3147 }
3134//BUG! globbing should be done after variable expansion! 3148
3135//See glob_and_vars testcase 3149 if (word->length || word->nonnull) {
3136 gr = xglob(word, glob_target); 3150 *glob_target = add_string_to_strings(*glob_target, xstrdup(word->data));
3137 if (gr != 0) { 3151 debug_print_strings("glob_target appended", *glob_target);
3138 debug_printf_parse("done_word return 1: xglob returned %d\n", gr);
3139 return 1;
3140 } 3152 }
3141 3153
3142 o_reset(word); 3154 o_reset(word);
@@ -3371,6 +3383,11 @@ static int process_command_subs(o_string *dest,
3371 o_addQchr(dest, '\n'); 3383 o_addQchr(dest, '\n');
3372 eol_cnt--; 3384 eol_cnt--;
3373 } 3385 }
3386 /* Even unquoted `echo '\'` results in two backslashes
3387 * (which are converted into one by globbing later) */
3388 if (!dest->o_quote && ch == '\\') {
3389 o_addchr(dest, ch);
3390 }
3374 o_addQchr(dest, ch); 3391 o_addQchr(dest, ch);
3375 } 3392 }
3376 3393
@@ -3440,7 +3457,7 @@ static void add_till_single_quote(o_string *dest, struct in_str *input)
3440 break; 3457 break;
3441 if (ch == '\'') 3458 if (ch == '\'')
3442 break; 3459 break;
3443 o_addqchr(dest, ch); 3460 o_addchr(dest, ch);
3444 } 3461 }
3445} 3462}
3446/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 3463/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
@@ -3451,15 +3468,15 @@ static void add_till_double_quote(o_string *dest, struct in_str *input)
3451 if (ch == '"') 3468 if (ch == '"')
3452 break; 3469 break;
3453 if (ch == '\\') { /* \x. Copy both chars. */ 3470 if (ch == '\\') { /* \x. Copy both chars. */
3454 o_addqchr(dest, ch); 3471 o_addchr(dest, ch);
3455 ch = i_getch(input); 3472 ch = i_getch(input);
3456 } 3473 }
3457 if (ch == EOF) 3474 if (ch == EOF)
3458 break; 3475 break;
3459 o_addqchr(dest, ch); 3476 o_addchr(dest, ch);
3460 if (ch == '`') { 3477 if (ch == '`') {
3461 add_till_backquote(dest, input); 3478 add_till_backquote(dest, input);
3462 o_addqchr(dest, ch); 3479 o_addchr(dest, ch);
3463 continue; 3480 continue;
3464 } 3481 }
3465 //if (ch == '$') ... 3482 //if (ch == '$') ...
@@ -3488,12 +3505,12 @@ static void add_till_backquote(o_string *dest, struct in_str *input)
3488 if (ch == '\\') { /* \x. Copy both chars unless it is \` */ 3505 if (ch == '\\') { /* \x. Copy both chars unless it is \` */
3489 int ch2 = i_getch(input); 3506 int ch2 = i_getch(input);
3490 if (ch2 != '`' && ch2 != '$' && ch2 != '\\') 3507 if (ch2 != '`' && ch2 != '$' && ch2 != '\\')
3491 o_addqchr(dest, ch); 3508 o_addchr(dest, ch);
3492 ch = ch2; 3509 ch = ch2;
3493 } 3510 }
3494 if (ch == EOF) 3511 if (ch == EOF)
3495 break; 3512 break;
3496 o_addqchr(dest, ch); 3513 o_addchr(dest, ch);
3497 } 3514 }
3498} 3515}
3499/* Process $(cmd) - copy contents until ")" is seen. Complicated by 3516/* Process $(cmd) - copy contents until ")" is seen. Complicated by
@@ -3520,22 +3537,22 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input)
3520 if (ch == ')') 3537 if (ch == ')')
3521 if (--count < 0) 3538 if (--count < 0)
3522 break; 3539 break;
3523 o_addqchr(dest, ch); 3540 o_addchr(dest, ch);
3524 if (ch == '\'') { 3541 if (ch == '\'') {
3525 add_till_single_quote(dest, input); 3542 add_till_single_quote(dest, input);
3526 o_addqchr(dest, ch); 3543 o_addchr(dest, ch);
3527 continue; 3544 continue;
3528 } 3545 }
3529 if (ch == '"') { 3546 if (ch == '"') {
3530 add_till_double_quote(dest, input); 3547 add_till_double_quote(dest, input);
3531 o_addqchr(dest, ch); 3548 o_addchr(dest, ch);
3532 continue; 3549 continue;
3533 } 3550 }
3534 if (ch == '\\') { /* \x. Copy verbatim. Important for \(, \) */ 3551 if (ch == '\\') { /* \x. Copy verbatim. Important for \(, \) */
3535 ch = i_getch(input); 3552 ch = i_getch(input);
3536 if (ch == EOF) 3553 if (ch == EOF)
3537 break; 3554 break;
3538 o_addqchr(dest, ch); 3555 o_addchr(dest, ch);
3539 continue; 3556 continue;
3540 } 3557 }
3541 } 3558 }
diff --git a/shell/hush_test/hush-bugs/empty_for.right b/shell/hush_test/hush-bugs/empty_for.right
new file mode 100644
index 000000000..290d39b7e
--- /dev/null
+++ b/shell/hush_test/hush-bugs/empty_for.right
@@ -0,0 +1 @@
OK: 0
diff --git a/shell/hush_test/hush-bugs/empty_for.tests b/shell/hush_test/hush-bugs/empty_for.tests
new file mode 100755
index 000000000..0cb52e849
--- /dev/null
+++ b/shell/hush_test/hush-bugs/empty_for.tests
@@ -0,0 +1,3 @@
1false
2for a in; do echo "HELLO"; done
3echo OK: $?
diff --git a/shell/hush_test/hush-bugs/glob_and_vars.tests b/shell/hush_test/hush-bugs/glob_and_vars.tests
index c8e0c067d..482cf9d8a 100755
--- a/shell/hush_test/hush-bugs/glob_and_vars.tests
+++ b/shell/hush_test/hush-bugs/glob_and_vars.tests
@@ -1,2 +1,2 @@
1v=. 1v=.
2echo $v/glob_and_vars.* 2echo $v/glob_and_vars.[tr]*
diff --git a/shell/hush_test/hush-bugs/glob_and_vars.right b/shell/hush_test/hush-vars/glob_and_vars.right
index 3ac7ec5ff..3ac7ec5ff 100644
--- a/shell/hush_test/hush-bugs/glob_and_vars.right
+++ b/shell/hush_test/hush-vars/glob_and_vars.right
diff --git a/shell/hush_test/hush-vars/glob_and_vars.tests b/shell/hush_test/hush-vars/glob_and_vars.tests
new file mode 100755
index 000000000..482cf9d8a
--- /dev/null
+++ b/shell/hush_test/hush-vars/glob_and_vars.tests
@@ -0,0 +1,2 @@
1v=.
2echo $v/glob_and_vars.[tr]*