mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-07 02:32:27 +02:00
Initial devel branch import from bash-3.0-alpha
This commit is contained in:
@@ -69,6 +69,8 @@
|
||||
|
||||
#if defined (ALIAS)
|
||||
# include "alias.h"
|
||||
#else
|
||||
typedef void *alias_t;
|
||||
#endif /* ALIAS */
|
||||
|
||||
#if defined (PROMPT_STRING_DECODE)
|
||||
@@ -171,7 +173,7 @@ static char *parse_compound_assignment __P((int *));
|
||||
#endif
|
||||
#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
|
||||
static int parse_dparen __P((int));
|
||||
static int parse_arith_cmd __P((char **));
|
||||
static int parse_arith_cmd __P((char **, int));
|
||||
#endif
|
||||
#if defined (COND_COMMAND)
|
||||
static void cond_error __P((void));
|
||||
@@ -239,6 +241,11 @@ int expand_aliases = 0;
|
||||
decode_prompt_string. */
|
||||
int promptvars = 1;
|
||||
|
||||
/* If non-zero, $'...' and $"..." are expanded when they appear within
|
||||
a ${...} expansion, even when the expansion appears within double
|
||||
quotes. */
|
||||
int extended_quote = 1;
|
||||
|
||||
/* The decoded prompt string. Used if READLINE is not defined or if
|
||||
editing is turned off. Analogous to current_readline_prompt. */
|
||||
static char *current_decoded_prompt;
|
||||
@@ -270,6 +277,13 @@ static int function_bstart;
|
||||
/* The line number in a script at which an arithmetic for command starts. */
|
||||
static int arith_for_lineno;
|
||||
|
||||
/* The line number in a script where the word in a `case WORD', `select WORD'
|
||||
or `for WORD' begins. This is a nested command maximum, since the array
|
||||
index is decremented after a case, select, or for command is parsed. */
|
||||
#define MAX_CASE_NEST 128
|
||||
static int word_lineno[MAX_CASE_NEST];
|
||||
static int word_top = -1;
|
||||
|
||||
static REDIRECTEE redir;
|
||||
%}
|
||||
|
||||
@@ -601,65 +615,116 @@ shell_command: for_command
|
||||
;
|
||||
|
||||
for_command: FOR WORD newline_list DO compound_list DONE
|
||||
{ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5); }
|
||||
{
|
||||
$$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD newline_list '{' compound_list '}'
|
||||
{ $$ = make_for_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5); }
|
||||
{
|
||||
$$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD ';' newline_list DO compound_list DONE
|
||||
{ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); }
|
||||
{
|
||||
$$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD ';' newline_list '{' compound_list '}'
|
||||
{ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6); }
|
||||
{
|
||||
$$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE
|
||||
{ $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); }
|
||||
{
|
||||
$$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}'
|
||||
{ $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); }
|
||||
{
|
||||
$$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE
|
||||
{ $$ = make_for_command ($2, (WORD_LIST *)NULL, $8); }
|
||||
{
|
||||
$$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}'
|
||||
{ $$ = make_for_command ($2, (WORD_LIST *)NULL, $8); }
|
||||
{
|
||||
$$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
;
|
||||
|
||||
arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE
|
||||
{ $$ = make_arith_for_command ($2, $6, arith_for_lineno); }
|
||||
{
|
||||
$$ = make_arith_for_command ($2, $6, arith_for_lineno);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}'
|
||||
{ $$ = make_arith_for_command ($2, $6, arith_for_lineno); }
|
||||
{
|
||||
$$ = make_arith_for_command ($2, $6, arith_for_lineno);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR ARITH_FOR_EXPRS DO compound_list DONE
|
||||
{ $$ = make_arith_for_command ($2, $4, arith_for_lineno); }
|
||||
{
|
||||
$$ = make_arith_for_command ($2, $4, arith_for_lineno);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| FOR ARITH_FOR_EXPRS '{' compound_list '}'
|
||||
{ $$ = make_arith_for_command ($2, $4, arith_for_lineno); }
|
||||
{
|
||||
$$ = make_arith_for_command ($2, $4, arith_for_lineno);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
;
|
||||
|
||||
select_command: SELECT WORD newline_list DO list DONE
|
||||
{
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5);
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| SELECT WORD newline_list '{' list '}'
|
||||
{
|
||||
$$ = make_select_command ($2, add_string_to_list ("$@", (WORD_LIST *)NULL), $5);
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| SELECT WORD ';' newline_list DO list DONE
|
||||
{
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6);
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| SELECT WORD ';' newline_list '{' list '}'
|
||||
{
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6);
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE
|
||||
{
|
||||
$$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9);
|
||||
$$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}'
|
||||
{
|
||||
$$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9);
|
||||
$$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
;
|
||||
|
||||
case_command: CASE WORD newline_list IN newline_list ESAC
|
||||
{ $$ = make_case_command ($2, (PATTERN_LIST *)NULL); }
|
||||
{
|
||||
$$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| CASE WORD newline_list IN case_clause_sequence newline_list ESAC
|
||||
{ $$ = make_case_command ($2, $5); }
|
||||
{
|
||||
$$ = make_case_command ($2, $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
| CASE WORD newline_list IN case_clause ESAC
|
||||
{ $$ = make_case_command ($2, $5); }
|
||||
{
|
||||
$$ = make_case_command ($2, $5, word_lineno[word_top]);
|
||||
if (word_top > 0) word_top--;
|
||||
}
|
||||
;
|
||||
|
||||
function_def: WORD '(' ')' newline_list function_body
|
||||
@@ -918,23 +983,35 @@ timespec: TIME
|
||||
%%
|
||||
|
||||
/* Possible states for the parser that require it to do special things. */
|
||||
#define PST_CASEPAT 0x001 /* in a case pattern list */
|
||||
#define PST_ALEXPNEXT 0x002 /* expand next word for aliases */
|
||||
#define PST_ALLOWOPNBRC 0x004 /* allow open brace for function def */
|
||||
#define PST_NEEDCLOSBRC 0x008 /* need close brace */
|
||||
#define PST_DBLPAREN 0x010 /* double-paren parsing */
|
||||
#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 [[...]] */
|
||||
#define PST_ARITHFOR 0x400 /* parsing an arithmetic for command */
|
||||
#define PST_CASEPAT 0x0001 /* in a case pattern list */
|
||||
#define PST_ALEXPNEXT 0x0002 /* expand next word for aliases */
|
||||
#define PST_ALLOWOPNBRC 0x0004 /* allow open brace for function def */
|
||||
#define PST_NEEDCLOSBRC 0x0008 /* need close brace */
|
||||
#define PST_DBLPAREN 0x0010 /* double-paren parsing */
|
||||
#define PST_SUBSHELL 0x0020 /* ( ... ) subshell */
|
||||
#define PST_CMDSUBST 0x0040 /* $( ... ) command substitution */
|
||||
#define PST_CASESTMT 0x0080 /* parsing a case statement */
|
||||
#define PST_CONDCMD 0x0100 /* parsing a [[...]] command */
|
||||
#define PST_CONDEXPR 0x0200 /* parsing the guts of [[...]] */
|
||||
#define PST_ARITHFOR 0x0400 /* parsing an arithmetic for command */
|
||||
#define PST_ALEXPAND 0x0800 /* OK to expand aliases - unused */
|
||||
#define PST_CMDTOKEN 0x1000 /* command token OK - unused */
|
||||
|
||||
/* Initial size to allocate for tokens, and the
|
||||
amount to grow them by. */
|
||||
#define TOKEN_DEFAULT_INITIAL_SIZE 496
|
||||
#define TOKEN_DEFAULT_GROW_SIZE 512
|
||||
|
||||
/* Should we call prompt_again? */
|
||||
#define SHOULD_PROMPT() \
|
||||
(interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
|
||||
|
||||
#if defined (ALIAS)
|
||||
# define expanding_alias() (pushed_string_list && pushed_string_list->expander)
|
||||
#else
|
||||
# define expanding_alias() 0
|
||||
#endif
|
||||
|
||||
/* The token currently being read. */
|
||||
static int current_token;
|
||||
|
||||
@@ -1399,10 +1476,6 @@ restore_token_state (ts)
|
||||
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
|
||||
#if !defined (ALIAS)
|
||||
typedef void *alias_t;
|
||||
#endif
|
||||
|
||||
#define END_OF_ALIAS 0
|
||||
|
||||
/*
|
||||
@@ -1462,7 +1535,9 @@ push_string (s, expand, ap)
|
||||
shell_input_line_size = strlen (s);
|
||||
shell_input_line_index = 0;
|
||||
shell_input_line_terminator = '\0';
|
||||
parser_state &= ~PST_ALEXPNEXT;
|
||||
#if 0
|
||||
parser_state &= ~PST_ALEXPNEXT; /* XXX */
|
||||
#endif
|
||||
|
||||
set_line_mbstate ();
|
||||
}
|
||||
@@ -1523,6 +1598,14 @@ free_string_list ()
|
||||
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
void
|
||||
free_pushed_string_input ()
|
||||
{
|
||||
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
|
||||
free_string_list ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -1536,9 +1619,9 @@ read_a_line (remove_quoted_newline)
|
||||
int indx = 0, c, peekc, pass_next;
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive && bash_input.type != st_string && no_line_editing)
|
||||
if (no_line_editing && SHOULD_PROMPT ())
|
||||
#else
|
||||
if (interactive && bash_input.type != st_string)
|
||||
if (SHOULD_PROMPT ())
|
||||
#endif
|
||||
print_prompt ();
|
||||
|
||||
@@ -1587,7 +1670,10 @@ read_a_line (remove_quoted_newline)
|
||||
{
|
||||
peekc = yy_getc ();
|
||||
if (peekc == '\n')
|
||||
continue; /* Make the unquoted \<newline> pair disappear. */
|
||||
{
|
||||
line_number++;
|
||||
continue; /* Make the unquoted \<newline> pair disappear. */
|
||||
}
|
||||
else
|
||||
{
|
||||
yy_ungetc (peekc);
|
||||
@@ -1616,7 +1702,8 @@ read_secondary_line (remove_quoted_newline)
|
||||
int remove_quoted_newline;
|
||||
{
|
||||
prompt_string_pointer = &ps2_prompt;
|
||||
prompt_again ();
|
||||
if (SHOULD_PROMPT())
|
||||
prompt_again ();
|
||||
return (read_a_line (remove_quoted_newline));
|
||||
}
|
||||
|
||||
@@ -1778,20 +1865,27 @@ shell_getc (remove_quoted_newline)
|
||||
i = 0;
|
||||
shell_input_line_terminator = 0;
|
||||
|
||||
/* If the shell is interatctive, but not currently printing a prompt
|
||||
(interactive_shell && interactive == 0), we don't want to print
|
||||
notifies or cleanup the jobs -- we want to defer it until we do
|
||||
print the next prompt. */
|
||||
if (interactive_shell == 0 || SHOULD_PROMPT())
|
||||
{
|
||||
#if defined (JOB_CONTROL)
|
||||
/* This can cause a problem when reading a command as the result
|
||||
of a trap, when the trap is called from flush_child. This call
|
||||
had better not cause jobs to disappear from the job table in
|
||||
that case, or we will have big trouble. */
|
||||
notify_and_cleanup ();
|
||||
notify_and_cleanup ();
|
||||
#else /* !JOB_CONTROL */
|
||||
cleanup_dead_jobs ();
|
||||
cleanup_dead_jobs ();
|
||||
#endif /* !JOB_CONTROL */
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive && bash_input.type != st_string && no_line_editing)
|
||||
if (no_line_editing && SHOULD_PROMPT())
|
||||
#else
|
||||
if (interactive && bash_input.type != st_string)
|
||||
if (SHOULD_PROMPT())
|
||||
#endif
|
||||
print_prompt ();
|
||||
|
||||
@@ -1911,7 +2005,8 @@ shell_getc (remove_quoted_newline)
|
||||
{
|
||||
shell_input_line_size = 0;
|
||||
prompt_string_pointer = ¤t_prompt_string;
|
||||
prompt_again ();
|
||||
if (SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
goto restart_read;
|
||||
}
|
||||
|
||||
@@ -1937,7 +2032,8 @@ shell_getc (remove_quoted_newline)
|
||||
|
||||
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
|
||||
{
|
||||
prompt_again ();
|
||||
if (SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
line_number++;
|
||||
goto restart_read;
|
||||
}
|
||||
@@ -1950,19 +2046,10 @@ shell_getc (remove_quoted_newline)
|
||||
to. */
|
||||
if (!uc && (pushed_string_list != (STRING_SAVER *)NULL))
|
||||
{
|
||||
if (mustpop)
|
||||
{
|
||||
pop_string ();
|
||||
uc = shell_input_line[shell_input_line_index];
|
||||
if (uc)
|
||||
shell_input_line_index++;
|
||||
mustpop--;
|
||||
}
|
||||
else
|
||||
{
|
||||
mustpop++;
|
||||
uc = ' ';
|
||||
}
|
||||
pop_string ();
|
||||
uc = shell_input_line[shell_input_line_index];
|
||||
if (uc)
|
||||
shell_input_line_index++;
|
||||
}
|
||||
#endif /* ALIAS || DPAREN_ARITHMETIC */
|
||||
|
||||
@@ -2016,25 +2103,17 @@ void
|
||||
execute_prompt_command (command)
|
||||
char *command;
|
||||
{
|
||||
sh_builtin_func_t *temp_last, *temp_this;
|
||||
char *last_lastarg;
|
||||
int temp_exit_value, temp_eof_encountered;
|
||||
sh_parser_state_t ps;
|
||||
|
||||
temp_last = last_shell_builtin;
|
||||
temp_this = this_shell_builtin;
|
||||
temp_exit_value = last_command_exit_value;
|
||||
temp_eof_encountered = eof_encountered;
|
||||
save_parser_state (&ps);
|
||||
last_lastarg = get_string_value ("_");
|
||||
if (last_lastarg)
|
||||
last_lastarg = savestring (last_lastarg);
|
||||
|
||||
parse_and_execute (savestring (command), "PROMPT_COMMAND", SEVAL_NONINT|SEVAL_NOHIST);
|
||||
|
||||
last_shell_builtin = temp_last;
|
||||
this_shell_builtin = temp_this;
|
||||
last_command_exit_value = temp_exit_value;
|
||||
eof_encountered = temp_eof_encountered;
|
||||
|
||||
restore_parser_state (&ps);
|
||||
bind_variable ("_", last_lastarg);
|
||||
FREE (last_lastarg);
|
||||
|
||||
@@ -2074,7 +2153,7 @@ yylex ()
|
||||
|
||||
/* Avoid printing a prompt if we're not going to read anything, e.g.
|
||||
after resetting the parser with read_token (RESET). */
|
||||
if (token_to_read == 0 && interactive)
|
||||
if (token_to_read == 0 && SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
}
|
||||
|
||||
@@ -2108,8 +2187,8 @@ static int open_brace_count;
|
||||
(((token) == ASSIGNMENT_WORD) || \
|
||||
((token) != SEMI_SEMI && reserved_word_acceptable(token)))
|
||||
|
||||
#define assignment_acceptable(token) command_token_position(token) && \
|
||||
((parser_state & PST_CASEPAT) == 0)
|
||||
#define assignment_acceptable(token) \
|
||||
(command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
|
||||
|
||||
/* Check to see if TOKEN is a reserved word and return the token
|
||||
value if it is. */
|
||||
@@ -2124,7 +2203,7 @@ static int open_brace_count;
|
||||
{ \
|
||||
if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \
|
||||
break; \
|
||||
if (word_token_alist[i].token == TIME) \
|
||||
if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \
|
||||
break; \
|
||||
if (word_token_alist[i].token == ESAC) \
|
||||
parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
|
||||
@@ -2157,6 +2236,23 @@ static int open_brace_count;
|
||||
|
||||
Special cases that disqualify:
|
||||
In a pattern list in a case statement (parser_state & PST_CASEPAT). */
|
||||
|
||||
static char *
|
||||
mk_alexpansion (s)
|
||||
char *s;
|
||||
{
|
||||
int l;
|
||||
char *r;
|
||||
|
||||
l = strlen (s);
|
||||
r = xmalloc (l + 2);
|
||||
strcpy (r, s);
|
||||
if (r[l -1] != ' ')
|
||||
r[l++] = ' ';
|
||||
r[l] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
alias_expand_token (tokstr)
|
||||
char *tokstr;
|
||||
@@ -2173,7 +2269,12 @@ alias_expand_token (tokstr)
|
||||
if (ap && (ap->flags & AL_BEINGEXPANDED))
|
||||
return (NO_EXPANSION);
|
||||
|
||||
expanded = ap ? savestring (ap->value) : (char *)NULL;
|
||||
/* mk_alexpansion puts an extra space on the end of the alias expansion,
|
||||
so the lookahead by the parser works right. If this gets changed,
|
||||
make sure the code in shell_getc that deals with reaching the end of
|
||||
an expanded alias is changed with it. */
|
||||
expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL;
|
||||
|
||||
if (expanded)
|
||||
{
|
||||
push_string (expanded, ap->flags & AL_EXPANDNEXT, ap);
|
||||
@@ -2317,10 +2418,12 @@ special_case_tokens (tokstr)
|
||||
return (TIMEOPT);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if defined (COMMAND_TIMING)
|
||||
if (STREQ (token, "time") && ((parser_state & PST_CASEPAT) == 0) && time_command_acceptable ())
|
||||
return (TIME);
|
||||
#endif /* COMMAND_TIMING */
|
||||
#endif
|
||||
|
||||
#if defined (COND_COMMAND) /* [[ */
|
||||
if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0')
|
||||
@@ -2565,6 +2668,7 @@ read_token (command)
|
||||
*/
|
||||
#define P_FIRSTCLOSE 0x01
|
||||
#define P_ALLOWESC 0x02
|
||||
#define P_DQUOTE 0x04
|
||||
|
||||
static char matched_pair_error;
|
||||
static char *
|
||||
@@ -2576,11 +2680,14 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
int count, ch, was_dollar;
|
||||
int pass_next_character, nestlen, ttranslen, start_lineno;
|
||||
char *ret, *nestret, *ttrans;
|
||||
int retind, retsize;
|
||||
int retind, retsize, rflags;
|
||||
|
||||
count = 1;
|
||||
pass_next_character = was_dollar = 0;
|
||||
|
||||
/* RFLAGS is the set of flags we want to pass to recursive calls. */
|
||||
rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE);
|
||||
|
||||
ret = (char *)xmalloc (retsize = 64);
|
||||
retind = 0;
|
||||
|
||||
@@ -2597,8 +2704,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
}
|
||||
|
||||
/* Possible reprompting. */
|
||||
if (ch == '\n' && interactive &&
|
||||
(bash_input.type == st_stdin || bash_input.type == st_stream))
|
||||
if (ch == '\n' && SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
|
||||
if (pass_next_character) /* last char was backslash */
|
||||
@@ -2654,16 +2760,16 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
/* '', ``, or "" inside $(...) or other grouping construct. */
|
||||
push_delimiter (dstack, ch);
|
||||
if MBTEST(was_dollar && ch == '\'') /* $'...' inside group */
|
||||
nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC);
|
||||
nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags);
|
||||
else
|
||||
nestret = parse_matched_pair (ch, ch, ch, &nestlen, 0);
|
||||
nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags);
|
||||
pop_delimiter (dstack);
|
||||
if (nestret == &matched_pair_error)
|
||||
{
|
||||
free (ret);
|
||||
return &matched_pair_error;
|
||||
}
|
||||
if MBTEST(was_dollar && ch == '\'')
|
||||
if MBTEST(was_dollar && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
|
||||
{
|
||||
/* Translate $'...' here. */
|
||||
ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
|
||||
@@ -2673,7 +2779,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
nestlen = strlen (nestret);
|
||||
retind -= 2; /* back up before the $' */
|
||||
}
|
||||
else if MBTEST(was_dollar && ch == '"')
|
||||
else if MBTEST(was_dollar && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
|
||||
{
|
||||
/* Locale expand $"..." here. */
|
||||
ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
|
||||
@@ -2702,7 +2808,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
/* XXX - sh and ksh93 don't do this - XXX */
|
||||
else if MBTEST(open == '"' && ch == '`')
|
||||
{
|
||||
nestret = parse_matched_pair (0, '`', '`', &nestlen, 0);
|
||||
nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags);
|
||||
if (nestret == &matched_pair_error)
|
||||
{
|
||||
free (ret);
|
||||
@@ -2722,11 +2828,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
if (open == ch) /* undo previous increment */
|
||||
count--;
|
||||
if (ch == '(') /* ) */
|
||||
nestret = parse_matched_pair (0, '(', ')', &nestlen, 0);
|
||||
nestret = parse_matched_pair (0, '(', ')', &nestlen, rflags);
|
||||
else if (ch == '{') /* } */
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE);
|
||||
nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
|
||||
else if (ch == '[') /* ] */
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, 0);
|
||||
nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
|
||||
if (nestret == &matched_pair_error)
|
||||
{
|
||||
free (ret);
|
||||
@@ -2766,19 +2872,12 @@ parse_dparen (c)
|
||||
if (last_read_token == FOR)
|
||||
{
|
||||
arith_for_lineno = line_number;
|
||||
cmdtyp = parse_arith_cmd (&wval);
|
||||
cmdtyp = parse_arith_cmd (&wval, 0);
|
||||
if (cmdtyp == 1)
|
||||
{
|
||||
/* parse_arith_cmd adds quotes at the beginning and end
|
||||
of the string it returns; we need to take those out. */
|
||||
len = strlen (wval);
|
||||
wv2 = (char *)xmalloc (len);
|
||||
strncpy (wv2, wval + 1, len - 2);
|
||||
wv2[len - 2] = '\0';
|
||||
wd = make_word (wv2);
|
||||
wd = make_word (wval);
|
||||
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
|
||||
free (wval);
|
||||
free (wv2);
|
||||
return (ARITH_FOR_EXPRS);
|
||||
}
|
||||
else
|
||||
@@ -2790,11 +2889,19 @@ parse_dparen (c)
|
||||
if (reserved_word_acceptable (last_read_token))
|
||||
{
|
||||
sline = line_number;
|
||||
cmdtyp = parse_arith_cmd (&wval);
|
||||
#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
|
||||
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
|
||||
free (wval); /* make_word copies it */
|
||||
return (ARITH_CMD);
|
||||
@@ -2820,8 +2927,9 @@ parse_dparen (c)
|
||||
allocated buffer and make *ep point to that buffer. Return -1 on an
|
||||
error, for example EOF. */
|
||||
static int
|
||||
parse_arith_cmd (ep)
|
||||
parse_arith_cmd (ep, adddq)
|
||||
char **ep;
|
||||
int adddq;
|
||||
{
|
||||
int exp_lineno, rval, c;
|
||||
char *ttok, *tokstr;
|
||||
@@ -2840,20 +2948,28 @@ parse_arith_cmd (ep)
|
||||
|
||||
tokstr = (char *)xmalloc (ttoklen + 4);
|
||||
|
||||
/* (( ... )) -> "..." */
|
||||
tokstr[0] = (rval == 1) ? '"' : '(';
|
||||
strncpy (tokstr + 1, ttok, ttoklen - 1); /* don't copy the final `)' */
|
||||
if (rval == 1)
|
||||
/* if ADDDQ != 0 then (( ... )) -> "..." */
|
||||
if (rval == 1 && adddq) /* arith cmd, add double quotes */
|
||||
{
|
||||
tokstr[0] = '"';
|
||||
strncpy (tokstr + 1, ttok, ttoklen - 1);
|
||||
tokstr[ttoklen] = '"';
|
||||
tokstr[ttoklen+1] = '\0';
|
||||
}
|
||||
else
|
||||
else if (rval == 1) /* arith cmd, don't add double quotes */
|
||||
{
|
||||
strncpy (tokstr, ttok, ttoklen - 1);
|
||||
tokstr[ttoklen-1] = '\0';
|
||||
}
|
||||
else /* nested subshell */
|
||||
{
|
||||
tokstr[0] = '(';
|
||||
strncpy (tokstr + 1, ttok, ttoklen - 1);
|
||||
tokstr[ttoklen] = ')';
|
||||
tokstr[ttoklen+1] = c;
|
||||
tokstr[ttoklen+2] = '\0';
|
||||
}
|
||||
|
||||
*ep = tokstr;
|
||||
FREE (ttok);
|
||||
return rval;
|
||||
@@ -2919,7 +3035,7 @@ cond_skip_newlines ()
|
||||
{
|
||||
while ((cond_token = read_token (READ)) == '\n')
|
||||
{
|
||||
if (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
|
||||
if (SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
}
|
||||
return (cond_token);
|
||||
@@ -3005,6 +3121,10 @@ cond_term ()
|
||||
tok = read_token (READ);
|
||||
if (tok == WORD && test_binop (yylval.word->word))
|
||||
op = yylval.word;
|
||||
#if defined (COND_REGEXP)
|
||||
else if (tok == WORD && STREQ (yylval.word->word,"=~"))
|
||||
op = yylval.word;
|
||||
#endif
|
||||
else if (tok == '<' || tok == '>')
|
||||
op = make_word_from_token (tok); /* ( */
|
||||
/* There should be a check before blindly accepting the `)' that we have
|
||||
@@ -3420,8 +3540,7 @@ read_token_word (character)
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
|
||||
next_character:
|
||||
if (character == '\n' && interactive &&
|
||||
(bash_input.type == st_stdin || bash_input.type == st_stream))
|
||||
if (character == '\n' && SHOULD_PROMPT ())
|
||||
prompt_again ();
|
||||
|
||||
/* We want to remove quoted newlines (that is, a \<newline> pair)
|
||||
@@ -3503,10 +3622,19 @@ got_token:
|
||||
result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT))
|
||||
? ASSIGNMENT_WORD : WORD;
|
||||
|
||||
if (last_read_token == FUNCTION)
|
||||
switch (last_read_token)
|
||||
{
|
||||
case FUNCTION:
|
||||
parser_state |= PST_ALLOWOPNBRC;
|
||||
function_dstart = line_number;
|
||||
break;
|
||||
case CASE:
|
||||
case SELECT:
|
||||
case FOR:
|
||||
if (word_top < MAX_CASE_NEST)
|
||||
word_top++;
|
||||
word_lineno[word_top] = line_number;
|
||||
break;
|
||||
}
|
||||
|
||||
return (result);
|
||||
@@ -3664,7 +3792,7 @@ prompt_again ()
|
||||
{
|
||||
char *temp_prompt;
|
||||
|
||||
if (!interactive) /* XXX */
|
||||
if (interactive == 0 || expanding_alias()) /* XXX */
|
||||
return;
|
||||
|
||||
ps1_prompt = get_string_value ("PS1");
|
||||
@@ -4020,6 +4148,11 @@ decode_prompt_string (string)
|
||||
#if defined (READLINE)
|
||||
case '[':
|
||||
case ']':
|
||||
if (no_line_editing)
|
||||
{
|
||||
string++;
|
||||
break;
|
||||
}
|
||||
temp = (char *)xmalloc (3);
|
||||
temp[0] = '\001';
|
||||
temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
|
||||
@@ -4514,6 +4647,105 @@ parse_compound_assignment (retlenp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* *
|
||||
* SAVING AND RESTORING PARTIAL PARSE STATE *
|
||||
* *
|
||||
************************************************/
|
||||
|
||||
sh_parser_state_t *
|
||||
save_parser_state (ps)
|
||||
sh_parser_state_t *ps;
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *v;
|
||||
#endif
|
||||
|
||||
if (ps == 0)
|
||||
ps = xmalloc (sizeof (sh_parser_state_t));
|
||||
if (ps == 0)
|
||||
return ((sh_parser_state_t *)NULL);
|
||||
|
||||
ps->parser_state = parser_state;
|
||||
ps->token_state = save_token_state ();
|
||||
|
||||
ps->input_line_terminator = shell_input_line_terminator;
|
||||
ps->eof_encountered = eof_encountered;
|
||||
|
||||
ps->current_command_line_count = current_command_line_count;
|
||||
|
||||
#if defined (HISTORY)
|
||||
ps->remember_on_history = remember_on_history;
|
||||
# if defined (BANG_HISTORY)
|
||||
ps->history_expansion_inhibited = history_expansion_inhibited;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ps->last_command_exit_value = last_command_exit_value;
|
||||
#if defined (ARRAY_VARS)
|
||||
v = find_variable ("PIPESTATUS");
|
||||
if (v && array_p (v) && array_cell (v))
|
||||
ps->pipestatus = array_copy (array_cell (v));
|
||||
else
|
||||
ps->pipestatus = (ARRAY *)NULL;
|
||||
#endif
|
||||
|
||||
ps->last_shell_builtin = last_shell_builtin;
|
||||
ps->this_shell_builtin = this_shell_builtin;
|
||||
|
||||
ps->expand_aliases = expand_aliases;
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
|
||||
return (ps);
|
||||
}
|
||||
|
||||
void
|
||||
restore_parser_state (ps)
|
||||
sh_parser_state_t *ps;
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *v;
|
||||
#endif
|
||||
|
||||
if (ps == 0)
|
||||
return;
|
||||
|
||||
parser_state = ps->parser_state;
|
||||
if (ps->token_state)
|
||||
{
|
||||
restore_token_state (ps->token_state);
|
||||
free (ps->token_state);
|
||||
}
|
||||
|
||||
shell_input_line_terminator = ps->input_line_terminator;
|
||||
eof_encountered = ps->eof_encountered;
|
||||
|
||||
current_command_line_count = ps->current_command_line_count;
|
||||
|
||||
#if defined (HISTORY)
|
||||
remember_on_history = ps->remember_on_history;
|
||||
# if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = ps->history_expansion_inhibited;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
last_command_exit_value = ps->last_command_exit_value;
|
||||
#if defined (ARRAY_VARS)
|
||||
v = find_variable ("PIPESTATUS");
|
||||
if (v && array_p (v) && array_cell (v))
|
||||
{
|
||||
array_dispose (array_cell (v));
|
||||
var_setarray (v, ps->pipestatus);
|
||||
}
|
||||
#endif
|
||||
|
||||
last_shell_builtin = ps->last_shell_builtin;
|
||||
this_shell_builtin = ps->this_shell_builtin;
|
||||
|
||||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* *
|
||||
* MULTIBYTE CHARACTER HANDLING *
|
||||
@@ -4524,7 +4756,7 @@ parse_compound_assignment (retlenp)
|
||||
static void
|
||||
set_line_mbstate ()
|
||||
{
|
||||
int i, previ, len;
|
||||
int i, previ, len, c;
|
||||
mbstate_t mbs, prevs;
|
||||
size_t mbclen;
|
||||
|
||||
@@ -4539,7 +4771,8 @@ set_line_mbstate ()
|
||||
{
|
||||
mbs = prevs;
|
||||
|
||||
if (shell_input_line[i] == EOF)
|
||||
c = shell_input_line[i];
|
||||
if (c == EOF)
|
||||
{
|
||||
int j;
|
||||
for (j = i; j < len; j++)
|
||||
@@ -4563,7 +4796,11 @@ set_line_mbstate ()
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mbrlen doesn't return any other values */
|
||||
/* XXX - what to do if mbrlen returns 0? (null wide character) */
|
||||
int j;
|
||||
for (j = i; j < len; j++)
|
||||
shell_input_line_property[j] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
shell_input_line_property[i] = mbclen;
|
||||
|
||||
Reference in New Issue
Block a user