Bash-4.4 distribution sources and documentation
This commit is contained in:
parent
30a978b7d8
commit
a0c0a00fc4
588 changed files with 130746 additions and 80164 deletions
337
parse.y
337
parse.y
|
@ -1,6 +1,6 @@
|
|||
/* parse.y - Yacc grammar for bash. */
|
||||
|
||||
/* Copyright (C) 1989-2012 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
@ -69,6 +69,8 @@
|
|||
|
||||
#if defined (JOB_CONTROL)
|
||||
# include "jobs.h"
|
||||
#else
|
||||
extern int cleanup_dead_jobs __P((void));
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (ALIAS)
|
||||
|
@ -125,6 +127,7 @@ extern char *dist_version;
|
|||
extern int patch_level;
|
||||
extern int dump_translatable_strings, dump_po_strings;
|
||||
extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
|
||||
extern int here_doc_first_line;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
extern int bash_input_fd_changed;
|
||||
#endif
|
||||
|
@ -232,6 +235,9 @@ char *secondary_prompt = SPROMPT;
|
|||
/* PROMPT_STRING_POINTER points to one of these, never to an actual string. */
|
||||
char *ps1_prompt, *ps2_prompt;
|
||||
|
||||
/* Displayed after reading a command but before executing it in an interactive shell */
|
||||
char *ps0_prompt;
|
||||
|
||||
/* Handle on the current prompt string. Indirectly points through
|
||||
ps1_ or ps2_prompt. */
|
||||
char **prompt_string_pointer = (char **)NULL;
|
||||
|
@ -268,8 +274,6 @@ int parser_state;
|
|||
|
||||
/* Variables to manage the task of reading here documents, because we need to
|
||||
defer the reading until after a complete command has been collected. */
|
||||
#define HEREDOC_MAX 16
|
||||
|
||||
static REDIRECT *redir_stack[HEREDOC_MAX];
|
||||
int need_here_doc;
|
||||
|
||||
|
@ -1224,6 +1228,8 @@ pipeline_command: pipeline
|
|||
/* XXX - let's cheat and push a newline back */
|
||||
if ($2 == '\n')
|
||||
token_to_read = '\n';
|
||||
else if ($2 == ';')
|
||||
token_to_read = ';';
|
||||
}
|
||||
| BANG list_terminator
|
||||
{
|
||||
|
@ -1242,6 +1248,8 @@ pipeline_command: pipeline
|
|||
/* XXX - let's cheat and push a newline back */
|
||||
if ($2 == '\n')
|
||||
token_to_read = '\n';
|
||||
if ($2 == ';')
|
||||
token_to_read = ';';
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1428,9 +1436,9 @@ yy_readline_get ()
|
|||
int line_len;
|
||||
unsigned char c;
|
||||
|
||||
if (!current_readline_line)
|
||||
if (current_readline_line == 0)
|
||||
{
|
||||
if (!bash_readline_initialized)
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
|
@ -1438,7 +1446,7 @@ yy_readline_get ()
|
|||
give_terminal_to (shell_pgrp, 0);
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
old_sigint = (SigHandler *)IMPOSSIBLE_TRAP_HANDLER;
|
||||
old_sigint = IMPOSSIBLE_TRAP_HANDLER;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
/* interrupt_immediately++; */
|
||||
|
@ -1953,6 +1961,13 @@ parser_restore_alias ()
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
clear_shell_input_line ()
|
||||
{
|
||||
if (shell_input_line)
|
||||
shell_input_line[shell_input_line_index = 0] = '\0';
|
||||
}
|
||||
|
||||
/* 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
|
||||
is non-zero, we remove unquoted \<newline> pairs. This is used by
|
||||
|
@ -2059,10 +2074,10 @@ read_secondary_line (remove_quoted_newline)
|
|||
#if defined (HISTORY)
|
||||
if (ret && remember_on_history && (parser_state & PST_HEREDOC))
|
||||
{
|
||||
/* To make adding the the here-document body right, we need to rely
|
||||
on history_delimiting_chars() returning \n for the first line of
|
||||
the here-document body and the null string for the second and
|
||||
subsequent lines, so we avoid double newlines.
|
||||
/* To make adding the here-document body right, we need to rely on
|
||||
history_delimiting_chars() returning \n for the first line of the
|
||||
here-document body and the null string for the second and subsequent
|
||||
lines, so we avoid double newlines.
|
||||
current_command_line_count == 2 for the first line of the body. */
|
||||
|
||||
current_command_line_count++;
|
||||
|
@ -2204,11 +2219,12 @@ shell_getc (remove_quoted_newline)
|
|||
int remove_quoted_newline;
|
||||
{
|
||||
register int i;
|
||||
int c, truncating;
|
||||
int c, truncating, last_was_backslash;
|
||||
unsigned char uc;
|
||||
|
||||
QUIT;
|
||||
|
||||
last_was_backslash = 0;
|
||||
if (sigwinch_received)
|
||||
{
|
||||
sigwinch_received = 0;
|
||||
|
@ -2305,7 +2321,7 @@ shell_getc (remove_quoted_newline)
|
|||
if (n <= 2) /* we have to save 1 for the newline added below */
|
||||
{
|
||||
if (truncating == 0)
|
||||
internal_warning("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%llu): line truncated", shell_input_line_size, SIZE_MAX);
|
||||
internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX);
|
||||
shell_input_line[i] = '\0';
|
||||
truncating = 1;
|
||||
}
|
||||
|
@ -2339,6 +2355,8 @@ shell_getc (remove_quoted_newline)
|
|||
current_command_line_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
last_was_backslash = last_was_backslash == 0 && c == '\\';
|
||||
}
|
||||
|
||||
shell_input_line_index = 0;
|
||||
|
@ -2360,6 +2378,8 @@ shell_getc (remove_quoted_newline)
|
|||
if (current_delimiter (dstack) == '\'')
|
||||
history_expansion_inhibited = 1;
|
||||
# endif
|
||||
/* Calling with a third argument of 1 allows remember_on_history to
|
||||
determine whether or not the line is saved to the history list */
|
||||
expansions = pre_process_line (shell_input_line, 1, 1);
|
||||
# if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = old_hist;
|
||||
|
@ -2433,7 +2453,14 @@ shell_getc (remove_quoted_newline)
|
|||
shell_input_line = (char *)xrealloc (shell_input_line,
|
||||
1 + (shell_input_line_size += 2));
|
||||
|
||||
shell_input_line[shell_input_line_len] = '\n';
|
||||
/* Don't add a newline to a string that ends with a backslash if we're
|
||||
going to be removing quoted newlines, since that will eat the
|
||||
backslash. Add another backslash instead (will be removed by
|
||||
word expansion). */
|
||||
if (bash_input.type == st_string && expanding_alias() == 0 && last_was_backslash && c == EOF && remove_quoted_newline)
|
||||
shell_input_line[shell_input_line_len] = '\\';
|
||||
else
|
||||
shell_input_line[shell_input_line_len] = '\n';
|
||||
shell_input_line[shell_input_line_len + 1] = '\0';
|
||||
|
||||
set_line_mbstate ();
|
||||
|
@ -2544,7 +2571,7 @@ parser_remaining_input ()
|
|||
if (shell_input_line == 0)
|
||||
return 0;
|
||||
if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len)
|
||||
return '\0'; /* XXX */
|
||||
return ""; /* XXX */
|
||||
return (shell_input_line + shell_input_line_index);
|
||||
}
|
||||
|
||||
|
@ -2595,6 +2622,17 @@ execute_variable_command (command, vname)
|
|||
token_to_read = 0;
|
||||
}
|
||||
|
||||
void
|
||||
push_token (x)
|
||||
int x;
|
||||
{
|
||||
two_tokens_ago = token_before_that;
|
||||
token_before_that = last_read_token;
|
||||
last_read_token = current_token;
|
||||
|
||||
current_token = x;
|
||||
}
|
||||
|
||||
/* Place to remember the token. We try to keep the buffer
|
||||
at a reasonable size, but it can grow. */
|
||||
static char *token = (char *)NULL;
|
||||
|
@ -2672,23 +2710,43 @@ gather_here_documents ()
|
|||
int r;
|
||||
|
||||
r = 0;
|
||||
here_doc_first_line = 1;
|
||||
while (need_here_doc > 0)
|
||||
{
|
||||
parser_state |= PST_HEREDOC;
|
||||
make_here_document (redir_stack[r++], line_number);
|
||||
parser_state &= ~PST_HEREDOC;
|
||||
need_here_doc--;
|
||||
redir_stack[r - 1] = 0; /* XXX */
|
||||
}
|
||||
here_doc_first_line = 0; /* just in case */
|
||||
}
|
||||
|
||||
/* When non-zero, an open-brace used to create a group is awaiting a close
|
||||
brace partner. */
|
||||
static int open_brace_count;
|
||||
|
||||
/* In the following three macros, `token' is always last_read_token */
|
||||
|
||||
/* Are we in the middle of parsing a redirection where we are about to read
|
||||
a word? This is used to make sure alias expansion doesn't happen in the
|
||||
middle of a redirection, even though we're parsing a simple command. */
|
||||
#define parsing_redirection(token) \
|
||||
(token == '<' || token == '>' || \
|
||||
token == GREATER_GREATER || token == GREATER_BAR || \
|
||||
token == LESS_GREATER || token == LESS_LESS_MINUS || \
|
||||
token == LESS_LESS || token == LESS_LESS_LESS || \
|
||||
token == LESS_AND || token == GREATER_AND || token == AND_GREATER)
|
||||
|
||||
/* Is `token' one that will allow a WORD to be read in a command position?
|
||||
We can read a simple command name on which we should attempt alias expansion
|
||||
or we can read an assignment statement. */
|
||||
#define command_token_position(token) \
|
||||
(((token) == ASSIGNMENT_WORD) || (parser_state&PST_REDIRLIST) || \
|
||||
(((token) == ASSIGNMENT_WORD) || \
|
||||
((parser_state&PST_REDIRLIST) && parsing_redirection(token) == 0) || \
|
||||
((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token)))
|
||||
|
||||
/* Are we in a position where we can read an assignment statement? */
|
||||
#define assignment_acceptable(token) \
|
||||
(command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
|
||||
|
||||
|
@ -2707,6 +2765,8 @@ static int open_brace_count;
|
|||
break; \
|
||||
if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \
|
||||
break; \
|
||||
if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \
|
||||
break; /* Posix grammar rule 4 */ \
|
||||
if (word_token_alist[i].token == ESAC) \
|
||||
parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
|
||||
else if (word_token_alist[i].token == CASE) \
|
||||
|
@ -2751,7 +2811,7 @@ mk_alexpansion (s)
|
|||
strcpy (r, s);
|
||||
/* If the last character in the alias is a newline, don't add a trailing
|
||||
space to the expansion. Works with shell_getc above. */
|
||||
if (r[l - 1] != ' ' && r[l - 1] != '\n')
|
||||
if (r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0)
|
||||
r[l++] = ' ';
|
||||
r[l] = '\0';
|
||||
return r;
|
||||
|
@ -2815,6 +2875,9 @@ time_command_acceptable ()
|
|||
case 0:
|
||||
case ';':
|
||||
case '\n':
|
||||
if (token_before_that == '|')
|
||||
return (0);
|
||||
/* FALLTHROUGH */
|
||||
case AND_AND:
|
||||
case OR_OR:
|
||||
case '&':
|
||||
|
@ -2972,12 +3035,14 @@ reset_parser ()
|
|||
#endif
|
||||
|
||||
parser_state = 0;
|
||||
here_doc_first_line = 0;
|
||||
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
if (pushed_string_list)
|
||||
free_string_list ();
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
/* This is where we resynchronize to the next newline on error/reset */
|
||||
if (shell_input_line)
|
||||
{
|
||||
free (shell_input_line);
|
||||
|
@ -3095,7 +3160,16 @@ read_token (command)
|
|||
|
||||
parser_state &= ~PST_ASSIGNOK;
|
||||
|
||||
peek_char = shell_getc (1);
|
||||
/* If we are parsing a command substitution and we have read a character
|
||||
that marks the end of it, don't bother to skip over quoted newlines
|
||||
when we read the next token. We're just interested in a character
|
||||
that will turn this into a two-character token, so we let the higher
|
||||
layers deal with quoted newlines following the command substitution. */
|
||||
if ((parser_state & PST_CMDSUBST) && character == shell_eof_token)
|
||||
peek_char = shell_getc (0);
|
||||
else
|
||||
peek_char = shell_getc (1);
|
||||
|
||||
if (character == peek_char)
|
||||
{
|
||||
switch (character)
|
||||
|
@ -3252,7 +3326,8 @@ tokword:
|
|||
#define LEX_INHEREDOC 0x080
|
||||
#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */
|
||||
#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */
|
||||
#define LEX_INWORD 0x400
|
||||
#define LEX_QUOTEDDOC 0x400 /* here doc with quoted delim */
|
||||
#define LEX_INWORD 0x800
|
||||
|
||||
#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|')
|
||||
|
||||
|
@ -3498,7 +3573,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
|||
APPEND_NESTRET ();
|
||||
FREE (nestret);
|
||||
}
|
||||
else if ((flags & P_ARRAYSUB) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
|
||||
else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
|
||||
goto parse_dollar_word;
|
||||
}
|
||||
/* Parse an old-style command substitution within double quotes as a
|
||||
|
@ -3544,6 +3619,81 @@ parse_dollar_word:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if defined (DEBUG)
|
||||
static void
|
||||
dump_tflags (flags)
|
||||
int flags;
|
||||
{
|
||||
int f;
|
||||
|
||||
f = flags;
|
||||
fprintf (stderr, "%d -> ", f);
|
||||
if (f & LEX_WASDOL)
|
||||
{
|
||||
f &= ~LEX_WASDOL;
|
||||
fprintf (stderr, "LEX_WASDOL%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_CKCOMMENT)
|
||||
{
|
||||
f &= ~LEX_CKCOMMENT;
|
||||
fprintf (stderr, "LEX_CKCOMMENT%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_INCOMMENT)
|
||||
{
|
||||
f &= ~LEX_INCOMMENT;
|
||||
fprintf (stderr, "LEX_INCOMMENT%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_PASSNEXT)
|
||||
{
|
||||
f &= ~LEX_PASSNEXT;
|
||||
fprintf (stderr, "LEX_PASSNEXT%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_RESWDOK)
|
||||
{
|
||||
f &= ~LEX_RESWDOK;
|
||||
fprintf (stderr, "LEX_RESWDOK%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_CKCASE)
|
||||
{
|
||||
f &= ~LEX_CKCASE;
|
||||
fprintf (stderr, "LEX_CKCASE%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_INCASE)
|
||||
{
|
||||
f &= ~LEX_INCASE;
|
||||
fprintf (stderr, "LEX_INCASE%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_INHEREDOC)
|
||||
{
|
||||
f &= ~LEX_INHEREDOC;
|
||||
fprintf (stderr, "LEX_INHEREDOC%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_HEREDELIM)
|
||||
{
|
||||
f &= ~LEX_HEREDELIM;
|
||||
fprintf (stderr, "LEX_HEREDELIM%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_STRIPDOC)
|
||||
{
|
||||
f &= ~LEX_STRIPDOC;
|
||||
fprintf (stderr, "LEX_WASDOL%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_QUOTEDDOC)
|
||||
{
|
||||
f &= ~LEX_QUOTEDDOC;
|
||||
fprintf (stderr, "LEX_QUOTEDDOC%s", f ? "|" : "");
|
||||
}
|
||||
if (f & LEX_INWORD)
|
||||
{
|
||||
f &= ~LEX_INWORD;
|
||||
fprintf (stderr, "LEX_INWORD%s", f ? "|" : "");
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse a $(...) command substitution. This is messier than I'd like, and
|
||||
reproduces a lot more of the token-reading code than I'd like. */
|
||||
static char *
|
||||
|
@ -3621,7 +3771,7 @@ eof_error:
|
|||
tind++;
|
||||
if (STREQN (ret + tind, heredelim, hdlen))
|
||||
{
|
||||
tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC);
|
||||
tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC);
|
||||
/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/
|
||||
free (heredelim);
|
||||
heredelim = 0;
|
||||
|
@ -3641,21 +3791,29 @@ eof_error:
|
|||
if ((tflags & LEX_INHEREDOC) && ch == close && count == 1)
|
||||
{
|
||||
int tind;
|
||||
/*itrace("parse_comsub: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", retind-lex_firstind, hdlen, retind);*/
|
||||
/*itrace("parse_comsub:%d: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", line_number, retind-lex_firstind, hdlen, retind);*/
|
||||
tind = lex_firstind;
|
||||
while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t')
|
||||
tind++;
|
||||
if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen))
|
||||
{
|
||||
tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC);
|
||||
/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/
|
||||
tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC);
|
||||
/*itrace("parse_comsub:%d: found here doc end `%*s'", line_number, hdlen, ret + tind);*/
|
||||
free (heredelim);
|
||||
heredelim = 0;
|
||||
lex_firstind = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't bother counting parens or doing anything else if in a comment */
|
||||
/* Don't bother counting parens or doing anything else if in a comment or
|
||||
here document (not exactly right for here-docs -- if we want to allow
|
||||
recursive calls to parse_comsub to have their own here documents,
|
||||
change the LEX_INHEREDOC to LEX_QUOTEDDOC here and uncomment the next
|
||||
clause below. Note that to make this work completely, we need to make
|
||||
additional changes to allow xparse_dolparen to work right when the
|
||||
command substitution is parsed, because read_secondary_line doesn't know
|
||||
to recursively parse through command substitutions embedded in here-
|
||||
documents */
|
||||
if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC))
|
||||
{
|
||||
/* Add this character. */
|
||||
|
@ -3670,6 +3828,21 @@ eof_error:
|
|||
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
/* If we're going to recursively parse a command substitution inside a
|
||||
here-document, make sure we call parse_comsub recursively below. See
|
||||
above for additional caveats. */
|
||||
if ((tflags & LEX_INHEREDOC) && ((tflags & LEX_WASDOL) == 0 || ch != '(')) /*)*/
|
||||
{
|
||||
/* Add this character. */
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
|
||||
ret[retind++] = ch;
|
||||
if MBTEST(ch == '$')
|
||||
tflags |= LEX_WASDOL;
|
||||
else
|
||||
tflags &= ~LEX_WASDOL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tflags & LEX_PASSNEXT) /* last char was backslash */
|
||||
{
|
||||
|
@ -3747,9 +3920,11 @@ eof_error:
|
|||
{
|
||||
nestret = substring (ret, lex_firstind, retind);
|
||||
heredelim = string_quote_removal (nestret, 0);
|
||||
free (nestret);
|
||||
hdlen = STRLEN(heredelim);
|
||||
/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/
|
||||
if (STREQ (heredelim, nestret) == 0)
|
||||
tflags |= LEX_QUOTEDDOC;
|
||||
free (nestret);
|
||||
}
|
||||
if (ch == '\n')
|
||||
{
|
||||
|
@ -3799,7 +3974,7 @@ eof_error:
|
|||
/* If we can read a reserved word, try to read one. */
|
||||
if (tflags & LEX_RESWDOK)
|
||||
{
|
||||
if MBTEST(islower (ch))
|
||||
if MBTEST(islower ((unsigned char)ch))
|
||||
{
|
||||
/* Add this character. */
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
|
||||
|
@ -3812,14 +3987,34 @@ eof_error:
|
|||
if (STREQN (ret + retind - 4, "case", 4))
|
||||
{
|
||||
tflags |= LEX_INCASE;
|
||||
tflags &= ~LEX_RESWDOK;
|
||||
/*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/
|
||||
}
|
||||
else if (STREQN (ret + retind - 4, "esac", 4))
|
||||
{
|
||||
tflags &= ~LEX_INCASE;
|
||||
/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 0", line_number);*/
|
||||
/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 1", line_number);*/
|
||||
tflags |= LEX_RESWDOK;
|
||||
lex_rwlen = 0;
|
||||
}
|
||||
else if (STREQN (ret + retind - 4, "done", 4) ||
|
||||
STREQN (ret + retind - 4, "then", 4) ||
|
||||
STREQN (ret + retind - 4, "else", 4) ||
|
||||
STREQN (ret + retind - 4, "elif", 4) ||
|
||||
STREQN (ret + retind - 4, "time", 4))
|
||||
{
|
||||
/* these are four-character reserved words that can be
|
||||
followed by a reserved word; anything else turns off
|
||||
the reserved-word-ok flag */
|
||||
/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 1", line_number, ret+retind-4);*/
|
||||
tflags |= LEX_RESWDOK;
|
||||
lex_rwlen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tflags &= ~LEX_RESWDOK;
|
||||
/*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 0", line_number, ret+retind-4);*/
|
||||
}
|
||||
tflags &= ~LEX_RESWDOK;
|
||||
}
|
||||
else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0)))
|
||||
; /* don't modify LEX_RESWDOK if we're starting a comment */
|
||||
|
@ -3827,11 +4022,11 @@ eof_error:
|
|||
RESWDOK flag, but reset the reserved word length counter so we
|
||||
can read another one. */
|
||||
else if MBTEST(((tflags & LEX_INCASE) == 0) &&
|
||||
(isblank(ch) || ch == '\n') &&
|
||||
(isblank((unsigned char)ch) || ch == '\n') &&
|
||||
lex_rwlen == 2 &&
|
||||
STREQN (ret + retind - 2, "do", 2))
|
||||
{
|
||||
/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', found \"do\"", line_number, ch);*/
|
||||
/*itrace("parse_comsub:%d: lex_incase == 0 found `%c', found \"do\"", line_number, ch);*/
|
||||
lex_rwlen = 0;
|
||||
}
|
||||
else if MBTEST((tflags & LEX_INCASE) && ch != '\n')
|
||||
|
@ -3852,7 +4047,7 @@ eof_error:
|
|||
#if 0
|
||||
/* If we find a space or tab but have read something and it's not
|
||||
`do', turn off the reserved-word-ok flag */
|
||||
else if MBTEST(isblank (ch) && lex_rwlen > 0)
|
||||
else if MBTEST(isblank ((unsigned char)ch) && lex_rwlen > 0)
|
||||
{
|
||||
tflags &= ~LEX_RESWDOK;
|
||||
/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/
|
||||
|
@ -4037,7 +4232,8 @@ xparse_dolparen (base, string, indp, flags)
|
|||
/*(*/
|
||||
parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/
|
||||
shell_eof_token = ')';
|
||||
parse_string (string, "command substitution", sflags, &ep);
|
||||
|
||||
nc = parse_string (string, "command substitution", sflags, &ep);
|
||||
|
||||
shell_eof_token = orig_eof_token;
|
||||
restore_parser_state (&ps);
|
||||
|
@ -4047,6 +4243,11 @@ xparse_dolparen (base, string, indp, flags)
|
|||
|
||||
token_to_read = 0;
|
||||
|
||||
/* If parse_string returns < 0, we need to jump to top level with the
|
||||
negative of the return value */
|
||||
if (nc < 0)
|
||||
jump_to_top_level (-nc); /* XXX */
|
||||
|
||||
/* Need to find how many characters parse_and_execute consumed, update
|
||||
*indp, if flags != 0, copy the portion of the string parsed into RET
|
||||
and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */
|
||||
|
@ -4502,7 +4703,7 @@ read_token_word (character)
|
|||
|
||||
/* Non-zero means to ignore the value of the next character, and just
|
||||
to add it no matter what. */
|
||||
int pass_next_character;
|
||||
int pass_next_character;
|
||||
|
||||
/* The current delimiting character. */
|
||||
int cd;
|
||||
|
@ -4799,7 +5000,6 @@ read_token_word (character)
|
|||
}
|
||||
|
||||
got_character:
|
||||
|
||||
if (character == CTLESC || character == CTLNUL)
|
||||
{
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
|
||||
|
@ -4876,7 +5076,7 @@ got_token:
|
|||
#endif
|
||||
CHECK_FOR_RESERVED_WORD (token);
|
||||
|
||||
the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
|
||||
the_word = alloc_word_desc ();
|
||||
the_word->word = (char *)xmalloc (1 + token_index);
|
||||
the_word->flags = 0;
|
||||
strcpy (the_word->word, token);
|
||||
|
@ -4919,7 +5119,7 @@ got_token:
|
|||
/* can use token; already copied to the_word */
|
||||
token[token_index-1] = '\0';
|
||||
#if defined (ARRAY_VARS)
|
||||
if (legal_identifier (token+1) || valid_array_reference (token+1))
|
||||
if (legal_identifier (token+1) || valid_array_reference (token+1, 0))
|
||||
#else
|
||||
if (legal_identifier (token+1))
|
||||
#endif
|
||||
|
@ -5092,7 +5292,7 @@ history_delimiting_chars (line)
|
|||
last_was_heredoc = 0;
|
||||
return "\n";
|
||||
}
|
||||
return (current_command_line_count == 2 ? "\n" : "");
|
||||
return (here_doc_first_line ? "\n" : "");
|
||||
}
|
||||
|
||||
if (parser_state & PST_COMPASSIGN)
|
||||
|
@ -5113,7 +5313,7 @@ history_delimiting_chars (line)
|
|||
command lists. It's a suboptimal solution. */
|
||||
else if (parser_state & PST_CASESTMT) /* case statement pattern */
|
||||
return " ";
|
||||
else
|
||||
else
|
||||
return "; "; /* (...) subshell */
|
||||
}
|
||||
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
|
||||
|
@ -5127,7 +5327,8 @@ history_delimiting_chars (line)
|
|||
last_was_heredoc = 1;
|
||||
return "\n";
|
||||
}
|
||||
|
||||
else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && need_here_doc > 0)
|
||||
return "\n";
|
||||
else if (token_before_that == WORD && two_tokens_ago == FOR)
|
||||
{
|
||||
/* Tricky. `for i\nin ...' should not have a semicolon, but
|
||||
|
@ -5164,6 +5365,8 @@ prompt_again ()
|
|||
ps1_prompt = get_string_value ("PS1");
|
||||
ps2_prompt = get_string_value ("PS2");
|
||||
|
||||
ps0_prompt = get_string_value ("PS0");
|
||||
|
||||
if (!prompt_string_pointer)
|
||||
prompt_string_pointer = &ps1_prompt;
|
||||
|
||||
|
@ -5256,9 +5459,10 @@ decode_prompt_string (string)
|
|||
struct dstack save_dstack;
|
||||
int last_exit_value, last_comsub_pid;
|
||||
#if defined (PROMPT_STRING_DECODE)
|
||||
int result_size, result_index;
|
||||
size_t result_size;
|
||||
int result_index;
|
||||
int c, n, i;
|
||||
char *temp, octal_string[4];
|
||||
char *temp, *t_host, octal_string[4];
|
||||
struct tm *tm;
|
||||
time_t the_time;
|
||||
char timebuf[128];
|
||||
|
@ -5406,7 +5610,11 @@ decode_prompt_string (string)
|
|||
|
||||
case 's':
|
||||
temp = base_pathname (shell_name);
|
||||
temp = savestring (temp);
|
||||
/* Try to quote anything the user can set in the file system */
|
||||
if (promptvars || posixly_correct)
|
||||
temp = sh_backslash_quote_for_double_quotes (temp);
|
||||
else
|
||||
temp = savestring (temp);
|
||||
goto add_string;
|
||||
|
||||
case 'v':
|
||||
|
@ -5496,9 +5704,17 @@ decode_prompt_string (string)
|
|||
|
||||
case 'h':
|
||||
case 'H':
|
||||
temp = savestring (current_host_name);
|
||||
if (c == 'h' && (t = (char *)strchr (temp, '.')))
|
||||
t_host = savestring (current_host_name);
|
||||
if (c == 'h' && (t = (char *)strchr (t_host, '.')))
|
||||
*t = '\0';
|
||||
if (promptvars || posixly_correct)
|
||||
/* Make sure that expand_prompt_string is called with a
|
||||
second argument of Q_DOUBLE_QUOTES if we use this
|
||||
function here. */
|
||||
temp = sh_backslash_quote_for_double_quotes (t_host);
|
||||
else
|
||||
temp = savestring (t_host);
|
||||
free (t_host);
|
||||
goto add_string;
|
||||
|
||||
case '#':
|
||||
|
@ -5589,6 +5805,10 @@ not_escape:
|
|||
else
|
||||
{
|
||||
RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH);
|
||||
/* dequote_string should take care of removing this if we are not
|
||||
performing the rest of the word expansions. */
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
result[result_index++] = CTLESC;
|
||||
result[result_index++] = c;
|
||||
result[result_index] = '\0';
|
||||
}
|
||||
|
@ -6082,6 +6302,8 @@ sh_parser_state_t *
|
|||
save_parser_state (ps)
|
||||
sh_parser_state_t *ps;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ps == 0)
|
||||
ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t));
|
||||
if (ps == 0)
|
||||
|
@ -6115,6 +6337,17 @@ save_parser_state (ps)
|
|||
ps->expand_aliases = expand_aliases;
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
ps->need_here_doc = need_here_doc;
|
||||
ps->here_doc_first_line = here_doc_first_line;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < HEREDOC_MAX; i++)
|
||||
ps->redir_stack[i] = redir_stack[i];
|
||||
#else
|
||||
if (need_here_doc == 0)
|
||||
ps->redir_stack[0] = 0;
|
||||
else
|
||||
memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX);
|
||||
#endif
|
||||
|
||||
ps->token = token;
|
||||
ps->token_buffer_size = token_buffer_size;
|
||||
|
@ -6129,6 +6362,8 @@ void
|
|||
restore_parser_state (ps)
|
||||
sh_parser_state_t *ps;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ps == 0)
|
||||
return;
|
||||
|
||||
|
@ -6164,6 +6399,17 @@ restore_parser_state (ps)
|
|||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
need_here_doc = ps->need_here_doc;
|
||||
here_doc_first_line = ps->here_doc_first_line;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < HEREDOC_MAX; i++)
|
||||
redir_stack[i] = ps->redir_stack[i];
|
||||
#else
|
||||
if (need_here_doc == 0)
|
||||
redir_stack[0] = 0;
|
||||
else
|
||||
memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX);
|
||||
#endif
|
||||
|
||||
FREE (token);
|
||||
token = ps->token;
|
||||
|
@ -6222,8 +6468,7 @@ set_line_mbstate ()
|
|||
if (shell_input_line == NULL)
|
||||
return;
|
||||
len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */
|
||||
FREE (shell_input_line_property);
|
||||
shell_input_line_property = (char *)xmalloc (len + 1);
|
||||
shell_input_line_property = (char *)xrealloc (shell_input_line_property, len + 1);
|
||||
|
||||
memset (&prevs, '\0', sizeof (mbstate_t));
|
||||
for (i = previ = 0; i < len; i++)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue