#endif
#define NEED_FPURGE_DECL
+#define NEED_SH_SETLINEBUF_DECL
#include "bashansi.h"
#include "bashintl.h"
# include <mbstr.h> /* mbschr */
#endif
-#if defined (ARRAY_VARS)
-struct func_array_state
- {
- ARRAY *funcname_a;
- SHELL_VAR *funcname_v;
- ARRAY *source_a;
- SHELL_VAR *source_v;
- ARRAY *lineno_a;
- SHELL_VAR *lineno_v;
- };
-#endif
-
extern int dollar_dollar_pid;
extern int posixly_correct;
extern int expand_aliases;
if (paren_pid == 0)
{
/* We want to run the exit trap for forced {} subshells, and we
- want to note this before execute_in_subshell[B modifies the
+ want to note this before execute_in_subshell modifies the
COMMAND struct. Need to keep in mind that execute_in_subshell
runs the exit trap for () subshells itself. */
/* This handles { command; } & */
/* If this is a user subshell, set a flag if stdin was redirected.
This is used later to decide whether to redirect fd 0 to
/dev/null for async commands in the subshell. This adds more
- sh compatibility, but I'm not sure it's the right thing to do. */
+ sh compatibility, but I'm not sure it's the right thing to do.
+ Note that an input pipe to a compound command suffices to inhibit
+ the implicit /dev/null redirection for asynchronous commands
+ executed as part of that compound command. */
if (user_subshell)
{
- stdin_redir = stdin_redirects (command->redirects);
+ stdin_redir = stdin_redirects (command->redirects) || pipe_in != NO_PIPE;
#if 0
restore_default_signal (EXIT_TRAP); /* XXX - reset_signal_handlers above */
#endif
}
+ else if (shell_control_structure (command->type) && pipe_in != NO_PIPE)
+ stdin_redir = 1;
/* If this is an asynchronous command (command &), we want to
redirect the standard input from /dev/null in the absence of
for (wcmd = words; wcmd; wcmd = wcmd->next)
if ((wcmd->word->flags & W_ASSIGNMENT) == 0)
break;
+ /* Posix (post-2008) says that `command' doesn't change whether
+ or not the builtin it shadows is a `declaration command', even
+ though it removes other special builtin properties. In Posix
+ mode, we skip over one or more instances of `command' and
+ deal with the next word as the assignment builtin. */
+ while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
+ wcmd = wcmd->next;
for (w = wcmd; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
{
+ /* Lazy builtin lookup, only do it if we find an assignment */
if (b == 0)
{
- /* Posix (post-2008) says that `command' doesn't change whether
- or not the builtin it shadows is a `declaration command', even
- though it removes other special builtin properties. In Posix
- mode, we skip over one or more instances of `command' and
- deal with the next word as the assignment builtin. */
- while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
- wcmd = wcmd->next;
b = builtin_address_internal (wcmd->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
#endif
if (global)
w->word->flags |= W_ASSNGLOBAL;
+
+ /* If we have an assignment builtin that does not create local variables,
+ make sure we create global variables even if we internally call
+ `declare' */
+ if (b && ((b->flags & (ASSIGNMENT_BUILTIN|LOCALVAR_BUILTIN)) == ASSIGNMENT_BUILTIN))
+ w->word->flags |= W_ASSNGLOBAL;
}
#if defined (ARRAY_VARS)
/* Note that we saw an associative array option to a builtin that takes
{
if (b == 0)
{
- while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
- wcmd = wcmd->next;
b = builtin_address_internal (wcmd->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
if (fds_to_close)
close_fd_bitmap (fds_to_close);
+ /* If we fork because of an input pipe, note input pipe for later to
+ inhibit async commands from redirecting stdin from /dev/null */
+ stdin_redir |= pipe_in != NO_PIPE;
+
do_piping (pipe_in, pipe_out);
pipe_in = pipe_out = NO_PIPE;
#if defined (COPROCESS_SUPPORT)
words = make_word_list (make_word ("--"), words);
words = make_word_list (make_word ("cd"), words);
xtrace_print_word_list (words, 0);
+ func = find_function ("cd");
goto run_builtin;
}
WORD_LIST *words;
int flags, subshell;
{
- int old_e_flag, result, eval_unwind;
+ int result, eval_unwind, ignexit_flag, old_e_flag;
int isbltinenv;
char *error_trap;
error_trap = 0;
- old_e_flag = exit_immediately_on_error;
/* The eval builtin calls parse_and_execute, which does not know about
the setting of flags, and always calls the execution functions with
restore_default_signal (ERROR_TRAP);
}
exit_immediately_on_error = 0;
+ ignexit_flag = builtin_ignoring_errexit;
builtin_ignoring_errexit = 1;
eval_unwind = 1;
}
sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */
}
-
/* `return' does a longjmp() back to a saved environment in execute_function.
If a variable assignment list preceded the command, and the shell is
running in POSIX mode, we need to merge that into the shell_variables
if (eval_unwind)
{
- exit_immediately_on_error = errexit_flag;
- builtin_ignoring_errexit = 0;
+ builtin_ignoring_errexit = ignexit_flag;
+ exit_immediately_on_error = builtin_ignoring_errexit ? 0 : errexit_flag;
if (error_trap)
{
set_error_trap (error_trap);
}
#if defined (ARRAY_VARS)
-static void
+void
restore_funcarray_state (fa)
struct func_array_state *fa;
{
/* Update BASH_ARGV and BASH_ARGC */
if (debugging_mode)
- push_args (words->next);
+ {
+ push_args (words->next);
+ if (subshell == 0)
+ add_unwind_protect (pop_args, 0);
+ }
/* Number of the line on which the function body starts. */
line_number = function_line_number = tc->line;
stop_pipeline (async, (COMMAND *)NULL);
#endif
- loop_level = 0;
+ if (shell_compatibility_level > 43)
+ loop_level = 0;
fc = tc;
showing_function_line = 0;
}
- /* Restore BASH_ARGC and BASH_ARGV */
- if (debugging_mode)
- pop_args ();
-
/* If we have a local copy of OPTIND, note it in the saved getopts state. */
gv = find_variable ("OPTIND");
if (gv && gv->context == variable_context)
run_unwind_frame ("function_calling");
#if defined (ARRAY_VARS)
else
- restore_funcarray_state (fa);
+ {
+ restore_funcarray_state (fa);
+ /* Restore BASH_ARGC and BASH_ARGV */
+ if (debugging_mode)
+ pop_args ();
+ }
#endif
if (variable_context == 0 || this_shell_function == 0)
# define SETOSTYPE(x)
#endif
+#define HASH_BANG_BUFSIZ 128
+
#define READ_SAMPLE_BUF(file, buf, len) \
do \
{ \
fd = open(file, O_RDONLY); \
if (fd >= 0) \
{ \
- len = read (fd, buf, 80); \
+ len = read (fd, buf, HASH_BANG_BUFSIZ); \
close (fd); \
} \
else \
char **args, **env;
{
int larray, i, fd;
- char sample[80];
+ char sample[HASH_BANG_BUFSIZ];
int sample_len;
SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */