LCOV - code coverage report
Current view: top level - bash-4.4.23 - parse.y (source / functions) Hit Total Coverage
Test: cov-sh.info Lines: 1463 2308 63.4 %
Date: 2020-10-29 14:49:55 Functions: 51 74 68.9 %

          Line data    Source code
       1             : /* parse.y - Yacc grammar for bash. */
       2             : 
       3             : /* Copyright (C) 1989-2015 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of GNU Bash, the Bourne Again SHell.
       6             : 
       7             :    Bash is free software: you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation, either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    Bash is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : %{
      22             : #include "config.h"
      23             : 
      24             : #include "bashtypes.h"
      25             : #include "bashansi.h"
      26             : 
      27             : #include "filecntl.h"
      28             : 
      29             : #if defined (HAVE_UNISTD_H)
      30             : #  include <unistd.h>
      31             : #endif
      32             : 
      33             : #if defined (HAVE_LOCALE_H)
      34             : #  include <locale.h>
      35             : #endif
      36             : 
      37             : #include <stdio.h>
      38             : #include "chartypes.h"
      39             : #include <signal.h>
      40             : 
      41             : #include "memalloc.h"
      42             : 
      43             : #include "bashintl.h"
      44             : 
      45             : #define NEED_STRFTIME_DECL      /* used in externs.h */
      46             : 
      47             : #include "shell.h"
      48             : #include "typemax.h"          /* SIZE_MAX if needed */
      49             : #include "trap.h"
      50             : #include "flags.h"
      51             : #include "parser.h"
      52             : #include "mailcheck.h"
      53             : #include "test.h"
      54             : #include "builtins.h"
      55             : #include "builtins/common.h"
      56             : #include "builtins/builtext.h"
      57             : 
      58             : #include "shmbutil.h"
      59             : 
      60             : #if defined (READLINE)
      61             : #  include "bashline.h"
      62             : #  include <readline/readline.h>
      63             : #endif /* READLINE */
      64             : 
      65             : #if defined (HISTORY)
      66             : #  include "bashhist.h"
      67             : #  include <readline/history.h>
      68             : #endif /* HISTORY */
      69             : 
      70             : #if defined (JOB_CONTROL)
      71             : #  include "jobs.h"
      72             : #else
      73             : extern int cleanup_dead_jobs __P((void));
      74             : #endif /* JOB_CONTROL */
      75             : 
      76             : #if defined (ALIAS)
      77             : #  include "alias.h"
      78             : #else
      79             : typedef void *alias_t;
      80             : #endif /* ALIAS */
      81             : 
      82             : #if defined (PROMPT_STRING_DECODE)
      83             : #  ifndef _MINIX
      84             : #    include <sys/param.h>
      85             : #  endif
      86             : #  include <time.h>
      87             : #  if defined (TM_IN_SYS_TIME)
      88             : #    include <sys/types.h>
      89             : #    include <sys/time.h>
      90             : #  endif /* TM_IN_SYS_TIME */
      91             : #  include "maxpath.h"
      92             : #endif /* PROMPT_STRING_DECODE */
      93             : 
      94             : #define RE_READ_TOKEN   -99
      95             : #define NO_EXPANSION    -100
      96             : 
      97             : #ifdef DEBUG
      98             : #  define YYDEBUG 1
      99             : #else
     100             : #  define YYDEBUG 0
     101             : #endif
     102             : 
     103             : #if defined (HANDLE_MULTIBYTE)
     104             : #  define last_shell_getc_is_singlebyte \
     105             :         ((shell_input_line_index > 1) \
     106             :                 ? shell_input_line_property[shell_input_line_index - 1] \
     107             :                 : 1)
     108             : #  define MBTEST(x)     ((x) && last_shell_getc_is_singlebyte)
     109             : #else
     110             : #  define last_shell_getc_is_singlebyte 1
     111             : #  define MBTEST(x)     ((x))
     112             : #endif
     113             : 
     114             : #if defined (EXTENDED_GLOB)
     115             : extern int extended_glob;
     116             : #endif
     117             : 
     118             : extern int eof_encountered;
     119             : extern int no_line_editing, running_under_emacs;
     120             : extern int current_command_number;
     121             : extern int sourcelevel, parse_and_execute_level;
     122             : extern int posixly_correct;
     123             : extern int last_command_exit_value;
     124             : extern pid_t last_command_subst_pid;
     125             : extern char *shell_name, *current_host_name;
     126             : extern char *dist_version;
     127             : extern int patch_level;
     128             : extern int dump_translatable_strings, dump_po_strings;
     129             : extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
     130             : extern int here_doc_first_line;
     131             : #if defined (BUFFERED_INPUT)
     132             : extern int bash_input_fd_changed;
     133             : #endif
     134             : 
     135             : extern int errno;
     136             : /* **************************************************************** */
     137             : /*                                                                  */
     138             : /*                  "Forward" declarations                        */
     139             : /*                                                                  */
     140             : /* **************************************************************** */
     141             : 
     142             : #ifdef DEBUG
     143             : static void debug_parser __P((int));
     144             : #endif
     145             : 
     146             : static int yy_getc __P((void));
     147             : static int yy_ungetc __P((int));
     148             : 
     149             : #if defined (READLINE)
     150             : static int yy_readline_get __P((void));
     151             : static int yy_readline_unget __P((int));
     152             : #endif
     153             : 
     154             : static int yy_string_get __P((void));
     155             : static int yy_string_unget __P((int));
     156             : static void rewind_input_string __P((void));
     157             : static int yy_stream_get __P((void));
     158             : static int yy_stream_unget __P((int));
     159             : 
     160             : static int shell_getc __P((int));
     161             : static void shell_ungetc __P((int));
     162             : static void discard_until __P((int));
     163             : 
     164             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
     165             : static void push_string __P((char *, int, alias_t *));
     166             : static void pop_string __P((void));
     167             : static void free_string_list __P((void));
     168             : #endif
     169             : 
     170             : static char *read_a_line __P((int));
     171             : 
     172             : static int reserved_word_acceptable __P((int));
     173             : static int yylex __P((void));
     174             : 
     175             : static void push_heredoc __P((REDIRECT *));
     176             : static char *mk_alexpansion __P((char *));
     177             : static int alias_expand_token __P((char *));
     178             : static int time_command_acceptable __P((void));
     179             : static int special_case_tokens __P((char *));
     180             : static int read_token __P((int));
     181             : static char *parse_matched_pair __P((int, int, int, int *, int));
     182             : static char *parse_comsub __P((int, int, int, int *, int));
     183             : #if defined (ARRAY_VARS)
     184             : static char *parse_compound_assignment __P((int *));
     185             : #endif
     186             : #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
     187             : static int parse_dparen __P((int));
     188             : static int parse_arith_cmd __P((char **, int));
     189             : #endif
     190             : #if defined (COND_COMMAND)
     191             : static void cond_error __P((void));
     192             : static COND_COM *cond_expr __P((void));
     193             : static COND_COM *cond_or __P((void));
     194             : static COND_COM *cond_and __P((void));
     195             : static COND_COM *cond_term __P((void));
     196             : static int cond_skip_newlines __P((void));
     197             : static COMMAND *parse_cond_command __P((void));
     198             : #endif
     199             : #if defined (ARRAY_VARS)
     200             : static int token_is_assignment __P((char *, int));
     201             : static int token_is_ident __P((char *, int));
     202             : #endif
     203             : static int read_token_word __P((int));
     204             : #if 0
     205             : static void discard_parser_constructs __P((int));
     206             : #endif
     207             : 
     208             : static char *error_token_from_token __P((int));
     209             : static char *error_token_from_text __P((void));
     210             : static void print_offending_line __P((void));
     211             : static void report_syntax_error __P((char *));
     212             : 
     213             : static void handle_eof_input_unit __P((void));
     214             : static void prompt_again __P((void));
     215             : #if 0
     216             : static void reset_readline_prompt __P((void));
     217             : #endif
     218             : static void print_prompt __P((void));
     219             : 
     220             : #if defined (HANDLE_MULTIBYTE)
     221             : static void set_line_mbstate __P((void));
     222             : static char *shell_input_line_property = NULL;
     223             : #else
     224             : #  define set_line_mbstate()
     225             : #endif
     226             : 
     227             : extern int yyerror __P((const char *));
     228             : 
     229             : #ifdef DEBUG
     230             : extern int yydebug;
     231             : #endif
     232             : 
     233             : /* Default prompt strings */
     234             : char *primary_prompt = PPROMPT;
     235             : char *secondary_prompt = SPROMPT;
     236             : 
     237             : /* PROMPT_STRING_POINTER points to one of these, never to an actual string. */
     238             : char *ps1_prompt, *ps2_prompt;
     239             : 
     240             : /* Displayed after reading a command but before executing it in an interactive shell */
     241             : char *ps0_prompt;
     242             : 
     243             : /* Handle on the current prompt string.  Indirectly points through
     244             :    ps1_ or ps2_prompt. */
     245             : char **prompt_string_pointer = (char **)NULL;
     246             : char *current_prompt_string;
     247             : 
     248             : /* Non-zero means we expand aliases in commands. */
     249             : int expand_aliases = 0;
     250             : 
     251             : /* If non-zero, the decoded prompt string undergoes parameter and
     252             :    variable substitution, command substitution, arithmetic substitution,
     253             :    string expansion, process substitution, and quote removal in
     254             :    decode_prompt_string. */
     255             : int promptvars = 1;
     256             : 
     257             : /* If non-zero, $'...' and $"..." are expanded when they appear within
     258             :    a ${...} expansion, even when the expansion appears within double
     259             :    quotes. */
     260             : int extended_quote = 1;
     261             : 
     262             : /* The number of lines read from input while creating the current command. */
     263             : int current_command_line_count;
     264             : 
     265             : /* The number of lines in a command saved while we run parse_and_execute */
     266             : int saved_command_line_count;
     267             : 
     268             : /* The token that currently denotes the end of parse. */
     269             : int shell_eof_token;
     270             : 
     271             : /* The token currently being read. */
     272             : int current_token;
     273             : 
     274             : /* The current parser state. */
     275             : int parser_state;
     276             : 
     277             : /* Variables to manage the task of reading here documents, because we need to
     278             :    defer the reading until after a complete command has been collected. */
     279             : static REDIRECT *redir_stack[HEREDOC_MAX];
     280             : int need_here_doc;
     281             : 
     282             : /* Where shell input comes from.  History expansion is performed on each
     283             :    line when the shell is interactive. */
     284             : static char *shell_input_line = (char *)NULL;
     285             : static size_t shell_input_line_index;
     286             : static size_t shell_input_line_size;    /* Amount allocated for shell_input_line. */
     287             : static size_t shell_input_line_len;     /* strlen (shell_input_line) */
     288             : 
     289             : /* Either zero or EOF. */
     290             : static int shell_input_line_terminator;
     291             : 
     292             : /* The line number in a script on which a function definition starts. */
     293             : static int function_dstart;
     294             : 
     295             : /* The line number in a script on which a function body starts. */
     296             : static int function_bstart;
     297             : 
     298             : /* The line number in a script at which an arithmetic for command starts. */
     299             : static int arith_for_lineno;
     300             : 
     301             : /* The decoded prompt string.  Used if READLINE is not defined or if
     302             :    editing is turned off.  Analogous to current_readline_prompt. */
     303             : static char *current_decoded_prompt;
     304             : 
     305             : /* The last read token, or NULL.  read_token () uses this for context
     306             :    checking. */
     307             : static int last_read_token;
     308             : 
     309             : /* The token read prior to last_read_token. */
     310             : static int token_before_that;
     311             : 
     312             : /* The token read prior to token_before_that. */
     313             : static int two_tokens_ago;
     314             : 
     315             : static int global_extglob;
     316             : 
     317             : /* The line number in a script where the word in a `case WORD', `select WORD'
     318             :    or `for WORD' begins.  This is a nested command maximum, since the array
     319             :    index is decremented after a case, select, or for command is parsed. */
     320             : #define MAX_CASE_NEST   128
     321             : static int word_lineno[MAX_CASE_NEST+1];
     322             : static int word_top = -1;
     323             : 
     324             : /* If non-zero, it is the token that we want read_token to return
     325             :    regardless of what text is (or isn't) present to be read.  This
     326             :    is reset by read_token.  If token_to_read == WORD or
     327             :    ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */
     328             : static int token_to_read;
     329             : static WORD_DESC *word_desc_to_read;
     330             : 
     331             : static REDIRECTEE source;
     332             : static REDIRECTEE redir;
     333             : %}
     334             : 
     335             : %union {
     336             :   WORD_DESC *word;              /* the word that we read. */
     337             :   int number;                   /* the number that we read. */
     338             :   WORD_LIST *word_list;
     339             :   COMMAND *command;
     340             :   REDIRECT *redirect;
     341             :   ELEMENT element;
     342             :   PATTERN_LIST *pattern;
     343             : }
     344             : 
     345             : /* Reserved words.  Members of the first group are only recognized
     346             :    in the case that they are preceded by a list_terminator.  Members
     347             :    of the second group are for [[...]] commands.  Members of the
     348             :    third group are recognized only under special circumstances. */
     349             : %token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION COPROC
     350             : %token COND_START COND_END COND_ERROR
     351             : %token IN BANG TIME TIMEOPT TIMEIGN
     352             : 
     353             : /* More general tokens. yylex () knows how to make these. */
     354             : %token <word> WORD ASSIGNMENT_WORD REDIR_WORD
     355             : %token <number> NUMBER
     356             : %token <word_list> ARITH_CMD ARITH_FOR_EXPRS
     357             : %token <command> COND_CMD
     358             : %token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS
     359             : %token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
     360             : %token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
     361             : %token GREATER_BAR BAR_AND
     362             : 
     363             : /* The types that the various syntactical units return. */
     364             : 
     365             : %type <command> inputunit command pipeline pipeline_command
     366             : %type <command> list list0 list1 compound_list simple_list simple_list1
     367             : %type <command> simple_command shell_command
     368             : %type <command> for_command select_command case_command group_command
     369             : %type <command> arith_command
     370             : %type <command> cond_command
     371             : %type <command> arith_for_command
     372             : %type <command> coproc
     373             : %type <command> function_def function_body if_command elif_clause subshell
     374             : %type <redirect> redirection redirection_list
     375             : %type <element> simple_command_element
     376             : %type <word_list> word_list pattern
     377             : %type <pattern> pattern_list case_clause_sequence case_clause
     378             : %type <number> timespec
     379             : %type <number> list_terminator
     380             : 
     381             : %start inputunit
     382             : 
     383             : %left '&' ';' '\n' yacc_EOF
     384             : %left AND_AND OR_OR
     385             : %right '|' BAR_AND
     386             : %%
     387             : 
     388             : inputunit:      simple_list simple_list_terminator
     389             :                         {
     390             :                           /* Case of regular command.  Discard the error
     391             :                              safety net,and return the command just parsed. */
     392    89378664 :                           global_command = $1;
     393    89378664 :                           eof_encountered = 0;
     394             :                           /* discard_parser_constructs (0); */
     395    89378664 :                           if (parser_state & PST_CMDSUBST)
     396          27 :                             parser_state |= PST_EOFTOKEN;
     397    89378664 :                           YYACCEPT;
     398             :                         }
     399             :         |       '\n'
     400             :                         {
     401             :                           /* Case of regular command, but not a very
     402             :                              interesting one.  Return a NULL command. */
     403   202028703 :                           global_command = (COMMAND *)NULL;
     404   202028703 :                           if (parser_state & PST_CMDSUBST)
     405           0 :                             parser_state |= PST_EOFTOKEN;
     406   202028703 :                           YYACCEPT;
     407             :                         }
     408             :         |       error '\n'
     409             :                         {
     410             :                           /* Error during parsing.  Return NULL command. */
     411     1914028 :                           global_command = (COMMAND *)NULL;
     412     1914028 :                           eof_encountered = 0;
     413             :                           /* discard_parser_constructs (1); */
     414     1914028 :                           if (interactive && parse_and_execute_level == 0)
     415             :                             {
     416             :                               YYACCEPT;
     417             :                             }
     418             :                           else
     419             :                             {
     420             :                               YYABORT;
     421             :                             }
     422             :                         }
     423             :         |       yacc_EOF
     424             :                         {
     425             :                           /* Case of EOF seen by itself.  Do ignoreeof or
     426             :                              not. */
     427      110845 :                           global_command = (COMMAND *)NULL;
     428      110845 :                           handle_eof_input_unit ();
     429      110845 :                           YYACCEPT;
     430             :                         }
     431             :         ;
     432             : 
     433             : word_list:      WORD
     434     9542969 :                         { $$ = make_word_list ($1, (WORD_LIST *)NULL); }
     435             :         |       word_list WORD
     436           0 :                         { $$ = make_word_list ($2, $1); }
     437             :         ;
     438             : 
     439             : redirection:    '>' WORD
     440             :                         {
     441     6011052 :                           source.dest = 1;
     442     6011052 :                           redir.filename = $2;
     443     6011052 :                           $$ = make_redirection (source, r_output_direction, redir, 0);
     444             :                         }
     445             :         |       '<' WORD
     446             :                         {
     447     3786649 :                           source.dest = 0;
     448     3786649 :                           redir.filename = $2;
     449     3786649 :                           $$ = make_redirection (source, r_input_direction, redir, 0);
     450             :                         }
     451             :         |       NUMBER '>' WORD
     452             :                         {
     453     1635249 :                           source.dest = $1;
     454     1635249 :                           redir.filename = $3;
     455     1635249 :                           $$ = make_redirection (source, r_output_direction, redir, 0);
     456             :                         }
     457             :         |       NUMBER '<' WORD
     458             :                         {
     459          61 :                           source.dest = $1;
     460          61 :                           redir.filename = $3;
     461          61 :                           $$ = make_redirection (source, r_input_direction, redir, 0);
     462             :                         }
     463             :         |       REDIR_WORD '>' WORD
     464             :                         {
     465           0 :                           source.filename = $1;
     466           0 :                           redir.filename = $3;
     467           0 :                           $$ = make_redirection (source, r_output_direction, redir, REDIR_VARASSIGN);
     468             :                         }
     469             :         |       REDIR_WORD '<' WORD
     470             :                         {
     471           0 :                           source.filename = $1;
     472           0 :                           redir.filename = $3;
     473           0 :                           $$ = make_redirection (source, r_input_direction, redir, REDIR_VARASSIGN);
     474             :                         }
     475             :         |       GREATER_GREATER WORD
     476             :                         {
     477     3500837 :                           source.dest = 1;
     478     3500837 :                           redir.filename = $2;
     479     3500837 :                           $$ = make_redirection (source, r_appending_to, redir, 0);
     480             :                         }
     481             :         |       NUMBER GREATER_GREATER WORD
     482             :                         {
     483          19 :                           source.dest = $1;
     484          19 :                           redir.filename = $3;
     485          19 :                           $$ = make_redirection (source, r_appending_to, redir, 0);
     486             :                         }
     487             :         |       REDIR_WORD GREATER_GREATER WORD
     488             :                         {
     489           0 :                           source.filename = $1;
     490           0 :                           redir.filename = $3;
     491           0 :                           $$ = make_redirection (source, r_appending_to, redir, REDIR_VARASSIGN);
     492             :                         }
     493             :         |       GREATER_BAR WORD
     494             :                         {
     495          80 :                           source.dest = 1;
     496          80 :                           redir.filename = $2;
     497          80 :                           $$ = make_redirection (source, r_output_force, redir, 0);
     498             :                         }
     499             :         |       NUMBER GREATER_BAR WORD
     500             :                         {
     501           0 :                           source.dest = $1;
     502           0 :                           redir.filename = $3;
     503           0 :                           $$ = make_redirection (source, r_output_force, redir, 0);
     504             :                         }
     505             :         |       REDIR_WORD GREATER_BAR WORD
     506             :                         {
     507           0 :                           source.filename = $1;
     508           0 :                           redir.filename = $3;
     509           0 :                           $$ = make_redirection (source, r_output_force, redir, REDIR_VARASSIGN);
     510             :                         }
     511             :         |       LESS_GREATER WORD
     512             :                         {
     513         103 :                           source.dest = 0;
     514         103 :                           redir.filename = $2;
     515         103 :                           $$ = make_redirection (source, r_input_output, redir, 0);
     516             :                         }
     517             :         |       NUMBER LESS_GREATER WORD
     518             :                         {
     519           0 :                           source.dest = $1;
     520           0 :                           redir.filename = $3;
     521           0 :                           $$ = make_redirection (source, r_input_output, redir, 0);
     522             :                         }
     523             :         |       REDIR_WORD LESS_GREATER WORD
     524             :                         {
     525           0 :                           source.filename = $1;
     526           0 :                           redir.filename = $3;
     527           0 :                           $$ = make_redirection (source, r_input_output, redir, REDIR_VARASSIGN);
     528             :                         }
     529             :         |       LESS_LESS WORD
     530             :                         {
     531         285 :                           source.dest = 0;
     532         285 :                           redir.filename = $2;
     533         285 :                           $$ = make_redirection (source, r_reading_until, redir, 0);
     534         285 :                           push_heredoc ($$);
     535             :                         }
     536             :         |       NUMBER LESS_LESS WORD
     537             :                         {
     538           0 :                           source.dest = $1;
     539           0 :                           redir.filename = $3;
     540           0 :                           $$ = make_redirection (source, r_reading_until, redir, 0);
     541           0 :                           push_heredoc ($$);
     542             :                         }
     543             :         |       REDIR_WORD LESS_LESS WORD
     544             :                         {
     545           0 :                           source.filename = $1;
     546           0 :                           redir.filename = $3;
     547           0 :                           $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
     548           0 :                           push_heredoc ($$);
     549             :                         }
     550             :         |       LESS_LESS_MINUS WORD
     551             :                         {
     552           0 :                           source.dest = 0;
     553           0 :                           redir.filename = $2;
     554           0 :                           $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
     555           0 :                           push_heredoc ($$);
     556             :                         }
     557             :         |       NUMBER LESS_LESS_MINUS WORD
     558             :                         {
     559           0 :                           source.dest = $1;
     560           0 :                           redir.filename = $3;
     561           0 :                           $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
     562           0 :                           push_heredoc ($$);
     563             :                         }
     564             :         |       REDIR_WORD  LESS_LESS_MINUS WORD
     565             :                         {
     566           0 :                           source.filename = $1;
     567           0 :                           redir.filename = $3;
     568           0 :                           $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
     569           0 :                           push_heredoc ($$);
     570             :                         }
     571             :         |       LESS_LESS_LESS WORD
     572             :                         {
     573          69 :                           source.dest = 0;
     574          69 :                           redir.filename = $2;
     575          69 :                           $$ = make_redirection (source, r_reading_string, redir, 0);
     576             :                         }
     577             :         |       NUMBER LESS_LESS_LESS WORD
     578             :                         {
     579           9 :                           source.dest = $1;
     580           9 :                           redir.filename = $3;
     581           9 :                           $$ = make_redirection (source, r_reading_string, redir, 0);
     582             :                         }
     583             :         |       REDIR_WORD LESS_LESS_LESS WORD
     584             :                         {
     585           0 :                           source.filename = $1;
     586           0 :                           redir.filename = $3;
     587           0 :                           $$ = make_redirection (source, r_reading_string, redir, REDIR_VARASSIGN);
     588             :                         }
     589             :         |       LESS_AND NUMBER
     590             :                         {
     591           0 :                           source.dest = 0;
     592           0 :                           redir.dest = $2;
     593           0 :                           $$ = make_redirection (source, r_duplicating_input, redir, 0);
     594             :                         }
     595             :         |       NUMBER LESS_AND NUMBER
     596             :                         {
     597           9 :                           source.dest = $1;
     598           9 :                           redir.dest = $3;
     599           9 :                           $$ = make_redirection (source, r_duplicating_input, redir, 0);
     600             :                         }
     601             :         |       REDIR_WORD LESS_AND NUMBER
     602             :                         {
     603           0 :                           source.filename = $1;
     604           0 :                           redir.dest = $3;
     605           0 :                           $$ = make_redirection (source, r_duplicating_input, redir, REDIR_VARASSIGN);
     606             :                         }
     607             :         |       GREATER_AND NUMBER
     608             :                         {
     609        4963 :                           source.dest = 1;
     610        4963 :                           redir.dest = $2;
     611        4963 :                           $$ = make_redirection (source, r_duplicating_output, redir, 0);
     612             :                         }
     613             :         |       NUMBER GREATER_AND NUMBER
     614             :                         {
     615     1853325 :                           source.dest = $1;
     616     1853325 :                           redir.dest = $3;
     617     1853325 :                           $$ = make_redirection (source, r_duplicating_output, redir, 0);
     618             :                         }
     619             :         |       REDIR_WORD GREATER_AND NUMBER
     620             :                         {
     621           0 :                           source.filename = $1;
     622           0 :                           redir.dest = $3;
     623           0 :                           $$ = make_redirection (source, r_duplicating_output, redir, REDIR_VARASSIGN);
     624             :                         }
     625             :         |       LESS_AND WORD
     626             :                         {
     627          51 :                           source.dest = 0;
     628          51 :                           redir.filename = $2;
     629          51 :                           $$ = make_redirection (source, r_duplicating_input_word, redir, 0);
     630             :                         }
     631             :         |       NUMBER LESS_AND WORD
     632             :                         {
     633           0 :                           source.dest = $1;
     634           0 :                           redir.filename = $3;
     635           0 :                           $$ = make_redirection (source, r_duplicating_input_word, redir, 0);
     636             :                         }
     637             :         |       REDIR_WORD LESS_AND WORD
     638             :                         {
     639           0 :                           source.filename = $1;
     640           0 :                           redir.filename = $3;
     641           0 :                           $$ = make_redirection (source, r_duplicating_input_word, redir, REDIR_VARASSIGN);
     642             :                         }
     643             :         |       GREATER_AND WORD
     644             :                         {
     645          68 :                           source.dest = 1;
     646          68 :                           redir.filename = $2;
     647          68 :                           $$ = make_redirection (source, r_duplicating_output_word, redir, 0);
     648             :                         }
     649             :         |       NUMBER GREATER_AND WORD
     650             :                         {
     651        5289 :                           source.dest = $1;
     652        5289 :                           redir.filename = $3;
     653        5289 :                           $$ = make_redirection (source, r_duplicating_output_word, redir, 0);
     654             :                         }
     655             :         |       REDIR_WORD GREATER_AND WORD
     656             :                         {
     657           0 :                           source.filename = $1;
     658           0 :                           redir.filename = $3;
     659           0 :                           $$ = make_redirection (source, r_duplicating_output_word, redir, REDIR_VARASSIGN);
     660             :                         }
     661             :         |       GREATER_AND '-'
     662             :                         {
     663           0 :                           source.dest = 1;
     664           0 :                           redir.dest = 0;
     665           0 :                           $$ = make_redirection (source, r_close_this, redir, 0);
     666             :                         }
     667             :         |       NUMBER GREATER_AND '-'
     668             :                         {
     669          10 :                           source.dest = $1;
     670          10 :                           redir.dest = 0;
     671          10 :                           $$ = make_redirection (source, r_close_this, redir, 0);
     672             :                         }
     673             :         |       REDIR_WORD GREATER_AND '-'
     674             :                         {
     675           0 :                           source.filename = $1;
     676           0 :                           redir.dest = 0;
     677           0 :                           $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN);
     678             :                         }
     679             :         |       LESS_AND '-'
     680             :                         {
     681           0 :                           source.dest = 0;
     682           0 :                           redir.dest = 0;
     683           0 :                           $$ = make_redirection (source, r_close_this, redir, 0);
     684             :                         }
     685             :         |       NUMBER LESS_AND '-'
     686             :                         {
     687           0 :                           source.dest = $1;
     688           0 :                           redir.dest = 0;
     689           0 :                           $$ = make_redirection (source, r_close_this, redir, 0);
     690             :                         }
     691             :         |       REDIR_WORD LESS_AND '-'
     692             :                         {
     693           0 :                           source.filename = $1;
     694           0 :                           redir.dest = 0;
     695           0 :                           $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN);
     696             :                         }
     697             :         |       AND_GREATER WORD
     698             :                         {
     699          50 :                           source.dest = 1;
     700          50 :                           redir.filename = $2;
     701          50 :                           $$ = make_redirection (source, r_err_and_out, redir, 0);
     702             :                         }
     703             :         |       AND_GREATER_GREATER WORD
     704             :                         {
     705          12 :                           source.dest = 1;
     706          12 :                           redir.filename = $2;
     707          12 :                           $$ = make_redirection (source, r_append_err_and_out, redir, 0);
     708             :                         }
     709             :         ;
     710             : 
     711             : simple_command_element: WORD
     712   642615775 :                         { $$.word = $1; $$.redirect = 0; }
     713             :         |       ASSIGNMENT_WORD
     714    56720875 :                         { $$.word = $1; $$.redirect = 0; }
     715             :         |       redirection
     716    16798181 :                         { $$.redirect = $1; $$.word = 0; }
     717             :         ;
     718             : 
     719             : redirection_list: redirection
     720             :                         {
     721           9 :                           $$ = $1;
     722             :                         }
     723             :         |       redirection_list redirection
     724             :                         {
     725           0 :                           register REDIRECT *t;
     726             : 
     727           0 :                           for (t = $1; t->next; t = t->next)
     728             :                             ;
     729           0 :                           t->next = $2;
     730           0 :                           $$ = $1;
     731             :                         }
     732             :         ;
     733             : 
     734             : simple_command: simple_command_element
     735   281725662 :                         { $$ = make_simple_command ($1, (COMMAND *)NULL); }
     736             :         |       simple_command simple_command_element
     737   434409169 :                         { $$ = make_simple_command ($2, $1); }
     738             :         ;
     739             : 
     740             : command:        simple_command
     741   281713534 :                         { $$ = clean_simple_command ($1); }
     742             :         |       shell_command
     743    95088693 :                         { $$ = $1; }
     744             :         |       shell_command redirection_list
     745             :                         {
     746           9 :                           COMMAND *tc;
     747             : 
     748           9 :                           tc = $1;
     749           9 :                           if (tc->redirects)
     750             :                             {
     751             :                               register REDIRECT *t;
     752           0 :                               for (t = tc->redirects; t->next; t = t->next)
     753             :                                 ;
     754           0 :                               t->next = $2;
     755             :                             }
     756             :                           else
     757           9 :                             tc->redirects = $2;
     758           9 :                           $$ = $1;
     759             :                         }
     760             :         |       function_def
     761    18763987 :                         { $$ = $1; }
     762             :         |       coproc
     763           0 :                         { $$ = $1; }
     764             :         ;
     765             : 
     766             : shell_command:  for_command
     767     9542969 :                         { $$ = $1; }
     768             :         |       case_command
     769    15245007 :                         { $$ = $1; }
     770             :         |       WHILE compound_list DO compound_list DONE
     771     1837422 :                         { $$ = make_while_command ($2, $4); }
     772             :         |       UNTIL compound_list DO compound_list DONE
     773           0 :                         { $$ = make_until_command ($2, $4); }
     774             :         |       select_command
     775           0 :                         { $$ = $1; }
     776             :         |       if_command
     777    68460861 :                         { $$ = $1; }
     778             :         |       subshell
     779         213 :                         { $$ = $1; }
     780             :         |       group_command
     781    18766217 :                         { $$ = $1; }
     782             :         |       arith_command
     783           0 :                         { $$ = $1; }
     784             :         |       cond_command
     785           0 :                         { $$ = $1; }
     786             :         |       arith_for_command
     787           0 :                         { $$ = $1; }
     788             :         ;
     789             : 
     790             : for_command:    FOR WORD newline_list DO compound_list DONE
     791             :                         {
     792           0 :                           $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
     793           0 :                           if (word_top > 0) word_top--;
     794             :                         }
     795             :         |       FOR WORD newline_list '{' compound_list '}'
     796             :                         {
     797           0 :                           $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
     798           0 :                           if (word_top > 0) word_top--;
     799             :                         }
     800             :         |       FOR WORD ';' newline_list DO compound_list DONE
     801             :                         {
     802           0 :                           $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
     803           0 :                           if (word_top > 0) word_top--;
     804             :                         }
     805             :         |       FOR WORD ';' newline_list '{' compound_list '}'
     806             :                         {
     807           0 :                           $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
     808           0 :                           if (word_top > 0) word_top--;
     809             :                         }
     810             :         |       FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE
     811             :                         {
     812     9542969 :                           $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
     813     9542969 :                           if (word_top > 0) word_top--;
     814             :                         }
     815             :         |       FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}'
     816             :                         {
     817           0 :                           $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
     818           0 :                           if (word_top > 0) word_top--;
     819             :                         }
     820             :         |       FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE
     821             :                         {
     822           0 :                           $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
     823           0 :                           if (word_top > 0) word_top--;
     824             :                         }
     825             :         |       FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}'
     826             :                         {
     827           0 :                           $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
     828           0 :                           if (word_top > 0) word_top--;
     829             :                         }
     830             :         ;
     831             : 
     832             : arith_for_command:      FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE
     833             :                                 {
     834           0 :                                   $$ = make_arith_for_command ($2, $6, arith_for_lineno);
     835           0 :                                   if (word_top > 0) word_top--;
     836             :                                 }
     837             :         |               FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}'
     838             :                                 {
     839           0 :                                   $$ = make_arith_for_command ($2, $6, arith_for_lineno);
     840           0 :                                   if (word_top > 0) word_top--;
     841             :                                 }
     842             :         |               FOR ARITH_FOR_EXPRS DO compound_list DONE
     843             :                                 {
     844           0 :                                   $$ = make_arith_for_command ($2, $4, arith_for_lineno);
     845           0 :                                   if (word_top > 0) word_top--;
     846             :                                 }
     847             :         |               FOR ARITH_FOR_EXPRS '{' compound_list '}'
     848             :                                 {
     849           0 :                                   $$ = make_arith_for_command ($2, $4, arith_for_lineno);
     850           0 :                                   if (word_top > 0) word_top--;
     851             :                                 }
     852             :         ;
     853             : 
     854             : select_command: SELECT WORD newline_list DO list DONE
     855             :                         {
     856           0 :                           $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
     857           0 :                           if (word_top > 0) word_top--;
     858             :                         }
     859             :         |       SELECT WORD newline_list '{' list '}'
     860             :                         {
     861           0 :                           $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
     862           0 :                           if (word_top > 0) word_top--;
     863             :                         }
     864             :         |       SELECT WORD ';' newline_list DO list DONE
     865             :                         {
     866           0 :                           $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
     867           0 :                           if (word_top > 0) word_top--;
     868             :                         }
     869             :         |       SELECT WORD ';' newline_list '{' list '}'
     870             :                         {
     871           0 :                           $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
     872           0 :                           if (word_top > 0) word_top--;
     873             :                         }
     874             :         |       SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE
     875             :                         {
     876           0 :                           $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
     877           0 :                           if (word_top > 0) word_top--;
     878             :                         }
     879             :         |       SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}'
     880             :                         {
     881           0 :                           $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
     882           0 :                           if (word_top > 0) word_top--;
     883             :                         }
     884             :         ;
     885             : 
     886             : case_command:   CASE WORD newline_list IN newline_list ESAC
     887             :                         {
     888           9 :                           $$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]);
     889           9 :                           if (word_top > 0) word_top--;
     890             :                         }
     891             :         |       CASE WORD newline_list IN case_clause_sequence newline_list ESAC
     892             :                         {
     893    11494761 :                           $$ = make_case_command ($2, $5, word_lineno[word_top]);
     894    11494761 :                           if (word_top > 0) word_top--;
     895             :                         }
     896             :         |       CASE WORD newline_list IN case_clause ESAC
     897             :                         {
     898     3750237 :                           $$ = make_case_command ($2, $5, word_lineno[word_top]);
     899     3750237 :                           if (word_top > 0) word_top--;
     900             :                         }
     901             :         ;
     902             : 
     903             : function_def:   WORD '(' ')' newline_list function_body
     904    18763978 :                         { $$ = make_function_def ($1, $5, function_dstart, function_bstart); }
     905             : 
     906             :         |       FUNCTION WORD '(' ')' newline_list function_body
     907           0 :                         { $$ = make_function_def ($2, $6, function_dstart, function_bstart); }
     908             : 
     909             :         |       FUNCTION WORD newline_list function_body
     910           9 :                         { $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
     911             :         ;
     912             : 
     913             : function_body:  shell_command
     914    18763987 :                         { $$ = $1; }
     915             :         |       shell_command redirection_list
     916             :                         {
     917           0 :                           COMMAND *tc;
     918             : 
     919           0 :                           tc = $1;
     920             :                           /* According to Posix.2 3.9.5, redirections
     921             :                              specified after the body of a function should
     922             :                              be attached to the function and performed when
     923             :                              the function is executed, not as part of the
     924             :                              function definition command. */
     925             :                           /* XXX - I don't think it matters, but we might
     926             :                              want to change this in the future to avoid
     927             :                              problems differentiating between a function
     928             :                              definition with a redirection and a function
     929             :                              definition containing a single command with a
     930             :                              redirection.  The two are semantically equivalent,
     931             :                              though -- the only difference is in how the
     932             :                              command printing code displays the redirections. */
     933           0 :                           if (tc->redirects)
     934             :                             {
     935             :                               register REDIRECT *t;
     936           0 :                               for (t = tc->redirects; t->next; t = t->next)
     937             :                                 ;
     938           0 :                               t->next = $2;
     939             :                             }
     940             :                           else
     941           0 :                             tc->redirects = $2;
     942           0 :                           $$ = $1;
     943             :                         }
     944             :         ;
     945             : 
     946             : subshell:       '(' compound_list ')'
     947             :                         {
     948         213 :                           $$ = make_subshell_command ($2);
     949         213 :                           $$->flags |= CMD_WANT_SUBSHELL;
     950             :                         }
     951             :         ;
     952             : 
     953             : coproc:         COPROC shell_command
     954             :                         {
     955           0 :                           $$ = make_coproc_command ("COPROC", $2);
     956           0 :                           $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
     957             :                         }
     958             :         |       COPROC shell_command redirection_list
     959             :                         {
     960           0 :                           COMMAND *tc;
     961             : 
     962           0 :                           tc = $2;
     963           0 :                           if (tc->redirects)
     964             :                             {
     965             :                               register REDIRECT *t;
     966           0 :                               for (t = tc->redirects; t->next; t = t->next)
     967             :                                 ;
     968           0 :                               t->next = $3;
     969             :                             }
     970             :                           else
     971           0 :                             tc->redirects = $3;
     972           0 :                           $$ = make_coproc_command ("COPROC", $2);
     973           0 :                           $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
     974             :                         }
     975             :         |       COPROC WORD shell_command
     976             :                         {
     977           0 :                           $$ = make_coproc_command ($2->word, $3);
     978           0 :                           $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
     979             :                         }
     980             :         |       COPROC WORD shell_command redirection_list
     981             :                         {
     982           0 :                           COMMAND *tc;
     983             : 
     984           0 :                           tc = $3;
     985           0 :                           if (tc->redirects)
     986             :                             {
     987             :                               register REDIRECT *t;
     988           0 :                               for (t = tc->redirects; t->next; t = t->next)
     989             :                                 ;
     990           0 :                               t->next = $4;
     991             :                             }
     992             :                           else
     993           0 :                             tc->redirects = $4;
     994           0 :                           $$ = make_coproc_command ($2->word, $3);
     995           0 :                           $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
     996             :                         }
     997             :         |       COPROC simple_command
     998             :                         {
     999           0 :                           $$ = make_coproc_command ("COPROC", clean_simple_command ($2));
    1000           0 :                           $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
    1001             :                         }
    1002             :         ;
    1003             : 
    1004             : if_command:     IF compound_list THEN compound_list FI
    1005    66804905 :                         { $$ = make_if_command ($2, $4, (COMMAND *)NULL); }
    1006             :         |       IF compound_list THEN compound_list ELSE compound_list FI
    1007     1655956 :                         { $$ = make_if_command ($2, $4, $6); }
    1008             :         |       IF compound_list THEN compound_list elif_clause FI
    1009           0 :                         { $$ = make_if_command ($2, $4, $5); }
    1010             :         ;
    1011             : 
    1012             : 
    1013             : group_command:  '{' compound_list '}'
    1014    18766217 :                         { $$ = make_group_command ($2); }
    1015             :         ;
    1016             : 
    1017             : arith_command:  ARITH_CMD
    1018           0 :                         { $$ = make_arith_command ($1); }
    1019             :         ;
    1020             : 
    1021             : cond_command:   COND_START COND_CMD COND_END
    1022           0 :                         { $$ = $2; }
    1023             :         ; 
    1024             : 
    1025             : elif_clause:    ELIF compound_list THEN compound_list
    1026           0 :                         { $$ = make_if_command ($2, $4, (COMMAND *)NULL); }
    1027             :         |       ELIF compound_list THEN compound_list ELSE compound_list
    1028           0 :                         { $$ = make_if_command ($2, $4, $6); }
    1029             :         |       ELIF compound_list THEN compound_list elif_clause
    1030           0 :                         { $$ = make_if_command ($2, $4, $5); }
    1031             :         ;
    1032             : 
    1033             : case_clause:    pattern_list
    1034             :         |       case_clause_sequence pattern_list
    1035     3895982 :                         { $2->next = $1; $$ = $2; }
    1036             :         ;
    1037             : 
    1038             : pattern_list:   newline_list pattern ')' compound_list
    1039    47359442 :                         { $$ = make_pattern_list ($2, $4); }
    1040             :         |       newline_list pattern ')' newline_list
    1041     1995782 :                         { $$ = make_pattern_list ($2, (COMMAND *)NULL); }
    1042             :         |       newline_list '(' pattern ')' compound_list
    1043          80 :                         { $$ = make_pattern_list ($3, $5); }
    1044             :         |       newline_list '(' pattern ')' newline_list
    1045          10 :                         { $$ = make_pattern_list ($3, (COMMAND *)NULL); }
    1046             :         ;
    1047             : 
    1048             : case_clause_sequence:  pattern_list SEMI_SEMI
    1049    15663833 :                         { $$ = $1; }
    1050             :         |       case_clause_sequence pattern_list SEMI_SEMI
    1051    29780684 :                         { $2->next = $1; $$ = $2; }
    1052             :         |       pattern_list SEMI_AND
    1053          12 :                         { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; }
    1054             :         |       case_clause_sequence pattern_list SEMI_AND
    1055          35 :                         { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; }
    1056             :         |       pattern_list SEMI_SEMI_AND
    1057          13 :                         { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; }
    1058             :         |       case_clause_sequence pattern_list SEMI_SEMI_AND
    1059          35 :                         { $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; }        
    1060             :         ;
    1061             : 
    1062             : pattern:        WORD
    1063    49637617 :                         { $$ = make_word_list ($1, (WORD_LIST *)NULL); }
    1064             :         |       pattern '|' WORD
    1065    25139881 :                         { $$ = make_word_list ($3, $1); }
    1066             :         ;
    1067             : 
    1068             : /* A list allows leading or trailing newlines and
    1069             :    newlines as operators (equivalent to semicolons).
    1070             :    It must end with a newline or semicolon.
    1071             :    Lists are used within commands such as if, for, while.  */
    1072             : 
    1073             : list:           newline_list list0
    1074             :                         {
    1075   218278565 :                           $$ = $2;
    1076   218278565 :                           if (need_here_doc)
    1077           0 :                             gather_here_documents ();
    1078             :                          }
    1079             :         ;
    1080             : 
    1081             : compound_list:  list
    1082             :         |       newline_list list1
    1083             :                         {
    1084      229977 :                           $$ = $2;
    1085             :                         }
    1086             :         ;
    1087             : 
    1088             : list0:          list1 '\n' newline_list
    1089             :         |       list1 '&' newline_list
    1090             :                         {
    1091         153 :                           if ($1->type == cm_connection)
    1092          72 :                             $$ = connect_async_list ($1, (COMMAND *)NULL, '&');
    1093             :                           else
    1094          81 :                             $$ = command_connect ($1, (COMMAND *)NULL, '&');
    1095             :                         }
    1096             :         |       list1 ';' newline_list
    1097             : 
    1098             :         ;
    1099             : 
    1100             : list1:          list1 AND_AND newline_list list1
    1101           9 :                         { $$ = command_connect ($1, $4, AND_AND); }
    1102             :         |       list1 OR_OR newline_list list1
    1103     1864345 :                         { $$ = command_connect ($1, $4, OR_OR); }
    1104             :         |       list1 '&' newline_list list1
    1105             :                         {
    1106        3476 :                           if ($1->type == cm_connection)
    1107        2895 :                             $$ = connect_async_list ($1, $4, '&');
    1108             :                           else
    1109         581 :                             $$ = command_connect ($1, $4, '&');
    1110             :                         }
    1111             :         |       list1 ';' newline_list list1
    1112      135958 :                         { $$ = command_connect ($1, $4, ';'); }
    1113             :         |       list1 '\n' newline_list list1
    1114    79801281 :                         { $$ = command_connect ($1, $4, ';'); }
    1115             :         |       pipeline_command
    1116   300405325 :                         { $$ = $1; }
    1117             :         ;
    1118             : 
    1119             : simple_list_terminator: '\n'
    1120             :         |       yacc_EOF
    1121             :         ;
    1122             : 
    1123             : list_terminator:'\n'
    1124         189 :                 { $$ = '\n'; }
    1125             :         |       ';'
    1126     9543045 :                 { $$ = ';'; }
    1127             :         |       yacc_EOF
    1128           0 :                 { $$ = yacc_EOF; }
    1129             :         ;
    1130             : 
    1131             : newline_list:
    1132             :         |       newline_list '\n'
    1133             :         ;
    1134             : 
    1135             : /* A simple_list is a list that contains no significant newlines
    1136             :    and no leading or trailing newlines.  Newlines are allowed
    1137             :    only following operators, where they are not significant.
    1138             : 
    1139             :    This is what an inputunit consists of.  */
    1140             : 
    1141             : simple_list:    simple_list1
    1142             :                         {
    1143    90431718 :                           $$ = $1;
    1144    90431718 :                           if (need_here_doc)
    1145          40 :                             gather_here_documents ();
    1146    90431718 :                           if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
    1147             :                             {
    1148           9 :                               global_command = $1;
    1149           9 :                               eof_encountered = 0;
    1150          18 :                               rewind_input_string ();
    1151           9 :                               YYACCEPT;
    1152             :                             }
    1153             :                         }
    1154             :         |       simple_list1 '&'
    1155             :                         {
    1156        4177 :                           if ($1->type == cm_connection)
    1157        1475 :                             $$ = connect_async_list ($1, (COMMAND *)NULL, '&');
    1158             :                           else
    1159        2702 :                             $$ = command_connect ($1, (COMMAND *)NULL, '&');
    1160        4177 :                           if (need_here_doc)
    1161           0 :                             gather_here_documents ();
    1162        4177 :                           if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
    1163             :                             {
    1164           0 :                               global_command = $1;
    1165           0 :                               eof_encountered = 0;
    1166           0 :                               rewind_input_string ();
    1167           0 :                               YYACCEPT;
    1168             :                             }
    1169             :                         }
    1170             :         |       simple_list1 ';'
    1171             :                         {
    1172       34232 :                           $$ = $1;
    1173       34232 :                           if (need_here_doc)
    1174           0 :                             gather_here_documents ();
    1175       34232 :                           if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
    1176             :                             {
    1177           0 :                               global_command = $1;
    1178           0 :                               eof_encountered = 0;
    1179           0 :                               rewind_input_string ();
    1180           0 :                               YYACCEPT;
    1181             :                             }
    1182             :                         }
    1183             :         ;
    1184             : 
    1185             : simple_list1:   simple_list1 AND_AND newline_list simple_list1
    1186          56 :                         { $$ = command_connect ($1, $4, AND_AND); }
    1187             :         |       simple_list1 OR_OR newline_list simple_list1
    1188     2364544 :                         { $$ = command_connect ($1, $4, OR_OR); }
    1189             :         |       simple_list1 '&' simple_list1
    1190             :                         {
    1191       17699 :                           if ($1->type == cm_connection)
    1192        5927 :                             $$ = connect_async_list ($1, $3, '&');
    1193             :                           else
    1194       11772 :                             $$ = command_connect ($1, $3, '&');
    1195             :                         }
    1196             :         |       simple_list1 ';' simple_list1
    1197       18653 :                         { $$ = command_connect ($1, $3, ';'); }
    1198             : 
    1199             :         |       pipeline_command
    1200    92877136 :                         { $$ = $1; }
    1201             :         ;
    1202             : 
    1203             : pipeline_command: pipeline
    1204   393282196 :                         { $$ = $1; }                    
    1205             :         |       BANG pipeline_command
    1206             :                         {
    1207         455 :                           if ($2)
    1208         455 :                             $2->flags ^= CMD_INVERT_RETURN;  /* toggle */
    1209         455 :                           $$ = $2;
    1210             :                         }
    1211             :         |       timespec pipeline_command
    1212             :                         {
    1213           0 :                           if ($2)
    1214           0 :                             $2->flags |= $1;
    1215           0 :                           $$ = $2;
    1216             :                         }
    1217             :         |       timespec list_terminator
    1218             :                         {
    1219           0 :                           ELEMENT x;
    1220             : 
    1221             :                           /* Boy, this is unclean.  `time' by itself can
    1222             :                              time a null command.  We cheat and push a
    1223             :                              newline back if the list_terminator was a newline
    1224             :                              to avoid the double-newline problem (one to
    1225             :                              terminate this, one to terminate the command) */
    1226           0 :                           x.word = 0;
    1227           0 :                           x.redirect = 0;
    1228           0 :                           $$ = make_simple_command (x, (COMMAND *)NULL);
    1229           0 :                           $$->flags |= $1;
    1230             :                           /* XXX - let's cheat and push a newline back */
    1231           0 :                           if ($2 == '\n')
    1232           0 :                             token_to_read = '\n';
    1233           0 :                           else if ($2 == ';')
    1234           0 :                             token_to_read = ';';
    1235             :                         }
    1236             :         |       BANG list_terminator
    1237             :                         {
    1238         265 :                           ELEMENT x;
    1239             : 
    1240             :                           /* This is just as unclean.  Posix says that `!'
    1241             :                              by itself should be equivalent to `false'.
    1242             :                              We cheat and push a
    1243             :                              newline back if the list_terminator was a newline
    1244             :                              to avoid the double-newline problem (one to
    1245             :                              terminate this, one to terminate the command) */
    1246         265 :                           x.word = 0;
    1247         265 :                           x.redirect = 0;
    1248         265 :                           $$ = make_simple_command (x, (COMMAND *)NULL);
    1249         265 :                           $$->flags |= CMD_INVERT_RETURN;
    1250             :                           /* XXX - let's cheat and push a newline back */
    1251         265 :                           if ($2 == '\n')
    1252         189 :                             token_to_read = '\n';
    1253         265 :                           if ($2 == ';')
    1254          76 :                             token_to_read = ';';
    1255             :                         }
    1256             :         ;
    1257             : 
    1258             : pipeline:       pipeline '|' newline_list pipeline
    1259     1905840 :                         { $$ = command_connect ($1, $4, '|'); }
    1260             :         |       pipeline BAR_AND newline_list pipeline
    1261             :                         {
    1262             :                           /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
    1263          92 :                           COMMAND *tc;
    1264          92 :                           REDIRECTEE rd, sd;
    1265          92 :                           REDIRECT *r;
    1266             : 
    1267          92 :                           tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1;
    1268          92 :                           sd.dest = 2;
    1269          92 :                           rd.dest = 1;
    1270          92 :                           r = make_redirection (sd, r_duplicating_output, rd, 0);
    1271          92 :                           if (tc->redirects)
    1272             :                             {
    1273             :                               register REDIRECT *t;
    1274          57 :                               for (t = tc->redirects; t->next; t = t->next)
    1275             :                                 ;
    1276          33 :                               t->next = r;
    1277             :                             }
    1278             :                           else
    1279          59 :                             tc->redirects = r;
    1280             : 
    1281          92 :                           $$ = command_connect ($1, $4, '|');
    1282             :                         }
    1283             :         |       command
    1284   395566223 :                         { $$ = $1; }
    1285             :         ;
    1286             : 
    1287             : timespec:       TIME
    1288           0 :                         { $$ = CMD_TIME_PIPELINE; }
    1289             :         |       TIME TIMEOPT
    1290           0 :                         { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; }
    1291             :         |       TIME TIMEOPT TIMEIGN
    1292           0 :                         { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; }
    1293             :         ;
    1294             : %%
    1295             : 
    1296             : /* Initial size to allocate for tokens, and the
    1297             :    amount to grow them by. */
    1298             : #define TOKEN_DEFAULT_INITIAL_SIZE 496
    1299             : #define TOKEN_DEFAULT_GROW_SIZE 512
    1300             : 
    1301             : /* Should we call prompt_again? */
    1302             : #define SHOULD_PROMPT() \
    1303             :   (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
    1304             : 
    1305             : #if defined (ALIAS)
    1306             : #  define expanding_alias() (pushed_string_list && pushed_string_list->expander)
    1307             : #else
    1308             : #  define expanding_alias() 0
    1309             : #endif
    1310             : 
    1311             : /* Global var is non-zero when end of file has been reached. */
    1312             : int EOF_Reached = 0;
    1313             : 
    1314             : #ifdef DEBUG
    1315             : static void
    1316             : debug_parser (i)
    1317             :      int i;
    1318             : {
    1319             : #if YYDEBUG != 0
    1320             :   yydebug = i;
    1321             : #endif
    1322             : }
    1323             : #endif
    1324             : 
    1325             : /* yy_getc () returns the next available character from input or EOF.
    1326             :    yy_ungetc (c) makes `c' the next character to read.
    1327             :    init_yy_io (get, unget, type, location) makes the function GET the
    1328             :    installed function for getting the next character, makes UNGET the
    1329             :    installed function for un-getting a character, sets the type of stream
    1330             :    (either string or file) from TYPE, and makes LOCATION point to where
    1331             :    the input is coming from. */
    1332             : 
    1333             : /* Unconditionally returns end-of-file. */
    1334             : int
    1335           0 : return_EOF ()
    1336             : {
    1337           0 :   return (EOF);
    1338             : }
    1339             : 
    1340             : /* Variable containing the current get and unget functions.
    1341             :    See ./input.h for a clearer description. */
    1342             : BASH_INPUT bash_input;
    1343             : 
    1344             : /* Set all of the fields in BASH_INPUT to NULL.  Free bash_input.name if it
    1345             :    is non-null, avoiding a memory leak. */
    1346             : void
    1347     9542961 : initialize_bash_input ()
    1348             : {
    1349     9542961 :   bash_input.type = st_none;
    1350     9542961 :   FREE (bash_input.name);
    1351     9542961 :   bash_input.name = (char *)NULL;
    1352     9542961 :   bash_input.location.file = (FILE *)NULL;
    1353     9542961 :   bash_input.location.string = (char *)NULL;
    1354     9542961 :   bash_input.getter = (sh_cget_func_t *)NULL;
    1355     9542961 :   bash_input.ungetter = (sh_cunget_func_t *)NULL;
    1356     9542961 : }
    1357             : 
    1358             : /* Set the contents of the current bash input stream from
    1359             :    GET, UNGET, TYPE, NAME, and LOCATION. */
    1360             : void
    1361    47734156 : init_yy_io (get, unget, type, name, location)
    1362             :      sh_cget_func_t *get;
    1363             :      sh_cunget_func_t *unget;
    1364             :      enum stream_type type;
    1365             :      const char *name;
    1366             :      INPUT_STREAM location;
    1367             : {
    1368    47734156 :   bash_input.type = type;
    1369    47734156 :   FREE (bash_input.name);
    1370    47734156 :   bash_input.name = name ? savestring (name) : (char *)NULL;
    1371             : 
    1372             :   /* XXX */
    1373             : #if defined (CRAY)
    1374             :   memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location));
    1375             : #else
    1376    47734156 :   bash_input.location = location;
    1377             : #endif
    1378    47734156 :   bash_input.getter = get;
    1379    47734156 :   bash_input.ungetter = unget;
    1380    47734156 : }
    1381             : 
    1382             : char *
    1383     4076515 : yy_input_name ()
    1384             : {
    1385     4076515 :   return (bash_input.name ? bash_input.name : "stdin");
    1386             : }
    1387             : 
    1388             : /* Call this to get the next character of input. */
    1389             : static int
    1390             : yy_getc ()
    1391             : {
    1392 15269784262 :   return (*(bash_input.getter)) ();
    1393             : }
    1394             : 
    1395             : /* Call this to unget C.  That is, to make C the next character
    1396             :    to be read. */
    1397             : static int
    1398             : yy_ungetc (c)
    1399             :      int c;
    1400             : {
    1401          43 :   return (*(bash_input.ungetter)) (c);
    1402             : }
    1403             : 
    1404             : #if defined (BUFFERED_INPUT)
    1405             : #ifdef INCLUDE_UNUSED
    1406             : int
    1407             : input_file_descriptor ()
    1408             : {
    1409             :   switch (bash_input.type)
    1410             :     {
    1411             :     case st_stream:
    1412             :       return (fileno (bash_input.location.file));
    1413             :     case st_bstream:
    1414             :       return (bash_input.location.buffered_fd);
    1415             :     case st_stdin:
    1416             :     default:
    1417             :       return (fileno (stdin));
    1418             :     }
    1419             : }
    1420             : #endif
    1421             : #endif /* BUFFERED_INPUT */
    1422             : 
    1423             : /* **************************************************************** */
    1424             : /*                                                                  */
    1425             : /*                Let input be read from readline ().               */
    1426             : /*                                                                  */
    1427             : /* **************************************************************** */
    1428             : 
    1429             : #if defined (READLINE)
    1430             : char *current_readline_prompt = (char *)NULL;
    1431             : char *current_readline_line = (char *)NULL;
    1432             : int current_readline_line_index = 0;
    1433             : 
    1434             : static int
    1435             : yy_readline_get ()
    1436             : {
    1437             :   SigHandler *old_sigint;
    1438             :   int line_len;
    1439             :   unsigned char c;
    1440             : 
    1441             :   if (current_readline_line == 0)
    1442             :     {
    1443             :       if (bash_readline_initialized == 0)
    1444             :         initialize_readline ();
    1445             : 
    1446             : #if defined (JOB_CONTROL)
    1447             :       if (job_control)
    1448             :         give_terminal_to (shell_pgrp, 0);
    1449             : #endif /* JOB_CONTROL */
    1450             : 
    1451             :       old_sigint = IMPOSSIBLE_TRAP_HANDLER;
    1452             :       if (signal_is_ignored (SIGINT) == 0)
    1453             :         {
    1454             :           /* interrupt_immediately++; */
    1455             :           old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
    1456             :         }
    1457             : 
    1458             :       sh_unset_nodelay_mode (fileno (rl_instream));     /* just in case */
    1459             :       current_readline_line = readline (current_readline_prompt ?
    1460             :                                           current_readline_prompt : "");
    1461             : 
    1462             :       CHECK_TERMSIG;
    1463             :       if (signal_is_ignored (SIGINT) == 0)
    1464             :         {
    1465             :           /* interrupt_immediately--; */
    1466             :           if (old_sigint != IMPOSSIBLE_TRAP_HANDLER)
    1467             :             set_signal_handler (SIGINT, old_sigint);
    1468             :         }
    1469             : 
    1470             : #if 0
    1471             :       /* Reset the prompt to the decoded value of prompt_string_pointer. */
    1472             :       reset_readline_prompt ();
    1473             : #endif
    1474             : 
    1475             :       if (current_readline_line == 0)
    1476             :         return (EOF);
    1477             : 
    1478             :       current_readline_line_index = 0;
    1479             :       line_len = strlen (current_readline_line);
    1480             : 
    1481             :       current_readline_line = (char *)xrealloc (current_readline_line, 2 + line_len);
    1482             :       current_readline_line[line_len++] = '\n';
    1483             :       current_readline_line[line_len] = '\0';
    1484             :     }
    1485             : 
    1486             :   if (current_readline_line[current_readline_line_index] == 0)
    1487             :     {
    1488             :       free (current_readline_line);
    1489             :       current_readline_line = (char *)NULL;
    1490             :       return (yy_readline_get ());
    1491             :     }
    1492             :   else
    1493             :     {
    1494             :       c = current_readline_line[current_readline_line_index++];
    1495             :       return (c);
    1496             :     }
    1497             : }
    1498             : 
    1499             : static int
    1500             : yy_readline_unget (c)
    1501             :      int c;
    1502             : {
    1503             :   if (current_readline_line_index && current_readline_line)
    1504             :     current_readline_line[--current_readline_line_index] = c;
    1505             :   return (c);
    1506             : }
    1507             : 
    1508             : void
    1509             : with_input_from_stdin ()
    1510             : {
    1511             :   INPUT_STREAM location;
    1512             : 
    1513             :   if (bash_input.type != st_stdin && stream_on_stack (st_stdin) == 0)
    1514             :     {
    1515             :       location.string = current_readline_line;
    1516             :       init_yy_io (yy_readline_get, yy_readline_unget,
    1517             :                   st_stdin, "readline stdin", location);
    1518             :     }
    1519             : }
    1520             : 
    1521             : #else  /* !READLINE */
    1522             : 
    1523             : void
    1524           0 : with_input_from_stdin ()
    1525             : {
    1526           0 :   with_input_from_stream (stdin, "stdin");
    1527           0 : }
    1528             : #endif  /* !READLINE */
    1529             : 
    1530             : /* **************************************************************** */
    1531             : /*                                                                  */
    1532             : /*   Let input come from STRING.  STRING is zero terminated.        */
    1533             : /*                                                                  */
    1534             : /* **************************************************************** */
    1535             : 
    1536             : static int
    1537  8275184999 : yy_string_get ()
    1538             : {
    1539  8275184999 :   register char *string;
    1540  8275184999 :   register unsigned char c;
    1541             : 
    1542  8275184999 :   string = bash_input.location.string;
    1543             : 
    1544             :   /* If the string doesn't exist, or is empty, EOF found. */
    1545  8275184999 :   if (string && *string)
    1546             :     {
    1547  8275173897 :       c = *string++;
    1548  8275173897 :       bash_input.location.string = string;
    1549  8275173897 :       return (c);
    1550             :     }
    1551             :   else
    1552             :     return (EOF);
    1553             : }
    1554             : 
    1555             : static int
    1556           0 : yy_string_unget (c)
    1557             :      int c;
    1558             : {
    1559           0 :   *(--bash_input.location.string) = c;
    1560           0 :   return (c);
    1561             : }
    1562             : 
    1563             : void
    1564    19096500 : with_input_from_string (string, name)
    1565             :      char *string;
    1566             :      const char *name;
    1567             : {
    1568    19096537 :   INPUT_STREAM location;
    1569             : 
    1570    19096537 :   location.string = string;
    1571    19096500 :   init_yy_io (yy_string_get, yy_string_unget, st_string, name, location);
    1572    19096500 : }
    1573             : 
    1574             : /* Count the number of characters we've consumed from bash_input.location.string
    1575             :    and read into shell_input_line, but have not returned from shell_getc.
    1576             :    That is the true input location.  Rewind bash_input.location.string by
    1577             :    that number of characters, so it points to the last character actually
    1578             :    consumed by the parser. */
    1579             : static void
    1580             : rewind_input_string ()
    1581             : {
    1582          72 :   int xchars;
    1583             : 
    1584             :   /* number of unconsumed characters in the input -- XXX need to take newlines
    1585             :      into account, e.g., $(...\n) */
    1586          72 :   xchars = shell_input_line_len - shell_input_line_index;
    1587           9 :   if (bash_input.location.string[-1] == '\n')
    1588          27 :     xchars++;
    1589             : 
    1590             :   /* XXX - how to reflect bash_input.location.string back to string passed to
    1591             :      parse_and_execute or xparse_dolparen?  xparse_dolparen needs to know how
    1592             :      far into the string we parsed.  parse_and_execute knows where bash_input.
    1593             :      location.string is, and how far from orig_string that is -- that's the
    1594             :      number of characters the command consumed. */
    1595             : 
    1596             :   /* bash_input.location.string - xchars should be where we parsed to */
    1597             :   /* need to do more validation on xchars value for sanity -- test cases. */
    1598          72 :   bash_input.location.string -= xchars;
    1599             : }
    1600             : 
    1601             : /* **************************************************************** */
    1602             : /*                                                                  */
    1603             : /*                   Let input come from STREAM.                    */
    1604             : /*                                                                  */
    1605             : /* **************************************************************** */
    1606             : 
    1607             : /* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS
    1608             :    define, and just use getc/ungetc if it was defined, but since bash
    1609             :    installs its signal handlers without the SA_RESTART flag, some signals
    1610             :    (like SIGCHLD, SIGWINCH, etc.) received during a read(2) will not cause
    1611             :    the read to be restarted.  We need to restart it ourselves. */
    1612             : 
    1613             : static int
    1614           0 : yy_stream_get ()
    1615             : {
    1616           0 :   int result;
    1617             : 
    1618           0 :   result = EOF;
    1619           0 :   if (bash_input.location.file)
    1620             :     {
    1621             : #if 0
    1622             :       if (interactive)
    1623             :         interrupt_immediately++;
    1624             : #endif
    1625             : 
    1626             :       /* XXX - don't need terminate_immediately; getc_with_restart checks
    1627             :          for terminating signals itself if read returns < 0 */
    1628           0 :       result = getc_with_restart (bash_input.location.file);
    1629             : 
    1630             : #if 0
    1631             :       if (interactive)
    1632             :         interrupt_immediately--;
    1633             : #endif
    1634             :     }
    1635           0 :   return (result);
    1636             : }
    1637             : 
    1638             : static int
    1639           0 : yy_stream_unget (c)
    1640             :      int c;
    1641             : {
    1642           0 :   return (ungetc_with_restart (c, bash_input.location.file));
    1643             : }
    1644             : 
    1645             : void
    1646           0 : with_input_from_stream (stream, name)
    1647             :      FILE *stream;
    1648             :      const char *name;
    1649             : {
    1650           0 :   INPUT_STREAM location;
    1651             : 
    1652           0 :   location.file = stream;
    1653           0 :   init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location);
    1654           0 : }
    1655             : 
    1656             : typedef struct stream_saver {
    1657             :   struct stream_saver *next;
    1658             :   BASH_INPUT bash_input;
    1659             :   int line;
    1660             : #if defined (BUFFERED_INPUT)
    1661             :   BUFFERED_STREAM *bstream;
    1662             : #endif /* BUFFERED_INPUT */
    1663             : } STREAM_SAVER;
    1664             : 
    1665             : /* The globally known line number. */
    1666             : int line_number = 0;
    1667             : 
    1668             : /* The line number offset set by assigning to LINENO.  Not currently used. */
    1669             : int line_number_base = 0;
    1670             : 
    1671             : #if defined (COND_COMMAND)
    1672             : static int cond_lineno;
    1673             : static int cond_token;
    1674             : #endif
    1675             : 
    1676             : STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL;
    1677             : 
    1678             : void
    1679    19096537 : push_stream (reset_lineno)
    1680             :      int reset_lineno;
    1681             : {
    1682    19096537 :   STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER));
    1683             : 
    1684    19096537 :   xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT));
    1685             : 
    1686             : #if defined (BUFFERED_INPUT)
    1687    19096537 :   saver->bstream = (BUFFERED_STREAM *)NULL;
    1688             :   /* If we have a buffered stream, clear out buffers[fd]. */
    1689    19096537 :   if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
    1690       10615 :     saver->bstream = set_buffered_stream (bash_input.location.buffered_fd,
    1691             :                                           (BUFFERED_STREAM *)NULL);
    1692             : #endif /* BUFFERED_INPUT */
    1693             : 
    1694    19096537 :   saver->line = line_number;
    1695    19096537 :   bash_input.name = (char *)NULL;
    1696    19096537 :   saver->next = stream_list;
    1697    19096537 :   stream_list = saver;
    1698    19096537 :   EOF_Reached = 0;
    1699    19096537 :   if (reset_lineno)
    1700    19086024 :     line_number = 0;
    1701    19096537 : }
    1702             : 
    1703             : void
    1704    19094658 : pop_stream ()
    1705             : {
    1706    19094658 :   if (!stream_list)
    1707           0 :     EOF_Reached = 1;
    1708             :   else
    1709             :     {
    1710    19094658 :       STREAM_SAVER *saver = stream_list;
    1711             : 
    1712    19094658 :       EOF_Reached = 0;
    1713    19094658 :       stream_list = stream_list->next;
    1714             : 
    1715    38189316 :       init_yy_io (saver->bash_input.getter,
    1716             :                   saver->bash_input.ungetter,
    1717             :                   saver->bash_input.type,
    1718    19094658 :                   saver->bash_input.name,
    1719             :                   saver->bash_input.location);
    1720             : 
    1721             : #if defined (BUFFERED_INPUT)
    1722             :       /* If we have a buffered stream, restore buffers[fd]. */
    1723             :       /* If the input file descriptor was changed while this was on the
    1724             :          save stack, update the buffered fd to the new file descriptor and
    1725             :          re-establish the buffer <-> bash_input fd correspondence. */
    1726    19094658 :       if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
    1727             :         {
    1728        8736 :           if (bash_input_fd_changed)
    1729             :             {
    1730           0 :               bash_input_fd_changed = 0;
    1731           0 :               if (default_buffered_input >= 0)
    1732             :                 {
    1733           0 :                   bash_input.location.buffered_fd = default_buffered_input;
    1734           0 :                   saver->bstream->b_fd = default_buffered_input;
    1735           0 :                   SET_CLOSE_ON_EXEC (default_buffered_input);
    1736             :                 }
    1737             :             }
    1738             :           /* XXX could free buffered stream returned as result here. */
    1739        8736 :           set_buffered_stream (bash_input.location.buffered_fd, saver->bstream);
    1740             :         }
    1741             : #endif /* BUFFERED_INPUT */
    1742             : 
    1743    19094658 :       line_number = saver->line;
    1744             : 
    1745    19094658 :       FREE (saver->bash_input.name);
    1746    19094658 :       free (saver);
    1747             :     }
    1748    19094658 : }
    1749             : 
    1750             : /* Return 1 if a stream of type TYPE is saved on the stack. */
    1751             : int
    1752           0 : stream_on_stack (type)
    1753             :      enum stream_type type;
    1754             : {
    1755           0 :   register STREAM_SAVER *s;
    1756             : 
    1757           0 :   for (s = stream_list; s; s = s->next)
    1758           0 :     if (s->bash_input.type == type)
    1759             :       return 1;
    1760             :   return 0;
    1761             : }
    1762             : 
    1763             : /* Save the current token state and return it in a malloced array. */
    1764             : int *
    1765          81 : save_token_state ()
    1766             : {
    1767          81 :   int *ret;
    1768             : 
    1769          81 :   ret = (int *)xmalloc (4 * sizeof (int));
    1770          81 :   ret[0] = last_read_token;
    1771          81 :   ret[1] = token_before_that;
    1772          81 :   ret[2] = two_tokens_ago;
    1773          81 :   ret[3] = current_token;
    1774          81 :   return ret;
    1775             : }
    1776             : 
    1777             : void
    1778           0 : restore_token_state (ts)
    1779             :      int *ts;
    1780             : {
    1781           0 :   if (ts == 0)
    1782             :     return;
    1783          81 :   last_read_token = ts[0];
    1784          81 :   token_before_that = ts[1];
    1785          81 :   two_tokens_ago = ts[2];
    1786           0 :   current_token = ts[3];
    1787             : }
    1788             : 
    1789             : /*
    1790             :  * This is used to inhibit alias expansion and reserved word recognition
    1791             :  * inside case statement pattern lists.  A `case statement pattern list' is:
    1792             :  *
    1793             :  *      everything between the `in' in a `case word in' and the next ')'
    1794             :  *      or `esac'
    1795             :  *      everything between a `;;' and the next `)' or `esac'
    1796             :  */
    1797             : 
    1798             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    1799             : 
    1800             : #define END_OF_ALIAS 0
    1801             : 
    1802             : /*
    1803             :  * Pseudo-global variables used in implementing token-wise alias expansion.
    1804             :  */
    1805             : 
    1806             : /*
    1807             :  * Pushing and popping strings.  This works together with shell_getc to
    1808             :  * implement alias expansion on a per-token basis.
    1809             :  */
    1810             : 
    1811             : #define PSH_ALIAS       0x01
    1812             : #define PSH_DPAREN      0x02
    1813             : #define PSH_SOURCE      0x04
    1814             : 
    1815             : typedef struct string_saver {
    1816             :   struct string_saver *next;
    1817             :   int expand_alias;  /* Value to set expand_alias to when string is popped. */
    1818             :   char *saved_line;
    1819             : #if defined (ALIAS)
    1820             :   alias_t *expander;   /* alias that caused this line to be pushed. */
    1821             : #endif
    1822             :   size_t saved_line_size, saved_line_index;
    1823             :   int saved_line_terminator;
    1824             :   int flags;
    1825             : } STRING_SAVER;
    1826             : 
    1827             : STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL;
    1828             : 
    1829             : /*
    1830             :  * Push the current shell_input_line onto a stack of such lines and make S
    1831             :  * the current input.  Used when expanding aliases.  EXPAND is used to set
    1832             :  * the value of expand_next_token when the string is popped, so that the
    1833             :  * word after the alias in the original line is handled correctly when the
    1834             :  * alias expands to multiple words.  TOKEN is the token that was expanded
    1835             :  * into S; it is saved and used to prevent infinite recursive expansion.
    1836             :  */
    1837             : static void
    1838          54 : push_string (s, expand, ap)
    1839             :      char *s;
    1840             :      int expand;
    1841             :      alias_t *ap;
    1842             : {
    1843          54 :   STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER));
    1844             : 
    1845          54 :   temp->expand_alias = expand;
    1846          54 :   temp->saved_line = shell_input_line;
    1847          54 :   temp->saved_line_size = shell_input_line_size;
    1848          54 :   temp->saved_line_index = shell_input_line_index;
    1849          54 :   temp->saved_line_terminator = shell_input_line_terminator;
    1850          54 :   temp->flags = 0;
    1851             : #if defined (ALIAS)
    1852          54 :   temp->expander = ap;
    1853          54 :   if (ap)
    1854           0 :     temp->flags = PSH_ALIAS;
    1855             : #endif
    1856          54 :   temp->next = pushed_string_list;
    1857          54 :   pushed_string_list = temp;
    1858             : 
    1859             : #if defined (ALIAS)
    1860          54 :   if (ap)
    1861           0 :     ap->flags |= AL_BEINGEXPANDED;
    1862             : #endif
    1863             : 
    1864          54 :   shell_input_line = s;
    1865          54 :   shell_input_line_size = STRLEN (s);
    1866          54 :   shell_input_line_index = 0;
    1867          54 :   shell_input_line_terminator = '\0';
    1868             : #if 0
    1869             :   parser_state &= ~PST_ALEXPNEXT;   /* XXX */
    1870             : #endif
    1871             : 
    1872          54 :   set_line_mbstate ();
    1873          54 : }
    1874             : 
    1875             : /*
    1876             :  * Make the top of the pushed_string stack be the current shell input.
    1877             :  * Only called when there is something on the stack.  Called from shell_getc
    1878             :  * when it thinks it has consumed the string generated by an alias expansion
    1879             :  * and needs to return to the original input line.
    1880             :  */
    1881             : static void
    1882           0 : pop_string ()
    1883             : {
    1884           0 :   STRING_SAVER *t;
    1885             : 
    1886           0 :   FREE (shell_input_line);
    1887           0 :   shell_input_line = pushed_string_list->saved_line;
    1888           0 :   shell_input_line_index = pushed_string_list->saved_line_index;
    1889           0 :   shell_input_line_size = pushed_string_list->saved_line_size;
    1890           0 :   shell_input_line_terminator = pushed_string_list->saved_line_terminator;
    1891             : 
    1892           0 :   if (pushed_string_list->expand_alias)
    1893           0 :     parser_state |= PST_ALEXPNEXT;
    1894             :   else
    1895           0 :     parser_state &= ~PST_ALEXPNEXT;
    1896             : 
    1897           0 :   t = pushed_string_list;
    1898           0 :   pushed_string_list = pushed_string_list->next;
    1899             : 
    1900             : #if defined (ALIAS)
    1901           0 :   if (t->expander)
    1902           0 :     t->expander->flags &= ~AL_BEINGEXPANDED;
    1903             : #endif
    1904             : 
    1905           0 :   free ((char *)t);
    1906             : 
    1907           0 :   set_line_mbstate ();
    1908           0 : }
    1909             : 
    1910             : static void
    1911       10399 : free_string_list ()
    1912             : {
    1913       10399 :   register STRING_SAVER *t, *t1;
    1914             : 
    1915       10453 :   for (t = pushed_string_list; t; )
    1916             :     {
    1917          54 :       t1 = t->next;
    1918          54 :       FREE (t->saved_line);
    1919             : #if defined (ALIAS)
    1920          54 :       if (t->expander)
    1921           0 :         t->expander->flags &= ~AL_BEINGEXPANDED;
    1922             : #endif
    1923          54 :       free ((char *)t);
    1924          54 :       t = t1;
    1925             :     }
    1926       10399 :   pushed_string_list = (STRING_SAVER *)NULL;
    1927       10399 : }
    1928             : 
    1929             : #endif /* ALIAS || DPAREN_ARITHMETIC */
    1930             : 
    1931             : void
    1932       10381 : free_pushed_string_input ()
    1933             : {
    1934             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    1935       10381 :   free_string_list ();
    1936             : #endif
    1937       10381 : }
    1938             : 
    1939             : int
    1940    38193000 : parser_expanding_alias ()
    1941             : {
    1942    38193000 :   return (expanding_alias ());
    1943             : }
    1944             : 
    1945             : void
    1946           0 : parser_save_alias ()
    1947             : {
    1948             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    1949           0 :   push_string ((char *)NULL, 0, (alias_t *)NULL);
    1950           0 :   pushed_string_list->flags = PSH_SOURCE;    /* XXX - for now */
    1951             : #else
    1952             :   ;
    1953             : #endif
    1954           0 : }
    1955             : 
    1956             : void
    1957           0 : parser_restore_alias ()
    1958             : {
    1959             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    1960           0 :   if (pushed_string_list)
    1961           0 :     pop_string ();
    1962             : #else
    1963             :   ;
    1964             : #endif
    1965           0 : }
    1966             : 
    1967             : void
    1968    19096419 : clear_shell_input_line ()
    1969             : {
    1970    19096419 :   if (shell_input_line)
    1971     9553449 :     shell_input_line[shell_input_line_index = 0] = '\0';
    1972    19096419 : }
    1973             : 
    1974             : /* Return a line of text, taken from wherever yylex () reads input.
    1975             :    If there is no more input, then we return NULL.  If REMOVE_QUOTED_NEWLINE
    1976             :    is non-zero, we remove unquoted \<newline> pairs.  This is used by
    1977             :    read_secondary_line to read here documents. */
    1978             : static char *
    1979        1789 : read_a_line (remove_quoted_newline)
    1980             :      int remove_quoted_newline;
    1981             : {
    1982        1789 :   static char *line_buffer = (char *)NULL;
    1983        1789 :   static int buffer_size = 0;
    1984        1789 :   int indx, c, peekc, pass_next;
    1985             : 
    1986             : #if defined (READLINE)
    1987             :   if (no_line_editing && SHOULD_PROMPT ())
    1988             : #else
    1989        1789 :   if (SHOULD_PROMPT ())
    1990             : #endif
    1991           0 :     print_prompt ();
    1992             : 
    1993             :   pass_next = indx = 0;
    1994       26248 :   while (1)
    1995             :     {
    1996             :       /* Allow immediate exit if interrupted during input. */
    1997       26248 :       QUIT;
    1998             : 
    1999       26248 :       c = yy_getc ();
    2000             : 
    2001             :       /* Ignore null bytes in input. */
    2002       26248 :       if (c == 0)
    2003             :         {
    2004             : #if 0
    2005             :           internal_warning ("read_a_line: ignored null byte in input");
    2006             : #endif
    2007             :           continue;
    2008             :         }
    2009             : 
    2010             :       /* If there is no more input, then we return NULL. */
    2011       25763 :       if (c == EOF)
    2012             :         {
    2013         336 :           if (interactive && bash_input.type == st_stream)
    2014           0 :             clearerr (stdin);
    2015         336 :           if (indx == 0)
    2016             :             return ((char *)NULL);
    2017             :           c = '\n';
    2018             :         }
    2019             : 
    2020             :       /* `+2' in case the final character in the buffer is a newline. */
    2021       25585 :       RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128);
    2022             : 
    2023             :       /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a
    2024             :          here document with an unquoted delimiter.  In this case,
    2025             :          the line will be expanded as if it were in double quotes.
    2026             :          We allow a backslash to escape the next character, but we
    2027             :          need to treat the backslash specially only if a backslash
    2028             :          quoting a backslash-newline pair appears in the line. */
    2029       25478 :       if (pass_next)
    2030             :         {
    2031          43 :           line_buffer[indx++] = c;
    2032          43 :           pass_next = 0;
    2033             :         }
    2034       25435 :       else if (c == '\\' && remove_quoted_newline)
    2035             :         {
    2036          43 :           QUIT;
    2037          43 :           peekc = yy_getc ();
    2038          43 :           if (peekc == '\n')
    2039             :             {
    2040           0 :               line_number++;
    2041           0 :               continue; /* Make the unquoted \<newline> pair disappear. */
    2042             :             }
    2043             :           else
    2044             :             {
    2045          43 :               yy_ungetc (peekc);
    2046          43 :               pass_next = 1;
    2047          43 :               line_buffer[indx++] = c;          /* Preserve the backslash. */
    2048             :             }
    2049             :         }
    2050             :       else
    2051       25392 :         line_buffer[indx++] = c;
    2052             : 
    2053       25478 :       if (c == '\n')
    2054             :         {
    2055        1504 :           line_buffer[indx] = '\0';
    2056        1504 :           return (line_buffer);
    2057             :         }
    2058             :     }
    2059             : }
    2060             : 
    2061             : /* Return a line as in read_a_line (), but insure that the prompt is
    2062             :    the secondary prompt.  This is used to read the lines of a here
    2063             :    document.  REMOVE_QUOTED_NEWLINE is non-zero if we should remove
    2064             :    newlines quoted with backslashes while reading the line.  It is
    2065             :    non-zero unless the delimiter of the here document was quoted. */
    2066             : char *
    2067        1789 : read_secondary_line (remove_quoted_newline)
    2068             :      int remove_quoted_newline;
    2069             : {
    2070        1789 :   char *ret;
    2071             : 
    2072        1789 :   prompt_string_pointer = &ps2_prompt;
    2073        1789 :   if (SHOULD_PROMPT())
    2074           0 :     prompt_again ();
    2075        1789 :   ret = read_a_line (remove_quoted_newline);
    2076             : #if defined (HISTORY)
    2077             :   if (ret && remember_on_history && (parser_state & PST_HEREDOC))
    2078             :     {
    2079             :       /* To make adding the here-document body right, we need to rely on
    2080             :          history_delimiting_chars() returning \n for the first line of the
    2081             :          here-document body and the null string for the second and subsequent
    2082             :          lines, so we avoid double newlines.
    2083             :          current_command_line_count == 2 for the first line of the body. */
    2084             : 
    2085             :       current_command_line_count++;
    2086             :       maybe_add_history (ret);
    2087             :     }
    2088             : #endif /* HISTORY */
    2089        1789 :   return ret;
    2090             : }
    2091             : 
    2092             : /* **************************************************************** */
    2093             : /*                                                                  */
    2094             : /*                              YYLEX ()                            */
    2095             : /*                                                                  */
    2096             : /* **************************************************************** */
    2097             : 
    2098             : /* Reserved words.  These are only recognized as the first word of a
    2099             :    command. */
    2100             : STRING_INT_ALIST word_token_alist[] = {
    2101             :   { "if", IF },
    2102             :   { "then", THEN },
    2103             :   { "else", ELSE },
    2104             :   { "elif", ELIF },
    2105             :   { "fi", FI },
    2106             :   { "case", CASE },
    2107             :   { "esac", ESAC },
    2108             :   { "for", FOR },
    2109             : #if defined (SELECT_COMMAND)
    2110             :   { "select", SELECT },
    2111             : #endif
    2112             :   { "while", WHILE },
    2113             :   { "until", UNTIL },
    2114             :   { "do", DO },
    2115             :   { "done", DONE },
    2116             :   { "in", IN },
    2117             :   { "function", FUNCTION },
    2118             : #if defined (COMMAND_TIMING)
    2119             :   { "time", TIME },
    2120             : #endif
    2121             :   { "{", '{' },
    2122             :   { "}", '}' },
    2123             :   { "!", BANG },
    2124             : #if defined (COND_COMMAND)
    2125             :   { "[[", COND_START },
    2126             :   { "]]", COND_END },
    2127             : #endif
    2128             : #if defined (COPROCESS_SUPPORT)
    2129             :   { "coproc", COPROC },
    2130             : #endif
    2131             :   { (char *)NULL, 0}
    2132             : };
    2133             : 
    2134             : /* other tokens that can be returned by read_token() */
    2135             : STRING_INT_ALIST other_token_alist[] = {
    2136             :   /* Multiple-character tokens with special values */
    2137             :   { "--", TIMEIGN },
    2138             :   { "-p", TIMEOPT },
    2139             :   { "&&", AND_AND },
    2140             :   { "||", OR_OR },
    2141             :   { ">>", GREATER_GREATER },
    2142             :   { "<<", LESS_LESS },
    2143             :   { "<&", LESS_AND },
    2144             :   { ">&", GREATER_AND },
    2145             :   { ";;", SEMI_SEMI },
    2146             :   { ";&", SEMI_AND },
    2147             :   { ";;&", SEMI_SEMI_AND },
    2148             :   { "<<-", LESS_LESS_MINUS },
    2149             :   { "<<<", LESS_LESS_LESS },
    2150             :   { "&>", AND_GREATER },
    2151             :   { "&>>", AND_GREATER_GREATER },
    2152             :   { "<>", LESS_GREATER },
    2153             :   { ">|", GREATER_BAR },
    2154             :   { "|&", BAR_AND },
    2155             :   { "EOF", yacc_EOF },
    2156             :   /* Tokens whose value is the character itself */
    2157             :   { ">", '>' },
    2158             :   { "<", '<' },
    2159             :   { "-", '-' },
    2160             :   { "{", '{' },
    2161             :   { "}", '}' },
    2162             :   { ";", ';' },
    2163             :   { "(", '(' },
    2164             :   { ")", ')' },
    2165             :   { "|", '|' },
    2166             :   { "&", '&' },
    2167             :   { "newline", '\n' },
    2168             :   { (char *)NULL, 0}
    2169             : };
    2170             : 
    2171             : /* others not listed here:
    2172             :         WORD                    look at yylval.word
    2173             :         ASSIGNMENT_WORD         look at yylval.word
    2174             :         NUMBER                  look at yylval.number
    2175             :         ARITH_CMD               look at yylval.word_list
    2176             :         ARITH_FOR_EXPRS         look at yylval.word_list
    2177             :         COND_CMD                look at yylval.command
    2178             : */
    2179             : 
    2180             : /* These are used by read_token_word, but appear up here so that shell_getc
    2181             :    can use them to decide when to add otherwise blank lines to the history. */
    2182             : 
    2183             : /* The primary delimiter stack. */
    2184             : struct dstack dstack = {  (char *)NULL, 0, 0 };
    2185             : 
    2186             : /* A temporary delimiter stack to be used when decoding prompt strings.
    2187             :    This is needed because command substitutions in prompt strings (e.g., PS2)
    2188             :    can screw up the parser's quoting state. */
    2189             : static struct dstack temp_dstack = { (char *)NULL, 0, 0 };
    2190             : 
    2191             : /* Macro for accessing the top delimiter on the stack.  Returns the
    2192             :    delimiter or zero if none. */
    2193             : #define current_delimiter(ds) \
    2194             :   (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0)
    2195             : 
    2196             : #define push_delimiter(ds, character) \
    2197             :   do \
    2198             :     { \
    2199             :       if (ds.delimiter_depth + 2 > ds.delimiter_space) \
    2200             :         ds.delimiters = (char *)xrealloc \
    2201             :           (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \
    2202             :       ds.delimiters[ds.delimiter_depth] = character; \
    2203             :       ds.delimiter_depth++; \
    2204             :     } \
    2205             :   while (0)
    2206             : 
    2207             : #define pop_delimiter(ds)       ds.delimiter_depth--
    2208             : 
    2209             : /* Return the next shell input character.  This always reads characters
    2210             :    from shell_input_line; when that line is exhausted, it is time to
    2211             :    read the next line.  This is called by read_token when the shell is
    2212             :    processing normal command input. */
    2213             : 
    2214             : /* This implements one-character lookahead/lookbehind across physical input
    2215             :    lines, to avoid something being lost because it's pushed back with
    2216             :    shell_ungetc when we're at the start of a line. */
    2217             : static int eol_ungetc_lookahead = 0;
    2218             : 
    2219             : static int
    2220 16662975830 : shell_getc (remove_quoted_newline)
    2221             :      int remove_quoted_newline;
    2222             : {
    2223 16662975830 :   register int i;
    2224 16662975830 :   int c, truncating, last_was_backslash;
    2225 16662975830 :   unsigned char uc;
    2226             : 
    2227 16662975830 :   QUIT;
    2228             : 
    2229 16662975830 :   last_was_backslash = 0;
    2230 16662975830 :   if (sigwinch_received)
    2231             :     {
    2232           0 :       sigwinch_received = 0;
    2233           0 :       get_new_window_size (0, (int *)0, (int *)0);
    2234             :     }
    2235             :       
    2236 16662975830 :   if (eol_ungetc_lookahead)
    2237             :     {
    2238         223 :       c = eol_ungetc_lookahead;
    2239         223 :       eol_ungetc_lookahead = 0;
    2240         223 :       return (c);
    2241             :     }
    2242             : 
    2243             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    2244             :   /* If shell_input_line[shell_input_line_index] == 0, but there is
    2245             :      something on the pushed list of strings, then we don't want to go
    2246             :      off and get another line.  We let the code down below handle it. */
    2247             : 
    2248 16662975607 :   if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) &&
    2249   808888645 :                             (pushed_string_list == (STRING_SAVER *)NULL)))
    2250             : #else /* !ALIAS && !DPAREN_ARITHMETIC */
    2251             :   if (!shell_input_line || !shell_input_line[shell_input_line_index])
    2252             : #endif /* !ALIAS && !DPAREN_ARITHMETIC */
    2253             :     {
    2254   818431936 :       line_number++;
    2255             : 
    2256             :       /* Let's not let one really really long line blow up memory allocation */
    2257   818431936 :       if (shell_input_line && shell_input_line_size >= 32768)
    2258             :         {
    2259           0 :           free (shell_input_line);
    2260           0 :           shell_input_line = 0;
    2261           0 :           shell_input_line_size = 0;
    2262             :         }
    2263             : 
    2264   818431936 :     restart_read:
    2265             : 
    2266             :       /* Allow immediate exit if interrupted during input. */
    2267   818432675 :       QUIT;
    2268             : 
    2269   818432675 :       i = truncating = 0;
    2270   818432675 :       shell_input_line_terminator = 0;
    2271             : 
    2272             :       /* If the shell is interatctive, but not currently printing a prompt
    2273             :          (interactive_shell && interactive == 0), we don't want to print
    2274             :          notifies or cleanup the jobs -- we want to defer it until we do
    2275             :          print the next prompt. */
    2276   818432675 :       if (interactive_shell == 0 || SHOULD_PROMPT())
    2277             :         {
    2278             : #if defined (JOB_CONTROL)
    2279             :       /* This can cause a problem when reading a command as the result
    2280             :          of a trap, when the trap is called from flush_child.  This call
    2281             :          had better not cause jobs to disappear from the job table in
    2282             :          that case, or we will have big trouble. */
    2283   818432675 :           notify_and_cleanup ();
    2284             : #else /* !JOB_CONTROL */
    2285             :           cleanup_dead_jobs ();
    2286             : #endif /* !JOB_CONTROL */
    2287             :         }
    2288             : 
    2289             : #if defined (READLINE)
    2290             :       if (no_line_editing && SHOULD_PROMPT())
    2291             : #else
    2292   818432675 :       if (SHOULD_PROMPT())
    2293             : #endif
    2294           0 :         print_prompt ();
    2295             : 
    2296   818432675 :       if (bash_input.type == st_stream)
    2297           0 :         clearerr (stdin);
    2298             : 
    2299 15269757971 :       while (1)
    2300             :         {
    2301 15269757971 :           c = yy_getc ();
    2302             : 
    2303             :           /* Allow immediate exit if interrupted during input. */
    2304 15269757971 :           QUIT;
    2305             : 
    2306 15269757971 :           if (c == '\0')
    2307             :             {
    2308             : #if 0
    2309             :               internal_warning ("shell_getc: ignored null byte in input");
    2310             : #endif
    2311             :               continue;
    2312             :             }
    2313             : 
    2314             :           /* Theoretical overflow */
    2315             :           /* If we can't put 256 bytes more into the buffer, allocate
    2316             :              everything we can and fill it as full as we can. */
    2317             :           /* XXX - we ignore rest of line using `truncating' flag */
    2318 15203272930 :           if (shell_input_line_size > (SIZE_MAX - 256))
    2319             :             {
    2320           0 :               size_t n;
    2321             : 
    2322           0 :               n = SIZE_MAX - i; /* how much more can we put into the buffer? */
    2323           0 :               if (n <= 2)    /* we have to save 1 for the newline added below */
    2324             :                 {
    2325           0 :                   if (truncating == 0)
    2326           0 :                     internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX);
    2327           0 :                   shell_input_line[i] = '\0';
    2328           0 :                   truncating = 1;
    2329             :                 }
    2330           0 :               if (shell_input_line_size < SIZE_MAX)
    2331             :                 {
    2332           0 :                   shell_input_line_size = SIZE_MAX;
    2333           0 :                   shell_input_line = xrealloc (shell_input_line, shell_input_line_size);
    2334             :                 }
    2335             :             }
    2336             :           else
    2337 15213779532 :             RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256);
    2338             : 
    2339 15203272930 :           if (c == EOF)
    2340             :             {
    2341     1497289 :               if (bash_input.type == st_stream)
    2342           0 :                 clearerr (stdin);
    2343             : 
    2344     1497289 :               if (i == 0)
    2345      433218 :                 shell_input_line_terminator = EOF;
    2346             : 
    2347     1497289 :               shell_input_line[i] = '\0';
    2348     1497289 :               break;
    2349             :             }
    2350             : 
    2351 15201775641 :           if (truncating == 0 || c == '\n')
    2352 15201775641 :             shell_input_line[i++] = c;
    2353             : 
    2354 15201775641 :           if (c == '\n')
    2355             :             {
    2356   816935386 :               shell_input_line[--i] = '\0';
    2357   816935386 :               current_command_line_count++;
    2358   816935386 :               break;
    2359             :             }
    2360             : 
    2361 14384840255 :           last_was_backslash = last_was_backslash == 0 && c == '\\';
    2362             :         }
    2363             : 
    2364   818432675 :       shell_input_line_index = 0;
    2365   818432675 :       shell_input_line_len = i;         /* == strlen (shell_input_line) */
    2366             : 
    2367   818432675 :       set_line_mbstate ();
    2368             : 
    2369             : #if defined (HISTORY)
    2370             :       if (remember_on_history && shell_input_line && shell_input_line[0])
    2371             :         {
    2372             :           char *expansions;
    2373             : #  if defined (BANG_HISTORY)
    2374             :           int old_hist;
    2375             : 
    2376             :           /* If the current delimiter is a single quote, we should not be
    2377             :              performing history expansion, even if we're on a different
    2378             :              line from the original single quote. */
    2379             :           old_hist = history_expansion_inhibited;
    2380             :           if (current_delimiter (dstack) == '\'')
    2381             :             history_expansion_inhibited = 1;
    2382             : #  endif
    2383             :           /* Calling with a third argument of 1 allows remember_on_history to
    2384             :              determine whether or not the line is saved to the history list */
    2385             :           expansions = pre_process_line (shell_input_line, 1, 1);
    2386             : #  if defined (BANG_HISTORY)
    2387             :           history_expansion_inhibited = old_hist;
    2388             : #  endif
    2389             :           if (expansions != shell_input_line)
    2390             :             {
    2391             :               free (shell_input_line);
    2392             :               shell_input_line = expansions;
    2393             :               shell_input_line_len = shell_input_line ?
    2394             :                                         strlen (shell_input_line) : 0;
    2395             :               if (shell_input_line_len == 0)
    2396             :                 current_command_line_count--;
    2397             : 
    2398             :               /* We have to force the xrealloc below because we don't know
    2399             :                  the true allocated size of shell_input_line anymore. */
    2400             :               shell_input_line_size = shell_input_line_len;
    2401             : 
    2402             :               set_line_mbstate ();
    2403             :             }
    2404             :         }
    2405             :       /* Try to do something intelligent with blank lines encountered while
    2406             :          entering multi-line commands.  XXX - this is grotesque */
    2407             :       else if (remember_on_history && shell_input_line &&
    2408             :                shell_input_line[0] == '\0' &&
    2409             :                current_command_line_count > 1)
    2410             :         {
    2411             :           if (current_delimiter (dstack))
    2412             :             /* We know shell_input_line[0] == 0 and we're reading some sort of
    2413             :                quoted string.  This means we've got a line consisting of only
    2414             :                a newline in a quoted string.  We want to make sure this line
    2415             :                gets added to the history. */
    2416             :             maybe_add_history (shell_input_line);
    2417             :           else
    2418             :             {
    2419             :               char *hdcs;
    2420             :               hdcs = history_delimiting_chars (shell_input_line);
    2421             :               if (hdcs && hdcs[0] == ';')
    2422             :                 maybe_add_history (shell_input_line);
    2423             :             }
    2424             :         }
    2425             : 
    2426             : #endif /* HISTORY */
    2427             : 
    2428   818432675 :       if (shell_input_line)
    2429             :         {
    2430             :           /* Lines that signify the end of the shell's input should not be
    2431             :              echoed.  We should not echo lines while parsing command
    2432             :              substitutions with recursive calls into the parsing engine; those
    2433             :              should only be echoed once when we read the word.  That is the
    2434             :              reason for the test against shell_eof_token, which is set to a
    2435             :              right paren when parsing the contents of command substitutions. */
    2436   818432675 :           if (echo_input_at_read && (shell_input_line[0] ||
    2437           0 :                                        shell_input_line_terminator != EOF) &&
    2438           0 :                                      shell_eof_token == 0)
    2439           0 :             fprintf (stderr, "%s\n", shell_input_line);
    2440             :         }
    2441             :       else
    2442             :         {
    2443           0 :           shell_input_line_size = 0;
    2444           0 :           prompt_string_pointer = &current_prompt_string;
    2445           0 :           if (SHOULD_PROMPT ())
    2446           0 :             prompt_again ();
    2447           0 :           goto restart_read;
    2448             :         }
    2449             : 
    2450             :       /* Add the newline to the end of this string, iff the string does
    2451             :          not already end in an EOF character.  */
    2452   818432675 :       if (shell_input_line_terminator != EOF)
    2453             :         {
    2454   817999457 :           if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size))
    2455           0 :             shell_input_line = (char *)xrealloc (shell_input_line,
    2456           0 :                                         1 + (shell_input_line_size += 2));
    2457             : 
    2458             :           /* Don't add a newline to a string that ends with a backslash if we're
    2459             :              going to be removing quoted newlines, since that will eat the
    2460             :              backslash.  Add another backslash instead (will be removed by
    2461             :              word expansion). */
    2462   817999457 :           if (bash_input.type == st_string && expanding_alias() == 0 && last_was_backslash && c == EOF && remove_quoted_newline)
    2463           0 :             shell_input_line[shell_input_line_len] = '\\';
    2464             :           else
    2465   817999457 :             shell_input_line[shell_input_line_len] = '\n';
    2466   817999457 :           shell_input_line[shell_input_line_len + 1] = '\0';
    2467             : 
    2468   817999457 :           set_line_mbstate ();
    2469             :         }
    2470             :     }
    2471             : 
    2472 16662976346 : next_alias_char:
    2473 16662976346 :   uc = shell_input_line[shell_input_line_index];
    2474             : 
    2475 16662976346 :   if (uc)
    2476 16662543128 :     shell_input_line_index++;
    2477             : 
    2478             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    2479             :   /* If UC is NULL, we have reached the end of the current input string.  If
    2480             :      pushed_string_list is non-empty, it's time to pop to the previous string
    2481             :      because we have fully consumed the result of the last alias expansion.
    2482             :      Do it transparently; just return the next character of the string popped
    2483             :      to. */
    2484             :   /* If pushed_string_list != 0 but pushed_string_list->expander == 0 (not
    2485             :      currently tested) and the flags value is not PSH_SOURCE, we are not
    2486             :      parsing an alias, we have just saved one (push_string, when called by
    2487             :      the parse_dparen code) In this case, just go on as well.  The PSH_SOURCE
    2488             :      case is handled below. */
    2489      433218 : pop_alias:
    2490 16662976346 :   if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE)
    2491             :     {
    2492           0 :       pop_string ();
    2493           0 :       uc = shell_input_line[shell_input_line_index];
    2494           0 :       if (uc)
    2495           0 :         shell_input_line_index++;
    2496             :     }
    2497             : #endif /* ALIAS || DPAREN_ARITHMETIC */
    2498             : 
    2499 16662976346 :   if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
    2500             :     {
    2501         739 :         if (SHOULD_PROMPT ())
    2502           0 :           prompt_again ();
    2503         739 :         line_number++;
    2504             :         /* What do we do here if we're expanding an alias whose definition
    2505             :            includes an escaped newline?  If that's the last character in the
    2506             :            alias expansion, we just pop the pushed string list (recall that
    2507             :            we inhibit the appending of a space in mk_alexpansion() if newline
    2508             :            is the last character).  If it's not the last character, we need
    2509             :            to consume the quoted newline and move to the next character in
    2510             :            the expansion. */
    2511             : #if defined (ALIAS)
    2512         739 :         if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0')
    2513             :           {
    2514             :             uc = 0;
    2515             :             goto pop_alias;
    2516             :           }
    2517         739 :         else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0')
    2518             :           {
    2519           0 :             shell_input_line_index++;   /* skip newline */
    2520           0 :             goto next_alias_char;       /* and get next character */
    2521             :           }
    2522             :         else
    2523             : #endif 
    2524             :           goto restart_read;
    2525             :     }
    2526             : 
    2527 16662975607 :   if (uc == 0 && shell_input_line_terminator == EOF)
    2528      866436 :     return ((shell_input_line_index != 0) ? '\n' : EOF);
    2529             : 
    2530             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    2531             :   /* We already know that we are not parsing an alias expansion because of the
    2532             :      check for expanding_alias() above.  This knows how parse_and_execute
    2533             :      handles switching to st_string input while an alias is being expanded,
    2534             :      hence the check for pushed_string_list without pushed_string_list->expander
    2535             :      and the check for PSH_SOURCE as pushed_string_list->flags.
    2536             :      parse_and_execute and parse_string both change the input type to st_string
    2537             :      and place the string to be parsed and executed into location.string, so
    2538             :      we should not stop reading that until the pointer is '\0'.
    2539             :      The check for shell_input_line_terminator may be superfluous.
    2540             : 
    2541             :      This solves the problem of `.' inside a multi-line alias with embedded
    2542             :      newlines executing things out of order. */
    2543 16662542389 :   if (uc == 0 && bash_input.type == st_string && *bash_input.location.string &&
    2544           0 :       pushed_string_list && pushed_string_list->flags == PSH_SOURCE &&
    2545           0 :       shell_input_line_terminator == 0)
    2546             :     {
    2547           0 :       shell_input_line_index = 0;
    2548           0 :       goto restart_read;
    2549             :     }
    2550             : #endif
    2551             : 
    2552 16662542389 :   return (uc);
    2553             : }
    2554             : 
    2555             : /* Put C back into the input for the shell.  This might need changes for
    2556             :    HANDLE_MULTIBYTE around EOLs.  Since we (currently) never push back a
    2557             :    character different than we read, shell_input_line_property doesn't need
    2558             :    to change when manipulating shell_input_line.  The define for
    2559             :    last_shell_getc_is_singlebyte should take care of it, though. */
    2560             : static void
    2561             : shell_ungetc (c)
    2562             :      int c;
    2563             : {
    2564  1684210839 :   if (shell_input_line && shell_input_line_index)
    2565  1684210616 :     shell_input_line[--shell_input_line_index] = c;
    2566             :   else
    2567         223 :     eol_ungetc_lookahead = c;
    2568             : }
    2569             : 
    2570             : char *
    2571           0 : parser_remaining_input ()
    2572             : {
    2573           0 :   if (shell_input_line == 0)
    2574             :     return 0;
    2575           0 :   if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len)
    2576             :     return "";        /* XXX */
    2577           0 :   return (shell_input_line + shell_input_line_index);
    2578             : }
    2579             : 
    2580             : #ifdef INCLUDE_UNUSED
    2581             : /* Back the input pointer up by one, effectively `ungetting' a character. */
    2582             : static void
    2583             : shell_ungetchar ()
    2584             : {
    2585             :   if (shell_input_line && shell_input_line_index)
    2586             :     shell_input_line_index--;
    2587             : }
    2588             : #endif
    2589             : 
    2590             : /* Discard input until CHARACTER is seen, then push that character back
    2591             :    onto the input stream. */
    2592             : static void
    2593   153743623 : discard_until (character)
    2594             :      int character;
    2595             : {
    2596   153743623 :   int c;
    2597             : 
    2598  4934545329 :   while ((c = shell_getc (0)) != EOF && c != character)
    2599  4780801706 :     ;
    2600             : 
    2601   153743623 :   if (c != EOF)
    2602   153743623 :     shell_ungetc (c);
    2603   153743623 : }
    2604             : 
    2605             : void
    2606           0 : execute_variable_command (command, vname)
    2607             :      char *command, *vname;
    2608             : {
    2609           0 :   char *last_lastarg;
    2610           0 :   sh_parser_state_t ps;
    2611             : 
    2612           0 :   save_parser_state (&ps);
    2613           0 :   last_lastarg = get_string_value ("_");
    2614           0 :   if (last_lastarg)
    2615           0 :     last_lastarg = savestring (last_lastarg);
    2616             : 
    2617           0 :   parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST);
    2618             : 
    2619           0 :   restore_parser_state (&ps);
    2620           0 :   bind_variable ("_", last_lastarg, 0);
    2621           0 :   FREE (last_lastarg);
    2622             : 
    2623           0 :   if (token_to_read == '\n')    /* reset_parser was called */
    2624           0 :     token_to_read = 0;
    2625           0 : }
    2626             : 
    2627             : void
    2628           0 : push_token (x)
    2629             :      int x;
    2630             : {
    2631           0 :   two_tokens_ago = token_before_that;
    2632           0 :   token_before_that = last_read_token;
    2633           0 :   last_read_token = current_token;
    2634             : 
    2635           0 :   current_token = x;
    2636           0 : }
    2637             : 
    2638             : /* Place to remember the token.  We try to keep the buffer
    2639             :    at a reasonable size, but it can grow. */
    2640             : static char *token = (char *)NULL;
    2641             : 
    2642             : /* Current size of the token buffer. */
    2643             : static int token_buffer_size;
    2644             : 
    2645             : /* Command to read_token () explaining what we want it to do. */
    2646             : #define READ 0
    2647             : #define RESET 1
    2648             : #define prompt_is_ps1 \
    2649             :       (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt)
    2650             : 
    2651             : /* Function for yyparse to call.  yylex keeps track of
    2652             :    the last two tokens read, and calls read_token.  */
    2653             : static int
    2654  2261648820 : yylex ()
    2655             : {
    2656  2261648820 :   if (interactive && (current_token == 0 || current_token == '\n'))
    2657             :     {
    2658             :       /* Before we print a prompt, we might have to check mailboxes.
    2659             :          We do this only if it is time to do so. Notice that only here
    2660             :          is the mail alarm reset; nothing takes place in check_mail ()
    2661             :          except the checking of mail.  Please don't change this. */
    2662           0 :       if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ())
    2663             :         {
    2664           0 :           check_mail ();
    2665           0 :           reset_mail_timer ();
    2666             :         }
    2667             : 
    2668             :       /* Avoid printing a prompt if we're not going to read anything, e.g.
    2669             :          after resetting the parser with read_token (RESET). */
    2670           0 :       if (token_to_read == 0 && SHOULD_PROMPT ())
    2671           0 :         prompt_again ();
    2672             :     }
    2673             : 
    2674  2261648820 :   two_tokens_ago = token_before_that;
    2675  2261648820 :   token_before_that = last_read_token;
    2676  2261648820 :   last_read_token = current_token;
    2677  2261648820 :   current_token = read_token (READ);
    2678             : 
    2679  2261648614 :   if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token)
    2680             :     {
    2681          63 :       current_token = yacc_EOF;
    2682          63 :       if (bash_input.type == st_string)
    2683          63 :         rewind_input_string ();
    2684             :     }
    2685  2261648614 :   parser_state &= ~PST_EOFTOKEN;
    2686             : 
    2687  2261648614 :   return (current_token);
    2688             : }
    2689             : 
    2690             : /* When non-zero, we have read the required tokens
    2691             :    which allow ESAC to be the next one read. */
    2692             : static int esacs_needed_count;
    2693             : 
    2694             : static void
    2695         285 : push_heredoc (r)
    2696             :      REDIRECT *r;
    2697             : {
    2698         285 :   if (need_here_doc >= HEREDOC_MAX)
    2699             :     {
    2700           0 :       last_command_exit_value = EX_BADUSAGE;
    2701           0 :       need_here_doc = 0;
    2702           0 :       report_syntax_error (_("maximum here-document count exceeded"));
    2703           0 :       reset_parser ();
    2704           0 :       exit_shell (last_command_exit_value);
    2705             :     }
    2706         285 :   redir_stack[need_here_doc++] = r;
    2707         285 : }
    2708             : 
    2709             : void
    2710         252 : gather_here_documents ()
    2711             : {
    2712         252 :   int r;
    2713             : 
    2714         252 :   r = 0;
    2715         252 :   here_doc_first_line = 1;
    2716         537 :   while (need_here_doc > 0)
    2717             :     {
    2718         285 :       parser_state |= PST_HEREDOC;
    2719         285 :       make_here_document (redir_stack[r++], line_number);
    2720         285 :       parser_state &= ~PST_HEREDOC;
    2721         285 :       need_here_doc--;
    2722         285 :       redir_stack[r - 1] = 0;           /* XXX */
    2723             :     }
    2724         252 :   here_doc_first_line = 0;              /* just in case */
    2725         252 : }
    2726             : 
    2727             : /* When non-zero, an open-brace used to create a group is awaiting a close
    2728             :    brace partner. */
    2729             : static int open_brace_count;
    2730             : 
    2731             : /* In the following three macros, `token' is always last_read_token */
    2732             : 
    2733             : /* Are we in the middle of parsing a redirection where we are about to read
    2734             :    a word?  This is used to make sure alias expansion doesn't happen in the
    2735             :    middle of a redirection, even though we're parsing a simple command. */
    2736             : #define parsing_redirection(token) \
    2737             :   (token == '<' || token == '>' || \
    2738             :    token == GREATER_GREATER || token == GREATER_BAR || \
    2739             :    token == LESS_GREATER || token == LESS_LESS_MINUS || \
    2740             :    token == LESS_LESS || token == LESS_LESS_LESS || \
    2741             :    token == LESS_AND || token == GREATER_AND || token == AND_GREATER)
    2742             : 
    2743             : /* Is `token' one that will allow a WORD to be read in a command position?
    2744             :    We can read a simple command name on which we should attempt alias expansion
    2745             :    or we can read an assignment statement. */
    2746             : #define command_token_position(token) \
    2747             :   (((token) == ASSIGNMENT_WORD) || \
    2748             :    ((parser_state&PST_REDIRLIST) && parsing_redirection(token) == 0) || \
    2749             :    ((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token)))
    2750             : 
    2751             : /* Are we in a position where we can read an assignment statement? */
    2752             : #define assignment_acceptable(token) \
    2753             :   (command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
    2754             : 
    2755             : /* Check to see if TOKEN is a reserved word and return the token
    2756             :    value if it is. */
    2757             : #define CHECK_FOR_RESERVED_WORD(tok) \
    2758             :   do { \
    2759             :     if (!dollar_present && !quoted && \
    2760             :         reserved_word_acceptable (last_read_token)) \
    2761             :       { \
    2762             :         int i; \
    2763             :         for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \
    2764             :           if (STREQ (tok, word_token_alist[i].word)) \
    2765             :             { \
    2766             :               if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \
    2767             :                 break; \
    2768             :               if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \
    2769             :                 break; \
    2770             :               if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \
    2771             :                 break; /* Posix grammar rule 4 */ \
    2772             :               if (word_token_alist[i].token == ESAC) \
    2773             :                 parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
    2774             :               else if (word_token_alist[i].token == CASE) \
    2775             :                 parser_state |= PST_CASESTMT; \
    2776             :               else if (word_token_alist[i].token == COND_END) \
    2777             :                 parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \
    2778             :               else if (word_token_alist[i].token == COND_START) \
    2779             :                 parser_state |= PST_CONDCMD; \
    2780             :               else if (word_token_alist[i].token == '{') \
    2781             :                 open_brace_count++; \
    2782             :               else if (word_token_alist[i].token == '}' && open_brace_count) \
    2783             :                 open_brace_count--; \
    2784             :               return (word_token_alist[i].token); \
    2785             :             } \
    2786             :       } \
    2787             :   } while (0)
    2788             : 
    2789             : #if defined (ALIAS)
    2790             : 
    2791             :     /* OK, we have a token.  Let's try to alias expand it, if (and only if)
    2792             :        it's eligible.
    2793             : 
    2794             :        It is eligible for expansion if EXPAND_ALIASES is set, and
    2795             :        the token is unquoted and the last token read was a command
    2796             :        separator (or expand_next_token is set), and we are currently
    2797             :        processing an alias (pushed_string_list is non-empty) and this
    2798             :        token is not the same as the current or any previously
    2799             :        processed alias.
    2800             : 
    2801             :        Special cases that disqualify:
    2802             :          In a pattern list in a case statement (parser_state & PST_CASEPAT). */
    2803             : 
    2804             : static char *
    2805           0 : mk_alexpansion (s)
    2806             :      char *s;
    2807             : {
    2808           0 :   int l;
    2809           0 :   char *r;
    2810             : 
    2811           0 :   l = strlen (s);
    2812           0 :   r = xmalloc (l + 2);
    2813           0 :   strcpy (r, s);
    2814             :   /* If the last character in the alias is a newline, don't add a trailing
    2815             :      space to the expansion.  Works with shell_getc above. */
    2816           0 :   if (r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0)
    2817           0 :     r[l++] = ' ';
    2818           0 :   r[l] = '\0';
    2819           0 :   return r;
    2820             : }
    2821             : 
    2822             : static int
    2823           0 : alias_expand_token (tokstr)
    2824             :      char *tokstr;
    2825             : {
    2826           0 :   char *expanded;
    2827           0 :   alias_t *ap;
    2828             : 
    2829           0 :   if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) &&
    2830           0 :         (parser_state & PST_CASEPAT) == 0)
    2831             :     {
    2832           0 :       ap = find_alias (tokstr);
    2833             : 
    2834             :       /* Currently expanding this token. */
    2835           0 :       if (ap && (ap->flags & AL_BEINGEXPANDED))
    2836             :         return (NO_EXPANSION);
    2837             : 
    2838             :       /* mk_alexpansion puts an extra space on the end of the alias expansion,
    2839             :          so the lookahead by the parser works right.  If this gets changed,
    2840             :          make sure the code in shell_getc that deals with reaching the end of
    2841             :          an expanded alias is changed with it. */
    2842           0 :       expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL;
    2843             : 
    2844           0 :       if (expanded)
    2845             :         {
    2846           0 :           push_string (expanded, ap->flags & AL_EXPANDNEXT, ap);
    2847           0 :           return (RE_READ_TOKEN);
    2848             :         }
    2849             :       else
    2850             :         /* This is an eligible token that does not have an expansion. */
    2851           0 :         return (NO_EXPANSION);
    2852             :     }
    2853             :   return (NO_EXPANSION);
    2854             : }
    2855             : #endif /* ALIAS */
    2856             : 
    2857             : static int
    2858             : time_command_acceptable ()
    2859             : {
    2860             : #if defined (COMMAND_TIMING)
    2861             :   int i;
    2862             : 
    2863             :   if (posixly_correct && shell_compatibility_level > 41)
    2864             :     {
    2865             :       /* Quick check of the rest of the line to find the next token.  If it
    2866             :          begins with a `-', Posix says to not return `time' as the token.
    2867             :          This was interp 267. */
    2868             :       i = shell_input_line_index;
    2869             :       while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t'))
    2870             :         i++;
    2871             :       if (shell_input_line[i] == '-')
    2872             :         return 0;
    2873             :     }
    2874             : 
    2875             :   switch (last_read_token)
    2876             :     {
    2877             :     case 0:
    2878             :     case ';':
    2879             :     case '\n':
    2880             :       if (token_before_that == '|')
    2881             :         return (0);
    2882             :       /* FALLTHROUGH */
    2883             :     case AND_AND:
    2884             :     case OR_OR:
    2885             :     case '&':
    2886             :     case WHILE:
    2887             :     case DO:
    2888             :     case UNTIL:
    2889             :     case IF:
    2890             :     case THEN:
    2891             :     case ELIF:
    2892             :     case ELSE:
    2893             :     case '{':           /* } */
    2894             :     case '(':           /* )( */
    2895             :     case ')':           /* only valid in case statement */
    2896             :     case BANG:          /* ! time pipeline */
    2897             :     case TIME:          /* time time pipeline */
    2898             :     case TIMEOPT:       /* time -p time pipeline */
    2899             :     case TIMEIGN:       /* time -p -- ... */
    2900             :       return 1;
    2901             :     default:
    2902             :       return 0;
    2903             :     }
    2904             : #else
    2905             :   return 0;
    2906             : #endif /* COMMAND_TIMING */
    2907             : }
    2908             : 
    2909             : /* Handle special cases of token recognition:
    2910             :         IN is recognized if the last token was WORD and the token
    2911             :         before that was FOR or CASE or SELECT.
    2912             : 
    2913             :         DO is recognized if the last token was WORD and the token
    2914             :         before that was FOR or SELECT.
    2915             : 
    2916             :         ESAC is recognized if the last token caused `esacs_needed_count'
    2917             :         to be set
    2918             : 
    2919             :         `{' is recognized if the last token as WORD and the token
    2920             :         before that was FUNCTION, or if we just parsed an arithmetic
    2921             :         `for' command.
    2922             : 
    2923             :         `}' is recognized if there is an unclosed `{' present.
    2924             : 
    2925             :         `-p' is returned as TIMEOPT if the last read token was TIME.
    2926             :         `--' is returned as TIMEIGN if the last read token was TIMEOPT.
    2927             : 
    2928             :         ']]' is returned as COND_END if the parser is currently parsing
    2929             :         a conditional expression ((parser_state & PST_CONDEXPR) != 0)
    2930             : 
    2931             :         `time' is returned as TIME if and only if it is immediately
    2932             :         preceded by one of `;', `\n', `||', `&&', or `&'.
    2933             : */
    2934             : 
    2935             : static int
    2936  1179036241 : special_case_tokens (tokstr)
    2937             :      char *tokstr;
    2938             : {
    2939  1179036241 :   if ((last_read_token == WORD) &&
    2940             : #if defined (SELECT_COMMAND)
    2941   442940164 :       ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) &&
    2942             : #else
    2943             :       ((token_before_that == FOR) || (token_before_that == CASE)) &&
    2944             : #endif
    2945    25263591 :       (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0))
    2946             :     {
    2947    25235144 :       if (token_before_that == CASE)
    2948             :         {
    2949    15692175 :           parser_state |= PST_CASEPAT;
    2950    15692175 :           esacs_needed_count++;
    2951             :         }
    2952    25235144 :       return (IN);
    2953             :     }
    2954             : 
    2955  1153801097 :   if (last_read_token == WORD &&
    2956             : #if defined (SELECT_COMMAND)
    2957   417705020 :       (token_before_that == FOR || token_before_that == SELECT) &&
    2958             : #else
    2959             :       (token_before_that == FOR) &&
    2960             : #endif
    2961          73 :       (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[2] == '\0'))
    2962             :     return (DO);
    2963             : 
    2964             :   /* Ditto for ESAC in the CASE case.
    2965             :      Specifically, this handles "case word in esac", which is a legal
    2966             :      construct, certainly because someone will pass an empty arg to the
    2967             :      case construct, and we don't want it to barf.  Of course, we should
    2968             :      insist that the case construct has at least one pattern in it, but
    2969             :      the designers disagree. */
    2970  1153801097 :   if (esacs_needed_count)
    2971             :     {
    2972    15691575 :       esacs_needed_count--;
    2973    15691575 :       if (STREQ (tokstr, "esac"))
    2974             :         {
    2975           9 :           parser_state &= ~PST_CASEPAT;
    2976           9 :           return (ESAC);
    2977             :         }
    2978             :     }
    2979             : 
    2980             :   /* The start of a shell function definition. */
    2981  1153801088 :   if (parser_state & PST_ALLOWOPNBRC)
    2982             :     {
    2983    19016144 :       parser_state &= ~PST_ALLOWOPNBRC;
    2984    19016144 :       if (tokstr[0] == '{' && tokstr[1] == '\0')                /* } */
    2985             :         {
    2986    18940225 :           open_brace_count++;
    2987    18940225 :           function_bstart = line_number;
    2988    18940225 :           return ('{');                                 /* } */
    2989             :         }
    2990             :     }
    2991             : 
    2992             :   /* We allow a `do' after a for ((...)) without an intervening
    2993             :      list_terminator */
    2994  1134860863 :   if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2])
    2995             :     return (DO);
    2996  1134860863 :   if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0')      /* } */
    2997             :     {
    2998           0 :       open_brace_count++;
    2999           0 :       return ('{');                     /* } */
    3000             :     }
    3001             : 
    3002  1134860863 :   if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1])
    3003             :     {
    3004    18782077 :       open_brace_count--;               /* { */
    3005    18782077 :       return ('}');
    3006             :     }
    3007             : 
    3008             : #if defined (COMMAND_TIMING)
    3009             :   /* Handle -p after `time'. */
    3010             :   if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2])
    3011             :     return (TIMEOPT);
    3012             :   /* Handle -- after `time -p'. */
    3013             :   if (last_read_token == TIMEOPT && tokstr[0] == '-' && tokstr[1] == '-' && !tokstr[2])
    3014             :     return (TIMEIGN);
    3015             : #endif
    3016             : 
    3017             : #if defined (COND_COMMAND) /* [[ */
    3018  1116078786 :   if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0')
    3019           0 :     return (COND_END);
    3020             : #endif
    3021             : 
    3022             :   return (-1);
    3023             : }
    3024             : 
    3025             : /* Called from shell.c when Control-C is typed at top level.  Or
    3026             :    by the error rule at top level. */
    3027             : void
    3028     2104417 : reset_parser ()
    3029             : {
    3030     2104417 :   dstack.delimiter_depth = 0;   /* No delimiters found so far. */
    3031     2104417 :   open_brace_count = 0;
    3032             : 
    3033             : #if defined (EXTENDED_GLOB)
    3034             :   /* Reset to global value of extended glob */
    3035     2104417 :   if (parser_state & PST_EXTPAT)
    3036           0 :     extended_glob = global_extglob;
    3037             : #endif
    3038             : 
    3039     2104417 :   parser_state = 0;
    3040     2104417 :   here_doc_first_line = 0;
    3041             : 
    3042             : #if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
    3043     2104417 :   if (pushed_string_list)
    3044          18 :     free_string_list ();
    3045             : #endif /* ALIAS || DPAREN_ARITHMETIC */
    3046             : 
    3047             :   /* This is where we resynchronize to the next newline on error/reset */
    3048     2104417 :   if (shell_input_line)
    3049             :     {
    3050     2104408 :       free (shell_input_line);
    3051     2104408 :       shell_input_line = (char *)NULL;
    3052     2104408 :       shell_input_line_size = shell_input_line_index = 0;
    3053             :     }
    3054             : 
    3055     2104417 :   FREE (word_desc_to_read);
    3056     2104417 :   word_desc_to_read = (WORD_DESC *)NULL;
    3057             : 
    3058     2104417 :   eol_ungetc_lookahead = 0;
    3059             : 
    3060     2104417 :   current_token = '\n';         /* XXX */
    3061     2104417 :   last_read_token = '\n';
    3062     2104417 :   token_to_read = '\n';
    3063     2104417 : }
    3064             : 
    3065             : /* Read the next token.  Command can be READ (normal operation) or
    3066             :    RESET (to normalize state). */
    3067             : static int
    3068  2261650730 : read_token (command)
    3069             :      int command;
    3070             : {
    3071  2261650730 :   int character;                /* Current character. */
    3072  2261650730 :   int peek_char;                /* Temporary look-ahead character. */
    3073  2261650730 :   int result;                   /* The thing to return. */
    3074             : 
    3075  2261650730 :   if (command == RESET)
    3076             :     {
    3077           0 :       reset_parser ();
    3078           0 :       return ('\n');
    3079             :     }
    3080             : 
    3081  2261650730 :   if (token_to_read)
    3082             :     {
    3083     1852392 :       result = token_to_read;
    3084     1852392 :       if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD)
    3085             :         {
    3086           0 :           yylval.word = word_desc_to_read;
    3087           0 :           word_desc_to_read = (WORD_DESC *)NULL;
    3088             :         }
    3089     1852392 :       token_to_read = 0;
    3090     1852392 :       return (result);
    3091             :     }
    3092             : 
    3093             : #if defined (COND_COMMAND)
    3094  2259798338 :   if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD)
    3095             :     {
    3096          72 :       cond_lineno = line_number;
    3097          72 :       parser_state |= PST_CONDEXPR;
    3098          72 :       yylval.command = parse_cond_command ();
    3099          72 :       if (cond_token != COND_END)
    3100             :         {
    3101          72 :           cond_error ();
    3102          72 :           return (-1);
    3103             :         }
    3104           0 :       token_to_read = COND_END;
    3105           0 :       parser_state &= ~(PST_CONDEXPR|PST_CONDCMD);
    3106           0 :       return (COND_CMD);
    3107             :     }
    3108             : #endif
    3109             : 
    3110             : #if defined (ALIAS)
    3111             :   /* This is a place to jump back to once we have successfully expanded a
    3112             :      token with an alias and pushed the string with push_string () */
    3113  2259798266 :  re_read_token:
    3114             : #endif /* ALIAS */
    3115             : 
    3116             :   /* Read a single word from input.  Start by skipping blanks. */
    3117  3720150635 :   while ((character = shell_getc (1)) != EOF && shellblank (character))
    3118  3720150635 :     ;
    3119             : 
    3120  2259798266 :   if (character == EOF)
    3121             :     {
    3122      243108 :       EOF_Reached = 1;
    3123      243108 :       return (yacc_EOF);
    3124             :     }
    3125             : 
    3126  2259555158 :   if MBTEST(character == '#' && (!interactive || interactive_comments))
    3127             :     {
    3128             :       /* A comment.  Discard until EOL or EOF, and then return a newline. */
    3129   153743623 :       discard_until ('\n');
    3130   153743623 :       shell_getc (0);
    3131   153743623 :       character = '\n'; /* this will take the next if statement and return. */
    3132             :     }
    3133             : 
    3134  2259555158 :   if (character == '\n')
    3135             :     {
    3136             :       /* If we're about to return an unquoted newline, we can go and collect
    3137             :          the text of any pending here document. */
    3138   811919490 :       if (need_here_doc)
    3139         174 :         gather_here_documents ();
    3140             : 
    3141             : #if defined (ALIAS)
    3142   811919490 :       parser_state &= ~PST_ALEXPNEXT;
    3143             : #endif /* ALIAS */
    3144             : 
    3145   811919490 :       parser_state &= ~PST_ASSIGNOK;
    3146             : 
    3147   811919490 :       return (character);
    3148             :     }
    3149             : 
    3150  1447635668 :   if (parser_state & PST_REGEXP)
    3151             :     goto tokword;
    3152             : 
    3153             :   /* Shell meta-characters. */
    3154  1447635668 :   if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0))
    3155             :     {
    3156             : #if defined (ALIAS)
    3157             :       /* Turn off alias tokenization iff this character sequence would
    3158             :          not leave us ready to read a command. */
    3159   262995028 :       if (character == '<' || character == '>')
    3160    16813734 :         parser_state &= ~PST_ALEXPNEXT;
    3161             : #endif /* ALIAS */
    3162             : 
    3163   262995028 :       parser_state &= ~PST_ASSIGNOK;
    3164             : 
    3165             :       /* If we are parsing a command substitution and we have read a character
    3166             :          that marks the end of it, don't bother to skip over quoted newlines
    3167             :          when we read the next token. We're just interested in a character
    3168             :          that will turn this into a two-character token, so we let the higher
    3169             :          layers deal with quoted newlines following the command substitution. */
    3170   262995028 :       if ((parser_state & PST_CMDSUBST) && character == shell_eof_token)
    3171          72 :         peek_char = shell_getc (0);
    3172             :       else
    3173   262994956 :         peek_char = shell_getc (1);
    3174             : 
    3175   262995028 :       if (character == peek_char)
    3176             :         {
    3177    53233911 :           switch (character)
    3178             :             {
    3179         571 :             case '<':
    3180             :               /* If '<' then we could be at "<<" or at "<<-".  We have to
    3181             :                  look ahead one more character. */
    3182         571 :               peek_char = shell_getc (1);
    3183         571 :               if MBTEST(peek_char == '-')
    3184             :                 return (LESS_LESS_MINUS);
    3185         571 :               else if MBTEST(peek_char == '<')
    3186             :                 return (LESS_LESS_LESS);
    3187             :               else
    3188             :                 {
    3189         307 :                   shell_ungetc (peek_char);
    3190         307 :                   return (LESS_LESS);
    3191             :                 }
    3192             : 
    3193             :             case '>':
    3194             :               return (GREATER_GREATER);
    3195             : 
    3196    45496904 :             case ';':
    3197    45496904 :               parser_state |= PST_CASEPAT;
    3198             : #if defined (ALIAS)
    3199    45496904 :               parser_state &= ~PST_ALEXPNEXT;
    3200             : #endif /* ALIAS */
    3201             : 
    3202    45496904 :               peek_char = shell_getc (1);
    3203    45496904 :               if MBTEST(peek_char == '&')
    3204             :                 return (SEMI_SEMI_AND);
    3205             :               else
    3206             :                 {
    3207    45496853 :                   shell_ungetc (peek_char);
    3208    45496853 :                   return (SEMI_SEMI);
    3209             :                 }
    3210             : 
    3211         212 :             case '&':
    3212         212 :               return (AND_AND);
    3213             : 
    3214     4233846 :             case '|':
    3215     4233846 :               return (OR_OR);
    3216             : 
    3217             : #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
    3218         585 :             case '(':           /* ) */
    3219         585 :               result = parse_dparen (character);
    3220         585 :               if (result == -2)
    3221             :                 break;
    3222             :               else
    3223         145 :                 return result;
    3224             : #endif
    3225             :             }
    3226         440 :         }
    3227   209761117 :       else if MBTEST(character == '<' && peek_char == '&')
    3228             :         return (LESS_AND);
    3229   209761032 :       else if MBTEST(character == '>' && peek_char == '&')
    3230             :         return (GREATER_AND);
    3231   207897322 :       else if MBTEST(character == '<' && peek_char == '>')
    3232             :         return (LESS_GREATER);
    3233   207897180 :       else if MBTEST(character == '>' && peek_char == '|')
    3234             :         return (GREATER_BAR);
    3235   207897069 :       else if MBTEST(character == '&' && peek_char == '>')
    3236             :         {
    3237          87 :           peek_char = shell_getc (1);
    3238          87 :           if MBTEST(peek_char == '>')
    3239             :             return (AND_GREATER_GREATER);
    3240             :           else
    3241             :             {
    3242          75 :               shell_ungetc (peek_char);
    3243          75 :               return (AND_GREATER);
    3244             :             }
    3245             :         }
    3246   207896982 :       else if MBTEST(character == '|' && peek_char == '&')
    3247             :         return (BAR_AND);
    3248   207896866 :       else if MBTEST(character == ';' && peek_char == '&')
    3249             :         {
    3250         135 :           parser_state |= PST_CASEPAT;
    3251             : #if defined (ALIAS)
    3252         135 :           parser_state &= ~PST_ALEXPNEXT;
    3253             : #endif /* ALIAS */
    3254         135 :           return (SEMI_AND);
    3255             :         }
    3256             : 
    3257   207897605 :       shell_ungetc (peek_char);
    3258             : 
    3259             :       /* If we look like we are reading the start of a function
    3260             :          definition, then let the reader know about it so that
    3261             :          we will do the right thing with `{'. */
    3262   207897605 :       if MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD)
    3263             :         {
    3264    19017551 :           parser_state |= PST_ALLOWOPNBRC;
    3265             : #if defined (ALIAS)
    3266    19017551 :           parser_state &= ~PST_ALEXPNEXT;
    3267             : #endif /* ALIAS */
    3268    19017551 :           function_dstart = line_number;
    3269             :         }
    3270             : 
    3271             :       /* case pattern lists may be preceded by an optional left paren.  If
    3272             :          we're not trying to parse a case pattern list, the left paren
    3273             :          indicates a subshell. */
    3274   207897605 :       if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */
    3275    20032806 :         parser_state |= PST_SUBSHELL;
    3276             :       /*(*/
    3277   187864799 :       else if MBTEST((parser_state & PST_CASEPAT) && character == ')')
    3278    49481197 :         parser_state &= ~PST_CASEPAT;
    3279             :       /*(*/
    3280   138383602 :       else if MBTEST((parser_state & PST_SUBSHELL) && character == ')')
    3281    19017891 :         parser_state &= ~PST_SUBSHELL;
    3282             : 
    3283             : #if defined (PROCESS_SUBSTITUTION)
    3284             :       /* Check for the constructs which introduce process substitution.
    3285             :          Shells running in `posix mode' don't do process substitution. */
    3286   207897605 :       if MBTEST(posixly_correct || ((character != '>' && character != '<') || peek_char != '(')) /*)*/
    3287             : #endif /* PROCESS_SUBSTITUTION */
    3288   207897534 :         return (character);
    3289             :     }
    3290             : 
    3291             :   /* Hack <&- (close stdin) case.  Also <&N- (dup and close). */
    3292  1184640711 :   if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
    3293             :     return (character);
    3294             : 
    3295  1184640701 : tokword:
    3296             :   /* Okay, if we got this far, we have to read a word.  Read one,
    3297             :      and then check it against the known ones. */
    3298  1184640701 :   result = read_token_word (character);
    3299             : #if defined (ALIAS)
    3300  1184640495 :   if (result == RE_READ_TOKEN)
    3301             :     goto re_read_token;
    3302             : #endif
    3303             :   return result;
    3304             : }
    3305             : 
    3306             : /*
    3307             :  * Match a $(...) or other grouping construct.  This has to handle embedded
    3308             :  * quoted strings ('', ``, "") and nested constructs.  It also must handle
    3309             :  * reprompting the user, if necessary, after reading a newline, and returning
    3310             :  * correct error values if it reads EOF.
    3311             :  */
    3312             : #define P_FIRSTCLOSE    0x0001
    3313             : #define P_ALLOWESC      0x0002
    3314             : #define P_DQUOTE        0x0004
    3315             : #define P_COMMAND       0x0008  /* parsing a command, so look for comments */
    3316             : #define P_BACKQUOTE     0x0010  /* parsing a backquoted command substitution */
    3317             : #define P_ARRAYSUB      0x0020  /* parsing a [...] array subscript for assignment */
    3318             : #define P_DOLBRACE      0x0040  /* parsing a ${...} construct */
    3319             : 
    3320             : /* Lexical state while parsing a grouping construct or $(...). */
    3321             : #define LEX_WASDOL      0x001
    3322             : #define LEX_CKCOMMENT   0x002
    3323             : #define LEX_INCOMMENT   0x004
    3324             : #define LEX_PASSNEXT    0x008
    3325             : #define LEX_RESWDOK     0x010
    3326             : #define LEX_CKCASE      0x020
    3327             : #define LEX_INCASE      0x040
    3328             : #define LEX_INHEREDOC   0x080
    3329             : #define LEX_HEREDELIM   0x100           /* reading here-doc delimiter */
    3330             : #define LEX_STRIPDOC    0x200           /* <<- strip tabs from here doc delim */
    3331             : #define LEX_QUOTEDDOC   0x400           /* here doc with quoted delim */
    3332             : #define LEX_INWORD      0x800
    3333             : 
    3334             : #define COMSUB_META(ch)         ((ch) == ';' || (ch) == '&' || (ch) == '|')
    3335             : 
    3336             : #define CHECK_NESTRET_ERROR() \
    3337             :   do { \
    3338             :     if (nestret == &matched_pair_error) \
    3339             :       { \
    3340             :         free (ret); \
    3341             :         return &matched_pair_error; \
    3342             :       } \
    3343             :   } while (0)
    3344             : 
    3345             : #define APPEND_NESTRET() \
    3346             :   do { \
    3347             :     if (nestlen) \
    3348             :       { \
    3349             :         RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \
    3350             :         strcpy (ret + retind, nestret); \
    3351             :         retind += nestlen; \
    3352             :       } \
    3353             :   } while (0)
    3354             : 
    3355             : static char matched_pair_error;
    3356             : 
    3357             : static char *
    3358   179500548 : parse_matched_pair (qc, open, close, lenp, flags)
    3359             :      int qc;    /* `"' if this construct is within double quotes */
    3360             :      int open, close;
    3361             :      int *lenp, flags;
    3362             : {
    3363   179500548 :   int count, ch, tflags;
    3364   179500548 :   int nestlen, ttranslen, start_lineno;
    3365   179500548 :   char *ret, *nestret, *ttrans;
    3366   179500548 :   int retind, retsize, rflags;
    3367   179500548 :   int dolbrace_state;
    3368             : 
    3369   179500548 :   dolbrace_state = (flags & P_DOLBRACE) ? DOLBRACE_PARAM : 0;
    3370             : 
    3371             : /*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/
    3372   179500548 :   count = 1;
    3373   179500548 :   tflags = 0;
    3374             : 
    3375   179500548 :   if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0)
    3376           0 :     tflags |= LEX_CKCOMMENT;
    3377             : 
    3378             :   /* RFLAGS is the set of flags we want to pass to recursive calls. */
    3379   179500548 :   rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE);
    3380             : 
    3381   179500548 :   ret = (char *)xmalloc (retsize = 64);
    3382   179500548 :   retind = 0;
    3383             : 
    3384   179500548 :   start_lineno = line_number;
    3385  2534469559 :   while (count)
    3386             :     {
    3387  3565847433 :       ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0);
    3388             : 
    3389  2534469559 :       if (ch == EOF)
    3390             :         {
    3391      189827 :           free (ret);
    3392      189827 :           parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close);
    3393      189827 :           EOF_Reached = 1;      /* XXX */
    3394      189827 :           return (&matched_pair_error);
    3395             :         }
    3396             : 
    3397             :       /* Possible reprompting. */
    3398  2534279732 :       if (ch == '\n' && SHOULD_PROMPT ())
    3399           0 :         prompt_again ();
    3400             : 
    3401             :       /* Don't bother counting parens or doing anything else if in a comment
    3402             :          or part of a case statement */
    3403  2534279732 :       if (tflags & LEX_INCOMMENT)
    3404             :         {
    3405             :           /* Add this character. */
    3406           0 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3407           0 :           ret[retind++] = ch;
    3408             : 
    3409           0 :           if (ch == '\n')
    3410           0 :             tflags &= ~LEX_INCOMMENT;
    3411             : 
    3412           0 :           continue;
    3413             :         }
    3414             : 
    3415             :       /* Not exactly right yet, should handle shell metacharacters, too.  If
    3416             :          any changes are made to this test, make analogous changes to subst.c:
    3417             :          extract_delimited_string(). */
    3418  2534279732 :       else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
    3419           0 :         tflags |= LEX_INCOMMENT;
    3420             : 
    3421  2534279732 :       if (tflags & LEX_PASSNEXT)            /* last char was backslash */
    3422             :         {
    3423       73431 :           tflags &= ~LEX_PASSNEXT;
    3424       73431 :           if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
    3425             :             {
    3426           0 :               if (retind > 0)
    3427           0 :                 retind--;       /* swallow previously-added backslash */
    3428           0 :               continue;
    3429             :             }
    3430             : 
    3431       74085 :           RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
    3432       73431 :           if MBTEST(ch == CTLESC)
    3433          63 :             ret[retind++] = CTLESC;
    3434       73431 :           ret[retind++] = ch;
    3435       73431 :           continue;
    3436             :         }
    3437             :       /* If we're reparsing the input (e.g., from parse_string_to_word_list),
    3438             :          we've already prepended CTLESC to single-quoted results of $'...'.
    3439             :          We may want to do this for other CTLESC-quoted characters in
    3440             :          reparse, too. */
    3441  2534206301 :       else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL))
    3442             :         {
    3443           0 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3444           0 :           ret[retind++] = ch;
    3445           0 :           continue;
    3446             :         }
    3447  2534206301 :       else if MBTEST(ch == CTLESC || ch == CTLNUL)      /* special shell escapes */
    3448             :         {
    3449      110583 :           RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
    3450      108375 :           ret[retind++] = CTLESC;
    3451      108375 :           ret[retind++] = ch;
    3452      108375 :           continue;
    3453             :         }
    3454  2534097926 :       else if MBTEST(ch == close)               /* ending delimiter */
    3455   179306156 :         count--;
    3456             :       /* handle nested ${...} specially. */
    3457  2354791770 :       else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */
    3458         180 :         count++;
    3459  2354791590 :       else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open)   /* nested begin */
    3460        6535 :         count++;
    3461             : 
    3462             :       /* Add this character. */
    3463  2548522641 :       RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3464  2534097926 :       ret[retind++] = ch;
    3465             : 
    3466             :       /* If we just read the ending character, don't bother continuing. */
    3467  2534097926 :       if (count == 0)
    3468             :         break;
    3469             : 
    3470  2354795727 :       if (open == '\'')                 /* '' inside grouping construct */
    3471             :         {
    3472   997257625 :           if MBTEST((flags & P_ALLOWESC) && ch == '\\')
    3473         137 :             tflags |= LEX_PASSNEXT;
    3474   997257625 :           continue;
    3475             :         }
    3476             : 
    3477  1357538102 :       if MBTEST(ch == '\\')                     /* backslashes */
    3478       73294 :         tflags |= LEX_PASSNEXT;
    3479             : 
    3480             :       /* Based on which dolstate is currently in (param, op, or word),
    3481             :          decide what the op is.  We're really only concerned if it's % or
    3482             :          #, so we can turn on a flag that says whether or not we should
    3483             :          treat single quotes as special when inside a double-quoted
    3484             :          ${...}. This logic must agree with subst.c:extract_dollar_brace_string
    3485             :          since they share the same defines. */
    3486             :       /* FLAG POSIX INTERP 221 */
    3487  1357538102 :       if (flags & P_DOLBRACE)
    3488             :         {
    3489             :           /* ${param%[%]word} */
    3490   363695118 :           if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '%' && retind > 1)
    3491             :             dolbrace_state = DOLBRACE_QUOTE;
    3492             :           /* ${param#[#]word} */
    3493   363695089 :           else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '#' && retind > 1)
    3494             :             dolbrace_state = DOLBRACE_QUOTE;
    3495             :           /* ${param/[/]pat/rep} */
    3496   357889777 :           else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '/' && retind > 1)
    3497             :             dolbrace_state = DOLBRACE_QUOTE2;   /* XXX */
    3498             :           /* ${param^[^]pat} */
    3499   357889126 :           else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == '^' && retind > 1)
    3500             :             dolbrace_state = DOLBRACE_QUOTE;
    3501             :           /* ${param,[,]pat} */
    3502   357889107 :           else if MBTEST(dolbrace_state == DOLBRACE_PARAM && ch == ',' && retind > 1)
    3503             :             dolbrace_state = DOLBRACE_QUOTE;
    3504   357889027 :           else if MBTEST(dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", ch) != 0)
    3505             :             dolbrace_state = DOLBRACE_OP;
    3506   338801835 :           else if MBTEST(dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", ch) == 0)
    3507    19087187 :             dolbrace_state = DOLBRACE_WORD;
    3508             :         }
    3509             : 
    3510             :       /* The big hammer.  Single quotes aren't special in double quotes.  The
    3511             :          problem is that Posix used to say the single quotes are semi-special:
    3512             :          within a double-quoted ${...} construct "an even number of
    3513             :          unescaped double-quotes or single-quotes, if any, shall occur." */
    3514             :       /* This was changed in Austin Group Interp 221 */
    3515  1357538102 :       if MBTEST(posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2 && (flags & P_DQUOTE) && (flags & P_DOLBRACE) && ch == '\'')
    3516             :         continue;
    3517             : 
    3518             :       /* Could also check open == '`' if we want to parse grouping constructs
    3519             :          inside old-style command substitution. */
    3520  1357538102 :       if (open != close)                /* a grouping construct */
    3521             :         {
    3522   365112057 :           if MBTEST(shellquote (ch))
    3523             :             {
    3524             :               /* '', ``, or "" inside $(...) or other grouping construct. */
    3525       31507 :               push_delimiter (dstack, ch);
    3526       31507 :               if MBTEST((tflags & LEX_WASDOL) && ch == '\'')        /* $'...' inside group */
    3527           9 :                 nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags);
    3528             :               else
    3529       31498 :                 nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags);
    3530       31507 :               pop_delimiter (dstack);
    3531       31507 :               CHECK_NESTRET_ERROR ();
    3532             : 
    3533       29845 :               if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
    3534             :                 {
    3535             :                   /* Translate $'...' here. */
    3536           9 :                   ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
    3537           9 :                   xfree (nestret);
    3538             : 
    3539             :                   /* If we're parsing a double-quoted brace expansion and we are
    3540             :                      not in a place where single quotes are treated specially,
    3541             :                      make sure we single-quote the results of the ansi
    3542             :                      expansion because quote removal should remove them later */
    3543             :                   /* FLAG POSIX INTERP 221 */
    3544           9 :                   if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE))
    3545             :                     {
    3546           0 :                       nestret = sh_single_quote (ttrans);
    3547           0 :                       free (ttrans);
    3548           0 :                       nestlen = strlen (nestret);
    3549             :                     }
    3550           9 :                   else if ((rflags & P_DQUOTE) == 0)
    3551             :                     {
    3552           9 :                       nestret = sh_single_quote (ttrans);
    3553           9 :                       free (ttrans);
    3554           9 :                       nestlen = strlen (nestret);
    3555             :                     }
    3556             :                   else
    3557             :                     {
    3558           0 :                       nestret = ttrans;
    3559           0 :                       nestlen = ttranslen;
    3560             :                     }
    3561           9 :                   retind -= 2;          /* back up before the $' */
    3562             :                 }
    3563       29836 :               else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
    3564             :                 {
    3565             :                   /* Locale expand $"..." here. */
    3566          11 :                   ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
    3567          11 :                   xfree (nestret);
    3568             : 
    3569          11 :                   nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
    3570          11 :                   free (ttrans);
    3571          11 :                   nestlen = ttranslen + 2;
    3572          11 :                   retind -= 2;          /* back up before the $" */
    3573             :                 }
    3574             : 
    3575       37276 :               APPEND_NESTRET ();
    3576       29845 :               FREE (nestret);
    3577             :             }
    3578   365080550 :           else if ((flags & (P_ARRAYSUB|P_DOLBRACE)) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
    3579             :             goto parse_dollar_word;
    3580             :         }
    3581             :       /* Parse an old-style command substitution within double quotes as a
    3582             :          single word. */
    3583             :       /* XXX - sh and ksh93 don't do this - XXX */
    3584   992426045 :       else if MBTEST(open == '"' && ch == '`')
    3585             :         {
    3586       10259 :           nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags);
    3587             : 
    3588       10259 :           CHECK_NESTRET_ERROR ();
    3589        9591 :           APPEND_NESTRET ();
    3590             : 
    3591        4429 :           FREE (nestret);
    3592             :         }
    3593   992415786 :       else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
    3594             :         /* check for $(), $[], or ${} inside quoted string. */
    3595             :         {
    3596    24833559 : parse_dollar_word:
    3597    24833895 :           if (open == ch)       /* undo previous increment */
    3598         180 :             count--;
    3599    24833895 :           if (ch == '(')                /* ) */
    3600         216 :             nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
    3601    24833679 :           else if (ch == '{')           /* } */
    3602    24833529 :             nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
    3603         150 :           else if (ch == '[')           /* ] */
    3604         150 :             nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
    3605             : 
    3606    24833895 :           CHECK_NESTRET_ERROR ();
    3607    24837593 :           APPEND_NESTRET ();
    3608             : 
    3609    24832865 :           FREE (nestret);
    3610             :         }
    3611  1357529580 :       if MBTEST(ch == '$')
    3612   116712213 :         tflags |= LEX_WASDOL;
    3613             :       else
    3614  1240817367 :         tflags &= ~LEX_WASDOL;
    3615             :     }
    3616             : 
    3617   179302199 :   ret[retind] = '\0';
    3618   179302199 :   if (lenp)
    3619   179302199 :     *lenp = retind;
    3620             : /*itrace("parse_matched_pair[%d]: returning %s", line_number, ret);*/
    3621             :   return ret;
    3622             : }
    3623             : 
    3624             : #if defined (DEBUG)
    3625             : static void
    3626             : dump_tflags (flags)
    3627             :      int flags;
    3628             : {
    3629             :   int f;
    3630             : 
    3631             :   f = flags;
    3632             :   fprintf (stderr, "%d -> ", f);
    3633             :   if (f & LEX_WASDOL)
    3634             :     {
    3635             :       f &= ~LEX_WASDOL;
    3636             :       fprintf (stderr, "LEX_WASDOL%s", f ? "|" : "");
    3637             :     }
    3638             :   if (f & LEX_CKCOMMENT)
    3639             :     {
    3640             :       f &= ~LEX_CKCOMMENT;
    3641             :       fprintf (stderr, "LEX_CKCOMMENT%s", f ? "|" : "");
    3642             :     }
    3643             :   if (f & LEX_INCOMMENT)
    3644             :     {
    3645             :       f &= ~LEX_INCOMMENT;
    3646             :       fprintf (stderr, "LEX_INCOMMENT%s", f ? "|" : "");
    3647             :     }
    3648             :   if (f & LEX_PASSNEXT)
    3649             :     {
    3650             :       f &= ~LEX_PASSNEXT;
    3651             :       fprintf (stderr, "LEX_PASSNEXT%s", f ? "|" : "");
    3652             :     }
    3653             :   if (f & LEX_RESWDOK)
    3654             :     {
    3655             :       f &= ~LEX_RESWDOK;
    3656             :       fprintf (stderr, "LEX_RESWDOK%s", f ? "|" : "");
    3657             :     }
    3658             :   if (f & LEX_CKCASE)
    3659             :     {
    3660             :       f &= ~LEX_CKCASE;
    3661             :       fprintf (stderr, "LEX_CKCASE%s", f ? "|" : "");
    3662             :     }
    3663             :   if (f & LEX_INCASE)
    3664             :     {
    3665             :       f &= ~LEX_INCASE;
    3666             :       fprintf (stderr, "LEX_INCASE%s", f ? "|" : "");
    3667             :     }
    3668             :   if (f & LEX_INHEREDOC)
    3669             :     {
    3670             :       f &= ~LEX_INHEREDOC;
    3671             :       fprintf (stderr, "LEX_INHEREDOC%s", f ? "|" : "");
    3672             :     }
    3673             :   if (f & LEX_HEREDELIM)
    3674             :     {
    3675             :       f &= ~LEX_HEREDELIM;
    3676             :       fprintf (stderr, "LEX_HEREDELIM%s", f ? "|" : "");
    3677             :     }
    3678             :   if (f & LEX_STRIPDOC)
    3679             :     {
    3680             :       f &= ~LEX_STRIPDOC;
    3681             :       fprintf (stderr, "LEX_WASDOL%s", f ? "|" : "");
    3682             :     }
    3683             :   if (f & LEX_QUOTEDDOC)
    3684             :     {
    3685             :       f &= ~LEX_QUOTEDDOC;
    3686             :       fprintf (stderr, "LEX_QUOTEDDOC%s", f ? "|" : "");
    3687             :     }
    3688             :   if (f & LEX_INWORD)
    3689             :     {
    3690             :       f &= ~LEX_INWORD;
    3691             :       fprintf (stderr, "LEX_INWORD%s", f ? "|" : "");
    3692             :     }
    3693             : 
    3694             :   fprintf (stderr, "\n");
    3695             :   fflush (stderr);
    3696             : }
    3697             : #endif
    3698             : 
    3699             : /* Parse a $(...) command substitution.  This is messier than I'd like, and
    3700             :    reproduces a lot more of the token-reading code than I'd like. */
    3701             : static char *
    3702         676 : parse_comsub (qc, open, close, lenp, flags)
    3703             :      int qc;    /* `"' if this construct is within double quotes */
    3704             :      int open, close;
    3705             :      int *lenp, flags;
    3706             : {
    3707         676 :   int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind;
    3708         676 :   int nestlen, ttranslen, start_lineno;
    3709         676 :   char *ret, *nestret, *ttrans, *heredelim;
    3710         676 :   int retind, retsize, rflags, hdlen = 0;
    3711             : 
    3712             :   /* Posix interp 217 says arithmetic expressions have precedence, so
    3713             :      assume $(( introduces arithmetic expansion and parse accordingly. */
    3714         676 :   peekc = shell_getc (0);
    3715         676 :   shell_ungetc (peekc);
    3716         676 :   if (peekc == '(')
    3717          10 :     return (parse_matched_pair (qc, open, close, lenp, 0));
    3718             : 
    3719             : /*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/
    3720         666 :   count = 1;
    3721         666 :   tflags = LEX_RESWDOK;
    3722             : 
    3723         666 :   if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0)
    3724         666 :     tflags |= LEX_CKCASE;
    3725         666 :   if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments))
    3726         666 :     tflags |= LEX_CKCOMMENT;
    3727             : 
    3728             :   /* RFLAGS is the set of flags we want to pass to recursive calls. */
    3729         666 :   rflags = (flags & P_DQUOTE);
    3730             : 
    3731         666 :   ret = (char *)xmalloc (retsize = 64);
    3732         666 :   retind = 0;
    3733             : 
    3734         666 :   start_lineno = line_number;
    3735         666 :   lex_rwlen = lex_wlen = 0;
    3736             : 
    3737         666 :   heredelim = 0;
    3738         666 :   lex_firstind = -1;
    3739             : 
    3740       88794 :   while (count)
    3741             :     {
    3742       96265 :       ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT)) == 0);
    3743             : 
    3744       88794 :       if (ch == EOF)
    3745             :         {
    3746         224 : eof_error:
    3747         224 :           free (ret);
    3748         224 :           FREE (heredelim);
    3749         224 :           parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close);
    3750         224 :           EOF_Reached = 1;      /* XXX */
    3751         224 :           return (&matched_pair_error);
    3752             :         }
    3753             : 
    3754             :       /* If we hit the end of a line and are reading the contents of a here
    3755             :          document, and it's not the same line that the document starts on,
    3756             :          check for this line being the here doc delimiter.  Otherwise, if
    3757             :          we're in a here document, mark the next character as the beginning
    3758             :          of a line. */
    3759       88570 :       if (ch == '\n')
    3760             :         {
    3761        5890 :           if ((tflags & LEX_HEREDELIM) && heredelim)
    3762             :             {
    3763           0 :               tflags &= ~LEX_HEREDELIM;
    3764           0 :               tflags |= LEX_INHEREDOC;
    3765           0 :               lex_firstind = retind + 1;
    3766             :             }
    3767        5890 :           else if (tflags & LEX_INHEREDOC)
    3768             :             {
    3769             :               int tind;
    3770             :               tind = lex_firstind;
    3771           0 :               while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t')
    3772           0 :                 tind++;
    3773           0 :               if (STREQN (ret + tind, heredelim, hdlen))
    3774             :                 {
    3775           0 :                   tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC);
    3776             : /*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/
    3777           0 :                   free (heredelim);
    3778           0 :                   heredelim = 0;
    3779           0 :                   lex_firstind = -1;
    3780             :                 }
    3781             :               else
    3782           0 :                 lex_firstind = retind + 1;
    3783             :             }
    3784             :         }
    3785             : 
    3786             :       /* Possible reprompting. */
    3787       88570 :       if (ch == '\n' && SHOULD_PROMPT ())
    3788           0 :         prompt_again ();
    3789             : 
    3790             :       /* XXX -- possibly allow here doc to be delimited by ending right
    3791             :          paren. */
    3792       88570 :       if ((tflags & LEX_INHEREDOC) && ch == close && count == 1)
    3793             :         {
    3794             :           int tind;
    3795             : /*itrace("parse_comsub:%d: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", line_number, retind-lex_firstind, hdlen, retind);*/
    3796             :           tind = lex_firstind;
    3797           0 :           while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t')
    3798           0 :             tind++;
    3799           0 :           if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen))
    3800             :             {
    3801           0 :               tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC|LEX_QUOTEDDOC);
    3802             : /*itrace("parse_comsub:%d: found here doc end `%*s'", line_number, hdlen, ret + tind);*/
    3803           0 :               free (heredelim);
    3804           0 :               heredelim = 0;
    3805           0 :               lex_firstind = -1;
    3806             :             }
    3807             :         }
    3808             : 
    3809             :       /* Don't bother counting parens or doing anything else if in a comment or
    3810             :          here document (not exactly right for here-docs -- if we want to allow
    3811             :          recursive calls to parse_comsub to have their own here documents,
    3812             :          change the LEX_INHEREDOC to LEX_QUOTEDDOC here and uncomment the next
    3813             :          clause below.  Note that to make this work completely, we need to make
    3814             :          additional changes to allow xparse_dolparen to work right when the
    3815             :          command substitution is parsed, because read_secondary_line doesn't know
    3816             :          to recursively parse through command substitutions embedded in here-
    3817             :          documents */
    3818       88570 :       if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC))
    3819             :         {
    3820             :           /* Add this character. */
    3821        7525 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3822        7408 :           ret[retind++] = ch;
    3823             : 
    3824        7408 :           if ((tflags & LEX_INCOMMENT) && ch == '\n')
    3825             :             {
    3826             : /*itrace("parse_comsub:%d: lex_incomment -> 0 ch = `%c'", line_number, ch);*/
    3827         172 :               tflags &= ~LEX_INCOMMENT;
    3828             :             }
    3829             : 
    3830        7408 :           continue;
    3831             :         }
    3832             : #if 0
    3833             :       /* If we're going to recursively parse a command substitution inside a
    3834             :          here-document, make sure we call parse_comsub recursively below.  See
    3835             :          above for additional caveats. */
    3836             :       if ((tflags & LEX_INHEREDOC) && ((tflags & LEX_WASDOL) == 0 || ch != '(')) /*)*/
    3837             :         {
    3838             :           /* Add this character. */
    3839             :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3840             :           ret[retind++] = ch;
    3841             :           if MBTEST(ch == '$')
    3842             :             tflags |= LEX_WASDOL;
    3843             :           else
    3844             :             tflags &= ~LEX_WASDOL;
    3845             :         }
    3846             : #endif
    3847             : 
    3848       81162 :       if (tflags & LEX_PASSNEXT)            /* last char was backslash */
    3849             :         {
    3850             : /*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
    3851          63 :           tflags &= ~LEX_PASSNEXT;
    3852          63 :           if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
    3853             :             {
    3854           0 :               if (retind > 0)
    3855           0 :                 retind--;       /* swallow previously-added backslash */
    3856           0 :               continue;
    3857             :             }
    3858             : 
    3859          63 :           RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
    3860          63 :           if MBTEST(ch == CTLESC)
    3861           0 :             ret[retind++] = CTLESC;
    3862          63 :           ret[retind++] = ch;
    3863          63 :           continue;
    3864             :         }
    3865             : 
    3866             :       /* If this is a shell break character, we are not in a word.  If not,
    3867             :          we either start or continue a word. */
    3868       81099 :       if MBTEST(shellbreak (ch))
    3869             :         {
    3870       20334 :           tflags &= ~LEX_INWORD;
    3871             : /*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
    3872             :         }
    3873             :       else
    3874             :         {
    3875       60765 :           if (tflags & LEX_INWORD)
    3876             :             {
    3877       52505 :               lex_wlen++;
    3878             : /*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/
    3879             :             }         
    3880             :           else
    3881             :             {
    3882             : /*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
    3883        8260 :               tflags |= LEX_INWORD;
    3884        8260 :               lex_wlen = 0;
    3885        8260 :               if (tflags & LEX_RESWDOK)
    3886        5511 :                 lex_rwlen = 0;
    3887             :             }
    3888             :         }
    3889             : 
    3890             :       /* Skip whitespace */
    3891       81099 :       if MBTEST(shellblank (ch) && (tflags & LEX_HEREDELIM) == 0 && lex_rwlen == 0)
    3892             :         {
    3893             :           /* Add this character. */
    3894        7464 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3895        7360 :           ret[retind++] = ch;
    3896        7360 :           continue;
    3897             :         }
    3898             : 
    3899             :       /* Either we are looking for the start of the here-doc delimiter
    3900             :          (lex_firstind == -1) or we are reading one (lex_firstind >= 0).
    3901             :          If this character is a shell break character and we are reading
    3902             :          the delimiter, save it and note that we are now reading a here
    3903             :          document.  If we've found the start of the delimiter, note it by
    3904             :          setting lex_firstind.  Backslashes can quote shell metacharacters
    3905             :          in here-doc delimiters. */
    3906       73739 :       if (tflags & LEX_HEREDELIM)
    3907             :         {
    3908           0 :           if (lex_firstind == -1 && shellbreak (ch) == 0)
    3909             :             lex_firstind = retind;
    3910             : #if 0
    3911             :           else if (heredelim && (tflags & LEX_PASSNEXT) == 0 && ch == '\n')
    3912             :             {
    3913             :               tflags |= LEX_INHEREDOC;
    3914             :               tflags &= ~LEX_HEREDELIM;
    3915             :               lex_firstind = retind + 1;
    3916             :             }
    3917             : #endif
    3918           0 :           else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch))
    3919             :             {
    3920           0 :               if (heredelim == 0)
    3921             :                 {
    3922           0 :                   nestret = substring (ret, lex_firstind, retind);
    3923           0 :                   heredelim = string_quote_removal (nestret, 0);
    3924           0 :                   hdlen = STRLEN(heredelim);
    3925             : /*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/
    3926           0 :                   if (STREQ (heredelim, nestret) == 0)
    3927           0 :                     tflags |= LEX_QUOTEDDOC;
    3928           0 :                   free (nestret);
    3929             :                 }
    3930           0 :               if (ch == '\n')
    3931             :                 {
    3932           0 :                   tflags |= LEX_INHEREDOC;
    3933           0 :                   tflags &= ~LEX_HEREDELIM;
    3934           0 :                   lex_firstind = retind + 1;
    3935             :                 }
    3936             :               else
    3937             :                 lex_firstind = -1;
    3938             :             }
    3939             :         }
    3940             : 
    3941             :       /* Meta-characters that can introduce a reserved word.  Not perfect yet. */
    3942       73739 :       if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n'))
    3943             :         {
    3944             :           /* Add this character. */
    3945        5051 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3946        4977 :           ret[retind++] = ch;
    3947        4977 :           peekc = shell_getc (1);
    3948        4977 :           if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */
    3949             :             {
    3950         416 :               RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3951         397 :               ret[retind++] = peekc;
    3952             : /*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/
    3953         397 :               tflags |= LEX_RESWDOK;
    3954         397 :               lex_rwlen = 0;
    3955         397 :               continue;
    3956             :             }
    3957        4580 :           else if (ch == '\n' || COMSUB_META(ch))
    3958             :             {
    3959        3825 :               shell_ungetc (peekc);
    3960             : /*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/
    3961        3825 :               tflags |= LEX_RESWDOK;
    3962        3825 :               lex_rwlen = 0;
    3963        3825 :               continue;
    3964             :             }
    3965         755 :           else if (ch == EOF)
    3966             :             goto eof_error;
    3967             :           else
    3968             :             {
    3969             :               /* `unget' the character we just added and fall through */
    3970         755 :               retind--;
    3971         755 :               shell_ungetc (peekc);
    3972             :             }
    3973             :         }
    3974             : 
    3975             :       /* If we can read a reserved word, try to read one. */
    3976       69517 :       if (tflags & LEX_RESWDOK)
    3977             :         {
    3978       24367 :           if MBTEST(islower ((unsigned char)ch))
    3979             :             {
    3980             :               /* Add this character. */
    3981       16110 :               RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    3982       15899 :               ret[retind++] = ch;
    3983       15899 :               lex_rwlen++;
    3984       15899 :               continue;
    3985             :             }
    3986        8468 :           else if MBTEST(lex_rwlen == 4 && shellbreak (ch))
    3987             :             {
    3988        1148 :               if (STREQN (ret + retind - 4, "case", 4))
    3989             :                 {
    3990         122 :                   tflags |= LEX_INCASE;
    3991         122 :                   tflags &= ~LEX_RESWDOK;
    3992             : /*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/
    3993             :                 }
    3994        1026 :               else if (STREQN (ret + retind - 4, "esac", 4))
    3995             :                 {
    3996          95 :                   tflags &= ~LEX_INCASE;
    3997             : /*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 1", line_number);*/
    3998          95 :                   tflags |= LEX_RESWDOK;
    3999          95 :                   lex_rwlen = 0;
    4000             :                 }
    4001         931 :               else if (STREQN (ret + retind - 4, "done", 4) ||
    4002         911 :                        STREQN (ret + retind - 4, "then", 4) ||
    4003         798 :                        STREQN (ret + retind - 4, "else", 4) ||
    4004         788 :                        STREQN (ret + retind - 4, "elif", 4) ||
    4005           0 :                        STREQN (ret + retind - 4, "time", 4))
    4006             :                 {
    4007             :                   /* these are four-character reserved words that can be
    4008             :                      followed by a reserved word; anything else turns off
    4009             :                      the reserved-word-ok flag */
    4010             : /*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 1", line_number, ret+retind-4);*/
    4011         143 :                   tflags |= LEX_RESWDOK;
    4012         143 :                   lex_rwlen = 0;
    4013             :                 }
    4014         788 :                else if (shellmeta (ch) == 0)
    4015             :                 {
    4016         549 :                   tflags &= ~LEX_RESWDOK;
    4017             : /*itrace("parse_comsub:%d: found `%.4s', lex_reswdok -> 0", line_number, ret+retind-4);*/
    4018             :                 }
    4019             :               else      /* can't be in a reserved word any more */
    4020             :                 lex_rwlen = 0;
    4021             :             }
    4022        7320 :           else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0)))
    4023             :             ;   /* don't modify LEX_RESWDOK if we're starting a comment */
    4024             :           /* Allow `do' followed by space, tab, or newline to preserve the
    4025             :              RESWDOK flag, but reset the reserved word length counter so we
    4026             :              can read another one. */
    4027        7157 :           else if MBTEST(((tflags & LEX_INCASE) == 0) &&
    4028             :                           (isblank((unsigned char)ch) || ch == '\n') &&
    4029             :                           lex_rwlen == 2 &&
    4030             :                           STREQN (ret + retind - 2, "do", 2))
    4031             :             {
    4032             : /*itrace("parse_comsub:%d: lex_incase == 0 found `%c', found \"do\"", line_number, ch);*/
    4033             :               lex_rwlen = 0;
    4034             :             }
    4035        7147 :           else if MBTEST((tflags & LEX_INCASE) && ch != '\n')
    4036             :             /* If we can read a reserved word and we're in case, we're at the
    4037             :                point where we can read a new pattern list or an esac.  We
    4038             :                handle the esac case above.  If we read a newline, we want to
    4039             :                leave LEX_RESWDOK alone.  If we read anything else, we want to
    4040             :                turn off LEX_RESWDOK, since we're going to read a pattern list. */
    4041             :             {
    4042        1712 :               tflags &= ~LEX_RESWDOK;
    4043             : /*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/
    4044             :             }
    4045        5435 :           else if MBTEST(shellbreak (ch) == 0)
    4046             :             {
    4047        2181 :               tflags &= ~LEX_RESWDOK;
    4048             : /*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/
    4049             :             }
    4050             : #if 0
    4051             :           /* If we find a space or tab but have read something and it's not
    4052             :              `do', turn off the reserved-word-ok flag */
    4053             :           else if MBTEST(isblank ((unsigned char)ch) && lex_rwlen > 0)
    4054             :             {
    4055             :               tflags &= ~LEX_RESWDOK;
    4056             : /*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/
    4057             :             }
    4058             : #endif
    4059             :         }
    4060             : 
    4061             :       /* Might be the start of a here-doc delimiter */
    4062       53618 :       if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<')
    4063             :         {
    4064             :           /* Add this character. */
    4065         149 :           RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    4066         149 :           ret[retind++] = ch;
    4067         149 :           peekc = shell_getc (1);
    4068         149 :           if (peekc == EOF)
    4069           0 :             goto eof_error;
    4070         149 :           if (peekc == ch)
    4071             :             {
    4072           0 :               RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    4073           0 :               ret[retind++] = peekc;
    4074           0 :               peekc = shell_getc (1);
    4075           0 :               if (peekc == EOF)
    4076           0 :                 goto eof_error;
    4077           0 :               if (peekc == '-')
    4078             :                 {
    4079           0 :                   RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    4080           0 :                   ret[retind++] = peekc;
    4081           0 :                   tflags |= LEX_STRIPDOC;
    4082             :                 }
    4083             :               else
    4084           0 :                 shell_ungetc (peekc);
    4085           0 :               if (peekc != '<')
    4086             :                 {
    4087           0 :                   tflags |= LEX_HEREDELIM;
    4088           0 :                   lex_firstind = -1;
    4089             :                 }
    4090           0 :               continue;
    4091             :             }
    4092             :           else
    4093             :             ch = peekc;         /* fall through and continue XXX */
    4094             :         }
    4095       53469 :       else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0)))
    4096             :         {
    4097             : /*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/
    4098         172 :           tflags |= LEX_INCOMMENT;
    4099             :         }
    4100             : 
    4101       53618 :       if MBTEST(ch == CTLESC || ch == CTLNUL)   /* special shell escapes */
    4102             :         {
    4103         444 :           RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
    4104         435 :           ret[retind++] = CTLESC;
    4105         435 :           ret[retind++] = ch;
    4106         435 :           continue;
    4107             :         }
    4108             : #if 0
    4109             :       else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')')
    4110             :         tflags &= ~LEX_INCASE;              /* XXX */
    4111             : #endif
    4112       53183 :       else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0)             /* ending delimiter */
    4113             :         {
    4114         405 :           count--;
    4115             : /*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/
    4116             :         }
    4117       52778 :       else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */
    4118             :         {
    4119         278 :           count++;
    4120             : /*itrace("parse_comsub:%d: found open: count = %d", line_number, count);*/
    4121             :         }
    4122             : 
    4123             :       /* Add this character. */
    4124       53859 :       RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
    4125       53183 :       ret[retind++] = ch;
    4126             : 
    4127             :       /* If we just read the ending character, don't bother continuing. */
    4128       53183 :       if (count == 0)
    4129             :         break;
    4130             : 
    4131       53029 :       if MBTEST(ch == '\\')                     /* backslashes */
    4132          63 :         tflags |= LEX_PASSNEXT;
    4133             : 
    4134       53029 :       if MBTEST(shellquote (ch))
    4135             :         {
    4136             :           /* '', ``, or "" inside $(...). */
    4137        1096 :           push_delimiter (dstack, ch);
    4138        1096 :           if MBTEST((tflags & LEX_WASDOL) && ch == '\'')    /* $'...' inside group */
    4139           0 :             nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags);
    4140             :           else
    4141        1096 :             nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags);
    4142        1096 :           pop_delimiter (dstack);
    4143        1096 :           CHECK_NESTRET_ERROR ();
    4144             : 
    4145         827 :           if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
    4146             :             {
    4147             :               /* Translate $'...' here. */
    4148           0 :               ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
    4149           0 :               xfree (nestret);
    4150             : 
    4151           0 :               if ((rflags & P_DQUOTE) == 0)
    4152             :                 {
    4153           0 :                   nestret = sh_single_quote (ttrans);
    4154           0 :                   free (ttrans);
    4155           0 :                   nestlen = strlen (nestret);
    4156             :                 }
    4157             :               else
    4158             :                 {
    4159           0 :                   nestret = ttrans;
    4160           0 :                   nestlen = ttranslen;
    4161             :                 }
    4162           0 :               retind -= 2;              /* back up before the $' */
    4163             :             }
    4164         827 :           else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
    4165             :             {
    4166             :               /* Locale expand $"..." here. */
    4167           0 :               ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
    4168           0 :               xfree (nestret);
    4169             : 
    4170           0 :               nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
    4171           0 :               free (ttrans);
    4172           0 :               nestlen = ttranslen + 2;
    4173           0 :               retind -= 2;              /* back up before the $" */
    4174             :             }
    4175             : 
    4176        1299 :           APPEND_NESTRET ();
    4177         827 :           FREE (nestret);
    4178             :         }
    4179       51933 :       else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))        /* ) } ] */
    4180             :         /* check for $(), $[], or ${} inside command substitution. */
    4181             :         {
    4182          69 :           if ((tflags & LEX_INCASE) == 0 && open == ch)     /* undo previous increment */
    4183          10 :             count--;
    4184          69 :           if (ch == '(')                /* ) */
    4185          10 :             nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
    4186          59 :           else if (ch == '{')           /* } */
    4187          59 :             nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|P_DOLBRACE|rflags);
    4188           0 :           else if (ch == '[')           /* ] */
    4189           0 :             nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
    4190             : 
    4191          69 :           CHECK_NESTRET_ERROR ();
    4192          50 :           APPEND_NESTRET ();
    4193             : 
    4194          50 :           FREE (nestret);
    4195             :         }
    4196       52741 :       if MBTEST(ch == '$')
    4197         891 :         tflags |= LEX_WASDOL;
    4198             :       else
    4199       51850 :         tflags &= ~LEX_WASDOL;
    4200             :     }
    4201             : 
    4202         154 :   FREE (heredelim);
    4203         154 :   ret[retind] = '\0';
    4204         154 :   if (lenp)
    4205         154 :     *lenp = retind;
    4206             : /*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/
    4207             :   return ret;
    4208             : }
    4209             : 
    4210             : /* Recursively call the parser to parse a $(...) command substitution. */
    4211             : char *
    4212          81 : xparse_dolparen (base, string, indp, flags)
    4213             :      char *base;
    4214             :      char *string;
    4215             :      int *indp;
    4216             :      int flags;
    4217             : {
    4218          81 :   sh_parser_state_t ps;
    4219          81 :   sh_input_line_state_t ls;
    4220          81 :   int nc, sflags, orig_eof_token;
    4221          81 :   char *ret, *ep, *ostring;
    4222             : 
    4223             :   /*yydebug = 1;*/
    4224          81 :   ostring = string;
    4225             : 
    4226             : /*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
    4227          81 :   sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
    4228          81 :   if (flags & SX_NOLONGJMP)
    4229           0 :     sflags |= SEVAL_NOLONGJMP;
    4230          81 :   save_parser_state (&ps);
    4231          81 :   save_input_line_state (&ls);
    4232          81 :   orig_eof_token = shell_eof_token;
    4233             : 
    4234             :   /*(*/
    4235          81 :   parser_state |= PST_CMDSUBST|PST_EOFTOKEN;    /* allow instant ')' */ /*(*/
    4236          81 :   shell_eof_token = ')';
    4237             : 
    4238          81 :   nc = parse_string (string, "command substitution", sflags, &ep);
    4239             : 
    4240          81 :   shell_eof_token = orig_eof_token;
    4241          81 :   restore_parser_state (&ps);
    4242          81 :   reset_parser ();
    4243             :   /* reset_parser clears shell_input_line and associated variables */
    4244          81 :   restore_input_line_state (&ls);
    4245             : 
    4246          81 :   token_to_read = 0;
    4247             : 
    4248             :   /* If parse_string returns < 0, we need to jump to top level with the
    4249             :      negative of the return value */
    4250          81 :   if (nc < 0)
    4251           9 :     jump_to_top_level (-nc);    /* XXX */
    4252             : 
    4253             :   /* Need to find how many characters parse_and_execute consumed, update
    4254             :      *indp, if flags != 0, copy the portion of the string parsed into RET
    4255             :      and return it.  If flags & 1 (EX_NOALLOC) we can return NULL. */
    4256             : 
    4257             :   /*(*/
    4258          72 :   if (ep[-1] != ')')
    4259             :     {
    4260             : #if DEBUG
    4261             :       if (ep[-1] != '\n')
    4262             :         itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
    4263             : #endif
    4264           0 :       while (ep > ostring && ep[-1] == '\n') ep--;
    4265             :     }
    4266             : 
    4267          72 :   nc = ep - ostring;
    4268          72 :   *indp = ep - base - 1;
    4269             : 
    4270             :   /*(*/
    4271             : #if DEBUG
    4272             :   if (base[*indp] != ')')
    4273             :     itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base);
    4274             : #endif
    4275             : 
    4276          72 :   if (flags & SX_NOALLOC) 
    4277             :     return (char *)NULL;
    4278             : 
    4279          72 :   if (nc == 0)
    4280             :     {
    4281           0 :       ret = xmalloc (1);
    4282           0 :       ret[0] = '\0';
    4283             :     }
    4284             :   else
    4285          72 :     ret = substring (ostring, 0, nc - 1);
    4286             : 
    4287             :   return ret;
    4288             : }
    4289             : 
    4290             : #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
    4291             : /* Parse a double-paren construct.  It can be either an arithmetic
    4292             :    command, an arithmetic `for' command, or a nested subshell.  Returns
    4293             :    the parsed token, -1 on error, or -2 if we didn't do anything and
    4294             :    should just go on. */
    4295             : static int
    4296         585 : parse_dparen (c)
    4297             :      int c;
    4298             : {
    4299         585 :   int cmdtyp;
    4300         585 :   char *wval;
    4301         585 :   WORD_DESC *wd;
    4302             : 
    4303             : #if defined (ARITH_FOR_COMMAND)
    4304         585 :   if (last_read_token == FOR)
    4305             :     {
    4306           0 :       arith_for_lineno = line_number;
    4307           0 :       cmdtyp = parse_arith_cmd (&wval, 0);
    4308           0 :       if (cmdtyp == 1)
    4309             :         {
    4310           0 :           wd = alloc_word_desc ();
    4311           0 :           wd->word = wval;
    4312           0 :           yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
    4313           0 :           return (ARITH_FOR_EXPRS);
    4314             :         }
    4315             :       else
    4316             :         return -1;              /* ERROR */
    4317             :     }
    4318             : #endif
    4319             : 
    4320             : #if defined (DPAREN_ARITHMETIC)
    4321         585 :   if (reserved_word_acceptable (last_read_token))
    4322             :     {
    4323         145 :       cmdtyp = parse_arith_cmd (&wval, 0);
    4324         145 :       if (cmdtyp == 1)  /* arithmetic command */
    4325             :         {
    4326           0 :           wd = alloc_word_desc ();
    4327           0 :           wd->word = wval;
    4328           0 :           wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
    4329           0 :           yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
    4330           0 :           return (ARITH_CMD);
    4331             :         }
    4332         145 :       else if (cmdtyp == 0)     /* nested subshell */
    4333             :         {
    4334          54 :           push_string (wval, 0, (alias_t *)NULL);
    4335          54 :           pushed_string_list->flags = PSH_DPAREN;
    4336          54 :           if ((parser_state & PST_CASEPAT) == 0)
    4337          54 :             parser_state |= PST_SUBSHELL;
    4338          54 :           return (c);
    4339             :         }
    4340             :       else                      /* ERROR */
    4341             :         return -1;
    4342             :     }
    4343             : #endif
    4344             : 
    4345             :   return -2;                    /* XXX */
    4346             : }
    4347             : 
    4348             : /* We've seen a `(('.  Look for the matching `))'.  If we get it, return 1.
    4349             :    If not, assume it's a nested subshell for backwards compatibility and
    4350             :    return 0.  In any case, put the characters we've consumed into a locally-
    4351             :    allocated buffer and make *ep point to that buffer.  Return -1 on an
    4352             :    error, for example EOF. */
    4353             : static int
    4354         145 : parse_arith_cmd (ep, adddq)
    4355             :      char **ep;
    4356             :      int adddq;
    4357             : {
    4358         145 :   int rval, c;
    4359         145 :   char *ttok, *tokstr;
    4360         145 :   int ttoklen;
    4361             : 
    4362         145 :   ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0);
    4363         145 :   rval = 1;
    4364         145 :   if (ttok == &matched_pair_error)
    4365             :     return -1;
    4366             :   /* Check that the next character is the closing right paren.  If
    4367             :      not, this is a syntax error. ( */
    4368          54 :   c = shell_getc (0);
    4369          54 :   if MBTEST(c != ')')
    4370          54 :     rval = 0;
    4371             : 
    4372          54 :   tokstr = (char *)xmalloc (ttoklen + 4);
    4373             : 
    4374             :   /* if ADDDQ != 0 then (( ... )) -> "..." */
    4375          54 :   if (rval == 1 && adddq)       /* arith cmd, add double quotes */
    4376             :     {
    4377           0 :       tokstr[0] = '"';
    4378           0 :       strncpy (tokstr + 1, ttok, ttoklen - 1);
    4379           0 :       tokstr[ttoklen] = '"';
    4380           0 :       tokstr[ttoklen+1] = '\0';
    4381             :     }
    4382          54 :   else if (rval == 1)           /* arith cmd, don't add double quotes */
    4383             :     {
    4384           0 :       strncpy (tokstr, ttok, ttoklen - 1);
    4385           0 :       tokstr[ttoklen-1] = '\0';
    4386             :     }
    4387             :   else                          /* nested subshell */
    4388             :     {
    4389          54 :       tokstr[0] = '(';
    4390          54 :       strncpy (tokstr + 1, ttok, ttoklen - 1);
    4391          54 :       tokstr[ttoklen] = ')';
    4392          54 :       tokstr[ttoklen+1] = c;
    4393          54 :       tokstr[ttoklen+2] = '\0';
    4394             :     }
    4395             : 
    4396          54 :   *ep = tokstr;
    4397          54 :   FREE (ttok);
    4398             :   return rval;
    4399             : }
    4400             : #endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */
    4401             : 
    4402             : #if defined (COND_COMMAND)
    4403             : static void
    4404          72 : cond_error ()
    4405             : {
    4406          72 :   char *etext;
    4407             : 
    4408          72 :   if (EOF_Reached && cond_token != COND_ERROR)          /* [[ */
    4409           0 :     parser_error (cond_lineno, _("unexpected EOF while looking for `]]'"));
    4410          72 :   else if (cond_token != COND_ERROR)
    4411             :     {
    4412          27 :       if (etext = error_token_from_token (cond_token))
    4413             :         {
    4414           0 :           parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext);
    4415           0 :           free (etext);
    4416             :         }
    4417             :       else
    4418          27 :         parser_error (cond_lineno, _("syntax error in conditional expression"));
    4419             :     }
    4420          72 : }
    4421             : 
    4422             : static COND_COM *
    4423           0 : cond_expr ()
    4424             : {
    4425           0 :   return (cond_or ());  
    4426             : }
    4427             : 
    4428             : static COND_COM *
    4429          72 : cond_or ()
    4430             : {
    4431          72 :   COND_COM *l, *r;
    4432             : 
    4433          72 :   l = cond_and ();
    4434          72 :   if (cond_token == OR_OR)
    4435             :     {
    4436           0 :       r = cond_or ();
    4437           0 :       l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r);
    4438             :     }
    4439          72 :   return l;
    4440             : }
    4441             : 
    4442             : static COND_COM *
    4443          72 : cond_and ()
    4444             : {
    4445          72 :   COND_COM *l, *r;
    4446             : 
    4447          72 :   l = cond_term ();
    4448          72 :   if (cond_token == AND_AND)
    4449             :     {
    4450           0 :       r = cond_and ();
    4451           0 :       l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r);
    4452             :     }
    4453          72 :   return l;
    4454             : }
    4455             : 
    4456             : static int
    4457         126 : cond_skip_newlines ()
    4458             : {
    4459         144 :   while ((cond_token = read_token (READ)) == '\n')
    4460             :     {
    4461          18 :       if (SHOULD_PROMPT ())
    4462           0 :         prompt_again ();
    4463             :     }
    4464         126 :   return (cond_token);
    4465             : }
    4466             : 
    4467             : #define COND_RETURN_ERROR() \
    4468             :   do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0)
    4469             : 
    4470             : static COND_COM *
    4471          99 : cond_term ()
    4472             : {
    4473          99 :   WORD_DESC *op;
    4474          99 :   COND_COM *term, *tleft, *tright;
    4475          99 :   int tok, lineno;
    4476          99 :   char *etext;
    4477             : 
    4478             :   /* Read a token.  It can be a left paren, a `!', a unary operator, or a
    4479             :      word that should be the first argument of a binary operator.  Start by
    4480             :      skipping newlines, since this is a compound command. */
    4481          99 :   tok = cond_skip_newlines ();
    4482          99 :   lineno = line_number;
    4483          99 :   if (tok == COND_END)
    4484             :     {
    4485           0 :       COND_RETURN_ERROR ();
    4486             :     }
    4487          99 :   else if (tok == '(')
    4488             :     {
    4489           0 :       term = cond_expr ();
    4490           0 :       if (cond_token != ')')
    4491             :         {
    4492           0 :           if (term)
    4493           0 :             dispose_cond_node (term);           /* ( */
    4494           0 :           if (etext = error_token_from_token (cond_token))
    4495             :             {
    4496           0 :               parser_error (lineno, _("unexpected token `%s', expected `)'"), etext);
    4497           0 :               free (etext);
    4498             :             }
    4499             :           else
    4500           0 :             parser_error (lineno, _("expected `)'"));
    4501           0 :           COND_RETURN_ERROR ();
    4502             :         }
    4503           0 :       term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL);
    4504           0 :       (void)cond_skip_newlines ();
    4505             :     }
    4506          99 :   else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0')))
    4507             :     {
    4508          27 :       if (tok == WORD)
    4509          27 :         dispose_word (yylval.word);     /* not needed */
    4510          27 :       term = cond_term ();
    4511          27 :       if (term)
    4512          18 :         term->flags |= CMD_INVERT_RETURN;
    4513             :     }
    4514          72 :   else if (tok == WORD && yylval.word->word[0] == '-' && yylval.word->word[2] == 0 && test_unop (yylval.word->word))
    4515             :     {
    4516          36 :       op = yylval.word;
    4517          36 :       tok = read_token (READ);
    4518          36 :       if (tok == WORD)
    4519             :         {
    4520          27 :           tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
    4521          27 :           term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
    4522             :         }
    4523             :       else
    4524             :         {
    4525           9 :           dispose_word (op);
    4526           9 :           if (etext = error_token_from_token (tok))
    4527             :             {
    4528           0 :               parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext);
    4529           0 :               free (etext);
    4530             :             }
    4531             :           else
    4532           9 :             parser_error (line_number, _("unexpected argument to conditional unary operator"));
    4533           9 :           COND_RETURN_ERROR ();
    4534             :         }
    4535             : 
    4536          27 :       (void)cond_skip_newlines ();
    4537             :     }
    4538          36 :   else if (tok == WORD)         /* left argument to binary operator */
    4539             :     {
    4540             :       /* lhs */
    4541          18 :       tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
    4542             : 
    4543             :       /* binop */
    4544          18 :       tok = read_token (READ);
    4545          18 :       if (tok == WORD && test_binop (yylval.word->word))
    4546             :         {
    4547           0 :           op = yylval.word;
    4548           0 :           if (op->word[0] == '=' && (op->word[1] == '\0' || (op->word[1] == '=' && op->word[2] == '\0')))
    4549           0 :             parser_state |= PST_EXTPAT;
    4550           0 :           else if (op->word[0] == '!' && op->word[1] == '=' && op->word[2] == '\0')
    4551           0 :             parser_state |= PST_EXTPAT;
    4552             :         }
    4553             : #if defined (COND_REGEXP)
    4554          18 :       else if (tok == WORD && STREQ (yylval.word->word, "=~"))
    4555             :         {
    4556           0 :           op = yylval.word;
    4557           0 :           parser_state |= PST_REGEXP;
    4558             :         }
    4559             : #endif
    4560          18 :       else if (tok == '<' || tok == '>')
    4561           0 :         op = make_word_from_token (tok);  /* ( */
    4562             :       /* There should be a check before blindly accepting the `)' that we have
    4563             :          seen the opening `('. */
    4564          18 :       else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')')
    4565             :         {
    4566             :           /* Special case.  [[ x ]] is equivalent to [[ -n x ]], just like
    4567             :              the test command.  Similarly for [[ x && expr ]] or
    4568             :              [[ x || expr ]] or [[ (x) ]]. */
    4569           0 :           op = make_word ("-n");
    4570           0 :           term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
    4571           0 :           cond_token = tok;
    4572           0 :           return (term);
    4573             :         }
    4574             :       else
    4575             :         {
    4576          18 :           if (etext = error_token_from_token (tok))
    4577             :             {
    4578           0 :               parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext);
    4579           0 :               free (etext);
    4580             :             }
    4581             :           else
    4582          18 :             parser_error (line_number, _("conditional binary operator expected"));
    4583          18 :           dispose_cond_node (tleft);
    4584          18 :           COND_RETURN_ERROR ();
    4585             :         }
    4586             : 
    4587             :       /* rhs */
    4588           0 :       if (parser_state & PST_EXTPAT)
    4589           0 :         extended_glob = 1;
    4590           0 :       tok = read_token (READ);
    4591           0 :       if (parser_state & PST_EXTPAT)
    4592           0 :         extended_glob = global_extglob;
    4593           0 :       parser_state &= ~(PST_REGEXP|PST_EXTPAT);
    4594             : 
    4595           0 :       if (tok == WORD)
    4596             :         {
    4597           0 :           tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
    4598           0 :           term = make_cond_node (COND_BINARY, op, tleft, tright);
    4599             :         }
    4600             :       else
    4601             :         {
    4602           0 :           if (etext = error_token_from_token (tok))
    4603             :             {
    4604           0 :               parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext);
    4605           0 :               free (etext);
    4606             :             }
    4607             :           else
    4608           0 :             parser_error (line_number, _("unexpected argument to conditional binary operator"));
    4609           0 :           dispose_cond_node (tleft);
    4610           0 :           dispose_word (op);
    4611           0 :           COND_RETURN_ERROR ();
    4612             :         }
    4613             : 
    4614           0 :       (void)cond_skip_newlines ();
    4615             :     }
    4616             :   else
    4617             :     {
    4618          18 :       if (tok < 256)
    4619           9 :         parser_error (line_number, _("unexpected token `%c' in conditional command"), tok);
    4620           9 :       else if (etext = error_token_from_token (tok))
    4621             :         {
    4622           9 :           parser_error (line_number, _("unexpected token `%s' in conditional command"), etext);
    4623           9 :           free (etext);
    4624             :         }
    4625             :       else
    4626           0 :         parser_error (line_number, _("unexpected token %d in conditional command"), tok);
    4627          18 :       COND_RETURN_ERROR ();
    4628             :     }
    4629             :   return (term);
    4630             : }      
    4631             : 
    4632             : /* This is kind of bogus -- we slip a mini recursive-descent parser in
    4633             :    here to handle the conditional statement syntax. */
    4634             : static COMMAND *
    4635          72 : parse_cond_command ()
    4636             : {
    4637          72 :   COND_COM *cexp;
    4638             : 
    4639          72 :   global_extglob = extended_glob;
    4640          72 :   cexp = cond_expr ();
    4641          72 :   return (make_cond_command (cexp));
    4642             : }
    4643             : #endif
    4644             : 
    4645             : #if defined (ARRAY_VARS)
    4646             : /* When this is called, it's guaranteed that we don't care about anything
    4647             :    in t beyond i.  We do save and restore the chars, though. */
    4648             : static int
    4649    56809186 : token_is_assignment (t, i)
    4650             :      char *t;
    4651             :      int i;
    4652             : {
    4653    56809186 :   unsigned char c, c1;
    4654    56809186 :   int r;
    4655             : 
    4656    56809186 :   c = t[i]; c1 = t[i+1];
    4657    56809186 :   t[i] = '='; t[i+1] = '\0';
    4658    56809186 :   r = assignment (t, (parser_state & PST_COMPASSIGN) != 0);
    4659    56809186 :   t[i] = c; t[i+1] = c1;
    4660    56809186 :   return r;
    4661             : }
    4662             : 
    4663             : /* XXX - possible changes here for `+=' */
    4664             : static int
    4665             : token_is_ident (t, i)
    4666             :      char *t;
    4667             :      int i;
    4668             : {
    4669       53444 :   unsigned char c;
    4670       53444 :   int r;
    4671             : 
    4672       53444 :   c = t[i];
    4673       53444 :   t[i] = '\0';
    4674      106888 :   r = legal_identifier (t);
    4675       53444 :   t[i] = c;
    4676       53444 :   return r;
    4677             : }
    4678             : #endif
    4679             : 
    4680             : static int
    4681  1184640701 : read_token_word (character)
    4682             :      int character;
    4683             : {
    4684             :   /* The value for YYLVAL when a WORD is read. */
    4685  1184640701 :   WORD_DESC *the_word;
    4686             : 
    4687             :   /* Index into the token that we are building. */
    4688  1184640701 :   int token_index;
    4689             : 
    4690             :   /* ALL_DIGITS becomes zero when we see a non-digit. */
    4691  1184640701 :   int all_digit_token;
    4692             : 
    4693             :   /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
    4694  1184640701 :   int dollar_present;
    4695             : 
    4696             :   /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound
    4697             :      assignment. */
    4698  1184640701 :   int compound_assignment;
    4699             : 
    4700             :   /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
    4701  1184640701 :   int quoted;
    4702             : 
    4703             :   /* Non-zero means to ignore the value of the next character, and just
    4704             :      to add it no matter what. */
    4705  1184640701 :   int pass_next_character;
    4706             : 
    4707             :   /* The current delimiting character. */
    4708  1184640701 :   int cd;
    4709  1184640701 :   int result, peek_char;
    4710  1184640701 :   char *ttok, *ttrans;
    4711  1184640701 :   int ttoklen, ttranslen;
    4712  1184640701 :   intmax_t lvalue;
    4713             : 
    4714  1184640701 :   if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE)
    4715     9543185 :     token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE);
    4716             : 
    4717  1184640701 :   token_index = 0;
    4718  1184640701 :   all_digit_token = DIGIT (character);
    4719  1184640701 :   dollar_present = quoted = pass_next_character = compound_assignment = 0;
    4720             : 
    4721 11329721279 :   for (;;)
    4722             :     {
    4723  6257180990 :       if (character == EOF)
    4724          59 :         goto got_token;
    4725             : 
    4726  6257180931 :       if (pass_next_character)
    4727             :         {
    4728             :           pass_next_character = 0;
    4729             :           goto got_escaped_character;
    4730             :         }
    4731             : 
    4732  6256141612 :       cd = current_delimiter (dstack);
    4733             : 
    4734             :       /* Handle backslashes.  Quote lots of things when not inside of
    4735             :          double-quotes, quote some things inside of double-quotes. */
    4736  6256141612 :       if MBTEST(character == '\\')
    4737             :         {
    4738     1039319 :           peek_char = shell_getc (0);
    4739             : 
    4740             :           /* Backslash-newline is ignored in all cases except
    4741             :              when quoted with single quotes. */
    4742     1039319 :           if (peek_char == '\n')
    4743             :             {
    4744             :               character = '\n';
    4745             :               goto next_character;
    4746             :             }
    4747             :           else
    4748             :             {
    4749     1039319 :               shell_ungetc (peek_char);
    4750             : 
    4751             :               /* If the next character is to be quoted, note it now. */
    4752     1039319 :               if (cd == 0 || cd == '`' ||
    4753           0 :                   (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE)))
    4754     1039319 :                 pass_next_character++;
    4755             : 
    4756     1039319 :               quoted = 1;
    4757     1039319 :               goto got_character;
    4758             :             }
    4759             :         }
    4760             : 
    4761             :       /* Parse a matched pair of quote characters. */
    4762  6255102293 :       if MBTEST(shellquote (character))
    4763             :         {
    4764   154536012 :           push_delimiter (dstack, character);
    4765   309029480 :           ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 0);
    4766   154536012 :           pop_delimiter (dstack);
    4767   154536012 :           if (ttok == &matched_pair_error)
    4768             :             return -1;          /* Bail immediately. */
    4769   154353432 :           RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
    4770             :                                   token_buffer_size, TOKEN_DEFAULT_GROW_SIZE);
    4771   154350729 :           token[token_index++] = character;
    4772   154350729 :           strcpy (token + token_index, ttok);
    4773   154350729 :           token_index += ttoklen;
    4774   154350729 :           all_digit_token = 0;
    4775   154350729 :           quoted = 1;
    4776   154350729 :           dollar_present |= (character == '"' && strchr (ttok, '$') != 0);
    4777   154350729 :           FREE (ttok);
    4778   154350729 :           goto next_character;
    4779             :         }
    4780             : 
    4781             : #ifdef COND_REGEXP
    4782             :       /* When parsing a regexp as a single word inside a conditional command,
    4783             :          we need to special-case characters special to both the shell and
    4784             :          regular expressions.  Right now, that is only '(' and '|'. */ /*)*/
    4785  6100566281 :       if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|'))              /*)*/
    4786             :         {
    4787           0 :           if (character == '|')
    4788             :             goto got_character;
    4789             : 
    4790           0 :           push_delimiter (dstack, character);
    4791           0 :           ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
    4792           0 :           pop_delimiter (dstack);
    4793           0 :           if (ttok == &matched_pair_error)
    4794             :             return -1;          /* Bail immediately. */
    4795           0 :           RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
    4796             :                                   token_buffer_size, TOKEN_DEFAULT_GROW_SIZE);
    4797           0 :           token[token_index++] = character;
    4798           0 :           strcpy (token + token_index, ttok);
    4799           0 :           token_index += ttoklen;
    4800           0 :           FREE (ttok);
    4801           0 :           dollar_present = all_digit_token = 0;
    4802           0 :           goto next_character;
    4803             :         }
    4804             : #endif /* COND_REGEXP */
    4805             : 
    4806             : #ifdef EXTENDED_GLOB
    4807             :       /* Parse a ksh-style extended pattern matching specification. */
    4808  6100566281 :       if MBTEST(extended_glob && PATTERN_CHAR (character))
    4809             :         {
    4810           0 :           peek_char = shell_getc (1);
    4811           0 :           if MBTEST(peek_char == '(')           /* ) */
    4812             :             {
    4813           0 :               push_delimiter (dstack, peek_char);
    4814           0 :               ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
    4815           0 :               pop_delimiter (dstack);
    4816           0 :               if (ttok == &matched_pair_error)
    4817             :                 return -1;              /* Bail immediately. */
    4818           0 :               RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
    4819             :                                       token_buffer_size,
    4820             :                                       TOKEN_DEFAULT_GROW_SIZE);
    4821           0 :               token[token_index++] = character;
    4822           0 :               token[token_index++] = peek_char;
    4823           0 :               strcpy (token + token_index, ttok);
    4824           0 :               token_index += ttoklen;
    4825           0 :               FREE (ttok);
    4826           0 :               dollar_present = all_digit_token = 0;
    4827           0 :               goto next_character;
    4828             :             }
    4829             :           else
    4830           0 :             shell_ungetc (peek_char);
    4831             :         }
    4832             : #endif /* EXTENDED_GLOB */
    4833             : 
    4834             :       /* If the delimiter character is not single quote, parse some of
    4835             :          the shell expansions that must be read as a single word. */
    4836  6100566281 :       if (shellexp (character))
    4837             :         {
    4838    34906015 :           peek_char = shell_getc (1);
    4839             :           /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
    4840    34906015 :           if MBTEST(peek_char == '(' ||
    4841             :                 ((peek_char == '{' || peek_char == '[') && character == '$'))   /* ) ] } */
    4842             :             {
    4843       61899 :               if (peek_char == '{')             /* } */
    4844       61175 :                 ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE|P_DOLBRACE);
    4845         724 :               else if (peek_char == '(')                /* ) */
    4846             :                 {
    4847             :                   /* XXX - push and pop the `(' as a delimiter for use by
    4848             :                      the command-oriented-history code.  This way newlines
    4849             :                      appearing in the $(...) string get added to the
    4850             :                      history literally rather than causing a possibly-
    4851             :                      incorrect `;' to be added. ) */
    4852         450 :                   push_delimiter (dstack, peek_char);
    4853         450 :                   ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND);
    4854         450 :                   pop_delimiter (dstack);
    4855             :                 }
    4856             :               else
    4857         274 :                 ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
    4858       61899 :               if (ttok == &matched_pair_error)
    4859             :                 return -1;              /* Bail immediately. */
    4860       61316 :               RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
    4861             :                                       token_buffer_size,
    4862             :                                       TOKEN_DEFAULT_GROW_SIZE);
    4863       61121 :               token[token_index++] = character;
    4864       61121 :               token[token_index++] = peek_char;
    4865       61121 :               strcpy (token + token_index, ttok);
    4866       61121 :               token_index += ttoklen;
    4867       61121 :               FREE (ttok);
    4868       61121 :               dollar_present = 1;
    4869       61121 :               all_digit_token = 0;
    4870       61121 :               goto next_character;
    4871             :             }
    4872             :           /* This handles $'...' and $"..." new-style quoted strings. */
    4873    34844116 :           else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"'))
    4874             :             {
    4875         414 :               int first_line;
    4876             : 
    4877         414 :               first_line = line_number;
    4878         414 :               push_delimiter (dstack, peek_char);
    4879         655 :               ttok = parse_matched_pair (peek_char, peek_char, peek_char,
    4880             :                                          &ttoklen,
    4881             :                                          (peek_char == '\'') ? P_ALLOWESC : 0);
    4882         414 :               pop_delimiter (dstack);
    4883         414 :               if (ttok == &matched_pair_error)
    4884             :                 return -1;
    4885         308 :               if (peek_char == '\'')
    4886             :                 {
    4887         106 :                   ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
    4888         106 :                   free (ttok);
    4889             : 
    4890             :                   /* Insert the single quotes and correctly quote any
    4891             :                      embedded single quotes (allowed because P_ALLOWESC was
    4892             :                      passed to parse_matched_pair). */
    4893         106 :                   ttok = sh_single_quote (ttrans);
    4894         106 :                   free (ttrans);
    4895         106 :                   ttranslen = strlen (ttok);
    4896         106 :                   ttrans = ttok;
    4897             :                 }
    4898             :               else
    4899             :                 {
    4900             :                   /* Try to locale-expand the converted string. */
    4901         202 :                   ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
    4902         202 :                   free (ttok);
    4903             : 
    4904             :                   /* Add the double quotes back */
    4905         202 :                   ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
    4906         202 :                   free (ttrans);
    4907         202 :                   ttranslen += 2;
    4908         202 :                   ttrans = ttok;
    4909             :                 }
    4910             : 
    4911         308 :               RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1,
    4912             :                                       token_buffer_size,
    4913             :                                       TOKEN_DEFAULT_GROW_SIZE);
    4914         308 :               strcpy (token + token_index, ttrans);
    4915         308 :               token_index += ttranslen;
    4916         308 :               FREE (ttrans);
    4917         308 :               quoted = 1;
    4918         308 :               all_digit_token = 0;
    4919         308 :               goto next_character;
    4920             :             }
    4921             :           /* This could eventually be extended to recognize all of the
    4922             :              shell's single-character parameter expansions, and set flags.*/
    4923    34843702 :           else if MBTEST(character == '$' && peek_char == '$')
    4924             :             {
    4925        3548 :               RESIZE_MALLOCED_BUFFER (token, token_index, 3,
    4926             :                                       token_buffer_size,
    4927             :                                       TOKEN_DEFAULT_GROW_SIZE);
    4928        3548 :               token[token_index++] = '$';
    4929        3548 :               token[token_index++] = peek_char;
    4930        3548 :               dollar_present = 1;
    4931        3548 :               all_digit_token = 0;
    4932        3548 :               goto next_character;
    4933             :             }
    4934             :           else
    4935    34840154 :             shell_ungetc (peek_char);
    4936             :         }
    4937             : 
    4938             : #if defined (ARRAY_VARS)
    4939             :       /* Identify possible array subscript assignment; match [...].  If
    4940             :          parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating
    4941             :          `sub' as if it were enclosed in double quotes. */
    4942  6065660266 :       else if MBTEST(character == '[' &&                /* ] */
    4943             :                      ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) ||
    4944             :                       (token_index == 0 && (parser_state&PST_COMPASSIGN))))
    4945             :         {
    4946       25918 :           ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB);
    4947       25918 :           if (ttok == &matched_pair_error)
    4948             :             return -1;          /* Bail immediately. */
    4949       22200 :           RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
    4950             :                                   token_buffer_size,
    4951             :                                   TOKEN_DEFAULT_GROW_SIZE);
    4952       22125 :           token[token_index++] = character;
    4953       22125 :           strcpy (token + token_index, ttok);
    4954       22125 :           token_index += ttoklen;
    4955       22125 :           FREE (ttok);
    4956       22125 :           all_digit_token = 0;
    4957       22125 :           goto next_character;
    4958             :         }
    4959             :       /* Identify possible compound array variable assignment. */
    4960  6065634348 :       else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index))
    4961             :         {
    4962    56737444 :           peek_char = shell_getc (1);
    4963    56737444 :           if MBTEST(peek_char == '(')           /* ) */
    4964             :             {
    4965         273 :               ttok = parse_compound_assignment (&ttoklen);
    4966             : 
    4967          67 :               RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4,
    4968             :                                       token_buffer_size,
    4969             :                                       TOKEN_DEFAULT_GROW_SIZE);
    4970             : 
    4971          67 :               token[token_index++] = '=';
    4972          67 :               token[token_index++] = '(';
    4973          67 :               if (ttok)
    4974             :                 {
    4975          18 :                   strcpy (token + token_index, ttok);
    4976          18 :                   token_index += ttoklen;
    4977             :                 }
    4978          67 :               token[token_index++] = ')';
    4979          67 :               FREE (ttok);
    4980          67 :               all_digit_token = 0;
    4981          67 :               compound_assignment = 1;
    4982             : #if 1
    4983          67 :               goto next_character;
    4984             : #else
    4985             :               goto got_token;           /* ksh93 seems to do this */
    4986             : #endif
    4987             :             }
    4988             :           else
    4989    56737171 :             shell_ungetc (peek_char);
    4990             :         }
    4991             : #endif
    4992             : 
    4993             :       /* When not parsing a multi-character word construct, shell meta-
    4994             :          characters break words. */
    4995  6100474229 :       if MBTEST(shellbreak (character))
    4996             :         {
    4997  1184450476 :           shell_ungetc (character);
    4998  1184450476 :           goto got_token;
    4999             :         }
    5000             : 
    5001  4916023753 : got_character:
    5002  4917063072 :       if (character == CTLESC || character == CTLNUL)
    5003             :         {
    5004     4968500 :           RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
    5005             :                                   TOKEN_DEFAULT_GROW_SIZE);
    5006     4968500 :           token[token_index++] = CTLESC;
    5007             :         }
    5008             :       else
    5009  4912094572 : got_escaped_character:
    5010  4913134147 :         RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
    5011             :                                 TOKEN_DEFAULT_GROW_SIZE);
    5012             : 
    5013  4918102391 :       token[token_index++] = character;
    5014             : 
    5015  4918102391 :       all_digit_token &= DIGIT (character);
    5016  4918102391 :       dollar_present |= character == '$';
    5017             : 
    5018  5072540289 :     next_character:
    5019  5072540289 :       if (character == '\n' && SHOULD_PROMPT ())
    5020           0 :         prompt_again ();
    5021             : 
    5022             :       /* We want to remove quoted newlines (that is, a \<newline> pair)
    5023             :          unless we are within single quotes or pass_next_character is
    5024             :          set (the shell equivalent of literal-next). */
    5025  5072540289 :       cd = current_delimiter (dstack);
    5026  5072540289 :       character = shell_getc (cd != '\'' && pass_next_character == 0);
    5027             :     }   /* end for (;;) */
    5028             : 
    5029  1184450535 : got_token:
    5030             : 
    5031             :   /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */
    5032  1184450535 :   token[token_index] = '\0';
    5033             : 
    5034             :   /* Check to see what thing we should return.  If the last_read_token
    5035             :      is a `<', or a `&', or the character which ended this token is
    5036             :      a '>' or '<', then, and ONLY then, is this input token a NUMBER.
    5037             :      Otherwise, it is just a word, and should be returned as such. */
    5038  1184450535 :   if MBTEST(all_digit_token && (character == '<' || character == '>' ||
    5039             :                     last_read_token == LESS_AND ||
    5040             :                     last_read_token == GREATER_AND))
    5041             :       {
    5042     5352505 :         if (legal_number (token, &lvalue) && (int)lvalue == lvalue)
    5043             :           {
    5044     5352505 :             yylval.number = lvalue;
    5045     5352505 :             return (NUMBER);
    5046             :           }
    5047             :       }
    5048             : 
    5049             :   /* Check for special case tokens. */
    5050  1179098030 :   result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1;
    5051  1179036241 :   if (result >= 0)
    5052             :     return result;
    5053             : 
    5054             : #if defined (ALIAS)
    5055             :   /* Posix.2 does not allow reserved words to be aliased, so check for all
    5056             :      of them, including special cases, before expanding the current token
    5057             :      as an alias. */
    5058  1116140575 :   if MBTEST(posixly_correct)
    5059           0 :     CHECK_FOR_RESERVED_WORD (token);
    5060             : 
    5061             :   /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting
    5062             :      inhibits alias expansion. */
    5063  1116140575 :   if (expand_aliases && quoted == 0)
    5064             :     {
    5065           0 :       result = alias_expand_token (token);
    5066           0 :       if (result == RE_READ_TOKEN)
    5067             :         return (RE_READ_TOKEN);
    5068           0 :       else if (result == NO_EXPANSION)
    5069           0 :         parser_state &= ~PST_ALEXPNEXT;
    5070             :     }
    5071             : 
    5072             :   /* If not in Posix.2 mode, check for reserved words after alias
    5073             :      expansion. */
    5074  1116140575 :   if MBTEST(posixly_correct == 0)
    5075             : #endif
    5076  9198670516 :     CHECK_FOR_RESERVED_WORD (token);
    5077             : 
    5078   843160871 :   the_word = alloc_word_desc ();
    5079   843160871 :   the_word->word = (char *)xmalloc (1 + token_index);
    5080   843160871 :   the_word->flags = 0;
    5081   843160871 :   strcpy (the_word->word, token);
    5082   843160871 :   if (dollar_present)
    5083   146619489 :     the_word->flags |= W_HASDOLLAR;
    5084   843160871 :   if (quoted)
    5085   155163845 :     the_word->flags |= W_QUOTED;             /*(*/
    5086   843160871 :   if (compound_assignment && token[token_index-1] == ')')
    5087          67 :     the_word->flags |= W_COMPASSIGN;
    5088             :   /* A word is an assignment if it appears at the beginning of a
    5089             :      simple command, or after another assignment word.  This is
    5090             :      context-dependent, so it cannot be handled in the grammar. */
    5091   843160871 :   if (assignment (token, (parser_state & PST_COMPASSIGN) != 0))
    5092             :     {
    5093    56759731 :       the_word->flags |= W_ASSIGNMENT;
    5094             :       /* Don't perform word splitting on assignment statements. */
    5095    56759731 :       if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0)
    5096             :         {
    5097    56721458 :           the_word->flags |= W_NOSPLIT;
    5098    56721458 :           if (parser_state & PST_COMPASSIGN)
    5099          67 :             the_word->flags |= W_NOGLOB;     /* XXX - W_NOBRACE? */
    5100             :         }
    5101             :     }
    5102             : 
    5103   843160871 :   if (command_token_position (last_read_token))
    5104             :     {
    5105   375656737 :       struct builtin *b;
    5106   375656737 :       b = builtin_address_internal (token, 0);
    5107   375656737 :       if (b && (b->flags & ASSIGNMENT_BUILTIN))
    5108        1779 :         parser_state |= PST_ASSIGNOK;
    5109   375654958 :       else if (STREQ (token, "eval") || STREQ (token, "let"))
    5110         363 :         parser_state |= PST_ASSIGNOK;
    5111             :     }
    5112             : 
    5113   843160871 :   yylval.word = the_word;
    5114             : 
    5115   843160871 :   if (token[0] == '{' && token[token_index-1] == '}' &&
    5116          87 :       (character == '<' || character == '>'))
    5117             :     {
    5118             :       /* can use token; already copied to the_word */
    5119           0 :       token[token_index-1] = '\0';
    5120             : #if defined (ARRAY_VARS)
    5121           0 :       if (legal_identifier (token+1) || valid_array_reference (token+1, 0))
    5122             : #else
    5123             :       if (legal_identifier (token+1))
    5124             : #endif
    5125             :         {
    5126           0 :           strcpy (the_word->word, token+1);
    5127             : /*itrace("read_token_word: returning REDIR_WORD for %s", the_word->word);*/
    5128           0 :           return (REDIR_WORD);
    5129             :         }
    5130             :     }
    5131             : 
    5132  1686321742 :   result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT))
    5133   843160871 :                 ? ASSIGNMENT_WORD : WORD;
    5134             : 
    5135   843160871 :   switch (last_read_token)
    5136             :     {
    5137         248 :     case FUNCTION:
    5138         248 :       parser_state |= PST_ALLOWOPNBRC;
    5139         248 :       function_dstart = line_number;
    5140         248 :       break;
    5141    25265945 :     case CASE:
    5142             :     case SELECT:
    5143             :     case FOR:
    5144    25265945 :       if (word_top < MAX_CASE_NEST)
    5145    25265945 :         word_top++;
    5146    25265945 :       word_lineno[word_top] = line_number;
    5147    25265945 :       break;
    5148             :     }
    5149             : 
    5150             :   return (result);
    5151             : }
    5152             : 
    5153             : /* Return 1 if TOKSYM is a token that after being read would allow
    5154             :    a reserved word to be seen, else 0. */
    5155             : static int
    5156  2050821792 : reserved_word_acceptable (toksym)
    5157             :      int toksym;
    5158             : {
    5159  2050821792 :   switch (toksym)
    5160             :     {
    5161             :     case '\n':
    5162             :     case ';':
    5163             :     case '(':
    5164             :     case ')':
    5165             :     case '|':
    5166             :     case '&':
    5167             :     case '{':
    5168             :     case '}':           /* XXX */
    5169             :     case AND_AND:
    5170             :     case BANG:
    5171             :     case BAR_AND:
    5172             :     case DO:
    5173             :     case DONE:
    5174             :     case ELIF:
    5175             :     case ELSE:
    5176             :     case ESAC:
    5177             :     case FI:
    5178             :     case IF:
    5179             :     case OR_OR:
    5180             :     case SEMI_SEMI:
    5181             :     case SEMI_AND:
    5182             :     case SEMI_SEMI_AND:
    5183             :     case THEN:
    5184             :     case TIME:
    5185             :     case TIMEOPT:
    5186             :     case TIMEIGN:
    5187             :     case COPROC:
    5188             :     case UNTIL:
    5189             :     case WHILE:
    5190             :     case 0:
    5191             :       return 1;
    5192   864531023 :     default:
    5193             : #if defined (COPROCESS_SUPPORT)
    5194   864531023 :       if (last_read_token == WORD && token_before_that == COPROC)
    5195             :         return 1;
    5196             : #endif
    5197   864531023 :       if (last_read_token == WORD && token_before_that == FUNCTION)
    5198         198 :         return 1;
    5199             :       return 0;
    5200             :     }
    5201             : }
    5202             :     
    5203             : /* Return the index of TOKEN in the alist of reserved words, or -1 if
    5204             :    TOKEN is not a shell reserved word. */
    5205             : int
    5206          54 : find_reserved_word (tokstr)
    5207             :      char *tokstr;
    5208             : {
    5209          54 :   int i;
    5210        1188 :   for (i = 0; word_token_alist[i].word; i++)
    5211        1134 :     if (STREQ (tokstr, word_token_alist[i].word))
    5212           0 :       return i;
    5213             :   return -1;
    5214             : }
    5215             : 
    5216             : /* An interface to let the rest of the shell (primarily the completion
    5217             :    system) know what the parser is expecting. */
    5218             : int
    5219           0 : parser_in_command_position ()
    5220             : {
    5221           0 :   return (command_token_position (last_read_token));
    5222             : }
    5223             : 
    5224             : #if 0
    5225             : #if defined (READLINE)
    5226             : /* Called after each time readline is called.  This insures that whatever
    5227             :    the new prompt string is gets propagated to readline's local prompt
    5228             :    variable. */
    5229             : static void
    5230             : reset_readline_prompt ()
    5231             : {
    5232             :   char *temp_prompt;
    5233             : 
    5234             :   if (prompt_string_pointer)
    5235             :     {
    5236             :       temp_prompt = (*prompt_string_pointer)
    5237             :                         ? decode_prompt_string (*prompt_string_pointer)
    5238             :                         : (char *)NULL;
    5239             : 
    5240             :       if (temp_prompt == 0)
    5241             :         {
    5242             :           temp_prompt = (char *)xmalloc (1);
    5243             :           temp_prompt[0] = '\0';
    5244             :         }
    5245             : 
    5246             :       FREE (current_readline_prompt);
    5247             :       current_readline_prompt = temp_prompt;
    5248             :     }
    5249             : }
    5250             : #endif /* READLINE */
    5251             : #endif /* 0 */
    5252             : 
    5253             : #if defined (HISTORY)
    5254             : /* A list of tokens which can be followed by newlines, but not by
    5255             :    semi-colons.  When concatenating multiple lines of history, the
    5256             :    newline separator for such tokens is replaced with a space. */
    5257             : static const int no_semi_successors[] = {
    5258             :   '\n', '{', '(', ')', ';', '&', '|',
    5259             :   CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, THEN, UNTIL,
    5260             :   WHILE, AND_AND, OR_OR, IN,
    5261             :   0
    5262             : };
    5263             : 
    5264             : /* If we are not within a delimited expression, try to be smart
    5265             :    about which separators can be semi-colons and which must be
    5266             :    newlines.  Returns the string that should be added into the
    5267             :    history entry.  LINE is the line we're about to add; it helps
    5268             :    make some more intelligent decisions in certain cases. */
    5269             : char *
    5270             : history_delimiting_chars (line)
    5271             :      const char *line;
    5272             : {
    5273             :   static int last_was_heredoc = 0;      /* was the last entry the start of a here document? */
    5274             :   register int i;
    5275             : 
    5276             :   if ((parser_state & PST_HEREDOC) == 0)
    5277             :     last_was_heredoc = 0;
    5278             : 
    5279             :   if (dstack.delimiter_depth != 0)
    5280             :     return ("\n");
    5281             : 
    5282             :   /* We look for current_command_line_count == 2 because we are looking to
    5283             :      add the first line of the body of the here document (the second line
    5284             :      of the command).  We also keep LAST_WAS_HEREDOC as a private sentinel
    5285             :      variable to note when we think we added the first line of a here doc
    5286             :      (the one with a "<<" somewhere in it) */
    5287             :   if (parser_state & PST_HEREDOC)
    5288             :     {
    5289             :       if (last_was_heredoc)
    5290             :         {
    5291             :           last_was_heredoc = 0;
    5292             :           return "\n";
    5293             :         }
    5294             :       return (here_doc_first_line ? "\n" : "");
    5295             :     }
    5296             : 
    5297             :   if (parser_state & PST_COMPASSIGN)
    5298             :     return (" ");
    5299             : 
    5300             :   /* First, handle some special cases. */
    5301             :   /*(*/
    5302             :   /* If we just read `()', assume it's a function definition, and don't
    5303             :      add a semicolon.  If the token before the `)' was not `(', and we're
    5304             :      not in the midst of parsing a case statement, assume it's a
    5305             :      parenthesized command and add the semicolon. */
    5306             :   /*)(*/
    5307             :   if (token_before_that == ')')
    5308             :     {
    5309             :       if (two_tokens_ago == '(')        /*)*/   /* function def */
    5310             :         return " ";
    5311             :       /* This does not work for subshells inside case statement
    5312             :          command lists.  It's a suboptimal solution. */
    5313             :       else if (parser_state & PST_CASESTMT) /* case statement pattern */
    5314             :         return " ";
    5315             :       else
    5316             :         return "; ";                          /* (...) subshell */
    5317             :     }
    5318             :   else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
    5319             :     return " ";               /* function def using `function name' without `()' */
    5320             : 
    5321             :   /* If we're not in a here document, but we think we're about to parse one,
    5322             :      and we would otherwise return a `;', return a newline to delimit the
    5323             :      line with the here-doc delimiter */
    5324             :   else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && last_read_token == '\n' && strstr (line, "<<"))
    5325             :     {
    5326             :       last_was_heredoc = 1;
    5327             :       return "\n";
    5328             :     }
    5329             :   else if ((parser_state & PST_HEREDOC) == 0 && current_command_line_count > 1 && need_here_doc > 0)
    5330             :     return "\n";
    5331             :   else if (token_before_that == WORD && two_tokens_ago == FOR)
    5332             :     {
    5333             :       /* Tricky.  `for i\nin ...' should not have a semicolon, but
    5334             :          `for i\ndo ...' should.  We do what we can. */
    5335             :       for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++)
    5336             :         ;
    5337             :       if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n')
    5338             :         return " ";
    5339             :       return ";";
    5340             :     }
    5341             :   else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT))
    5342             :     return " ";
    5343             : 
    5344             :   for (i = 0; no_semi_successors[i]; i++)
    5345             :     {
    5346             :       if (token_before_that == no_semi_successors[i])
    5347             :         return (" ");
    5348             :     }
    5349             : 
    5350             :   return ("; ");
    5351             : }
    5352             : #endif /* HISTORY */
    5353             : 
    5354             : /* Issue a prompt, or prepare to issue a prompt when the next character
    5355             :    is read. */
    5356             : static void
    5357           0 : prompt_again ()
    5358             : {
    5359           0 :   char *temp_prompt;
    5360             : 
    5361           0 :   if (interactive == 0 || expanding_alias ())   /* XXX */
    5362             :     return;
    5363             : 
    5364           0 :   ps1_prompt = get_string_value ("PS1");
    5365           0 :   ps2_prompt = get_string_value ("PS2");
    5366             : 
    5367           0 :   ps0_prompt = get_string_value ("PS0");
    5368             : 
    5369           0 :   if (!prompt_string_pointer)
    5370           0 :     prompt_string_pointer = &ps1_prompt;
    5371             : 
    5372           0 :   temp_prompt = *prompt_string_pointer
    5373           0 :                         ? decode_prompt_string (*prompt_string_pointer)
    5374           0 :                         : (char *)NULL;
    5375             : 
    5376           0 :   if (temp_prompt == 0)
    5377             :     {
    5378           0 :       temp_prompt = (char *)xmalloc (1);
    5379           0 :       temp_prompt[0] = '\0';
    5380             :     }
    5381             : 
    5382           0 :   current_prompt_string = *prompt_string_pointer;
    5383           0 :   prompt_string_pointer = &ps2_prompt;
    5384             : 
    5385             : #if defined (READLINE)
    5386             :   if (!no_line_editing)
    5387             :     {
    5388             :       FREE (current_readline_prompt);
    5389             :       current_readline_prompt = temp_prompt;
    5390             :     }
    5391             :   else
    5392             : #endif  /* READLINE */
    5393             :     {
    5394           0 :       FREE (current_decoded_prompt);
    5395           0 :       current_decoded_prompt = temp_prompt;
    5396             :     }
    5397             : }
    5398             : 
    5399             : int
    5400           0 : get_current_prompt_level ()
    5401             : {
    5402           0 :   return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1);
    5403             : }
    5404             : 
    5405             : void
    5406   188633223 : set_current_prompt_level (x)
    5407             :      int x;
    5408             : {
    5409   188633223 :   prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt;
    5410   188633223 :   current_prompt_string = *prompt_string_pointer;
    5411   188633223 : }
    5412             :       
    5413             : static void
    5414           0 : print_prompt ()
    5415             : {
    5416           0 :   fprintf (stderr, "%s", current_decoded_prompt);
    5417           0 :   fflush (stderr);
    5418           0 : }
    5419             : 
    5420             : /* Return a string which will be printed as a prompt.  The string
    5421             :    may contain special characters which are decoded as follows:
    5422             : 
    5423             :         \a      bell (ascii 07)
    5424             :         \d      the date in Day Mon Date format
    5425             :         \e      escape (ascii 033)
    5426             :         \h      the hostname up to the first `.'
    5427             :         \H      the hostname
    5428             :         \j      the number of active jobs
    5429             :         \l      the basename of the shell's tty device name
    5430             :         \n      CRLF
    5431             :         \r      CR
    5432             :         \s      the name of the shell
    5433             :         \t      the time in 24-hour hh:mm:ss format
    5434             :         \T      the time in 12-hour hh:mm:ss format
    5435             :         \@      the time in 12-hour hh:mm am/pm format
    5436             :         \A      the time in 24-hour hh:mm format
    5437             :         \D{fmt} the result of passing FMT to strftime(3)
    5438             :         \u      your username
    5439             :         \v      the version of bash (e.g., 2.00)
    5440             :         \V      the release of bash, version + patchlevel (e.g., 2.00.0)
    5441             :         \w      the current working directory
    5442             :         \W      the last element of $PWD
    5443             :         \!      the history number of this command
    5444             :         \#      the command number of this command
    5445             :         \$      a $ or a # if you are root
    5446             :         \nnn    character code nnn in octal
    5447             :         \\      a backslash
    5448             :         \[      begin a sequence of non-printing chars
    5449             :         \]      end a sequence of non-printing chars
    5450             : */
    5451             : #define PROMPT_GROWTH 48
    5452             : char *
    5453           0 : decode_prompt_string (string)
    5454             :      char *string;
    5455             : {
    5456           0 :   WORD_LIST *list;
    5457           0 :   char *result, *t;
    5458           0 :   struct dstack save_dstack;
    5459           0 :   int last_exit_value, last_comsub_pid;
    5460             : #if defined (PROMPT_STRING_DECODE)
    5461           0 :   size_t result_size;
    5462           0 :   int result_index;
    5463           0 :   int c, n;
    5464             : #if defined (READLINE)
    5465             :   int i;
    5466             : #endif
    5467           0 :   char *temp, *t_host, octal_string[4];
    5468           0 :   struct tm *tm;  
    5469           0 :   time_t the_time;
    5470           0 :   char timebuf[128];
    5471           0 :   char *timefmt;
    5472             : 
    5473           0 :   result = (char *)xmalloc (result_size = PROMPT_GROWTH);
    5474           0 :   result[result_index = 0] = 0;
    5475           0 :   temp = (char *)NULL;
    5476             : 
    5477           0 :   while (c = *string++)
    5478             :     {
    5479           0 :       if (posixly_correct && c == '!')
    5480             :         {
    5481           0 :           if (*string == '!')
    5482             :             {
    5483           0 :               temp = savestring ("!");
    5484           0 :               goto add_string;
    5485             :             }
    5486             :           else
    5487             :             {
    5488             : #if !defined (HISTORY)
    5489           0 :                 temp = savestring ("1");
    5490             : #else /* HISTORY */
    5491             :                 temp = itos (history_number ());
    5492             : #endif /* HISTORY */
    5493           0 :                 string--;       /* add_string increments string again. */
    5494           0 :                 goto add_string;
    5495             :             }
    5496             :         }
    5497           0 :       if (c == '\\')
    5498             :         {
    5499           0 :           c = *string;
    5500             : 
    5501           0 :           switch (c)
    5502             :             {
    5503             :             case '0':
    5504             :             case '1':
    5505             :             case '2':
    5506             :             case '3':
    5507             :             case '4':
    5508             :             case '5':
    5509             :             case '6':
    5510             :             case '7':
    5511           0 :               strncpy (octal_string, string, 3);
    5512           0 :               octal_string[3] = '\0';
    5513             : 
    5514           0 :               n = read_octal (octal_string);
    5515           0 :               temp = (char *)xmalloc (3);
    5516             : 
    5517           0 :               if (n == CTLESC || n == CTLNUL)
    5518             :                 {
    5519           0 :                   temp[0] = CTLESC;
    5520           0 :                   temp[1] = n;
    5521           0 :                   temp[2] = '\0';
    5522             :                 }
    5523           0 :               else if (n == -1)
    5524             :                 {
    5525           0 :                   temp[0] = '\\';
    5526           0 :                   temp[1] = '\0';
    5527             :                 }
    5528             :               else
    5529             :                 {
    5530           0 :                   temp[0] = n;
    5531           0 :                   temp[1] = '\0';
    5532             :                 }
    5533             : 
    5534           0 :               for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++)
    5535           0 :                 string++;
    5536             : 
    5537           0 :               c = 0;            /* tested at add_string: */
    5538           0 :               goto add_string;
    5539             : 
    5540           0 :             case 'd':
    5541             :             case 't':
    5542             :             case 'T':
    5543             :             case '@':
    5544             :             case 'A':
    5545             :               /* Make the current time/date into a string. */
    5546           0 :               (void) time (&the_time);
    5547             : #if defined (HAVE_TZSET)
    5548           0 :               sv_tz ("TZ");           /* XXX -- just make sure */
    5549             : #endif
    5550           0 :               tm = localtime (&the_time);
    5551             : 
    5552           0 :               if (c == 'd')
    5553           0 :                 n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm);
    5554           0 :               else if (c == 't')
    5555           0 :                 n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm);
    5556           0 :               else if (c == 'T')
    5557           0 :                 n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm);
    5558           0 :               else if (c == '@')
    5559           0 :                 n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm);
    5560           0 :               else if (c == 'A')
    5561           0 :                 n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm);
    5562             :               else
    5563             :                 n = 0;
    5564             : 
    5565           0 :               if (n == 0)
    5566           0 :                 timebuf[0] = '\0';
    5567             :               else
    5568           0 :                 timebuf[sizeof(timebuf) - 1] = '\0';
    5569             : 
    5570           0 :               temp = savestring (timebuf);
    5571           0 :               goto add_string;
    5572             : 
    5573           0 :             case 'D':           /* strftime format */
    5574           0 :               if (string[1] != '{')             /* } */
    5575             :                 goto not_escape;
    5576             : 
    5577           0 :               (void) time (&the_time);
    5578           0 :               tm = localtime (&the_time);
    5579           0 :               string += 2;                      /* skip { */
    5580           0 :               timefmt = xmalloc (strlen (string) + 3);
    5581           0 :               for (t = timefmt; *string && *string != '}'; )
    5582           0 :                 *t++ = *string++;
    5583           0 :               *t = '\0';
    5584           0 :               c = *string;      /* tested at add_string */
    5585           0 :               if (timefmt[0] == '\0')
    5586             :                 {
    5587           0 :                   timefmt[0] = '%';
    5588           0 :                   timefmt[1] = 'X';     /* locale-specific current time */
    5589           0 :                   timefmt[2] = '\0';
    5590             :                 }
    5591           0 :               n = strftime (timebuf, sizeof (timebuf), timefmt, tm);
    5592           0 :               free (timefmt);
    5593             : 
    5594           0 :               if (n == 0)
    5595           0 :                 timebuf[0] = '\0';
    5596             :               else
    5597           0 :                 timebuf[sizeof(timebuf) - 1] = '\0';
    5598             : 
    5599           0 :               if (promptvars || posixly_correct)
    5600             :                 /* Make sure that expand_prompt_string is called with a
    5601             :                    second argument of Q_DOUBLE_QUOTES if we use this
    5602             :                    function here. */
    5603           0 :                 temp = sh_backslash_quote_for_double_quotes (timebuf);
    5604             :               else
    5605           0 :                 temp = savestring (timebuf);
    5606           0 :               goto add_string;
    5607             :               
    5608           0 :             case 'n':
    5609           0 :               temp = (char *)xmalloc (3);
    5610           0 :               temp[0] = no_line_editing ? '\n' : '\r';
    5611           0 :               temp[1] = no_line_editing ? '\0' : '\n';
    5612           0 :               temp[2] = '\0';
    5613           0 :               goto add_string;
    5614             : 
    5615           0 :             case 's':
    5616           0 :               temp = base_pathname (shell_name);
    5617             :               /* Try to quote anything the user can set in the file system */
    5618           0 :               if (promptvars || posixly_correct)
    5619           0 :                 temp = sh_backslash_quote_for_double_quotes (temp);
    5620             :               else
    5621           0 :                 temp = savestring (temp);
    5622           0 :               goto add_string;
    5623             : 
    5624           0 :             case 'v':
    5625             :             case 'V':
    5626           0 :               temp = (char *)xmalloc (16);
    5627           0 :               if (c == 'v')
    5628           0 :                 strcpy (temp, dist_version);
    5629             :               else
    5630           0 :                 sprintf (temp, "%s.%d", dist_version, patch_level);
    5631           0 :               goto add_string;
    5632             : 
    5633           0 :             case 'w':
    5634             :             case 'W':
    5635             :               {
    5636             :                 /* Use the value of PWD because it is much more efficient. */
    5637           0 :                 char t_string[PATH_MAX];
    5638           0 :                 int tlen;
    5639             : 
    5640           0 :                 temp = get_string_value ("PWD");
    5641             : 
    5642           0 :                 if (temp == 0)
    5643             :                   {
    5644           0 :                     if (getcwd (t_string, sizeof(t_string)) == 0)
    5645             :                       {
    5646           0 :                         t_string[0] = '.';
    5647           0 :                         tlen = 1;
    5648             :                       }
    5649             :                     else
    5650           0 :                       tlen = strlen (t_string);
    5651             :                   }
    5652             :                 else
    5653             :                   {
    5654           0 :                     tlen = sizeof (t_string) - 1;
    5655           0 :                     strncpy (t_string, temp, tlen);
    5656             :                   }
    5657           0 :                 t_string[tlen] = '\0';
    5658             : 
    5659             : #if defined (MACOSX)
    5660             :                 /* Convert from "fs" format to "input" format */
    5661             :                 temp = fnx_fromfs (t_string, strlen (t_string));
    5662             :                 if (temp != t_string)
    5663             :                   strcpy (t_string, temp);
    5664             : #endif
    5665             : 
    5666             : #define ROOT_PATH(x)    ((x)[0] == '/' && (x)[1] == 0)
    5667             : #define DOUBLE_SLASH_ROOT(x)    ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0)
    5668             :                 /* Abbreviate \W as ~ if $PWD == $HOME */
    5669           0 :                 if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0))
    5670             :                   {
    5671           0 :                     if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0)
    5672             :                       {
    5673           0 :                         t = strrchr (t_string, '/');
    5674           0 :                         if (t)
    5675           0 :                           memmove (t_string, t + 1, strlen (t));        /* strlen(t) to copy NULL */
    5676             :                       }
    5677             :                   }
    5678             : #undef ROOT_PATH
    5679             : #undef DOUBLE_SLASH_ROOT
    5680             :                 else
    5681             :                   {
    5682             :                     /* polite_directory_format is guaranteed to return a string
    5683             :                        no longer than PATH_MAX - 1 characters. */
    5684           0 :                     temp = polite_directory_format (t_string);
    5685           0 :                     if (temp != t_string)
    5686           0 :                       strcpy (t_string, temp);
    5687             :                   }
    5688             : 
    5689           0 :                 temp = trim_pathname (t_string, PATH_MAX - 1);
    5690             :                 /* If we're going to be expanding the prompt string later,
    5691             :                    quote the directory name. */
    5692           0 :                 if (promptvars || posixly_correct)
    5693             :                   /* Make sure that expand_prompt_string is called with a
    5694             :                      second argument of Q_DOUBLE_QUOTES if we use this
    5695             :                      function here. */
    5696           0 :                   temp = sh_backslash_quote_for_double_quotes (t_string);
    5697             :                 else
    5698           0 :                   temp = savestring (t_string);
    5699             : 
    5700           0 :                 goto add_string;
    5701             :               }
    5702             : 
    5703           0 :             case 'u':
    5704           0 :               if (current_user.user_name == 0)
    5705           0 :                 get_current_user_info ();
    5706           0 :               temp = savestring (current_user.user_name);
    5707           0 :               goto add_string;
    5708             : 
    5709           0 :             case 'h':
    5710             :             case 'H':
    5711           0 :               t_host = savestring (current_host_name);
    5712           0 :               if (c == 'h' && (t = (char *)strchr (t_host, '.')))
    5713           0 :                 *t = '\0';
    5714           0 :               if (promptvars || posixly_correct)
    5715             :                 /* Make sure that expand_prompt_string is called with a
    5716             :                    second argument of Q_DOUBLE_QUOTES if we use this
    5717             :                    function here. */
    5718           0 :                 temp = sh_backslash_quote_for_double_quotes (t_host);
    5719             :               else
    5720           0 :                 temp = savestring (t_host);
    5721           0 :               free (t_host);
    5722           0 :               goto add_string;
    5723             : 
    5724           0 :             case '#':
    5725           0 :               temp = itos (current_command_number);
    5726           0 :               goto add_string;
    5727             : 
    5728           0 :             case '!':
    5729             : #if !defined (HISTORY)
    5730           0 :               temp = savestring ("1");
    5731             : #else /* HISTORY */
    5732             :               temp = itos (history_number ());
    5733             : #endif /* HISTORY */
    5734           0 :               goto add_string;
    5735             : 
    5736           0 :             case '$':
    5737           0 :               t = temp = (char *)xmalloc (3);
    5738           0 :               if ((promptvars || posixly_correct) && (current_user.euid != 0))
    5739           0 :                 *t++ = '\\';
    5740           0 :               *t++ = current_user.euid == 0 ? '#' : '$';
    5741           0 :               *t = '\0';
    5742           0 :               goto add_string;
    5743             : 
    5744           0 :             case 'j':
    5745           0 :               temp = itos (count_all_jobs ());
    5746           0 :               goto add_string;
    5747             : 
    5748           0 :             case 'l':
    5749             : #if defined (HAVE_TTYNAME)
    5750           0 :               temp = (char *)ttyname (fileno (stdin));
    5751           0 :               t = temp ? base_pathname (temp) : "tty";
    5752           0 :               temp = savestring (t);
    5753             : #else
    5754             :               temp = savestring ("tty");
    5755             : #endif /* !HAVE_TTYNAME */
    5756           0 :               goto add_string;
    5757             : 
    5758             : #if defined (READLINE)
    5759             :             case '[':
    5760             :             case ']':
    5761             :               if (no_line_editing)
    5762             :                 {
    5763             :                   string++;
    5764             :                   break;
    5765             :                 }
    5766             :               temp = (char *)xmalloc (3);
    5767             :               n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
    5768             :               i = 0;
    5769             :               if (n == CTLESC || n == CTLNUL)
    5770             :                 temp[i++] = CTLESC;
    5771             :               temp[i++] = n;
    5772             :               temp[i] = '\0';
    5773             :               goto add_string;
    5774             : #endif /* READLINE */
    5775             : 
    5776           0 :             case '\\':
    5777             :             case 'a':
    5778             :             case 'e':
    5779             :             case 'r':
    5780           0 :               temp = (char *)xmalloc (2);
    5781           0 :               if (c == 'a')
    5782           0 :                 temp[0] = '\07';
    5783           0 :               else if (c == 'e')
    5784           0 :                 temp[0] = '\033';
    5785           0 :               else if (c == 'r')
    5786           0 :                 temp[0] = '\r';
    5787             :               else                      /* (c == '\\') */
    5788           0 :                 temp[0] = c;
    5789           0 :               temp[1] = '\0';
    5790           0 :               goto add_string;
    5791             : 
    5792             :             default:
    5793           0 : not_escape:
    5794           0 :               temp = (char *)xmalloc (3);
    5795           0 :               temp[0] = '\\';
    5796           0 :               temp[1] = c;
    5797           0 :               temp[2] = '\0';
    5798             : 
    5799           0 :             add_string:
    5800           0 :               if (c)
    5801           0 :                 string++;
    5802           0 :               result =
    5803           0 :                 sub_append_string (temp, result, &result_index, &result_size);
    5804           0 :               temp = (char *)NULL; /* Freed in sub_append_string (). */
    5805           0 :               result[result_index] = '\0';
    5806           0 :               break;
    5807             :             }
    5808             :         }
    5809             :       else
    5810             :         {
    5811           0 :           RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH);
    5812             :           /* dequote_string should take care of removing this if we are not
    5813             :              performing the rest of the word expansions. */
    5814           0 :           if (c == CTLESC || c == CTLNUL)
    5815           0 :             result[result_index++] = CTLESC;
    5816           0 :           result[result_index++] = c;
    5817           0 :           result[result_index] = '\0';
    5818             :         }
    5819             :     }
    5820             : #else /* !PROMPT_STRING_DECODE */
    5821             :   result = savestring (string);
    5822             : #endif /* !PROMPT_STRING_DECODE */
    5823             : 
    5824             :   /* Save the delimiter stack and point `dstack' to temp space so any
    5825             :      command substitutions in the prompt string won't result in screwing
    5826             :      up the parser's quoting state. */
    5827           0 :   save_dstack = dstack;
    5828           0 :   dstack = temp_dstack;
    5829           0 :   dstack.delimiter_depth = 0;
    5830             : 
    5831             :   /* Perform variable and parameter expansion and command substitution on
    5832             :      the prompt string. */
    5833           0 :   if (promptvars || posixly_correct)
    5834             :     {
    5835           0 :       last_exit_value = last_command_exit_value;
    5836           0 :       last_comsub_pid = last_command_subst_pid;
    5837           0 :       list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0);
    5838           0 :       free (result);
    5839           0 :       result = string_list (list);
    5840           0 :       dispose_words (list);
    5841           0 :       last_command_exit_value = last_exit_value;
    5842           0 :       last_command_subst_pid = last_comsub_pid;
    5843             :     }
    5844             :   else
    5845             :     {
    5846           0 :       t = dequote_string (result);
    5847           0 :       free (result);
    5848           0 :       result = t;
    5849             :     }
    5850             : 
    5851           0 :   dstack = save_dstack;
    5852             : 
    5853           0 :   return (result);
    5854             : }
    5855             : 
    5856             : /************************************************
    5857             :  *                                              *
    5858             :  *              ERROR HANDLING                  *
    5859             :  *                                              *
    5860             :  ************************************************/
    5861             : 
    5862             : /* Report a syntax error, and restart the parser.  Call here for fatal
    5863             :    errors. */
    5864             : int
    5865           0 : yyerror (msg)
    5866             :      const char *msg;
    5867             : {
    5868     2104122 :   report_syntax_error ((char *)NULL);
    5869           9 :   reset_parser ();
    5870     2104318 :   return (0);
    5871             : }
    5872             : 
    5873             : static char *
    5874     1782118 : error_token_from_token (tok)
    5875             :      int tok;
    5876             : {
    5877     1782118 :   char *t;
    5878             : 
    5879     1782118 :   if (t = find_token_in_alist (tok, word_token_alist, 0))
    5880             :     return t;
    5881             : 
    5882     1479775 :   if (t = find_token_in_alist (tok, other_token_alist, 0))
    5883             :     return t;
    5884             : 
    5885      237396 :   t = (char *)NULL;
    5886             :   /* This stuff is dicy and needs closer inspection */
    5887      237396 :   switch (current_token)
    5888             :     {
    5889      237257 :     case WORD:
    5890             :     case ASSIGNMENT_WORD:
    5891      237257 :       if (yylval.word)
    5892      237257 :         t = savestring (yylval.word->word);
    5893             :       break;
    5894          49 :     case NUMBER:
    5895          49 :       t = itos (yylval.number);
    5896          49 :       break;
    5897           0 :     case ARITH_CMD:
    5898           0 :       if (yylval.word_list)
    5899           0 :         t = string_list (yylval.word_list);
    5900             :       break;
    5901           0 :     case ARITH_FOR_EXPRS:
    5902           0 :       if (yylval.word_list)
    5903           0 :         t = string_list_internal (yylval.word_list, " ; ");
    5904             :       break;
    5905             :     case COND_CMD:
    5906             :       t = (char *)NULL;         /* punt */
    5907             :       break;
    5908             :     }
    5909             : 
    5910             :   return t;
    5911             : }
    5912             : 
    5913             : static char *
    5914          36 : error_token_from_text ()
    5915             : {
    5916          36 :   char *msg, *t;
    5917          36 :   int token_end, i;
    5918             : 
    5919          36 :   t = shell_input_line;
    5920          36 :   i = shell_input_line_index;
    5921          36 :   token_end = 0;
    5922          36 :   msg = (char *)NULL;
    5923             : 
    5924          36 :   if (i && t[i] == '\0')
    5925           0 :     i--;
    5926             : 
    5927          45 :   while (i && (whitespace (t[i]) || t[i] == '\n'))
    5928           9 :     i--;
    5929             : 
    5930          36 :   if (i)
    5931          36 :     token_end = i + 1;
    5932             : 
    5933         126 :   while (i && (member (t[i], " \n\t;|&") == 0))
    5934          90 :     i--;
    5935             : 
    5936          45 :   while (i != token_end && (whitespace (t[i]) || t[i] == '\n'))
    5937           9 :     i++;
    5938             : 
    5939             :   /* Return our idea of the offending token. */
    5940          36 :   if (token_end || (i == 0 && token_end == 0))
    5941             :     {
    5942          36 :       if (token_end)
    5943          36 :         msg = substring (t, i, token_end);
    5944             :       else      /* one-character token */
    5945             :         {
    5946           0 :           msg = (char *)xmalloc (2);
    5947           0 :           msg[0] = t[i];
    5948           0 :           msg[1] = '\0';
    5949             :         }
    5950             :     }
    5951             : 
    5952          36 :   return (msg);
    5953             : }
    5954             : 
    5955             : static void
    5956     1782055 : print_offending_line ()
    5957             : {
    5958     1782055 :   char *msg;
    5959     1782055 :   int token_end;
    5960             : 
    5961     1782055 :   msg = savestring (shell_input_line);
    5962     1782055 :   token_end = strlen (msg);
    5963     3564101 :   while (token_end && msg[token_end - 1] == '\n')
    5964     1782046 :     msg[--token_end] = '\0';
    5965             : 
    5966     1782055 :   parser_error (line_number, "`%s'", msg);
    5967     1782055 :   free (msg);
    5968     1782055 : }
    5969             : 
    5970             : /* Report a syntax error with line numbers, etc.
    5971             :    Call here for recoverable errors.  If you have a message to print,
    5972             :    then place it in MESSAGE, otherwise pass NULL and this will figure
    5973             :    out an appropriate message for you. */
    5974             : static void
    5975     2104327 : report_syntax_error (message)
    5976             :      char *message;
    5977             : {
    5978     2104327 :   char *msg, *p;
    5979             : 
    5980     2104327 :   if (message)
    5981             :     {
    5982           0 :       parser_error (line_number, "%s", message);
    5983           0 :       if (interactive && EOF_Reached)
    5984           0 :         EOF_Reached = 0;
    5985           0 :       last_command_exit_value = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
    5986           0 :       return;
    5987             :     }
    5988             : 
    5989             :   /* If the line of input we're reading is not null, try to find the
    5990             :      objectionable token.  First, try to figure out what token the
    5991             :      parser's complaining about by looking at current_token. */
    5992     2104327 :   if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token)))
    5993             :     {
    5994     1782019 :       if (ansic_shouldquote (msg))
    5995             :         {
    5996       20247 :           p = ansic_quote (msg, 0, NULL);
    5997       20247 :           free (msg);
    5998       20247 :           msg = p;
    5999             :         }
    6000     1782019 :       parser_error (line_number, _("syntax error near unexpected token `%s'"), msg);
    6001     1782019 :       free (msg);
    6002             : 
    6003     1782019 :       if (interactive == 0)
    6004     1782019 :         print_offending_line ();
    6005             : 
    6006     1782019 :       last_command_exit_value = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
    6007     1782019 :       return;
    6008             :     }
    6009             : 
    6010             :   /* If looking at the current token doesn't prove fruitful, try to find the
    6011             :      offending token by analyzing the text of the input line near the current
    6012             :      input line index and report what we find. */
    6013      322308 :   if (shell_input_line && *shell_input_line)
    6014             :     {
    6015          36 :       msg = error_token_from_text ();
    6016          36 :       if (msg)
    6017             :         {
    6018          36 :           parser_error (line_number, _("syntax error near `%s'"), msg);
    6019          36 :           free (msg);
    6020             :         }
    6021             : 
    6022             :       /* If not interactive, print the line containing the error. */
    6023          36 :       if (interactive == 0)
    6024          36 :         print_offending_line ();
    6025             :     }
    6026             :   else
    6027             :     {
    6028      322272 :       msg = EOF_Reached ? _("syntax error: unexpected end of file") : _("syntax error");
    6029      322272 :       parser_error (line_number, "%s", msg);
    6030             :       /* When the shell is interactive, this file uses EOF_Reached
    6031             :          only for error reporting.  Other mechanisms are used to
    6032             :          decide whether or not to exit. */
    6033      322272 :       if (interactive && EOF_Reached)
    6034           0 :         EOF_Reached = 0;
    6035             :     }
    6036             : 
    6037      643147 :   last_command_exit_value = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
    6038             : }
    6039             : 
    6040             : #if 0
    6041             : /* ??? Needed function. ??? We have to be able to discard the constructs
    6042             :    created during parsing.  In the case of error, we want to return
    6043             :    allocated objects to the memory pool.  In the case of no error, we want
    6044             :    to throw away the information about where the allocated objects live.
    6045             :    (dispose_command () will actually free the command.) */
    6046             : static void
    6047             : discard_parser_constructs (error_p)
    6048             :      int error_p;
    6049             : {
    6050             : }
    6051             : #endif
    6052             : 
    6053             : /************************************************
    6054             :  *                                              *
    6055             :  *              EOF HANDLING                    *
    6056             :  *                                              *
    6057             :  ************************************************/
    6058             : 
    6059             : /* Do that silly `type "bye" to exit' stuff.  You know, "ignoreeof". */
    6060             : 
    6061             : /* A flag denoting whether or not ignoreeof is set. */
    6062             : int ignoreeof = 0;
    6063             : 
    6064             : /* The number of times that we have encountered an EOF character without
    6065             :    another character intervening.  When this gets above the limit, the
    6066             :    shell terminates. */
    6067             : int eof_encountered = 0;
    6068             : 
    6069             : /* The limit for eof_encountered. */
    6070             : int eof_encountered_limit = 10;
    6071             : 
    6072             : /* If we have EOF as the only input unit, this user wants to leave
    6073             :    the shell.  If the shell is not interactive, then just leave.
    6074             :    Otherwise, if ignoreeof is set, and we haven't done this the
    6075             :    required number of times in a row, print a message. */
    6076             : static void
    6077      110845 : handle_eof_input_unit ()
    6078             : {
    6079      110845 :   if (interactive)
    6080             :     {
    6081             :       /* shell.c may use this to decide whether or not to write out the
    6082             :          history, among other things.  We use it only for error reporting
    6083             :          in this file. */
    6084           0 :       if (EOF_Reached)
    6085           0 :         EOF_Reached = 0;
    6086             : 
    6087             :       /* If the user wants to "ignore" eof, then let her do so, kind of. */
    6088           0 :       if (ignoreeof)
    6089             :         {
    6090           0 :           if (eof_encountered < eof_encountered_limit)
    6091             :             {
    6092           0 :               fprintf (stderr, _("Use \"%s\" to leave the shell.\n"),
    6093           0 :                        login_shell ? "logout" : "exit");
    6094           0 :               eof_encountered++;
    6095             :               /* Reset the parsing state. */
    6096           0 :               last_read_token = current_token = '\n';
    6097             :               /* Reset the prompt string to be $PS1. */
    6098           0 :               prompt_string_pointer = (char **)NULL;
    6099           0 :               prompt_again ();
    6100           0 :               return;
    6101             :             }
    6102             :         }
    6103             : 
    6104             :       /* In this case EOF should exit the shell.  Do it now. */
    6105           0 :       reset_parser ();
    6106           0 :       exit_builtin ((WORD_LIST *)NULL);
    6107             :     }
    6108             :   else
    6109             :     {
    6110             :       /* We don't write history files, etc., for non-interactive shells. */
    6111      110845 :       EOF_Reached = 1;
    6112             :     }
    6113             : }
    6114             : 
    6115             : /************************************************
    6116             :  *                                              *
    6117             :  *      STRING PARSING FUNCTIONS                *
    6118             :  *                                              *
    6119             :  ************************************************/
    6120             : 
    6121             : /* It's very important that these two functions treat the characters
    6122             :    between ( and ) identically. */
    6123             : 
    6124             : static WORD_LIST parse_string_error;
    6125             : 
    6126             : /* Take a string and run it through the shell parser, returning the
    6127             :    resultant word list.  Used by compound array assignment. */
    6128             : WORD_LIST *
    6129          37 : parse_string_to_word_list (s, flags, whom)
    6130             :      char *s;
    6131             :      int flags;
    6132             :      const char *whom;
    6133             : {
    6134          37 :   WORD_LIST *wl;
    6135          37 :   int tok, orig_current_token, orig_line_number, orig_input_terminator;
    6136          37 :   int orig_line_count;
    6137          37 :   int old_echo_input, old_expand_aliases;
    6138             : #if defined (HISTORY)
    6139             :   int old_remember_on_history, old_history_expansion_inhibited;
    6140             : #endif
    6141             : 
    6142             : #if defined (HISTORY)
    6143             :   old_remember_on_history = remember_on_history;
    6144             : #  if defined (BANG_HISTORY)
    6145             :   old_history_expansion_inhibited = history_expansion_inhibited;
    6146             : #  endif
    6147             :   bash_history_disable ();
    6148             : #endif
    6149             : 
    6150          37 :   orig_line_number = line_number;
    6151          37 :   orig_line_count = current_command_line_count;
    6152          37 :   orig_input_terminator = shell_input_line_terminator;
    6153          37 :   old_echo_input = echo_input_at_read;
    6154          37 :   old_expand_aliases = expand_aliases;
    6155             : 
    6156          37 :   push_stream (1);
    6157          37 :   last_read_token = WORD;               /* WORD to allow reserved words here */
    6158          37 :   current_command_line_count = 0;
    6159          37 :   echo_input_at_read = expand_aliases = 0;
    6160             : 
    6161          37 :   with_input_from_string (s, whom);
    6162          37 :   wl = (WORD_LIST *)NULL;
    6163             : 
    6164          37 :   if (flags & 1)
    6165          37 :     parser_state |= PST_COMPASSIGN|PST_REPARSE;
    6166             : 
    6167          46 :   while ((tok = read_token (READ)) != yacc_EOF)
    6168             :     {
    6169          18 :       if (tok == '\n' && *bash_input.location.string == '\0')
    6170             :         break;
    6171          18 :       if (tok == '\n')          /* Allow newlines in compound assignments */
    6172             :         continue;
    6173          18 :       if (tok != WORD && tok != ASSIGNMENT_WORD)
    6174             :         {
    6175           9 :           line_number = orig_line_number + line_number - 1;
    6176           9 :           orig_current_token = current_token;
    6177           9 :           current_token = tok;
    6178           9 :           yyerror (NULL);       /* does the right thing */
    6179           9 :           current_token = orig_current_token;
    6180           9 :           if (wl)
    6181           9 :             dispose_words (wl);
    6182             :           wl = &parse_string_error;
    6183             :           break;
    6184             :         }
    6185           9 :       wl = make_word_list (yylval.word, wl);
    6186             :     }
    6187             :   
    6188          37 :   last_read_token = '\n';
    6189          37 :   pop_stream ();
    6190             : 
    6191             : #if defined (HISTORY)
    6192             :   remember_on_history = old_remember_on_history;
    6193             : #  if defined (BANG_HISTORY)
    6194             :   history_expansion_inhibited = old_history_expansion_inhibited;
    6195             : #  endif /* BANG_HISTORY */
    6196             : #endif /* HISTORY */
    6197             : 
    6198          37 :   echo_input_at_read = old_echo_input;
    6199          37 :   expand_aliases = old_expand_aliases;
    6200             : 
    6201          37 :   current_command_line_count = orig_line_count;
    6202          37 :   shell_input_line_terminator = orig_input_terminator;
    6203             : 
    6204          37 :   if (flags & 1)
    6205          37 :     parser_state &= ~(PST_COMPASSIGN|PST_REPARSE);
    6206             : 
    6207          37 :   if (wl == &parse_string_error)
    6208             :     {
    6209           9 :       last_command_exit_value = EXECUTION_FAILURE;
    6210           9 :       if (interactive_shell == 0 && posixly_correct)
    6211           0 :         jump_to_top_level (FORCE_EOF);
    6212             :       else
    6213           9 :         jump_to_top_level (DISCARD);
    6214             :     }
    6215             : 
    6216          28 :   return (REVERSE_LIST (wl, WORD_LIST *));
    6217             : }
    6218             : 
    6219             : static char *
    6220         273 : parse_compound_assignment (retlenp)
    6221             :      int *retlenp;
    6222             : {
    6223         273 :   WORD_LIST *wl, *rl;
    6224         273 :   int tok, orig_line_number, orig_token_size, orig_last_token, assignok;
    6225         273 :   char *saved_token, *ret;
    6226             : 
    6227         273 :   saved_token = token;
    6228         273 :   orig_token_size = token_buffer_size;
    6229         273 :   orig_line_number = line_number;
    6230         273 :   orig_last_token = last_read_token;
    6231             : 
    6232         273 :   last_read_token = WORD;       /* WORD to allow reserved words here */
    6233             : 
    6234         273 :   token = (char *)NULL;
    6235         273 :   token_buffer_size = 0;
    6236             : 
    6237         273 :   assignok = parser_state&PST_ASSIGNOK;             /* XXX */
    6238             : 
    6239         273 :   wl = (WORD_LIST *)NULL;       /* ( */
    6240         273 :   parser_state |= PST_COMPASSIGN;
    6241             : 
    6242        1666 :   while ((tok = read_token (READ)) != ')')
    6243             :     {
    6244        1599 :       if (tok == '\n')                  /* Allow newlines in compound assignments */
    6245             :         {
    6246         644 :           if (SHOULD_PROMPT ())
    6247           0 :             prompt_again ();
    6248         644 :           continue;
    6249             :         }
    6250         955 :       if (tok != WORD && tok != ASSIGNMENT_WORD)
    6251             :         {
    6252         206 :           current_token = tok;  /* for error reporting */
    6253         206 :           if (tok == yacc_EOF)  /* ( */
    6254          10 :             parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'"));
    6255             :           else
    6256         196 :             yyerror(NULL);      /* does the right thing */
    6257         206 :           if (wl)
    6258         188 :             dispose_words (wl);
    6259             :           wl = &parse_string_error;
    6260             :           break;
    6261             :         }
    6262         749 :       wl = make_word_list (yylval.word, wl);
    6263             :     }
    6264             : 
    6265         273 :   FREE (token);
    6266         273 :   token = saved_token;
    6267         273 :   token_buffer_size = orig_token_size;
    6268             : 
    6269         273 :   parser_state &= ~PST_COMPASSIGN;
    6270             : 
    6271         273 :   if (wl == &parse_string_error)
    6272             :     {
    6273         206 :       last_command_exit_value = EXECUTION_FAILURE;
    6274         206 :       last_read_token = '\n';   /* XXX */
    6275         206 :       if (interactive_shell == 0 && posixly_correct)
    6276           0 :         jump_to_top_level (FORCE_EOF);
    6277             :       else
    6278         206 :         jump_to_top_level (DISCARD);
    6279             :     }
    6280             : 
    6281          67 :   last_read_token = orig_last_token;            /* XXX - was WORD? */
    6282             : 
    6283          67 :   if (wl)
    6284             :     {
    6285          18 :       rl = REVERSE_LIST (wl, WORD_LIST *);
    6286          18 :       ret = string_list (rl);
    6287          18 :       dispose_words (rl);
    6288             :     }
    6289             :   else
    6290             :     ret = (char *)NULL;
    6291             : 
    6292          67 :   if (retlenp)
    6293          67 :     *retlenp = (ret && *ret) ? strlen (ret) : 0;
    6294             : 
    6295          67 :   if (assignok)
    6296           0 :     parser_state |= PST_ASSIGNOK;
    6297             : 
    6298          67 :   return ret;
    6299             : }
    6300             : 
    6301             : /************************************************
    6302             :  *                                              *
    6303             :  *   SAVING AND RESTORING PARTIAL PARSE STATE   *
    6304             :  *                                              *
    6305             :  ************************************************/
    6306             : 
    6307             : sh_parser_state_t *
    6308          81 : save_parser_state (ps)
    6309             :      sh_parser_state_t *ps;
    6310             : {
    6311          81 :   if (ps == 0)
    6312           0 :     ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t));
    6313          81 :   if (ps == 0)
    6314             :     return ((sh_parser_state_t *)NULL);
    6315             : 
    6316          81 :   ps->parser_state = parser_state;
    6317          81 :   ps->token_state = save_token_state ();
    6318             : 
    6319          81 :   ps->input_line_terminator = shell_input_line_terminator;
    6320          81 :   ps->eof_encountered = eof_encountered;
    6321             : 
    6322          81 :   ps->prompt_string_pointer = prompt_string_pointer;
    6323             : 
    6324          81 :   ps->current_command_line_count = current_command_line_count;
    6325             : 
    6326             : #if defined (HISTORY)
    6327             :   ps->remember_on_history = remember_on_history;
    6328             : #  if defined (BANG_HISTORY)
    6329             :   ps->history_expansion_inhibited = history_expansion_inhibited;
    6330             : #  endif
    6331             : #endif
    6332             : 
    6333          81 :   ps->last_command_exit_value = last_command_exit_value;
    6334             : #if defined (ARRAY_VARS)
    6335          81 :   ps->pipestatus = save_pipestatus_array ();
    6336             : #endif
    6337             :     
    6338          81 :   ps->last_shell_builtin = last_shell_builtin;
    6339          81 :   ps->this_shell_builtin = this_shell_builtin;
    6340             : 
    6341          81 :   ps->expand_aliases = expand_aliases;
    6342          81 :   ps->echo_input_at_read = echo_input_at_read;
    6343          81 :   ps->need_here_doc = need_here_doc;
    6344          81 :   ps->here_doc_first_line = here_doc_first_line;
    6345             : 
    6346             : #if 0
    6347             :   for (i = 0; i < HEREDOC_MAX; i++)
    6348             :     ps->redir_stack[i] = redir_stack[i];
    6349             : #else
    6350          81 :   if (need_here_doc == 0)
    6351          81 :     ps->redir_stack[0] = 0;
    6352             :   else
    6353           0 :     memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX);
    6354             : #endif
    6355             : 
    6356          81 :   ps->token = token;
    6357          81 :   ps->token_buffer_size = token_buffer_size;
    6358             :   /* Force reallocation on next call to read_token_word */
    6359          81 :   token = 0;
    6360          81 :   token_buffer_size = 0;
    6361             : 
    6362          81 :   return (ps);
    6363             : }
    6364             : 
    6365             : void
    6366          81 : restore_parser_state (ps)
    6367             :      sh_parser_state_t *ps;
    6368             : {
    6369          81 :   if (ps == 0)
    6370             :     return;
    6371             : 
    6372          81 :   parser_state = ps->parser_state;
    6373          81 :   if (ps->token_state)
    6374             :     {
    6375         162 :       restore_token_state (ps->token_state);
    6376          81 :       free (ps->token_state);
    6377             :     }
    6378             : 
    6379          81 :   shell_input_line_terminator = ps->input_line_terminator;
    6380          81 :   eof_encountered = ps->eof_encountered;
    6381             : 
    6382          81 :   prompt_string_pointer = ps->prompt_string_pointer;
    6383             : 
    6384          81 :   current_command_line_count = ps->current_command_line_count;
    6385             : 
    6386             : #if defined (HISTORY)
    6387             :   remember_on_history = ps->remember_on_history;
    6388             : #  if defined (BANG_HISTORY)
    6389             :   history_expansion_inhibited = ps->history_expansion_inhibited;
    6390             : #  endif
    6391             : #endif
    6392             : 
    6393          81 :   last_command_exit_value = ps->last_command_exit_value;
    6394             : #if defined (ARRAY_VARS)
    6395          81 :   restore_pipestatus_array (ps->pipestatus);
    6396             : #endif
    6397             : 
    6398          81 :   last_shell_builtin = ps->last_shell_builtin;
    6399          81 :   this_shell_builtin = ps->this_shell_builtin;
    6400             : 
    6401          81 :   expand_aliases = ps->expand_aliases;
    6402          81 :   echo_input_at_read = ps->echo_input_at_read;
    6403          81 :   need_here_doc = ps->need_here_doc;
    6404          81 :   here_doc_first_line = ps->here_doc_first_line;
    6405             : 
    6406             : #if 0
    6407             :   for (i = 0; i < HEREDOC_MAX; i++)
    6408             :     redir_stack[i] = ps->redir_stack[i];
    6409             : #else
    6410          81 :   if (need_here_doc == 0)
    6411          81 :     redir_stack[0] = 0;
    6412             :   else
    6413           0 :     memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX);
    6414             : #endif
    6415             : 
    6416          81 :   FREE (token);
    6417          81 :   token = ps->token;
    6418          81 :   token_buffer_size = ps->token_buffer_size;
    6419             : }
    6420             : 
    6421             : sh_input_line_state_t *
    6422          81 : save_input_line_state (ls)
    6423             :      sh_input_line_state_t *ls;
    6424             : {
    6425          81 :   if (ls == 0)
    6426           0 :     ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t));
    6427          81 :   if (ls == 0)
    6428             :     return ((sh_input_line_state_t *)NULL);
    6429             : 
    6430          81 :   ls->input_line = shell_input_line;
    6431          81 :   ls->input_line_size = shell_input_line_size;
    6432          81 :   ls->input_line_len = shell_input_line_len;
    6433          81 :   ls->input_line_index = shell_input_line_index;
    6434             : 
    6435             :   /* force reallocation */
    6436          81 :   shell_input_line = 0;
    6437          81 :   shell_input_line_size = shell_input_line_len = shell_input_line_index = 0;
    6438             : 
    6439          81 :   return ls;
    6440             : }
    6441             : 
    6442             : void
    6443          81 : restore_input_line_state (ls)
    6444             :      sh_input_line_state_t *ls;
    6445             : {
    6446          81 :   FREE (shell_input_line);
    6447          81 :   shell_input_line = ls->input_line;
    6448          81 :   shell_input_line_size = ls->input_line_size;
    6449          81 :   shell_input_line_len = ls->input_line_len;
    6450          81 :   shell_input_line_index = ls->input_line_index;
    6451             : 
    6452          81 :   set_line_mbstate ();
    6453          81 : }
    6454             : 
    6455             : /************************************************
    6456             :  *                                              *
    6457             :  *      MULTIBYTE CHARACTER HANDLING            *
    6458             :  *                                              *
    6459             :  ************************************************/
    6460             : 
    6461             : #if defined (HANDLE_MULTIBYTE)
    6462             : static void
    6463  1636432267 : set_line_mbstate ()
    6464             : {
    6465  1636432267 :   int c;
    6466  1636432267 :   size_t i, previ, len;
    6467  1636432267 :   mbstate_t mbs, prevs;
    6468  1636432267 :   size_t mbclen;
    6469             : 
    6470  1636432267 :   if (shell_input_line == NULL)
    6471           0 :     return;
    6472  1636432267 :   len = strlen (shell_input_line);      /* XXX - shell_input_line_len ? */
    6473  1636432267 :   shell_input_line_property = (char *)xrealloc (shell_input_line_property, len + 1);
    6474             : 
    6475  1636432267 :   memset (&prevs, '\0', sizeof (mbstate_t));
    6476 30683917457 :   for (i = previ = 0; i < len; i++)
    6477             :     {
    6478 29049864115 :       mbs = prevs;
    6479             : 
    6480 29049864115 :       c = shell_input_line[i];
    6481 29049864115 :       if (c == EOF)
    6482             :         {
    6483             :           size_t j;
    6484   542612276 :           for (j = i; j < len; j++)
    6485   540233351 :             shell_input_line_property[j] = 1;
    6486             :           break;
    6487             :         }
    6488             : 
    6489 29047485190 :       mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs);
    6490 29047485190 :       if (mbclen == 1 || mbclen == (size_t)-1)
    6491             :         {
    6492 29039998635 :           mbclen = 1;
    6493 29039998635 :           previ = i + 1;
    6494             :         }
    6495     7486555 :       else if (mbclen == (size_t)-2)
    6496             :         mbclen = 0;
    6497      558038 :       else if (mbclen > 1)
    6498             :         {
    6499      558038 :           mbclen = 0;
    6500      558038 :           previ = i + 1;
    6501      558038 :           prevs = mbs;
    6502             :         }
    6503             :       else
    6504             :         {
    6505             :           /* XXX - what to do if mbrlen returns 0? (null wide character) */
    6506             :           size_t j;
    6507           0 :           for (j = i; j < len; j++)
    6508           0 :             shell_input_line_property[j] = 1;
    6509             :           break;
    6510             :         }
    6511             : 
    6512 29047485190 :       shell_input_line_property[i] = mbclen;
    6513             :     }
    6514             : }
    6515             : #endif /* HANDLE_MULTIBYTE */

Generated by: LCOV version 1.14.0.6.4058