hush: move variable expansion into a separate function. No logic changes
function old new delta expand_one_var - 1551 +1551 expand_vars_to_list 2833 1175 -1658 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 1551/-1658) Total: -107 bytes Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
parent
36f774a0cd
commit
f2dc20c2d5
513
shell/hush.c
513
shell/hush.c
@ -2664,6 +2664,263 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Helper:
|
||||
* Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct.
|
||||
*/
|
||||
static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp, char first_ch)
|
||||
{
|
||||
const char *val = NULL;
|
||||
char *to_be_freed = NULL;
|
||||
char *p = *pp;
|
||||
char *var;
|
||||
char first_char;
|
||||
char exp_op;
|
||||
char exp_save = exp_save; /* for compiler */
|
||||
char *exp_saveptr; /* points to expansion operator */
|
||||
char *exp_word = exp_word; /* for compiler */
|
||||
|
||||
var = arg;
|
||||
*p = '\0';
|
||||
exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
|
||||
first_char = arg[0] = first_ch & 0x7f;
|
||||
exp_op = 0;
|
||||
|
||||
if (first_char == '#' && arg[1] && !exp_saveptr) {
|
||||
/* handle length expansion ${#var} */
|
||||
var++;
|
||||
exp_op = 'L';
|
||||
} else {
|
||||
/* maybe handle parameter expansion */
|
||||
if (exp_saveptr /* if 2nd char is one of expansion operators */
|
||||
&& strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */
|
||||
) {
|
||||
/* ${?:0}, ${#[:]%0} etc */
|
||||
exp_saveptr = var + 1;
|
||||
} else {
|
||||
/* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */
|
||||
exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS);
|
||||
}
|
||||
exp_op = exp_save = *exp_saveptr;
|
||||
if (exp_op) {
|
||||
exp_word = exp_saveptr + 1;
|
||||
if (exp_op == ':') {
|
||||
exp_op = *exp_word++;
|
||||
if (ENABLE_HUSH_BASH_COMPAT
|
||||
&& (exp_op == '\0' || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op))
|
||||
) {
|
||||
/* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */
|
||||
exp_op = ':';
|
||||
exp_word--;
|
||||
}
|
||||
}
|
||||
*exp_saveptr = '\0';
|
||||
} /* else: it's not an expansion op, but bare ${var} */
|
||||
}
|
||||
|
||||
/* lookup the variable in question */
|
||||
if (isdigit(var[0])) {
|
||||
/* parse_dollar() should have vetted var for us */
|
||||
int n = xatoi_positive(var);
|
||||
if (n < G.global_argc)
|
||||
val = G.global_argv[n];
|
||||
/* else val remains NULL: $N with too big N */
|
||||
} else {
|
||||
switch (var[0]) {
|
||||
case '$': /* pid */
|
||||
val = utoa(G.root_pid);
|
||||
break;
|
||||
case '!': /* bg pid */
|
||||
val = G.last_bg_pid ? utoa(G.last_bg_pid) : "";
|
||||
break;
|
||||
case '?': /* exitcode */
|
||||
val = utoa(G.last_exitcode);
|
||||
break;
|
||||
case '#': /* argc */
|
||||
val = utoa(G.global_argc ? G.global_argc-1 : 0);
|
||||
break;
|
||||
default:
|
||||
val = get_local_var_value(var);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle any expansions */
|
||||
if (exp_op == 'L') {
|
||||
debug_printf_expand("expand: length(%s)=", val);
|
||||
val = utoa(val ? strlen(val) : 0);
|
||||
debug_printf_expand("%s\n", val);
|
||||
} else if (exp_op) {
|
||||
if (exp_op == '%' || exp_op == '#') {
|
||||
/* Standard-mandated substring removal ops:
|
||||
* ${parameter%word} - remove smallest suffix pattern
|
||||
* ${parameter%%word} - remove largest suffix pattern
|
||||
* ${parameter#word} - remove smallest prefix pattern
|
||||
* ${parameter##word} - remove largest prefix pattern
|
||||
*
|
||||
* Word is expanded to produce a glob pattern.
|
||||
* Then var's value is matched to it and matching part removed.
|
||||
*/
|
||||
if (val && val[0]) {
|
||||
char *exp_exp_word;
|
||||
char *loc;
|
||||
unsigned scan_flags = pick_scan(exp_op, *exp_word);
|
||||
if (exp_op == *exp_word) /* ## or %% */
|
||||
exp_word++;
|
||||
//TODO: avoid xstrdup unless needed
|
||||
// (see HACK ALERT below)
|
||||
val = to_be_freed = xstrdup(val);
|
||||
exp_exp_word = expand_pseudo_dquoted(exp_word);
|
||||
if (exp_exp_word)
|
||||
exp_word = exp_exp_word;
|
||||
loc = scan_and_match(to_be_freed, exp_word, scan_flags);
|
||||
//bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'",
|
||||
// exp_op, to_be_freed, exp_word, loc);
|
||||
free(exp_exp_word);
|
||||
if (loc) { /* match was found */
|
||||
if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
|
||||
val = loc;
|
||||
else /* %[%] */
|
||||
*loc = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ENABLE_HUSH_BASH_COMPAT
|
||||
else if (exp_op == '/' || exp_op == '\\') {
|
||||
/* Empty variable always gives nothing: */
|
||||
// "v=''; echo ${v/*/w}" prints ""
|
||||
if (val && val[0]) {
|
||||
/* It's ${var/[/]pattern[/repl]} thing */
|
||||
char *pattern, *repl, *t;
|
||||
pattern = expand_pseudo_dquoted(exp_word);
|
||||
if (!pattern)
|
||||
pattern = xstrdup(exp_word);
|
||||
debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern);
|
||||
*p++ = SPECIAL_VAR_SYMBOL;
|
||||
exp_word = p;
|
||||
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
||||
*p = '\0';
|
||||
repl = expand_pseudo_dquoted(exp_word);
|
||||
debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl);
|
||||
/* HACK ALERT. We depend here on the fact that
|
||||
* G.global_argv and results of utoa and get_local_var_value
|
||||
* are actually in writable memory:
|
||||
* replace_pattern momentarily stores NULs there. */
|
||||
t = (char*)val;
|
||||
to_be_freed = replace_pattern(t,
|
||||
pattern,
|
||||
(repl ? repl : exp_word),
|
||||
exp_op);
|
||||
if (to_be_freed) /* at least one replace happened */
|
||||
val = to_be_freed;
|
||||
free(pattern);
|
||||
free(repl);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (exp_op == ':') {
|
||||
#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT
|
||||
/* It's ${var:N[:M]} bashism.
|
||||
* Note that in encoded form it has TWO parts:
|
||||
* var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
|
||||
*/
|
||||
arith_t beg, len;
|
||||
int errcode = 0;
|
||||
|
||||
beg = expand_and_evaluate_arith(exp_word, &errcode);
|
||||
debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
|
||||
*p++ = SPECIAL_VAR_SYMBOL;
|
||||
exp_word = p;
|
||||
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
||||
*p = '\0';
|
||||
len = expand_and_evaluate_arith(exp_word, &errcode);
|
||||
debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
|
||||
|
||||
if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
|
||||
if (beg < 0) /* bash compat */
|
||||
beg = 0;
|
||||
debug_printf_varexp("from val:'%s'\n", val);
|
||||
if (len == 0 || !val || beg >= strlen(val))
|
||||
val = "";
|
||||
else {
|
||||
/* Paranoia. What if user entered 9999999999999
|
||||
* which fits in arith_t but not int? */
|
||||
if (len >= INT_MAX)
|
||||
len = INT_MAX;
|
||||
val = to_be_freed = xstrndup(val + beg, len);
|
||||
}
|
||||
debug_printf_varexp("val:'%s'\n", val);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
die_if_script("malformed ${%s:...}", var);
|
||||
val = "";
|
||||
}
|
||||
} else { /* one of "-=+?" */
|
||||
/* Standard-mandated substitution ops:
|
||||
* ${var?word} - indicate error if unset
|
||||
* If var is unset, word (or a message indicating it is unset
|
||||
* if word is null) is written to standard error
|
||||
* and the shell exits with a non-zero exit status.
|
||||
* Otherwise, the value of var is substituted.
|
||||
* ${var-word} - use default value
|
||||
* If var is unset, word is substituted.
|
||||
* ${var=word} - assign and use default value
|
||||
* If var is unset, word is assigned to var.
|
||||
* In all cases, final value of var is substituted.
|
||||
* ${var+word} - use alternative value
|
||||
* If var is unset, null is substituted.
|
||||
* Otherwise, word is substituted.
|
||||
*
|
||||
* Word is subjected to tilde expansion, parameter expansion,
|
||||
* command substitution, and arithmetic expansion.
|
||||
* If word is not needed, it is not expanded.
|
||||
*
|
||||
* Colon forms (${var:-word}, ${var:=word} etc) do the same,
|
||||
* but also treat null var as if it is unset.
|
||||
*/
|
||||
int use_word = (!val || ((exp_save == ':') && !val[0]));
|
||||
if (exp_op == '+')
|
||||
use_word = !use_word;
|
||||
debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
|
||||
(exp_save == ':') ? "true" : "false", use_word);
|
||||
if (use_word) {
|
||||
to_be_freed = expand_pseudo_dquoted(exp_word);
|
||||
if (to_be_freed)
|
||||
exp_word = to_be_freed;
|
||||
if (exp_op == '?') {
|
||||
/* mimic bash message */
|
||||
die_if_script("%s: %s",
|
||||
var,
|
||||
exp_word[0] ? exp_word : "parameter null or not set"
|
||||
);
|
||||
//TODO: how interactive bash aborts expansion mid-command?
|
||||
} else {
|
||||
val = exp_word;
|
||||
}
|
||||
|
||||
if (exp_op == '=') {
|
||||
/* ${var=[word]} or ${var:=[word]} */
|
||||
if (isdigit(var[0]) || var[0] == '#') {
|
||||
/* mimic bash message */
|
||||
die_if_script("$%s: cannot assign in this way", var);
|
||||
val = NULL;
|
||||
} else {
|
||||
char *new_var = xasprintf("%s=%s", var, val);
|
||||
set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* one of "-=+?" */
|
||||
|
||||
*exp_saveptr = exp_save;
|
||||
} /* if (exp_op) */
|
||||
|
||||
arg[0] = first_ch;
|
||||
|
||||
*pp = p;
|
||||
*to_be_freed_pp = to_be_freed;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Expand all variable references in given string, adding words to list[]
|
||||
* at n, n+1,... positions. Return updated n (so that list[n] is next one
|
||||
* to be filled). This routine is extremely tricky: has to deal with
|
||||
@ -2803,255 +3060,12 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
|
||||
//TODO: move to a subroutine?
|
||||
char *var;
|
||||
char first_char;
|
||||
char exp_op;
|
||||
char exp_save = exp_save; /* for compiler */
|
||||
char *exp_saveptr; /* points to expansion operator */
|
||||
char *exp_word = exp_word; /* for compiler */
|
||||
|
||||
var = arg;
|
||||
*p = '\0';
|
||||
exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
|
||||
first_char = arg[0] = first_ch & 0x7f;
|
||||
exp_op = 0;
|
||||
|
||||
if (first_char == '#' && arg[1] && !exp_saveptr) {
|
||||
/* handle length expansion ${#var} */
|
||||
var++;
|
||||
exp_op = 'L';
|
||||
} else {
|
||||
/* maybe handle parameter expansion */
|
||||
if (exp_saveptr /* if 2nd char is one of expansion operators */
|
||||
&& strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */
|
||||
) {
|
||||
/* ${?:0}, ${#[:]%0} etc */
|
||||
exp_saveptr = var + 1;
|
||||
} else {
|
||||
/* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */
|
||||
exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS);
|
||||
}
|
||||
exp_op = exp_save = *exp_saveptr;
|
||||
if (exp_op) {
|
||||
exp_word = exp_saveptr + 1;
|
||||
if (exp_op == ':') {
|
||||
exp_op = *exp_word++;
|
||||
if (ENABLE_HUSH_BASH_COMPAT
|
||||
&& (exp_op == '\0' || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op))
|
||||
) {
|
||||
/* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */
|
||||
exp_op = ':';
|
||||
exp_word--;
|
||||
}
|
||||
}
|
||||
*exp_saveptr = '\0';
|
||||
} /* else: it's not an expansion op, but bare ${var} */
|
||||
}
|
||||
|
||||
/* lookup the variable in question */
|
||||
if (isdigit(var[0])) {
|
||||
/* parse_dollar() should have vetted var for us */
|
||||
i = xatoi_positive(var);
|
||||
if (i < G.global_argc)
|
||||
val = G.global_argv[i];
|
||||
/* else val remains NULL: $N with too big N */
|
||||
} else {
|
||||
switch (var[0]) {
|
||||
case '$': /* pid */
|
||||
val = utoa(G.root_pid);
|
||||
break;
|
||||
case '!': /* bg pid */
|
||||
val = G.last_bg_pid ? utoa(G.last_bg_pid) : "";
|
||||
break;
|
||||
case '?': /* exitcode */
|
||||
val = utoa(G.last_exitcode);
|
||||
break;
|
||||
case '#': /* argc */
|
||||
val = utoa(G.global_argc ? G.global_argc-1 : 0);
|
||||
break;
|
||||
default:
|
||||
val = get_local_var_value(var);
|
||||
}
|
||||
}
|
||||
|
||||
/* handle any expansions */
|
||||
if (exp_op == 'L') {
|
||||
debug_printf_expand("expand: length(%s)=", val);
|
||||
val = utoa(val ? strlen(val) : 0);
|
||||
debug_printf_expand("%s\n", val);
|
||||
} else if (exp_op) {
|
||||
if (exp_op == '%' || exp_op == '#') {
|
||||
/* Standard-mandated substring removal ops:
|
||||
* ${parameter%word} - remove smallest suffix pattern
|
||||
* ${parameter%%word} - remove largest suffix pattern
|
||||
* ${parameter#word} - remove smallest prefix pattern
|
||||
* ${parameter##word} - remove largest prefix pattern
|
||||
*
|
||||
* Word is expanded to produce a glob pattern.
|
||||
* Then var's value is matched to it and matching part removed.
|
||||
*/
|
||||
if (val) {
|
||||
char *exp_exp_word;
|
||||
char *loc;
|
||||
unsigned scan_flags = pick_scan(exp_op, *exp_word);
|
||||
if (exp_op == *exp_word) /* ## or %% */
|
||||
exp_word++;
|
||||
val = to_be_freed = xstrdup(val);
|
||||
exp_exp_word = expand_pseudo_dquoted(exp_word);
|
||||
if (exp_exp_word)
|
||||
exp_word = exp_exp_word;
|
||||
loc = scan_and_match(to_be_freed, exp_word, scan_flags);
|
||||
//bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'",
|
||||
// exp_op, to_be_freed, exp_word, loc);
|
||||
free(exp_exp_word);
|
||||
if (loc) { /* match was found */
|
||||
if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
|
||||
val = loc;
|
||||
else /* %[%] */
|
||||
*loc = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ENABLE_HUSH_BASH_COMPAT
|
||||
else if (exp_op == '/' || exp_op == '\\') {
|
||||
/* Empty variable always gives nothing: */
|
||||
// "v=''; echo ${v/*/w}" prints ""
|
||||
if (val && val[0]) {
|
||||
/* It's ${var/[/]pattern[/repl]} thing */
|
||||
char *pattern, *repl, *t;
|
||||
pattern = expand_pseudo_dquoted(exp_word);
|
||||
if (!pattern)
|
||||
pattern = xstrdup(exp_word);
|
||||
debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern);
|
||||
*p++ = SPECIAL_VAR_SYMBOL;
|
||||
exp_word = p;
|
||||
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
||||
*p = '\0';
|
||||
repl = expand_pseudo_dquoted(exp_word);
|
||||
debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl);
|
||||
/* HACK ALERT. We depend here on the fact that
|
||||
* G.global_argv and results of utoa and get_local_var_value
|
||||
* are actually in writable memory:
|
||||
* replace_pattern momentarily stores NULs there. */
|
||||
t = (char*)val;
|
||||
to_be_freed = replace_pattern(t,
|
||||
pattern,
|
||||
(repl ? repl : exp_word),
|
||||
exp_op);
|
||||
if (to_be_freed) /* at least one replace happened */
|
||||
val = to_be_freed;
|
||||
free(pattern);
|
||||
free(repl);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (exp_op == ':') {
|
||||
#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT
|
||||
/* It's ${var:N[:M]} bashism.
|
||||
* Note that in encoded form it has TWO parts:
|
||||
* var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
|
||||
*/
|
||||
arith_t beg, len;
|
||||
int errcode = 0;
|
||||
|
||||
beg = expand_and_evaluate_arith(exp_word, &errcode);
|
||||
debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
|
||||
*p++ = SPECIAL_VAR_SYMBOL;
|
||||
exp_word = p;
|
||||
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
||||
*p = '\0';
|
||||
len = expand_and_evaluate_arith(exp_word, &errcode);
|
||||
debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
|
||||
|
||||
if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
|
||||
if (beg < 0) /* bash compat */
|
||||
beg = 0;
|
||||
debug_printf_varexp("from val:'%s'\n", val);
|
||||
if (len == 0 || !val || beg >= strlen(val))
|
||||
val = "";
|
||||
else {
|
||||
/* Paranoia. What if user entered 9999999999999
|
||||
* which fits in arith_t but not int? */
|
||||
if (len >= INT_MAX)
|
||||
len = INT_MAX;
|
||||
val = to_be_freed = xstrndup(val + beg, len);
|
||||
}
|
||||
debug_printf_varexp("val:'%s'\n", val);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
die_if_script("malformed ${%s:...}", var);
|
||||
val = "";
|
||||
}
|
||||
} else { /* one of "-=+?" */
|
||||
/* Standard-mandated substitution ops:
|
||||
* ${var?word} - indicate error if unset
|
||||
* If var is unset, word (or a message indicating it is unset
|
||||
* if word is null) is written to standard error
|
||||
* and the shell exits with a non-zero exit status.
|
||||
* Otherwise, the value of var is substituted.
|
||||
* ${var-word} - use default value
|
||||
* If var is unset, word is substituted.
|
||||
* ${var=word} - assign and use default value
|
||||
* If var is unset, word is assigned to var.
|
||||
* In all cases, final value of var is substituted.
|
||||
* ${var+word} - use alternative value
|
||||
* If var is unset, null is substituted.
|
||||
* Otherwise, word is substituted.
|
||||
*
|
||||
* Word is subjected to tilde expansion, parameter expansion,
|
||||
* command substitution, and arithmetic expansion.
|
||||
* If word is not needed, it is not expanded.
|
||||
*
|
||||
* Colon forms (${var:-word}, ${var:=word} etc) do the same,
|
||||
* but also treat null var as if it is unset.
|
||||
*/
|
||||
int use_word = (!val || ((exp_save == ':') && !val[0]));
|
||||
if (exp_op == '+')
|
||||
use_word = !use_word;
|
||||
debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
|
||||
(exp_save == ':') ? "true" : "false", use_word);
|
||||
if (use_word) {
|
||||
to_be_freed = expand_pseudo_dquoted(exp_word);
|
||||
if (to_be_freed)
|
||||
exp_word = to_be_freed;
|
||||
if (exp_op == '?') {
|
||||
/* mimic bash message */
|
||||
die_if_script("%s: %s",
|
||||
var,
|
||||
exp_word[0] ? exp_word : "parameter null or not set"
|
||||
);
|
||||
//TODO: how interactive bash aborts expansion mid-command?
|
||||
} else {
|
||||
val = exp_word;
|
||||
}
|
||||
|
||||
if (exp_op == '=') {
|
||||
/* ${var=[word]} or ${var:=[word]} */
|
||||
if (isdigit(var[0]) || var[0] == '#') {
|
||||
/* mimic bash message */
|
||||
die_if_script("$%s: cannot assign in this way", var);
|
||||
val = NULL;
|
||||
} else {
|
||||
char *new_var = xasprintf("%s=%s", var, val);
|
||||
set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* one of "-=+?" */
|
||||
|
||||
*exp_saveptr = exp_save;
|
||||
} /* if (exp_op) */
|
||||
|
||||
arg[0] = first_ch;
|
||||
#if ENABLE_HUSH_TICK
|
||||
store_val:
|
||||
#endif
|
||||
default:
|
||||
val = expand_one_var(&to_be_freed, arg, &p, first_ch);
|
||||
IF_HUSH_TICK(store_val:)
|
||||
if (!(first_ch & 0x80)) { /* unquoted $VAR */
|
||||
debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, output->o_escape);
|
||||
if (val) {
|
||||
if (val && val[0]) {
|
||||
/* unquoted var's contents should be globbed, so don't escape */
|
||||
smallint sv = output->o_escape;
|
||||
output->o_escape = 0;
|
||||
@ -3062,10 +3076,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
||||
} else { /* quoted $VAR, val will be appended below */
|
||||
debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, output->o_escape);
|
||||
}
|
||||
} /* default: */
|
||||
break;
|
||||
|
||||
} /* switch (char after <SPECIAL_VAR_SYMBOL>) */
|
||||
|
||||
if (val) {
|
||||
if (val && val[0]) {
|
||||
o_addQstr(output, val, strlen(val));
|
||||
}
|
||||
free(to_be_freed);
|
||||
|
Loading…
Reference in New Issue
Block a user