Imported from ../bash-2.05.tar.gz.
[platform/upstream/bash.git] / builtins / evalstring.c
index bf4a8a5..21e4772 100644 (file)
@@ -4,7 +4,7 @@
 
    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 1, or (at your option) any later
+   Software Foundation; either version 2, or (at your option) any later
    version.
 
    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
    
    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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
 #include <config.h>
 
 #if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
 #  include <unistd.h>
 #endif
 
 #include <stdio.h>
 #include <signal.h>
 
+#include <errno.h>
+
+#include "filecntl.h"
 #include "../bashansi.h"
 
 #include "../shell.h"
@@ -33,6 +39,7 @@
 #include "../flags.h"
 #include "../input.h"
 #include "../execute_cmd.h"
+#include "../redir.h"
 
 #if defined (HISTORY)
 #  include "../bashhist.h"
 
 #include "common.h"
 
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define IS_BUILTIN(s)  (builtin_address_internal(s, 0) != (struct builtin *)NULL)
+
 extern void run_trap_cleanup ();
+extern int zwrite ();
 
 extern int interactive, interactive_shell;
 extern int indirection_level, startup_state, subshell_environment;
 extern int line_number;
 extern int last_command_exit_value;
 extern int running_trap;
+extern int posixly_correct;
 extern COMMAND *global_command;
 
 int parse_and_execute_level = 0;
 
+static int cat_file ();
+
 /* How to force parse_and_execute () to clean up after itself. */
 void
 parse_and_execute_cleanup ()
@@ -78,7 +95,7 @@ parse_and_execute (string, from_file, flags)
      char *from_file;
      int flags;
 {
-  int code;
+  int code, x;
   volatile int should_jump_to_top_level, last_result;
   char *orig_string;
   COMMAND *volatile command;
@@ -103,6 +120,12 @@ parse_and_execute (string, from_file, flags)
 #  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)
     add_unwind_protect (xfree, orig_string);
@@ -152,7 +175,7 @@ parse_and_execute (string, from_file, flags)
 
            case DISCARD:
              run_unwind_frame ("pe_dispose");
-             last_command_exit_value = 1;      /* XXX */
+             last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
              if (subshell_environment)
                {
                  should_jump_to_top_level = 1;
@@ -160,12 +183,14 @@ parse_and_execute (string, from_file, flags)
                }
              else
                {
-                 dispose_command (command);    /* XXX */
+#if 0
+                 dispose_command (command);    /* pe_dispose does this */
+#endif
                  continue;
                }
 
            default:
-             programming_error ("parse_and_execute: bad jump: code %d", code);
+             command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
              break;
            }
        }
@@ -190,16 +215,44 @@ parse_and_execute (string, from_file, flags)
              global_command = (COMMAND *)NULL;
 
 #if defined (ONESHOT)
-             if (startup_state == 2 && *bash_input.location.string == '\0' &&
-                 command->type == cm_simple && !command->redirects &&
-                 !command->value.Simple->redirects)
+             /*
+              * IF
+              *   we were invoked as `bash -c' (startup_state == 2) AND
+              *   parse_and_execute has not been called recursively AND
+              *   we have parsed the full command (string == '\0') AND
+              *   we have a simple command without redirections AND
+              *   the command is not being timed
+              * THEN
+              *   tell the execution code that we don't need to fork
+              */
+             if (startup_state == 2 && parse_and_execute_level == 1 &&
+                 *bash_input.location.string == '\0' &&
+                 command->type == cm_simple &&
+                 !command->redirects && !command->value.Simple->redirects &&
+                 ((command->flags & CMD_TIME_PIPELINE) == 0))
                {
                  command->flags |= CMD_NO_FORK;
                  command->value.Simple->flags |= CMD_NO_FORK;
                }
 #endif /* ONESHOT */
 
-             last_result = execute_command_internal
+             /* See if this is a candidate for $( <file ). */
+             if (startup_state == 2 &&
+                 (subshell_environment & SUBSHELL_COMSUB) &&
+                 *bash_input.location.string == '\0' &&
+                 command->type == cm_simple && !command->redirects &&
+                 (command->flags & CMD_TIME_PIPELINE) == 0 &&
+                 command->value.Simple->words == 0 &&
+                 command->value.Simple->redirects &&
+                 command->value.Simple->redirects->next == 0 &&
+                 command->value.Simple->redirects->instruction == r_input_direction)
+               {
+                 int r;
+                 r = cat_file (command->value.Simple->redirects);
+                 last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
+               }
+             else
+               last_result = execute_command_internal
                                (command, 0, NO_PIPE, NO_PIPE, bitmap);
 
              dispose_command (command);
@@ -224,8 +277,8 @@ parse_and_execute (string, from_file, flags)
   if (interrupt_state && parse_and_execute_level == 0)
     {
       /* An interrupt during non-interactive execution in an
-         interactive shell (e.g. via $PROMPT_COMMAND) should
-         not cause the shell to exit. */
+        interactive shell (e.g. via $PROMPT_COMMAND) should
+        not cause the shell to exit. */
       interactive = interactive_shell;
       throw_to_top_level ();
     }
@@ -235,3 +288,61 @@ parse_and_execute (string, from_file, flags)
 
   return (last_result);
 }
+
+/* Handle a $( < file ) command substitution.  This expands the filename,
+   returning errors as appropriate, then just cats the file to the standard
+   output. */
+static int
+cat_file (r)
+     REDIRECT *r;
+{
+  char lbuf[128], *fn;
+  int nr, fd, rval;
+
+  if (r->instruction != r_input_direction)
+    return -1;
+
+  /* Get the filename. */
+  if (posixly_correct && !interactive_shell)
+    disallow_filename_globbing++;
+  fn = redirection_expand (r->redirectee.filename);
+  if (posixly_correct && !interactive_shell)
+    disallow_filename_globbing--;
+
+  if (fn == 0)
+    {
+      redirection_error (r, AMBIGUOUS_REDIRECT);
+      return -1;
+    }
+
+  fd = open(fn, O_RDONLY);
+  if (fd < 0)
+    {
+      file_error (fn);
+      free (fn);
+      return -1;
+    }
+
+  rval = 0;
+  while (1)
+    {
+      nr = zread (fd, lbuf, sizeof(lbuf));
+      if (nr == 0)
+       break;
+      else if (nr < 0)
+       {
+         rval = -1;
+         break;
+       }
+      if (zwrite (1, lbuf, nr) < 0)
+       {
+         rval = -1;
+         break;
+       }
+    }
+
+  free (fn);
+  close (fd);
+
+  return (0);  
+}