Bash-4.1 distribution source

This commit is contained in:
Chet Ramey 2011-11-21 20:51:19 -05:00
commit 0001803f0b
252 changed files with 51563 additions and 37176 deletions

365
subst.c
View file

@ -86,6 +86,7 @@ extern int errno;
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
/* These defs make it easier to use the editor. */
#define LBRACE '{'
@ -93,6 +94,11 @@ extern int errno;
#define LPAREN '('
#define RPAREN ')'
#if defined (HANDLE_MULTIBYTE)
#define WLPAREN L'('
#define WRPAREN L')'
#endif
/* Evaluates to 1 if C is one of the shell's special parameters whose length
can be taken, but is also one of the special expansion characters. */
#define VALID_SPECIAL_LENGTH_PARAM(c) \
@ -134,12 +140,20 @@ size_t ifs_firstc_len;
unsigned char ifs_firstc;
#endif
/* Sentinel to tell when we are performing variable assignments preceding a
command name and putting them into the environment. Used to make sure
we use the temporary environment when looking up variable values. */
int assigning_in_environment;
/* Used to hold a list of variable assignments preceding a command. Global
so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
SIGCHLD trap and so it can be saved and restored by the trap handlers. */
WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
/* Extern functions and variables from different files. */
extern int last_command_exit_value, last_command_exit_signal;
extern int subshell_environment;
extern int subshell_level, parse_and_execute_level;
extern int subshell_environment, line_number;
extern int subshell_level, parse_and_execute_level, sourcelevel;
extern int eof_encountered;
extern int return_catch_flag, return_catch_value;
extern pid_t dollar_dollar_pid;
@ -183,11 +197,6 @@ static int no_longjmp_on_fatal_error = 0;
$* on $IFS, primarily when doing assignment statements. */
static int expand_no_split_dollar_star = 0;
/* Used to hold a list of variable assignments preceding a command. Global
so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
SIGCHLD trap. */
WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
/* A WORD_LIST of words to be expanded by expand_word_list_internal,
without any leading variable assignments. */
static WORD_LIST *garglist = (WORD_LIST *)NULL;
@ -285,7 +294,7 @@ static char *parameter_brace_patsub __P((char *, char *, char *, int));
static char *pos_params_casemod __P((char *, char *, int, int));
static char *parameter_brace_casemod __P((char *, char *, int, char *, int));
static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *));
static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));
static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));
static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
@ -311,6 +320,135 @@ static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
/* */
/* **************************************************************** */
#if defined (DEBUG)
void
dump_word_flags (flags)
int flags;
{
int f;
f = flags;
fprintf (stderr, "%d -> ", f);
if (f & W_ASSIGNASSOC)
{
f &= ~W_ASSIGNASSOC;
fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
}
if (f & W_HASCTLESC)
{
f &= ~W_HASCTLESC;
fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
}
if (f & W_NOPROCSUB)
{
f &= ~W_NOPROCSUB;
fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
}
if (f & W_DQUOTE)
{
f &= ~W_DQUOTE;
fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
}
if (f & W_HASQUOTEDNULL)
{
f &= ~W_HASQUOTEDNULL;
fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
}
if (f & W_ASSIGNARG)
{
f &= ~W_ASSIGNARG;
fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
}
if (f & W_ASSNBLTIN)
{
f &= ~W_ASSNBLTIN;
fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
}
if (f & W_COMPASSIGN)
{
f &= ~W_COMPASSIGN;
fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
}
if (f & W_NOEXPAND)
{
f &= ~W_NOEXPAND;
fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
}
if (f & W_ITILDE)
{
f &= ~W_ITILDE;
fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
}
if (f & W_NOTILDE)
{
f &= ~W_NOTILDE;
fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
}
if (f & W_ASSIGNRHS)
{
f &= ~W_ASSIGNRHS;
fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
}
if (f & W_NOCOMSUB)
{
f &= ~W_NOCOMSUB;
fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
}
if (f & W_DOLLARSTAR)
{
f &= ~W_DOLLARSTAR;
fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
}
if (f & W_DOLLARAT)
{
f &= ~W_DOLLARAT;
fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
}
if (f & W_TILDEEXP)
{
f &= ~W_TILDEEXP;
fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
}
if (f & W_NOSPLIT2)
{
f &= ~W_NOSPLIT2;
fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
}
if (f & W_NOGLOB)
{
f &= ~W_NOGLOB;
fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
}
if (f & W_NOSPLIT)
{
f &= ~W_NOSPLIT;
fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
}
if (f & W_GLOBEXP)
{
f &= ~W_GLOBEXP;
fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
}
if (f & W_ASSIGNMENT)
{
f &= ~W_ASSIGNMENT;
fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
}
if (f & W_QUOTED)
{
f &= ~W_QUOTED;
fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
}
if (f & W_HASDOLLAR)
{
f &= ~W_HASDOLLAR;
fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
}
fprintf (stderr, "\n");
fflush (stderr);
}
#endif
#ifdef INCLUDE_UNUSED
static char *
quoted_substring (string, start, end)
@ -585,7 +723,7 @@ string_extract (string, sindex, charlist, flags)
{
int ni;
/* If this is an array subscript, skip over it and continue. */
ni = skipsubscript (string, i);
ni = skipsubscript (string, i, 0);
if (string[ni] == ']')
i = ni;
}
@ -899,7 +1037,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
char *charlist;
int flags;
{
register int i = *sindex;
register int i;
#if defined (HANDLE_MULTIBYTE)
size_t clen;
wchar_t *wcharlist;
@ -992,14 +1130,14 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
/* Extract the $( construct in STRING, and return a new string.
Start extracting at (SINDEX) as if we had just seen "$(".
Make (SINDEX) get the position of the matching ")". )
XFLAGS is additional flags to pass to other extraction functions, */
XFLAGS is additional flags to pass to other extraction functions. */
char *
extract_command_subst (string, sindex, xflags)
char *string;
int *sindex;
int xflags;
{
if (string[*sindex] == '(') /*)*/
if (string[*sindex] == LPAREN)
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
@ -1111,7 +1249,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
}
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
multibyte characters, too. See COMMENT_BEGIN define in parse.y */
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
{
in_comment = 1;
@ -1126,6 +1264,18 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
continue;
}
#if 0
/* Process a nested command substitution, but only if we're parsing a
command substitution. XXX - for bash-4.2 */
if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_command_subst (string, &si, flags);
i = si + 1;
continue;
}
#endif
/* Process a nested OPENER. */
if (STREQN (string + i, opener, len_opener))
{
@ -1377,7 +1527,10 @@ unquote_bang (string)
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
/* This function assumes s[i] == open; returns with s[ret] == close; used to
parse array subscripts. FLAGS currently unused. */
parse array subscripts. FLAGS & 1 means to not attempt to skip over
matched pairs of quotes or backquotes, or skip word expansions; it is
intended to be used after expansion has been performed and during final
assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
static int
skip_matched_pair (string, start, open, close, flags)
const char *string;
@ -1418,13 +1571,13 @@ skip_matched_pair (string, start, open, close, flags)
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '`')
else if ((flags & 1) == 0 && c == '`')
{
backq = 1;
i++;
continue;
}
else if (c == open)
else if ((flags & 1) == 0 && c == open)
{
count++;
i++;
@ -1438,13 +1591,13 @@ skip_matched_pair (string, start, open, close, flags)
i++;
continue;
}
else if (c == '\'' || c == '"')
else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
{
i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
: skip_double_quoted (ss, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
@ -1469,11 +1622,11 @@ skip_matched_pair (string, start, open, close, flags)
#if defined (ARRAY_VARS)
int
skipsubscript (string, start)
skipsubscript (string, start, flags)
const char *string;
int start;
int start, flags;
{
return (skip_matched_pair (string, start, '[', ']', 0));
return (skip_matched_pair (string, start, '[', ']', flags));
}
#endif
@ -1490,7 +1643,7 @@ skip_to_delim (string, start, delims, flags)
char *delims;
int flags;
{
int i, pass_next, backq, si, c, invert;
int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
size_t slen;
char *temp;
DECLARE_MBSTATE;
@ -1499,11 +1652,17 @@ skip_to_delim (string, start, delims, flags)
if (flags & SD_NOJMP)
no_longjmp_on_fatal_error = 1;
invert = (flags & SD_INVERT);
skipcmd = (flags & SD_NOSKIPCMD) == 0;
i = start;
pass_next = backq = 0;
while (c = string[i])
{
/* If this is non-zero, we should not let quote characters be delimiters
and the current character is a single or double quote. We should not
test whether or not it's a delimiter until after we skip single- or
double-quoted strings. */
skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
if (pass_next)
{
pass_next = 0;
@ -1531,7 +1690,7 @@ skip_to_delim (string, start, delims, flags)
i++;
continue;
}
else if (invert == 0 && member (c, delims))
else if (skipquote == 0 && invert == 0 && member (c, delims))
break;
else if (c == '\'' || c == '"')
{
@ -1539,7 +1698,7 @@ skip_to_delim (string, start, delims, flags)
: skip_double_quoted (string, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
@ -1555,7 +1714,21 @@ skip_to_delim (string, start, delims, flags)
i++;
continue;
}
else if (invert && (member (c, delims) == 0))
#if defined (PROCESS_SUBSTITUTION)
else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN)
{
si = i + 2;
if (string[si] == '\0')
CQ_RETURN(si);
temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
i = si;
if (string[i] == '\0')
break;
i++;
continue;
}
#endif /* PROCESS_SUBSTITUTION */
else if ((skipquote || invert) && (member (c, delims) == 0))
break;
else
ADVANCE_CHAR (string, slen, i);
@ -1673,14 +1846,14 @@ unclosed_pair (string, eindex, openstr)
the index of the word containing SENTINEL. Non-whitespace chars in
DELIMS delimit separate fields. */
WORD_LIST *
split_at_delims (string, slen, delims, sentinel, nwp, cwp)
split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
char *string;
int slen;
char *delims;
int sentinel;
int sentinel, flags;
int *nwp, *cwp;
{
int ts, te, i, nw, cw, ifs_split;
int ts, te, i, nw, cw, ifs_split, dflags;
char *token, *d, *d2;
WORD_LIST *ret, *tl;
@ -1737,7 +1910,7 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
ret = (WORD_LIST *)NULL;
/* Remove sequences of whitspace characters at the start of the string, as
/* Remove sequences of whitespace characters at the start of the string, as
long as those characters are delimiters. */
for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
;
@ -1747,9 +1920,10 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
ts = i;
nw = 0;
cw = -1;
dflags = flags|SD_NOJMP;
while (1)
{
te = skip_to_delim (string, ts, d, SD_NOJMP);
te = skip_to_delim (string, ts, d, dflags);
/* If we have a non-whitespace delimiter character, use it to make a
separate field. This is just about what $IFS splitting does and
@ -1807,9 +1981,10 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
/* Special case for SENTINEL at the end of STRING. If we haven't found
the word containing SENTINEL yet, and the index we're looking for is at
the end of STRING, add an additional null argument and set the current
word pointer to that. */
if (cwp && cw == -1 && sentinel >= slen)
the end of STRING (or past the end of the previously-found token,
possible if the end of the line is composed solely of IFS whitespace)
add an additional null argument and set the current word pointer to that. */
if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
{
if (whitespace (string[sentinel - 1]))
{
@ -2058,7 +2233,7 @@ string_list_dollar_at (list, quoted)
#if 0
tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
#else
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
#endif
? quote_list (list)
: list_quote_escapes (list);
@ -2526,7 +2701,6 @@ do_assignment_internal (word, expand)
}
else
#endif
if (expand && temp[0])
value = expand_string_if_necessary (temp, 0, expand_string_assignment);
else
@ -2554,7 +2728,7 @@ do_assignment_internal (word, expand)
aflags |= ASS_APPEND;
#if defined (ARRAY_VARS)
if (t = xstrchr (name, '[')) /*]*/
if (t = mbschr (name, '[')) /*]*/
{
if (assign_list)
{
@ -2739,7 +2913,7 @@ pos_params (string, start, end, quoted)
save = params = t;
}
for (i = 1; params && i < start; i++)
for (i = start ? 1 : 0; params && i < start; i++)
params = params->next;
if (params == 0)
return ((char *)NULL);
@ -2915,6 +3089,7 @@ cond_expand_word (w, special)
if (w->word == 0 || w->word[0] == '\0')
return ((char *)NULL);
w->flags |= W_NOSPLIT2;
l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
if (l)
{
@ -3787,11 +3962,11 @@ match_upattern (string, pat, mtype, sp, ep)
/* XXX - check this later if I ever implement `**' with special meaning,
since this will potentially result in `**' at the beginning or end */
len = STRLEN (pat);
if (pat[0] != '*' || (pat[0] == '*' && pat[1] == '(' && extended_glob) || pat[len - 1] != '*') /*)*/
if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
{
p = npat = (char *)xmalloc (len + 3);
p1 = pat;
if (*p1 != '*' || (*p1 == '*' && p1[1] == '(' && extended_glob)) /*)*/
if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
*p++ = '*';
while (*p1)
*p++ = *p1++;
@ -3931,11 +4106,11 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
/* XXX - check this later if I ever implement `**' with special meaning,
since this will potentially result in `**' at the beginning or end */
len = wcslen (wpat);
if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == L'(' && extended_glob) || wpat[len - 1] != L'*') /*)*/
if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
{
wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
wp1 = wpat;
if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == '(' && extended_glob)) /*)*/
if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
*wp++ = L'*';
while (*wp1 != L'\0')
*wp++ = *wp1++;
@ -4313,6 +4488,12 @@ expand_word_unsplit (word, quoted)
WORD_LIST *result;
expand_no_split_dollar_star = 1;
#if defined (HANDLE_MULTIBYTE)
if (ifs_firstc[0] == 0)
#else
if (ifs_firstc == 0)
#endif
word->flags |= W_NOSPLIT;
result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
expand_no_split_dollar_star = 0;
@ -4320,13 +4501,27 @@ expand_word_unsplit (word, quoted)
}
/* Perform shell expansions on WORD, but do not perform word splitting or
quote removal on the result. */
quote removal on the result. Virtually identical to expand_word_unsplit;
could be combined if implementations don't diverge. */
WORD_LIST *
expand_word_leave_quoted (word, quoted)
WORD_DESC *word;
int quoted;
{
return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL));
WORD_LIST *result;
expand_no_split_dollar_star = 1;
#if defined (HANDLE_MULTIBYTE)
if (ifs_firstc[0] == 0)
#else
if (ifs_firstc == 0)
#endif
word->flags |= W_NOSPLIT;
word->flags |= W_NOSPLIT2;
result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
expand_no_split_dollar_star = 0;
return result;
}
#if defined (PROCESS_SUBSTITUTION)
@ -4843,7 +5038,7 @@ command_substitute (string, quoted)
if (wordexp_only && read_but_dont_execute)
{
last_command_exit_value = 125;
last_command_exit_value = EX_WEXPCOMSUB;
jump_to_top_level (EXITPROG);
}
@ -4860,7 +5055,7 @@ command_substitute (string, quoted)
maybe_make_export_env (); /* XXX */
/* Flags to pass to parse_and_execute() */
pflags = interactive ? SEVAL_RESETLINE : 0;
pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
/* Pipe the output of executing STRING into the current shell. */
if (pipe (fildes) < 0)
@ -5058,6 +5253,7 @@ array_length_reference (s)
{
c = *--t;
*t = '\0';
last_command_exit_value = EXECUTION_FAILURE;
err_unboundvar (s);
*t = c;
return (-1);
@ -5168,7 +5364,7 @@ chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
#if defined (ARRAY_VARS)
else if (valid_array_reference (name))
{
temp1 = xstrchr (name, '[');
temp1 = mbschr (name, '[');
if (temp1 && temp1[1] == '@' && temp1[2] == ']')
{
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
@ -6008,7 +6204,13 @@ pat_subst (string, pat, rep, mflags)
break;
if (s == e)
e++, str++; /* avoid infinite recursion on zero-length match */
{
/* On a zero-length match, make sure we copy one character, since
we increment one character to avoid infinite recursion. */
RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
ret[rptr++] = *str++;
e++; /* avoid infinite recursion on zero-length match */
}
}
/* Now copy the unmatched portion of the input string */
@ -6375,9 +6577,9 @@ chk_arithsub (s, len)
i = count = 0;
while (i < len)
{
if (s[i] == '(')
if (s[i] == LPAREN)
count++;
else if (s[i] == ')')
else if (s[i] == RPAREN)
{
count--;
if (count < 0)
@ -6417,9 +6619,9 @@ chk_arithsub (s, len)
/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
static WORD_DESC *
parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
char *string;
int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
{
int check_nullness, var_is_set, var_is_null, var_is_special;
int want_substring, want_indir, want_patsub, want_casemod;
@ -6659,7 +6861,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
if (want_indir)
tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
else
tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2));
if (tdesc)
{
@ -6929,8 +7131,8 @@ param_expand (string, sindex, quoted, expanded_something,
uerror[0] = '$';
uerror[1] = c;
uerror[2] = '\0';
err_unboundvar (uerror);
last_command_exit_value = EXECUTION_FAILURE;
err_unboundvar (uerror);
return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
}
if (temp1)
@ -6977,8 +7179,8 @@ param_expand (string, sindex, quoted, expanded_something,
uerror[0] = '$';
uerror[1] = c;
uerror[2] = '\0';
err_unboundvar (uerror);
last_command_exit_value = EXECUTION_FAILURE;
err_unboundvar (uerror);
return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
}
}
@ -7015,14 +7217,14 @@ param_expand (string, sindex, quoted, expanded_something,
even if it's quoted. */
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
temp = (char *)NULL;
else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
{
/* If we have "$*" we want to make a string of the positional
parameters, separated by the first character of $IFS, and
quote the whole string, including the separators. If IFS
is unset, the parameters are separated by ' '; if $IFS is
null, the parameters are concatenated. */
temp = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list);
temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
temp1 = quote_string (temp);
if (*temp == 0)
tflag |= W_HASQUOTEDNULL;
@ -7087,11 +7289,17 @@ param_expand (string, sindex, quoted, expanded_something,
string might need it (consider "\"$@\""), but we need some
way to signal that the final split on the first character
of $IFS should be done, even though QUOTED is 1. */
/* XXX - should this test include Q_PATQUOTE? */
if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
*quoted_dollar_at_p = 1;
if (contains_dollar_at)
*contains_dollar_at = 1;
#if 0
if (pflags & PF_NOSPLIT2)
temp = string_list_internal (quoted ? quote_list (list) : list, " ");
else
#endif
/* We want to separate the positional parameters with the first
character of $IFS in case $IFS is something other than a space.
We also want to make sure that splitting is done no matter what --
@ -7103,7 +7311,7 @@ param_expand (string, sindex, quoted, expanded_something,
break;
case LBRACE:
tdesc = parameter_brace_expand (string, &zindex, quoted,
tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
quoted_dollar_at_p,
contains_dollar_at);
@ -7162,6 +7370,9 @@ param_expand (string, sindex, quoted, expanded_something,
if (chk_arithsub (temp2, t_index) == 0)
{
free (temp2);
#if 0
internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
#endif
goto comsub;
}
@ -7280,7 +7491,10 @@ comsub:
unbound_variable:
if (unbound_vars_is_error)
err_unboundvar (temp1);
{
last_command_exit_value = EXECUTION_FAILURE;
err_unboundvar (temp1);
}
else
{
free (temp1);
@ -7378,6 +7592,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin
int had_quoted_null;
int has_dollar_at;
int tflag;
int pflags; /* flags passed to param_expand */
int assignoff; /* If assignment, offset of `=' */
@ -7487,7 +7702,7 @@ add_string:
even in POSIX mode. */
if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
{
if (isexp == 0 && isifs (c))
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
goto add_ifs_character;
else
goto add_character;
@ -7507,7 +7722,7 @@ add_string:
string[sindex+1] == '~')
word->flags |= W_ITILDE;
#endif
if (isexp == 0 && isifs (c))
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
goto add_ifs_character;
else
goto add_character;
@ -7515,7 +7730,7 @@ add_string:
case ':':
if (word->flags & W_NOTILDE)
{
if (isexp == 0 && isifs (c))
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
goto add_ifs_character;
else
goto add_character;
@ -7525,7 +7740,7 @@ add_string:
string[sindex+1] == '~')
word->flags |= W_ITILDE;
if (isexp == 0 && isifs (c))
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
goto add_ifs_character;
else
goto add_character;
@ -7539,7 +7754,7 @@ add_string:
(quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
{
word->flags &= ~W_ITILDE;
if (isexp == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
goto add_ifs_character;
else
goto add_character;
@ -7581,10 +7796,12 @@ add_string:
*expanded_something = 1;
has_dollar_at = 0;
pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
if (word->flags & W_NOSPLIT2)
pflags |= PF_NOSPLIT2;
tword = param_expand (string, &sindex, quoted, expanded_something,
&has_dollar_at, &quoted_dollar_at,
&had_quoted_null,
(word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0);
&had_quoted_null, pflags);
if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
{
@ -7779,6 +7996,11 @@ add_twochars:
{
if (list->next)
{
#if 0
if (quoted_dollar_at && word->flags & W_NOSPLIT2)
temp = string_list_internal (quote_list (list), " ");
else
#endif
/* Testing quoted_dollar_at makes sure that "$@" is
split correctly when $IFS does not contain a space. */
temp = quoted_dollar_at
@ -8297,7 +8519,7 @@ separate_out_assignments (tlist)
{
register WORD_LIST *vp, *lp;
if (!tlist)
if (tlist == 0)
return ((WORD_LIST *)NULL);
if (subst_assign_varlist)
@ -8549,14 +8771,21 @@ brace_expand_word_list (tlist, eflags)
{
next = tlist->next;
if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
{
/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
PREPEND_LIST (tlist, output_list);
continue;
}
/* Only do brace expansion if the word has a brace character. If
not, just add the word list element to BRACES and continue. In
the common case, at least when running shell scripts, this will
degenerate to a bunch of calls to `xstrchr', and then what is
degenerate to a bunch of calls to `mbschr', and then what is
basically a reversal of TLIST into BRACES, which is corrected
by a call to REVERSE_LIST () on BRACES when the end of TLIST
is reached. */
if (xstrchr (tlist->word->word, LBRACE))
if (mbschr (tlist->word->word, LBRACE))
{
expansions = brace_expand (tlist->word->word);