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>
This commit is contained in:
parent
05c5d745f7
commit
b278d82c61
103
shell/hush.c
103
shell/hush.c
@ -384,6 +384,7 @@
|
|||||||
#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
|
#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
|
#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_SOURCE 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_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
|
#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
|
#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 */
|
#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 */
|
/* Return code: 0 for OK, 1 for syntax error */
|
||||||
#if BB_MMU
|
#if BB_MMU
|
||||||
#define parse_dollar(as_string, dest, input, quote_mask) \
|
#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 $ */
|
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)) {
|
if (isalpha(ch)) {
|
||||||
make_var:
|
make_var:
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
@ -5247,6 +5342,8 @@ static int encode_string(o_string *as_string,
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
|
//if (parse_dollar_squote(as_string, dest, input))
|
||||||
|
// goto again;
|
||||||
if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
|
if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
|
||||||
debug_printf_parse("encode_string return 0: "
|
debug_printf_parse("encode_string return 0: "
|
||||||
"parse_dollar returned 0 (error)\n");
|
"parse_dollar returned 0 (error)\n");
|
||||||
@ -5723,6 +5820,8 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
o_addchr(&ctx.word, ch);
|
o_addchr(&ctx.word, ch);
|
||||||
continue; /* get next char */
|
continue; /* get next char */
|
||||||
case '$':
|
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)) {
|
if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
|
||||||
debug_printf_parse("parse_stream parse error: "
|
debug_printf_parse("parse_stream parse error: "
|
||||||
"parse_dollar returned 0 (error)\n");
|
"parse_dollar returned 0 (error)\n");
|
||||||
@ -6166,6 +6265,8 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
|
if (parse_dollar_squote(NULL, &dest, &input))
|
||||||
|
continue;
|
||||||
if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
|
if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
|
||||||
debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
|
debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
10
shell/hush_test/hush-quoting/dollar_squote_bash1.right
Normal file
10
shell/hush_test/hush-quoting/dollar_squote_bash1.right
Normal file
@ -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
|
8
shell/hush_test/hush-quoting/dollar_squote_bash1.tests
Executable file
8
shell/hush_test/hush-quoting/dollar_squote_bash1.tests
Executable file
@ -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'
|
6
shell/hush_test/hush-quoting/dollar_squote_bash2.right
Normal file
6
shell/hush_test/hush-quoting/dollar_squote_bash2.right
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
|
||||||
|
strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
|
||||||
|
80:\€
|
||||||
|
81:\<5C>
|
||||||
|
82:\‚
|
||||||
|
Done:0
|
10
shell/hush_test/hush-quoting/dollar_squote_bash2.tests
Executable file
10
shell/hush_test/hush-quoting/dollar_squote_bash2.tests
Executable file
@ -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:$'\<5C>'
|
||||||
|
echo 82:$'\‚'
|
||||||
|
|
||||||
|
echo Done:$?
|
1
shell/hush_test/hush-vars/var_bash7.right
Normal file
1
shell/hush_test/hush-vars/var_bash7.right
Normal file
@ -0,0 +1 @@
|
|||||||
|
B
|
1
shell/hush_test/hush-vars/var_bash7.tests
Executable file
1
shell/hush_test/hush-vars/var_bash7.tests
Executable file
@ -0,0 +1 @@
|
|||||||
|
x=AB; echo "${x#$'\x41'}"
|
Loading…
Reference in New Issue
Block a user