Imported from ../bash-2.02.tar.gz.
This commit is contained in:
parent
e8ce775db8
commit
cce855bc5b
323 changed files with 33916 additions and 12321 deletions
400
parse.y
400
parse.y
|
@ -64,9 +64,11 @@
|
|||
#endif /* ALIAS */
|
||||
|
||||
#if defined (PROMPT_STRING_DECODE)
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
#include "maxpath.h"
|
||||
# ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
# endif
|
||||
# include <time.h>
|
||||
# include "maxpath.h"
|
||||
#endif /* PROMPT_STRING_DECODE */
|
||||
|
||||
#define RE_READ_TOKEN -99
|
||||
|
@ -74,6 +76,13 @@
|
|||
|
||||
#define YYDEBUG 0
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
#define PATTERN_CHAR(c) \
|
||||
((c) == '@' || (c) == '*' || (c) == '+' || (c) == '?' || (c) == '!')
|
||||
|
||||
extern int extended_glob;
|
||||
#endif
|
||||
|
||||
extern int eof_encountered;
|
||||
extern int no_line_editing, running_under_emacs;
|
||||
extern int current_command_number;
|
||||
|
@ -85,7 +94,7 @@ extern int interrupt_immediately;
|
|||
extern char *shell_name, *current_host_name;
|
||||
extern char *dist_version;
|
||||
extern int patch_level;
|
||||
extern int dump_translatable_strings;
|
||||
extern int dump_translatable_strings, dump_po_strings;
|
||||
extern Function *last_shell_builtin, *this_shell_builtin;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
extern int bash_input_fd_changed;
|
||||
|
@ -103,6 +112,9 @@ static int reserved_word_acceptable ();
|
|||
static int read_token ();
|
||||
static int yylex ();
|
||||
static int parse_arith_cmd ();
|
||||
#if defined (COND_COMMAND)
|
||||
static COMMAND *parse_cond_command ();
|
||||
#endif
|
||||
static int read_token_word ();
|
||||
static void discard_parser_constructs ();
|
||||
|
||||
|
@ -180,13 +192,17 @@ static REDIRECTEE redir;
|
|||
|
||||
/* Reserved words. Members of the first group are only recognized
|
||||
in the case that they are preceded by a list_terminator. Members
|
||||
of the second group are recognized only under special circumstances. */
|
||||
of the second group are for [[...]] commands. Members of the
|
||||
third group are recognized only under special circumstances. */
|
||||
%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION
|
||||
%token IN BANG TIME TIMEOPT
|
||||
%token COND_START COND_END COND_ERROR
|
||||
%token IN BANG TIME TIMEOPT
|
||||
|
||||
/* More general tokens. yylex () knows how to make these. */
|
||||
%token <word> WORD ASSIGNMENT_WORD
|
||||
%token <number> NUMBER
|
||||
%token <word_list> ARITH_CMD
|
||||
%token <command> COND_CMD
|
||||
%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND
|
||||
%token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER
|
||||
%token GREATER_BAR
|
||||
|
@ -197,6 +213,8 @@ static REDIRECTEE redir;
|
|||
%type <command> list list0 list1 compound_list simple_list simple_list1
|
||||
%type <command> simple_command shell_command
|
||||
%type <command> for_command select_command case_command group_command
|
||||
%type <command> arith_command
|
||||
%type <command> cond_command
|
||||
%type <command> function_def if_command elif_clause subshell
|
||||
%type <redirect> redirection redirection_list
|
||||
%type <element> simple_command_element
|
||||
|
@ -479,6 +497,10 @@ shell_command: for_command
|
|||
{ $$ = $1; }
|
||||
| group_command
|
||||
{ $$ = $1; }
|
||||
| arith_command
|
||||
{ $$ = $1; }
|
||||
| cond_command
|
||||
{ $$ = $1; }
|
||||
| function_def
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
@ -559,6 +581,14 @@ group_command: '{' list '}'
|
|||
{ $$ = make_group_command ($2); }
|
||||
;
|
||||
|
||||
arith_command: ARITH_CMD
|
||||
{ $$ = make_arith_command ($1); }
|
||||
;
|
||||
|
||||
cond_command: COND_START COND_CMD COND_END
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
elif_clause: ELIF compound_list THEN compound_list
|
||||
{ $$ = make_if_command ($2, $4, (COMMAND *)NULL); }
|
||||
| ELIF compound_list THEN compound_list ELSE compound_list
|
||||
|
@ -747,6 +777,8 @@ timespec: TIME
|
|||
#define PST_SUBSHELL 0x020 /* ( ... ) subshell */
|
||||
#define PST_CMDSUBST 0x040 /* $( ... ) command substitution */
|
||||
#define PST_CASESTMT 0x080 /* parsing a case statement */
|
||||
#define PST_CONDCMD 0x100 /* parsing a [[...]] command */
|
||||
#define PST_CONDEXPR 0x200 /* parsing the guts of [[...]] */
|
||||
|
||||
/* Initial size to allocate for tokens, and the
|
||||
amount to grow them by. */
|
||||
|
@ -1084,6 +1116,11 @@ typedef struct stream_saver {
|
|||
/* The globally known line number. */
|
||||
int line_number = 0;
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
static int cond_lineno;
|
||||
static int cond_token;
|
||||
#endif
|
||||
|
||||
STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL;
|
||||
|
||||
void
|
||||
|
@ -1098,10 +1135,8 @@ push_stream (reset_lineno)
|
|||
saver->bstream = (BUFFERED_STREAM *)NULL;
|
||||
/* If we have a buffered stream, clear out buffers[fd]. */
|
||||
if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
|
||||
{
|
||||
saver->bstream = buffers[bash_input.location.buffered_fd];
|
||||
buffers[bash_input.location.buffered_fd] = (BUFFERED_STREAM *)NULL;
|
||||
}
|
||||
saver->bstream = set_buffered_stream (bash_input.location.buffered_fd,
|
||||
(BUFFERED_STREAM *)NULL);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
saver->line = line_number;
|
||||
|
@ -1147,7 +1182,7 @@ pop_stream ()
|
|||
saver->bstream->b_fd = default_buffered_input;
|
||||
}
|
||||
}
|
||||
buffers[bash_input.location.buffered_fd] = saver->bstream;
|
||||
set_buffered_stream (bash_input.location.buffered_fd, saver->bstream);
|
||||
}
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
|
@ -1180,7 +1215,11 @@ stream_on_stack (type)
|
|||
* everything between a `;;' and the next `)' or `esac'
|
||||
*/
|
||||
|
||||
#if defined (ALIAS)
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
|
||||
#if !defined (ALIAS)
|
||||
typedef void *alias_t;
|
||||
#endif
|
||||
|
||||
#define END_OF_ALIAS 0
|
||||
|
||||
|
@ -1197,7 +1236,9 @@ typedef struct string_saver {
|
|||
struct string_saver *next;
|
||||
int expand_alias; /* Value to set expand_alias to when string is popped. */
|
||||
char *saved_line;
|
||||
#if defined (ALIAS)
|
||||
alias_t *expander; /* alias that caused this line to be pushed. */
|
||||
#endif
|
||||
int saved_line_size, saved_line_index, saved_line_terminator;
|
||||
} STRING_SAVER;
|
||||
|
||||
|
@ -1224,12 +1265,16 @@ push_string (s, expand, ap)
|
|||
temp->saved_line_size = shell_input_line_size;
|
||||
temp->saved_line_index = shell_input_line_index;
|
||||
temp->saved_line_terminator = shell_input_line_terminator;
|
||||
#if defined (ALIAS)
|
||||
temp->expander = ap;
|
||||
#endif
|
||||
temp->next = pushed_string_list;
|
||||
pushed_string_list = temp;
|
||||
|
||||
#if defined (ALIAS)
|
||||
if (ap)
|
||||
ap->flags |= AL_BEINGEXPANDED;
|
||||
#endif
|
||||
|
||||
shell_input_line = s;
|
||||
shell_input_line_size = strlen (s);
|
||||
|
@ -1263,8 +1308,10 @@ pop_string ()
|
|||
t = pushed_string_list;
|
||||
pushed_string_list = pushed_string_list->next;
|
||||
|
||||
#if defined (ALIAS)
|
||||
if (t->expander)
|
||||
t->expander->flags &= ~AL_BEINGEXPANDED;
|
||||
#endif
|
||||
|
||||
free ((char *)t);
|
||||
}
|
||||
|
@ -1278,14 +1325,17 @@ free_string_list ()
|
|||
{
|
||||
t1 = t->next;
|
||||
FREE (t->saved_line);
|
||||
t->expander->flags &= ~AL_BEINGEXPANDED;
|
||||
#if defined (ALIAS)
|
||||
if (t->expander)
|
||||
t->expander->flags &= ~AL_BEINGEXPANDED;
|
||||
#endif
|
||||
free ((char *)t);
|
||||
t = t1;
|
||||
}
|
||||
pushed_string_list = (STRING_SAVER *)NULL;
|
||||
}
|
||||
|
||||
#endif /* ALIAS */
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
/* Return a line of text, taken from wherever yylex () reads input.
|
||||
If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE
|
||||
|
@ -1410,6 +1460,10 @@ STRING_INT_ALIST word_token_alist[] = {
|
|||
{ "{", '{' },
|
||||
{ "}", '}' },
|
||||
{ "!", BANG },
|
||||
#if defined (COND_COMMAND)
|
||||
{ "[[", COND_START },
|
||||
{ "]]", COND_END },
|
||||
#endif
|
||||
{ (char *)NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -1457,16 +1511,16 @@ shell_getc (remove_quoted_newline)
|
|||
|
||||
QUIT;
|
||||
|
||||
#if defined (ALIAS)
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
/* If shell_input_line[shell_input_line_index] == 0, but there is
|
||||
something on the pushed list of strings, then we don't want to go
|
||||
off and get another line. We let the code down below handle it. */
|
||||
|
||||
if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) &&
|
||||
(pushed_string_list == (STRING_SAVER *)NULL)))
|
||||
#else /* !ALIAS */
|
||||
#else /* !ALIAS && !DPAREN_ARITHMETIC */
|
||||
if (!shell_input_line || !shell_input_line[shell_input_line_index])
|
||||
#endif /* !ALIAS */
|
||||
#endif /* !ALIAS && !DPAREN_ARITHMETIC */
|
||||
{
|
||||
line_number++;
|
||||
|
||||
|
@ -1617,7 +1671,7 @@ shell_getc (remove_quoted_newline)
|
|||
goto restart_read;
|
||||
}
|
||||
|
||||
#if defined (ALIAS)
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
/* If C 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
|
||||
because we have fully consumed the result of the last alias expansion.
|
||||
|
@ -1639,7 +1693,7 @@ shell_getc (remove_quoted_newline)
|
|||
c = ' ';
|
||||
}
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
if (!c && shell_input_line_terminator == EOF)
|
||||
return ((shell_input_line_index != 0) ? '\n' : EOF);
|
||||
|
@ -1790,10 +1844,16 @@ static int open_brace_count;
|
|||
{ \
|
||||
if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \
|
||||
break; \
|
||||
if (word_token_alist[i].token == TIME) \
|
||||
break; \
|
||||
if (word_token_alist[i].token == ESAC) \
|
||||
parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
|
||||
else if (word_token_alist[i].token == CASE) \
|
||||
parser_state |= PST_CASESTMT; \
|
||||
else if (word_token_alist[i].token == COND_END) \
|
||||
parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \
|
||||
else if (word_token_alist[i].token == COND_START) \
|
||||
parser_state |= PST_CONDCMD; \
|
||||
else if (word_token_alist[i].token == '{') \
|
||||
open_brace_count++; \
|
||||
else if (word_token_alist[i].token == '}' && open_brace_count) \
|
||||
|
@ -1847,6 +1907,27 @@ alias_expand_token (token)
|
|||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
static int
|
||||
time_command_acceptable ()
|
||||
{
|
||||
#if defined (COMMAND_TIMING)
|
||||
switch (last_read_token)
|
||||
{
|
||||
case 0:
|
||||
case ';':
|
||||
case '\n':
|
||||
case AND_AND:
|
||||
case OR_OR:
|
||||
case '&':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif /* COMMAND_TIMING */
|
||||
}
|
||||
|
||||
/* Handle special cases of token recognition:
|
||||
IN is recognized if the last token was WORD and the token
|
||||
before that was FOR or CASE or SELECT.
|
||||
|
@ -1861,6 +1942,14 @@ alias_expand_token (token)
|
|||
before that was FUNCTION.
|
||||
|
||||
`}' is recognized if there is an unclosed `{' prsent.
|
||||
|
||||
`-p' is returned as TIMEOPT if the last read token was TIME.
|
||||
|
||||
']]' is returned as COND_END if the parser is currently parsing
|
||||
a conditional expression ((parser_state & PST_CONDEXPR) != 0)
|
||||
|
||||
`time' is returned as TIME if and only if it is immediately
|
||||
preceded by one of `;', `\n', `||', `&&', or `&'.
|
||||
*/
|
||||
|
||||
static int
|
||||
|
@ -1926,9 +2015,21 @@ special_case_tokens (token)
|
|||
return ('}');
|
||||
}
|
||||
|
||||
#if defined (COMMAND_TIMING)
|
||||
/* Handle -p after `time'. */
|
||||
if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2])
|
||||
return (TIMEOPT);
|
||||
#endif
|
||||
|
||||
#if defined (COMMAND_TIMING)
|
||||
if (STREQ (token, "time") && time_command_acceptable ())
|
||||
return (TIME);
|
||||
#endif /* COMMAND_TIMING */
|
||||
|
||||
#if defined (COND_COMMAND) /* [[ */
|
||||
if ((parser_state & PST_CONDEXPR) && token[0] == ']' && token[1] == ']' && token[2] == '\0')
|
||||
return (COND_END);
|
||||
#endif
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
@ -1943,13 +2044,10 @@ reset_parser ()
|
|||
|
||||
parser_state = 0;
|
||||
|
||||
#if defined (ALIAS)
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
if (pushed_string_list)
|
||||
{
|
||||
free_string_list ();
|
||||
pushed_string_list = (STRING_SAVER *)NULL;
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
free_string_list ();
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
if (shell_input_line)
|
||||
{
|
||||
|
@ -1993,6 +2091,26 @@ read_token (command)
|
|||
return (result);
|
||||
}
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD)
|
||||
{
|
||||
cond_lineno = line_number;
|
||||
parser_state |= PST_CONDEXPR;
|
||||
yylval.command = parse_cond_command ();
|
||||
if (cond_token != COND_END)
|
||||
{
|
||||
if (EOF_Reached && cond_token != COND_ERROR) /* [[ */
|
||||
parser_error (cond_lineno, "unexpected EOF while looking for `]]'");
|
||||
else if (cond_token != COND_ERROR)
|
||||
parser_error (cond_lineno, "syntax error in conditional expression");
|
||||
return (-1);
|
||||
}
|
||||
token_to_read = COND_END;
|
||||
parser_state &= ~(PST_CONDEXPR|PST_CONDCMD);
|
||||
return (COND_CMD);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* This is a place to jump back to once we have successfully expanded a
|
||||
token with an alias and pushed the string with push_string () */
|
||||
|
@ -2080,17 +2198,17 @@ read_token (command)
|
|||
{
|
||||
int cmdtyp, sline;
|
||||
char *wval;
|
||||
WORD_DESC *wd;
|
||||
|
||||
sline = line_number;
|
||||
cmdtyp = parse_arith_cmd (&wval);
|
||||
if (cmdtyp == 1) /* arithmetic command */
|
||||
{
|
||||
word_desc_to_read = make_word (wval);
|
||||
word_desc_to_read->flags = W_QUOTED;
|
||||
token_to_read = WORD;
|
||||
free (wval);
|
||||
yylval.word = make_word ("let");
|
||||
return (WORD);
|
||||
wd = make_word (wval);
|
||||
wd->flags = W_QUOTED;
|
||||
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 */
|
||||
{
|
||||
|
@ -2362,6 +2480,175 @@ parse_arith_cmd (ep)
|
|||
}
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *cond_term ();
|
||||
static COND_COM *cond_and ();
|
||||
static COND_COM *cond_or ();
|
||||
static COND_COM *cond_expr ();
|
||||
|
||||
static COND_COM *
|
||||
cond_expr ()
|
||||
{
|
||||
return (cond_or ());
|
||||
}
|
||||
|
||||
static COND_COM *
|
||||
cond_or ()
|
||||
{
|
||||
COND_COM *l, *r;
|
||||
|
||||
l = cond_and ();
|
||||
if (cond_token == OR_OR)
|
||||
{
|
||||
r = cond_or ();
|
||||
l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
static COND_COM *
|
||||
cond_and ()
|
||||
{
|
||||
COND_COM *l, *r;
|
||||
|
||||
l = cond_term ();
|
||||
if (cond_token == AND_AND)
|
||||
{
|
||||
r = cond_and ();
|
||||
l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
static int
|
||||
cond_skip_newlines ()
|
||||
{
|
||||
while ((cond_token = read_token (READ)) == '\n')
|
||||
{
|
||||
if (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
|
||||
prompt_again ();
|
||||
}
|
||||
return (cond_token);
|
||||
}
|
||||
|
||||
#define COND_RETURN_ERROR() \
|
||||
do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0)
|
||||
|
||||
static COND_COM *
|
||||
cond_term ()
|
||||
{
|
||||
WORD_DESC *op;
|
||||
COND_COM *term, *tleft, *tright;
|
||||
int tok, lineno;
|
||||
|
||||
/* Read a token. It can be a left paren, a `!', a unary operator, or a
|
||||
word that should be the first argument of a binary operator. Start by
|
||||
skipping newlines, since this is a compound command. */
|
||||
tok = cond_skip_newlines ();
|
||||
lineno = line_number;
|
||||
if (tok == COND_END)
|
||||
{
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
else if (tok == '(')
|
||||
{
|
||||
term = cond_expr ();
|
||||
if (cond_token != ')')
|
||||
{
|
||||
if (term)
|
||||
dispose_cond_node (term); /* ( */
|
||||
parser_error (lineno, "expected `)'");
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL);
|
||||
(void)cond_skip_newlines ();
|
||||
}
|
||||
else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0')))
|
||||
{
|
||||
if (tok == WORD)
|
||||
dispose_word (yylval.word); /* not needed */
|
||||
term = cond_term ();
|
||||
if (term)
|
||||
term->flags |= CMD_INVERT_RETURN;
|
||||
}
|
||||
else if (tok == WORD && test_unop (yylval.word->word))
|
||||
{
|
||||
op = yylval.word;
|
||||
tok = read_token (READ);
|
||||
if (tok == WORD)
|
||||
{
|
||||
tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
|
||||
term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispose_word (op);
|
||||
parser_error (line_number, "unexpected argument to conditional unary operator");
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
|
||||
(void)cond_skip_newlines ();
|
||||
}
|
||||
else /* left argument to binary operator */
|
||||
{
|
||||
/* lhs */
|
||||
tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
|
||||
|
||||
/* binop */
|
||||
tok = read_token (READ);
|
||||
if (tok == WORD && test_binop (yylval.word->word))
|
||||
op = yylval.word;
|
||||
else if (tok == '<' || tok == '>')
|
||||
op = make_word_from_token (tok);
|
||||
else if (tok == COND_END || tok == AND_AND || tok == OR_OR)
|
||||
{
|
||||
/* Special case. [[ x ]] is equivalent to [[ -n x ]], just like
|
||||
the test command. Similarly for [[ x && expr ]] or
|
||||
[[ x || expr ]] */
|
||||
op = make_word ("-n");
|
||||
term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
|
||||
cond_token = tok;
|
||||
return (term);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_error (line_number, "conditional binary operator expected");
|
||||
dispose_cond_node (tleft);
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
|
||||
/* rhs */
|
||||
tok = read_token (READ);
|
||||
if (tok == WORD)
|
||||
{
|
||||
tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
|
||||
term = make_cond_node (COND_BINARY, op, tleft, tright);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_error (line_number, "unexpected argument to conditional binary operator");
|
||||
dispose_cond_node (tleft);
|
||||
dispose_word (op);
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
|
||||
(void)cond_skip_newlines ();
|
||||
}
|
||||
return (term);
|
||||
}
|
||||
|
||||
/* This is kind of bogus -- we slip a mini recursive-descent parser in
|
||||
here to handle the conditional statement syntax. */
|
||||
static COMMAND *
|
||||
parse_cond_command ()
|
||||
{
|
||||
COND_COM *cexp;
|
||||
|
||||
cexp = cond_expr ();
|
||||
return (make_cond_command (cexp));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
read_token_word (character)
|
||||
int character;
|
||||
|
@ -2458,6 +2745,34 @@ read_token_word (character)
|
|||
goto next_character;
|
||||
}
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* Parse a ksh-style extended pattern matching specification. */
|
||||
if (extended_glob && PATTERN_CHAR(character))
|
||||
{
|
||||
peek_char = shell_getc (1);
|
||||
if (peek_char == '(') /* ) */
|
||||
{
|
||||
push_delimiter (dstack, peek_char);
|
||||
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
|
||||
pop_delimiter (dstack);
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
token[token_index++] = character;
|
||||
token[token_index++] = peek_char;
|
||||
strcpy (token + token_index, ttok);
|
||||
token_index += ttoklen;
|
||||
FREE (ttok);
|
||||
dollar_present = all_digits = 0;
|
||||
goto next_character;
|
||||
}
|
||||
else
|
||||
shell_ungetc (peek_char);
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
/* If the delimiter character is not single quote, parse some of
|
||||
the shell expansions that must be read as a single word. */
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
|
@ -2503,13 +2818,16 @@ read_token_word (character)
|
|||
/* This handles $'...' and $"..." new-style quoted strings. */
|
||||
else if (character == '$' && (peek_char == '\'' || peek_char == '"'))
|
||||
{
|
||||
int first_line;
|
||||
|
||||
first_line = line_number;
|
||||
ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0);
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1;
|
||||
if (peek_char == '\'')
|
||||
ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
|
||||
else
|
||||
ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen);
|
||||
ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
|
||||
free (ttok);
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
|
||||
token_buffer_size,
|
||||
|
@ -2701,9 +3019,9 @@ ansiexpand (string, start, end, lenp)
|
|||
by the caller. The length of the translated string is returned in LENP,
|
||||
if non-null. */
|
||||
static char *
|
||||
localeexpand (string, start, end, lenp)
|
||||
localeexpand (string, start, end, lineno, lenp)
|
||||
char *string;
|
||||
int start, end, *lenp;
|
||||
int start, end, lineno, *lenp;
|
||||
{
|
||||
int len, tlen;
|
||||
char *temp, *t;
|
||||
|
@ -2716,7 +3034,11 @@ localeexpand (string, start, end, lenp)
|
|||
/* If we're just dumping translatable strings, don't do anything. */
|
||||
if (dump_translatable_strings)
|
||||
{
|
||||
printf ("\"%s\"\n", temp);
|
||||
if (dump_po_strings)
|
||||
printf ("#: %s:%d\nmsgid \"%s\"\nmsgstr \"\"\n",
|
||||
(bash_input.name ? bash_input.name : "stdin"), lineno, temp);
|
||||
else
|
||||
printf ("\"%s\"\n", temp);
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
return (temp);
|
||||
|
@ -2849,6 +3171,8 @@ history_delimiting_chars ()
|
|||
else
|
||||
return "; "; /* (...) subshell */
|
||||
}
|
||||
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
|
||||
return " "; /* function def using `function name' without `()' */
|
||||
|
||||
for (i = 0; no_semi_successors[i]; i++)
|
||||
{
|
||||
|
@ -3051,6 +3375,12 @@ decode_prompt_string (string)
|
|||
}
|
||||
goto add_string;
|
||||
|
||||
case 'r':
|
||||
temp = xmalloc (2);
|
||||
temp[0] = '\r';
|
||||
temp[1] = '\0';
|
||||
goto add_string;
|
||||
|
||||
case 'n':
|
||||
temp = xmalloc (3);
|
||||
temp[0] = no_line_editing ? '\n' : '\r';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue