summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-07-26 15:29:13 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-07-26 15:32:46 +0200
commitb278d82c61ab5125b5c7e350b264c1f3d52d682b (patch)
treef2c0a2c2bd630b22f7eebee1d63eb810e480b4e5
parent05c5d745f7b14e265144489b7809a3d6dbbadec6 (diff)
downloadbusybox-b278d82c61ab5125b5c7e350b264c1f3d52d682b.tar.gz
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.c103
-rw-r--r--shell/hush_test/hush-quoting/dollar_squote_bash1.right10
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_squote_bash1.tests8
-rw-r--r--shell/hush_test/hush-quoting/dollar_squote_bash2.right6
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_squote_bash2.tests10
-rw-r--r--shell/hush_test/hush-vars/var_bash7.right1
-rwxr-xr-xshell/hush_test/hush-vars/var_bash7.tests1
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 @@
#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
+#define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT
#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
#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
}
#endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */
+#if BASH_DOLLAR_SQUOTE
+/* Return code: 1 for "found and parsed", 0 for "seen something else" */
+#if BB_MMU
+#define parse_dollar_squote(as_string, dest, input) \
+ parse_dollar_squote(dest, input)
+#define as_string NULL
+#endif
+static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input)
+{
+ int start;
+ int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
+ debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch);
+ if (ch != '\'')
+ return 0;
+
+ dest->has_quoted_part = 1;
+ start = dest->length;
+
+ ch = i_getch(input); /* eat ' */
+ nommu_addchr(as_string, ch);
+ while (1) {
+ ch = i_getch(input);
+ nommu_addchr(as_string, ch);
+ if (ch == EOF) {
+ syntax_error_unterm_ch('\'');
+ return 0;
+ }
+ if (ch == '\'')
+ break;
+ if (ch == SPECIAL_VAR_SYMBOL) {
+ /* Convert raw ^C to corresponding special variable reference */
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
+ /* will addchr() another SPECIAL_VAR_SYMBOL (see after the if() block) */
+ } else if (ch == '\\') {
+ static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
+
+ ch = i_getch(input);
+ nommu_addchr(as_string, ch);
+ if (strchr(C_escapes, ch)) {
+ char buf[4];
+ char *p = buf;
+ int cnt = 2;
+
+ buf[0] = ch;
+ if ((unsigned char)(ch - '0') <= 7) { /* \ooo */
+ do {
+ ch = i_peek(input);
+ if ((unsigned char)(ch - '0') > 7)
+ break;
+ *++p = ch = i_getch(input);
+ nommu_addchr(as_string, ch);
+ } while (--cnt != 0);
+ } else if (ch == 'x') { /* \xHH */
+ do {
+ ch = i_peek(input);
+ if (!isxdigit(ch))
+ break;
+ *++p = ch = i_getch(input);
+ nommu_addchr(as_string, ch);
+ } while (--cnt != 0);
+ if (cnt == 2) { /* \x but next char is "bad" */
+ ch = 'x';
+ goto unrecognized;
+ }
+ } /* else simple seq like \\ or \t */
+ *++p = '\0';
+ p = buf;
+ ch = bb_process_escape_sequence((void*)&p);
+ //bb_error_msg("buf:'%s' ch:%x", buf, ch);
+ if (ch == '\0')
+ continue; /* bash compat: $'...\0...' emits nothing */
+ } else { /* unrecognized "\z": encode both chars unless ' or " */
+ if (ch != '\'' && ch != '"') {
+ unrecognized:
+ o_addqchr(dest, '\\');
+ }
+ }
+ } /* if (\...) */
+ o_addqchr(dest, ch);
+ }
+
+ if (dest->length == start) {
+ /* $'', $'\0', $'\000\x00' and the like */
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ }
+
+ return 1;
+}
+#else
+# #define parse_dollar_squote(as_string, dest, input) 0
+#endif /* BASH_DOLLAR_SQUOTE */
+
/* Return code: 0 for OK, 1 for syntax error */
#if BB_MMU
#define parse_dollar(as_string, dest, input, quote_mask) \
@@ -4931,7 +5026,7 @@ static int parse_dollar(o_string *as_string,
{
int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
- debug_printf_parse("parse_dollar entered: ch='%c'\n", ch);
+ debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask);
if (isalpha(ch)) {
make_var:
ch = i_getch(input);
@@ -5247,6 +5342,8 @@ static int encode_string(o_string *as_string,
goto again;
}
if (ch == '$') {
+ //if (parse_dollar_squote(as_string, dest, input))
+ // goto again;
if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
debug_printf_parse("encode_string return 0: "
"parse_dollar returned 0 (error)\n");
@@ -5723,6 +5820,8 @@ static struct pipe *parse_stream(char **pstring,
o_addchr(&ctx.word, ch);
continue; /* get next char */
case '$':
+ if (parse_dollar_squote(&ctx.as_string, &ctx.word, input))
+ continue; /* get next char */
if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
debug_printf_parse("parse_stream parse error: "
"parse_dollar returned 0 (error)\n");
@@ -6166,6 +6265,8 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int
continue;
}
if (ch == '$') {
+ if (parse_dollar_squote(NULL, &dest, &input))
+ continue;
if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
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 @@
+a b
+$'a\tb'
+a
+b c
+def
+a'b c"d e\f
+a3b c3b e33f
+a\80b c08b
+a3b c30b
+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 @@
+echo $'a\tb'
+echo "$'a\tb'"
+echo $'a\nb' $'c\nd''ef'
+echo $'a\'b' $'c\"d' $'e\\f'
+echo $'a\63b' $'c\063b' $'e\0633f'
+echo $'a\80b' $'c\608b'
+echo $'a\x33b' $'c\x330b'
+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 @@
+strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+80:\
+81:\
+82:\
+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 @@
+# Embedded NULs
+echo $'str\x00'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+echo $'str\000'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+
+# The chars after '\' are hex 0x80,81,82...
+echo 80:$'\'
+echo 81:$'\'
+echo 82:$'\'
+
+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'}"