diff options
author | Jari Aalto <jari.aalto@cante.net> | 2001-04-06 19:14:31 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:53 +0000 |
commit | 28ef6c316f1aff914bb95ac09787a3c83c1815fd (patch) | |
tree | 2812fe7ffc9beec4f99856906ddfcafda54cf16a /subst.c | |
parent | bb70624e964126b7ac4ff085ba163a9c35ffa18f (diff) | |
download | android_external_bash-28ef6c316f1aff914bb95ac09787a3c83c1815fd.tar.gz android_external_bash-28ef6c316f1aff914bb95ac09787a3c83c1815fd.tar.bz2 android_external_bash-28ef6c316f1aff914bb95ac09787a3c83c1815fd.zip |
Imported from ../bash-2.05.tar.gz.
Diffstat (limited to 'subst.c')
-rw-r--r-- | subst.c | 656 |
1 files changed, 419 insertions, 237 deletions
@@ -80,11 +80,26 @@ extern int errno; #define LPAREN '(' #define RPAREN ')' +/* 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) \ + ((c) == '-' || (c) == '?' || (c) == '#') + +/* Evaluates to 1 if C is one of the shell's special parameters for which an + indirect variable reference may be made. */ +#define VALID_INDIR_PARAM(c) \ + ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*') + +/* Evaluates to 1 if C is one of the OP characters that follows the parameter + in ${parameter[:]OPword}. */ +#define VALID_PARAM_EXPAND_CHAR(c) \ + ((c) == '-' || (c) == '=' || (c) == '?' || (c) == '+') + /* Evaluates to 1 if this is one of the shell's special variables. */ #define SPECIAL_VAR(name, wi) \ - ((digit (*name) && all_digits (name)) || \ - (name[1] == '\0' && member (*name, "#-?$!@*")) || \ - (wi && name[2] == '\0' && member (name[1], "#?@*"))) + ((isdigit (*name) && all_digits (name)) || \ + (name[1] == '\0' && (sh_syntaxtab[*name] & CSPECVAR)) || \ + (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) /* Process ID of the last command executed within command substitution. */ pid_t last_command_subst_pid = NO_PID; @@ -115,13 +130,19 @@ static int glob_argv_flags_size; static WORD_LIST expand_word_error, expand_word_fatal; static char expand_param_error, expand_param_fatal; -static int doing_completion = 0; -static int doing_prompt_expansion = 0; +/* Tell the expansion functions to not longjmp back to top_level on fatal + errors. Enabled when doing completion and prompt string expansion. */ +static int no_longjmp_on_fatal_error = 0; + +/* Set by expand_word_unsplit; used to inhibit splitting and re-joining + $* 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; @@ -187,12 +208,12 @@ quoted_substring (string, start, end) { if (*s == CTLESC) { - s++; - continue; + s++; + continue; } l++; if (*s == 0) - break; + break; } r = result = xmalloc (2*len + 1); /* save room for quotes */ @@ -202,11 +223,11 @@ quoted_substring (string, start, end) for (l = 0; l < len; s++) { if (*s == CTLESC) - *r++ = *s++; + *r++ = *s++; *r++ = *s; l++; if (*s == 0) - break; + break; } *r = '\0'; return result; @@ -460,7 +481,7 @@ string_extract_double_quoted (string, sindex, stripdq) The returned string will be run through expansion as if it were double-quoted. */ if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && strchr (slashify_in_quotes, c)) || dquote == 0))) + (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) temp[j++] = '\\'; temp[j++] = c; pass_next = 0; @@ -518,7 +539,7 @@ string_extract_double_quoted (string, sindex, stripdq) } /* Add any character but a double quote to the quoted string we're - accumulating. */ + accumulating. */ if (c != '"') { temp[j++] = c; @@ -632,13 +653,13 @@ skip_single_quoted (string, sind) char *string; int sind; { - register int i; + register int c; - for (i = sind; string[i] && string[i] != '\''; i++) + for (c = sind; string[c] && string[c] != '\''; c++) ; - if (string[i]) - i++; - return i; + if (string[c]) + c++; + return c; } /* Just like string_extract, but doesn't hack backslashes or any of @@ -688,7 +709,7 @@ extract_command_subst (string, sindex) return (extract_delimited_string (string, sindex, "$(", "(", ")")); } -/* Extract the $[ construct in STRING, and return a new string. +/* 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 "]". */ char * @@ -696,7 +717,7 @@ extract_arithmetic_subst (string, sindex) char *string; int *sindex; { - return (extract_delimited_string (string, sindex, "$[", "[", "]")); + return (extract_delimited_string (string, sindex, "$[", "[", "]")); /*]*/ } #if defined (PROCESS_SUBSTITUTION) @@ -756,7 +777,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer) c = string[i]; if (c == 0) - break; + break; if (pass_character) /* previous char was backslash */ { @@ -772,12 +793,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer) continue; } -#if 0 - if (c == '\\' && delimiter == '"' && - (member (string[i], slashify_in_quotes))) -#else if (c == '\\') -#endif { pass_character++; i++; @@ -816,29 +832,29 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer) /* Pass old-style command substitution through verbatim. */ if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", 0); - i = si + 1; - FREE (t); - continue; - } + { + si = i + 1; + t = string_extract (string, &si, "`", 0); + i = si + 1; + FREE (t); + continue; + } /* Pass single-quoted strings through verbatim. */ if (c == '\'') - { - si = i + 1; - i = skip_single_quoted (string, si); - continue; - } + { + si = i + 1; + i = skip_single_quoted (string, si); + continue; + } /* Pass embedded double-quoted strings through verbatim as well. */ if (c == '"') - { - si = i + 1; - i = skip_double_quoted (string, si); - continue; - } + { + si = i + 1; + i = skip_double_quoted (string, si); + continue; + } i++; /* move past this character, which was not special. */ } @@ -846,10 +862,11 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer) #if 0 if (c == 0 && nesting_level) #else - if (c == 0 && nesting_level && doing_completion == 0) + if (c == 0 && nesting_level && no_longjmp_on_fatal_error == 0) #endif { report_error ("bad substitution: no `%s' in %s", closer, string); + last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level (DISCARD); } @@ -948,9 +965,10 @@ extract_dollar_brace_string (string, sindex, quoted) } } - if (c == 0 && nesting_level && doing_completion == 0) + if (c == 0 && nesting_level && no_longjmp_on_fatal_error == 0) { report_error ("bad substitution: no ending `}' in %s", string); + last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level (DISCARD); } @@ -1003,11 +1021,11 @@ unquote_bang (string) #if defined (READLINE) /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. DOING_COMPLETION is used to flag that the various + by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various single and double-quoted string parsing functions should not return an error if there are unclosed quotes or braces. */ -#define CQ_RETURN(x) do { doing_completion = 0; return (x); } while (0) +#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) int char_is_quoted (string, eindex) @@ -1016,7 +1034,7 @@ char_is_quoted (string, eindex) { int i, pass_next, quoted; - doing_completion = 1; + no_longjmp_on_fatal_error = 1; for (i = pass_next = quoted = 0; i <= eindex; i++) { if (pass_next) @@ -1097,7 +1115,7 @@ skip_to_delim (string, start, delims) int i, pass_next, backq, si; char *temp; - doing_completion = 1; + no_longjmp_on_fatal_error = 1; for (i = start, pass_next = backq = 0; string[i]; i++) { if (pass_next) @@ -1143,7 +1161,7 @@ skip_to_delim (string, start, delims) continue; } else if (member (string[i], delims)) - break; + break; } CQ_RETURN(i); } @@ -1192,7 +1210,7 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp) ret = (WORD_LIST *)NULL; - for (i = 0; member (string[i], d) && whitespace(string[i]); i++) + for (i = 0; member (string[i], d) && (whitespace(string[i]) || string[i] == '\n'); i++) ; if (string[i] == '\0') return (ret); @@ -1207,10 +1225,10 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp) /* If we have a non-whitespace delimiter character, use it to make a separate field. This is just about what $IFS splitting does and is closer to the behavior of the shell parser. */ - if (ts == te && member(string[ts], d2)) + if (ts == te && d2 && member (string[ts], d2)) { te = ts + 1; - while (member(string[te], d2)) + while (member (string[te], d2)) te++; } @@ -1224,27 +1242,27 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp) cw = nw; /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ + sentinel word to the current word. */ if (cwp && cw == -1 && sentinel == ts-1) cw = nw; /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ + word, add it before (well, after, since the list is in reverse order) + the word we just added, and set the current word to that one. */ if (cwp && cw == -1 && sentinel < ts) - { - tl = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); - tl->word = make_word (""); - tl->next = ret->next; - ret->next = tl; - cw = nw; - nw++; - } + { + tl = (WORD_LIST *)xmalloc (sizeof (WORD_LIST)); + tl->word = make_word (""); + tl->next = ret->next; + ret->next = tl; + cw = nw; + nw++; + } if (string[te] == 0) break; - i = te + member(string[te], d); + i = te + member (string[te], d); while (member (string[i], d) && whitespace(string[i])) i++; @@ -1261,11 +1279,11 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp) if (cwp && cw == -1 && sentinel >= slen) { if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } + { + token = ""; + ret = add_string_to_list (token, ret); + nw++; + } cw = nw; } @@ -1444,7 +1462,7 @@ list_string (string, separators, quoted) WORD_LIST *result; WORD_DESC *t; char *current_word, *s; - int sindex, sh_style_split; + int sindex, sh_style_split, whitesep; if (!string || !*string) return ((WORD_LIST *)NULL); @@ -1511,6 +1529,9 @@ list_string (string, separators, quoted) free (current_word); + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = string[sindex] && spctabnl (string[sindex]); + /* Move past the current separator character. */ if (string[sindex]) sindex++; @@ -1519,6 +1540,13 @@ list_string (string, separators, quoted) in the list of separators. */ while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex])) sindex++; + + /* If the first separator was IFS whitespace and the current character is + a non-whitespace IFS character, it should be part of the current field + delimiter, not a separate delimiter that would result in an empty field. + Look at POSIX.2, 3.6.5, (3)(b). */ + if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex])) + sindex++; } return (REVERSE_LIST (result, WORD_LIST *)); } @@ -1534,7 +1562,7 @@ get_word_from_string (stringp, separators, endptr) { register char *s; char *current_word; - int sindex, sh_style_split; + int sindex, sh_style_split, whitesep; if (!stringp || !*stringp || !**stringp) return ((char *)NULL); @@ -1573,6 +1601,9 @@ get_word_from_string (stringp, separators, endptr) if (endptr) *endptr = s + sindex; + /* Note whether or not the separator is IFS whitespace, used later. */ + whitesep = s[sindex] && spctabnl (s[sindex]); + /* Move past the current separator character. */ if (s[sindex]) sindex++; @@ -1582,6 +1613,13 @@ get_word_from_string (stringp, separators, endptr) while (s[sindex] && spctabnl (s[sindex]) && issep (s[sindex])) sindex++; + /* If the first separator was IFS whitespace and the current character is + a non-whitespace IFS character, it should be part of the current field + delimiter, not a separate delimiter that would result in an empty field. + Look at POSIX.2, 3.6.5, (3)(b). */ + if (s[sindex] && whitesep && issep (s[sindex]) && !spctabnl (s[sindex])) + sindex++; + /* Update STRING to point to the next field. */ *stringp = s + sindex; return (current_word); @@ -1636,7 +1674,7 @@ list_string_with_quotes (string) i++; } else if (c == '\'') - i = skip_single_quoted (s, ++i); + i = skip_single_quoted (s, ++i); else if (c == '"') i = skip_double_quoted (s, ++i); else if (c == 0 || spctabnl (c)) @@ -1689,12 +1727,12 @@ do_array_element_assignment (name, value) ind = array_expand_index (t, ni - ind); if (ind < 0) { - t[-1] = '['; /* restore original name */ + t[-1] = '['; /* restore original name ] */ report_error ("%s: bad array subscript", name); return ((SHELL_VAR *)NULL); } entry = bind_array_variable (name, ind, value); - t[-1] = '['; /* restore original name */ + t[-1] = '['; /* restore original name ] */ return (entry); } #endif /* ARRAY_VARS */ @@ -1739,7 +1777,7 @@ do_assignment_internal (string, expand) /* Perform tilde expansion. */ if (expand && temp[0]) - { + { temp = (strchr (temp, '~') && unquoted_member ('~', temp)) ? bash_tilde_expand (temp) : savestring (temp); @@ -1768,7 +1806,7 @@ do_assignment_internal (string, expand) #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) #if defined (ARRAY_VARS) - if (t = strchr (name, '[')) + if (t = strchr (name, '[')) /*]*/ { if (assign_list) { @@ -1777,7 +1815,7 @@ do_assignment_internal (string, expand) } entry = do_array_element_assignment (name, value); if (entry == 0) - ASSIGN_RETURN (0); + ASSIGN_RETURN (0); } else if (assign_list) entry = assign_array_from_string (name, value); @@ -1791,7 +1829,7 @@ do_assignment_internal (string, expand) VUNSETATTR (entry, att_invisible); /* Return 1 if the assignment seems to have been performed correctly. */ - ASSIGN_RETURN (entry ? (readonly_p (entry) == 0) : 0); + ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); } /* Perform the assignment statement in STRING, and expand the @@ -1863,7 +1901,7 @@ get_dollar_var_value (ind) { ind -= 10; for (p = rest_of_args; p && ind--; p = p->next) - ; + ; temp = p ? savestring (p->word->word) : (char *)NULL; } return (temp); @@ -2014,9 +2052,9 @@ remove_backslashes (string) for (s = string; s && *s; ) { if (*s == '\\') - s++; + s++; if (*s == 0) - break; + break; *r++ = *s++; } *r = '\0'; @@ -2041,6 +2079,13 @@ cond_expand_word (w, special) if (w->word == 0 || w->word[0] == '\0') return ((char *)NULL); + if (strchr (w->word, '~') && unquoted_member ('~', w->word)) + { + p = bash_tilde_expand (w->word); + free (w->word); + w->word = p; + } + l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); if (l) { @@ -2050,11 +2095,11 @@ cond_expand_word (w, special) r = string_list (l); } else - { - p = string_list (l); - r = quote_string_for_globbing (p, QGLOB_CVTNULL); - free (p); - } + { + p = string_list (l); + r = quote_string_for_globbing (p, QGLOB_CVTNULL); + free (p); + } dispose_words (l); } else @@ -2077,11 +2122,13 @@ call_expand_word_internal (w, q, i, c, e) result = expand_word_internal (w, q, i, c, e); if (result == &expand_word_error || result == &expand_word_fatal) { + expand_no_split_dollar_star = 0; /* XXX */ /* By convention, each time this error is returned, w->word has already been freed (it sometimes may not be in the fatal case, but that doesn't result in a memory leak because we're going to exit in most cases). */ w->word = (char *)NULL; + last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); /* NOTREACHED */ } @@ -2102,9 +2149,12 @@ expand_string_internal (string, quoted) if (string == 0 || *string == 0) return ((WORD_LIST *)NULL); - bzero ((char *)&td, sizeof (td)); - td.word = string; + td.flags = 0; + td.word = savestring (string); + tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); + + FREE (td.word); return (tresult); } @@ -2120,10 +2170,13 @@ expand_string_unsplit (string, quoted) { WORD_LIST *value; - if (!string || !*string) + if (string == 0 || *string == '\0') return ((WORD_LIST *)NULL); + expand_no_split_dollar_star = 1; value = expand_string_internal (string, quoted); + expand_no_split_dollar_star = 0; + if (value) { if (value->word) @@ -2149,11 +2202,13 @@ expand_prompt_string (string, quoted) if (string == 0 || *string == 0) return ((WORD_LIST *)NULL); - bzero ((char *)&td, sizeof (td)); + td.flags = 0; td.word = savestring (string); - doing_prompt_expansion = 1; + + no_longjmp_on_fatal_error = 1; value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - doing_prompt_expansion = 0; + no_longjmp_on_fatal_error = 0; + if (value == &expand_word_error || value == &expand_word_fatal) { value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); @@ -2209,7 +2264,7 @@ expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) if (string == 0 || *string == '\0') return (WORD_LIST *)NULL; - bzero ((char *)&td, sizeof (td)); + td.flags = 0; td.word = string; tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); return (tresult); @@ -2227,7 +2282,7 @@ expand_string (string, quoted) { WORD_LIST *result; - if (!string || !*string) + if (string == 0 || *string == '\0') return ((WORD_LIST *)NULL); result = expand_string_leave_quoted (string, quoted); @@ -2494,7 +2549,7 @@ remove_quoted_nulls (string) continue; } if (*s == CTLNUL) - continue; + continue; *p++ = *s; } *p = '\0'; @@ -2625,13 +2680,13 @@ match_pattern_char (pat, string) case '\\': return (*string == *pat); case '?': - return (*string == LPAREN ? 1 : (*string != '\0')); + return (*pat == LPAREN ? 1 : (*string != '\0')); case '*': return (1); case '+': case '!': case '@': - return (*string == LPAREN ? 1 : (*string == c)); + return (*pat == LPAREN ? 1 : (*string == c)); case '[': return (*string != '\0'); } @@ -2683,7 +2738,7 @@ match_pattern (string, pat, mtype, sp, ep) case MATCH_BEG: if (match_pattern_char (pat, string) == 0) - return (0); + return (0); for (p = end; p >= string; p--) { c = *p; *p = '\0'; @@ -2870,14 +2925,14 @@ array_remove_pattern (value, aspec, aval, c, quoted) if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') { if (array_p (var) == 0) - { - report_error ("%s: bad array subscript", aspec); - FREE (pattern); - return ((char *)NULL); - } + { + report_error ("%s: bad array subscript", aspec); + FREE (pattern); + return ((char *)NULL); + } l = array_to_word_list (array_cell (var)); if (l == 0) - return ((char *)NULL); + return ((char *)NULL); ret = list_remove_pattern (l, pattern, patspec, t[0], quoted); dispose_words (l); } @@ -2924,13 +2979,16 @@ expand_word (word, quoted) does parameter expansion, command substitution, arithmetic expansion, and quote removal. */ WORD_LIST * -expand_word_no_split (word, quoted) +expand_word_unsplit (word, quoted) WORD_DESC *word; int quoted; { WORD_LIST *result; + expand_no_split_dollar_star = 1; result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + expand_no_split_dollar_star = 0; + return (result ? dequote_list (result) : result); } @@ -2958,7 +3016,6 @@ expand_word_leave_quoted (word, quoted) unlink all of them. add_fifo_list adds the name of an open FIFO to the list. NFIFO is a count of the number of FIFOs in the list. */ #define FIFO_INCR 20 -extern char *mktemp (); static char **fifo_list = (char **)NULL; static int nfifo; @@ -2998,7 +3055,7 @@ make_named_pipe () { char *tname; - tname = mktemp (savestring ("/tmp/sh-np-XXXXXX")); + tname = sh_mktmpname ("sh-np", MT_USERANDOM); if (mkfifo (tname, 0600) < 0) { free (tname); @@ -3171,7 +3228,7 @@ process_substitute (string, open_for_read_in_child) /* Cancel traps, in trap.c. */ restore_original_signals (); setup_async_signals (); - subshell_environment = SUBSHELL_COMSUB; + subshell_environment |= SUBSHELL_COMSUB; } #if defined (JOB_CONTROL) @@ -3227,7 +3284,7 @@ process_substitute (string, open_for_read_in_child) } if (open_for_read_in_child) { - if (unset_nodelay_mode (fd) < 0) + if (sh_unset_nodelay_mode (fd) < 0) { sys_error ("cannout reset nodelay mode for fd %d", fd); exit (127); @@ -3290,11 +3347,15 @@ read_comsub (fd, quoted) istring = (char *)NULL; istring_index = istring_size = bufn = 0; +#ifdef __CYGWIN__ + setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */ +#endif + /* Read the output of the command through the pipe. */ while (1) { if (fd < 0) - break; + break; if (--bufn <= 0) { bufn = zread (fd, buf, sizeof (buf)); @@ -3304,6 +3365,14 @@ read_comsub (fd, quoted) } c = *bufp++; + if (c == 0) + { +#if 0 + internal_warning ("read_comsub: ignored null byte in input"); +#endif + continue; + } + /* Add the character to ISTRING, possibly after resizing it. */ RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); @@ -3311,6 +3380,16 @@ read_comsub (fd, quoted) istring[istring_index++] = CTLESC; istring[istring_index++] = c; + +#if 0 +#if defined (__CYGWIN__) + if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') + { + istring_index--; + istring[istring_index - 1] = '\n'; + } +#endif +#endif } if (istring) @@ -3394,7 +3473,9 @@ command_substitute (string, quoted) old_pid = last_made_pid; #if defined (JOB_CONTROL) old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; + /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ + if ((subshell_environment & SUBSHELL_PIPE) == 0) + pipeline_pgrp = shell_pgrp; cleanup_the_pipeline (); #endif @@ -3424,11 +3505,7 @@ command_substitute (string, quoted) if (pid == 0) { set_sigint_handler (); /* XXX */ -#if 0 -#if defined (JOB_CONTROL) - set_job_control (0); -#endif -#endif + if (dup2 (fildes[1], 1) < 0) { sys_error ("command_substitute: cannot duplicate pipe as fd 1"); @@ -3455,10 +3532,12 @@ command_substitute (string, quoted) interactive = 0; /* This is a subshell environment. */ - subshell_environment = SUBSHELL_COMSUB; + subshell_environment |= SUBSHELL_COMSUB; - /* Command substitution does not inherit the -e flag. */ - exit_immediately_on_error = 0; + /* When not in POSIX mode, command substitution does not inherit + the -e flag. */ + if (posixly_correct == 0) + exit_immediately_on_error = 0; remove_quoted_escapes (string); @@ -3517,9 +3596,9 @@ command_substitute (string, quoted) #if 0 if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid) #else - if (interactive && pipeline_pgrp != (pid_t)0 && subshell_environment != SUBSHELL_ASYNC) + if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) #endif - give_terminal_to (pipeline_pgrp); + give_terminal_to (pipeline_pgrp, 0); #endif /* JOB_CONTROL */ return (istring); @@ -3542,7 +3621,7 @@ valid_array_reference (name) char *t; int r, len; - t = strchr (name, '['); + t = strchr (name, '['); /* ] */ if (t) { *t = '\0'; @@ -3580,7 +3659,10 @@ array_expand_index (s, len) free (t); free (exp); if (expok == 0) - jump_to_top_level (DISCARD); + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (DISCARD); + } return val; } @@ -3607,7 +3689,7 @@ array_variable_part (s, subp, lenp) *t = '\0'; var = find_variable (s); - *t++ = '['; + *t++ = '['; /* ] */ if (subp) *subp = t; @@ -3631,23 +3713,26 @@ array_value_internal (s, quoted, allow_all) if (var == 0) return (char *)NULL; + /* [ */ if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') { - if (array_p (var) == 0 || allow_all == 0) - { - report_error ("%s: bad array subscript", s); - return ((char *)NULL); - } - l = array_to_word_list (array_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *) NULL); + if (allow_all == 0) + { + report_error ("%s: bad array subscript", s); + return ((char *)NULL); + } + else if (array_p (var) == 0) + { + l = (WORD_LIST *)NULL; + l = add_string_to_list (value_cell (var), l); + } + else + { + l = array_to_word_list (array_cell (var)); + if (l == (WORD_LIST *)NULL) + return ((char *) NULL); + } -#if 0 - if (t[0] == '*') /* ${name[*]} */ - retval = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); - else /* ${name[@]} */ - retval = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); -#else if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) { temp = string_list_dollar_star (l); @@ -3656,7 +3741,6 @@ array_value_internal (s, quoted, allow_all) } else /* ${name[@]} or unquoted ${name[*]} */ retval = string_list_dollar_at (l, quoted); -#endif dispose_words (l); } @@ -3669,7 +3753,7 @@ array_value_internal (s, quoted, allow_all) return ((char *)NULL); } if (array_p (var) == 0) - return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL); + return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL); retval = array_reference (array_cell (var), ind); if (retval) retval = quote_escapes (retval); @@ -3721,13 +3805,15 @@ array_length_reference (s) } else if (var == 0) return 0; - else if (array_p (var) == 0) - return 1; - array = array_cell (var); + /* We support a couple of expansions for variables that are not arrays. + We'll return the length of the value for v[0], and 1 for v[@] or + v[*]. Return 0 for everything else. */ + + array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - return (array_num_elements (array)); + return (array_p (var) ? array_num_elements (array) : 1); ind = array_expand_index (t, len); if (ind < 0) @@ -3735,9 +3821,13 @@ array_length_reference (s) report_error ("%s: bad array subscript", t); return (-1); } - t = array_reference (array, ind); - len = STRLEN (t); + if (array_p (var)) + t = array_reference (array, ind); + else + t = (ind == 0) ? value_cell (var) : (char *)NULL; + + len = STRLEN (t); return (len); } #endif /* ARRAY_VARS */ @@ -3747,7 +3837,7 @@ valid_brace_expansion_word (name, var_is_special) char *name; int var_is_special; { - if (digit (*name) && all_digits (name)) + if (isdigit (*name) && all_digits (name)) return 1; else if (var_is_special) return 1; @@ -3777,7 +3867,7 @@ parameter_brace_expand_word (name, var_is_special, quoted) WORD_LIST *l; /* Handle multiple digit arguments, as in ${11}. */ - if (digit (*name)) + if (isdigit (*name)) { arg_index = atoi (name); temp = get_dollar_var_value (arg_index); @@ -3808,7 +3898,7 @@ parameter_brace_expand_word (name, var_is_special, quoted) else if (var = find_variable (name)) { if (var && invisible_p (var) == 0) - { + { #if defined (ARRAY_VARS) temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var); #else @@ -3820,7 +3910,7 @@ parameter_brace_expand_word (name, var_is_special, quoted) if (tempvar_p (var)) dispose_variable (var); - } + } else temp = (char *)NULL; } @@ -3865,7 +3955,7 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) int hasdol; temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value))) - ? bash_tilde_expand (value) + ? bash_tilde_expand (value) : savestring (value); /* If the entire expression is between double quotes, we want to treat @@ -3935,7 +4025,12 @@ parameter_brace_expand_error (name, value) if (value && *value) { - l = expand_string (value, 0); + temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value))) + ? bash_tilde_expand (value) + : savestring (value); + + l = expand_string (temp, 0); + FREE (temp); temp = string_list (l); report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ FREE (temp); @@ -3956,10 +4051,9 @@ static int valid_length_expression (name) char *name; { - return (!name[1] || /* ${#} */ - ((name[1] == '@' || name[1] == '*') && !name[2]) || /* ${#@}, ${#*} */ - (member (name[1], "-?$!#") && !name[2]) || /* ${#-}, etc. */ - (digit (name[1]) && all_digits (name + 1)) || /* ${#11} */ + return (name[1] == '\0' || /* ${#} */ + ((sh_syntaxtab[name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ + (isdigit (name[1]) && all_digits (name + 1)) || /* ${#11} */ #if defined (ARRAY_VARS) valid_array_reference (name + 1) || /* ${#a[7]} */ #endif @@ -3983,7 +4077,7 @@ parameter_brace_expand_length (name) number = number_of_args (); else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ number = number_of_args (); - else if (member (name[1], "-?$!#") && name[2] == '\0') + else if ((sh_syntaxtab[name[1]] & CSPECVAR) && name[2] == '\0') { /* Take the lengths of some of the shell's special parameters. */ switch (name[1]) @@ -4018,7 +4112,7 @@ parameter_brace_expand_length (name) { number = 0; - if (digit (name[1])) /* ${#1} */ + if (isdigit (name[1])) /* ${#1} */ { t = get_dollar_var_value (atoi (name + 1)); number = STRLEN (t); @@ -4049,6 +4143,54 @@ parameter_brace_expand_length (name) return (number); } +/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, + so we do some ad-hoc parsing of an arithmetic expression to find + the first DELIM, instead of using strchr(3). Two rules: + 1. If the substring contains a `(', read until closing `)'. + 2. If the substring contains a `?', read past one `:' for each `?'. +*/ + +static char * +skiparith (substr, delim) + char *substr; + int delim; +{ + int skipcol, pcount; + char *t; + + for (skipcol = pcount = 0, t = substr; *t; t++) + { + /* Balance parens */ + if (*t == '(') + { + pcount++; + continue; + } + if (*t == ')' && pcount) + { + pcount--; + continue; + } + if (pcount) + continue; + + /* Skip one `:' for each `?' */ + if (*t == ':' && skipcol) + { + skipcol--; + continue; + } + if (*t == delim) + break; + if (*t == '?') + { + skipcol++; + continue; + } + } + return t; +} + /* Verify and limit the start and end of the desired substring. If VTYPE == 0, a regular shell variable is being used; if it is 1, then the positional parameters are being used; if it is 2, then @@ -4066,9 +4208,18 @@ verify_substring_values (value, substr, vtype, e1p, e2p) ARRAY *a; #endif +#if 1 + /* duplicate behavior of strchr(3) */ + t = skiparith (substr, ':'); + if (*t && *t == ':') + *t = '\0'; + else + t = (char *)0; +#else t = strchr (substr, ':'); if (t) *t = '\0'; +#endif temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string); *e1p = evalexp (temp1, &expok); free (temp1); @@ -4108,15 +4259,15 @@ verify_substring_values (value, substr, vtype, e1p, e2p) *e2p = evalexp (temp1, &expok); free (temp1); if (expok == 0) - return (0); + return (0); if (*e2p < 0) - { - internal_error ("%s: substring expression < 0", t); + { + internal_error ("%s: substring expression < 0", t); return (0); - } + } *e2p += *e1p; /* want E2 chars starting at E1 */ if (*e2p > len) - *e2p = len; + *e2p = len; } else *e2p = len; @@ -4217,6 +4368,8 @@ parameter_brace_substring (varname, value, substr, quoted) case VT_VARIABLE: case VT_ARRAYMEMBER: temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2); + if (val && vtype == VT_ARRAYMEMBER) + free (val); break; case VT_POSPARMS: temp = pos_params (varname, e1, e2, quoted); @@ -4285,8 +4438,8 @@ pat_subst (string, pat, rep, mflags) /* OK, now copy the leading unmatched portion of the string (from str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ + the replacement string at ret + rptr + (s - str). Increment + rptr (if necessary) and str and go on. */ if (l) { strncpy (ret + rptr, str, l); @@ -4297,9 +4450,11 @@ pat_subst (string, pat, rep, mflags) strncpy (ret + rptr, rep, replen); rptr += replen; } + if (s == e) + e++; /* avoid infinite recursion on zero-length match */ str = e; /* e == end of match */ if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; + break; } /* Now copy the unmatched portion of the input string */ @@ -4400,7 +4555,7 @@ parameter_brace_patsub (varname, value, patsub, quoted) if ((mflags & MATCH_QUOTED) == 0) rep = maybe_expand_string (rep, quoted, expand_string_unsplit); else - rep = expand_string_to_string (rep, quoted, expand_string_unsplit); + rep = expand_string_to_string (rep, quoted, expand_string_unsplit); } p = pat; @@ -4480,10 +4635,10 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll string[t_index] == '?' || string[t_index] == '#')) || (sindex == t_index - 1 && string[sindex] == '!' && - (string[t_index] == '#' || - string[t_index] == '?' || - string[t_index] == '@' || - string[t_index] == '*'))) + (string[t_index] == '#' || + string[t_index] == '?' || + string[t_index] == '@' || + string[t_index] == '*'))) { t_index++; free (name); @@ -4492,9 +4647,9 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll *name = string[sindex]; if (string[sindex] == '!') { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); + /* indirect reference of $#, $?, $@, or $* */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); } else strcpy (name + 1, temp1); @@ -4511,7 +4666,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll characters, move past it as normal. If not, assume that a substring specification is being given, and do not move past it. */ - if (c == ':' && member (string[sindex], "-=?+")) + if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) { check_nullness++; if (c = string[sindex]) @@ -4527,7 +4682,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll /* ${#-} is a valid expansion and means to take the length of $-. Similarly for ${#?} and ${##}... */ if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "-?#") && string[sindex] == RBRACE) + VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) { name = xrealloc (name, 3); name[1] = c; @@ -4547,7 +4702,8 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll either a variable name, one of the positional parameters or a special variable that expands to one of the positional parameters. */ want_indir = *name == '!' && - (legal_variable_starter (name[1]) || digit (name[1]) || member (name[1], "#?@*")); + (legal_variable_starter (name[1]) || isdigit (name[1]) + || VALID_INDIR_PARAM (name[1])); /* Determine the value of this variable. */ @@ -4559,10 +4715,10 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll if (*name == '#' && name[1]) { /* If we are not pointing at the character just after the - closing brace, then we haven't gotten all of the name. - Since it begins with a special character, this is a bad - substitution. Also check NAME for validity before trying - to go on. */ + closing brace, then we haven't gotten all of the name. + Since it begins with a special character, this is a bad + substitution. Also check NAME for validity before trying + to go on. */ if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) { temp = (char *)NULL; @@ -4599,7 +4755,16 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll temp1[number - 1] = '\0'; x = all_variables_matching_prefix (temp1); xlist = argv_to_word_list (x, 1, 0); - temp = string_list_dollar_star (xlist, quoted); + if (string[sindex - 2] == '*') + temp = string_list_dollar_star (xlist); + else + { + temp = string_list_dollar_at (xlist, quoted); + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + } free (x); free (xlist); free (temp1); @@ -4621,15 +4786,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll temp = parameter_brace_expand_word (name, var_is_special, quoted); #if defined (ARRAY_VARS) -#if 0 - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name)) -#else if (valid_array_reference (name)) -#endif { temp1 = strchr (name, '['); if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { + { if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) *quoted_dollar_atp = 1; if (contains_dollar_at) @@ -4652,10 +4813,10 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll if (c && c != RBRACE) { /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ + according to the Posix.2 rules. */ value = extract_dollar_brace_string (string, &sindex, quoted); if (string[sindex] == RBRACE) - sindex++; + sindex++; else goto bad_substitution; } @@ -4696,7 +4857,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll case RBRACE: if (var_is_set == 0 && unbound_vars_is_error) - { + { report_error ("%s: unbound variable", name); FREE (value); FREE (temp); @@ -4709,10 +4870,10 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll case '#': /* ${param#[#]pattern} */ case '%': /* ${param%[%]pattern} */ if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); + { + FREE (value); break; - } + } if ((name[0] == '@' || name[0] == '*') && name[1] == '\0') temp1 = parameter_list_remove_pattern (value, name[0], c, quoted); #if defined (ARRAY_VARS) @@ -4731,23 +4892,23 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll case '?': case '+': if (var_is_set && var_is_null == 0) - { - /* We don't want the value of the named variable for - anything, just the value of the right hand side. */ - - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- we're not - using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; + { + /* If the operator is `+', we don't want the value of the named + variable for anything, just the value of the right hand side. */ if (c == '+') { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + FREE (temp); if (value) - { + { temp = parameter_brace_expand_rhs (name, value, c, quoted, quoted_dollar_atp, @@ -4755,7 +4916,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll free (value); } else - temp = (char *)NULL; + temp = (char *)NULL; } else { @@ -4764,7 +4925,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll /* Otherwise do nothing; just use the value in TEMP. */ } else /* VAR not set or VAR is NULL. */ - { + { FREE (temp); temp = (char *)NULL; if (c == '=' && var_is_special) @@ -4777,14 +4938,25 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll else if (c == '?') { parameter_brace_expand_error (name, value); - return (interactive ? &expand_param_error : &expand_param_fatal); + return (interactive_shell ? &expand_param_error : &expand_param_fatal); } else if (c != '+') - temp = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); + { + /* XXX -- if we're double-quoted and the named variable is "$@", + we want to turn off any special handling of "$@" -- + we're not using it, so whatever is on the rhs applies. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) + *quoted_dollar_atp = 0; + if (contains_dollar_at) + *contains_dollar_at = 0; + + temp = parameter_brace_expand_rhs (name, value, c, quoted, + quoted_dollar_atp, + contains_dollar_at); + } free (value); } + break; } free (name); @@ -4899,12 +5071,12 @@ param_expand (string, sindex, quoted, expanded_something, temp = temp1; } else - { - /* If the $* is not quoted it is identical to $@ */ - temp = string_list_dollar_at (list, quoted); - if (contains_dollar_at) - *contains_dollar_at = 1; - } + { + /* If the $* is not quoted it is identical to $@ */ + temp = string_list_dollar_at (list, quoted); + if (expand_no_split_dollar_star == 0 && contains_dollar_at) + *contains_dollar_at = 1; + } dispose_words (list); break; @@ -4948,13 +5120,19 @@ param_expand (string, sindex, quoted, expanded_something, in the string. */ /* Note that we saw the quoted null so we can add one back at the end of this function if there are no other characters - in the string, discard TEMP, and go on. */ + in the string, discard TEMP, and go on. The exception to + this is when we have "${@}" and $1 is '', since $@ needs + special handling. */ if (temp && QUOTED_NULL (temp)) { if (had_quoted_null_p) *had_quoted_null_p = 1; - free (temp); - temp = (char *)NULL; + if (*quoted_dollar_at_p == 0) + { + free (temp); + temp = (char *)NULL; + } + } goto return0; @@ -4967,7 +5145,7 @@ param_expand (string, sindex, quoted, expanded_something, zindex = t_index; /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ + extract the expression and pass it to the evaluator. */ if (temp && *temp == LPAREN) { char *temp2; @@ -5161,6 +5339,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin int had_quoted_null; int has_dollar_at; + int tflag; register int c; /* Current character. */ int number; /* Temporary number value. */ @@ -5300,13 +5479,14 @@ add_string: c = string[++sindex]; if (quoted & Q_HERE_DOCUMENT) - temp1 = slashify_in_here_document; + tflag = CBSHDOC; else if (quoted & Q_DOUBLE_QUOTES) - temp1 = slashify_in_quotes; + tflag = CBSDQUOTE; else - temp1 = ""; + tflag = 0; + - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0) + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) { twochars[0] = '\\'; twochars[1] = c; @@ -5601,7 +5781,7 @@ finished_with_string: if (word->flags & W_NOGLOB) tword->flags |= W_NOGLOB; /* XXX */ if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; + tword->flags |= W_QUOTED; } else { @@ -5659,7 +5839,7 @@ string_quote_removal (string, quoted) { case '\\': c = string[++sindex]; - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0) + if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) *r++ = '\\'; /* FALLTHROUGH */ @@ -5976,12 +6156,8 @@ glob_expand_word_list (tlist, eflags) next = tlist->next; /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ -#if 0 - if ((tlist->word->flags & W_ASSIGNMENT) == 0 && -#else + pattern matching character, then glob it. */ if ((tlist->word->flags & W_NOGLOB) == 0 && -#endif unquoted_glob_pattern_p (tlist->word->word)) { glob_array = shell_glob_filename (tlist->word->word); @@ -6159,6 +6335,7 @@ shell_expand_word_list (tlist, eflags) /* Dispose the new list we're building. */ dispose_words (new_list); + last_command_exit_value = EXECUTION_FAILURE; if (expanded == &expand_word_error) jump_to_top_level (DISCARD); else @@ -6232,10 +6409,13 @@ expand_word_list_internal (list, eflags) tint = do_assignment (temp_list->word->word); /* Variable assignment errors in non-interactive shells running in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && interactive_shell == 0 && posixly_correct) + if (tint == 0) { last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); } } dispose_words (subst_assign_varlist); @@ -6287,11 +6467,13 @@ expand_word_list_internal (list, eflags) tint = (*assign_func) (temp_list->word->word); /* Variable assignment errors in non-interactive shells running in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && assign_func == do_assignment && - interactive_shell == 0 && posixly_correct) + if (tint == 0 && assign_func == do_assignment) { last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); + if (interactive_shell == 0 && posixly_correct) + jump_to_top_level (FORCE_EOF); + else + jump_to_top_level (DISCARD); } } |