aboutsummaryrefslogtreecommitdiffstats
path: root/subst.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1999-02-19 17:11:39 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:52 +0000
commitb72432fdcc59300c6fe7c9d6c8a31ad3447933f5 (patch)
treeb9899162338c2ff3fd83a8aef8831cb119e85cd7 /subst.c
parentbc4cd23ce958feda898c618215f94d8a4e8f4ffa (diff)
downloadandroid_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.tar.gz
android_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.tar.bz2
android_external_bash-b72432fdcc59300c6fe7c9d6c8a31ad3447933f5.zip
Imported from ../bash-2.03.tar.gz.
Diffstat (limited to 'subst.c')
-rw-r--r--subst.c136
1 files changed, 102 insertions, 34 deletions
diff --git a/subst.c b/subst.c
index 94c230f..5e0eb87 100644
--- a/subst.c
+++ b/subst.c
@@ -79,6 +79,7 @@ extern int errno;
/* Process ID of the last command executed within command substitution. */
pid_t last_command_subst_pid = NO_PID;
+pid_t current_command_subst_pid = NO_PID;
/* Extern functions and variables from different files. */
extern int last_command_exit_value, interactive, interactive_shell;
@@ -104,6 +105,8 @@ 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 char *make_quoted_char ();
static void remove_quoted_nulls ();
static char *param_expand ();
@@ -113,6 +116,7 @@ static WORD_LIST *expand_string_internal ();
static WORD_LIST *expand_word_internal (), *expand_word_list_internal ();
static WORD_LIST *expand_string_leave_quoted ();
static WORD_LIST *expand_string_for_rhs ();
+static char *getifs ();
static WORD_LIST *word_list_split ();
static WORD_LIST *quote_list (), *dequote_list ();
static char *quote_escapes ();
@@ -929,7 +933,7 @@ extract_dollar_brace_string (string, sindex, quoted)
}
}
- if (c == 0 && nesting_level)
+ if (c == 0 && nesting_level && doing_completion == 0)
{
report_error ("bad substitution: no ending `}' in %s", string);
jump_to_top_level (DISCARD);
@@ -987,7 +991,12 @@ 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. */
+ by a backslash. DOING_COMPLETION 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)
+
int
char_is_quoted (string, eindex)
char *string;
@@ -995,13 +1004,14 @@ char_is_quoted (string, eindex)
{
int i, pass_next, quoted;
+ doing_completion = 1;
for (i = pass_next = quoted = 0; i <= eindex; i++)
{
if (pass_next)
{
pass_next = 0;
if (i >= eindex) /* XXX was if (i >= eindex - 1) */
- return 1;
+ CQ_RETURN(1);
continue;
}
else if (string[i] == '\'' || string[i] == '"')
@@ -1009,7 +1019,7 @@ char_is_quoted (string, eindex)
i = (string[i] == '\'') ? skip_single_quoted (string, ++i)
: skip_double_quoted (string, ++i);
if (i > eindex)
- return 1;
+ CQ_RETURN(1);
i--; /* the skip functions increment past the closing quote. */
}
else if (string[i] == '\\')
@@ -1018,7 +1028,7 @@ char_is_quoted (string, eindex)
continue;
}
}
- return (0);
+ CQ_RETURN(0);
}
int
@@ -1829,7 +1839,7 @@ cond_expand_word (w, special)
if (w->word == 0 || w->word[0] == '\0')
return ((char *)NULL);
- l = call_expand_word_internal (w, 0, (int *)0, (int *)0);
+ l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
if (l)
{
if (special == 0)
@@ -1856,13 +1866,13 @@ cond_expand_word (w, special)
A convenience function for functions that don't want to handle
any errors or free any memory before aborting. */
static WORD_LIST *
-call_expand_word_internal (w, q, c, e)
+call_expand_word_internal (w, q, i, c, e)
WORD_DESC *w;
- int q, *c, *e;
+ int q, i, *c, *e;
{
WORD_LIST *result;
- result = expand_word_internal (w, q, c, e);
+ result = expand_word_internal (w, q, i, c, e);
if (result == &expand_word_error)
{
/* By convention, each time this error is returned, w->word has
@@ -1893,7 +1903,7 @@ expand_string_internal (string, quoted)
bzero ((char *)&td, sizeof (td));
td.word = string;
- tresult = call_expand_word_internal (&td, quoted, (int *)NULL, (int *)NULL);
+ tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
return (tresult);
}
@@ -1926,7 +1936,7 @@ expand_string_unsplit (string, quoted)
the resultant WORD_LIST. This is called only from within this file,
and is used to correctly preserve quoted characters when expanding
things like ${1+"$@"}. This does parameter expansion, command
- subsitution, arithmetic expansion, and word splitting. */
+ substitution, arithmetic expansion, and word splitting. */
static WORD_LIST *
expand_string_leave_quoted (string, quoted)
char *string;
@@ -1964,7 +1974,7 @@ expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
bzero ((char *)&td, sizeof (td));
td.word = string;
- tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at);
+ tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
return (tresult);
}
@@ -2665,7 +2675,7 @@ expand_word (word, quoted)
{
WORD_LIST *result, *tresult;
- tresult = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
+ tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
result = word_list_split (tresult);
dispose_words (tresult);
return (result ? dequote_list (result) : result);
@@ -2681,7 +2691,7 @@ expand_word_no_split (word, quoted)
{
WORD_LIST *result;
- result = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
+ result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
return (result ? dequote_list (result) : result);
}
@@ -2692,7 +2702,7 @@ expand_word_leave_quoted (word, quoted)
WORD_DESC *word;
int quoted;
{
- return (call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL));
+ return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL));
}
#if defined (PROCESS_SUBSTITUTION)
@@ -3212,6 +3222,7 @@ command_substitute (string, quoted)
close (fildes[0]);
+ current_command_subst_pid = pid;
last_command_exit_value = wait_for (pid);
last_command_subst_pid = pid;
last_made_pid = old_pid;
@@ -3954,11 +3965,35 @@ pat_subst (string, pat, rep, mflags)
char *ret, *s, *e, *str;
int rsize, rptr, l, replen, mtype;
+ mtype = mflags & MATCH_TYPEMASK;
+
+ /* Special cases:
+ * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
+ * with REP and return the result.
+ * 2. A null pattern with mtype == MATCH_END means to append REP to
+ * STRING and return the result.
+ */
+ if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
+ {
+ replen = STRLEN (rep);
+ l = strlen (string);
+ ret = xmalloc (replen + l + 2);
+ if (mtype == MATCH_BEG)
+ {
+ strcpy (ret, rep);
+ strcpy (ret + replen, string);
+ }
+ else
+ {
+ strcpy (ret, string);
+ strcpy (ret + l, rep);
+ }
+ return (ret);
+ }
+
ret = xmalloc (rsize = 64);
ret[0] = '\0';
- mtype = mflags & MATCH_TYPEMASK;
-
for (replen = STRLEN (rep), rptr = 0, str = string;;)
{
if (match_pattern (str, pat, mtype, &s, &e) == 0)
@@ -4754,6 +4789,10 @@ return0:
QUOTED contains flag values defined in shell.h.
+ ISEXP is used to tell expand_word_internal that the word should be
+ treated as the result of an expansion. This has implications for
+ how IFS characters in the word are treated.
+
CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
they point to an integer value which receives information about expansion.
CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
@@ -4769,9 +4808,9 @@ return0:
#define WHOLLY_QUOTED 2
static WORD_LIST *
-expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
+expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
WORD_DESC *word;
- int quoted;
+ int quoted, isexp;
int *contains_dollar_at;
int *expanded_something;
{
@@ -4808,12 +4847,12 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
int had_quoted_null;
int has_dollar_at;
- int expok;
-
register int c; /* Current character. */
int number; /* Temporary number value. */
int t_index; /* For calls to string_extract_xxx. */
+ char ifscmap[256];
+
istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
istring[istring_index = 0] = '\0';
quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
@@ -4826,6 +4865,20 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
if (contains_dollar_at)
*contains_dollar_at = 0;
+ /* Cache a bitmap of characters in IFS for quoting IFS characters that are
+ not part of an expansion. POSIX.2 says this is a must. */
+ temp = getifs ();
+ bzero (ifscmap, sizeof (ifscmap));
+ for (temp1 = temp; temp1 && *temp1; temp1++)
+#if 0
+ /* This check compensates for what I think is a parsing problem -- the
+ end brace matching algorithms for ${...} expressions differ between
+ parse.y and subst.c. For instance, the parser passes
+ ${abc:-G { I } K } as one word when it should be three. */
+ if (*temp1 != ' ' && *temp1 != '\t' && *temp1 != '\n')
+#endif
+ ifscmap[*temp1] = 1;
+
/* Begin the expansion. */
for (sindex = 0; ;)
@@ -4970,7 +5023,7 @@ add_string:
temp = (char *)NULL;
has_dollar_at = 0;
- list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &has_dollar_at, (int *)NULL);
+ list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
if (list == &expand_word_error || list == &expand_word_fatal)
{
@@ -5117,7 +5170,7 @@ add_string:
default:
/* This is the fix for " $@ " */
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
+ if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && ifscmap[c]))
{
temp = make_quoted_char (c);
goto dollar_add_string;
@@ -5193,6 +5246,8 @@ finished_with_string:
list = make_word_list (tword, (WORD_LIST *)NULL);
if (word->flags & W_ASSIGNMENT)
tword->flags |= W_ASSIGNMENT; /* XXX */
+ if (word->flags & W_NOGLOB)
+ tword->flags |= W_NOGLOB; /* XXX */
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
tword->flags |= W_QUOTED;
}
@@ -5200,13 +5255,7 @@ finished_with_string:
{
char *ifs_chars;
- if (quoted_dollar_at || has_dollar_at)
- {
- var = find_variable ("IFS");
- ifs_chars = var ? value_cell (var) : " \t\n";
- }
- else
- ifs_chars = (char *)NULL;
+ ifs_chars = (quoted_dollar_at || has_dollar_at) ? getifs () : (char *)NULL;
/* If we have $@, we need to split the results no matter what. If
IFS is unset or NULL, string_list_dollar_at has separated the
@@ -5224,6 +5273,8 @@ finished_with_string:
tword->flags |= W_QUOTED;
if (word->flags & W_ASSIGNMENT)
tword->flags |= W_ASSIGNMENT;
+ if (word->flags & W_NOGLOB)
+ tword->flags |= W_NOGLOB;
}
}
@@ -5338,6 +5389,16 @@ word_list_quote_removal (list, quoted)
* *
*******************************************/
+static char *
+getifs ()
+{
+ SHELL_VAR *ifs;
+
+ ifs = find_variable ("IFS");
+ /* If IFS is unset, it defaults to " \t\n". */
+ return (ifs ? value_cell (ifs) : " \t\n");
+}
+
/* This splits a single word into a WORD LIST on $IFS, but only if the word
is not quoted. list_string () performs quote removal for us, even if we
don't do any splitting. */
@@ -5411,6 +5472,9 @@ separate_out_assignments (tlist)
if (!tlist)
return ((WORD_LIST *)NULL);
+ if (varlist)
+ dispose_words (varlist); /* Clean up after previous error */
+
varlist = (WORD_LIST *)NULL;
vp = lp = tlist;
@@ -5562,7 +5626,11 @@ glob_expand_word_list (tlist, eflags)
/* 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
+ if ((tlist->word->flags & W_NOGLOB) == 0 &&
+#endif
unquoted_glob_pattern_p (tlist->word->word))
{
glob_array = shell_glob_filename (tlist->word->word);
@@ -5727,7 +5795,7 @@ shell_expand_word_list (tlist, eflags)
expanded_something = 0;
expanded = expand_word_internal
- (tlist->word, 0, &has_dollar_at, &expanded_something);
+ (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
if (expanded == &expand_word_error || expanded == &expand_word_fatal)
{
@@ -5777,15 +5845,15 @@ shell_expand_word_list (tlist, eflags)
/* The workhorse for expand_words () and expand_words_no_vars ().
First arg is LIST, a WORD_LIST of words.
- Second arg DO_VARS is non-zero if you want to do environment and
- variable assignments, else zero.
+ Second arg EFLAGS is a flags word controlling which expansions are
+ performed.
This does all of the substitutions: brace expansion, tilde expansion,
parameter expansion, command substitution, arithmetic expansion,
process substitution, word splitting, and pathname expansion, according
to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
set, or for which no expansion is done, do not undergo word splitting.
- Words with the W_ASSIGNMENT bit set do not undergo pathname expansion. */
+ Words with the W_NOGLOB bit set do not undergo pathname expansion. */
static WORD_LIST *
expand_word_list_internal (list, eflags)
WORD_LIST *list;