diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-07-19 12:14:47 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-07-20 16:27:26 +0200 |
commit | 8a6a4615048d51af0e765e893211073faa7951cc (patch) | |
tree | c15d0af26bf9f8e70ddb79db58b260470dc2dde0 | |
parent | 116b50a5c1ea9d80d60641f2df2b61473b57fe47 (diff) | |
download | busybox-w32-8a6a4615048d51af0e765e893211073faa7951cc.tar.gz busybox-w32-8a6a4615048d51af0e765e893211073faa7951cc.tar.bz2 busybox-w32-8a6a4615048d51af0e765e893211073faa7951cc.zip |
hush: propagate (output,n) parameters into expand_one_var()
This is necessary since expand_one_var() for ${var:+ARG} must create more than one
output word, and thus can't simply return a char*.
function old new delta
expand_one_var 1610 1643 +33
expand_vars_to_list 1139 1125 -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 33/-14) Total: 19 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c index b738d2fd8..ea259f53c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -5976,7 +5976,8 @@ static int append_str_maybe_ifs_split(o_string *output, int *ended_in_ifs, int n | |||
5976 | /* Helper: | 5976 | /* Helper: |
5977 | * Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct. | 5977 | * Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct. |
5978 | */ | 5978 | */ |
5979 | static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) | 5979 | static NOINLINE int expand_one_var(o_string *output, |
5980 | int *ended_in_ifs, int n, int first_ch, char *arg, char **pp) | ||
5980 | { | 5981 | { |
5981 | const char *val; | 5982 | const char *val; |
5982 | char *to_be_freed; | 5983 | char *to_be_freed; |
@@ -6038,9 +6039,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
6038 | /* Look up the variable in question */ | 6039 | /* Look up the variable in question */ |
6039 | if (isdigit(var[0])) { | 6040 | if (isdigit(var[0])) { |
6040 | /* parse_dollar should have vetted var for us */ | 6041 | /* parse_dollar should have vetted var for us */ |
6041 | int n = xatoi_positive(var); | 6042 | int nn = xatoi_positive(var); |
6042 | if (n < G.global_argc) | 6043 | if (nn < G.global_argc) |
6043 | val = G.global_argv[n]; | 6044 | val = G.global_argv[nn]; |
6044 | /* else val remains NULL: $N with too big N */ | 6045 | /* else val remains NULL: $N with too big N */ |
6045 | } else { | 6046 | } else { |
6046 | switch (var[0]) { | 6047 | switch (var[0]) { |
@@ -6236,6 +6237,34 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
6236 | * Colon forms (${var:-word}, ${var:=word} etc) do the same, | 6237 | * Colon forms (${var:-word}, ${var:=word} etc) do the same, |
6237 | * but also treat null var as if it is unset. | 6238 | * but also treat null var as if it is unset. |
6238 | */ | 6239 | */ |
6240 | /* | ||
6241 | * Word-splitting and squote behavior of bash: | ||
6242 | * $ f() { for i; do echo "|$i|"; done; }; | ||
6243 | * | ||
6244 | * $ x=; f ${x:?'x y' z} | ||
6245 | * bash: x: x y z | ||
6246 | * $ x=; f "${x:?'x y' z}" | ||
6247 | * bash: x: x y z # dash prints: dash: x: 'x y' z | ||
6248 | * | ||
6249 | * $ x=; f ${x:='x y' z} | ||
6250 | * |x| | ||
6251 | * |y| | ||
6252 | * |z| | ||
6253 | * $ x=; f "${x:='x y' z}" | ||
6254 | * |'x y' z| | ||
6255 | * | ||
6256 | * $ x=x; f ${x:+'x y' z} | ||
6257 | * |x y| | ||
6258 | * |z| | ||
6259 | * $ x=x; f "${x:+'x y' z}" | ||
6260 | * |'x y' z| | ||
6261 | * | ||
6262 | * $ x=; f ${x:-'x y' z} | ||
6263 | * |x y| | ||
6264 | * |z| | ||
6265 | * $ x=; f "${x:-'x y' z}" | ||
6266 | * |'x y' z| | ||
6267 | */ | ||
6239 | int use_word = (!val || ((exp_save == ':') && !val[0])); | 6268 | int use_word = (!val || ((exp_save == ':') && !val[0])); |
6240 | if (exp_op == '+') | 6269 | if (exp_op == '+') |
6241 | use_word = !use_word; | 6270 | use_word = !use_word; |
@@ -6244,7 +6273,10 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
6244 | if (use_word) { | 6273 | if (use_word) { |
6245 | //FIXME: unquoted ${x:+"b c" d} and ${x:+'b c' d} should expand to two words | 6274 | //FIXME: unquoted ${x:+"b c" d} and ${x:+'b c' d} should expand to two words |
6246 | //currently it expands to three. | 6275 | //currently it expands to three. |
6247 | to_be_freed = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ !(arg0 & 0x80), /*unbackslash:*/ 0); | 6276 | to_be_freed = encode_then_expand_vararg(exp_word, |
6277 | /*handle_squotes:*/ !(arg0 & 0x80), | ||
6278 | /*unbackslash:*/ 0 | ||
6279 | ); | ||
6248 | if (to_be_freed) | 6280 | if (to_be_freed) |
6249 | exp_word = to_be_freed; | 6281 | exp_word = to_be_freed; |
6250 | if (exp_op == '?') { | 6282 | if (exp_op == '?') { |
@@ -6258,6 +6290,11 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
6258 | /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/ | 6290 | /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/ |
6259 | ); | 6291 | ); |
6260 | //TODO: how interactive bash aborts expansion mid-command? | 6292 | //TODO: how interactive bash aborts expansion mid-command? |
6293 | //It aborts the entire line: | ||
6294 | // $ f() { for i; do echo "|$i|"; done; }; x=; f "${x:?'x y' z}"; echo YO | ||
6295 | // bash: x: x y z | ||
6296 | // $ | ||
6297 | // ("echo YO" is not executed, neither the f function call) | ||
6261 | } else { | 6298 | } else { |
6262 | val = exp_word; | 6299 | val = exp_word; |
6263 | } | 6300 | } |
@@ -6280,10 +6317,12 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
6280 | } /* if (exp_op) */ | 6317 | } /* if (exp_op) */ |
6281 | 6318 | ||
6282 | arg[0] = arg0; | 6319 | arg[0] = arg0; |
6283 | |||
6284 | *pp = p; | 6320 | *pp = p; |
6285 | *to_be_freed_pp = to_be_freed; | 6321 | |
6286 | return val; | 6322 | n = append_str_maybe_ifs_split(output, ended_in_ifs, n, first_ch, val); |
6323 | |||
6324 | free(to_be_freed); | ||
6325 | return n; | ||
6287 | } | 6326 | } |
6288 | 6327 | ||
6289 | /* Expand all variable references in given string, adding words to list[] | 6328 | /* Expand all variable references in given string, adding words to list[] |
@@ -6427,13 +6466,9 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
6427 | break; | 6466 | break; |
6428 | } | 6467 | } |
6429 | #endif | 6468 | #endif |
6430 | default: { | 6469 | default: |
6431 | char *to_be_freed; | 6470 | n = expand_one_var(output, &ended_in_ifs, n, first_ch, arg, &p); |
6432 | val = expand_one_var(&to_be_freed, arg, &p); | ||
6433 | n = append_str_maybe_ifs_split(output, &ended_in_ifs, n, first_ch, val); | ||
6434 | free(to_be_freed); | ||
6435 | goto restore; | 6471 | goto restore; |
6436 | } /* default: */ | ||
6437 | } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ | 6472 | } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ |
6438 | 6473 | ||
6439 | if (val && val[0]) { | 6474 | if (val && val[0]) { |