diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-04 19:52:44 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-04 19:52:44 +0200 |
commit | e298ce69baef029f3951dd1d5ed50fdbc6c55c80 (patch) | |
tree | 85060a1578474d8ca4e1d5f89e1b0c8241235ba5 | |
parent | 8ae6e9be5c1c7e7a1e9ce96f463c7d6ab1c9500f (diff) | |
download | busybox-w32-e298ce69baef029f3951dd1d5ed50fdbc6c55c80.tar.gz busybox-w32-e298ce69baef029f3951dd1d5ed50fdbc6c55c80.tar.bz2 busybox-w32-e298ce69baef029f3951dd1d5ed50fdbc6c55c80.zip |
hush: fix handling of backslashes in variable assignment
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rwxr-xr-x | shell/ash_test/ash-vars/var_bash5.tests | 4 | ||||
-rw-r--r-- | shell/hush.c | 43 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_unbackslash.right | 11 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_unbackslash.tests | 23 | ||||
-rw-r--r-- | shell/match.c | 34 |
5 files changed, 74 insertions, 41 deletions
diff --git a/shell/ash_test/ash-vars/var_bash5.tests b/shell/ash_test/ash-vars/var_bash5.tests index 3f49321e1..7f482a554 100755 --- a/shell/ash_test/ash-vars/var_bash5.tests +++ b/shell/ash_test/ash-vars/var_bash5.tests | |||
@@ -1,5 +1,5 @@ | |||
1 | # This testcase checks whether slashes in ${v/a/b} are parsed before or after expansions | 1 | # This testcase checks whether slashes in ${v/a/b} are parsed before |
2 | # in a part | 2 | # or after expansions |
3 | 3 | ||
4 | v='a/b/c' | 4 | v='a/b/c' |
5 | s='b/c' | 5 | s='b/c' |
diff --git a/shell/hush.c b/shell/hush.c index e8dfb2499..d3dab5863 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -390,6 +390,7 @@ typedef struct o_string { | |||
390 | smallint o_glob; | 390 | smallint o_glob; |
391 | /* At least some part of the string was inside '' or "", | 391 | /* At least some part of the string was inside '' or "", |
392 | * possibly empty one: word"", wo''rd etc. */ | 392 | * possibly empty one: word"", wo''rd etc. */ |
393 | //TODO: rename to no_empty_expansion? | ||
393 | smallint o_quoted; | 394 | smallint o_quoted; |
394 | smallint has_empty_slot; | 395 | smallint has_empty_slot; |
395 | smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ | 396 | smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ |
@@ -2018,11 +2019,10 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len | |||
2018 | { | 2019 | { |
2019 | while (len) { | 2020 | while (len) { |
2020 | o_addchr(o, *str); | 2021 | o_addchr(o, *str); |
2021 | if (*str++ == '\\' | 2022 | if (*str == '\\') { |
2022 | && (*str != '*' && *str != '?' && *str != '[') | ||
2023 | ) { | ||
2024 | o_addchr(o, '\\'); | 2023 | o_addchr(o, '\\'); |
2025 | } | 2024 | } |
2025 | str++; | ||
2026 | len--; | 2026 | len--; |
2027 | } | 2027 | } |
2028 | } | 2028 | } |
@@ -2128,8 +2128,8 @@ static void debug_print_list(const char *prefix, o_string *o, int n) | |||
2128 | int i = 0; | 2128 | int i = 0; |
2129 | 2129 | ||
2130 | indent(); | 2130 | indent(); |
2131 | fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d\n", | 2131 | fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", |
2132 | prefix, list, n, string_start, o->length, o->maxlen); | 2132 | prefix, list, n, string_start, o->length, o->maxlen, o->o_glob, o->o_quoted, o->o_escape); |
2133 | while (i < n) { | 2133 | while (i < n) { |
2134 | indent(); | 2134 | indent(); |
2135 | fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], | 2135 | fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], |
@@ -2563,9 +2563,9 @@ static char *expand_pseudo_dquoted(const char *str) | |||
2563 | struct in_str input; | 2563 | struct in_str input; |
2564 | o_string dest = NULL_O_STRING; | 2564 | o_string dest = NULL_O_STRING; |
2565 | 2565 | ||
2566 | if (strchr(str, '$') == NULL | 2566 | if (!strchr(str, '$') |
2567 | #if ENABLE_HUSH_TICK | 2567 | #if ENABLE_HUSH_TICK |
2568 | && strchr(str, '`') == NULL | 2568 | && !strchr(str, '`') |
2569 | #endif | 2569 | #endif |
2570 | ) { | 2570 | ) { |
2571 | return NULL; | 2571 | return NULL; |
@@ -2740,6 +2740,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2740 | } | 2740 | } |
2741 | #endif | 2741 | #endif |
2742 | default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ | 2742 | default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ |
2743 | //TODO: move to a subroutine? | ||
2743 | char *var; | 2744 | char *var; |
2744 | char first_char; | 2745 | char first_char; |
2745 | char exp_op; | 2746 | char exp_op; |
@@ -3000,18 +3001,22 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
3000 | return n; | 3001 | return n; |
3001 | } | 3002 | } |
3002 | 3003 | ||
3003 | static char **expand_variables(char **argv, int or_mask) | 3004 | enum { |
3005 | EXPVAR_FLAG_GLOB = 0x200, | ||
3006 | EXPVAR_FLAG_ESCAPE_VARS = 0x100, | ||
3007 | EXPVAR_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ | ||
3008 | }; | ||
3009 | static char **expand_variables(char **argv, unsigned or_mask) | ||
3004 | { | 3010 | { |
3005 | int n; | 3011 | int n; |
3006 | char **list; | 3012 | char **list; |
3007 | char **v; | 3013 | char **v; |
3008 | o_string output = NULL_O_STRING; | 3014 | o_string output = NULL_O_STRING; |
3009 | 3015 | ||
3010 | if (or_mask & 0x100) { | 3016 | /* protect against globbing for "$var"? */ |
3011 | output.o_escape = 1; /* protect against globbing for "$var" */ | 3017 | /* (unquoted $var will temporarily switch it off) */ |
3012 | /* (unquoted $var will temporarily switch it off) */ | 3018 | output.o_escape = 1 & (or_mask / EXPVAR_FLAG_ESCAPE_VARS); |
3013 | output.o_glob = 1; | 3019 | output.o_glob = 1 & (or_mask / EXPVAR_FLAG_GLOB); |
3014 | } | ||
3015 | 3020 | ||
3016 | n = 0; | 3021 | n = 0; |
3017 | v = argv; | 3022 | v = argv; |
@@ -3029,13 +3034,13 @@ static char **expand_variables(char **argv, int or_mask) | |||
3029 | 3034 | ||
3030 | static char **expand_strvec_to_strvec(char **argv) | 3035 | static char **expand_strvec_to_strvec(char **argv) |
3031 | { | 3036 | { |
3032 | return expand_variables(argv, 0x100); | 3037 | return expand_variables(argv, EXPVAR_FLAG_GLOB | EXPVAR_FLAG_ESCAPE_VARS); |
3033 | } | 3038 | } |
3034 | 3039 | ||
3035 | #if ENABLE_HUSH_BASH_COMPAT | 3040 | #if ENABLE_HUSH_BASH_COMPAT |
3036 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | 3041 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) |
3037 | { | 3042 | { |
3038 | return expand_variables(argv, 0x80); | 3043 | return expand_variables(argv, EXPVAR_FLAG_SINGLEWORD); |
3039 | } | 3044 | } |
3040 | #endif | 3045 | #endif |
3041 | 3046 | ||
@@ -3075,15 +3080,15 @@ static char **expand_strvec_to_strvec_singleword_noglob_cond(char **argv) | |||
3075 | #endif | 3080 | #endif |
3076 | 3081 | ||
3077 | /* Used for expansion of right hand of assignments */ | 3082 | /* Used for expansion of right hand of assignments */ |
3078 | /* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs | 3083 | /* NB: should NOT do globbing! |
3079 | * "v=/bin/c*" */ | 3084 | * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */ |
3080 | static char *expand_string_to_string(const char *str) | 3085 | static char *expand_string_to_string(const char *str) |
3081 | { | 3086 | { |
3082 | char *argv[2], **list; | 3087 | char *argv[2], **list; |
3083 | 3088 | ||
3084 | argv[0] = (char*)str; | 3089 | argv[0] = (char*)str; |
3085 | argv[1] = NULL; | 3090 | argv[1] = NULL; |
3086 | list = expand_variables(argv, 0x80); /* 0x80: singleword expansion */ | 3091 | list = expand_variables(argv, EXPVAR_FLAG_ESCAPE_VARS | EXPVAR_FLAG_SINGLEWORD); |
3087 | if (HUSH_DEBUG) | 3092 | if (HUSH_DEBUG) |
3088 | if (!list[0] || list[1]) | 3093 | if (!list[0] || list[1]) |
3089 | bb_error_msg_and_die("BUG in varexp2"); | 3094 | bb_error_msg_and_die("BUG in varexp2"); |
@@ -3099,7 +3104,7 @@ static char* expand_strvec_to_string(char **argv) | |||
3099 | { | 3104 | { |
3100 | char **list; | 3105 | char **list; |
3101 | 3106 | ||
3102 | list = expand_variables(argv, 0x80); | 3107 | list = expand_variables(argv, EXPVAR_FLAG_SINGLEWORD); |
3103 | /* Convert all NULs to spaces */ | 3108 | /* Convert all NULs to spaces */ |
3104 | if (list[0]) { | 3109 | if (list[0]) { |
3105 | int n = 1; | 3110 | int n = 1; |
diff --git a/shell/hush_test/hush-vars/var_unbackslash.right b/shell/hush_test/hush-vars/var_unbackslash.right new file mode 100644 index 000000000..20c2ddf55 --- /dev/null +++ b/shell/hush_test/hush-vars/var_unbackslash.right | |||
@@ -0,0 +1,11 @@ | |||
1 | b1=-qwerty-t-\-"---z-*-?- | ||
2 | b1=-qwerty-t-\-"---z-*-?- | ||
3 | b2=-qwerty-\t-\-"-\--\z-\*-\?- | ||
4 | b2=-qwerty-\t-\-"-\--\z-\*-\?- | ||
5 | b3=-$a-\t-\\-\"-\--\z-\*-\?- | ||
6 | b3=-$a-\t-\\-\"-\--\z-\*-\?- | ||
7 | c=-$a-\t-\\-\"-\--\z-\*-\?- | ||
8 | c=-$a-\t-\\-\"-\--\z-\*-\?- | ||
9 | c=-$a-\t-\\-\"-\--\z-\*-\?- | ||
10 | c=-$a-\t-\\-\"-\--\z-\*-\?- | ||
11 | Done: 0 | ||
diff --git a/shell/hush_test/hush-vars/var_unbackslash.tests b/shell/hush_test/hush-vars/var_unbackslash.tests new file mode 100755 index 000000000..3c35d7df5 --- /dev/null +++ b/shell/hush_test/hush-vars/var_unbackslash.tests | |||
@@ -0,0 +1,23 @@ | |||
1 | # Test for correct handling of backslashes | ||
2 | a=qwerty | ||
3 | |||
4 | b=-$a-\t-\\-\"-\--\z-\*-\?- | ||
5 | echo b1=$b | ||
6 | echo "b1=$b" | ||
7 | b="-$a-\t-\\-\"-\--\z-\*-\?-" | ||
8 | echo b2=$b | ||
9 | echo "b2=$b" | ||
10 | b='-$a-\t-\\-\"-\--\z-\*-\?-' | ||
11 | echo b3=$b | ||
12 | echo "b3=$b" | ||
13 | |||
14 | c=$b | ||
15 | echo "c=$c" | ||
16 | c=${b} | ||
17 | echo "c=$c" | ||
18 | c="$b" | ||
19 | echo "c=$c" | ||
20 | c="${b}" | ||
21 | echo "c=$c" | ||
22 | |||
23 | echo "Done: $?" | ||
diff --git a/shell/match.c b/shell/match.c index 8b1ddacd5..01b843918 100644 --- a/shell/match.c +++ b/shell/match.c | |||
@@ -31,26 +31,23 @@ char *scanleft(char *string, char *pattern, bool match_at_left) | |||
31 | char c; | 31 | char c; |
32 | char *loc = string; | 32 | char *loc = string; |
33 | 33 | ||
34 | do { | 34 | while (1) { |
35 | int match; | 35 | int match; |
36 | const char *s; | ||
37 | 36 | ||
38 | c = *loc; | 37 | c = *loc; |
39 | if (match_at_left) { | 38 | if (match_at_left) { |
40 | *loc = '\0'; | 39 | *loc = '\0'; |
41 | s = string; | 40 | match = pmatch(pattern, string); |
42 | } else | 41 | *loc = c; |
43 | s = loc; | 42 | } else { |
44 | match = pmatch(pattern, s); | 43 | match = pmatch(pattern, loc); |
45 | *loc = c; | 44 | } |
46 | |||
47 | if (match) | 45 | if (match) |
48 | return loc; | 46 | return loc; |
49 | 47 | if (!c) | |
48 | return NULL; | ||
50 | loc++; | 49 | loc++; |
51 | } while (c); | 50 | } |
52 | |||
53 | return NULL; | ||
54 | } | 51 | } |
55 | 52 | ||
56 | char *scanright(char *string, char *pattern, bool match_at_left) | 53 | char *scanright(char *string, char *pattern, bool match_at_left) |
@@ -60,20 +57,17 @@ char *scanright(char *string, char *pattern, bool match_at_left) | |||
60 | 57 | ||
61 | while (loc >= string) { | 58 | while (loc >= string) { |
62 | int match; | 59 | int match; |
63 | const char *s; | ||
64 | 60 | ||
65 | c = *loc; | 61 | c = *loc; |
66 | if (match_at_left) { | 62 | if (match_at_left) { |
67 | *loc = '\0'; | 63 | *loc = '\0'; |
68 | s = string; | 64 | match = pmatch(pattern, string); |
69 | } else | 65 | *loc = c; |
70 | s = loc; | 66 | } else { |
71 | match = pmatch(pattern, s); | 67 | match = pmatch(pattern, loc); |
72 | *loc = c; | 68 | } |
73 | |||
74 | if (match) | 69 | if (match) |
75 | return loc; | 70 | return loc; |
76 | |||
77 | loc--; | 71 | loc--; |
78 | } | 72 | } |
79 | 73 | ||