281 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* eval.c -- reading and evaluating commands. */
 | |
| 
 | |
| /* 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 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.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #if defined (HAVE_UNISTD_H)
 | |
| #  ifdef _MINIX
 | |
| #    include <sys/types.h>
 | |
| #  endif
 | |
| #  include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include "bashansi.h"
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include "bashintl.h"
 | |
| 
 | |
| #include "shell.h"
 | |
| #include "flags.h"
 | |
| #include "trap.h"
 | |
| 
 | |
| #include "builtins/common.h"
 | |
| 
 | |
| #include "input.h"
 | |
| #include "execute_cmd.h"
 | |
| 
 | |
| #if defined (HISTORY)
 | |
| #  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;
 | |
| 
 | |
| 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. */
 | |
| int
 | |
| reader_loop ()
 | |
| {
 | |
|   int our_indirection_level;
 | |
|   COMMAND * volatile current_command;
 | |
| 
 | |
|   USE_VAR(current_command);
 | |
| 
 | |
|   current_command = (COMMAND *)NULL;
 | |
| 
 | |
|   our_indirection_level = ++indirection_level;
 | |
| 
 | |
|   while (EOF_Reached == 0)
 | |
|     {
 | |
|       int code;
 | |
| 
 | |
|       code = setjmp (top_level);
 | |
| 
 | |
| #if defined (PROCESS_SUBSTITUTION)
 | |
|       unlink_fifo_list ();
 | |
| #endif /* PROCESS_SUBSTITUTION */
 | |
| 
 | |
|       if (interactive_shell && signal_is_ignored (SIGINT) == 0)
 | |
| 	set_signal_handler (SIGINT, sigint_sighandler);
 | |
| 
 | |
|       if (code != NOT_JUMPED)
 | |
| 	{
 | |
| 	  indirection_level = our_indirection_level;
 | |
| 
 | |
| 	  switch (code)
 | |
| 	    {
 | |
| 	      /* Some kind of throw to top_level has occured. */
 | |
| 	    case FORCE_EOF:
 | |
| 	    case ERREXIT:
 | |
| 	    case EXITPROG:
 | |
| 	      current_command = (COMMAND *)NULL;
 | |
| 	      if (exit_immediately_on_error)
 | |
| 		variable_context = 0;	/* not in a function */
 | |
| 	      EOF_Reached = EOF;
 | |
| 	      goto exec_done;
 | |
| 
 | |
| 	    case DISCARD:
 | |
| 	      /* 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;
 | |
| 		  EOF_Reached = EOF;
 | |
| 		  goto exec_done;
 | |
| 		}
 | |
| 	      /* Obstack free command elements, etc. */
 | |
| 	      if (current_command)
 | |
| 		{
 | |
| 		  dispose_command (current_command);
 | |
| 		  current_command = (COMMAND *)NULL;
 | |
| 		}
 | |
| 	      break;
 | |
| 
 | |
| 	    default:
 | |
| 	      command_error ("reader_loop", CMDERR_BADJUMP, code, 0);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|       executing = 0;
 | |
|       if (temporary_env)
 | |
| 	dispose_used_env_vars ();
 | |
| 
 | |
| #if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA)
 | |
|       /* Attempt to reclaim memory allocated with alloca (). */
 | |
|       (void) alloca (0);
 | |
| #endif
 | |
| 
 | |
|       if (read_command () == 0)
 | |
| 	{
 | |
| 	  if (interactive_shell == 0 && read_but_dont_execute)
 | |
| 	    {
 | |
| 	      last_command_exit_value = EXECUTION_SUCCESS;
 | |
| 	      dispose_command (global_command);
 | |
| 	      global_command = (COMMAND *)NULL;
 | |
| 	    }
 | |
| 	  else if (current_command = global_command)
 | |
| 	    {
 | |
| 	      global_command = (COMMAND *)NULL;
 | |
| 	      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;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* Parse error, maybe discard rest of stream if not interactive. */
 | |
| 	  if (interactive == 0)
 | |
| 	    EOF_Reached = EOF;
 | |
| 	}
 | |
|       if (just_one_command)
 | |
| 	EOF_Reached = EOF;
 | |
|     }
 | |
|   indirection_level--;
 | |
|   return (last_command_exit_value);
 | |
| }
 | |
| 
 | |
| static sighandler
 | |
| alrm_catcher(i)
 | |
|      int i;
 | |
| {
 | |
|   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);
 | |
| }
 | |
| 
 | |
| /* Send an escape sequence to emacs term mode to tell it the
 | |
|    current working directory. */
 | |
| static void
 | |
| send_pwd_to_eterm ()
 | |
| {
 | |
|   char *pwd;
 | |
| 
 | |
|   pwd = get_string_value ("PWD");
 | |
|   if (pwd == 0)
 | |
|     pwd = get_working_directory ("eterm");
 | |
|   fprintf (stderr, "\032/%s\n", pwd);
 | |
| }
 | |
| 
 | |
| /* 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.
 | |
|    This is where PROMPT_COMMAND is executed. */
 | |
| int
 | |
| parse_command ()
 | |
| {
 | |
|   int r;
 | |
|   char *command_to_execute;
 | |
| 
 | |
|   need_here_doc = 0;
 | |
|   run_pending_traps ();
 | |
| 
 | |
|   /* 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)
 | |
|     {
 | |
|       command_to_execute = get_string_value ("PROMPT_COMMAND");
 | |
|       if (command_to_execute)
 | |
| 	execute_variable_command (command_to_execute, "PROMPT_COMMAND");
 | |
| 
 | |
|       if (running_under_emacs == 2)
 | |
| 	send_pwd_to_eterm ();	/* Yuck */
 | |
|     }
 | |
| 
 | |
|   current_command_line_count = 0;
 | |
|   r = yyparse ();
 | |
| 
 | |
|   if (need_here_doc)
 | |
|     gather_here_documents ();
 | |
| 
 | |
|   return (r);
 | |
| }
 | |
| 
 | |
| /* Read and parse a command, returning the status of the parse.  The command
 | |
|    is left in the globval variable GLOBAL_COMMAND for use by reader_loop.
 | |
|    This is where the shell timeout code is executed. */
 | |
| int
 | |
| read_command ()
 | |
| {
 | |
|   SHELL_VAR *tmout_var;
 | |
|   int tmout_len, result;
 | |
|   SigHandler *old_alrm;
 | |
| 
 | |
|   set_current_prompt_level (1);
 | |
|   global_command = (COMMAND *)NULL;
 | |
| 
 | |
|   /* Only do timeouts if interactive. */
 | |
|   tmout_var = (SHELL_VAR *)NULL;
 | |
|   tmout_len = 0;
 | |
|   old_alrm = (SigHandler *)NULL;
 | |
| 
 | |
|   if (interactive)
 | |
|     {
 | |
|       tmout_var = find_variable ("TMOUT");
 | |
| 
 | |
|       if (tmout_var && var_isset (tmout_var))
 | |
| 	{
 | |
| 	  tmout_len = atoi (value_cell (tmout_var));
 | |
| 	  if (tmout_len > 0)
 | |
| 	    {
 | |
| 	      old_alrm = set_signal_handler (SIGALRM, alrm_catcher);
 | |
| 	      alarm (tmout_len);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   QUIT;
 | |
| 
 | |
|   current_command_line_count = 0;
 | |
|   result = parse_command ();
 | |
| 
 | |
|   if (interactive && tmout_var && (tmout_len > 0))
 | |
|     {
 | |
|       alarm(0);
 | |
|       set_signal_handler (SIGALRM, old_alrm);
 | |
|     }
 | |
| 
 | |
|   return (result);
 | |
| }
 | 
