Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / builtins / evalstring.c
index 333a56e..ce5b4d6 100644 (file)
@@ -1,6 +1,6 @@
 /* evalstring.c - evaluate a string as one or more shell commands. */
 
-/* Copyright (C) 1996-2010 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2012 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -61,7 +61,7 @@ extern int errno;
 #define IS_BUILTIN(s)  (builtin_address_internal(s, 0) != (struct builtin *)NULL)
 
 extern int indirection_level, subshell_environment;
-extern int line_number;
+extern int line_number, line_number_for_err_trap;
 extern int current_token, shell_eof_token;
 extern int last_command_exit_value;
 extern int running_trap;
@@ -69,7 +69,9 @@ extern int loop_level;
 extern int executing_list;
 extern int comsub_ignore_return;
 extern int posixly_correct;
+extern int return_catch_flag, return_catch_value;
 extern sh_builtin_func_t *this_shell_builtin;
+extern char *the_printed_command_except_trap;
 
 int parse_and_execute_level = 0;
 
@@ -86,6 +88,14 @@ set_history_remembering ()
 }
 #endif
 
+static void
+restore_lastcom (x)
+     char *x;
+{
+  FREE (the_printed_command_except_trap);
+  the_printed_command_except_trap = x;
+}
+
 /* How to force parse_and_execute () to clean up after itself. */
 void
 parse_and_execute_cleanup ()
@@ -108,7 +118,7 @@ parse_prologue (string, flags, tag)
      int flags;
      char *tag;
 {
-  char *orig_string;
+  char *orig_string, *lastcom;
   int x;
 
   orig_string = string;
@@ -118,6 +128,7 @@ parse_prologue (string, flags, tag)
   unwind_protect_jmp_buf (top_level);
   unwind_protect_int (indirection_level);
   unwind_protect_int (line_number);
+  unwind_protect_int (line_number_for_err_trap);
   unwind_protect_int (loop_level);
   unwind_protect_int (executing_list);
   unwind_protect_int (comsub_ignore_return);
@@ -140,8 +151,17 @@ parse_prologue (string, flags, tag)
       x = get_current_prompt_level ();
       add_unwind_protect (set_current_prompt_level, x);
     }
-  
+
+  if (the_printed_command_except_trap)
+    {
+      lastcom = savestring (the_printed_command_except_trap);
+      add_unwind_protect (restore_lastcom, lastcom);
+    }
+
   add_unwind_protect (pop_stream, (char *)NULL);
+  if (parser_expanding_alias ())
+    add_unwind_protect (parser_restore_alias, (char *)NULL);
+
   if (orig_string && ((flags & SEVAL_NOFREE) == 0))
     add_unwind_protect (xfree, orig_string);
   end_unwind_frame ();
@@ -175,6 +195,7 @@ parse_and_execute (string, from_file, flags)
   int code, lreset;
   volatile int should_jump_to_top_level, last_result;
   COMMAND *volatile command;
+  volatile sigset_t pe_sigmask;
 
   parse_prologue (string, flags, PE_TAG);
 
@@ -182,11 +203,21 @@ parse_and_execute (string, from_file, flags)
 
   lreset = flags & SEVAL_RESETLINE;
 
+#if defined (HAVE_POSIX_SIGNALS)
+  /* If we longjmp and are going to go on, use this to restore signal mask */
+  sigemptyset (&pe_sigmask);
+  sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &pe_sigmask);
+#endif
+
   /* 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 (lreset);
+  if (parser_expanding_alias ())
+    /* push current shell_input_line */
+    parser_save_alias ();
+  
   if (lreset == 0)
     line_number--;
     
@@ -209,15 +240,28 @@ parse_and_execute (string, from_file, flags)
       /* Provide a location for functions which `longjmp (top_level)' to
         jump to.  This prevents errors in substitution from restarting
         the reader loop directly, for example. */
-      code = setjmp (top_level);
+      code = setjmp_nosigs (top_level);
 
       if (code)
        {
          should_jump_to_top_level = 0;
          switch (code)
            {
-           case FORCE_EOF:
            case ERREXIT:
+             /* variable_context -> 0 is what eval.c:reader_loop() does in
+                these circumstances.  Don't bother with cleanup here because
+                we don't want to run the function execution cleanup stuff
+                that will cause pop_context and other functions to run.
+                XXX - change that if we want the function context to be
+                unwound. */
+             if (exit_immediately_on_error && variable_context)
+               {
+                 discard_unwind_frame ("pe_dispose");
+                 variable_context = 0; /* not in a function */
+               }
+             should_jump_to_top_level = 1;
+             goto out;
+           case FORCE_EOF:           
            case EXITPROG:
              if (command)
                run_unwind_frame ("pe_dispose");
@@ -240,6 +284,9 @@ parse_and_execute (string, from_file, flags)
 #if 0
                  dispose_command (command);    /* pe_dispose does this */
 #endif
+#if defined (HAVE_POSIX_SIGNALS)
+                 sigprocmask (SIG_SETMASK, &pe_sigmask, (sigset_t *)NULL);
+#endif
                  continue;
                }
 
@@ -308,7 +355,8 @@ parse_and_execute (string, from_file, flags)
                  command->value.Simple->words == 0 &&
                  command->value.Simple->redirects &&
                  command->value.Simple->redirects->next == 0 &&
-                 command->value.Simple->redirects->instruction == r_input_direction)
+                 command->value.Simple->redirects->instruction == r_input_direction &&
+                 command->value.Simple->redirects->redirector.dest == 0)
                {
                  int r;
                  r = cat_file (command->value.Simple->redirects);
@@ -317,7 +365,6 @@ parse_and_execute (string, from_file, flags)
              else
                last_result = execute_command_internal
                                (command, 0, NO_PIPE, NO_PIPE, bitmap);
-
              dispose_command (command);
              dispose_fd_bitmap (bitmap);
              discard_unwind_frame ("pe_dispose");
@@ -377,15 +424,26 @@ parse_string (string, from_file, flags, endp)
   volatile int should_jump_to_top_level;
   COMMAND *volatile command, *oglobal;
   char *ostring;
+  volatile sigset_t ps_sigmask;
 
   parse_prologue (string, flags, PS_TAG);
 
+#if defined (HAVE_POSIX_SIGNALS)
+  /* If we longjmp and are going to go on, use this to restore signal mask */
+  sigemptyset (&ps_sigmask);
+  sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &ps_sigmask);
+#endif
+
+/* itrace("parse_string: `%s'", string); */
   /* 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);
-    
+  if (parser_expanding_alias ())
+    /* push current shell_input_line */
+    parser_save_alias ();
+
   code = should_jump_to_top_level = 0;
   oglobal = global_command;
   ostring = string;
@@ -402,7 +460,7 @@ parse_string (string, from_file, flags, endp)
 
       /* Provide a location for functions which `longjmp (top_level)' to
         jump to. */
-      code = setjmp (top_level);
+      code = setjmp_nosigs (top_level);
 
       if (code)
        {
@@ -424,6 +482,9 @@ itrace("parse_string: longjmp executed: code = %d", code);
              goto out;
 
            default:
+#if defined (HAVE_POSIX_SIGNALS)
+             sigprocmask (SIG_SETMASK, &ps_sigmask, (sigset_t *)NULL);
+#endif
              command_error ("parse_string", CMDERR_BADJUMP, code, 0);
              break;
            }
@@ -506,3 +567,49 @@ cat_file (r)
 
   return (rval);
 }
+
+int
+evalstring (string, from_file, flags)
+     char *string;
+     const char *from_file;
+     int flags;
+{
+  volatile int r, rflag, rcatch;
+
+  rcatch = 0;
+  rflag = return_catch_flag;
+  /* If we are in a place where `return' is valid, we have to catch
+     `eval "... return"' and make sure parse_and_execute cleans up. Then
+     we can trampoline to the previous saved return_catch location. */
+  if (rflag)
+    {
+      begin_unwind_frame ("evalstring");
+
+      unwind_protect_int (return_catch_flag);
+      unwind_protect_jmp_buf (return_catch);
+
+      return_catch_flag++;     /* increment so we have a counter */
+      rcatch = setjmp_nosigs (return_catch);
+    }
+
+  if (rcatch)
+    {
+      parse_and_execute_cleanup ();
+      r = return_catch_value;
+    }
+  else
+    /* Note that parse_and_execute () frees the string it is passed. */
+    r = parse_and_execute (string, from_file, flags);
+
+  if (rflag)
+    {
+      run_unwind_frame ("evalstring");
+      if (rcatch && return_catch_flag)
+       {
+         return_catch_value = r;
+         longjmp (return_catch, 1);
+       }
+    }
+    
+  return (r);
+}