diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-26 15:29:13 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-26 15:32:46 +0200 |
commit | b278d82c61ab5125b5c7e350b264c1f3d52d682b (patch) | |
tree | f2c0a2c2bd630b22f7eebee1d63eb810e480b4e5 | |
parent | 05c5d745f7b14e265144489b7809a3d6dbbadec6 (diff) | |
download | busybox-w32-b278d82c61ab5125b5c7e350b264c1f3d52d682b.tar.gz busybox-w32-b278d82c61ab5125b5c7e350b264c1f3d52d682b.tar.bz2 busybox-w32-b278d82c61ab5125b5c7e350b264c1f3d52d682b.zip |
hush: implement $'str' bashism
function old new delta
parse_dollar_squote - 441 +441
encode_then_expand_vararg 359 380 +21
parse_stream 2252 2271 +19
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 481/0) Total: 481 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 103 | ||||
-rw-r--r-- | shell/hush_test/hush-quoting/dollar_squote_bash1.right | 10 | ||||
-rwxr-xr-x | shell/hush_test/hush-quoting/dollar_squote_bash1.tests | 8 | ||||
-rw-r--r-- | shell/hush_test/hush-quoting/dollar_squote_bash2.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-quoting/dollar_squote_bash2.tests | 10 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_bash7.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_bash7.tests | 1 |
7 files changed, 138 insertions, 1 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1aa0a400d..af6a9a73e 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -384,6 +384,7 @@ | |||
384 | #define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT | 384 | #define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT |
385 | #define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT | 385 | #define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT |
386 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT | 386 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT |
387 | #define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT | ||
387 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT | 388 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT |
388 | #define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT | 389 | #define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT |
389 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | 390 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) |
@@ -4919,6 +4920,100 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
4919 | } | 4920 | } |
4920 | #endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */ | 4921 | #endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */ |
4921 | 4922 | ||
4923 | #if BASH_DOLLAR_SQUOTE | ||
4924 | /* Return code: 1 for "found and parsed", 0 for "seen something else" */ | ||
4925 | #if BB_MMU | ||
4926 | #define parse_dollar_squote(as_string, dest, input) \ | ||
4927 | parse_dollar_squote(dest, input) | ||
4928 | #define as_string NULL | ||
4929 | #endif | ||
4930 | static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input) | ||
4931 | { | ||
4932 | int start; | ||
4933 | int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */ | ||
4934 | debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch); | ||
4935 | if (ch != '\'') | ||
4936 | return 0; | ||
4937 | |||
4938 | dest->has_quoted_part = 1; | ||
4939 | start = dest->length; | ||
4940 | |||
4941 | ch = i_getch(input); /* eat ' */ | ||
4942 | nommu_addchr(as_string, ch); | ||
4943 | while (1) { | ||
4944 | ch = i_getch(input); | ||
4945 | nommu_addchr(as_string, ch); | ||
4946 | if (ch == EOF) { | ||
4947 | syntax_error_unterm_ch('\''); | ||
4948 | return 0; | ||
4949 | } | ||
4950 | if (ch == '\'') | ||
4951 | break; | ||
4952 | if (ch == SPECIAL_VAR_SYMBOL) { | ||
4953 | /* Convert raw ^C to corresponding special variable reference */ | ||
4954 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
4955 | o_addchr(dest, SPECIAL_VAR_QUOTED_SVS); | ||
4956 | /* will addchr() another SPECIAL_VAR_SYMBOL (see after the if() block) */ | ||
4957 | } else if (ch == '\\') { | ||
4958 | static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567"; | ||
4959 | |||
4960 | ch = i_getch(input); | ||
4961 | nommu_addchr(as_string, ch); | ||
4962 | if (strchr(C_escapes, ch)) { | ||
4963 | char buf[4]; | ||
4964 | char *p = buf; | ||
4965 | int cnt = 2; | ||
4966 | |||
4967 | buf[0] = ch; | ||
4968 | if ((unsigned char)(ch - '0') <= 7) { /* \ooo */ | ||
4969 | do { | ||
4970 | ch = i_peek(input); | ||
4971 | if ((unsigned char)(ch - '0') > 7) | ||
4972 | break; | ||
4973 | *++p = ch = i_getch(input); | ||
4974 | nommu_addchr(as_string, ch); | ||
4975 | } while (--cnt != 0); | ||
4976 | } else if (ch == 'x') { /* \xHH */ | ||
4977 | do { | ||
4978 | ch = i_peek(input); | ||
4979 | if (!isxdigit(ch)) | ||
4980 | break; | ||
4981 | *++p = ch = i_getch(input); | ||
4982 | nommu_addchr(as_string, ch); | ||
4983 | } while (--cnt != 0); | ||
4984 | if (cnt == 2) { /* \x but next char is "bad" */ | ||
4985 | ch = 'x'; | ||
4986 | goto unrecognized; | ||
4987 | } | ||
4988 | } /* else simple seq like \\ or \t */ | ||
4989 | *++p = '\0'; | ||
4990 | p = buf; | ||
4991 | ch = bb_process_escape_sequence((void*)&p); | ||
4992 | //bb_error_msg("buf:'%s' ch:%x", buf, ch); | ||
4993 | if (ch == '\0') | ||
4994 | continue; /* bash compat: $'...\0...' emits nothing */ | ||
4995 | } else { /* unrecognized "\z": encode both chars unless ' or " */ | ||
4996 | if (ch != '\'' && ch != '"') { | ||
4997 | unrecognized: | ||
4998 | o_addqchr(dest, '\\'); | ||
4999 | } | ||
5000 | } | ||
5001 | } /* if (\...) */ | ||
5002 | o_addqchr(dest, ch); | ||
5003 | } | ||
5004 | |||
5005 | if (dest->length == start) { | ||
5006 | /* $'', $'\0', $'\000\x00' and the like */ | ||
5007 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
5008 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
5009 | } | ||
5010 | |||
5011 | return 1; | ||
5012 | } | ||
5013 | #else | ||
5014 | # #define parse_dollar_squote(as_string, dest, input) 0 | ||
5015 | #endif /* BASH_DOLLAR_SQUOTE */ | ||
5016 | |||
4922 | /* Return code: 0 for OK, 1 for syntax error */ | 5017 | /* Return code: 0 for OK, 1 for syntax error */ |
4923 | #if BB_MMU | 5018 | #if BB_MMU |
4924 | #define parse_dollar(as_string, dest, input, quote_mask) \ | 5019 | #define parse_dollar(as_string, dest, input, quote_mask) \ |
@@ -4931,7 +5026,7 @@ static int parse_dollar(o_string *as_string, | |||
4931 | { | 5026 | { |
4932 | int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */ | 5027 | int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */ |
4933 | 5028 | ||
4934 | debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); | 5029 | debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask); |
4935 | if (isalpha(ch)) { | 5030 | if (isalpha(ch)) { |
4936 | make_var: | 5031 | make_var: |
4937 | ch = i_getch(input); | 5032 | ch = i_getch(input); |
@@ -5247,6 +5342,8 @@ static int encode_string(o_string *as_string, | |||
5247 | goto again; | 5342 | goto again; |
5248 | } | 5343 | } |
5249 | if (ch == '$') { | 5344 | if (ch == '$') { |
5345 | //if (parse_dollar_squote(as_string, dest, input)) | ||
5346 | // goto again; | ||
5250 | if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { | 5347 | if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { |
5251 | debug_printf_parse("encode_string return 0: " | 5348 | debug_printf_parse("encode_string return 0: " |
5252 | "parse_dollar returned 0 (error)\n"); | 5349 | "parse_dollar returned 0 (error)\n"); |
@@ -5723,6 +5820,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5723 | o_addchr(&ctx.word, ch); | 5820 | o_addchr(&ctx.word, ch); |
5724 | continue; /* get next char */ | 5821 | continue; /* get next char */ |
5725 | case '$': | 5822 | case '$': |
5823 | if (parse_dollar_squote(&ctx.as_string, &ctx.word, input)) | ||
5824 | continue; /* get next char */ | ||
5726 | if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { | 5825 | if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { |
5727 | debug_printf_parse("parse_stream parse error: " | 5826 | debug_printf_parse("parse_stream parse error: " |
5728 | "parse_dollar returned 0 (error)\n"); | 5827 | "parse_dollar returned 0 (error)\n"); |
@@ -6166,6 +6265,8 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int | |||
6166 | continue; | 6265 | continue; |
6167 | } | 6266 | } |
6168 | if (ch == '$') { | 6267 | if (ch == '$') { |
6268 | if (parse_dollar_squote(NULL, &dest, &input)) | ||
6269 | continue; | ||
6169 | if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) { | 6270 | if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) { |
6170 | debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__); | 6271 | debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__); |
6171 | goto ret; | 6272 | goto ret; |
diff --git a/shell/hush_test/hush-quoting/dollar_squote_bash1.right b/shell/hush_test/hush-quoting/dollar_squote_bash1.right new file mode 100644 index 000000000..9f4e25efa --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_squote_bash1.right | |||
@@ -0,0 +1,10 @@ | |||
1 | a b | ||
2 | $'a\tb' | ||
3 | a | ||
4 | b c | ||
5 | def | ||
6 | a'b c"d e\f | ||
7 | a3b c3b e33f | ||
8 | a\80b c08b | ||
9 | a3b c30b | ||
10 | x y | ||
diff --git a/shell/hush_test/hush-quoting/dollar_squote_bash1.tests b/shell/hush_test/hush-quoting/dollar_squote_bash1.tests new file mode 100755 index 000000000..6fc411b93 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_squote_bash1.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | echo $'a\tb' | ||
2 | echo "$'a\tb'" | ||
3 | echo $'a\nb' $'c\nd''ef' | ||
4 | echo $'a\'b' $'c\"d' $'e\\f' | ||
5 | echo $'a\63b' $'c\063b' $'e\0633f' | ||
6 | echo $'a\80b' $'c\608b' | ||
7 | echo $'a\x33b' $'c\x330b' | ||
8 | echo $'x\x9y' | ||
diff --git a/shell/hush_test/hush-quoting/dollar_squote_bash2.right b/shell/hush_test/hush-quoting/dollar_squote_bash2.right new file mode 100644 index 000000000..f7a1731dd --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_squote_bash2.right | |||
@@ -0,0 +1,6 @@ | |||
1 | strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||
2 | strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||
3 | 80:\ | ||
4 | 81:\ | ||
5 | 82:\ | ||
6 | Done:0 | ||
diff --git a/shell/hush_test/hush-quoting/dollar_squote_bash2.tests b/shell/hush_test/hush-quoting/dollar_squote_bash2.tests new file mode 100755 index 000000000..449772813 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_squote_bash2.tests | |||
@@ -0,0 +1,10 @@ | |||
1 | # Embedded NULs | ||
2 | echo $'str\x00'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||
3 | echo $'str\000'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||
4 | |||
5 | # The chars after '\' are hex 0x80,81,82... | ||
6 | echo 80:$'\' | ||
7 | echo 81:$'\' | ||
8 | echo 82:$'\' | ||
9 | |||
10 | echo Done:$? | ||
diff --git a/shell/hush_test/hush-vars/var_bash7.right b/shell/hush_test/hush-vars/var_bash7.right new file mode 100644 index 000000000..223b7836f --- /dev/null +++ b/shell/hush_test/hush-vars/var_bash7.right | |||
@@ -0,0 +1 @@ | |||
B | |||
diff --git a/shell/hush_test/hush-vars/var_bash7.tests b/shell/hush_test/hush-vars/var_bash7.tests new file mode 100755 index 000000000..c4ce03f7f --- /dev/null +++ b/shell/hush_test/hush-vars/var_bash7.tests | |||
@@ -0,0 +1 @@ | |||
x=AB; echo "${x#$'\x41'}" | |||