hush: fix word splitting in ${v:+ARG} - dollar_altvalue1 test
ash might be a bit buggy, need to investigate dollar_altvalue9 test function old new delta expand_one_var 1639 2236 +597 expand_variables 112 128 +16 expand_vars_to_list 1117 1097 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 613/-20) Total: 593 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
57235beb69
commit
294eb4612c
24
shell/ash_test/ash-quoting/dollar_altvalue9.right
Normal file
24
shell/ash_test/ash-quoting/dollar_altvalue9.right
Normal file
@ -0,0 +1,24 @@
|
||||
Unquoted 1:
|
||||
|a|
|
||||
|x y|
|
||||
|1|
|
||||
|2|
|
||||
|1 2|
|
||||
|A|
|
||||
|B|
|
||||
|C D|
|
||||
|zb|
|
||||
Quoted 1:
|
||||
|a 'x y' 1 2 '' 1 2 A B C D zb|
|
||||
Unquoted 2:
|
||||
|ax y|
|
||||
|1|
|
||||
|2|
|
||||
|1 2|
|
||||
|A|
|
||||
|B|
|
||||
|C D|
|
||||
|z|
|
||||
|b|
|
||||
Quoted 2:
|
||||
|a 'x y' 1 2 '' 1 2 A B C D z b|
|
17
shell/ash_test/ash-quoting/dollar_altvalue9.tests
Executable file
17
shell/ash_test/ash-quoting/dollar_altvalue9.tests
Executable file
@ -0,0 +1,17 @@
|
||||
f() { for i; do echo "|$i|"; done; }
|
||||
|
||||
echo Unquoted 1:
|
||||
x='1 2'; f a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b
|
||||
echo Quoted 1:
|
||||
x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b"
|
||||
|
||||
echo Unquoted 2:
|
||||
x='1 2'; f a${x:+'x y' $x '' "$x" `echo A B` "`echo C D`" z }b
|
||||
echo Quoted 2:
|
||||
x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z }b"
|
||||
|
||||
#echo Unquoted 3:
|
||||
#e=
|
||||
#x='1 2'; f a${x:+'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b
|
||||
#echo Quoted 3:
|
||||
#x='1 2'; f "a${x:+ 'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b"
|
163
shell/hush.c
163
shell/hush.c
@ -5873,6 +5873,138 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int
|
||||
return exp_str;
|
||||
}
|
||||
|
||||
static int expand_vars_to_list(o_string *output, int n, char *arg);
|
||||
|
||||
static int encode_then_append_var_plusminus(o_string *output, int n,
|
||||
const char *str, int dquoted)
|
||||
{
|
||||
struct in_str input;
|
||||
o_string dest = NULL_O_STRING;
|
||||
|
||||
#if 0 //todo?
|
||||
const char *cp;
|
||||
cp = str;
|
||||
for (;;) {
|
||||
if (!*cp) return NULL; /* string has no special chars */
|
||||
if (*cp == '$') break;
|
||||
if (*cp == '\\') break;
|
||||
if (*cp == '\'') break;
|
||||
if (*cp == '"') break;
|
||||
#if ENABLE_HUSH_TICK
|
||||
if (*cp == '`') break;
|
||||
#endif
|
||||
cp++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Expanding ARG in ${var+ARG}, ${var-ARG} */
|
||||
|
||||
setup_string_in_str(&input, str);
|
||||
|
||||
for (;;) {
|
||||
int ch;
|
||||
|
||||
ch = i_getch(&input);
|
||||
debug_printf_parse("%s: ch=%c (%d) escape=%x\n",
|
||||
__func__, ch, ch, dest.o_expflags);
|
||||
|
||||
if (!dest.o_expflags) {
|
||||
if (ch == EOF)
|
||||
break;
|
||||
if (!dquoted && strchr(G.ifs, ch)) {
|
||||
/* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word.
|
||||
* do not assume we are at the start of the word (PREFIX above).
|
||||
*/
|
||||
if (dest.data) {
|
||||
n = expand_vars_to_list(output, n, dest.data);
|
||||
o_free(&dest);
|
||||
o_addchr(output, '\0');
|
||||
n = o_save_ptr(output, n); /* create next word */
|
||||
} else
|
||||
if (output->length != o_get_last_ptr(output, n)
|
||||
|| output->has_quoted_part
|
||||
) {
|
||||
/* For these cases:
|
||||
* f() { for i; do echo "|$i|"; done; }; x=x
|
||||
* f a${x:+ }b # 1st condition
|
||||
* |a|
|
||||
* |b|
|
||||
* f ""${x:+ }b # 2nd condition
|
||||
* ||
|
||||
* |b|
|
||||
*/
|
||||
o_addchr(output, '\0');
|
||||
n = o_save_ptr(output, n); /* create next word */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!dquoted && ch == '\'') {
|
||||
//quoting version of add_till_single_quote() (try to merge?):
|
||||
for (;;) {
|
||||
ch = i_getch(&input);
|
||||
if (ch == EOF) {
|
||||
syntax_error_unterm_ch('\'');
|
||||
goto ret; /* error */
|
||||
}
|
||||
if (ch == '\'')
|
||||
break;
|
||||
o_addqchr(&dest, ch);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ch == EOF) {
|
||||
syntax_error_unterm_ch('"');
|
||||
goto ret; /* error */
|
||||
}
|
||||
if (ch == '"') {
|
||||
dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
|
||||
continue;
|
||||
}
|
||||
if (ch == '\\') {
|
||||
ch = i_getch(&input);
|
||||
if (ch == EOF) {
|
||||
//example? error message? syntax_error_unterm_ch('"');
|
||||
debug_printf_parse("%s: error: \\<eof>\n", __func__);
|
||||
goto ret;
|
||||
}
|
||||
o_addqchr(&dest, ch);
|
||||
continue;
|
||||
}
|
||||
if (ch == '$') {
|
||||
if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ (dest.o_expflags || dquoted) ? 0x80 : 0)) {
|
||||
debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
|
||||
goto ret;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if ENABLE_HUSH_TICK
|
||||
if (ch == '`') {
|
||||
//unsigned pos = dest->length;
|
||||
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
||||
o_addchr(&dest, (dest.o_expflags || dquoted) ? 0x80 | '`' : '`');
|
||||
if (!add_till_backquote(&dest, &input,
|
||||
/*in_dquote:*/ dest.o_expflags /* nonzero if EXP_FLAG_ESC_GLOB_CHARS set */
|
||||
)
|
||||
) {
|
||||
goto ret; /* error */
|
||||
}
|
||||
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
||||
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
o_addQchr(&dest, ch);
|
||||
} /* for (;;) */
|
||||
|
||||
if (dest.data) {
|
||||
n = expand_vars_to_list(output, n, dest.data);
|
||||
}
|
||||
ret:
|
||||
o_free_unsafe(&dest);
|
||||
return n;
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_SH_MATH
|
||||
static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
|
||||
{
|
||||
@ -6231,9 +6363,9 @@ static NOINLINE int expand_one_var(o_string *output,
|
||||
*
|
||||
* Colon forms (${var:-word}, ${var:=word} etc) do the same,
|
||||
* but also treat null var as if it is unset.
|
||||
*/
|
||||
/*
|
||||
* Word-splitting and squote behavior of bash:
|
||||
*
|
||||
* Word-splitting and single quote behavior:
|
||||
*
|
||||
* $ f() { for i; do echo "|$i|"; done; };
|
||||
*
|
||||
* $ x=; f ${x:?'x y' z}
|
||||
@ -6248,7 +6380,7 @@ static NOINLINE int expand_one_var(o_string *output,
|
||||
* $ x=; f "${x:='x y' z}"
|
||||
* |'x y' z|
|
||||
*
|
||||
* $ x=x; f ${x:+'x y' z}
|
||||
* $ x=x; f ${x:+'x y' z}|
|
||||
* |x y|
|
||||
* |z|
|
||||
* $ x=x; f "${x:+'x y' z}"
|
||||
@ -6266,8 +6398,16 @@ static NOINLINE int expand_one_var(o_string *output,
|
||||
debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
|
||||
(exp_save == ':') ? "true" : "false", use_word);
|
||||
if (use_word) {
|
||||
//FIXME: unquoted ${x:+"b c" d} and ${x:+'b c' d} should expand to two words
|
||||
//currently it expands to three.
|
||||
if (exp_op == '+' || exp_op == '-') {
|
||||
/* ${var+word} - use alternative value */
|
||||
/* ${var-word} - use default value */
|
||||
n = encode_then_append_var_plusminus(output, n, exp_word,
|
||||
/*dquoted:*/ (arg0 & 0x80)
|
||||
);
|
||||
val = NULL;
|
||||
} else {
|
||||
/* ${var?word} - indicate error if unset */
|
||||
/* ${var=word} - assign and use default value */
|
||||
to_be_freed = encode_then_expand_vararg(exp_word,
|
||||
/*handle_squotes:*/ !(arg0 & 0x80),
|
||||
/*unbackslash:*/ 0
|
||||
@ -6293,7 +6433,6 @@ static NOINLINE int expand_one_var(o_string *output,
|
||||
} else {
|
||||
val = exp_word;
|
||||
}
|
||||
|
||||
if (exp_op == '=') {
|
||||
/* ${var=[word]} or ${var:=[word]} */
|
||||
if (isdigit(var[0]) || var[0] == '#') {
|
||||
@ -6306,6 +6445,7 @@ static NOINLINE int expand_one_var(o_string *output,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* one of "-=+?" */
|
||||
|
||||
*exp_saveptr = exp_save;
|
||||
@ -6482,8 +6622,9 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
|
||||
}
|
||||
debug_print_list("expand_vars_to_list[a]", output, n);
|
||||
/* this part is literal, and it was already pre-quoted
|
||||
* if needed (much earlier), do not use o_addQstr here! */
|
||||
o_addstr_with_NUL(output, arg);
|
||||
* if needed (much earlier), do not use o_addQstr here!
|
||||
*/
|
||||
o_addstr(output, arg);
|
||||
debug_print_list("expand_vars_to_list[b]", output, n);
|
||||
} else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
|
||||
&& !(cant_be_null & 0x80) /* and all vars were not quoted. */
|
||||
@ -6491,8 +6632,6 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
|
||||
n--;
|
||||
/* allow to reuse list[n] later without re-growth */
|
||||
output->has_empty_slot = 1;
|
||||
} else {
|
||||
o_addchr(output, '\0');
|
||||
}
|
||||
|
||||
return n;
|
||||
@ -6517,6 +6656,8 @@ static char **expand_variables(char **argv, unsigned expflags)
|
||||
|
||||
/* expand argv[i] */
|
||||
n = expand_vars_to_list(&output, n, *argv++);
|
||||
/* if (!output->has_empty_slot) -- need this?? */
|
||||
o_addchr(&output, '\0');
|
||||
}
|
||||
debug_print_list("expand_variables", &output, n);
|
||||
|
||||
|
24
shell/hush_test/hush-quoting/dollar_altvalue9.right
Normal file
24
shell/hush_test/hush-quoting/dollar_altvalue9.right
Normal file
@ -0,0 +1,24 @@
|
||||
Unquoted 1:
|
||||
|a|
|
||||
|x y|
|
||||
|1|
|
||||
|2|
|
||||
|1 2|
|
||||
|A|
|
||||
|B|
|
||||
|C D|
|
||||
|zb|
|
||||
Quoted 1:
|
||||
|a 'x y' 1 2 '' 1 2 A B C D zb|
|
||||
Unquoted 2:
|
||||
|ax y|
|
||||
|1|
|
||||
|2|
|
||||
|1 2|
|
||||
|A|
|
||||
|B|
|
||||
|C D|
|
||||
|z|
|
||||
|b|
|
||||
Quoted 2:
|
||||
|a 'x y' 1 2 '' 1 2 A B C D z b|
|
17
shell/hush_test/hush-quoting/dollar_altvalue9.tests
Executable file
17
shell/hush_test/hush-quoting/dollar_altvalue9.tests
Executable file
@ -0,0 +1,17 @@
|
||||
f() { for i; do echo "|$i|"; done; }
|
||||
|
||||
echo Unquoted 1:
|
||||
x='1 2'; f a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b
|
||||
echo Quoted 1:
|
||||
x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b"
|
||||
|
||||
echo Unquoted 2:
|
||||
x='1 2'; f a${x:+'x y' $x '' "$x" `echo A B` "`echo C D`" z }b
|
||||
echo Quoted 2:
|
||||
x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z }b"
|
||||
|
||||
#echo Unquoted 3:
|
||||
#e=
|
||||
#x='1 2'; f a${x:+'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b
|
||||
#echo Quoted 3:
|
||||
#x='1 2'; f "a${x:+ 'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b"
|
Loading…
Reference in New Issue
Block a user