Imported from ../bash-3.1.tar.gz.

This commit is contained in:
Jari Aalto 2005-12-07 14:08:12 +00:00
commit 95732b497d
267 changed files with 24541 additions and 18843 deletions

200
parse.y
View file

@ -1,6 +1,6 @@
/* Yacc grammar for bash. */
/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@ -50,6 +50,7 @@
#include "parser.h"
#include "mailcheck.h"
#include "test.h"
#include "builtins.h"
#include "builtins/common.h"
#include "builtins/builtext.h"
@ -961,22 +962,26 @@ pipeline_command: pipeline
{ $$ = $1; }
| BANG pipeline
{
$2->flags |= CMD_INVERT_RETURN;
if ($2)
$2->flags |= CMD_INVERT_RETURN;
$$ = $2;
}
| timespec pipeline
{
$2->flags |= $1;
if ($2)
$2->flags |= $1;
$$ = $2;
}
| timespec BANG pipeline
{
$3->flags |= $1|CMD_INVERT_RETURN;
if ($3)
$3->flags |= $1|CMD_INVERT_RETURN;
$$ = $3;
}
| BANG timespec pipeline
{
$3->flags |= $2|CMD_INVERT_RETURN;
if ($3)
$3->flags |= $2|CMD_INVERT_RETURN;
$$ = $3;
}
| timespec list_terminator
@ -1028,6 +1033,7 @@ timespec: TIME
#define PST_ALEXPAND 0x0800 /* OK to expand aliases - unused */
#define PST_CMDTOKEN 0x1000 /* command token OK - unused */
#define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */
#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */
/* Initial size to allocate for tokens, and the
amount to grow them by. */
@ -1339,8 +1345,13 @@ yy_stream_get ()
result = EOF;
if (bash_input.location.file)
result = getc_with_restart (bash_input.location.file);
{
if (interactive)
interrupt_immediately++;
result = getc_with_restart (bash_input.location.file);
if (interactive)
interrupt_immediately--;
}
return (result);
}
@ -1653,11 +1664,11 @@ read_a_line (remove_quoted_newline)
pass_next = 0;
while (1)
{
c = yy_getc ();
/* Allow immediate exit if interrupted during input. */
QUIT;
c = yy_getc ();
/* Ignore null bytes in input. */
if (c == 0)
{
@ -1862,6 +1873,12 @@ shell_getc (remove_quoted_newline)
QUIT;
if (sigwinch_received)
{
sigwinch_received = 0;
get_new_window_size (0, (int *)0, (int *)0);
}
if (eol_ungetc_lookahead)
{
c = eol_ungetc_lookahead;
@ -2055,14 +2072,6 @@ shell_getc (remove_quoted_newline)
if (uc)
shell_input_line_index++;
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
/* If UC is NULL, we have reached the end of the current input string. If
pushed_string_list is non-empty, it's time to pop to the previous string
@ -2078,6 +2087,14 @@ shell_getc (remove_quoted_newline)
}
#endif /* ALIAS || DPAREN_ARITHMETIC */
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
if (!uc && shell_input_line_terminator == EOF)
return ((shell_input_line_index != 0) ? '\n' : EOF);
@ -2139,7 +2156,7 @@ execute_prompt_command (command)
parse_and_execute (savestring (command), "PROMPT_COMMAND", SEVAL_NONINT|SEVAL_NOHIST);
restore_parser_state (&ps);
bind_variable ("_", last_lastarg);
bind_variable ("_", last_lastarg, 0);
FREE (last_lastarg);
if (token_to_read == '\n') /* reset_parser was called */
@ -2567,6 +2584,8 @@ read_token (command)
parser_state &= ~PST_ALEXPNEXT;
#endif /* ALIAS */
parser_state &= ~PST_ASSIGNOK;
return (character);
}
@ -2580,6 +2599,8 @@ read_token (command)
parser_state &= ~PST_ALEXPNEXT;
#endif /* ALIAS */
parser_state &= ~PST_ASSIGNOK;
peek_char = shell_getc (1);
if (character == peek_char)
{
@ -2607,6 +2628,7 @@ read_token (command)
#if defined (ALIAS)
parser_state &= ~PST_ALEXPNEXT;
#endif /* ALIAS */
return (SEMI_SEMI);
case '&':
@ -2687,13 +2709,13 @@ read_token (command)
/*
* Match a $(...) or other grouping construct. This has to handle embedded
* quoted strings ('', ``, "") and nested constructs. It also must handle
* reprompting the user, if necessary, after reading a newline (unless the
* P_NONL flag is passed), and returning correct error values if it reads
* EOF.
* reprompting the user, if necessary, after reading a newline, and returning
* correct error values if it reads EOF.
*/
#define P_FIRSTCLOSE 0x01
#define P_ALLOWESC 0x02
#define P_DQUOTE 0x04
#define P_COMMAND 0x08 /* parsing a command, so look for comments */
static char matched_pair_error;
static char *
@ -2702,13 +2724,14 @@ parse_matched_pair (qc, open, close, lenp, flags)
int open, close;
int *lenp, flags;
{
int count, ch, was_dollar;
int count, ch, was_dollar, in_comment, check_comment;
int pass_next_character, nestlen, ttranslen, start_lineno;
char *ret, *nestret, *ttrans;
int retind, retsize, rflags;
count = 1;
pass_next_character = was_dollar = 0;
pass_next_character = was_dollar = in_comment = 0;
check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0;
/* RFLAGS is the set of flags we want to pass to recursive calls. */
rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE);
@ -2719,7 +2742,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
start_lineno = line_number;
while (count)
{
#if 0
ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0);
#else
ch = shell_getc (qc != '\'' && pass_next_character == 0);
#endif
if (ch == EOF)
{
free (ret);
@ -2732,6 +2759,21 @@ parse_matched_pair (qc, open, close, lenp, flags)
if (ch == '\n' && SHOULD_PROMPT ())
prompt_again ();
if (in_comment)
{
/* Add this character. */
RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
ret[retind++] = ch;
if (ch == '\n')
in_comment = 0;
continue;
}
/* Not exactly right yet */
else if (check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind -1])))
in_comment = 1;
if (pass_next_character) /* last char was backslash */
{
pass_next_character = 0;
@ -2799,9 +2841,18 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Translate $'...' here. */
ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
xfree (nestret);
nestret = sh_single_quote (ttrans);
free (ttrans);
nestlen = strlen (nestret);
if ((rflags & P_DQUOTE) == 0)
{
nestret = sh_single_quote (ttrans);
free (ttrans);
nestlen = strlen (nestret);
}
else
{
nestret = ttrans;
nestlen = ttranslen;
}
retind -= 2; /* back up before the $' */
}
else if MBTEST(was_dollar && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
@ -2809,13 +2860,10 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* Locale expand $"..." here. */
ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
xfree (nestret);
nestret = (char *)xmalloc (ttranslen + 3);
nestret[0] = '"';
strcpy (nestret + 1, ttrans);
nestret[ttranslen + 1] = '"';
nestret[ttranslen += 2] = '\0';
nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
free (ttrans);
nestlen = ttranslen;
nestlen = ttranslen + 2;
retind -= 2; /* back up before the $" */
}
@ -2834,6 +2882,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
else if MBTEST(open == '"' && ch == '`')
{
nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags);
add_nestret:
if (nestret == &matched_pair_error)
{
free (ret);
@ -2847,6 +2896,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
}
FREE (nestret);
}
else if MBTEST(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0)
{
nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags);
goto add_nestret;
}
else if MBTEST(was_dollar && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
/* check for $(), $[], or ${} inside quoted string. */
{
@ -2858,18 +2912,8 @@ parse_matched_pair (qc, open, close, lenp, flags)
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
else if (ch == '[') /* ] */
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
if (nestret == &matched_pair_error)
{
free (ret);
return &matched_pair_error;
}
if (nestlen)
{
RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64);
strcpy (ret + retind, nestret);
retind += nestlen;
}
FREE (nestret);
goto add_nestret;
}
was_dollar = MBTEST(ch == '$');
}
@ -2900,9 +2944,10 @@ parse_dparen (c)
cmdtyp = parse_arith_cmd (&wval, 0);
if (cmdtyp == 1)
{
wd = alloc_word_desc ();
wd->word = wval;
wd = make_word (wval);
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
free (wval);
return (ARITH_FOR_EXPRS);
}
else
@ -2914,21 +2959,14 @@ parse_dparen (c)
if (reserved_word_acceptable (last_read_token))
{
sline = line_number;
#if 0
cmdtyp = parse_arith_cmd (&wval, 1);
#else
cmdtyp = parse_arith_cmd (&wval, 0);
#endif
if (cmdtyp == 1) /* arithmetic command */
{
wd = make_word (wval);
#if 0
wd->flags = W_QUOTED;
#else
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB;
#endif
wd = alloc_word_desc ();
wd->word = wval;
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
free (wval); /* make_word copies it */
return (ARITH_CMD);
}
else if (cmdtyp == 0) /* nested subshell */
@ -3246,6 +3284,7 @@ token_is_assignment (t, i)
return r;
}
/* XXX - possible changes here for `+=' */
static int
token_is_ident (t, i)
char *t;
@ -3278,6 +3317,10 @@ read_token_word (character)
/* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
int dollar_present;
/* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound
assignment. */
int compound_assignment;
/* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
int quoted;
@ -3297,7 +3340,7 @@ read_token_word (character)
token_index = 0;
all_digit_token = DIGIT (character);
dollar_present = quoted = pass_next_character = 0;
dollar_present = quoted = pass_next_character = compound_assignment = 0;
for (;;)
{
@ -3343,7 +3386,7 @@ read_token_word (character)
if MBTEST(shellquote (character))
{
push_delimiter (dstack, character);
ttok = parse_matched_pair (character, character, character, &ttoklen, 0);
ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 0);
pop_delimiter (dstack);
if (ttok == &matched_pair_error)
return -1; /* Bail immediately. */
@ -3406,7 +3449,7 @@ read_token_word (character)
history literally rather than causing a possibly-
incorrect `;' to be added. ) */
push_delimiter (dstack, peek_char);
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, P_COMMAND);
pop_delimiter (dstack);
}
else
@ -3442,27 +3485,25 @@ read_token_word (character)
{
ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
free (ttok);
/* Insert the single quotes and correctly quote any
embedded single quotes (allowed because P_ALLOWESC was
passed to parse_matched_pair). */
ttok = sh_single_quote (ttrans);
free (ttrans);
ttranslen = strlen (ttok);
ttrans = ttok;
ttranslen = strlen (ttrans);
}
else
{
/* Try to locale-expand the converted string. */
/* Try to locale)-expand the converted string. */
ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
free (ttok);
/* Add the double quotes back */
ttok = (char *)xmalloc (ttranslen + 3);
ttok[0] = '"';
strcpy (ttok + 1, ttrans);
ttok[ttranslen + 1] = '"';
ttok[ttranslen += 2] = '\0';
ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
free (ttrans);
ttranslen += 2;
ttrans = ttok;
}
@ -3515,7 +3556,7 @@ read_token_word (character)
goto next_character;
}
/* Identify possible compound array variable assignment. */
else if MBTEST(character == '=' && token_index > 0 && token_is_assignment (token, token_index))
else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index))
{
peek_char = shell_getc (1);
if MBTEST(peek_char == '(') /* ) */
@ -3536,7 +3577,12 @@ read_token_word (character)
token[token_index++] = ')';
FREE (ttok);
all_digit_token = 0;
compound_assignment = 1;
#if 0
goto next_character;
#else
goto got_token; /* ksh93 seems to do this */
#endif
}
else
shell_ungetc (peek_char);
@ -3631,6 +3677,8 @@ got_token:
the_word->flags |= W_HASDOLLAR;
if (quoted)
the_word->flags |= W_QUOTED;
if (compound_assignment)
the_word->flags |= W_COMPASSIGN;
/* A word is an assignment if it appears at the beginning of a
simple command, or after another assignment word. This is
context-dependent, so it cannot be handled in the grammar. */
@ -3642,6 +3690,14 @@ got_token:
the_word->flags |= W_NOSPLIT;
}
if (command_token_position (last_read_token))
{
struct builtin *b;
b = builtin_address_internal (token, 0);
if (b && (b->flags & ASSIGNMENT_BUILTIN))
parser_state |= PST_ASSIGNOK;
}
yylval.word = the_word;
result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT))
@ -3799,6 +3855,8 @@ history_delimiting_chars ()
return " ";
return ";";
}
else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT))
return " ";
for (i = 0; no_semi_successors[i]; i++)
{
@ -4103,7 +4161,7 @@ decode_prompt_string (string)
#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0)
#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0)
/* Abbreviate \W as ~ if $PWD == $HOME */
if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, temp) == 0))
if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0))
{
if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0)
{
@ -4582,7 +4640,7 @@ parse_string_to_word_list (s, flags, whom)
line_number = orig_line_number + line_number - 1;
orig_current_token = current_token;
current_token = tok;
yyerror ((char *)NULL); /* does the right thing */
yyerror (NULL); /* does the right thing */
current_token = orig_current_token;
if (wl)
dispose_words (wl);
@ -4657,7 +4715,7 @@ parse_compound_assignment (retlenp)
if (tok == yacc_EOF) /* ( */
parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'"));
else
yyerror ((char *)NULL); /* does the right thing */
yyerror(NULL); /* does the right thing */
if (wl)
dispose_words (wl);
wl = &parse_string_error;
@ -4712,7 +4770,7 @@ save_parser_state (ps)
#endif
if (ps == 0)
ps = xmalloc (sizeof (sh_parser_state_t));
ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t));
if (ps == 0)
return ((sh_parser_state_t *)NULL);