diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-17 07:24:29 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-17 07:24:29 +0000 |
commit | 30c9cc5b178932bc417846919eaa2fc1bf8e5996 (patch) | |
tree | 57e6d113f605411ee3fe272fdc0746d7f189f71c | |
parent | c7985b76c5174c4c224b67e29dd554443f80f47e (diff) | |
download | busybox-w32-30c9cc5b178932bc417846919eaa2fc1bf8e5996.tar.gz busybox-w32-30c9cc5b178932bc417846919eaa2fc1bf8e5996.tar.bz2 busybox-w32-30c9cc5b178932bc417846919eaa2fc1bf8e5996.zip |
hush: continue fixing quoting and subst: fix glob_and_assign.tests.
-rw-r--r-- | shell/hush.c | 73 | ||||
-rw-r--r-- | shell/hush_test/hush-bugs/glob_and_assign.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-bugs/glob_and_assign.tests | 26 | ||||
-rwxr-xr-x | shell/hush_test/run-all | 9 |
4 files changed, 65 insertions, 51 deletions
diff --git a/shell/hush.c b/shell/hush.c index e64cc476d..ae12ebec4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -106,6 +106,7 @@ | |||
106 | #define debug_printf_expand(...) do {} while (0) | 106 | #define debug_printf_expand(...) do {} while (0) |
107 | #define debug_printf_glob(...) do {} while (0) | 107 | #define debug_printf_glob(...) do {} while (0) |
108 | #define debug_printf_list(...) do {} while (0) | 108 | #define debug_printf_list(...) do {} while (0) |
109 | #define debug_printf_subst(...) do {} while (0) | ||
109 | #define debug_printf_clean(...) do {} while (0) | 110 | #define debug_printf_clean(...) do {} while (0) |
110 | 111 | ||
111 | #ifndef debug_printf | 112 | #ifndef debug_printf |
@@ -145,6 +146,10 @@ | |||
145 | #define debug_printf_list(...) fprintf(stderr, __VA_ARGS__) | 146 | #define debug_printf_list(...) fprintf(stderr, __VA_ARGS__) |
146 | #endif | 147 | #endif |
147 | 148 | ||
149 | #ifndef debug_printf_subst | ||
150 | #define debug_printf_subst(...) fprintf(stderr, __VA_ARGS__) | ||
151 | #endif | ||
152 | |||
148 | /* Keep unconditionally on for now */ | 153 | /* Keep unconditionally on for now */ |
149 | #define ENABLE_HUSH_DEBUG 1 | 154 | #define ENABLE_HUSH_DEBUG 1 |
150 | 155 | ||
@@ -516,8 +521,6 @@ static int run_list(struct pipe *pi); | |||
516 | static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN; | 521 | static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN; |
517 | static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN; | 522 | static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN; |
518 | static int run_pipe(struct pipe *pi); | 523 | static int run_pipe(struct pipe *pi); |
519 | /* variable assignment: */ | ||
520 | static int is_assignment(const char *s); | ||
521 | /* data structure manipulation: */ | 524 | /* data structure manipulation: */ |
522 | static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); | 525 | static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); |
523 | static void initialize_context(struct p_context *ctx); | 526 | static void initialize_context(struct p_context *ctx); |
@@ -573,6 +576,16 @@ static int glob_needed(const char *s) | |||
573 | return 0; | 576 | return 0; |
574 | } | 577 | } |
575 | 578 | ||
579 | static int is_assignment(const char *s) | ||
580 | { | ||
581 | if (!s || !isalpha(*s)) | ||
582 | return 0; | ||
583 | s++; | ||
584 | while (isalnum(*s) || *s == '_') | ||
585 | s++; | ||
586 | return *s == '='; | ||
587 | } | ||
588 | |||
576 | static char **add_malloced_strings_to_strings(char **strings, char **add) | 589 | static char **add_malloced_strings_to_strings(char **strings, char **add) |
577 | { | 590 | { |
578 | int i; | 591 | int i; |
@@ -938,7 +951,7 @@ static void o_addQstr(o_string *o, const char *str, int len) | |||
938 | if (ordinary_cnt == len) | 951 | if (ordinary_cnt == len) |
939 | return; | 952 | return; |
940 | str += ordinary_cnt; | 953 | str += ordinary_cnt; |
941 | len -= ordinary_cnt - 1; /* we are processing + 1 char below */ | 954 | len -= ordinary_cnt + 1; /* we are processing + 1 char below */ |
942 | 955 | ||
943 | ch = *str++; | 956 | ch = *str++; |
944 | sz = 1; | 957 | sz = 1; |
@@ -1000,7 +1013,7 @@ static int o_save_ptr_helper(o_string *o, int n) | |||
1000 | string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); | 1013 | string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); |
1001 | string_len = o->length - string_start; | 1014 | string_len = o->length - string_start; |
1002 | if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */ | 1015 | if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */ |
1003 | debug_printf_list("list[%d]=%d string_start=%d (growing)", n, string_len, string_start); | 1016 | debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start); |
1004 | /* list[n] points to string_start, make space for 16 more pointers */ | 1017 | /* list[n] points to string_start, make space for 16 more pointers */ |
1005 | o->maxlen += 0x10 * sizeof(list[0]); | 1018 | o->maxlen += 0x10 * sizeof(list[0]); |
1006 | o->data = xrealloc(o->data, o->maxlen + 1); | 1019 | o->data = xrealloc(o->data, o->maxlen + 1); |
@@ -1008,12 +1021,12 @@ static int o_save_ptr_helper(o_string *o, int n) | |||
1008 | memmove(list + n + 0x10, list + n, string_len); | 1021 | memmove(list + n + 0x10, list + n, string_len); |
1009 | o->length += 0x10 * sizeof(list[0]); | 1022 | o->length += 0x10 * sizeof(list[0]); |
1010 | } else | 1023 | } else |
1011 | debug_printf_list("list[%d]=%d string_start=%d", n, string_len, string_start); | 1024 | debug_printf_list("list[%d]=%d string_start=%d\n", n, string_len, string_start); |
1012 | } else { | 1025 | } else { |
1013 | /* We have empty slot at list[n], reuse without growth */ | 1026 | /* We have empty slot at list[n], reuse without growth */ |
1014 | string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */ | 1027 | string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */ |
1015 | string_len = o->length - string_start; | 1028 | string_len = o->length - string_start; |
1016 | debug_printf_list("list[%d]=%d string_start=%d (empty slot)", n, string_len, string_start); | 1029 | debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n", n, string_len, string_start); |
1017 | o->has_empty_slot = 0; | 1030 | o->has_empty_slot = 0; |
1018 | } | 1031 | } |
1019 | list[n] = (char*)string_len; | 1032 | list[n] = (char*)string_len; |
@@ -1048,15 +1061,15 @@ static int o_glob(o_string *o, int n) | |||
1048 | int gr; | 1061 | int gr; |
1049 | char *pattern; | 1062 | char *pattern; |
1050 | 1063 | ||
1051 | debug_printf_glob("start o_glob: n:%d o->data:%p", n, o->data); | 1064 | debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data); |
1052 | if (!o->data) | 1065 | if (!o->data) |
1053 | return o_save_ptr_helper(o, n); | 1066 | return o_save_ptr_helper(o, n); |
1054 | pattern = o->data + o_get_last_ptr(o, n); | 1067 | pattern = o->data + o_get_last_ptr(o, n); |
1055 | debug_printf_glob("glob pattern '%s'", pattern); | 1068 | debug_printf_glob("glob pattern '%s'\n", pattern); |
1056 | if (!glob_needed(pattern)) { | 1069 | if (!glob_needed(pattern)) { |
1057 | literal: | 1070 | literal: |
1058 | o->length = unbackslash(pattern) - o->data; | 1071 | o->length = unbackslash(pattern) - o->data; |
1059 | debug_printf_glob("glob pattern '%s' is literal", pattern); | 1072 | debug_printf_glob("glob pattern '%s' is literal\n", pattern); |
1060 | return o_save_ptr_helper(o, n); | 1073 | return o_save_ptr_helper(o, n); |
1061 | } | 1074 | } |
1062 | 1075 | ||
@@ -1108,7 +1121,7 @@ static char **o_finalize_list(o_string *o, int n) | |||
1108 | n = o_save_ptr(o, n); /* force growth for list[n] if necessary */ | 1121 | n = o_save_ptr(o, n); /* force growth for list[n] if necessary */ |
1109 | if (DEBUG_EXPAND) | 1122 | if (DEBUG_EXPAND) |
1110 | debug_print_list("finalized", o, n); | 1123 | debug_print_list("finalized", o, n); |
1111 | debug_printf_expand("finalized n:%d", n); | 1124 | debug_printf_expand("finalized n:%d\n", n); |
1112 | list = (char**)o->data; | 1125 | list = (char**)o->data; |
1113 | string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); | 1126 | string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); |
1114 | list[--n] = NULL; | 1127 | list[--n] = NULL; |
@@ -2285,7 +2298,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
2285 | while (1) { | 2298 | while (1) { |
2286 | int word_len = strcspn(str, ifs); | 2299 | int word_len = strcspn(str, ifs); |
2287 | if (word_len) { | 2300 | if (word_len) { |
2288 | o_addQstr(output, str, word_len); | 2301 | o_addstr(output, str, word_len); |
2289 | str += word_len; | 2302 | str += word_len; |
2290 | } | 2303 | } |
2291 | if (!*str) /* EOL - do not finalize word */ | 2304 | if (!*str) /* EOL - do not finalize word */ |
@@ -2328,7 +2341,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2328 | o_string subst_result = NULL_O_STRING; | 2341 | o_string subst_result = NULL_O_STRING; |
2329 | #endif | 2342 | #endif |
2330 | 2343 | ||
2331 | o_addQstr(output, arg, p - arg); | 2344 | o_addstr(output, arg, p - arg); |
2332 | debug_print_list("expand_vars_to_list[1]", output, n); | 2345 | debug_print_list("expand_vars_to_list[1]", output, n); |
2333 | arg = ++p; | 2346 | arg = ++p; |
2334 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 2347 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
@@ -2374,7 +2387,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2374 | * and in this case should treat it like '$*' - see 'else...' below */ | 2387 | * and in this case should treat it like '$*' - see 'else...' below */ |
2375 | if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ | 2388 | if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ |
2376 | while (1) { | 2389 | while (1) { |
2377 | o_addQstr(output, global_argv[i], strlen(global_argv[i])); | 2390 | o_addQstr(output, global_argv[i], strlen(global_argv[i])); ///really Q? |
2378 | if (++i >= global_argc) | 2391 | if (++i >= global_argc) |
2379 | break; | 2392 | break; |
2380 | o_addchr(output, '\0'); | 2393 | o_addchr(output, '\0'); |
@@ -2383,7 +2396,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2383 | } | 2396 | } |
2384 | } else { /* quoted $*: add as one word */ | 2397 | } else { /* quoted $*: add as one word */ |
2385 | while (1) { | 2398 | while (1) { |
2386 | o_addQstr(output, global_argv[i], strlen(global_argv[i])); | 2399 | o_addQstr(output, global_argv[i], strlen(global_argv[i])); ///really Q? |
2387 | if (!global_argv[++i]) | 2400 | if (!global_argv[++i]) |
2388 | break; | 2401 | break; |
2389 | if (ifs[0]) | 2402 | if (ifs[0]) |
@@ -2397,10 +2410,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2397 | *p = '\0'; | 2410 | *p = '\0'; |
2398 | arg++; | 2411 | arg++; |
2399 | //TODO: can we just stuff it into "output" directly? | 2412 | //TODO: can we just stuff it into "output" directly? |
2400 | //bb_error_msg("SUBST '%s' first_ch %x", arg, first_ch); | 2413 | debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); |
2401 | setup_string_in_str(&input, arg); | 2414 | setup_string_in_str(&input, arg); |
2402 | process_command_subs(&subst_result, &input, NULL); | 2415 | process_command_subs(&subst_result, &input, NULL); |
2403 | //bb_error_msg("RES '%s'", subst_result.data); | 2416 | debug_printf_subst("SUBST RES '%s'\n", subst_result.data); |
2404 | val = subst_result.data; | 2417 | val = subst_result.data; |
2405 | goto store_val; | 2418 | goto store_val; |
2406 | } | 2419 | } |
@@ -2421,14 +2434,16 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2421 | #endif | 2434 | #endif |
2422 | *p = SPECIAL_VAR_SYMBOL; | 2435 | *p = SPECIAL_VAR_SYMBOL; |
2423 | if (!(first_ch & 0x80)) { /* unquoted $VAR */ | 2436 | if (!(first_ch & 0x80)) { /* unquoted $VAR */ |
2437 | debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote); | ||
2424 | if (val) { | 2438 | if (val) { |
2425 | n = expand_on_ifs(output, n, val); | 2439 | n = expand_on_ifs(output, n, val); |
2426 | val = NULL; | 2440 | val = NULL; |
2427 | } | 2441 | } |
2428 | } /* else: quoted $VAR, val will be appended below */ | 2442 | } else /* quoted $VAR, val will be appended below */ |
2443 | debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); | ||
2429 | } | 2444 | } |
2430 | if (val) { | 2445 | if (val) { |
2431 | o_addQstr(output, val, strlen(val)); | 2446 | o_addQstr(output, val, strlen(val)); ///maybe q? |
2432 | } | 2447 | } |
2433 | 2448 | ||
2434 | #if ENABLE_HUSH_TICK | 2449 | #if ENABLE_HUSH_TICK |
@@ -2439,7 +2454,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2439 | 2454 | ||
2440 | if (arg[0]) { | 2455 | if (arg[0]) { |
2441 | debug_print_list("expand_vars_to_list[a]", output, n); | 2456 | debug_print_list("expand_vars_to_list[a]", output, n); |
2442 | o_addQstr(output, arg, strlen(arg) + 1); | 2457 | /* this part is literal, and it was already pre-quoted |
2458 | * if needed (much earlier), do not use o_addQstr here! */ | ||
2459 | o_addstr(output, arg, strlen(arg) + 1); | ||
2443 | debug_print_list("expand_vars_to_list[b]", output, n); | 2460 | debug_print_list("expand_vars_to_list[b]", output, n); |
2444 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ | 2461 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ |
2445 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ | 2462 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ |
@@ -2460,8 +2477,10 @@ static char **expand_variables(char **argv, int or_mask) | |||
2460 | char **v; | 2477 | char **v; |
2461 | o_string output = NULL_O_STRING; | 2478 | o_string output = NULL_O_STRING; |
2462 | 2479 | ||
2463 | if (or_mask & 0x100) | 2480 | if (or_mask & 0x100) { |
2481 | output.o_quote = 1; | ||
2464 | output.o_glob = 1; | 2482 | output.o_glob = 1; |
2483 | } | ||
2465 | 2484 | ||
2466 | n = 0; | 2485 | n = 0; |
2467 | v = argv; | 2486 | v = argv; |
@@ -2637,16 +2656,6 @@ static void unset_local_var(const char *name) | |||
2637 | } | 2656 | } |
2638 | } | 2657 | } |
2639 | 2658 | ||
2640 | static int is_assignment(const char *s) | ||
2641 | { | ||
2642 | if (!s || !isalpha(*s)) | ||
2643 | return 0; | ||
2644 | s++; | ||
2645 | while (isalnum(*s) || *s == '_') | ||
2646 | s++; | ||
2647 | return *s == '='; | ||
2648 | } | ||
2649 | |||
2650 | /* the src parameter allows us to peek forward to a possible &n syntax | 2659 | /* the src parameter allows us to peek forward to a possible &n syntax |
2651 | * for file descriptor duplication, e.g., "2>&1". | 2660 | * for file descriptor duplication, e.g., "2>&1". |
2652 | * Return code is 0 normally, 1 if a syntax error is detected in src. | 2661 | * Return code is 0 normally, 1 if a syntax error is detected in src. |
@@ -3341,7 +3350,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
3341 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3350 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3342 | o_addchr(dest, quote_mask | '`'); | 3351 | o_addchr(dest, quote_mask | '`'); |
3343 | add_till_closing_curly_brace(dest, input); | 3352 | add_till_closing_curly_brace(dest, input); |
3344 | //bb_error_msg("RES '%s'", dest->data + pos); | 3353 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); |
3345 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3354 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3346 | break; | 3355 | break; |
3347 | } | 3356 | } |
@@ -3496,7 +3505,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3496 | o_addchr(dest, dest->o_quote ? 0x80 | '`' : '`'); | 3505 | o_addchr(dest, dest->o_quote ? 0x80 | '`' : '`'); |
3497 | add_till_backquote(dest, input); | 3506 | add_till_backquote(dest, input); |
3498 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3507 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3499 | //bb_error_msg("RES '%s'", dest->data + pos); | 3508 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); |
3500 | break; | 3509 | break; |
3501 | } | 3510 | } |
3502 | #endif | 3511 | #endif |
diff --git a/shell/hush_test/hush-bugs/glob_and_assign.right b/shell/hush_test/hush-bugs/glob_and_assign.right index dae832361..d46e44363 100644 --- a/shell/hush_test/hush-bugs/glob_and_assign.right +++ b/shell/hush_test/hush-bugs/glob_and_assign.right | |||
@@ -1,2 +1,6 @@ | |||
1 | ZVAR=z.map | 1 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp |
2 | *.map | 2 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp |
3 | *.tmp | ||
4 | ZVAR=z.tmp z.tmp | ||
5 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
6 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
diff --git a/shell/hush_test/hush-bugs/glob_and_assign.tests b/shell/hush_test/hush-bugs/glob_and_assign.tests index ea11e364b..0b158f20f 100755 --- a/shell/hush_test/hush-bugs/glob_and_assign.tests +++ b/shell/hush_test/hush-bugs/glob_and_assign.tests | |||
@@ -1,18 +1,10 @@ | |||
1 | ## # bash zbad2 | 1 | >ZVAR=z.tmp |
2 | ## ZVAR=z.map | 2 | >z.tmp |
3 | ## *.map | 3 | ZVAR=*.tmp echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" |
4 | ## # hush zbad2 | 4 | ZVAR=*.tmp /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" |
5 | ## ZVAR=z.map | 5 | ZVAR=*.tmp |
6 | ## z.map <====== !!! | ||
7 | |||
8 | ## hush does globbing for "VAR=val" too! | ||
9 | ## it should do it only for non-assignments. | ||
10 | ## even if word looks like assignment, it can be non-assignment: | ||
11 | ## ZVAR=*.map /bin/echo ZVAR=*.map | ||
12 | ## ^dont_glob ^glob | ||
13 | |||
14 | >ZVAR=z.map | ||
15 | ZVAR=*.map /bin/echo ZVAR=*.map | ||
16 | ZVAR=*.map | ||
17 | echo "$ZVAR" | 6 | echo "$ZVAR" |
18 | rm ZVAR=z.map | 7 | echo $ZVAR |
8 | echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
9 | /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
10 | rm ZVAR=z.tmp z.tmp | ||
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 5cec85af6..b79af2f67 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all | |||
@@ -1,5 +1,14 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | 2 | ||
3 | unset LANG LANGUAGE | ||
4 | unset LC_COLLATE | ||
5 | unset LC_CTYPE | ||
6 | unset LC_MONETARY | ||
7 | unset LC_MESSAGES | ||
8 | unset LC_NUMERIC | ||
9 | unset LC_TIME | ||
10 | unset LC_ALL | ||
11 | |||
3 | test -x hush || { | 12 | test -x hush || { |
4 | echo "No ./hush - creating a link to ../../busybox" | 13 | echo "No ./hush - creating a link to ../../busybox" |
5 | ln -s ../../busybox hush | 14 | ln -s ../../busybox hush |