Imported from ../bash-2.03.tar.gz.
This commit is contained in:
parent
bc4cd23ce9
commit
b72432fdcc
191 changed files with 10113 additions and 3553 deletions
136
subst.c
136
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue