aboutsummaryrefslogtreecommitdiffstats
path: root/subst.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2001-04-06 19:14:31 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:53 +0000
commit28ef6c316f1aff914bb95ac09787a3c83c1815fd (patch)
tree2812fe7ffc9beec4f99856906ddfcafda54cf16a /subst.c
parentbb70624e964126b7ac4ff085ba163a9c35ffa18f (diff)
downloadandroid_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.c656
1 files changed, 419 insertions, 237 deletions
diff --git a/subst.c b/subst.c
index d578675..bba1eb2 100644
--- a/subst.c
+++ b/subst.c
@@ -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);
}
}