diff options
author | Jari Aalto <jari.aalto@cante.net> | 1996-12-23 17:02:34 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:49 +0000 |
commit | ccc6cda312fea9f0468ee65b8f368e9653e1380b (patch) | |
tree | b059878adcfd876c4acb8030deda1eeb918c7e75 /y.tab.c | |
parent | 726f63884db0132f01745f1fb4465e6621088ccf (diff) | |
download | android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.tar.gz android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.tar.bz2 android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.zip |
Imported from ../bash-2.0.tar.gz.
Diffstat (limited to 'y.tab.c')
-rw-r--r-- | y.tab.c | 3324 |
1 files changed, 1829 insertions, 1495 deletions
@@ -21,33 +21,54 @@ #define FUNCTION 271 #define IN 272 #define BANG 273 -#define WORD 274 -#define ASSIGNMENT_WORD 275 -#define NUMBER 276 -#define AND_AND 277 -#define OR_OR 278 -#define GREATER_GREATER 279 -#define LESS_LESS 280 -#define LESS_AND 281 -#define GREATER_AND 282 -#define SEMI_SEMI 283 -#define LESS_LESS_MINUS 284 -#define AND_GREATER 285 -#define LESS_GREATER 286 -#define GREATER_BAR 287 -#define yacc_EOF 288 +#define TIME 274 +#define TIMEOPT 275 +#define WORD 276 +#define ASSIGNMENT_WORD 277 +#define NUMBER 278 +#define AND_AND 279 +#define OR_OR 280 +#define GREATER_GREATER 281 +#define LESS_LESS 282 +#define LESS_AND 283 +#define GREATER_AND 284 +#define SEMI_SEMI 285 +#define LESS_LESS_MINUS 286 +#define AND_GREATER 287 +#define LESS_GREATER 288 +#define GREATER_BAR 289 +#define yacc_EOF 290 #line 21 "./parse.y" -#include <stdio.h> +#include "config.h" + #include "bashtypes.h" -#include <signal.h> #include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> +#include <signal.h> + +#include "memalloc.h" + #include "shell.h" +#include "trap.h" #include "flags.h" -#include "input.h" +#include "parser.h" +#include "mailcheck.h" +#include "builtins/common.h" +#include "builtins/builtext.h" #if defined (READLINE) +# include "bashline.h" # include <readline/readline.h> #endif /* READLINE */ @@ -70,19 +91,24 @@ #include "maxpath.h" #endif /* PROMPT_STRING_DECODE */ -#define YYDEBUG 1 +#define RE_READ_TOKEN -99 +#define NO_EXPANSION -100 + +#define YYDEBUG 0 + extern int eof_encountered; -extern int no_line_editing; +extern int no_line_editing, running_under_emacs; extern int current_command_number; extern int interactive, interactive_shell, login_shell; +extern int sourcelevel; extern int posixly_correct; extern int last_command_exit_value; extern int interrupt_immediately; extern char *shell_name, *current_host_name; +extern char *dist_version; +extern int patch_level; +extern int dump_translatable_strings; extern Function *last_shell_builtin, *this_shell_builtin; -#if defined (READLINE) -extern int bash_readline_initialized; -#endif #if defined (BUFFERED_INPUT) extern int bash_input_fd_changed; #endif @@ -93,12 +119,13 @@ extern int bash_input_fd_changed; /* */ /* **************************************************************** */ -/* This is kind of sickening. In order to let these variables be seen by - all the functions that need them, I am forced to place their declarations - far away from the place where they should logically be found. */ - +static char *ansiexpand (); +static char *localeexpand (); static int reserved_word_acceptable (); static int read_token (); +static int yylex (); +static int read_token_word (); +static void discard_parser_constructs (); static void report_syntax_error (); static void handle_eof_input_unit (); @@ -106,6 +133,10 @@ static void prompt_again (); static void reset_readline_prompt (); static void print_prompt (); +/* Default prompt strings */ +char *primary_prompt = PPROMPT; +char *secondary_prompt = SPROMPT; + /* PROMPT_STRING_POINTER points to one of these, never to an actual string. */ char *ps1_prompt, *ps2_prompt; @@ -114,31 +145,46 @@ char *ps1_prompt, *ps2_prompt; char **prompt_string_pointer = (char **)NULL; char *current_prompt_string; +/* Non-zero means we expand aliases in commands. */ +int expand_aliases = 0; + +/* If non-zero, the decoded prompt string undergoes parameter and + variable substitution, command substitution, arithmetic substitution, + string expansion, process substitution, and quote removal in + decode_prompt_string. */ +int promptvars = 1; + /* The decoded prompt string. Used if READLINE is not defined or if editing is turned off. Analogous to current_readline_prompt. */ static char *current_decoded_prompt; /* The number of lines read from input while creating the current command. */ -int current_command_line_count = 0; +int current_command_line_count; /* Variables to manage the task of reading here documents, because we need to defer the reading until after a complete command has been collected. */ static REDIRECT *redir_stack[10]; -int need_here_doc = 0; +int need_here_doc; /* Where shell input comes from. History expansion is performed on each line when the shell is interactive. */ static char *shell_input_line = (char *)NULL; -static int shell_input_line_index = 0; -static int shell_input_line_size = 0; /* Amount allocated for shell_input_line. */ -static int shell_input_line_len = 0; /* strlen (shell_input_line) */ +static int shell_input_line_index; +static int shell_input_line_size; /* Amount allocated for shell_input_line. */ +static int shell_input_line_len; /* strlen (shell_input_line) */ /* Either zero or EOF. */ -static int shell_input_line_terminator = 0; +static int shell_input_line_terminator; + +/* The line number in a script on which a function definition starts. */ +static int function_dstart; + +/* The line number in a script on which a function body starts. */ +static int function_bstart; static REDIRECTEE redir; -#line 122 "./parse.y" +#line 166 "./parse.y" typedef union { WORD_DESC *word; /* the word that we read. */ int number; /* the number that we read. */ @@ -158,26 +204,26 @@ typedef union { -#define YYFINAL 258 +#define YYFINAL 263 #define YYFLAG -32768 -#define YYNTBASE 45 +#define YYNTBASE 47 -#define YYTRANSLATE(x) ((unsigned)(x) <= 288 ? yytranslate[x] : 73) +#define YYTRANSLATE(x) ((unsigned)(x) <= 290 ? yytranslate[x] : 78) static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 33, 2, 43, - 44, 2, 2, 2, 40, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 34, 39, - 2, 38, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 35, 2, 45, + 46, 2, 2, 2, 42, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 36, 41, + 2, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 41, 37, 42, 2, 2, 2, 2, 2, + 2, 2, 43, 39, 44, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -193,99 +239,97 @@ static const char yytranslate[] = { 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 36 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 38 }; #if YYDEBUG != 0 static const short yyprhs[] = { 0, - 0, 3, 5, 8, 10, 11, 14, 17, 20, 24, - 28, 31, 35, 38, 42, 45, 49, 52, 56, 59, - 63, 66, 70, 73, 77, 80, 84, 87, 91, 94, - 98, 101, 104, 108, 110, 112, 114, 116, 119, 121, - 124, 126, 128, 130, 133, 140, 147, 155, 163, 174, - 185, 192, 200, 207, 213, 219, 221, 223, 225, 227, - 229, 236, 243, 251, 259, 270, 281, 287, 294, 301, - 309, 314, 320, 324, 330, 338, 345, 349, 354, 361, - 367, 369, 372, 377, 382, 388, 394, 396, 399, 405, - 411, 418, 425, 427, 431, 434, 436, 440, 444, 448, - 453, 458, 463, 468, 473, 475, 478, 480, 482, 484, - 485, 488, 490, 493, 496, 501, 506, 510, 514, 516, - 519, 524 + 0, 3, 5, 8, 10, 12, 15, 18, 21, 25, + 29, 32, 36, 39, 43, 46, 50, 53, 57, 60, + 64, 67, 71, 74, 78, 81, 85, 88, 92, 95, + 99, 102, 105, 109, 111, 113, 115, 117, 120, 122, + 125, 127, 129, 132, 134, 136, 142, 148, 150, 152, + 154, 156, 158, 165, 172, 180, 188, 199, 210, 217, + 224, 232, 240, 251, 262, 269, 277, 284, 290, 297, + 302, 306, 312, 320, 327, 331, 336, 343, 349, 351, + 354, 359, 364, 370, 376, 379, 383, 385, 389, 392, + 394, 397, 401, 405, 409, 414, 419, 424, 429, 434, + 436, 438, 440, 442, 443, 446, 448, 451, 454, 459, + 464, 468, 472, 474, 476, 479, 482, 486, 490, 495, + 497, 499 }; -static const short yyrhs[] = { 70, - 35, 0, 35, 0, 1, 35, 0, 36, 0, 0, - 46, 19, 0, 38, 19, 0, 39, 19, 0, 21, - 38, 19, 0, 21, 39, 19, 0, 24, 19, 0, - 21, 24, 19, 0, 25, 19, 0, 21, 25, 19, - 0, 26, 21, 0, 21, 26, 21, 0, 27, 21, - 0, 21, 27, 21, 0, 26, 19, 0, 21, 26, - 19, 0, 27, 19, 0, 21, 27, 19, 0, 29, - 19, 0, 21, 29, 19, 0, 27, 40, 0, 21, - 27, 40, 0, 26, 40, 0, 21, 26, 40, 0, - 30, 19, 0, 21, 31, 19, 0, 31, 19, 0, - 32, 19, 0, 21, 32, 19, 0, 19, 0, 20, - 0, 47, 0, 47, 0, 49, 47, 0, 48, 0, - 50, 48, 0, 50, 0, 52, 0, 53, 0, 53, - 49, 0, 10, 19, 69, 14, 65, 15, 0, 10, - 19, 69, 41, 65, 42, 0, 10, 19, 34, 69, - 14, 65, 15, 0, 10, 19, 34, 69, 41, 65, - 42, 0, 10, 19, 69, 17, 46, 68, 69, 14, - 65, 15, 0, 10, 19, 69, 17, 46, 68, 69, - 41, 65, 42, 0, 8, 19, 69, 17, 69, 9, - 0, 8, 19, 69, 17, 62, 69, 9, 0, 8, - 19, 69, 17, 60, 9, 0, 12, 65, 14, 65, - 15, 0, 13, 65, 14, 65, 15, 0, 54, 0, - 57, 0, 56, 0, 58, 0, 55, 0, 11, 19, - 69, 14, 65, 15, 0, 11, 19, 69, 41, 65, - 42, 0, 11, 19, 34, 69, 14, 65, 15, 0, - 11, 19, 34, 69, 41, 65, 42, 0, 11, 19, - 69, 17, 46, 68, 69, 14, 65, 15, 0, 11, - 19, 69, 17, 46, 68, 69, 41, 65, 42, 0, - 19, 43, 44, 69, 58, 0, 19, 43, 44, 69, - 58, 49, 0, 16, 19, 43, 44, 69, 58, 0, - 16, 19, 43, 44, 69, 58, 49, 0, 16, 19, - 69, 58, 0, 16, 19, 69, 58, 49, 0, 43, - 65, 44, 0, 3, 65, 4, 65, 7, 0, 3, - 65, 4, 65, 5, 65, 7, 0, 3, 65, 4, - 65, 59, 7, 0, 41, 65, 42, 0, 6, 65, - 4, 65, 0, 6, 65, 4, 65, 5, 65, 0, - 6, 65, 4, 65, 59, 0, 61, 0, 62, 61, - 0, 69, 64, 44, 65, 0, 69, 64, 44, 69, - 0, 69, 43, 64, 44, 65, 0, 69, 43, 64, - 44, 69, 0, 63, 0, 62, 63, 0, 69, 64, - 44, 65, 28, 0, 69, 64, 44, 69, 28, 0, - 69, 43, 64, 44, 65, 28, 0, 69, 43, 64, - 44, 69, 28, 0, 19, 0, 64, 37, 19, 0, - 69, 66, 0, 67, 0, 67, 35, 69, 0, 67, - 33, 69, 0, 67, 34, 69, 0, 67, 22, 69, - 67, 0, 67, 23, 69, 67, 0, 67, 33, 69, - 67, 0, 67, 34, 69, 67, 0, 67, 35, 69, - 67, 0, 72, 0, 18, 72, 0, 35, 0, 34, - 0, 36, 0, 0, 69, 35, 0, 71, 0, 71, - 33, 0, 71, 34, 0, 71, 22, 69, 71, 0, - 71, 23, 69, 71, 0, 71, 33, 71, 0, 71, - 34, 71, 0, 72, 0, 18, 72, 0, 72, 37, - 69, 72, 0, 51, 0 +static const short yyrhs[] = { 73, + 37, 0, 37, 0, 1, 37, 0, 38, 0, 21, + 0, 48, 21, 0, 40, 21, 0, 41, 21, 0, + 23, 40, 21, 0, 23, 41, 21, 0, 26, 21, + 0, 23, 26, 21, 0, 27, 21, 0, 23, 27, + 21, 0, 28, 23, 0, 23, 28, 23, 0, 29, + 23, 0, 23, 29, 23, 0, 28, 21, 0, 23, + 28, 21, 0, 29, 21, 0, 23, 29, 21, 0, + 31, 21, 0, 23, 31, 21, 0, 29, 42, 0, + 23, 29, 42, 0, 28, 42, 0, 23, 28, 42, + 0, 32, 21, 0, 23, 33, 21, 0, 33, 21, + 0, 34, 21, 0, 23, 34, 21, 0, 21, 0, + 22, 0, 49, 0, 49, 0, 51, 49, 0, 50, + 0, 52, 50, 0, 52, 0, 54, 0, 54, 51, + 0, 55, 0, 57, 0, 12, 68, 14, 68, 15, + 0, 13, 68, 14, 68, 15, 0, 56, 0, 60, + 0, 59, 0, 61, 0, 58, 0, 10, 21, 72, + 14, 67, 15, 0, 10, 21, 72, 43, 67, 44, + 0, 10, 21, 36, 72, 14, 67, 15, 0, 10, + 21, 36, 72, 43, 67, 44, 0, 10, 21, 72, + 17, 48, 71, 72, 14, 67, 15, 0, 10, 21, + 72, 17, 48, 71, 72, 43, 67, 44, 0, 11, + 21, 72, 14, 67, 15, 0, 11, 21, 72, 43, + 67, 44, 0, 11, 21, 36, 72, 14, 67, 15, + 0, 11, 21, 36, 72, 43, 67, 44, 0, 11, + 21, 72, 17, 48, 71, 72, 14, 67, 15, 0, + 11, 21, 72, 17, 48, 71, 72, 43, 67, 44, + 0, 8, 21, 72, 17, 72, 9, 0, 8, 21, + 72, 17, 65, 72, 9, 0, 8, 21, 72, 17, + 63, 9, 0, 21, 45, 46, 72, 61, 0, 16, + 21, 45, 46, 72, 61, 0, 16, 21, 72, 61, + 0, 45, 68, 46, 0, 3, 68, 4, 68, 7, + 0, 3, 68, 4, 68, 5, 68, 7, 0, 3, + 68, 4, 68, 62, 7, 0, 43, 67, 44, 0, + 6, 68, 4, 68, 0, 6, 68, 4, 68, 5, + 68, 0, 6, 68, 4, 68, 62, 0, 64, 0, + 65, 64, 0, 72, 66, 46, 68, 0, 72, 66, + 46, 72, 0, 72, 45, 66, 46, 68, 0, 72, + 45, 66, 46, 72, 0, 64, 30, 0, 65, 64, + 30, 0, 21, 0, 66, 39, 21, 0, 72, 69, + 0, 67, 0, 72, 70, 0, 70, 37, 72, 0, + 70, 35, 72, 0, 70, 36, 72, 0, 70, 24, + 72, 70, 0, 70, 25, 72, 70, 0, 70, 35, + 72, 70, 0, 70, 36, 72, 70, 0, 70, 37, + 72, 70, 0, 75, 0, 37, 0, 36, 0, 38, + 0, 0, 72, 37, 0, 74, 0, 74, 35, 0, + 74, 36, 0, 74, 24, 72, 74, 0, 74, 25, + 72, 74, 0, 74, 35, 74, 0, 74, 36, 74, + 0, 75, 0, 76, 0, 18, 76, 0, 77, 76, + 0, 77, 18, 76, 0, 18, 77, 76, 0, 76, + 39, 72, 76, 0, 53, 0, 19, 0, 19, 20, + 0 }; #endif #if YYDEBUG != 0 static const short yyrline[] = { 0, - 163, 172, 179, 195, 205, 207, 211, 216, 221, 226, - 231, 236, 241, 247, 253, 258, 263, 268, 273, 278, - 283, 288, 293, 300, 307, 312, 317, 322, 327, 332, - 337, 353, 358, 365, 367, 369, 373, 377, 388, 390, - 394, 396, 400, 402, 417, 419, 421, 423, 425, 427, - 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, - 452, 458, 464, 470, 476, 482, 490, 493, 496, 499, - 502, 505, 509, 513, 515, 517, 522, 526, 528, 530, - 534, 535, 539, 541, 543, 545, 549, 550, 554, 556, - 558, 560, 564, 566, 575, 583, 584, 585, 592, 596, - 598, 600, 607, 609, 611, 613, 620, 621, 622, 625, - 626, 635, 641, 650, 658, 660, 662, 669, 671, 673, - 680, 683 + 209, 218, 225, 240, 250, 252, 256, 261, 266, 271, + 276, 281, 286, 292, 298, 303, 308, 313, 318, 323, + 328, 333, 338, 345, 352, 357, 362, 367, 372, 377, + 382, 387, 392, 399, 401, 403, 407, 411, 422, 424, + 428, 430, 432, 461, 463, 465, 467, 469, 471, 473, + 475, 477, 481, 483, 485, 487, 489, 491, 495, 499, + 503, 507, 511, 515, 521, 523, 525, 529, 533, 536, + 540, 544, 546, 548, 553, 557, 559, 561, 565, 566, + 570, 572, 574, 576, 580, 581, 585, 587, 596, 604, + 605, 611, 612, 619, 623, 625, 627, 634, 636, 638, + 642, 643, 644, 647, 648, 657, 663, 672, 680, 682, + 684, 691, 694, 698, 700, 705, 710, 715, 722, 725, + 729, 731 }; #endif @@ -294,236 +338,238 @@ static const short yyrline[] = { 0, static const char * const yytname[] = { "$","error","$undefined.","IF","THEN", "ELSE","ELIF","FI","CASE","ESAC","FOR","SELECT","WHILE","UNTIL","DO","DONE", -"FUNCTION","IN","BANG","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND","OR_OR","GREATER_GREATER", -"LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS","AND_GREATER", -"LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'","'>'","'<'", -"'-'","'{'","'}'","'('","')'","inputunit","words","redirection","simple_command_element", -"redirections","simple_command","command","shell_command","shell_command_1", -"select_command","function_def","subshell","if_command","group_command","elif_clause", -"case_clause_1","pattern_list_1","case_clause_sequence","pattern_list","pattern", -"list","list0","list1","list_terminator","newlines","simple_list","simple_list1", -"pipeline", NULL +"FUNCTION","IN","BANG","TIME","TIMEOPT","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND", +"OR_OR","GREATER_GREATER","LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS", +"AND_GREATER","LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'", +"'>'","'<'","'-'","'{'","'}'","'('","')'","inputunit","word_list","redirection", +"simple_command_element","redirection_list","simple_command","command","shell_command", +"for_command","select_command","case_command","function_def","subshell","if_command", +"group_command","elif_clause","case_clause","pattern_list","case_clause_sequence", +"pattern","list","compound_list","list0","list1","list_terminator","newline_list", +"simple_list","simple_list1","pipeline_command","pipeline","timespec", NULL }; #endif static const short yyr1[] = { 0, - 45, 45, 45, 45, 46, 46, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 48, 48, 48, 49, 49, 50, 50, - 51, 51, 52, 52, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, - 55, 55, 56, 57, 57, 57, 58, 59, 59, 59, - 60, 60, 61, 61, 61, 61, 62, 62, 63, 63, - 63, 63, 64, 64, 65, 66, 66, 66, 66, 67, - 67, 67, 67, 67, 67, 67, 68, 68, 68, 69, - 69, 70, 70, 70, 71, 71, 71, 71, 71, 71, - 72, 72 + 47, 47, 47, 47, 48, 48, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 50, 50, 50, 51, 51, 52, 52, + 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, + 56, 56, 56, 56, 57, 57, 57, 58, 58, 58, + 59, 60, 60, 60, 61, 62, 62, 62, 63, 63, + 64, 64, 64, 64, 65, 65, 66, 66, 67, 68, + 68, 69, 69, 69, 70, 70, 70, 70, 70, 70, + 71, 71, 71, 72, 72, 73, 73, 73, 74, 74, + 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, + 77, 77 }; static const short yyr2[] = { 0, - 2, 1, 2, 1, 0, 2, 2, 2, 3, 3, + 2, 1, 2, 1, 1, 2, 2, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 3, 1, 1, 1, 1, 2, 1, 2, - 1, 1, 1, 2, 6, 6, 7, 7, 10, 10, - 6, 7, 6, 5, 5, 1, 1, 1, 1, 1, - 6, 6, 7, 7, 10, 10, 5, 6, 6, 7, - 4, 5, 3, 5, 7, 6, 3, 4, 6, 5, - 1, 2, 4, 4, 5, 5, 1, 2, 5, 5, - 6, 6, 1, 3, 2, 1, 3, 3, 3, 4, - 4, 4, 4, 4, 1, 2, 1, 1, 1, 0, - 2, 1, 2, 2, 4, 4, 3, 3, 1, 2, - 4, 1 + 1, 1, 2, 1, 1, 5, 5, 1, 1, 1, + 1, 1, 6, 6, 7, 7, 10, 10, 6, 6, + 7, 7, 10, 10, 6, 7, 6, 5, 6, 4, + 3, 5, 7, 6, 3, 4, 6, 5, 1, 2, + 4, 4, 5, 5, 2, 3, 1, 3, 2, 1, + 2, 3, 3, 3, 4, 4, 4, 4, 4, 1, + 1, 1, 1, 0, 2, 1, 2, 2, 4, 4, + 3, 3, 1, 1, 2, 2, 3, 3, 4, 1, + 1, 2 }; static const short yydefact[] = { 0, - 0, 110, 0, 0, 0, 110, 110, 0, 0, 34, - 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 4, 0, 0, 110, 110, 36, 39, 41, 122, - 42, 43, 56, 60, 58, 57, 59, 0, 112, 119, - 3, 0, 0, 110, 110, 110, 0, 0, 110, 120, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, 13, 19, 15, 27, 21, 17, 25, 23, 29, - 31, 32, 7, 8, 0, 0, 34, 40, 37, 44, - 1, 110, 110, 113, 114, 110, 110, 0, 111, 95, - 96, 105, 0, 110, 0, 110, 0, 110, 110, 0, - 0, 110, 12, 14, 20, 16, 28, 22, 18, 26, - 24, 30, 33, 9, 10, 77, 73, 38, 0, 0, - 117, 118, 0, 0, 106, 110, 110, 110, 110, 110, - 110, 0, 110, 5, 110, 0, 110, 5, 110, 0, - 0, 110, 71, 0, 115, 116, 0, 0, 121, 110, - 110, 74, 0, 0, 0, 98, 99, 97, 0, 81, - 110, 87, 0, 110, 110, 0, 0, 0, 110, 110, - 0, 0, 0, 54, 55, 0, 72, 67, 0, 0, - 76, 100, 101, 102, 103, 104, 53, 82, 88, 0, - 51, 93, 0, 0, 0, 0, 45, 6, 108, 107, - 109, 110, 46, 0, 0, 61, 110, 62, 69, 68, - 75, 110, 110, 110, 110, 52, 0, 0, 110, 47, - 48, 0, 63, 64, 0, 70, 78, 0, 0, 0, - 110, 94, 83, 84, 110, 110, 110, 110, 110, 80, - 85, 86, 89, 90, 0, 0, 0, 0, 79, 91, - 92, 49, 50, 65, 66, 0, 0, 0 + 0, 104, 0, 0, 0, 104, 104, 0, 0, 121, + 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 4, 0, 0, 104, 104, 36, 39, 41, + 120, 42, 44, 48, 45, 52, 50, 49, 51, 0, + 106, 113, 114, 0, 3, 90, 0, 0, 104, 104, + 104, 0, 0, 104, 115, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 11, 13, 19, + 15, 27, 21, 17, 25, 23, 29, 31, 32, 7, + 8, 0, 0, 0, 34, 40, 37, 43, 1, 104, + 104, 107, 108, 104, 0, 116, 104, 105, 89, 91, + 100, 0, 104, 0, 104, 0, 104, 104, 0, 0, + 118, 104, 12, 14, 20, 16, 28, 22, 18, 26, + 24, 30, 33, 9, 10, 75, 0, 71, 38, 0, + 0, 111, 112, 0, 117, 0, 104, 104, 104, 104, + 104, 104, 0, 104, 0, 104, 0, 104, 0, 104, + 0, 0, 104, 70, 0, 109, 110, 0, 0, 119, + 104, 104, 72, 0, 0, 0, 93, 94, 92, 0, + 79, 104, 0, 104, 104, 0, 5, 0, 0, 104, + 104, 0, 0, 0, 46, 47, 0, 68, 0, 0, + 74, 95, 96, 97, 98, 99, 67, 85, 80, 0, + 65, 87, 0, 0, 0, 0, 53, 6, 102, 101, + 103, 104, 54, 0, 0, 59, 104, 60, 69, 73, + 104, 104, 104, 104, 86, 66, 0, 0, 104, 55, + 56, 0, 61, 62, 0, 76, 0, 0, 0, 104, + 88, 81, 82, 104, 104, 104, 104, 104, 78, 83, + 84, 0, 0, 0, 0, 77, 57, 58, 63, 64, + 0, 0, 0 }; -static const short yydefgoto[] = { 256, - 167, 27, 28, 80, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 153, 159, 160, 161, 162, 194, 42, - 90, 91, 202, 43, 38, 121, 92 +static const short yydefgoto[] = { 261, + 178, 28, 29, 88, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 164, 170, 171, 172, 204, 46, + 47, 99, 100, 212, 83, 40, 132, 101, 43, 44 }; -static const short yypact[] = { 233, - -28,-32768, 2, 10, 15,-32768,-32768, 32, 437, 19, --32768, 494, 46, 52, -5, 39, 59, 61, 93, 95, --32768,-32768, 102, 103,-32768,-32768,-32768,-32768, 462,-32768, --32768, 478,-32768,-32768,-32768,-32768,-32768, 71, 116, 91, --32768, 126, 301,-32768, 117, 118, 123, 139, 89, 91, - 111, 137, 138, 75, 76, 141, 143, 146, 148, 149, +static const short yypact[] = { 246, + -19,-32768, 8, 25, 29,-32768,-32768, 33, 354, 4, + 34,-32768, 499, 46, 51, 32, 38, 56, 70, 72, + 90,-32768,-32768, 97, 101,-32768,-32768,-32768,-32768, 161, +-32768, 483,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 6, + 139,-32768, 84, 390,-32768,-32768, 120, 282,-32768, 89, + 94, 112, 117, 87, 84, 462,-32768, 96, 123, 127, + 52, 55, 128, 129, 133, 137, 140,-32768,-32768,-32768, -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768, 127, 131,-32768,-32768,-32768, 478, --32768,-32768,-32768, 369, 369,-32768,-32768, 437,-32768,-32768, - 101, 91, 37,-32768, -4,-32768, 22,-32768,-32768, 133, - -23,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 335, 335, - 60, 60, 403, 98, 91,-32768,-32768,-32768,-32768,-32768, --32768, 3,-32768,-32768,-32768, 33,-32768,-32768,-32768, 167, - 172,-32768, 478, -23,-32768,-32768, 369, 369, 91,-32768, --32768,-32768, 181, 301, 301, 301, 301, 301, 186,-32768, --32768,-32768, 21,-32768,-32768, 192, 83, 168,-32768,-32768, - 194, 83, 175,-32768,-32768, -23, 478, 478, 208, 214, --32768,-32768,-32768, 87, 87, 87,-32768,-32768,-32768, 24, --32768,-32768, 200, -22, 205, 179,-32768,-32768,-32768,-32768, --32768,-32768,-32768, 207, 182,-32768,-32768,-32768, 478, 478, --32768,-32768,-32768,-32768,-32768,-32768, 29, 204,-32768,-32768, --32768, 34,-32768,-32768, 35, 478, 135, 301, 301, 301, --32768,-32768, 198, 173,-32768,-32768,-32768,-32768,-32768,-32768, - 199, 267,-32768,-32768, 213, 193, 222, 196,-32768,-32768, --32768,-32768,-32768,-32768,-32768, 239, 240,-32768 +-32768, 121, 282, 122,-32768,-32768,-32768, 483,-32768,-32768, +-32768, 318, 318,-32768, 462, 84,-32768,-32768,-32768, 92, +-32768, -10,-32768, 2,-32768, 14,-32768,-32768, 130, -28, + 84,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 92,-32768,-32768, 282, + 282, 10, 10, 426, 84, 93,-32768,-32768,-32768,-32768, +-32768,-32768, 23,-32768, 148,-32768, 26,-32768, 148,-32768, + 158, 164,-32768,-32768, -28,-32768,-32768, 318, 318, 84, +-32768,-32768,-32768, 178, 282, 282, 282, 282, 282, 177, + 166,-32768, -7,-32768,-32768, 176,-32768, 83, 153,-32768, +-32768, 183, 83, 155,-32768,-32768, -28,-32768, 193, 199, +-32768,-32768,-32768, 57, 57, 57,-32768,-32768, 174, -1, +-32768,-32768, 184, -29, 191, 163,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, 194, 167,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, -13, 187,-32768,-32768, +-32768, 27,-32768,-32768, 28, 103, 282, 282, 282,-32768, +-32768,-32768, 282,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 282, 197, 169, 201, 170,-32768,-32768,-32768,-32768,-32768, + 217, 218,-32768 }; static const short yypgoto[] = {-32768, - 104, -30, 218, -132,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768, -92, 28,-32768, 100,-32768, 105, 55, -6, --32768, -130, 78, -41,-32768, 6, 23 + 74, -26, 195,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, -97, -12,-32768, 58,-32768, 30, -3, + 5,-32768, -82, 45, -2,-32768, 3, 22, 12, 220 }; -#define YYLAST 533 - - -static const short yytable[] = { 47, - 48, 79, 93, 95, 97, 39, 41, 101, 143, 133, - 177, 89, 134, 63, 218, 64, 164, 25, 75, 76, - 44, 219, 40, 182, 183, 184, 185, 186, 45, 191, - 89, 50, 216, 46, 65, 137, 135, 89, 138, 192, - 119, 120, 192, 165, 123, 210, 169, 235, 237, 118, - 49, 178, 132, 131, 136, 89, 89, 66, 89, 67, - 144, 51, 139, 193, 61, 218, 193, 89, 89, 89, - 62, 89, 231, 170, 236, 238, 226, 69, 68, 70, - 124, 82, 83, 209, 154, 155, 156, 157, 158, 163, - 122, 140, 141, 105, 108, 106, 109, 184, 185, 186, - 176, 198, 150, 151, 152, 81, 40, 40, 126, 127, - 125, 71, 79, 72, 107, 110, 199, 200, 201, 190, - 73, 74, 126, 127, 145, 146, 166, 86, 168, 87, - 171, 100, 173, 128, 129, 130, 98, 82, 83, 239, - 151, 40, 40, 179, 180, 149, 118, 79, 84, 85, - 94, 96, 99, 122, 102, 103, 104, 195, 196, 111, - 222, 112, 204, 205, 113, 225, 114, 115, 116, 40, - 40, 228, 229, 230, 117, 2, 142, 234, 79, 118, - 3, 174, 4, 5, 6, 7, 175, 181, 8, 242, - 88, 10, 11, 12, 187, 118, 13, 14, 15, 16, - 244, 17, 18, 19, 20, 227, 197, 89, 206, 203, - 23, 24, 233, 25, 211, 26, 208, 212, 192, 220, - 221, 223, 232, 224, 241, 243, 250, 252, 245, 246, - 247, 248, 249, 1, 253, 2, 254, 255, 257, 258, - 3, 172, 4, 5, 6, 7, 78, 217, 8, 207, - 9, 10, 11, 12, 240, 0, 13, 14, 15, 16, - 188, 17, 18, 19, 20, 189, 0, 21, 22, 2, - 23, 24, 0, 25, 3, 26, 4, 5, 6, 7, - 0, 0, 8, 0, 88, 10, 11, 12, 0, 0, - 13, 14, 15, 16, 251, 17, 18, 19, 20, 0, - 0, 89, 0, 2, 23, 24, 0, 25, 3, 26, - 4, 5, 6, 7, 0, 0, 8, 0, 88, 10, - 11, 12, 0, 0, 13, 14, 15, 16, 0, 17, - 18, 19, 20, 0, 0, 89, 0, 2, 23, 24, - 0, 25, 3, 26, 4, 5, 6, 7, 0, 0, - 8, 0, 9, 10, 11, 12, 0, 0, 13, 14, - 15, 16, 0, 17, 18, 19, 20, 0, 0, 89, - 0, 2, 23, 24, 0, 25, 3, 26, 4, 5, - 6, 7, 0, 0, 8, 0, 9, 10, 11, 12, - 0, 0, 13, 14, 15, 16, 0, 17, 18, 19, - 20, 0, 0, 0, 0, 2, 23, 24, 0, 25, - 3, 26, 4, 5, 6, 7, 0, 0, 8, 0, - 0, 10, 11, 12, 0, 0, 13, 14, 15, 16, - 0, 17, 18, 19, 20, 0, 0, 89, 0, 2, - 23, 24, 0, 25, 3, 26, 4, 5, 6, 7, - 0, 0, 8, 0, 0, 10, 11, 12, 0, 0, - 13, 14, 15, 16, 0, 17, 18, 19, 20, 0, - 0, 0, 0, 0, 23, 24, 0, 25, 0, 26, - 77, 11, 12, 0, 0, 13, 14, 15, 16, 0, - 17, 18, 19, 20, 0, 0, 0, 0, 12, 23, - 24, 13, 14, 15, 16, 0, 17, 18, 19, 20, - 0, 0, 0, 0, 0, 23, 24, 52, 53, 54, - 55, 0, 56, 0, 57, 58, 0, 0, 0, 0, - 0, 59, 60 +#define YYLAST 540 + + +static const short yytable[] = { 48, + 127, 201, 41, 48, 48, 87, 142, 226, 98, 228, + 52, 53, 154, 202, 26, 144, 229, 45, 145, 202, + 55, 42, 82, 57, 48, 228, 98, 148, 49, 98, + 149, 84, 240, 90, 91, 98, 174, 203, 98, 180, + 244, 246, 89, 203, 146, 50, 102, 104, 106, 51, + 98, 110, 70, 54, 71, 96, 150, 188, 73, 98, + 74, 129, 98, 98, 98, 175, 68, 111, 181, 245, + 247, 69, 115, 72, 116, 118, 76, 119, 58, 75, + 137, 138, 192, 193, 194, 195, 196, 130, 131, 219, + 77, 134, 78, 117, 48, 133, 120, 161, 162, 163, + 143, 136, 147, 208, 48, 48, 135, 248, 162, 155, + 79, 151, 152, 42, 42, 137, 138, 80, 209, 210, + 211, 81, 94, 97, 103, 107, 139, 140, 141, 105, + 108, 109, 156, 157, 165, 166, 167, 168, 169, 173, + 176, 112, 179, 113, 182, 160, 184, 114, 121, 122, + 187, 42, 42, 123, 194, 195, 196, 124, 48, 48, + 125, 133, 90, 91, 126, 189, 190, 128, 177, 200, + 205, 206, 185, 92, 93, 153, 214, 215, 186, 42, + 42, 85, 12, 13, 191, 197, 14, 15, 16, 17, + 207, 18, 19, 20, 21, 198, 213, 216, 218, 220, + 24, 25, 221, 225, 202, 230, 231, 241, 233, 232, + 234, 257, 258, 260, 235, 259, 262, 263, 48, 237, + 238, 239, 183, 249, 86, 236, 243, 217, 56, 199, + 0, 0, 227, 242, 0, 0, 0, 251, 0, 0, + 252, 253, 254, 255, 250, 48, 1, 0, 2, 0, + 0, 0, 256, 3, 0, 4, 5, 6, 7, 0, + 0, 8, 0, 9, 10, 0, 11, 12, 13, 0, + 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, + 0, 0, 22, 23, 2, 24, 25, 0, 26, 3, + 27, 4, 5, 6, 7, 0, 0, 8, 0, 9, + 10, 0, 11, 12, 13, 0, 0, 14, 15, 16, + 17, 0, 18, 19, 20, 21, 0, 0, 98, 0, + 2, 24, 25, 0, 26, 3, 27, 4, 5, 6, + 7, 0, 0, 8, 0, 9, 10, 0, 11, 12, + 13, 0, 0, 14, 15, 16, 17, 0, 18, 19, + 20, 21, 0, 0, 0, 0, 2, 24, 25, 0, + 26, 3, 27, 4, 5, 6, 7, 0, 0, 8, + 0, 0, 10, 0, 11, 12, 13, 0, 0, 14, + 15, 16, 17, 0, 18, 19, 20, 21, 0, 0, + 0, 0, 2, 24, 25, 0, 26, 3, 27, 4, + 5, 6, 7, 0, 0, 8, 0, 95, 0, 0, + 11, 12, 13, 0, 0, 14, 15, 16, 17, 0, + 18, 19, 20, 21, 0, 0, 0, 0, 2, 24, + 25, 0, 26, 3, 27, 4, 5, 6, 7, 0, + 0, 8, 0, 0, 0, 0, 11, 12, 13, 0, + 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, + 0, 0, 98, 0, 2, 24, 25, 0, 26, 3, + 27, 4, 5, 6, 7, 0, 0, 8, 0, 0, + 0, 0, 11, 12, 13, 0, 0, 14, 15, 16, + 17, 0, 18, 19, 20, 21, 0, 0, 0, 0, + 0, 24, 25, 0, 26, 13, 27, 0, 14, 15, + 16, 17, 0, 18, 19, 20, 21, 0, 0, 0, + 0, 0, 24, 25, 59, 60, 61, 62, 0, 63, + 0, 64, 65, 0, 0, 0, 0, 0, 66, 67 }; -static const short yycheck[] = { 6, - 7, 32, 44, 45, 46, 0, 35, 49, 101, 14, - 143, 35, 17, 19, 37, 21, 14, 41, 25, 26, - 19, 44, 0, 154, 155, 156, 157, 158, 19, 9, - 35, 9, 9, 19, 40, 14, 41, 35, 17, 19, - 82, 83, 19, 41, 86, 178, 14, 14, 14, 80, - 19, 144, 94, 17, 96, 35, 35, 19, 35, 21, - 102, 43, 41, 43, 19, 37, 43, 35, 35, 35, - 19, 35, 44, 41, 41, 41, 209, 19, 40, 19, - 87, 22, 23, 176, 126, 127, 128, 129, 130, 131, - 85, 98, 99, 19, 19, 21, 21, 228, 229, 230, - 142, 19, 5, 6, 7, 35, 84, 85, 22, 23, - 88, 19, 143, 19, 40, 40, 34, 35, 36, 161, - 19, 19, 22, 23, 119, 120, 133, 37, 135, 4, - 137, 43, 139, 33, 34, 35, 14, 22, 23, 5, - 6, 119, 120, 150, 151, 123, 177, 178, 33, 34, - 34, 34, 14, 148, 44, 19, 19, 164, 165, 19, - 202, 19, 169, 170, 19, 207, 19, 19, 42, 147, - 148, 213, 214, 215, 44, 3, 44, 219, 209, 210, - 8, 15, 10, 11, 12, 13, 15, 7, 16, 231, - 18, 19, 20, 21, 9, 226, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 212, 15, 35, 15, 42, - 38, 39, 219, 41, 7, 43, 42, 4, 19, 15, - 42, 15, 19, 42, 231, 28, 28, 15, 235, 236, - 237, 238, 239, 1, 42, 3, 15, 42, 0, 0, - 8, 138, 10, 11, 12, 13, 29, 193, 16, 172, - 18, 19, 20, 21, 227, -1, 24, 25, 26, 27, - 161, 29, 30, 31, 32, 161, -1, 35, 36, 3, - 38, 39, -1, 41, 8, 43, 10, 11, 12, 13, - -1, -1, 16, -1, 18, 19, 20, 21, -1, -1, - 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, - -1, 35, -1, 3, 38, 39, -1, 41, 8, 43, - 10, 11, 12, 13, -1, -1, 16, -1, 18, 19, - 20, 21, -1, -1, 24, 25, 26, 27, -1, 29, - 30, 31, 32, -1, -1, 35, -1, 3, 38, 39, - -1, 41, 8, 43, 10, 11, 12, 13, -1, -1, - 16, -1, 18, 19, 20, 21, -1, -1, 24, 25, - 26, 27, -1, 29, 30, 31, 32, -1, -1, 35, - -1, 3, 38, 39, -1, 41, 8, 43, 10, 11, - 12, 13, -1, -1, 16, -1, 18, 19, 20, 21, - -1, -1, 24, 25, 26, 27, -1, 29, 30, 31, - 32, -1, -1, -1, -1, 3, 38, 39, -1, 41, - 8, 43, 10, 11, 12, 13, -1, -1, 16, -1, - -1, 19, 20, 21, -1, -1, 24, 25, 26, 27, - -1, 29, 30, 31, 32, -1, -1, 35, -1, 3, - 38, 39, -1, 41, 8, 43, 10, 11, 12, 13, - -1, -1, 16, -1, -1, 19, 20, 21, -1, -1, - 24, 25, 26, 27, -1, 29, 30, 31, 32, -1, - -1, -1, -1, -1, 38, 39, -1, 41, -1, 43, - 19, 20, 21, -1, -1, 24, 25, 26, 27, -1, - 29, 30, 31, 32, -1, -1, -1, -1, 21, 38, - 39, 24, 25, 26, 27, -1, 29, 30, 31, 32, - -1, -1, -1, -1, -1, 38, 39, 24, 25, 26, - 27, -1, 29, -1, 31, 32, -1, -1, -1, -1, - -1, 38, 39 +static const short yycheck[] = { 2, + 83, 9, 0, 6, 7, 32, 17, 9, 37, 39, + 6, 7, 110, 21, 43, 14, 46, 37, 17, 21, + 9, 0, 26, 20, 27, 39, 37, 14, 21, 37, + 17, 27, 46, 24, 25, 37, 14, 45, 37, 14, + 14, 14, 37, 45, 43, 21, 49, 50, 51, 21, + 37, 54, 21, 21, 23, 44, 43, 155, 21, 37, + 23, 88, 37, 37, 37, 43, 21, 56, 43, 43, + 43, 21, 21, 42, 23, 21, 21, 23, 45, 42, + 24, 25, 165, 166, 167, 168, 169, 90, 91, 187, + 21, 94, 21, 42, 97, 93, 42, 5, 6, 7, + 103, 97, 105, 21, 107, 108, 95, 5, 6, 112, + 21, 107, 108, 92, 93, 24, 25, 21, 36, 37, + 38, 21, 39, 4, 36, 14, 35, 36, 37, 36, + 14, 45, 130, 131, 137, 138, 139, 140, 141, 142, + 144, 46, 146, 21, 148, 134, 150, 21, 21, 21, + 153, 130, 131, 21, 237, 238, 239, 21, 161, 162, + 21, 159, 24, 25, 44, 161, 162, 46, 21, 172, + 174, 175, 15, 35, 36, 46, 180, 181, 15, 158, + 159, 21, 22, 23, 7, 9, 26, 27, 28, 29, + 15, 31, 32, 33, 34, 30, 44, 15, 44, 7, + 40, 41, 4, 30, 21, 15, 44, 21, 15, 212, + 44, 15, 44, 44, 217, 15, 0, 0, 221, 222, + 223, 224, 149, 236, 30, 221, 229, 183, 9, 172, + -1, -1, 203, 229, -1, -1, -1, 240, -1, -1, + 244, 245, 246, 247, 240, 248, 1, -1, 3, -1, + -1, -1, 248, 8, -1, 10, 11, 12, 13, -1, + -1, 16, -1, 18, 19, -1, 21, 22, 23, -1, + -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, + -1, -1, 37, 38, 3, 40, 41, -1, 43, 8, + 45, 10, 11, 12, 13, -1, -1, 16, -1, 18, + 19, -1, 21, 22, 23, -1, -1, 26, 27, 28, + 29, -1, 31, 32, 33, 34, -1, -1, 37, -1, + 3, 40, 41, -1, 43, 8, 45, 10, 11, 12, + 13, -1, -1, 16, -1, 18, 19, -1, 21, 22, + 23, -1, -1, 26, 27, 28, 29, -1, 31, 32, + 33, 34, -1, -1, -1, -1, 3, 40, 41, -1, + 43, 8, 45, 10, 11, 12, 13, -1, -1, 16, + -1, -1, 19, -1, 21, 22, 23, -1, -1, 26, + 27, 28, 29, -1, 31, 32, 33, 34, -1, -1, + -1, -1, 3, 40, 41, -1, 43, 8, 45, 10, + 11, 12, 13, -1, -1, 16, -1, 18, -1, -1, + 21, 22, 23, -1, -1, 26, 27, 28, 29, -1, + 31, 32, 33, 34, -1, -1, -1, -1, 3, 40, + 41, -1, 43, 8, 45, 10, 11, 12, 13, -1, + -1, 16, -1, -1, -1, -1, 21, 22, 23, -1, + -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, + -1, -1, 37, -1, 3, 40, 41, -1, 43, 8, + 45, 10, 11, 12, 13, -1, -1, 16, -1, -1, + -1, -1, 21, 22, 23, -1, -1, 26, 27, 28, + 29, -1, 31, 32, 33, 34, -1, -1, -1, -1, + -1, 40, 41, -1, 43, 23, 45, -1, 26, 27, + 28, 29, -1, 31, 32, 33, 34, -1, -1, -1, + -1, -1, 40, 41, 26, 27, 28, 29, -1, 31, + -1, 33, 34, -1, -1, -1, -1, -1, 40, 41 }; /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ #line 3 "/usr/local/lib/bison.simple" @@ -1024,7 +1070,7 @@ yyreduce: switch (yyn) { case 1: -#line 164 "./parse.y" +#line 210 "./parse.y" { /* Case of regular command. Discard the error safety net,and return the command just parsed. */ @@ -1035,7 +1081,7 @@ case 1: ; break;} case 2: -#line 173 "./parse.y" +#line 219 "./parse.y" { /* Case of regular command, but not a very interesting one. Return a NULL command. */ @@ -1044,7 +1090,7 @@ case 2: ; break;} case 3: -#line 181 "./parse.y" +#line 226 "./parse.y" { /* Error during parsing. Return NULL command. */ global_command = (COMMAND *)NULL; @@ -1061,9 +1107,9 @@ case 3: ; break;} case 4: -#line 196 "./parse.y" +#line 241 "./parse.y" { - /* Case of EOF seen by itself. Do ignoreeof or + /* Case of EOF seen by itself. Do ignoreeof or not. */ global_command = (COMMAND *)NULL; handle_eof_input_unit (); @@ -1071,57 +1117,57 @@ case 4: ; break;} case 5: -#line 206 "./parse.y" -{ yyval.word_list = (WORD_LIST *)NULL; ; +#line 251 "./parse.y" +{ yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} case 6: -#line 208 "./parse.y" +#line 253 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-1].word_list); ; break;} case 7: -#line 212 "./parse.y" +#line 257 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_direction, redir); ; break;} case 8: -#line 217 "./parse.y" +#line 262 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_input_direction, redir); ; break;} case 9: -#line 222 "./parse.y" +#line 267 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_direction, redir); ; break;} case 10: -#line 227 "./parse.y" +#line 272 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_direction, redir); ; break;} case 11: -#line 232 "./parse.y" +#line 277 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_appending_to, redir); ; break;} case 12: -#line 237 "./parse.y" +#line 282 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_appending_to, redir); ; break;} case 13: -#line 242 "./parse.y" +#line 287 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_reading_until, redir); @@ -1129,7 +1175,7 @@ case 13: ; break;} case 14: -#line 248 "./parse.y" +#line 293 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_reading_until, redir); @@ -1137,63 +1183,63 @@ case 14: ; break;} case 15: -#line 254 "./parse.y" +#line 299 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (0, r_duplicating_input, redir); ; break;} case 16: -#line 259 "./parse.y" +#line 304 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input, redir); ; break;} case 17: -#line 264 "./parse.y" +#line 309 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (1, r_duplicating_output, redir); ; break;} case 18: -#line 269 "./parse.y" +#line 314 "./parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output, redir); ; break;} case 19: -#line 274 "./parse.y" +#line 319 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_duplicating_input_word, redir); ; break;} case 20: -#line 279 "./parse.y" +#line 324 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input_word, redir); ; break;} case 21: -#line 284 "./parse.y" +#line 329 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_duplicating_output_word, redir); ; break;} case 22: -#line 289 "./parse.y" +#line 334 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output_word, redir); ; break;} case 23: -#line 294 "./parse.y" +#line 339 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1202,7 +1248,7 @@ case 23: ; break;} case 24: -#line 301 "./parse.y" +#line 346 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1211,369 +1257,342 @@ case 24: ; break;} case 25: -#line 308 "./parse.y" +#line 353 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (1, r_close_this, redir); ; break;} case 26: -#line 313 "./parse.y" +#line 358 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 27: -#line 318 "./parse.y" +#line 363 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (0, r_close_this, redir); ; break;} case 28: -#line 323 "./parse.y" +#line 368 "./parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 29: -#line 328 "./parse.y" +#line 373 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_err_and_out, redir); ; break;} case 30: -#line 333 "./parse.y" +#line 378 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_output, redir); ; break;} case 31: -#line 338 "./parse.y" +#line 383 "./parse.y" { - REDIRECT *t1, *t2; - redir.filename = yyvsp[0].word; - if (posixly_correct) - yyval.redirect = make_redirection (0, r_input_output, redir); - else - { - t1 = make_redirection (0, r_input_direction, redir); - redir.filename = copy_word (yyvsp[0].word); - t2 = make_redirection (1, r_output_direction, redir); - t1->next = t2; - yyval.redirect = t1; - } + yyval.redirect = make_redirection (0, r_input_output, redir); ; break;} case 32: -#line 354 "./parse.y" +#line 388 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_force, redir); ; break;} case 33: -#line 359 "./parse.y" +#line 393 "./parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_force, redir); ; break;} case 34: -#line 366 "./parse.y" +#line 400 "./parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 35: -#line 368 "./parse.y" +#line 402 "./parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 36: -#line 370 "./parse.y" +#line 404 "./parse.y" { yyval.element.redirect = yyvsp[0].redirect; yyval.element.word = 0; ; break;} case 37: -#line 374 "./parse.y" +#line 408 "./parse.y" { yyval.redirect = yyvsp[0].redirect; ; break;} case 38: -#line 378 "./parse.y" -{ - register REDIRECT *t = yyvsp[-1].redirect; +#line 412 "./parse.y" +{ + register REDIRECT *t; - while (t->next) - t = t->next; - t->next = yyvsp[0].redirect; + for (t = yyvsp[-1].redirect; t->next; t = t->next) + ; + t->next = yyvsp[0].redirect; yyval.redirect = yyvsp[-1].redirect; ; break;} case 39: -#line 389 "./parse.y" +#line 423 "./parse.y" { yyval.command = make_simple_command (yyvsp[0].element, (COMMAND *)NULL); ; break;} case 40: -#line 391 "./parse.y" +#line 425 "./parse.y" { yyval.command = make_simple_command (yyvsp[0].element, yyvsp[-1].command); ; break;} case 41: -#line 395 "./parse.y" +#line 429 "./parse.y" { yyval.command = clean_simple_command (yyvsp[0].command); ; break;} case 42: -#line 397 "./parse.y" +#line 431 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} case 43: -#line 401 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 44: -#line 403 "./parse.y" +#line 433 "./parse.y" { - if (yyvsp[-1].command->redirects) + COMMAND *tc; + + tc = yyvsp[-1].command; + /* According to Posix.2 3.9.5, redirections + specified after the body of a function should + be attached to the function and performed when + the function is executed, not as part of the + function definition command. */ + if (tc->type == cm_function_def) + { + tc = tc->value.Function_def->command; + if (tc->type == cm_group) + tc = tc->value.Group->command; + } + if (tc->redirects) { register REDIRECT *t; - for (t = yyvsp[-1].command->redirects; t->next; t = t->next) + for (t = tc->redirects; t->next; t = t->next) ; t->next = yyvsp[0].redirect; } else - yyvsp[-1].command->redirects = yyvsp[0].redirect; + tc->redirects = yyvsp[0].redirect; yyval.command = yyvsp[-1].command; ; break;} +case 44: +#line 462 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} case 45: -#line 418 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 464 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 46: -#line 420 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 466 "./parse.y" +{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 47: -#line 422 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 468 "./parse.y" +{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 48: -#line 424 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 470 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 49: -#line 426 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 472 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 50: -#line 428 "./parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 474 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 51: -#line 431 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; +#line 476 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 52: -#line 433 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; +#line 478 "./parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 53: -#line 435 "./parse.y" -{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; +#line 482 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 54: -#line 437 "./parse.y" -{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; +#line 484 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 55: -#line 439 "./parse.y" -{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; +#line 486 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 56: -#line 441 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 488 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 57: -#line 443 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 490 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; break;} case 58: -#line 445 "./parse.y" -{ yyval.command = yyvsp[0].command; ; +#line 492 "./parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; break;} case 59: -#line 447 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 60: -#line 449 "./parse.y" -{ yyval.command = yyvsp[0].command; ; - break;} -case 61: -#line 453 "./parse.y" +#line 496 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 62: -#line 459 "./parse.y" +case 60: +#line 500 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 63: -#line 465 "./parse.y" +case 61: +#line 504 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 64: -#line 471 "./parse.y" +case 62: +#line 508 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); -#endif ; break;} -case 65: -#line 477 "./parse.y" +case 63: +#line 512 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); -#endif ; break;} -case 66: -#line 483 "./parse.y" +case 64: +#line 516 "./parse.y" { -#if defined (SELECT_COMMAND) yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); -#endif ; break;} +case 65: +#line 522 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; + break;} +case 66: +#line 524 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; + break;} case 67: -#line 491 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; +#line 526 "./parse.y" +{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; break;} case 68: -#line 494 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ; +#line 530 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 69: -#line 497 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ; +#line 534 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 70: -#line 500 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ; +#line 537 "./parse.y" +{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} case 71: -#line 503 "./parse.y" -{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command); ; - break;} -case 72: -#line 506 "./parse.y" -{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-3].word, yyvsp[-1].command); ; - break;} -case 73: -#line 510 "./parse.y" +#line 541 "./parse.y" { yyvsp[-1].command->flags |= CMD_WANT_SUBSHELL; yyval.command = yyvsp[-1].command; ; break;} -case 74: -#line 514 "./parse.y" +case 72: +#line 545 "./parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, (COMMAND *)NULL); ; break;} -case 75: -#line 516 "./parse.y" +case 73: +#line 547 "./parse.y" { yyval.command = make_if_command (yyvsp[-5].command, yyvsp[-3].command, yyvsp[-1].command); ; break;} -case 76: -#line 518 "./parse.y" +case 74: +#line 549 "./parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[-1].command); ; break;} -case 77: -#line 523 "./parse.y" +case 75: +#line 554 "./parse.y" { yyval.command = make_group_command (yyvsp[-1].command); ; break;} -case 78: -#line 527 "./parse.y" +case 76: +#line 558 "./parse.y" { yyval.command = make_if_command (yyvsp[-2].command, yyvsp[0].command, (COMMAND *)NULL); ; break;} -case 79: -#line 529 "./parse.y" +case 77: +#line 560 "./parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[0].command); ; break;} -case 80: -#line 531 "./parse.y" +case 78: +#line 562 "./parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, yyvsp[0].command); ; break;} -case 82: -#line 536 "./parse.y" +case 80: +#line 567 "./parse.y" { yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; break;} -case 83: -#line 540 "./parse.y" +case 81: +#line 571 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 84: -#line 542 "./parse.y" +case 82: +#line 573 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 85: -#line 544 "./parse.y" +case 83: +#line 575 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 86: -#line 546 "./parse.y" +case 84: +#line 577 "./parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 88: -#line 551 "./parse.y" -{ yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; - break;} -case 89: -#line 555 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ; - break;} -case 90: -#line 557 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ; - break;} -case 91: -#line 559 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ; - break;} -case 92: -#line 561 "./parse.y" -{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ; +case 86: +#line 582 "./parse.y" +{ yyvsp[-1].pattern->next = yyvsp[-2].pattern; yyval.pattern = yyvsp[-1].pattern; ; break;} -case 93: -#line 565 "./parse.y" +case 87: +#line 586 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} -case 94: -#line 567 "./parse.y" +case 88: +#line 588 "./parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-2].word_list); ; break;} -case 95: -#line 576 "./parse.y" +case 89: +#line 597 "./parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 98: -#line 586 "./parse.y" +case 91: +#line 606 "./parse.y" +{ + yyval.command = yyvsp[0].command; + ; + break;} +case 93: +#line 613 "./parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, (COMMAND *)NULL, '&'); @@ -1581,16 +1600,16 @@ case 98: yyval.command = command_connect (yyvsp[-2].command, (COMMAND *)NULL, '&'); ; break;} -case 100: -#line 597 "./parse.y" +case 95: +#line 624 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 101: -#line 599 "./parse.y" +case 96: +#line 626 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 102: -#line 601 "./parse.y" +case 97: +#line 628 "./parse.y" { if (yyvsp[-3].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-3].command, yyvsp[0].command, '&'); @@ -1598,35 +1617,28 @@ case 102: yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '&'); ; break;} -case 103: -#line 608 "./parse.y" +case 98: +#line 635 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 104: -#line 610 "./parse.y" +case 99: +#line 637 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 105: -#line 612 "./parse.y" +case 100: +#line 639 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} case 106: -#line 614 "./parse.y" -{ - yyvsp[0].command->flags |= CMD_INVERT_RETURN; - yyval.command = yyvsp[0].command; - ; - break;} -case 112: -#line 636 "./parse.y" +#line 658 "./parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 113: -#line 642 "./parse.y" +case 107: +#line 664 "./parse.y" { if (yyvsp[-1].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-1].command, (COMMAND *)NULL, '&'); @@ -1636,24 +1648,24 @@ case 113: gather_here_documents (); ; break;} -case 114: -#line 651 "./parse.y" +case 108: +#line 673 "./parse.y" { yyval.command = yyvsp[-1].command; if (need_here_doc) gather_here_documents (); ; break;} -case 115: -#line 659 "./parse.y" +case 109: +#line 681 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 116: -#line 661 "./parse.y" +case 110: +#line 683 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 117: -#line 663 "./parse.y" +case 111: +#line 685 "./parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, yyvsp[0].command, '&'); @@ -1661,29 +1673,62 @@ case 117: yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, '&'); ; break;} -case 118: -#line 670 "./parse.y" +case 112: +#line 692 "./parse.y" { yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, ';'); ; break;} -case 119: -#line 672 "./parse.y" +case 113: +#line 695 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 120: -#line 674 "./parse.y" +case 114: +#line 699 "./parse.y" +{ yyval.command = yyvsp[0].command; ; + break;} +case 115: +#line 701 "./parse.y" { yyvsp[0].command->flags |= CMD_INVERT_RETURN; yyval.command = yyvsp[0].command; ; break;} -case 121: -#line 682 "./parse.y" +case 116: +#line 706 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-1].number; + yyval.command = yyvsp[0].command; + ; + break;} +case 117: +#line 711 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-2].number; + yyval.command = yyvsp[0].command; + ; + break;} +case 118: +#line 716 "./parse.y" +{ + yyvsp[0].command->flags |= yyvsp[-1].number|CMD_INVERT_RETURN; + yyval.command = yyvsp[0].command; + ; + break;} +case 119: +#line 724 "./parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '|'); ; break;} -case 122: -#line 684 "./parse.y" +case 120: +#line 726 "./parse.y" { yyval.command = yyvsp[0].command; ; break;} +case 121: +#line 730 "./parse.y" +{ yyval.number = CMD_TIME_PIPELINE; ; + break;} +case 122: +#line 732 "./parse.y" +{ yyval.number = CMD_TIME_PIPELINE|CMD_TIME_POSIX; ; + break;} } /* the action file gets copied in in place of this dollarsign */ #line 498 "/usr/local/lib/bison.simple" @@ -1882,31 +1927,64 @@ yyerrhandle: yystate = yyn; goto yynewstate; } -#line 686 "./parse.y" +#line 734 "./parse.y" +/* Possible states for the parser that require it to do special things. */ +#define PST_CASEPAT 0x001 /* in a case pattern list */ +#define PST_ALEXPNEXT 0x002 /* expand next word for aliases */ +#define PST_ALLOWOPNBRC 0x004 /* allow open brace for function def */ +#define PST_NEEDCLOSBRC 0x008 /* need close brace */ +#define PST_DBLPAREN 0x010 /* double-paren parsing */ +#define PST_SUBSHELL 0x020 /* ( ... ) subshell */ +#define PST_CMDSUBST 0x040 /* $( ... ) command substitution */ +#define PST_CASESTMT 0x080 /* parsing a case statement */ + /* Initial size to allocate for tokens, and the amount to grow them by. */ #define TOKEN_DEFAULT_GROW_SIZE 512 +/* Shell meta-characters that, when unquoted, separate words. */ +#define shellmeta(c) (strchr ("()<>;&|", (c)) != 0) +#define shellbreak(c) (strchr ("()<>;&| \t\n", (c)) != 0) +#define shellquote(c) ((c) == '"' || (c) == '`' || (c) == '\'') +#define shellexp(c) ((c) == '$' || (c) == '<' || (c) == '>') + /* The token currently being read. */ -static int current_token = 0; +static int current_token; /* The last read token, or NULL. read_token () uses this for context checking. */ -static int last_read_token = 0; +static int last_read_token; /* The token read prior to last_read_token. */ -static int token_before_that = 0; +static int token_before_that; + +/* The token read prior to token_before_that. */ +static int two_tokens_ago; /* If non-zero, it is the token that we want read_token to return regardless of what text is (or isn't) present to be read. This - is reset by read_token. */ -static int token_to_read = 0; + is reset by read_token. If token_to_read == WORD or + ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */ +static int token_to_read; +static WORD_DESC *word_desc_to_read; + +/* The current parser state. */ +static int parser_state; /* Global var is non-zero when end of file has been reached. */ int EOF_Reached = 0; +void +debug_parser (i) + int i; +{ +#if YYDEBUG != 0 + yydebug = i; +#endif +} + /* yy_getc () returns the next available character from input or EOF. yy_ungetc (c) makes `c' the next character to read. init_yy_io (get, unget, type, location) makes the function GET the @@ -1916,6 +1994,7 @@ int EOF_Reached = 0; the input is coming from. */ /* Unconditionally returns end-of-file. */ +int return_EOF () { return (EOF); @@ -1925,11 +2004,13 @@ return_EOF () See ./input.h for a clearer description. */ BASH_INPUT bash_input; -/* Set all of the fields in BASH_INPUT to NULL. */ +/* Set all of the fields in BASH_INPUT to NULL. Free bash_input.name if it + is non-null, avoiding a memory leak. */ void initialize_bash_input () { - bash_input.type = 0; + bash_input.type = st_none; + FREE (bash_input.name); bash_input.name = (char *)NULL; bash_input.location.file = (FILE *)NULL; bash_input.location.string = (char *)NULL; @@ -1948,12 +2029,9 @@ init_yy_io (get, unget, type, name, location) { bash_input.type = type; FREE (bash_input.name); + bash_input.name = name ? savestring (name) : (char *)NULL; - if (name) - bash_input.name = savestring (name); - else - bash_input.name = (char *)NULL; - + /* XXX */ #if defined (CRAY) memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location)); #else @@ -1964,6 +2042,7 @@ init_yy_io (get, unget, type, name, location) } /* Call this to get the next character of input. */ +int yy_getc () { return (*(bash_input.getter)) (); @@ -1971,6 +2050,7 @@ yy_getc () /* Call this to unget C. That is, to make C the next character to be read. */ +int yy_ungetc (c) int c; { @@ -1987,6 +2067,7 @@ input_file_descriptor () return (fileno (bash_input.location.file)); case st_bstream: return (bash_input.location.buffered_fd); + case st_stdin: default: return (fileno (stdin)); } @@ -2007,11 +2088,11 @@ int current_readline_line_index = 0; static int yy_readline_get () { + SigHandler *old_sigint; + int line_len, c; + if (!current_readline_line) { - SigHandler *old_sigint; - int line_len; - if (!bash_readline_initialized) initialize_readline (); @@ -2026,10 +2107,8 @@ yy_readline_get () interrupt_immediately++; } - if (!current_readline_prompt) - current_readline_line = readline (""); - else - current_readline_line = readline (current_readline_prompt); + current_readline_line = readline (current_readline_prompt ? + current_readline_prompt : ""); if (signal_is_ignored (SIGINT) == 0) { @@ -2037,22 +2116,23 @@ yy_readline_get () set_signal_handler (SIGINT, old_sigint); } - /* Reset the prompt to whatever is in the decoded value of - prompt_string_pointer. */ +#if 0 + /* Reset the prompt to the decoded value of prompt_string_pointer. */ reset_readline_prompt (); +#endif - current_readline_line_index = 0; - - if (!current_readline_line) + if (current_readline_line == 0) return (EOF); + current_readline_line_index = 0; line_len = strlen (current_readline_line); + current_readline_line = xrealloc (current_readline_line, 2 + line_len); current_readline_line[line_len++] = '\n'; current_readline_line[line_len] = '\0'; } - if (!current_readline_line[current_readline_line_index]) + if (current_readline_line[current_readline_line_index] == 0) { free (current_readline_line); current_readline_line = (char *)NULL; @@ -2060,20 +2140,21 @@ yy_readline_get () } else { - int c = (unsigned char)current_readline_line[current_readline_line_index++]; + c = (unsigned char)current_readline_line[current_readline_line_index++]; return (c); } } static int yy_readline_unget (c) + int c; { if (current_readline_line_index && current_readline_line) current_readline_line[--current_readline_line_index] = c; return (c); } -void +void with_input_from_stdin () { INPUT_STREAM location; @@ -2104,7 +2185,7 @@ with_input_from_stdin () static int yy_string_get () { - register unsigned char *string; + register char *string; register int c; string = bash_input.location.string; @@ -2113,7 +2194,7 @@ yy_string_get () /* If the string doesn't exist, or is empty, EOF found. */ if (string && *string) { - c = *string++; + c = *(unsigned char *)string++; bash_input.location.string = string; } return (c); @@ -2129,13 +2210,11 @@ yy_string_unget (c) void with_input_from_string (string, name) - char *string; - char *name; + char *string, *name; { INPUT_STREAM location; location.string = string; - init_yy_io (yy_string_get, yy_string_unget, st_string, name, location); } @@ -2151,11 +2230,14 @@ yy_stream_get () int result = EOF; if (bash_input.location.file) -#if defined (NO_READ_RESTART_ON_SIGNAL) - result = (unsigned char)getc_with_restart (bash_input.location.file); -#else - result = (unsigned char)getc (bash_input.location.file); -#endif /* !NO_READ_RESTART_ON_SIGNAL */ + { +#if !defined (HAVE_RESTARTABLE_SYSCALLS) + result = getc_with_restart (bash_input.location.file); +#else /* HAVE_RESTARTABLE_SYSCALLS */ + result = getc (bash_input.location.file); + result = (feof (bash_input.location.file)) ? EOF : (unsigned char)result; +#endif /* HAVE_RESTARTABLE_SYSCALLS */ + } return (result); } @@ -2163,11 +2245,11 @@ static int yy_stream_unget (c) int c; { -#if defined (NO_READ_RESTART_ON_SIGNAL) +#if !defined (HAVE_RESTARTABLE_SYSCALLS) return (ungetc_with_restart (c, bash_input.location.file)); -#else +#else /* HAVE_RESTARTABLE_SYSCALLS */ return (ungetc (c, bash_input.location.file)); -#endif +#endif /* HAVE_RESTARTABLE_SYSCALLS */ } void @@ -2195,7 +2277,9 @@ int line_number = 0; STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL; -push_stream () +void +push_stream (reset_lineno) + int reset_lineno; { STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); @@ -2215,13 +2299,14 @@ push_stream () bash_input.name = (char *)NULL; saver->next = stream_list; stream_list = saver; - EOF_Reached = line_number = 0; + EOF_Reached = 0; + if (reset_lineno) + line_number = 0; } +void pop_stream () { - int temp; - if (!stream_list) EOF_Reached = 1; else @@ -2267,36 +2352,35 @@ pop_stream () /* Return 1 if a stream of type TYPE is saved on the stack. */ int stream_on_stack (type) - int type; + enum stream_type type; { register STREAM_SAVER *s; - + for (s = stream_list; s; s = s->next) if (s->bash_input.type == type) return 1; return 0; } - /* * This is used to inhibit alias expansion and reserved word recognition - * inside case statement pattern lists. A `case statement pattern list' - * is: + * inside case statement pattern lists. A `case statement pattern list' is: + * * everything between the `in' in a `case word in' and the next ')' * or `esac' * everything between a `;;' and the next `)' or `esac' */ -static int in_case_pattern_list = 0; #if defined (ALIAS) + +#define END_OF_ALIAS 0 + /* * Pseudo-global variables used in implementing token-wise alias expansion. */ -static int expand_next_token = 0; - /* - * Pushing and popping strings. This works together with shell_getc to + * Pushing and popping strings. This works together with shell_getc to * implement alias expansion on a per-token basis. */ @@ -2304,13 +2388,12 @@ typedef struct string_saver { struct string_saver *next; int expand_alias; /* Value to set expand_alias to when string is popped. */ char *saved_line; + alias_t *expander; /* alias that caused this line to be pushed. */ int saved_line_size, saved_line_index, saved_line_terminator; } STRING_SAVER; STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL; -static void save_expansion (); - /* * Push the current shell_input_line onto a stack of such lines and make S * the current input. Used when expanding aliases. EXPAND is used to set @@ -2320,10 +2403,10 @@ static void save_expansion (); * into S; it is saved and used to prevent infinite recursive expansion. */ static void -push_string (s, expand, token) +push_string (s, expand, ap) char *s; int expand; - char *token; + alias_t *ap; { STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER)); @@ -2332,16 +2415,17 @@ push_string (s, expand, token) temp->saved_line_size = shell_input_line_size; temp->saved_line_index = shell_input_line_index; temp->saved_line_terminator = shell_input_line_terminator; + temp->expander = ap; temp->next = pushed_string_list; pushed_string_list = temp; - save_expansion (token); + ap->flags |= AL_BEINGEXPANDED; shell_input_line = s; shell_input_line_size = strlen (s); shell_input_line_index = 0; shell_input_line_terminator = '\0'; - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; } /* @@ -2360,102 +2444,38 @@ pop_string () shell_input_line_index = pushed_string_list->saved_line_index; shell_input_line_size = pushed_string_list->saved_line_size; shell_input_line_terminator = pushed_string_list->saved_line_terminator; - expand_next_token = pushed_string_list->expand_alias; + + if (pushed_string_list->expand_alias) + parser_state |= PST_ALEXPNEXT; + else + parser_state &= ~PST_ALEXPNEXT; t = pushed_string_list; pushed_string_list = pushed_string_list->next; - free((char *)t); + + t->expander->flags &= ~AL_BEINGEXPANDED; + + free ((char *)t); } static void free_string_list () { - register STRING_SAVER *t = pushed_string_list, *t1; + register STRING_SAVER *t, *t1; - while (t) + for (t = pushed_string_list; t; ) { t1 = t->next; FREE (t->saved_line); + t->expander->flags &= ~AL_BEINGEXPANDED; free ((char *)t); t = t1; } pushed_string_list = (STRING_SAVER *)NULL; } -/* This is a stack to save the values of all tokens for which alias - expansion has been performed during the current call to read_token (). - It is used to prevent alias expansion loops: - - alias foo=bar - alias bar=baz - alias baz=foo - - Ideally this would be taken care of by push and pop string, but because - of when strings are popped the stack will not contain the correct - strings to test against. (The popping is done in shell_getc, so that when - the current string is exhausted, shell_getc can simply pop that string off - the stack, restore the previous string, and continue with the character - following the token whose expansion was originally pushed on the stack.) - - What we really want is a record of all tokens that have been expanded for - aliases during the `current' call to read_token(). This does that, at the - cost of being somewhat special-purpose (OK, OK vile and unclean). */ - -typedef struct _exp_saver { - struct _exp_saver *next; - char *saved_token; -} EXPANSION_SAVER; - -EXPANSION_SAVER *expanded_token_stack = (EXPANSION_SAVER *)NULL; - -static void -save_expansion (s) - char *s; -{ - EXPANSION_SAVER *t; - - t = (EXPANSION_SAVER *) xmalloc (sizeof (EXPANSION_SAVER)); - t->saved_token = savestring (s); - t->next = expanded_token_stack; - expanded_token_stack = t; -} - -/* Return 1 if TOKEN has already been expanded in the current `stack' of - expansions. If it has been expanded already, it will appear as the value - of saved_token for some entry in the stack of expansions created for the - current token being expanded. */ -static int -token_has_been_expanded (token) - char *token; -{ - register EXPANSION_SAVER *t = expanded_token_stack; - - while (t) - { - if (STREQ (token, t->saved_token)) - return (1); - t = t->next; - } - return (0); -} - -static void -free_expansion_stack () -{ - register EXPANSION_SAVER *t = expanded_token_stack, *t1; - - while (t) - { - t1 = t->next; - free (t->saved_token); - free (t); - t = t1; - } - expanded_token_stack = (EXPANSION_SAVER *)NULL; -} - #endif /* ALIAS */ - + /* Return a line of text, taken from wherever yylex () reads input. If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE is non-zero, we remove unquoted \<newline> pairs. This is used by @@ -2468,6 +2488,13 @@ read_a_line (remove_quoted_newline) static int buffer_size = 0; int indx = 0, c, peekc, pass_next; +#if defined (READLINE) + if (interactive && bash_input.type != st_string && no_line_editing) +#else + if (interactive && bash_input.type != st_string) +#endif + print_prompt (); + pass_next = 0; while (1) { @@ -2482,17 +2509,15 @@ read_a_line (remove_quoted_newline) /* If there is no more input, then we return NULL. */ if (c == EOF) { + if (interactive && bash_input.type == st_stream) + clearerr (stdin); if (indx == 0) return ((char *)NULL); c = '\n'; } /* `+2' in case the final character in the buffer is a newline. */ - if (indx + 2 > buffer_size) - if (!buffer_size) - line_buffer = xmalloc (buffer_size = 128); - else - line_buffer = xrealloc (line_buffer, buffer_size += 128); + RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a here document with an unquoted delimiter. In this case, @@ -2542,7 +2567,6 @@ read_secondary_line (remove_quoted_newline) return (read_a_line (remove_quoted_newline)); } - /* **************************************************************** */ /* */ /* YYLEX () */ @@ -2569,21 +2593,56 @@ STRING_INT_ALIST word_token_alist[] = { { "done", DONE }, { "in", IN }, { "function", FUNCTION }, +#if defined (COMMAND_TIMING) + { "time", TIME }, +#endif { "{", '{' }, { "}", '}' }, { "!", BANG }, { (char *)NULL, 0} }; +/* These are used by read_token_word, but appear up here so that shell_getc + can use them to decide when to add otherwise blank lines to the history. */ + +/* The primary delimiter stack. */ +struct dstack dstack = { (char *)NULL, 0, 0 }; + +/* A temporary delimiter stack to be used when decoding prompt strings. + This is needed because command substitutions in prompt strings (e.g., PS2) + can screw up the parser's quoting state. */ +static struct dstack temp_dstack = { (char *)NULL, 0, 0 }; + +/* Macro for accessing the top delimiter on the stack. Returns the + delimiter or zero if none. */ +#define current_delimiter(ds) \ + (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0) + +#define push_delimiter(ds, character) \ + do \ + { \ + if (ds.delimiter_depth + 2 > ds.delimiter_space) \ + ds.delimiters = xrealloc \ + (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ + ds.delimiters[ds.delimiter_depth] = character; \ + ds.delimiter_depth++; \ + } \ + while (0) + +#define pop_delimiter(ds) ds.delimiter_depth-- + /* Return the next shell input character. This always reads characters from shell_input_line; when that line is exhausted, it is time to read the next line. This is called by read_token when the shell is processing normal command input. */ + static int shell_getc (remove_quoted_newline) int remove_quoted_newline; { + register int i; int c; + static int mustpop = 0; QUIT; @@ -2598,10 +2657,6 @@ shell_getc (remove_quoted_newline) if (!shell_input_line || !shell_input_line[shell_input_line_index]) #endif /* !ALIAS */ { - register int i, l; - - restart_read_next_line: - line_number++; restart_read: @@ -2637,16 +2692,14 @@ shell_getc (remove_quoted_newline) /* Allow immediate exit if interrupted during input. */ QUIT; - if (i + 2 > shell_input_line_size) - shell_input_line = - xrealloc (shell_input_line, shell_input_line_size += 256); + RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); if (c == EOF) { if (bash_input.type == st_stream) clearerr (stdin); - if (!i) + if (i == 0) shell_input_line_terminator = EOF; shell_input_line[i] = '\0'; @@ -2666,11 +2719,23 @@ shell_getc (remove_quoted_newline) shell_input_line_len = i; /* == strlen (shell_input_line) */ #if defined (HISTORY) - if (interactive && shell_input_line && shell_input_line[0]) + if (remember_on_history && shell_input_line && shell_input_line[0]) { char *expansions; - +# if defined (BANG_HISTORY) + int old_hist; + + /* If the current delimiter is a single quote, we should not be + performing history expansion, even if we're on a different + line from the original single quote. */ + old_hist = history_expansion_inhibited; + if (current_delimiter (dstack) == '\'') + history_expansion_inhibited = 1; +# endif expansions = pre_process_line (shell_input_line, 1, 1); +# if defined (BANG_HISTORY) + history_expansion_inhibited = old_hist; +# endif free (shell_input_line); shell_input_line = expansions; @@ -2684,6 +2749,18 @@ shell_getc (remove_quoted_newline) true allocated size of shell_input_line anymore. */ shell_input_line_size = shell_input_line_len; } + /* XXX - this is grotesque */ + else if (remember_on_history && shell_input_line && + shell_input_line[0] == '\0' && + current_command_line_count > 1 && current_delimiter (dstack)) + { + /* We know shell_input_line[0] == 0 and we're reading some sort of + quoted string. This means we've got a line consisting of only + a newline in a quoted string. We want to make sure this line + gets added to the history. */ + maybe_add_history (shell_input_line); + } + #endif /* HISTORY */ if (shell_input_line) @@ -2706,17 +2783,15 @@ shell_getc (remove_quoted_newline) not already end in an EOF character. */ if (shell_input_line_terminator != EOF) { - l = shell_input_line_len; /* was a call to strlen */ - - if (l + 3 > shell_input_line_size) + if (shell_input_line_len + 3 > shell_input_line_size) shell_input_line = xrealloc (shell_input_line, 1 + (shell_input_line_size += 2)); - shell_input_line[l] = '\n'; - shell_input_line[l + 1] = '\0'; + shell_input_line[shell_input_line_len] = '\n'; + shell_input_line[shell_input_line_len + 1] = '\0'; } } - + c = shell_input_line[shell_input_line_index]; if (c) @@ -2726,7 +2801,8 @@ shell_getc (remove_quoted_newline) shell_input_line[shell_input_line_index] == '\n') { prompt_again (); - goto restart_read_next_line; + line_number++; + goto restart_read; } #if defined (ALIAS) @@ -2737,20 +2813,24 @@ shell_getc (remove_quoted_newline) to. */ if (!c && (pushed_string_list != (STRING_SAVER *)NULL)) { - pop_string (); - c = shell_input_line[shell_input_line_index]; - if (c) - shell_input_line_index++; + if (mustpop) + { + pop_string (); + c = shell_input_line[shell_input_line_index]; + if (c) + shell_input_line_index++; + mustpop--; + } + else + { + mustpop++; + c = ' '; + } } #endif /* ALIAS */ if (!c && shell_input_line_terminator == EOF) - { - if (shell_input_line_index != 0) - return ('\n'); - else - return (EOF); - } + return ((shell_input_line_index != 0) ? '\n' : EOF); return ((unsigned char)c); } @@ -2764,7 +2844,15 @@ shell_ungetc (c) shell_input_line[--shell_input_line_index] = c; } -/* Discard input until CHARACTER is seen. */ +static void +shell_ungetchar () +{ + if (shell_input_line && shell_input_line_index) + shell_input_line_index--; +} + +/* Discard input until CHARACTER is seen, then push that character back + onto the input stream. */ static void discard_until (character) int character; @@ -2777,13 +2865,6 @@ discard_until (character) if (c != EOF) shell_ungetc (c); } - -/* Place to remember the token. We try to keep the buffer - at a reasonable size, but it can grow. */ -static char *token = (char *)NULL; - -/* Current size of the token buffer. */ -static int token_buffer_size = 0; void execute_prompt_command (command) @@ -2811,10 +2892,17 @@ execute_prompt_command (command) bind_variable ("_", last_lastarg); FREE (last_lastarg); - if (token_to_read == '\n') + if (token_to_read == '\n') /* reset_parser was called */ token_to_read = 0; } +/* Place to remember the token. We try to keep the buffer + at a reasonable size, but it can grow. */ +static char *token = (char *)NULL; + +/* Current size of the token buffer. */ +static int token_buffer_size; + /* Command to read_token () explaining what we want it to do. */ #define READ 0 #define RESET 1 @@ -2823,10 +2911,10 @@ execute_prompt_command (command) /* Function for yyparse to call. yylex keeps track of the last two tokens read, and calls read_token. */ - +static int yylex () { - if (interactive && (!current_token || current_token == '\n')) + if (interactive && (current_token == 0 || current_token == '\n')) { /* Before we print a prompt, we might have to check mailboxes. We do this only if it is time to do so. Notice that only here @@ -2844,35 +2932,16 @@ yylex () prompt_again (); } + two_tokens_ago = token_before_that; token_before_that = last_read_token; last_read_token = current_token; current_token = read_token (READ); return (current_token); } -/* Called from shell.c when Control-C is typed at top level. Or - by the error rule at top level. */ -reset_parser () -{ - read_token (RESET); -} - /* When non-zero, we have read the required tokens which allow ESAC to be the next one read. */ -static int allow_esac_as_next = 0; - -/* When non-zero, accept single '{' as a token itself. */ -static int allow_open_brace = 0; - -/* DELIMITERS is a stack of the nested delimiters that we have - encountered so far. */ -static char *delimiters = (char *)NULL; - -/* Offset into the stack of delimiters. */ -int delimiter_depth = 0; - -/* How many slots are allocated to DELIMITERS. */ -static int delimiter_space = 0; +static int esacs_needed_count; void gather_here_documents () @@ -2885,32 +2954,16 @@ gather_here_documents () } } -/* Macro for accessing the top delimiter on the stack. Returns the - delimiter or zero if none. */ -#define current_delimiter() \ - (delimiter_depth ? delimiters[delimiter_depth - 1] : 0) - -#define push_delimiter(character) \ - do \ - { \ - if (delimiter_depth + 2 > delimiter_space) \ - delimiters = xrealloc \ - (delimiters, (delimiter_space += 10) * sizeof (char)); \ - delimiters[delimiter_depth] = character; \ - delimiter_depth++; \ - } \ - while (0) - /* When non-zero, an open-brace used to create a group is awaiting a close brace partner. */ -static int open_brace_awaiting_satisfaction = 0; +static int open_brace_count; #define command_token_position(token) \ (((token) == ASSIGNMENT_WORD) || \ ((token) != SEMI_SEMI && reserved_word_acceptable(token))) #define assignment_acceptable(token) command_token_position(token) && \ - (in_case_pattern_list == 0) + ((parser_state & PST_CASEPAT) == 0) /* Check to see if TOKEN is a reserved word and return the token value if it is. */ @@ -2923,101 +2976,217 @@ static int open_brace_awaiting_satisfaction = 0; for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \ if (STREQ (tok, word_token_alist[i].word)) \ { \ - if (in_case_pattern_list && (word_token_alist[i].token != ESAC)) \ + if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ break; \ -\ if (word_token_alist[i].token == ESAC) \ - in_case_pattern_list = 0; \ -\ - if (word_token_alist[i].token == '{') \ - open_brace_awaiting_satisfaction++; \ -\ - if (word_token_alist[i].token == '}' && open_brace_awaiting_satisfaction) \ - open_brace_awaiting_satisfaction--; \ -\ + parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ + else if (word_token_alist[i].token == CASE) \ + parser_state |= PST_CASESTMT; \ + else if (word_token_alist[i].token == '{') \ + open_brace_count++; \ + else if (word_token_alist[i].token == '}' && open_brace_count) \ + open_brace_count--; \ return (word_token_alist[i].token); \ } \ } \ } while (0) -/* Read the next token. Command can be READ (normal operation) or - RESET (to normalize state). */ +#if defined (ALIAS) + + /* OK, we have a token. Let's try to alias expand it, if (and only if) + it's eligible. + + It is eligible for expansion if the shell is in interactive mode, and + the token is unquoted and the last token read was a command + separator (or expand_next_token is set), and we are currently + processing an alias (pushed_string_list is non-empty) and this + token is not the same as the current or any previously + processed alias. + + Special cases that disqualify: + In a pattern list in a case statement (parser_state & PST_CASEPAT). */ static int -read_token (command) - int command; +alias_expand_token (token) + char *token; { - int character; /* Current character. */ - int peek_char; /* Temporary look-ahead character. */ - int result; /* The thing to return. */ - WORD_DESC *the_word; /* The value for YYLVAL when a WORD is read. */ + char *expanded; + alias_t *ap; - if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) && + (parser_state & PST_CASEPAT) == 0) { - FREE (token); - token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + ap = find_alias (token); + + /* Currently expanding this token. */ + if (ap && (ap->flags & AL_BEINGEXPANDED)) + return (NO_EXPANSION); + + expanded = ap ? savestring (ap->value) : (char *)NULL; + if (expanded) + { + push_string (expanded, ap->flags & AL_EXPANDNEXT, ap); + return (RE_READ_TOKEN); + } + else + /* This is an eligible token that does not have an expansion. */ + return (NO_EXPANSION); } + return (NO_EXPANSION); +} +#endif /* ALIAS */ - if (command == RESET) +/* Handle special cases of token recognition: + IN is recognized if the last token was WORD and the token + before that was FOR or CASE or SELECT. + + DO is recognized if the last token was WORD and the token + before that was FOR or SELECT. + + ESAC is recognized if the last token caused `esacs_needed_count' + to be set + + `{' is recognized if the last token as WORD and the token + before that was FUNCTION. + + `}' is recognized if there is an unclosed `{' prsent. +*/ + +static int +special_case_tokens (token) + char *token; +{ + if ((last_read_token == WORD) && +#if defined (SELECT_COMMAND) + ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && +#else + ((token_before_that == FOR) || (token_before_that == CASE)) && +#endif + (token[0] == 'i' && token[1] == 'n' && token[2] == 0)) { - delimiter_depth = 0; /* No delimiters found so far. */ - open_brace_awaiting_satisfaction = 0; - in_case_pattern_list = 0; + if (token_before_that == CASE) + { + parser_state |= PST_CASEPAT; + esacs_needed_count++; + } + return (IN); + } -#if defined (ALIAS) - if (pushed_string_list) + if (last_read_token == WORD && +#if defined (SELECT_COMMAND) + (token_before_that == FOR || token_before_that == SELECT) && +#else + (token_before_that == FOR) && +#endif + (token[0] == 'd' && token[1] == 'o' && token[2] == '\0')) + return (DO); + + /* Ditto for ESAC in the CASE case. + Specifically, this handles "case word in esac", which is a legal + construct, certainly because someone will pass an empty arg to the + case construct, and we don't want it to barf. Of course, we should + insist that the case construct has at least one pattern in it, but + the designers disagree. */ + if (esacs_needed_count) + { + esacs_needed_count--; + if (STREQ (token, "esac")) { - free_string_list (); - pushed_string_list = (STRING_SAVER *)NULL; + parser_state &= ~PST_CASEPAT; + return (ESAC); } + } - if (expanded_token_stack) + /* The start of a shell function definition. */ + if (parser_state & PST_ALLOWOPNBRC) + { + parser_state &= ~PST_ALLOWOPNBRC; + if (token[0] == '{' && token[1] == '\0') /* } */ { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; + open_brace_count++; + function_bstart = line_number; + return ('{'); /* } */ } + } + + if (open_brace_count && reserved_word_acceptable (last_read_token) && token[0] == '}' && !token[1]) + { + open_brace_count--; /* { */ + return ('}'); + } + + /* Handle -p after `time'. */ + if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2]) + return (TIMEOPT); + + return (-1); +} + +/* Called from shell.c when Control-C is typed at top level. Or + by the error rule at top level. */ +void +reset_parser () +{ + dstack.delimiter_depth = 0; /* No delimiters found so far. */ + open_brace_count = 0; + + parser_state = 0; - expand_next_token = 0; +#if defined (ALIAS) + if (pushed_string_list) + { + free_string_list (); + pushed_string_list = (STRING_SAVER *)NULL; + } #endif /* ALIAS */ - if (shell_input_line) - { - free (shell_input_line); - shell_input_line = (char *)NULL; - shell_input_line_size = shell_input_line_index = 0; - } - last_read_token = '\n'; - token_to_read = '\n'; + if (shell_input_line) + { + free (shell_input_line); + shell_input_line = (char *)NULL; + shell_input_line_size = shell_input_line_index = 0; + } + + FREE (word_desc_to_read); + word_desc_to_read = (WORD_DESC *)NULL; + + last_read_token = '\n'; + token_to_read = '\n'; +} + +/* Read the next token. Command can be READ (normal operation) or + RESET (to normalize state). */ +static int +read_token (command) + int command; +{ + int character; /* Current character. */ + int peek_char; /* Temporary look-ahead character. */ + int result; /* The thing to return. */ + + if (command == RESET) + { + reset_parser (); return ('\n'); } if (token_to_read) { - int rt = token_to_read; + result = token_to_read; + if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD) + yylval.word = word_desc_to_read; token_to_read = 0; - return (rt); + return (result); } #if defined (ALIAS) - /* If we hit read_token () and there are no saved strings on the - pushed_string_list, then we are no longer currently expanding a - token. This can't be done in pop_stream, because pop_stream - may pop the stream before the current token has finished being - completely expanded (consider what happens when we alias foo to foo, - and then try to expand it). */ - if (!pushed_string_list && expanded_token_stack) - { - free_expansion_stack (); - expanded_token_stack = (EXPANSION_SAVER *)NULL; - } - /* This is a place to jump back to once we have successfully expanded a token with an alias and pushed the string with push_string () */ re_read_token: - #endif /* ALIAS */ /* Read a single word from input. Start by skipping blanks. */ - while ((character = shell_getc (1)) != EOF && whitespace (character)); + while ((character = shell_getc (1)) != EOF && whitespace (character)) + ; if (character == EOF) { @@ -3030,17 +3199,7 @@ read_token (command) /* A comment. Discard until EOL or EOF, and then return a newline. */ discard_until ('\n'); shell_getc (0); - - /* If we're about to return an unquoted newline, we can go and collect - the text of any pending here documents. */ - if (need_here_doc) - gather_here_documents (); - -#if defined (ALIAS) - expand_next_token = 0; -#endif /* ALIAS */ - - return ('\n'); + character = '\n'; /* this will take the next if statement and return. */ } if (character == '\n') @@ -3051,31 +3210,30 @@ read_token (command) gather_here_documents (); #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (character); } - if (member (character, "()<>;&|")) + /* Shell meta-characters. */ + if (shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) { #if defined (ALIAS) /* Turn off alias tokenization iff this character sequence would not leave us ready to read a command. */ if (character == '<' || character == '>') - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ - /* Please note that the shell does not allow whitespace to - appear in between tokens which are character pairs, such as - "<<" or ">>". I believe this is the correct behaviour. */ - if (character == (peek_char = shell_getc (1))) + peek_char = shell_getc (1); + if (character == peek_char) { switch (character) { + case '<': /* If '<' then we could be at "<<" or at "<<-". We have to look ahead one more character. */ - case '<': peek_char = shell_getc (1); if (peek_char == '-') return (LESS_LESS_MINUS); @@ -3089,9 +3247,9 @@ read_token (command) return (GREATER_GREATER); case ';': - in_case_pattern_list = 1; + parser_state |= PST_CASEPAT; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ return (SEMI_SEMI); @@ -3100,526 +3258,637 @@ read_token (command) case '|': return (OR_OR); - } - } - else - { - if (peek_char == '&') - { - switch (character) + +#if defined (DPAREN_ARITHMETIC) + case '(': /* ) */ + if (reserved_word_acceptable (last_read_token)) { - case '<': return (LESS_AND); - case '>': return (GREATER_AND); + parser_state |= PST_DBLPAREN; + yylval.word = make_word ("let"); + return (WORD); } + break; +#endif } - if (character == '<' && peek_char == '>') - return (LESS_GREATER); - if (character == '>' && peek_char == '|') - return (GREATER_BAR); - if (peek_char == '>' && character == '&') - return (AND_GREATER); } + else if (character == '<' && peek_char == '&') + return (LESS_AND); + else if (character == '>' && peek_char == '&') + return (GREATER_AND); + else if (character == '<' && peek_char == '>') + return (LESS_GREATER); + else if (character == '>' && peek_char == '|') + return (GREATER_BAR); + else if (peek_char == '>' && character == '&') + return (AND_GREATER); + shell_ungetc (peek_char); /* If we look like we are reading the start of a function definition, then let the reader know about it so that we will do the right thing with `{'. */ - if (character == ')' && - last_read_token == '(' && token_before_that == WORD) + if (character == ')' && last_read_token == '(' && token_before_that == WORD) { - allow_open_brace = 1; + parser_state |= PST_ALLOWOPNBRC; #if defined (ALIAS) - expand_next_token = 0; + parser_state &= ~PST_ALEXPNEXT; #endif /* ALIAS */ + function_dstart = line_number; } - if (in_case_pattern_list && (character == ')')) - in_case_pattern_list = 0; + /* case pattern lists may be preceded by an optional left paren. If + we're not trying to parse a case pattern list, the left paren + indicates a subshell. */ + if (character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */ + parser_state |= PST_SUBSHELL; + /*(*/ + else if ((parser_state & PST_CASEPAT) && character == ')') + parser_state &= ~PST_CASEPAT; + /*(*/ + else if ((parser_state & PST_SUBSHELL) && character == ')') + parser_state &= ~PST_SUBSHELL; #if defined (PROCESS_SUBSTITUTION) /* Check for the constructs which introduce process substitution. Shells running in `posix mode' don't do process substitution. */ if (posixly_correct || - (((character == '>' || character == '<') && peek_char == '(') == 0)) + ((character != '>' && character != '<') || peek_char != '(')) #endif /* PROCESS_SUBSTITUTION */ return (character); } /* Hack <&- (close stdin) case. */ - if (character == '-') - { - switch (last_read_token) - { - case LESS_AND: - case GREATER_AND: - return (character); - } - } - + if (character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) + return (character); + /* Okay, if we got this far, we have to read a word. Read one, and then check it against the known ones. */ - { - /* Index into the token that we are building. */ - int token_index = 0; - - /* ALL_DIGITS becomes zero when we see a non-digit. */ - int all_digits = digit (character); + result = read_token_word (character); +#if defined (ALIAS) + if (result == RE_READ_TOKEN) + goto re_read_token; +#endif + return result; +} - /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ - int dollar_present = 0; +/* Match a $(...) or other grouping construct. This has to handle embedded + quoted strings ('', ``, "") and nested constructs. It also must handle + reprompting the user, if necessary, after reading a newline, and returning + correct error values if it reads EOF. */ +static char matched_pair_error; +static char * +parse_matched_pair (qc, open, close, lenp, flags) + int qc; /* `"' if this construct is within double quotes */ + int open, close; + int *lenp, flags; +{ + int count, ch, was_dollar; + int pass_next_character, nestlen, start_lineno; + char *ret, *nestret; + int retind, retsize; - /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ - int quoted = 0; + count = 1; + pass_next_character = was_dollar = 0; - /* Non-zero means to ignore the value of the next character, and just - to add it no matter what. */ - int pass_next_character = 0; + ret = xmalloc (retsize = 64); + retind = 0; - /* Non-zero means parsing a dollar-paren construct. It is the count of - un-quoted closes we need to see. */ - int dollar_paren_level = 0; + start_lineno = line_number; + while (count) + { + ch = shell_getc (qc != '\'' && pass_next_character == 0); + if (ch == EOF) + { + free (ret); + parser_error (start_lineno, "unexpected EOF while looking for matching `%c'", close); + EOF_Reached = 1; /* XXX */ + return (&matched_pair_error); + } - /* Non-zero means parsing a dollar-bracket construct ($[...]). It is - the count of un-quoted `]' characters we need to see. */ - int dollar_bracket_level = 0; + /* Possible reprompting. */ + if (ch == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - /* Non-zero means parsing a `${' construct. It is the count of - un-quoted `}' we need to see. */ - int dollar_brace_level = 0; + if (pass_next_character) /* last char was backslash */ + { + pass_next_character = 0; + if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */ + { + if (retind > 0) retind--; /* swallow previously-added backslash */ + continue; + } - /* A level variable for parsing '${ ... }' constructs inside of double - quotes. */ - int delimited_brace_level = 0; + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + if (ch == CTLESC || ch == CTLNUL) + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == CTLESC || ch == CTLNUL) /* special shell escapes */ + { + RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64); + ret[retind++] = CTLESC; + ret[retind++] = ch; + continue; + } + else if (ch == close) /* ending delimiter */ + count--; + else if (ch == open) /* nested begin */ + count++; - /* A boolean variable denoting whether or not we are currently parsing - a double-quoted string embedded in a $( ) or ${ } construct. */ - int embedded_quoted_string = 0; + /* Add this character. */ + RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); + ret[retind++] = ch; - /* Another level variable. This one is for dollar_parens inside of - double-quotes. */ - int delimited_paren_level = 0; + if (open == '\'') /* '' inside grouping construct */ + continue; - /* The current delimiting character. */ - int cd; + if (ch == '\\') /* backslashes */ + pass_next_character++; - for (;;) - { - if (character == EOF) - goto got_token; + if (open != close) /* a grouping construct */ + { + if (shellquote (ch)) + { + /* '', ``, or "" inside $(...) or other grouping construct. */ + push_delimiter (dstack, ch); + nestret = parse_matched_pair (ch, ch, ch, &nestlen, 0); + pop_delimiter (dstack); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + } + /* Parse an old-style command substitution within double quotes as a + single word. */ + /* XXX - sh and ksh93 don't do this - XXX */ + else if (open == '"' && ch == '`') + { + nestret = parse_matched_pair (0, '`', '`', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + else if (was_dollar && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ + /* check for $(), $[], or ${} inside quoted string. */ + { + if (open == ch) /* undo previous increment */ + count--; + if (ch == '(') /* ) */ + nestret = parse_matched_pair (0, '(', ')', &nestlen, 0); + else if (ch == '{') /* } */ + nestret = parse_matched_pair (0, '{', '}', &nestlen, 0); + else if (ch == '[') /* ] */ + nestret = parse_matched_pair (0, '[', ']', &nestlen, 0); + if (nestret == &matched_pair_error) + { + free (ret); + return &matched_pair_error; + } + if (nestlen) + { + RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); + strcpy (ret + retind, nestret); + retind += nestlen; + } + FREE (nestret); + } + was_dollar = (ch == '$'); + } - if (pass_next_character) - { - pass_next_character = 0; - goto got_character; - } + ret[retind] = '\0'; + if (lenp) + *lenp = retind; + return ret; +} - cd = current_delimiter (); +static int +read_token_word (character) + int character; +{ + /* The value for YYLVAL when a WORD is read. */ + WORD_DESC *the_word; - if (cd && character == '\\' && cd != '\'') - { - peek_char = shell_getc (0); - if (peek_char != '\\') - shell_ungetc (peek_char); - else - { - token[token_index++] = character; - goto got_character; - } - } - - /* Handle backslashes. Quote lots of things when not inside of - double-quotes, quote some things inside of double-quotes. */ - - if (character == '\\' && (!delimiter_depth || cd != '\'')) - { - peek_char = shell_getc (0); - - /* Backslash-newline is ignored in all cases excepting - when quoted with single quotes. */ - if (peek_char == '\n') - { - character = '\n'; - goto next_character; - } - else - { - shell_ungetc (peek_char); + /* Index into the token that we are building. */ + int token_index; - /* If the next character is to be quoted, do it now. */ - if (!cd || cd == '`' || - (cd == '"' && member (peek_char, slashify_in_quotes))) - { - pass_next_character++; - quoted = 1; - goto got_character; - } - } - } - - /* This is a hack, in its present form. If a backquote substitution - appears within double quotes, everything within the backquotes - should be read as part of a single word. Jesus. Now I see why - Korn introduced the $() form. */ - if (delimiter_depth && (cd == '"') && (character == '`')) - { - push_delimiter (character); - goto got_character; - } - - cd = current_delimiter (); /* XXX - may not need */ - if (delimiter_depth) - { - if (character == cd) - { - /* If we see a double quote while parsing a double-quoted - $( ) or ${ }, and we have not seen ) or }, respectively, - note that we are in the middle of reading an embedded - quoted string. */ - if ((delimited_paren_level || delimited_brace_level) && - (character == '"')) - { - embedded_quoted_string = !embedded_quoted_string; - goto got_character; - } - - delimiter_depth--; - goto got_character; - } - } + /* ALL_DIGITS becomes zero when we see a non-digit. */ + int all_digits; - if (cd != '\'') - { -#if defined (PROCESS_SUBSTITUTION) - if (character == '$' || character == '<' || character == '>') -#else - if (character == '$') -#endif /* !PROCESS_SUBSTITUTION */ - { - /* If we're in the middle of parsing a $( ) or ${ } - construct with an embedded quoted string, don't - bother looking at this character any further. */ - if (embedded_quoted_string) - goto got_character; - - peek_char = shell_getc (1); - shell_ungetc (peek_char); - if (peek_char == '(') - { - if (!delimiter_depth) - dollar_paren_level++; - else - delimited_paren_level++; + /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ + int dollar_present; - pass_next_character++; - goto got_character; - } - else if (peek_char == '[' && character == '$') - { - if (!delimiter_depth) - dollar_bracket_level++; + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ + int quoted; - pass_next_character++; - goto got_character; - } - /* This handles ${...} constructs. */ - else if (peek_char == '{' && character == '$') - { - if (!delimiter_depth) - dollar_brace_level++; - else - delimited_brace_level++; + /* Non-zero means to ignore the value of the next character, and just + to add it no matter what. */ + int pass_next_character; - pass_next_character++; - goto got_character; - } - } + /* The current delimiting character. */ + int cd; + int result, peek_char; + char *ttok, *ttrans; + int ttoklen, ttranslen; - /* If we are parsing a $() or $[] construct, we need to balance - parens and brackets inside the construct. This whole function - could use a rewrite. */ - if (character == '(' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level++; + if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE) + { + FREE (token); + token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE); + } - if (!delimiter_depth && dollar_paren_level) - dollar_paren_level++; - } + token_index = 0; + all_digits = digit (character); + dollar_present = quoted = pass_next_character = 0; - if (character == '[') - { - if (!delimiter_depth && dollar_bracket_level) - dollar_bracket_level++; - } + for (;;) + { + if (character == EOF) + goto got_token; - if (character == '{' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level++; + if (pass_next_character) + { + pass_next_character = 0; + goto got_character; + } - if (!delimiter_depth && dollar_brace_level) - dollar_brace_level++; - } + cd = current_delimiter (dstack); - /* This code needs to take into account whether we are inside a - case statement pattern list, and whether this paren is supposed - to terminate it (hey, it could happen). It's not as simple - as just using in_case_pattern_list, because we're not parsing - anything while we're reading a $( ) construct. Maybe we - should move that whole mess into the yacc parser. */ - if (character == ')' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_paren_level) - delimited_paren_level--; + /* Handle backslashes. Quote lots of things when not inside of + double-quotes, quote some things inside of double-quotes. */ + if (character == '\\') + { + peek_char = shell_getc (0); - if (!delimiter_depth && dollar_paren_level) - { - dollar_paren_level--; - goto got_character; - } - } + /* Backslash-newline is ignored in all cases except + when quoted with single quotes. */ + if (peek_char == '\n') + { + character = '\n'; + goto next_character; + } + else + { + shell_ungetc (peek_char); - if (character == ']') - { - if (!delimiter_depth && dollar_bracket_level) - { - dollar_bracket_level--; - goto got_character; - } - } + /* If the next character is to be quoted, note it now. */ + if (cd == 0 || cd == '`' || + (cd == '"' && member (peek_char, slashify_in_quotes))) + pass_next_character++; - if (character == '}' && !embedded_quoted_string) - { - if (delimiter_depth && delimited_brace_level) - delimited_brace_level--; + quoted = 1; + goto got_character; + } + } - if (!delimiter_depth && dollar_brace_level) - { - dollar_brace_level--; - goto got_character; - } - } - } +#if defined (DPAREN_ARITHMETIC) + /* Parse a ksh-style ((...)) expression. */ + if (parser_state & PST_DBLPAREN) + { + int exp_lineno; - if (!dollar_paren_level && !dollar_bracket_level && - !dollar_brace_level && !delimiter_depth && - member (character, " \t\n;&()|<>")) - { + /* If we've already consumed a right paren that should be part of + the expression, push it back so the paren matching code won't + return prematurely. */ + if (character == '(') /* ) */ shell_ungetc (character); - goto got_token; - } - - if (!delimiter_depth) - { - if (character == '"' || character == '`' || character == '\'') - { - push_delimiter (character); - - quoted = 1; - goto got_character; - } - } - - if (all_digits) - all_digits = digit (character); - if (character == '$') - dollar_present = 1; + exp_lineno = line_number; + ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0); + parser_state &= ~PST_DBLPAREN; + if (ttok == &matched_pair_error) + return -1; + /* Check that the next character is the closing right paren. If + not, this is a syntax error. ( */ + if (shell_getc (0) != ')') + { + FREE (ttok); /* ( */ + parser_error (exp_lineno, "missing closing `)' for arithmetic expression"); + return -1; + } + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = '"'; + if (character != '(') /* ) */ + token[token_index++] = character; + strncpy (token + token_index, ttok, ttoklen - 1); + token_index += ttoklen - 1; + token[token_index++] = '"'; + FREE (ttok); + dollar_present = all_digits = 0; + quoted = 1; + goto got_token; + } +#endif /* DPAREN_ARITHMETIC */ - got_character: + /* Parse a matched pair of quote characters. */ + if (shellquote (character)) + { + push_delimiter (dstack, character); + ttok = parse_matched_pair (character, character, character, &ttoklen, 0); + pop_delimiter (dstack); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + strcpy (token + token_index, ttok); + token_index += ttoklen; + all_digits = 0; + quoted = 1; + dollar_present |= (character == '"' && strchr (ttok, '$') != 0); + FREE (ttok); + goto next_character; + } - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; + /* If the delimiter character is not single quote, parse some of + the shell expansions that must be read as a single word. */ +#if defined (PROCESS_SUBSTITUTION) + if (character == '$' || character == '<' || character == '>') +#else + if (character == '$') +#endif /* !PROCESS_SUBSTITUTION */ + { + peek_char = shell_getc (1); + /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */ + if (peek_char == '(' || + ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */ + { + if (peek_char == '{') /* } */ + ttok = parse_matched_pair (cd, '{', '}', &ttoklen, 0); + else if (peek_char == '(') /* ) */ + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + else + ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + dollar_present = 1; + all_digits = 0; + goto next_character; + } + /* This handles $'...' and $"..." new-style quoted strings. */ + else if (character == '$' && (peek_char == '\'' || peek_char == '"')) + { + ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; + if (peek_char == '\'') + ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); + else + ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen); + free (ttok); + RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = peek_char; + strcpy (token + token_index, ttrans); + token_index += ttranslen; + token[token_index++] = peek_char; + FREE (ttrans); + quoted = 1; + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } - token[token_index++] = character; +#if defined (ARRAY_VARS) + /* Identify possible compound array variable assignment. */ + else if (character == '=') + { + peek_char = shell_getc (1); + if (peek_char == '(') /* ) */ + { + ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); + if (ttok == &matched_pair_error) + return -1; /* Bail immediately. */ + RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, + token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); + token[token_index++] = character; + token[token_index++] = peek_char; + strcpy (token + token_index, ttok); + token_index += ttoklen; + FREE (ttok); + all_digits = 0; + goto next_character; + } + else + shell_ungetc (peek_char); + } +#endif - if (token_index == (token_buffer_size - 1)) - { - token_buffer_size += TOKEN_DEFAULT_GROW_SIZE; - token = xrealloc (token, token_buffer_size); - } - next_character: - if (character == '\n' && interactive && bash_input.type != st_string) - prompt_again (); + /* When not parsing a multi-character word construct, shell meta- + characters break words. */ + if (shellbreak (character)) + { + shell_ungetc (character); + goto got_token; + } - /* We want to remove quoted newlines (that is, a \<newline> pair) - unless we are within single quotes or pass_next_character is - set (the shell equivalent of literal-next). */ - character = shell_getc - ((current_delimiter () != '\'') && (!pass_next_character)); - } + got_character: - got_token: + all_digits &= digit (character); + dollar_present |= character == '$'; - token[token_index] = '\0'; - - if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) && - character == EOF) - { - char reporter = '\0'; + if (character == CTLESC || character == CTLNUL) + token[token_index++] = CTLESC; - if (!delimiter_depth) - { - if (dollar_paren_level) - reporter = ')'; - else if (dollar_bracket_level) - reporter = ']'; - } + token[token_index++] = character; - if (!reporter) - reporter = current_delimiter (); + RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, + TOKEN_DEFAULT_GROW_SIZE); - report_error ("unexpected EOF while looking for `%c'", reporter); - return (-1); - } + next_character: + if (character == '\n' && interactive && + (bash_input.type == st_stdin || bash_input.type == st_stream)) + prompt_again (); - if (all_digits) - { - /* Check to see what thing we should return. If the last_read_token - is a `<', or a `&', or the character which ended this token is - a '>' or '<', then, and ONLY then, is this input token a NUMBER. - Otherwise, it is just a word, and should be returned as such. */ - - if (character == '<' || character == '>' || - last_read_token == LESS_AND || last_read_token == GREATER_AND) - { - yylval.number = atoi (token); - return (NUMBER); - } - } + /* We want to remove quoted newlines (that is, a \<newline> pair) + unless we are within single quotes or pass_next_character is + set (the shell equivalent of literal-next). */ + cd = current_delimiter (dstack); + character = shell_getc (cd != '\'' && pass_next_character == 0); + } /* end for (;;) */ - /* Handle special case. IN is recognized if the last token - was WORD and the token before that was FOR or CASE. */ - if ((last_read_token == WORD) && -#if defined (SELECT_COMMAND) - ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) && -#else - ((token_before_that == FOR) || (token_before_that == CASE)) && -#endif - (token[0] == 'i' && token[1] == 'n' && !token[2])) - { - if (token_before_that == CASE) - { - in_case_pattern_list = 1; - allow_esac_as_next++; - } - return (IN); - } +got_token: - /* Ditto for DO in the FOR case. */ -#if defined (SELECT_COMMAND) - if ((last_read_token == WORD) && ((token_before_that == FOR) || (token_before_that == SELECT)) && -#else - if ((last_read_token == WORD) && (token_before_that == FOR) && -#endif - (token[0] == 'd' && token[1] == 'o' && !token[2])) - return (DO); - - /* Ditto for ESAC in the CASE case. - Specifically, this handles "case word in esac", which is a legal - construct, certainly because someone will pass an empty arg to the - case construct, and we don't want it to barf. Of course, we should - insist that the case construct has at least one pattern in it, but - the designers disagree. */ - if (allow_esac_as_next) - { - allow_esac_as_next--; - if (STREQ (token, "esac")) - { - in_case_pattern_list = 0; - return (ESAC); - } - } + token[token_index] = '\0'; - /* Ditto for `{' in the FUNCTION case. */ - if (allow_open_brace) + /* Check to see what thing we should return. If the last_read_token + is a `<', or a `&', or the character which ended this token is + a '>' or '<', then, and ONLY then, is this input token a NUMBER. + Otherwise, it is just a word, and should be returned as such. */ + if (all_digits && (character == '<' || character == '>' || + last_read_token == LESS_AND || + last_read_token == GREATER_AND)) { - allow_open_brace = 0; - if (token[0] == '{' && !token[1]) - { - open_brace_awaiting_satisfaction++; - return ('{'); - } + yylval.number = atoi (token); + return (NUMBER); } - if (posixly_correct) - CHECK_FOR_RESERVED_WORD (token); + /* Check for special case tokens. */ + result = special_case_tokens (token); + if (result >= 0) + return result; #if defined (ALIAS) - /* OK, we have a token. Let's try to alias expand it, if (and only if) - it's eligible. + /* Posix.2 does not allow reserved words to be aliased, so check for all + of them, including special cases, before expanding the current token + as an alias. */ + if (posixly_correct) + CHECK_FOR_RESERVED_WORD (token); + + /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting + inhibits alias expansion. */ + if (expand_aliases && quoted == 0) + { + result = alias_expand_token (token); + if (result == RE_READ_TOKEN) + return (RE_READ_TOKEN); + else if (result == NO_EXPANSION) + parser_state &= ~PST_ALEXPNEXT; + } - It is eligible for expansion if the shell is in interactive mode, and - the token is unquoted and the last token read was a command - separator (or expand_next_token is set), and we are currently - processing an alias (pushed_string_list is non-empty) and this - token is not the same as the current or any previously - processed alias. + /* If not in Posix.2 mode, check for reserved words after alias + expansion. */ + if (posixly_correct == 0) +#endif + CHECK_FOR_RESERVED_WORD (token); + + the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); + the_word->word = xmalloc (1 + token_index); + the_word->flags = 0; + strcpy (the_word->word, token); + if (dollar_present) + the_word->flags |= W_HASDOLLAR; + if (quoted) + the_word->flags |= W_QUOTED; + /* A word is an assignment if it appears at the beginning of a + simple command, or after another assignment word. This is + context-dependent, so it cannot be handled in the grammar. */ + if (assignment (token)) + { + the_word->flags |= W_ASSIGNMENT; + /* Don't perform word splitting on assignment statements. */ + if (assignment_acceptable (last_read_token)) + the_word->flags |= W_NOSPLIT; + } - Special cases that disqualify: - In a pattern list in a case statement (in_case_pattern_list). */ - if (interactive_shell && !quoted && !in_case_pattern_list && - (expand_next_token || command_token_position (last_read_token))) - { - char *alias_expand_word (), *expanded; + yylval.word = the_word; - if (expanded_token_stack && token_has_been_expanded (token)) - goto no_expansion; + result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT)) + ? ASSIGNMENT_WORD : WORD; - expanded = alias_expand_word (token); - if (expanded) - { - int len = strlen (expanded), expand_next; + if (last_read_token == FUNCTION) + { + parser_state |= PST_ALLOWOPNBRC; + function_dstart = line_number; + } - /* Erase the current token. */ - token_index = 0; + return (result); +} - expand_next = (expanded[len - 1] == ' ') || - (expanded[len - 1] == '\t'); +/* $'...' ANSI-C expand the portion of STRING between START and END and + return the result. The result cannot be longer than the input string. */ +static char * +ansiexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + char *temp, *t; + int len, tlen; - push_string (expanded, expand_next, token); - goto re_read_token; - } - else - /* This is an eligible token that does not have an expansion. */ -no_expansion: - expand_next_token = 0; - } - else - { - expand_next_token = 0; - } -#endif /* ALIAS */ + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; - if (!posixly_correct) - CHECK_FOR_RESERVED_WORD (token); + if (*temp) + { + t = ansicstr (temp, tlen, (int *)NULL); + free (temp); + if (lenp) + *lenp = strlen (t); + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } +} - /* What if we are attempting to satisfy an open-brace grouper? */ - if (open_brace_awaiting_satisfaction && token[0] == '}' && !token[1]) - { - open_brace_awaiting_satisfaction--; - return ('}'); - } +/* $"..." -- Translate the portion of STRING between START and END + according to current locale using gettext (if available) and return + the result. The caller will take care of leaving the quotes intact. + The string will be left without the leading `$' by the caller. + If translation is performed, the translated string will be double-quoted + by the caller. The length of the translated string is returned in LENP, + if non-null. */ +static char * +localeexpand (string, start, end, lenp) + char *string; + int start, end, *lenp; +{ + int len, tlen; + char *temp, *t; - the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - the_word->word = xmalloc (1 + token_index); - strcpy (the_word->word, token); - the_word->dollar_present = dollar_present; - the_word->quoted = quoted; - the_word->assignment = assignment (token); - - yylval.word = the_word; - result = WORD; - - /* A word is an assignment if it appears at the beginning of a - simple command, or after another assignment word. This is - context-dependent, so it cannot be handled in the grammar. */ - if (assignment_acceptable (last_read_token) && the_word->assignment) - result = ASSIGNMENT_WORD; - - if (last_read_token == FUNCTION) - allow_open_brace = 1; - } - return (result); + temp = xmalloc (end - start + 1); + for (tlen = 0, len = start; len < end; ) + temp[tlen++] = string[len++]; + temp[tlen] = '\0'; + + /* If we're just dumping translatable strings, don't do anything. */ + if (dump_translatable_strings) + { + printf ("\"%s\"\n", temp); + if (lenp) + *lenp = tlen; + return (temp); + } + else if (*temp) + { + t = localetrans (temp, tlen, &len); + free (temp); + if (lenp) + *lenp = len; + return (t); + } + else + { + if (lenp) + *lenp = 0; + return (temp); + } } /* Return 1 if TOKEN is a token that after being read would allow @@ -3628,15 +3897,12 @@ static int reserved_word_acceptable (token) int token; { -#if 0 - if (member (token, "\n;()|&{") || -#else if (token == '\n' || token == ';' || token == '(' || token == ')' || token == '|' || token == '&' || token == '{' || -#endif token == '}' || /* XXX */ token == AND_AND || token == BANG || + token == TIME || token == TIMEOPT || token == DO || token == ELIF || token == ELSE || @@ -3662,12 +3928,13 @@ find_reserved_word (token) char *token; { int i; - for (i = 0; word_token_alist[i].word != (char *)NULL; i++) + for (i = 0; word_token_alist[i].word; i++) if (STREQ (token, word_token_alist[i].word)) return i; return -1; } +#if 0 #if defined (READLINE) /* Called after each time readline is called. This insures that whatever the new prompt string is gets propagated to readline's local prompt @@ -3675,11 +3942,11 @@ find_reserved_word (token) static void reset_readline_prompt () { + char *temp_prompt; + if (prompt_string_pointer) { - char *temp_prompt; - - temp_prompt = *prompt_string_pointer + temp_prompt = (*prompt_string_pointer) ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -3690,11 +3957,11 @@ reset_readline_prompt () } FREE (current_readline_prompt); - current_readline_prompt = temp_prompt; } } #endif /* READLINE */ +#endif /* 0 */ #if defined (HISTORY) /* A list of tokens which can be followed by newlines, but not by @@ -3702,29 +3969,48 @@ reset_readline_prompt () newline separator for such tokens is replaced with a space. */ static int no_semi_successors[] = { '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, IN, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, + CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN, 0 }; /* If we are not within a delimited expression, try to be smart about which separators can be semi-colons and which must be - newlines. */ + newlines. Returns the string that should be added into the + history entry. */ char * history_delimiting_chars () { - if (!delimiter_depth) + register int i; + + if (dstack.delimiter_depth != 0) + return ("\n"); + + /* First, handle some special cases. */ + /*(*/ + /* If we just read `()', assume it's a function definition, and don't + add a semicolon. If the token before the `)' was not `(', and we're + not in the midst of parsing a case statement, assume it's a + parenthesized command and add the semicolon. */ + /*)(*/ + if (token_before_that == ')') { - register int i; + if (two_tokens_ago == '(') /*)*/ /* function def */ + return " "; + /* This does not work for subshells inside case statement + command lists. It's a suboptimal solution. */ + else if (parser_state & PST_CASESTMT) /* case statement pattern */ + return " "; + else + return "; "; /* (...) subshell */ + } - for (i = 0; no_semi_successors[i]; i++) - { - if (token_before_that == no_semi_successors[i]) - return (" "); - } - return ("; "); + for (i = 0; no_semi_successors[i]; i++) + { + if (token_before_that == no_semi_successors[i]) + return (" "); } - else - return ("\n"); + + return ("; "); } #endif /* HISTORY */ @@ -3744,7 +4030,7 @@ prompt_again () if (!prompt_string_pointer) prompt_string_pointer = &ps1_prompt; - temp_prompt = (*prompt_string_pointer) + temp_prompt = *prompt_string_pointer ? decode_prompt_string (*prompt_string_pointer) : (char *)NULL; @@ -3780,37 +4066,47 @@ print_prompt () /* Return a string which will be printed as a prompt. The string may contain special characters which are decoded as follows: - - \t the time - \d the date + + \a bell (ascii 07) + \e escape (ascii 033) + \d the date in Day Mon Date format + \h the hostname up to the first `.' + \H the hostname \n CRLF \s the name of the shell + \t the time in 24-hour hh:mm:ss format + \T the time in 12-hour hh:mm:ss format + \@ the time in 12-hour am/pm format + \v the version of bash (e.g., 2.00) + \V the release of bash, version + patchlevel (e.g., 2.00.0) \w the current working directory - \W the last element of PWD + \W the last element of $PWD \u your username - \h the hostname \# the command number of this command \! the history number of this command \$ a $ or a # if you are root - \<octal> character code in octal + \nnn character code nnn in octal \\ a backslash + \[ begin a sequence of non-printing chars + \] end a sequence of non-printing chars */ #define PROMPT_GROWTH 50 char * decode_prompt_string (string) char *string; { - int result_size = PROMPT_GROWTH; - int result_index = 0; - char *result; - int c; - char *temp = (char *)NULL; WORD_LIST *list; - + char *result, *t; + struct dstack save_dstack; #if defined (PROMPT_STRING_DECODE) + int result_size, result_index; + int c, n; + char *temp, octal_string[4]; + time_t the_time; - result = xmalloc (PROMPT_GROWTH); - result[0] = 0; + result = xmalloc (result_size = PROMPT_GROWTH); + result[result_index = 0] = 0; + temp = (char *)NULL; while (c = *string++) { @@ -3831,7 +4127,7 @@ decode_prompt_string (string) string--; /* add_string increments string again. */ goto add_string; } - } + } if (c == '\\') { c = *string; @@ -3846,171 +4142,199 @@ decode_prompt_string (string) case '5': case '6': case '7': - { - char octal_string[4]; - int n; + strncpy (octal_string, string, 3); + octal_string[3] = '\0'; - strncpy (octal_string, string, 3); - octal_string[3] = '\0'; + n = read_octal (octal_string); + temp = xmalloc (3); - n = read_octal (octal_string); - temp = xmalloc (3); + if (n == CTLESC || n == CTLNUL) + { + string += 3; + temp[0] = CTLESC; + temp[1] = n; + temp[2] = '\0'; + } + else if (n == -1) + { + temp[0] = '\\'; + temp[1] = '\0'; + } + else + { + string += 3; + temp[0] = n; + temp[1] = '\0'; + } - if (n == CTLESC || n == CTLNUL) - { - string += 3; - temp[0] = CTLESC; - temp[1] = n; - temp[2] = '\0'; - } - else if (n == -1) - { - temp[0] = '\\'; - temp[1] = '\0'; - } - else - { - string += 3; - temp[0] = n; - temp[1] = '\0'; - } + c = 0; + goto add_string; - c = 0; - goto add_string; - } - case 't': case 'd': + case 'T': + case '@': /* Make the current time/date into a string. */ - { - time_t the_time = time (0); - char *ttemp = ctime (&the_time); - temp = savestring (ttemp); + the_time = time (0); + temp = ctime (&the_time); - if (c == 't') - { - strcpy (temp, temp + 11); - temp[8] = '\0'; - } - else - temp[10] = '\0'; + temp = (c != 'd') ? savestring (temp + 11) : savestring (temp); + temp[(c != 'd') ? 8 : 10] = '\0'; - goto add_string; - } + /* quick and dirty conversion to 12-hour time */ + if (c == 'T' || c == '@') + { + if (c == '@') + { + temp[5] = 'a'; /* am/pm format */ + temp[6] = 'm'; + temp[7] = '\0'; + } + c = temp[2]; + temp[2] = '\0'; + n = atoi (temp); + temp[2] = c; + n -= 12; + if (n > 0) + { + temp[0] = (n / 10) + '0'; + temp[1] = (n % 10) + '0'; + } + if (n >= 0 && temp[5] == 'a') + temp[5] = 'p'; + } + goto add_string; case 'n': - if (!no_line_editing) - temp = savestring ("\r\n"); - else - temp = savestring ("\n"); + temp = xmalloc (3); + temp[0] = no_line_editing ? '\n' : '\r'; + temp[1] = no_line_editing ? '\0' : '\n'; + temp[2] = '\0'; goto add_string; case 's': - { - temp = base_pathname (shell_name); - temp = savestring (temp); - goto add_string; - } - + temp = base_pathname (shell_name); + temp = savestring (temp); + goto add_string; + + case 'v': + case 'V': + temp = xmalloc (8); + if (c == 'v') + strcpy (temp, dist_version); + else + sprintf (temp, "%s.%d", dist_version, patch_level); + goto add_string; + case 'w': case 'W': { - /* Use the value of PWD because it is much more effecient. */ -#define EFFICIENT -#ifdef EFFICIENT - char *polite_directory_format (), t_string[MAXPATHLEN]; + /* Use the value of PWD because it is much more efficient. */ + char t_string[PATH_MAX]; temp = get_string_value ("PWD"); - if (!temp) - getwd (t_string); + if (temp == 0) + { + if (getcwd (t_string, sizeof(t_string)) == 0) + { + t_string[0] = '.'; + t_string[1] = '\0'; + } + } else strcpy (t_string, temp); -#else - getwd (t_string); -#endif /* EFFICIENT */ if (c == 'W') { - char *dir = (char *)strrchr (t_string, '/'); - if (dir && dir != t_string) - strcpy (t_string, dir + 1); - temp = savestring (t_string); + t = strrchr (t_string, '/'); + if (t && t != t_string) + strcpy (t_string, t + 1); } else - temp = savestring (polite_directory_format (t_string)); + strcpy (t_string, polite_directory_format (t_string)); + + /* If we're going to be expanding the prompt string later, + quote the directory name. */ + if (promptvars || posixly_correct) + temp = backslash_quote (t_string); + else + temp = savestring (t_string); + goto add_string; } - + case 'u': - { - temp = savestring (current_user.user_name); - goto add_string; - } + temp = savestring (current_user.user_name); + goto add_string; case 'h': - { - char *t_string; - - temp = savestring (current_host_name); - if (t_string = (char *)strchr (temp, '.')) - *t_string = '\0'; - goto add_string; - } + case 'H': + temp = savestring (current_host_name); + if (c == 'h' && (t = (char *)strchr (temp, '.'))) + *t = '\0'; + goto add_string; case '#': - { - temp = itos (current_command_number); - goto add_string; - } + temp = itos (current_command_number); + goto add_string; case '!': - { #if !defined (HISTORY) - temp = savestring ("1"); + temp = savestring ("1"); #else /* HISTORY */ - temp = itos (history_number ()); + temp = itos (history_number ()); #endif /* HISTORY */ - goto add_string; - } + goto add_string; case '$': - temp = savestring (geteuid () == 0 ? "#" : "$"); + temp = xmalloc (2); + temp[0] = current_user.euid == 0 ? '#' : '$'; + temp[1] = '\0'; goto add_string; #if defined (READLINE) case '[': case ']': - temp = xmalloc(3); + temp = xmalloc (3); temp[0] = '\001'; temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; temp[2] = '\0'; goto add_string; -#endif +#endif /* READLINE */ case '\\': - temp = savestring ("\\"); + temp = xmalloc (2); + temp[0] = c; + temp[1] = '\0'; + goto add_string; + + case 'a': + case 'e': + temp = xmalloc (2); + temp[0] = (c == 'a') ? '\07' : '\033'; + temp[1] = '\0'; goto add_string; default: - temp = savestring ("\\ "); + temp = xmalloc (3); + temp[0] = '\\'; temp[1] = c; + temp[2] = '\0'; add_string: if (c) string++; result = sub_append_string (temp, result, &result_index, &result_size); - temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */ + temp = (char *)NULL; /* Freed in sub_append_string (). */ result[result_index] = '\0'; break; } } else { - while (3 + result_index > result_size) - result = xrealloc (result, result_size += PROMPT_GROWTH); - + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH); result[result_index++] = c; result[result_index] = '\0'; } @@ -4019,22 +4343,42 @@ decode_prompt_string (string) result = savestring (string); #endif /* !PROMPT_STRING_DECODE */ + /* Save the delimiter stack and point `dstack' to temp space so any + command substitutions in the prompt string won't result in screwing + up the parser's quoting state. */ + save_dstack = dstack; + dstack = temp_dstack; + dstack.delimiter_depth = 0; + /* Perform variable and parameter expansion and command substitution on the prompt string. */ - list = expand_string_unsplit (result, 1); - free (result); - result = string_list (list); - dispose_words (list); + if (promptvars || posixly_correct) + { + list = expand_string_unsplit (result, Q_DOUBLE_QUOTES); + free (result); + result = string_list (list); + dispose_words (list); + } + else + { + t = dequote_string (result); + free (result); + result = t; + } + + dstack = save_dstack; return (result); } /* Report a syntax error, and restart the parser. Call here for fatal errors. */ +int yyerror () { report_syntax_error ((char *)NULL); reset_parser (); + return (0); } /* Report a syntax error with line numbers, etc. @@ -4045,96 +4389,85 @@ static void report_syntax_error (message) char *message; { + char *msg, *t; + int token_end, i; + char msg2[2]; + if (message) { - if (!interactive) - { - char *name = bash_input.name ? bash_input.name : "stdin"; - report_error ("%s: line %d: `%s'", name, line_number, message); - } - else - { - if (EOF_Reached) - EOF_Reached = 0; - report_error ("%s", message); - } - + parser_error (line_number, "%s", message); + if (interactive && EOF_Reached) + EOF_Reached = 0; last_command_exit_value = EX_USAGE; return; } + /* If the line of input we're reading is not null, try to find the + objectionable token. */ if (shell_input_line && *shell_input_line) { - char *t = shell_input_line; - register int i = shell_input_line_index; - int token_end = 0; + t = shell_input_line; + i = shell_input_line_index; + token_end = 0; - if (!t[i] && i) + if (i && t[i] == '\0') i--; - while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n')) + while (i && (whitespace (t[i]) || t[i] == '\n')) i--; if (i) token_end = i + 1; - while (i && !member (t[i], " \n\t;|&")) + while (i && (member (t[i], " \n\t;|&") == 0)) i--; - while (i != token_end && member (t[i], " \t\n")) + while (i != token_end && (whitespace (t[i]) || t[i] == '\n')) i++; - if (token_end) + /* Print the offending token. */ + if (token_end || (i == 0 && token_end == 0)) { - char *error_token; - error_token = xmalloc (1 + (token_end - i)); - strncpy (error_token, t + i, token_end - i); - error_token[token_end - i] = '\0'; + if (token_end) + { + msg = xmalloc (1 + (token_end - i)); + strncpy (msg, t + i, token_end - i); + msg[token_end - i] = '\0'; + } + else /* one-character token */ + { + msg2[0] = t[i]; + msg2[1] = '\0'; + msg = msg2; + } - report_error ("syntax error near unexpected token `%s'", error_token); - free (error_token); - } - else if ((i == 0) && (token_end == 0)) /* a 1-character token */ - { - char etoken[2]; - etoken[0] = t[i]; - etoken[1] = '\0'; + parser_error (line_number, "syntax error near unexpected token `%s'", msg); - report_error ("syntax error near unexpected token `%s'", etoken); + if (msg != msg2) + free (msg); } - if (!interactive) + /* If not interactive, print the line containing the error. */ + if (interactive == 0) { - char *temp = savestring (shell_input_line); - char *name = bash_input.name ? bash_input.name : "stdin"; - int l = strlen (temp); - - while (l && temp[l - 1] == '\n') - temp[--l] = '\0'; + msg = savestring (shell_input_line); + token_end = strlen (msg); + while (token_end && msg[token_end - 1] == '\n') + msg[--token_end] = '\0'; - report_error ("%s: line %d: `%s'", name, line_number, temp); - free (temp); + parser_error (line_number, "`%s'", msg); + free (msg); } } else { - char *name, *msg; - if (!interactive) - name = bash_input.name ? bash_input.name : "stdin"; - if (EOF_Reached) - msg = "syntax error: unexpected end of file"; - else - msg = "syntax error"; - if (!interactive) - report_error ("%s: line %d: %s", name, line_number, msg); - else - { - /* This file uses EOF_Reached only for error reporting - when the shell is interactive. Other mechanisms are - used to decide whether or not to exit. */ - EOF_Reached = 0; - report_error (msg); - } + msg = EOF_Reached ? "syntax error: unexpected end of file" : "syntax error"; + parser_error (line_number, "%s", msg); + /* When the shell is interactive, this file uses EOF_Reached + only for error reporting. Other mechanisms are used to + decide whether or not to exit. */ + if (interactive && EOF_Reached) + EOF_Reached = 0; } last_command_exit_value = EX_USAGE; } @@ -4144,11 +4477,12 @@ report_syntax_error (message) allocated objects to the memory pool. In the case of no error, we want to throw away the information about where the allocated objects live. (dispose_command () will actually free the command. */ +static void discard_parser_constructs (error_p) int error_p; { } - + /* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */ /* A flag denoting whether or not ignoreeof is set. */ @@ -4190,7 +4524,7 @@ handle_eof_input_unit () prompt_again (); last_read_token = current_token = '\n'; return; - } + } } /* In this case EOF should exit the shell. Do it now. */ |