diff options
author | Chet Ramey <chet.ramey@case.edu> | 2011-11-21 20:51:19 -0500 |
---|---|---|
committer | Chet Ramey <chet.ramey@case.edu> | 2011-11-21 20:51:19 -0500 |
commit | 0001803f0b9523c94fa2ede48eaecb047fef4524 (patch) | |
tree | f334332811e033ff966d94f6268f0629a94304b3 /subst.c | |
parent | 89a92869e56aba4e4cab2d639c00a86f0545c862 (diff) | |
download | android_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.tar.gz android_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.tar.bz2 android_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.zip |
Bash-4.1 distribution source
Diffstat (limited to 'subst.c')
-rw-r--r-- | subst.c | 365 |
1 files changed, 297 insertions, 68 deletions
@@ -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, "ed_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); |