]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - eval.c
Bash-5.0 patch 4: the wait builtin without arguments only waits for known children...
[thirdparty/bash.git] / eval.c
diff --git a/eval.c b/eval.c
index b9572b9299f012760493355650db6fb2b061f26a..f02d6e40e8812b7430b2b79179f20d31af8e5369 100644 (file)
--- a/eval.c
+++ b/eval.c
@@ -1,22 +1,22 @@
 /* eval.c -- reading and evaluating commands. */
 
-/* Copyright (C) 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2011 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.
+   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. */
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include "config.h"
 
 #include "bashansi.h"
 #include <stdio.h>
 
+#include <signal.h>
+
+#include "bashintl.h"
+
 #include "shell.h"
+#include "parser.h"
 #include "flags.h"
 #include "trap.h"
 
 #  include "bashhist.h"
 #endif
 
-extern int EOF_reached;
-extern int indirection_level;
-extern int posixly_correct;
-extern int subshell_environment, running_under_emacs;
-extern int last_command_exit_value, stdin_redir;
-extern int need_here_doc;
-extern int current_command_number, current_command_line_count, line_number;
-extern int expand_aliases;
+#if defined (HAVE_POSIX_SIGNALS)
+extern sigset_t top_level_mask;
+#endif
+
+static void send_pwd_to_eterm __P((void));
+static sighandler alrm_catcher __P((int));
 
 /* Read and execute commands until EOF is reached.  This assumes that
    the input source has already been initialized. */
@@ -58,23 +61,30 @@ int
 reader_loop ()
 {
   int our_indirection_level;
-  COMMAND *current_command = (COMMAND *)NULL;
+  COMMAND * volatile current_command;
 
   USE_VAR(current_command);
 
+  current_command = (COMMAND *)NULL;
+
   our_indirection_level = ++indirection_level;
 
+  if (just_one_command)
+    reset_readahead_token ();
+
   while (EOF_Reached == 0)
     {
       int code;
 
-      code = setjmp (top_level);
+      code = setjmp_nosigs (top_level);
 
 #if defined (PROCESS_SUBSTITUTION)
       unlink_fifo_list ();
 #endif /* PROCESS_SUBSTITUTION */
 
-      if (interactive_shell && signal_is_ignored (SIGINT) == 0)
+      /* XXX - why do we set this every time through the loop?  And why do
+        it if SIGINT is trapped in an interactive shell? */
+      if (interactive_shell && signal_is_ignored (SIGINT) == 0 && signal_is_trapped (SIGINT) == 0)
        set_signal_handler (SIGINT, sigint_sighandler);
 
       if (code != NOT_JUMPED)
@@ -83,8 +93,9 @@ reader_loop ()
 
          switch (code)
            {
-             /* Some kind of throw to top_level has occured. */
+             /* Some kind of throw to top_level has occurred. */
            case FORCE_EOF:
+           case ERREXIT:
            case EXITPROG:
              current_command = (COMMAND *)NULL;
              if (exit_immediately_on_error)
@@ -93,7 +104,11 @@ reader_loop ()
              goto exec_done;
 
            case DISCARD:
-             last_command_exit_value = 1;
+             /* Make sure the exit status is reset to a non-zero value, but
+                leave existing non-zero values (e.g., > 128 on signal)
+                alone. */
+             if (last_command_exit_value == 0)
+               last_command_exit_value = EXECUTION_FAILURE;
              if (subshell_environment)
                {
                  current_command = (COMMAND *)NULL;
@@ -106,6 +121,9 @@ reader_loop ()
                  dispose_command (current_command);
                  current_command = (COMMAND *)NULL;
                }
+#if defined (HAVE_POSIX_SIGNALS)
+             sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
+#endif
              break;
 
            default:
@@ -114,7 +132,8 @@ reader_loop ()
        }
 
       executing = 0;
-      dispose_used_env_vars ();
+      if (temporary_env)
+       dispose_used_env_vars ();
 
 #if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA)
       /* Attempt to reclaim memory allocated with alloca (). */
@@ -132,20 +151,37 @@ reader_loop ()
          else if (current_command = global_command)
            {
              global_command = (COMMAND *)NULL;
+
+             /* If the shell is interactive, expand and display $PS0 after reading a
+                command (possibly a list or pipeline) and before executing it. */
+             if (interactive && ps0_prompt)
+               {
+                 char *ps0_string;
+
+                 ps0_string = decode_prompt_string (ps0_prompt);
+                 if (ps0_string && *ps0_string)
+                   {
+                     fprintf (stderr, "%s", ps0_string);
+                     fflush (stderr);
+                   }
+                 free (ps0_string);
+               }
+
              current_command_number++;
 
              executing = 1;
              stdin_redir = 0;
+
              execute_command (current_command);
 
            exec_done:
+             QUIT;
+
              if (current_command)
                {
                  dispose_command (current_command);
                  current_command = (COMMAND *)NULL;
                }
-
-             QUIT;
            }
        }
       else
@@ -161,11 +197,54 @@ reader_loop ()
   return (last_command_exit_value);
 }
 
+/* Pretty print shell scripts */
+int
+pretty_print_loop ()
+{
+  COMMAND *current_command;
+  char *command_to_print;
+  int code;
+  int global_posix_mode, last_was_newline;
+
+  global_posix_mode = posixly_correct;
+  last_was_newline = 0;
+  while (EOF_Reached == 0)
+    {
+      code = setjmp_nosigs (top_level);
+      if (code)
+        return (EXECUTION_FAILURE);
+      if (read_command() == 0)
+       {
+         current_command = global_command;
+         global_command = 0;
+         posixly_correct = 1;                  /* print posix-conformant */
+         if (current_command && (command_to_print = make_command_string (current_command)))
+           {
+             printf ("%s\n", command_to_print);        /* for now */
+             last_was_newline = 0;
+           }
+         else if (last_was_newline == 0)
+           {
+              printf ("\n");
+              last_was_newline = 1;
+           }
+         posixly_correct = global_posix_mode;
+         dispose_command (current_command);
+       }
+      else
+       return (EXECUTION_FAILURE);
+    }
+    
+  return (EXECUTION_SUCCESS);
+}
+
 static sighandler
 alrm_catcher(i)
      int i;
 {
-  printf ("\007timed out waiting for input: auto-logout\n");
+  printf (_("\007timed out waiting for input: auto-logout\n"));
+  fflush (stdout);
+  bash_logout ();      /* run ~/.bash_logout if this is a login shell */
   jump_to_top_level (EXITPROG);
   SIGRETURN (0);
 }
@@ -175,14 +254,25 @@ alrm_catcher(i)
 static void
 send_pwd_to_eterm ()
 {
-  char *pwd;
+  char *pwd, *f;
 
+  f = 0;
   pwd = get_string_value ("PWD");
   if (pwd == 0)
-    pwd = get_working_directory ("eterm");
+    f = pwd = get_working_directory ("eterm");
   fprintf (stderr, "\032/%s\n", pwd);
+  free (f);
 }
 
+static void
+execute_prompt_command ()
+{
+  char *command_to_execute;
+
+  command_to_execute = get_string_value ("PROMPT_COMMAND");
+  if (command_to_execute)
+    execute_variable_command (command_to_execute, "PROMPT_COMMAND");
+}
 /* Call the YACC-generated parser and return the status of the parse.
    Input is read from the current input stream (bash_input).  yyparse
    leaves the parsed command in the global variable GLOBAL_COMMAND.
@@ -191,7 +281,6 @@ int
 parse_command ()
 {
   int r;
-  char *command_to_execute;
 
   need_here_doc = 0;
   run_pending_traps ();
@@ -199,11 +288,12 @@ parse_command ()
   /* Allow the execution of a random command just before the printing
      of each primary prompt.  If the shell variable PROMPT_COMMAND
      is set then the value of it is the command to execute. */
-  if (interactive && bash_input.type != st_string)
+  /* The tests are a combination of SHOULD_PROMPT() and prompt_again() 
+     from parse.y, which are the conditions under which the prompt is
+     actually printed. */
+  if (interactive && bash_input.type != st_string && parser_expanding_alias() == 0)
     {
-      command_to_execute = get_string_value ("PROMPT_COMMAND");
-      if (command_to_execute)
-       execute_prompt_command (command_to_execute);
+      execute_prompt_command ();
 
       if (running_under_emacs == 2)
        send_pwd_to_eterm ();   /* Yuck */
@@ -240,9 +330,9 @@ read_command ()
     {
       tmout_var = find_variable ("TMOUT");
 
-      if (tmout_var && tmout_var->value)
+      if (tmout_var && var_isset (tmout_var))
        {
-         tmout_len = atoi (tmout_var->value);
+         tmout_len = atoi (value_cell (tmout_var));
          if (tmout_len > 0)
            {
              old_alrm = set_signal_handler (SIGALRM, alrm_catcher);