hush: fix handling of by backslash-newline in $((arith)) and $(cmd)

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2016-09-29 18:07:42 +02:00
parent d17a91db6e
commit 657086a3dc

View File

@ -2387,6 +2387,15 @@ static void o_addchr(o_string *o, int ch)
o->data[o->length] = '\0'; o->data[o->length] = '\0';
} }
#if 0
/* Valid only if we know o_string is not empty */
static void o_delchr(o_string *o)
{
o->length--;
o->data[o->length] = '\0';
}
#endif
static void o_addblock(o_string *o, const char *str, int len) static void o_addblock(o_string *o, const char *str, int len)
{ {
o_grow_by(o, len); o_grow_by(o, len);
@ -3900,6 +3909,23 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
/* command remains "open", available for possible redirects */ /* command remains "open", available for possible redirects */
} }
static int i_peek_and_eat_bkslash_nl(struct in_str *input)
{
for (;;) {
int ch, ch2;
ch = i_peek(input);
if (ch != '\\')
return ch;
ch2 = i_peek2(input);
if (ch2 != '\n')
return ch;
/* backslash+newline, skip it */
i_getch(input);
i_getch(input);
}
}
#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS
/* Subroutines for copying $(...) and `...` things */ /* Subroutines for copying $(...) and `...` things */
static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
@ -4017,7 +4043,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
if (!dbl) if (!dbl)
break; break;
/* we look for closing )) of $((EXPR)) */ /* we look for closing )) of $((EXPR)) */
if (i_peek(input) == end_ch) { if (i_peek_and_eat_bkslash_nl(input) == end_ch) {
i_getch(input); /* eat second ')' */ i_getch(input); /* eat second ')' */
break; break;
} }
@ -4055,6 +4081,13 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
syntax_error_unterm_ch(')'); syntax_error_unterm_ch(')');
return 0; return 0;
} }
#if 0
if (ch == '\n') {
/* "backslash+newline", ignore both */
o_delchr(dest); /* undo insertion of '\' */
continue;
}
#endif
o_addchr(dest, ch); o_addchr(dest, ch);
continue; continue;
} }
@ -4073,7 +4106,7 @@ static int parse_dollar(o_string *as_string,
o_string *dest, o_string *dest,
struct in_str *input, unsigned char quote_mask) struct in_str *input, unsigned char quote_mask)
{ {
int ch = i_peek(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'\n", ch);
if (isalpha(ch)) { if (isalpha(ch)) {
@ -4085,18 +4118,8 @@ static int parse_dollar(o_string *as_string,
debug_printf_parse(": '%c'\n", ch); debug_printf_parse(": '%c'\n", ch);
o_addchr(dest, ch | quote_mask); o_addchr(dest, ch | quote_mask);
quote_mask = 0; quote_mask = 0;
next_ch: ch = i_peek_and_eat_bkslash_nl(input);
ch = i_peek(input);
if (!isalnum(ch) && ch != '_') { if (!isalnum(ch) && ch != '_') {
if (ch == '\\') {
/* If backslash+newline, skip it */
int ch2 = i_peek2(input);
if (ch2 == '\n') {
i_getch(input);
i_getch(input);
goto next_ch;
}
}
/* End of variable name reached */ /* End of variable name reached */
break; break;
} }
@ -4126,6 +4149,7 @@ static int parse_dollar(o_string *as_string,
ch = i_getch(input); /* eat '{' */ ch = i_getch(input); /* eat '{' */
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
i_peek_and_eat_bkslash_nl(input);
ch = i_getch(input); /* first char after '{' */ ch = i_getch(input); /* first char after '{' */
/* It should be ${?}, or ${#var}, /* It should be ${?}, or ${#var},
* or even ${?+subst} - operator acting on a special variable, * or even ${?+subst} - operator acting on a special variable,
@ -4232,7 +4256,7 @@ static int parse_dollar(o_string *as_string,
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
# if ENABLE_SH_MATH_SUPPORT # if ENABLE_SH_MATH_SUPPORT
if (i_peek(input) == '(') { if (i_peek_and_eat_bkslash_nl(input) == '(') {
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
o_addchr(dest, SPECIAL_VAR_SYMBOL); o_addchr(dest, SPECIAL_VAR_SYMBOL);
@ -4269,7 +4293,7 @@ static int parse_dollar(o_string *as_string,
case '_': case '_':
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
ch = i_peek(input); ch = i_peek_and_eat_bkslash_nl(input);
if (isalnum(ch)) { /* it's $_name or $_123 */ if (isalnum(ch)) { /* it's $_name or $_123 */
ch = '_'; ch = '_';
goto make_var; goto make_var;