Imported from ../bash-4.0-rc1.tar.gz.

This commit is contained in:
Jari Aalto 2009-01-12 13:36:28 +00:00
commit 3185942a52
666 changed files with 188710 additions and 54674 deletions

View file

@ -1,22 +1,22 @@
/* Evaluate a string as one or more shell commands.
/* evalstring.c - evaluate a string as one or more shell commands.
Copyright (C) 1996-2005 Free Software Foundation, Inc.
/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@ -44,6 +44,8 @@
#include "../redir.h"
#include "../trap.h"
#include <y.tab.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
@ -58,15 +60,21 @@ extern int errno;
extern int indirection_level, subshell_environment;
extern int line_number;
extern int current_token, shell_eof_token;
extern int last_command_exit_value;
extern int running_trap;
extern int loop_level;
extern int executing_list;
extern int comsub_ignore_return;
extern int posixly_correct;
int parse_and_execute_level = 0;
static int cat_file __P((REDIRECT *));
#define PE_TAG "parse_and_execute top"
#define PS_TAG "parse_string top"
#if defined (HISTORY)
static void
set_history_remembering ()
@ -84,7 +92,64 @@ parse_and_execute_cleanup ()
run_trap_cleanup (running_trap - 1);
unfreeze_jobs_list ();
}
run_unwind_frame ("parse_and_execute_top");
if (have_unwind_protects ())
run_unwind_frame (PE_TAG);
else
parse_and_execute_level = 0; /* XXX */
}
static void
parse_prologue (string, flags, tag)
char *string;
int flags;
char *tag;
{
char *orig_string;
int x;
orig_string = string;
/* Unwind protect this invocation of parse_and_execute (). */
begin_unwind_frame (tag);
unwind_protect_int (parse_and_execute_level);
unwind_protect_jmp_buf (top_level);
unwind_protect_int (indirection_level);
unwind_protect_int (line_number);
unwind_protect_int (loop_level);
unwind_protect_int (executing_list);
unwind_protect_int (comsub_ignore_return);
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
unwind_protect_int (interactive);
#if defined (HISTORY)
if (parse_and_execute_level == 0)
add_unwind_protect (set_history_remembering, (char *)NULL);
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
if (interactive_shell)
unwind_protect_int (history_expansion_inhibited);
# endif /* BANG_HISTORY */
#endif /* HISTORY */
if (interactive_shell)
{
x = get_current_prompt_level ();
add_unwind_protect (set_current_prompt_level, x);
}
add_unwind_protect (pop_stream, (char *)NULL);
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
add_unwind_protect (xfree, orig_string);
end_unwind_frame ();
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
#endif /* HISTORY */
}
/* Parse and execute the commands in STRING. Returns whatever
@ -104,50 +169,16 @@ parse_and_execute (string, from_file, flags)
const char *from_file;
int flags;
{
int code, x, lreset;
int code, lreset;
volatile int should_jump_to_top_level, last_result;
char *orig_string;
COMMAND *volatile command;
orig_string = string;
/* Unwind protect this invocation of parse_and_execute (). */
begin_unwind_frame ("parse_and_execute_top");
unwind_protect_int (parse_and_execute_level);
unwind_protect_jmp_buf (top_level);
unwind_protect_int (indirection_level);
unwind_protect_int (line_number);
unwind_protect_int (loop_level);
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
unwind_protect_int (interactive);
lreset = flags & SEVAL_RESETLINE;
#if defined (HISTORY)
if (parse_and_execute_level == 0)
add_unwind_protect (set_history_remembering, (char *)NULL);
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
if (interactive_shell)
{
unwind_protect_int (history_expansion_inhibited);
}
# endif /* BANG_HISTORY */
#endif /* HISTORY */
if (interactive_shell)
{
x = get_current_prompt_level ();
add_unwind_protect (set_current_prompt_level, x);
}
add_unwind_protect (pop_stream, (char *)NULL);
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
add_unwind_protect (xfree, orig_string);
end_unwind_frame ();
parse_prologue (string, flags, PE_TAG);
parse_and_execute_level++;
lreset = flags & SEVAL_RESETLINE;
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
@ -157,13 +188,6 @@ parse_and_execute (string, from_file, flags)
line_number--;
indirection_level++;
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
#endif /* HISTORY */
code = should_jump_to_top_level = 0;
last_result = EXECUTION_SUCCESS;
@ -224,7 +248,7 @@ parse_and_execute (string, from_file, flags)
if (parse_command () == 0)
{
if (interactive_shell == 0 && read_but_dont_execute)
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
{
last_result = EXECUTION_SUCCESS;
dispose_command (global_command);
@ -241,6 +265,12 @@ parse_and_execute (string, from_file, flags)
global_command = (COMMAND *)NULL;
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
{
command->flags |= CMD_IGNORE_RETURN;
itrace("parse_and_execute: turned on CMD_IGNORE_RETURN from comsub_ignore_return");
}
#if defined (ONESHOT)
/*
* IF
@ -305,7 +335,7 @@ parse_and_execute (string, from_file, flags)
out:
run_unwind_frame ("parse_and_execute_top");
run_unwind_frame (PE_TAG);
if (interrupt_state && parse_and_execute_level == 0)
{
@ -322,6 +352,110 @@ parse_and_execute (string, from_file, flags)
return (last_result);
}
/* Parse a command contained in STRING according to FLAGS and return the
number of characters consumed from the string. If non-NULL, set *ENDP
to the position in the string where the parse ended. Used to validate
command substitutions during parsing to obey Posix rules about finding
the end of the command and balancing parens. */
int
parse_string (string, from_file, flags, endp)
char *string;
const char *from_file;
int flags;
char **endp;
{
int code, nc;
volatile int should_jump_to_top_level;
COMMAND *volatile command, *oglobal;
char *ostring;
parse_prologue (string, flags, PS_TAG);
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (0);
code = should_jump_to_top_level = 0;
oglobal = global_command;
ostring = string;
with_input_from_string (string, from_file);
while (*(bash_input.location.string))
{
command = (COMMAND *)NULL;
#if 0
if (interrupt_state)
break;
#endif
/* Provide a location for functions which `longjmp (top_level)' to
jump to. */
code = setjmp (top_level);
if (code)
{
#if defined (DEBUG)
itrace("parse_string: longjmp executed: code = %d", code);
#endif
should_jump_to_top_level = 0;
switch (code)
{
case FORCE_EOF:
case ERREXIT:
case EXITPROG:
case DISCARD: /* XXX */
if (command)
dispose_command (command);
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
default:
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else
{
if ((flags & SEVAL_NOLONGJMP) == 0)
{
should_jump_to_top_level = 1;
code = DISCARD;
}
else
reset_parser (); /* XXX - sets token_to_read */
break;
}
if (current_token == yacc_EOF || current_token == shell_eof_token)
break;
}
out:
global_command = oglobal;
nc = bash_input.location.string - ostring;
if (endp)
*endp = bash_input.location.string;
run_unwind_frame (PS_TAG);
if (should_jump_to_top_level)
jump_to_top_level (code);
return (nc);
}
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */