aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-07-19 12:14:47 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-07-20 16:27:26 +0200
commit8a6a4615048d51af0e765e893211073faa7951cc (patch)
treec15d0af26bf9f8e70ddb79db58b260470dc2dde0
parent116b50a5c1ea9d80d60641f2df2b61473b57fe47 (diff)
downloadbusybox-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.c63
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 */
5979static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) 5979static 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]) {