--- /dev/null
+/* parse.y - Yacc grammar for bash. */
+
+/* Copyright (C) 1989-2010 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+%{
+#include "config.h"
+
+#include "bashtypes.h"
+#include "bashansi.h"
+
+#include "filecntl.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+#include <stdio.h>
+#include "chartypes.h"
+#include <signal.h>
+
+#include "memalloc.h"
+
+#include "bashintl.h"
+
+#define NEED_STRFTIME_DECL /* used in externs.h */
+
+#include "shell.h"
+#include "trap.h"
+#include "flags.h"
+#include "parser.h"
+#include "mailcheck.h"
+#include "test.h"
+#include "builtins.h"
+#include "builtins/common.h"
+#include "builtins/builtext.h"
+
+#include "shmbutil.h"
+
+#if defined (READLINE)
+# include "bashline.h"
+# include <readline/readline.h>
+#endif /* READLINE */
+
+#if defined (HISTORY)
+# include "bashhist.h"
+# include <readline/history.h>
+#endif /* HISTORY */
+
+#if defined (JOB_CONTROL)
+# include "jobs.h"
+#endif /* JOB_CONTROL */
+
+#if defined (ALIAS)
+# include "alias.h"
+#else
+typedef void *alias_t;
+#endif /* ALIAS */
+
+#if defined (PROMPT_STRING_DECODE)
+# ifndef _MINIX
+# include <sys/param.h>
+# endif
+# include <time.h>
+# if defined (TM_IN_SYS_TIME)
+# include <sys/types.h>
+# include <sys/time.h>
+# endif /* TM_IN_SYS_TIME */
+# include "maxpath.h"
+#endif /* PROMPT_STRING_DECODE */
+
+#define RE_READ_TOKEN -99
+#define NO_EXPANSION -100
+
+#ifdef DEBUG
+# define YYDEBUG 1
+#else
+# define YYDEBUG 0
+#endif
+
+#if defined (HANDLE_MULTIBYTE)
+# define last_shell_getc_is_singlebyte \
+ ((shell_input_line_index > 1) \
+ ? shell_input_line_property[shell_input_line_index - 1] \
+ : 1)
+# define MBTEST(x) ((x) && last_shell_getc_is_singlebyte)
+#else
+# define last_shell_getc_is_singlebyte 1
+# define MBTEST(x) ((x))
+#endif
+
+#if defined (EXTENDED_GLOB)
+extern int extended_glob;
+#endif
+
+extern int eof_encountered;
+extern int no_line_editing, running_under_emacs;
+extern int current_command_number;
+extern int sourcelevel, parse_and_execute_level;
+extern int posixly_correct;
+extern int last_command_exit_value;
+extern pid_t last_command_subst_pid;
+extern char *shell_name, *current_host_name;
+extern char *dist_version;
+extern int patch_level;
+extern int dump_translatable_strings, dump_po_strings;
+extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
+#if defined (BUFFERED_INPUT)
+extern int bash_input_fd_changed;
+#endif
+
+extern int errno;
+/* **************************************************************** */
+/* */
+/* "Forward" declarations */
+/* */
+/* **************************************************************** */
+
+#ifdef DEBUG
+static void debug_parser __P((int));
+#endif
+
+static int yy_getc __P((void));
+static int yy_ungetc __P((int));
+
+#if defined (READLINE)
+static int yy_readline_get __P((void));
+static int yy_readline_unget __P((int));
+#endif
+
+static int yy_string_get __P((void));
+static int yy_string_unget __P((int));
+static void rewind_input_string __P((void));
+static int yy_stream_get __P((void));
+static int yy_stream_unget __P((int));
+
+static int shell_getc __P((int));
+static void shell_ungetc __P((int));
+static void discard_until __P((int));
+
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+static void push_string __P((char *, int, alias_t *));
+static void pop_string __P((void));
+static void free_string_list __P((void));
+#endif
+
+static char *read_a_line __P((int));
+
+static int reserved_word_acceptable __P((int));
+static int yylex __P((void));
+static int alias_expand_token __P((char *));
+static int time_command_acceptable __P((void));
+static int special_case_tokens __P((char *));
+static int read_token __P((int));
+static char *parse_matched_pair __P((int, int, int, int *, int));
+static char *parse_comsub __P((int, int, int, int *, int));
+#if defined (ARRAY_VARS)
+static char *parse_compound_assignment __P((int *));
+#endif
+#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
+static int parse_dparen __P((int));
+static int parse_arith_cmd __P((char **, int));
+#endif
+#if defined (COND_COMMAND)
+static void cond_error __P((void));
+static COND_COM *cond_expr __P((void));
+static COND_COM *cond_or __P((void));
+static COND_COM *cond_and __P((void));
+static COND_COM *cond_term __P((void));
+static int cond_skip_newlines __P((void));
+static COMMAND *parse_cond_command __P((void));
+#endif
+#if defined (ARRAY_VARS)
+static int token_is_assignment __P((char *, int));
+static int token_is_ident __P((char *, int));
+#endif
+static int read_token_word __P((int));
+static void discard_parser_constructs __P((int));
+
+static char *error_token_from_token __P((int));
+static char *error_token_from_text __P((void));
+static void print_offending_line __P((void));
+static void report_syntax_error __P((char *));
+
+static void handle_eof_input_unit __P((void));
+static void prompt_again __P((void));
+#if 0
+static void reset_readline_prompt __P((void));
+#endif
+static void print_prompt __P((void));
+
+#if defined (HANDLE_MULTIBYTE)
+static void set_line_mbstate __P((void));
+static char *shell_input_line_property = NULL;
+#else
+# define set_line_mbstate()
+#endif
+
+extern int yyerror __P((const char *));
+
+#ifdef DEBUG
+extern int yydebug;
+#endif
+
+/* 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;
+
+/* Handle on the current prompt string. Indirectly points through
+ ps1_ or 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;
+
+/* If non-zero, $'...' and $"..." are expanded when they appear within
+ a ${...} expansion, even when the expansion appears within double
+ quotes. */
+int extended_quote = 1;
+
+/* The number of lines read from input while creating the current command. */
+int current_command_line_count;
+
+/* The token that currently denotes the end of parse. */
+int shell_eof_token;
+
+/* The token currently being read. */
+int current_token;
+
+/* The current parser state. */
+int parser_state;
+
+/* 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;
+
+/* 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;
+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;
+
+/* 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;
+
+/* The line number in a script at which an arithmetic for command starts. */
+static int arith_for_lineno;
+
+/* 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 last read token, or NULL. read_token () uses this for context
+ checking. */
+static int last_read_token;
+
+/* The token read prior to last_read_token. */
+static int token_before_that;
+
+/* The token read prior to token_before_that. */
+static int two_tokens_ago;
+
+static int global_extglob;
+
+/* The line number in a script where the word in a `case WORD', `select WORD'
+ or `for WORD' begins. This is a nested command maximum, since the array
+ index is decremented after a case, select, or for command is parsed. */
+#define MAX_CASE_NEST 128
+static int word_lineno[MAX_CASE_NEST];
+static int word_top = -1;
+
+/* 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. 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;
+
+static REDIRECTEE source;
+static REDIRECTEE redir;
+%}
+
+%union {
+ WORD_DESC *word; /* the word that we read. */
+ int number; /* the number that we read. */
+ WORD_LIST *word_list;
+ COMMAND *command;
+ REDIRECT *redirect;
+ ELEMENT element;
+ PATTERN_LIST *pattern;
+}
+
+/* Reserved words. Members of the first group are only recognized
+ in the case that they are preceded by a list_terminator. Members
+ of the second group are for [[...]] commands. Members of the
+ third group are recognized only under special circumstances. */
+%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION COPROC
+%token COND_START COND_END COND_ERROR
+%token IN BANG TIME TIMEOPT
+
+/* More general tokens. yylex () knows how to make these. */
+%token <word> WORD ASSIGNMENT_WORD REDIR_WORD
+%token <number> NUMBER
+%token <word_list> ARITH_CMD ARITH_FOR_EXPRS
+%token <command> COND_CMD
+%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND LESS_LESS_LESS
+%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
+%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
+%token GREATER_BAR BAR_AND
+
+/* The types that the various syntactical units return. */
+
+%type <command> inputunit command pipeline pipeline_command
+%type <command> list list0 list1 compound_list simple_list simple_list1
+%type <command> simple_command shell_command
+%type <command> for_command select_command case_command group_command
+%type <command> arith_command
+%type <command> cond_command
+%type <command> arith_for_command
+%type <command> coproc
+%type <command> function_def function_body if_command elif_clause subshell
+%type <redirect> redirection redirection_list
+%type <element> simple_command_element
+%type <word_list> word_list pattern
+%type <pattern> pattern_list case_clause_sequence case_clause
+%type <number> timespec
+%type <number> list_terminator
+
+%start inputunit
+
+%left '&' ';' '\n' yacc_EOF
+%left AND_AND OR_OR
+%right '|' BAR_AND
+%%
+
+inputunit: simple_list simple_list_terminator
+ {
+ /* Case of regular command. Discard the error
+ safety net,and return the command just parsed. */
+ global_command = $1;
+ eof_encountered = 0;
+ /* discard_parser_constructs (0); */
+ if (parser_state & PST_CMDSUBST)
+ parser_state |= PST_EOFTOKEN;
+ YYACCEPT;
+ }
+ | '\n'
+ {
+ /* Case of regular command, but not a very
+ interesting one. Return a NULL command. */
+ global_command = (COMMAND *)NULL;
+ if (parser_state & PST_CMDSUBST)
+ parser_state |= PST_EOFTOKEN;
+ YYACCEPT;
+ }
+ | error '\n'
+ {
+ /* Error during parsing. Return NULL command. */
+ global_command = (COMMAND *)NULL;
+ eof_encountered = 0;
+ /* discard_parser_constructs (1); */
+ if (interactive && parse_and_execute_level == 0)
+ {
+ YYACCEPT;
+ }
+ else
+ {
+ YYABORT;
+ }
+ }
+ | yacc_EOF
+ {
+ /* Case of EOF seen by itself. Do ignoreeof or
+ not. */
+ global_command = (COMMAND *)NULL;
+ handle_eof_input_unit ();
+ YYACCEPT;
+ }
+ ;
+
+word_list: WORD
+ { $$ = make_word_list ($1, (WORD_LIST *)NULL); }
+ | word_list WORD
+ { $$ = make_word_list ($2, $1); }
+ ;
+
+redirection: '>' WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_output_direction, redir, 0);
+ }
+ | '<' WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_input_direction, redir, 0);
+ }
+ | NUMBER '>' WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_output_direction, redir, 0);
+ }
+ | NUMBER '<' WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_input_direction, redir, 0);
+ }
+ | REDIR_WORD '>' WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_output_direction, redir, REDIR_VARASSIGN);
+ }
+ | REDIR_WORD '<' WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_input_direction, redir, REDIR_VARASSIGN);
+ }
+ | GREATER_GREATER WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_appending_to, redir, 0);
+ }
+ | NUMBER GREATER_GREATER WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_appending_to, redir, 0);
+ }
+ | REDIR_WORD GREATER_GREATER WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_appending_to, redir, REDIR_VARASSIGN);
+ }
+ | GREATER_BAR WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_output_force, redir, 0);
+ }
+ | NUMBER GREATER_BAR WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_output_force, redir, 0);
+ }
+ | REDIR_WORD GREATER_BAR WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_output_force, redir, REDIR_VARASSIGN);
+ }
+ | LESS_GREATER WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_input_output, redir, 0);
+ }
+ | NUMBER LESS_GREATER WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_input_output, redir, 0);
+ }
+ | REDIR_WORD LESS_GREATER WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_input_output, redir, REDIR_VARASSIGN);
+ }
+ | LESS_LESS WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_reading_until, redir, 0);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | NUMBER LESS_LESS WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_reading_until, redir, 0);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | REDIR_WORD LESS_LESS WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | LESS_LESS_MINUS WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | NUMBER LESS_LESS_MINUS WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | REDIR_WORD LESS_LESS_MINUS WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
+ redir_stack[need_here_doc++] = $$;
+ }
+ | LESS_LESS_LESS WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_reading_string, redir, 0);
+ }
+ | NUMBER LESS_LESS_LESS WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_reading_string, redir, 0);
+ }
+ | REDIR_WORD LESS_LESS_LESS WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_reading_string, redir, REDIR_VARASSIGN);
+ }
+ | LESS_AND NUMBER
+ {
+ source.dest = 0;
+ redir.dest = $2;
+ $$ = make_redirection (source, r_duplicating_input, redir, 0);
+ }
+ | NUMBER LESS_AND NUMBER
+ {
+ source.dest = $1;
+ redir.dest = $3;
+ $$ = make_redirection (source, r_duplicating_input, redir, 0);
+ }
+ | REDIR_WORD LESS_AND NUMBER
+ {
+ source.filename = $1;
+ redir.dest = $3;
+ $$ = make_redirection (source, r_duplicating_input, redir, REDIR_VARASSIGN);
+ }
+ | GREATER_AND NUMBER
+ {
+ source.dest = 1;
+ redir.dest = $2;
+ $$ = make_redirection (source, r_duplicating_output, redir, 0);
+ }
+ | NUMBER GREATER_AND NUMBER
+ {
+ source.dest = $1;
+ redir.dest = $3;
+ $$ = make_redirection (source, r_duplicating_output, redir, 0);
+ }
+ | REDIR_WORD GREATER_AND NUMBER
+ {
+ source.filename = $1;
+ redir.dest = $3;
+ $$ = make_redirection (source, r_duplicating_output, redir, REDIR_VARASSIGN);
+ }
+ | LESS_AND WORD
+ {
+ source.dest = 0;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_duplicating_input_word, redir, 0);
+ }
+ | NUMBER LESS_AND WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_duplicating_input_word, redir, 0);
+ }
+ | REDIR_WORD LESS_AND WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_duplicating_input_word, redir, REDIR_VARASSIGN);
+ }
+ | GREATER_AND WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_duplicating_output_word, redir, 0);
+ }
+ | NUMBER GREATER_AND WORD
+ {
+ source.dest = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_duplicating_output_word, redir, 0);
+ }
+ | REDIR_WORD GREATER_AND WORD
+ {
+ source.filename = $1;
+ redir.filename = $3;
+ $$ = make_redirection (source, r_duplicating_output_word, redir, REDIR_VARASSIGN);
+ }
+ | GREATER_AND '-'
+ {
+ source.dest = 1;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, 0);
+ }
+ | NUMBER GREATER_AND '-'
+ {
+ source.dest = $1;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, 0);
+ }
+ | REDIR_WORD GREATER_AND '-'
+ {
+ source.filename = $1;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN);
+ }
+ | LESS_AND '-'
+ {
+ source.dest = 0;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, 0);
+ }
+ | NUMBER LESS_AND '-'
+ {
+ source.dest = $1;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, 0);
+ }
+ | REDIR_WORD LESS_AND '-'
+ {
+ source.filename = $1;
+ redir.dest = 0;
+ $$ = make_redirection (source, r_close_this, redir, REDIR_VARASSIGN);
+ }
+ | AND_GREATER WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_err_and_out, redir, 0);
+ }
+ | AND_GREATER_GREATER WORD
+ {
+ source.dest = 1;
+ redir.filename = $2;
+ $$ = make_redirection (source, r_append_err_and_out, redir, 0);
+ }
+ ;
+
+simple_command_element: WORD
+ { $$.word = $1; $$.redirect = 0; }
+ | ASSIGNMENT_WORD
+ { $$.word = $1; $$.redirect = 0; }
+ | redirection
+ { $$.redirect = $1; $$.word = 0; }
+ ;
+
+redirection_list: redirection
+ {
+ $$ = $1;
+ }
+ | redirection_list redirection
+ {
+ register REDIRECT *t;
+
+ for (t = $1; t->next; t = t->next)
+ ;
+ t->next = $2;
+ $$ = $1;
+ }
+ ;
+
+simple_command: simple_command_element
+ { $$ = make_simple_command ($1, (COMMAND *)NULL); }
+ | simple_command simple_command_element
+ { $$ = make_simple_command ($2, $1); }
+ ;
+
+command: simple_command
+ { $$ = clean_simple_command ($1); }
+ | shell_command
+ { $$ = $1; }
+ | shell_command redirection_list
+ {
+ COMMAND *tc;
+
+ tc = $1;
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = $2;
+ }
+ else
+ tc->redirects = $2;
+ $$ = $1;
+ }
+ | function_def
+ { $$ = $1; }
+ | coproc
+ { $$ = $1; }
+ ;
+
+shell_command: for_command
+ { $$ = $1; }
+ | case_command
+ { $$ = $1; }
+ | WHILE compound_list DO compound_list DONE
+ { $$ = make_while_command ($2, $4); }
+ | UNTIL compound_list DO compound_list DONE
+ { $$ = make_until_command ($2, $4); }
+ | select_command
+ { $$ = $1; }
+ | if_command
+ { $$ = $1; }
+ | subshell
+ { $$ = $1; }
+ | group_command
+ { $$ = $1; }
+ | arith_command
+ { $$ = $1; }
+ | cond_command
+ { $$ = $1; }
+ | arith_for_command
+ { $$ = $1; }
+ ;
+
+for_command: FOR WORD newline_list DO compound_list DONE
+ {
+ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD newline_list '{' compound_list '}'
+ {
+ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD ';' newline_list DO compound_list DONE
+ {
+ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD ';' newline_list '{' compound_list '}'
+ {
+ $$ = make_for_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE
+ {
+ $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}'
+ {
+ $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD newline_list IN list_terminator newline_list DO compound_list DONE
+ {
+ $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | FOR WORD newline_list IN list_terminator newline_list '{' compound_list '}'
+ {
+ $$ = make_for_command ($2, (WORD_LIST *)NULL, $8, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ ;
+
+arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE
+ {
+ $$ = make_arith_for_command ($2, $6, arith_for_lineno);
+ if (word_top > 0) word_top--;
+ }
+ | FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}'
+ {
+ $$ = make_arith_for_command ($2, $6, arith_for_lineno);
+ if (word_top > 0) word_top--;
+ }
+ | FOR ARITH_FOR_EXPRS DO compound_list DONE
+ {
+ $$ = make_arith_for_command ($2, $4, arith_for_lineno);
+ if (word_top > 0) word_top--;
+ }
+ | FOR ARITH_FOR_EXPRS '{' compound_list '}'
+ {
+ $$ = make_arith_for_command ($2, $4, arith_for_lineno);
+ if (word_top > 0) word_top--;
+ }
+ ;
+
+select_command: SELECT WORD newline_list DO list DONE
+ {
+ $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | SELECT WORD newline_list '{' list '}'
+ {
+ $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | SELECT WORD ';' newline_list DO list DONE
+ {
+ $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | SELECT WORD ';' newline_list '{' list '}'
+ {
+ $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE
+ {
+ $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}'
+ {
+ $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ ;
+
+case_command: CASE WORD newline_list IN newline_list ESAC
+ {
+ $$ = make_case_command ($2, (PATTERN_LIST *)NULL, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | CASE WORD newline_list IN case_clause_sequence newline_list ESAC
+ {
+ $$ = make_case_command ($2, $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ | CASE WORD newline_list IN case_clause ESAC
+ {
+ $$ = make_case_command ($2, $5, word_lineno[word_top]);
+ if (word_top > 0) word_top--;
+ }
+ ;
+
+function_def: WORD '(' ')' newline_list function_body
+ { $$ = make_function_def ($1, $5, function_dstart, function_bstart); }
+
+ | FUNCTION WORD '(' ')' newline_list function_body
+ { $$ = make_function_def ($2, $6, function_dstart, function_bstart); }
+
+ | FUNCTION WORD newline_list function_body
+ { $$ = make_function_def ($2, $4, function_dstart, function_bstart); }
+ ;
+
+function_body: shell_command
+ { $$ = $1; }
+ | shell_command redirection_list
+ {
+ COMMAND *tc;
+
+ tc = $1;
+ /* 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. */
+ /* XXX - I don't think it matters, but we might
+ want to change this in the future to avoid
+ problems differentiating between a function
+ definition with a redirection and a function
+ definition containing a single command with a
+ redirection. The two are semantically equivalent,
+ though -- the only difference is in how the
+ command printing code displays the redirections. */
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = $2;
+ }
+ else
+ tc->redirects = $2;
+ $$ = $1;
+ }
+ ;
+
+subshell: '(' compound_list ')'
+ {
+ $$ = make_subshell_command ($2);
+ $$->flags |= CMD_WANT_SUBSHELL;
+ }
+ ;
+
+coproc: COPROC shell_command
+ {
+ $$ = make_coproc_command ("COPROC", $2);
+ $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
+ }
+ | COPROC shell_command redirection_list
+ {
+ COMMAND *tc;
+
+ tc = $2;
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = $3;
+ }
+ else
+ tc->redirects = $3;
+ $$ = make_coproc_command ("COPROC", $2);
+ $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
+ }
+ | COPROC WORD shell_command
+ {
+ $$ = make_coproc_command ($2->word, $3);
+ $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
+ }
+ | COPROC WORD shell_command redirection_list
+ {
+ COMMAND *tc;
+
+ tc = $3;
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = $4;
+ }
+ else
+ tc->redirects = $4;
+ $$ = make_coproc_command ($2->word, $3);
+ $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
+ }
+ | COPROC simple_command
+ {
+ $$ = make_coproc_command ("COPROC", clean_simple_command ($2));
+ $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
+ }
+ ;
+
+if_command: IF compound_list THEN compound_list FI
+ { $$ = make_if_command ($2, $4, (COMMAND *)NULL); }
+ | IF compound_list THEN compound_list ELSE compound_list FI
+ { $$ = make_if_command ($2, $4, $6); }
+ | IF compound_list THEN compound_list elif_clause FI
+ { $$ = make_if_command ($2, $4, $5); }
+ ;
+
+
+group_command: '{' compound_list '}'
+ { $$ = make_group_command ($2); }
+ ;
+
+arith_command: ARITH_CMD
+ { $$ = make_arith_command ($1); }
+ ;
+
+cond_command: COND_START COND_CMD COND_END
+ { $$ = $2; }
+ ;
+
+elif_clause: ELIF compound_list THEN compound_list
+ { $$ = make_if_command ($2, $4, (COMMAND *)NULL); }
+ | ELIF compound_list THEN compound_list ELSE compound_list
+ { $$ = make_if_command ($2, $4, $6); }
+ | ELIF compound_list THEN compound_list elif_clause
+ { $$ = make_if_command ($2, $4, $5); }
+ ;
+
+case_clause: pattern_list
+ | case_clause_sequence pattern_list
+ { $2->next = $1; $$ = $2; }
+ ;
+
+pattern_list: newline_list pattern ')' compound_list
+ { $$ = make_pattern_list ($2, $4); }
+ | newline_list pattern ')' newline_list
+ { $$ = make_pattern_list ($2, (COMMAND *)NULL); }
+ | newline_list '(' pattern ')' compound_list
+ { $$ = make_pattern_list ($3, $5); }
+ | newline_list '(' pattern ')' newline_list
+ { $$ = make_pattern_list ($3, (COMMAND *)NULL); }
+ ;
+
+case_clause_sequence: pattern_list SEMI_SEMI
+ { $$ = $1; }
+ | case_clause_sequence pattern_list SEMI_SEMI
+ { $2->next = $1; $$ = $2; }
+ | pattern_list SEMI_AND
+ { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; }
+ | case_clause_sequence pattern_list SEMI_AND
+ { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; }
+ | pattern_list SEMI_SEMI_AND
+ { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; }
+ | case_clause_sequence pattern_list SEMI_SEMI_AND
+ { $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; }
+ ;
+
+pattern: WORD
+ { $$ = make_word_list ($1, (WORD_LIST *)NULL); }
+ | pattern '|' WORD
+ { $$ = make_word_list ($3, $1); }
+ ;
+
+/* A list allows leading or trailing newlines and
+ newlines as operators (equivalent to semicolons).
+ It must end with a newline or semicolon.
+ Lists are used within commands such as if, for, while. */
+
+list: newline_list list0
+ {
+ $$ = $2;
+ if (need_here_doc)
+ gather_here_documents ();
+ }
+ ;
+
+compound_list: list
+ | newline_list list1
+ {
+ $$ = $2;
+ }
+ ;
+
+list0: list1 '\n' newline_list
+ | list1 '&' newline_list
+ {
+ if ($1->type == cm_connection)
+ $$ = connect_async_list ($1, (COMMAND *)NULL, '&');
+ else
+ $$ = command_connect ($1, (COMMAND *)NULL, '&');
+ }
+ | list1 ';' newline_list
+
+ ;
+
+list1: list1 AND_AND newline_list list1
+ { $$ = command_connect ($1, $4, AND_AND); }
+ | list1 OR_OR newline_list list1
+ { $$ = command_connect ($1, $4, OR_OR); }
+ | list1 '&' newline_list list1
+ {
+ if ($1->type == cm_connection)
+ $$ = connect_async_list ($1, $4, '&');
+ else
+ $$ = command_connect ($1, $4, '&');
+ }
+ | list1 ';' newline_list list1
+ { $$ = command_connect ($1, $4, ';'); }
+ | list1 '\n' newline_list list1
+ { $$ = command_connect ($1, $4, ';'); }
+ | pipeline_command
+ { $$ = $1; }
+ ;
+
+simple_list_terminator: '\n'
+ | yacc_EOF
+ ;
+
+list_terminator:'\n'
+ { $$ = '\n'; }
+ | ';'
+ { $$ = ';'; }
+ | yacc_EOF
+ { $$ = yacc_EOF; }
+ ;
+
+newline_list:
+ | newline_list '\n'
+ ;
+
+/* A simple_list is a list that contains no significant newlines
+ and no leading or trailing newlines. Newlines are allowed
+ only following operators, where they are not significant.
+
+ This is what an inputunit consists of. */
+
+simple_list: simple_list1
+ {
+ $$ = $1;
+ if (need_here_doc)
+ gather_here_documents ();
+ if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
+ {
+ global_command = $1;
+ eof_encountered = 0;
+ rewind_input_string ();
+ YYACCEPT;
+ }
+ }
+ | simple_list1 '&'
+ {
+ if ($1->type == cm_connection)
+ $$ = connect_async_list ($1, (COMMAND *)NULL, '&');
+ else
+ $$ = command_connect ($1, (COMMAND *)NULL, '&');
+ if (need_here_doc)
+ gather_here_documents ();
+ if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
+ {
+ global_command = $1;
+ eof_encountered = 0;
+ rewind_input_string ();
+ YYACCEPT;
+ }
+ }
+ | simple_list1 ';'
+ {
+ $$ = $1;
+ if (need_here_doc)
+ gather_here_documents ();
+ if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
+ {
+ global_command = $1;
+ eof_encountered = 0;
+ rewind_input_string ();
+ YYACCEPT;
+ }
+ }
+ ;
+
+simple_list1: simple_list1 AND_AND newline_list simple_list1
+ { $$ = command_connect ($1, $4, AND_AND); }
+ | simple_list1 OR_OR newline_list simple_list1
+ { $$ = command_connect ($1, $4, OR_OR); }
+ | simple_list1 '&' simple_list1
+ {
+ if ($1->type == cm_connection)
+ $$ = connect_async_list ($1, $3, '&');
+ else
+ $$ = command_connect ($1, $3, '&');
+ }
+ | simple_list1 ';' simple_list1
+ { $$ = command_connect ($1, $3, ';'); }
+
+ | pipeline_command
+ { $$ = $1; }
+ ;
+
+pipeline_command: pipeline
+ { $$ = $1; }
+ | BANG pipeline
+ {
+ if ($2)
+ $2->flags |= CMD_INVERT_RETURN;
+ $$ = $2;
+ }
+ | timespec pipeline
+ {
+ if ($2)
+ $2->flags |= $1;
+ $$ = $2;
+ }
+ | timespec BANG pipeline
+ {
+ if ($3)
+ $3->flags |= $1|CMD_INVERT_RETURN;
+ $$ = $3;
+ }
+ | BANG timespec pipeline
+ {
+ if ($3)
+ $3->flags |= $2|CMD_INVERT_RETURN;
+ $$ = $3;
+ }
+ | timespec list_terminator
+ {
+ ELEMENT x;
+
+ /* Boy, this is unclean. `time' by itself can
+ time a null command. We cheat and push a
+ newline back if the list_terminator was a newline
+ to avoid the double-newline problem (one to
+ terminate this, one to terminate the command) */
+ x.word = 0;
+ x.redirect = 0;
+ $$ = make_simple_command (x, (COMMAND *)NULL);
+ $$->flags |= $1;
+ /* XXX - let's cheat and push a newline back */
+ if ($2 == '\n')
+ token_to_read = '\n';
+ }
+
+ ;
+
+pipeline: pipeline '|' newline_list pipeline
+ { $$ = command_connect ($1, $4, '|'); }
+ | pipeline BAR_AND newline_list pipeline
+ {
+ /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
+ COMMAND *tc;
+ REDIRECTEE rd, sd;
+ REDIRECT *r;
+
+ tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1;
+ sd.dest = 2;
+ rd.dest = 1;
+ r = make_redirection (sd, r_duplicating_output, rd, 0);
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = r;
+ }
+ else
+ tc->redirects = r;
+
+ $$ = command_connect ($1, $4, '|');
+ }
+ | command
+ { $$ = $1; }
+ ;
+
+timespec: TIME
+ { $$ = CMD_TIME_PIPELINE; }
+ | TIME TIMEOPT
+ { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; }
+ ;
+%%
+
+/* Initial size to allocate for tokens, and the
+ amount to grow them by. */
+#define TOKEN_DEFAULT_INITIAL_SIZE 496
+#define TOKEN_DEFAULT_GROW_SIZE 512
+
+/* Should we call prompt_again? */
+#define SHOULD_PROMPT() \
+ (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
+
+#if defined (ALIAS)
+# define expanding_alias() (pushed_string_list && pushed_string_list->expander)
+#else
+# define expanding_alias() 0
+#endif
+
+/* Global var is non-zero when end of file has been reached. */
+int EOF_Reached = 0;
+
+#ifdef DEBUG
+static void
+debug_parser (i)
+ int i;
+{
+#if YYDEBUG != 0
+ yydebug = i;
+#endif
+}
+#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
+ installed function for getting the next character, makes UNGET the
+ installed function for un-getting a character, sets the type of stream
+ (either string or file) from TYPE, and makes LOCATION point to where
+ the input is coming from. */
+
+/* Unconditionally returns end-of-file. */
+int
+return_EOF ()
+{
+ return (EOF);
+}
+
+/* Variable containing the current get and unget functions.
+ See ./input.h for a clearer description. */
+BASH_INPUT bash_input;
+
+/* 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 = st_none;
+ FREE (bash_input.name);
+ bash_input.name = (char *)NULL;
+ bash_input.location.file = (FILE *)NULL;
+ bash_input.location.string = (char *)NULL;
+ bash_input.getter = (sh_cget_func_t *)NULL;
+ bash_input.ungetter = (sh_cunget_func_t *)NULL;
+}
+
+/* Set the contents of the current bash input stream from
+ GET, UNGET, TYPE, NAME, and LOCATION. */
+void
+init_yy_io (get, unget, type, name, location)
+ sh_cget_func_t *get;
+ sh_cunget_func_t *unget;
+ enum stream_type type;
+ const char *name;
+ INPUT_STREAM location;
+{
+ bash_input.type = type;
+ FREE (bash_input.name);
+ bash_input.name = name ? savestring (name) : (char *)NULL;
+
+ /* XXX */
+#if defined (CRAY)
+ memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location));
+#else
+ bash_input.location = location;
+#endif
+ bash_input.getter = get;
+ bash_input.ungetter = unget;
+}
+
+char *
+yy_input_name ()
+{
+ return (bash_input.name ? bash_input.name : "stdin");
+}
+
+/* Call this to get the next character of input. */
+static int
+yy_getc ()
+{
+ return (*(bash_input.getter)) ();
+}
+
+/* Call this to unget C. That is, to make C the next character
+ to be read. */
+static int
+yy_ungetc (c)
+ int c;
+{
+ return (*(bash_input.ungetter)) (c);
+}
+
+#if defined (BUFFERED_INPUT)
+#ifdef INCLUDE_UNUSED
+int
+input_file_descriptor ()
+{
+ switch (bash_input.type)
+ {
+ case st_stream:
+ return (fileno (bash_input.location.file));
+ case st_bstream:
+ return (bash_input.location.buffered_fd);
+ case st_stdin:
+ default:
+ return (fileno (stdin));
+ }
+}
+#endif
+#endif /* BUFFERED_INPUT */
+
+/* **************************************************************** */
+/* */
+/* Let input be read from readline (). */
+/* */
+/* **************************************************************** */
+
+#if defined (READLINE)
+char *current_readline_prompt = (char *)NULL;
+char *current_readline_line = (char *)NULL;
+int current_readline_line_index = 0;
+
+static int
+yy_readline_get ()
+{
+ SigHandler *old_sigint;
+ int line_len;
+ unsigned char c;
+
+ if (!current_readline_line)
+ {
+ if (!bash_readline_initialized)
+ initialize_readline ();
+
+#if defined (JOB_CONTROL)
+ if (job_control)
+ give_terminal_to (shell_pgrp, 0);
+#endif /* JOB_CONTROL */
+
+ old_sigint = (SigHandler *)IMPOSSIBLE_TRAP_HANDLER;
+ if (signal_is_ignored (SIGINT) == 0)
+ {
+ interrupt_immediately++;
+ old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
+ }
+ terminate_immediately = 1;
+
+ current_readline_line = readline (current_readline_prompt ?
+ current_readline_prompt : "");
+
+ terminate_immediately = 0;
+ if (signal_is_ignored (SIGINT) == 0)
+ {
+ interrupt_immediately--;
+ if (old_sigint != IMPOSSIBLE_TRAP_HANDLER)
+ set_signal_handler (SIGINT, old_sigint);
+ }
+
+#if 0
+ /* Reset the prompt to the decoded value of prompt_string_pointer. */
+ reset_readline_prompt ();
+#endif
+
+ if (current_readline_line == 0)
+ return (EOF);
+
+ current_readline_line_index = 0;
+ line_len = strlen (current_readline_line);
+
+ current_readline_line = (char *)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] == 0)
+ {
+ free (current_readline_line);
+ current_readline_line = (char *)NULL;
+ return (yy_readline_get ());
+ }
+ else
+ {
+ c = 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
+with_input_from_stdin ()
+{
+ INPUT_STREAM location;
+
+ if (bash_input.type != st_stdin && stream_on_stack (st_stdin) == 0)
+ {
+ location.string = current_readline_line;
+ init_yy_io (yy_readline_get, yy_readline_unget,
+ st_stdin, "readline stdin", location);
+ }
+}
+
+#else /* !READLINE */
+
+void
+with_input_from_stdin ()
+{
+ with_input_from_stream (stdin, "stdin");
+}
+#endif /* !READLINE */
+
+/* **************************************************************** */
+/* */
+/* Let input come from STRING. STRING is zero terminated. */
+/* */
+/* **************************************************************** */
+
+static int
+yy_string_get ()
+{
+ register char *string;
+ register unsigned char c;
+
+ string = bash_input.location.string;
+
+ /* If the string doesn't exist, or is empty, EOF found. */
+ if (string && *string)
+ {
+ c = *string++;
+ bash_input.location.string = string;
+ return (c);
+ }
+ else
+ return (EOF);
+}
+
+static int
+yy_string_unget (c)
+ int c;
+{
+ *(--bash_input.location.string) = c;
+ return (c);
+}
+
+void
+with_input_from_string (string, name)
+ char *string;
+ const char *name;
+{
+ INPUT_STREAM location;
+
+ location.string = string;
+ init_yy_io (yy_string_get, yy_string_unget, st_string, name, location);
+}
+
+/* Count the number of characters we've consumed from bash_input.location.string
+ and read into shell_input_line, but have not returned from shell_getc.
+ That is the true input location. Rewind bash_input.location.string by
+ that number of characters, so it points to the last character actually
+ consumed by the parser. */
+static void
+rewind_input_string ()
+{
+ int xchars;
+
+ /* number of unconsumed characters in the input -- XXX need to take newlines
+ into account, e.g., $(...\n) */
+ xchars = shell_input_line_len - shell_input_line_index;
+ if (bash_input.location.string[-1] == '\n')
+ xchars++;
+
+ /* XXX - how to reflect bash_input.location.string back to string passed to
+ parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how
+ far into the string we parsed. parse_and_execute knows where bash_input.
+ location.string is, and how far from orig_string that is -- that's the
+ number of characters the command consumed. */
+
+ /* bash_input.location.string - xchars should be where we parsed to */
+ /* need to do more validation on xchars value for sanity -- test cases. */
+ bash_input.location.string -= xchars;
+}
+
+/* **************************************************************** */
+/* */
+/* Let input come from STREAM. */
+/* */
+/* **************************************************************** */
+
+/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS
+ define, and just use getc/ungetc if it was defined, but since bash
+ installs its signal handlers without the SA_RESTART flag, some signals
+ (like SIGCHLD, SIGWINCH, etc.) received during a read(2) will not cause
+ the read to be restarted. We need to restart it ourselves. */
+
+static int
+yy_stream_get ()
+{
+ int result;
+
+ result = EOF;
+ if (bash_input.location.file)
+ {
+ if (interactive)
+ {
+ interrupt_immediately++;
+ terminate_immediately++;
+ }
+ result = getc_with_restart (bash_input.location.file);
+ if (interactive)
+ {
+ interrupt_immediately--;
+ terminate_immediately--;
+ }
+ }
+ return (result);
+}
+
+static int
+yy_stream_unget (c)
+ int c;
+{
+ return (ungetc_with_restart (c, bash_input.location.file));
+}
+
+void
+with_input_from_stream (stream, name)
+ FILE *stream;
+ const char *name;
+{
+ INPUT_STREAM location;
+
+ location.file = stream;
+ init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location);
+}
+
+typedef struct stream_saver {
+ struct stream_saver *next;
+ BASH_INPUT bash_input;
+ int line;
+#if defined (BUFFERED_INPUT)
+ BUFFERED_STREAM *bstream;
+#endif /* BUFFERED_INPUT */
+} STREAM_SAVER;
+
+/* The globally known line number. */
+int line_number = 0;
+
+#if defined (COND_COMMAND)
+static int cond_lineno;
+static int cond_token;
+#endif
+
+STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL;
+
+void
+push_stream (reset_lineno)
+ int reset_lineno;
+{
+ STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER));
+
+ xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT));
+
+#if defined (BUFFERED_INPUT)
+ saver->bstream = (BUFFERED_STREAM *)NULL;
+ /* If we have a buffered stream, clear out buffers[fd]. */
+ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
+ saver->bstream = set_buffered_stream (bash_input.location.buffered_fd,
+ (BUFFERED_STREAM *)NULL);
+#endif /* BUFFERED_INPUT */
+
+ saver->line = line_number;
+ bash_input.name = (char *)NULL;
+ saver->next = stream_list;
+ stream_list = saver;
+ EOF_Reached = 0;
+ if (reset_lineno)
+ line_number = 0;
+}
+
+void
+pop_stream ()
+{
+ if (!stream_list)
+ EOF_Reached = 1;
+ else
+ {
+ STREAM_SAVER *saver = stream_list;
+
+ EOF_Reached = 0;
+ stream_list = stream_list->next;
+
+ init_yy_io (saver->bash_input.getter,
+ saver->bash_input.ungetter,
+ saver->bash_input.type,
+ saver->bash_input.name,
+ saver->bash_input.location);
+
+#if defined (BUFFERED_INPUT)
+ /* If we have a buffered stream, restore buffers[fd]. */
+ /* If the input file descriptor was changed while this was on the
+ save stack, update the buffered fd to the new file descriptor and
+ re-establish the buffer <-> bash_input fd correspondence. */
+ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
+ {
+ if (bash_input_fd_changed)
+ {
+ bash_input_fd_changed = 0;
+ if (default_buffered_input >= 0)
+ {
+ bash_input.location.buffered_fd = default_buffered_input;
+ saver->bstream->b_fd = default_buffered_input;
+ SET_CLOSE_ON_EXEC (default_buffered_input);
+ }
+ }
+ /* XXX could free buffered stream returned as result here. */
+ set_buffered_stream (bash_input.location.buffered_fd, saver->bstream);
+ }
+#endif /* BUFFERED_INPUT */
+
+ line_number = saver->line;
+
+ FREE (saver->bash_input.name);
+ free (saver);
+ }
+}
+
+/* Return 1 if a stream of type TYPE is saved on the stack. */
+int
+stream_on_stack (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;
+}
+
+/* Save the current token state and return it in a malloced array. */
+int *
+save_token_state ()
+{
+ int *ret;
+
+ ret = (int *)xmalloc (4 * sizeof (int));
+ ret[0] = last_read_token;
+ ret[1] = token_before_that;
+ ret[2] = two_tokens_ago;
+ ret[3] = current_token;
+ return ret;
+}
+
+void
+restore_token_state (ts)
+ int *ts;
+{
+ if (ts == 0)
+ return;
+ last_read_token = ts[0];
+ token_before_that = ts[1];
+ two_tokens_ago = ts[2];
+ current_token = ts[3];
+}
+
+/*
+ * This is used to inhibit alias expansion and reserved word recognition
+ * 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'
+ */
+
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+
+#define END_OF_ALIAS 0
+
+/*
+ * Pseudo-global variables used in implementing token-wise alias expansion.
+ */
+
+/*
+ * Pushing and popping strings. This works together with shell_getc to
+ * implement alias expansion on a per-token basis.
+ */
+
+typedef struct string_saver {
+ struct string_saver *next;
+ int expand_alias; /* Value to set expand_alias to when string is popped. */
+ char *saved_line;
+#if defined (ALIAS)
+ alias_t *expander; /* alias that caused this line to be pushed. */
+#endif
+ int saved_line_size, saved_line_index, saved_line_terminator;
+} STRING_SAVER;
+
+STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL;
+
+/*
+ * 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
+ * the value of expand_next_token when the string is popped, so that the
+ * word after the alias in the original line is handled correctly when the
+ * alias expands to multiple words. TOKEN is the token that was expanded
+ * into S; it is saved and used to prevent infinite recursive expansion.
+ */
+static void
+push_string (s, expand, ap)
+ char *s;
+ int expand;
+ alias_t *ap;
+{
+ STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER));
+
+ temp->expand_alias = expand;
+ temp->saved_line = shell_input_line;
+ temp->saved_line_size = shell_input_line_size;
+ temp->saved_line_index = shell_input_line_index;
+ temp->saved_line_terminator = shell_input_line_terminator;
+#if defined (ALIAS)
+ temp->expander = ap;
+#endif
+ temp->next = pushed_string_list;
+ pushed_string_list = temp;
+
+#if defined (ALIAS)
+ if (ap)
+ ap->flags |= AL_BEINGEXPANDED;
+#endif
+
+ shell_input_line = s;
+ shell_input_line_size = strlen (s);
+ shell_input_line_index = 0;
+ shell_input_line_terminator = '\0';
+#if 0
+ parser_state &= ~PST_ALEXPNEXT; /* XXX */
+#endif
+
+ set_line_mbstate ();
+}
+
+/*
+ * Make the top of the pushed_string stack be the current shell input.
+ * Only called when there is something on the stack. Called from shell_getc
+ * when it thinks it has consumed the string generated by an alias expansion
+ * and needs to return to the original input line.
+ */
+static void
+pop_string ()
+{
+ STRING_SAVER *t;
+
+ FREE (shell_input_line);
+ shell_input_line = pushed_string_list->saved_line;
+ 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;
+
+ 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;
+
+#if defined (ALIAS)
+ if (t->expander)
+ t->expander->flags &= ~AL_BEINGEXPANDED;
+#endif
+
+ free ((char *)t);
+
+ set_line_mbstate ();
+}
+
+static void
+free_string_list ()
+{
+ register STRING_SAVER *t, *t1;
+
+ for (t = pushed_string_list; t; )
+ {
+ t1 = t->next;
+ FREE (t->saved_line);
+#if defined (ALIAS)
+ if (t->expander)
+ t->expander->flags &= ~AL_BEINGEXPANDED;
+#endif
+ free ((char *)t);
+ t = t1;
+ }
+ pushed_string_list = (STRING_SAVER *)NULL;
+}
+
+#endif /* ALIAS || DPAREN_ARITHMETIC */
+
+void
+free_pushed_string_input ()
+{
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+ free_string_list ();
+#endif
+}
+
+/* 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
+ read_secondary_line to read here documents. */
+static char *
+read_a_line (remove_quoted_newline)
+ int remove_quoted_newline;
+{
+ static char *line_buffer = (char *)NULL;
+ static int buffer_size = 0;
+ int indx, c, peekc, pass_next;
+
+#if defined (READLINE)
+ if (no_line_editing && SHOULD_PROMPT ())
+#else
+ if (SHOULD_PROMPT ())
+#endif
+ print_prompt ();
+
+ pass_next = indx = 0;
+ while (1)
+ {
+ /* Allow immediate exit if interrupted during input. */
+ QUIT;
+
+ c = yy_getc ();
+
+ /* Ignore null bytes in input. */
+ if (c == 0)
+ {
+#if 0
+ internal_warning ("read_a_line: ignored null byte in input");
+#endif
+ continue;
+ }
+
+ /* 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. */
+ 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,
+ the line will be expanded as if it were in double quotes.
+ We allow a backslash to escape the next character, but we
+ need to treat the backslash specially only if a backslash
+ quoting a backslash-newline pair appears in the line. */
+ if (pass_next)
+ {
+ line_buffer[indx++] = c;
+ pass_next = 0;
+ }
+ else if (c == '\\' && remove_quoted_newline)
+ {
+ QUIT;
+ peekc = yy_getc ();
+ if (peekc == '\n')
+ {
+ line_number++;
+ continue; /* Make the unquoted \<newline> pair disappear. */
+ }
+ else
+ {
+ yy_ungetc (peekc);
+ pass_next = 1;
+ line_buffer[indx++] = c; /* Preserve the backslash. */
+ }
+ }
+ else
+ line_buffer[indx++] = c;
+
+ if (c == '\n')
+ {
+ line_buffer[indx] = '\0';
+ return (line_buffer);
+ }
+ }
+}
+
+/* Return a line as in read_a_line (), but insure that the prompt is
+ the secondary prompt. This is used to read the lines of a here
+ document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove
+ newlines quoted with backslashes while reading the line. It is
+ non-zero unless the delimiter of the here document was quoted. */
+char *
+read_secondary_line (remove_quoted_newline)
+ int remove_quoted_newline;
+{
+ char *ret;
+ int n, c;
+
+ prompt_string_pointer = &ps2_prompt;
+ if (SHOULD_PROMPT())
+ prompt_again ();
+ ret = read_a_line (remove_quoted_newline);
+#if defined (HISTORY)
+ if (ret && remember_on_history && (parser_state & PST_HEREDOC))
+ {
+ /* To make adding the the here-document body right, we need to rely
+ on history_delimiting_chars() returning \n for the first line of
+ the here-document body and the null string for the second and
+ subsequent lines, so we avoid double newlines.
+ current_command_line_count == 2 for the first line of the body. */
+
+ current_command_line_count++;
+ maybe_add_history (ret);
+ }
+#endif /* HISTORY */
+ return ret;
+}
+
+/* **************************************************************** */
+/* */
+/* YYLEX () */
+/* */
+/* **************************************************************** */
+
+/* Reserved words. These are only recognized as the first word of a
+ command. */
+STRING_INT_ALIST word_token_alist[] = {
+ { "if", IF },
+ { "then", THEN },
+ { "else", ELSE },
+ { "elif", ELIF },
+ { "fi", FI },
+ { "case", CASE },
+ { "esac", ESAC },
+ { "for", FOR },
+#if defined (SELECT_COMMAND)
+ { "select", SELECT },
+#endif
+ { "while", WHILE },
+ { "until", UNTIL },
+ { "do", DO },
+ { "done", DONE },
+ { "in", IN },
+ { "function", FUNCTION },
+#if defined (COMMAND_TIMING)
+ { "time", TIME },
+#endif
+ { "{", '{' },
+ { "}", '}' },
+ { "!", BANG },
+#if defined (COND_COMMAND)
+ { "[[", COND_START },
+ { "]]", COND_END },
+#endif
+#if defined (COPROCESS_SUPPORT)
+ { "coproc", COPROC },
+#endif
+ { (char *)NULL, 0}
+};
+
+/* other tokens that can be returned by read_token() */
+STRING_INT_ALIST other_token_alist[] = {
+ /* Multiple-character tokens with special values */
+ { "-p", TIMEOPT },
+ { "&&", AND_AND },
+ { "||", OR_OR },
+ { ">>", GREATER_GREATER },
+ { "<<", LESS_LESS },
+ { "<&", LESS_AND },
+ { ">&", GREATER_AND },
+ { ";;", SEMI_SEMI },
+ { ";&", SEMI_AND },
+ { ";;&", SEMI_SEMI_AND },
+ { "<<-", LESS_LESS_MINUS },
+ { "<<<", LESS_LESS_LESS },
+ { "&>", AND_GREATER },
+ { "&>>", AND_GREATER_GREATER },
+ { "<>", LESS_GREATER },
+ { ">|", GREATER_BAR },
+ { "|&", BAR_AND },
+ { "EOF", yacc_EOF },
+ /* Tokens whose value is the character itself */
+ { ">", '>' },
+ { "<", '<' },
+ { "-", '-' },
+ { "{", '{' },
+ { "}", '}' },
+ { ";", ';' },
+ { "(", '(' },
+ { ")", ')' },
+ { "|", '|' },
+ { "&", '&' },
+ { "newline", '\n' },
+ { (char *)NULL, 0}
+};
+
+/* others not listed here:
+ WORD look at yylval.word
+ ASSIGNMENT_WORD look at yylval.word
+ NUMBER look at yylval.number
+ ARITH_CMD look at yylval.word_list
+ ARITH_FOR_EXPRS look at yylval.word_list
+ COND_CMD look at yylval.command
+*/
+
+/* 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 = (char *)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. */
+
+/* This implements one-character lookahead/lookbehind across physical input
+ lines, to avoid something being lost because it's pushed back with
+ shell_ungetc when we're at the start of a line. */
+static int eol_ungetc_lookahead = 0;
+
+static int
+shell_getc (remove_quoted_newline)
+ int remove_quoted_newline;
+{
+ register int i;
+ int c;
+ unsigned char uc;
+
+ QUIT;
+
+ if (sigwinch_received)
+ {
+ sigwinch_received = 0;
+ get_new_window_size (0, (int *)0, (int *)0);
+ }
+
+ if (eol_ungetc_lookahead)
+ {
+ c = eol_ungetc_lookahead;
+ eol_ungetc_lookahead = 0;
+ return (c);
+ }
+
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+ /* If shell_input_line[shell_input_line_index] == 0, but there is
+ something on the pushed list of strings, then we don't want to go
+ off and get another line. We let the code down below handle it. */
+
+ if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) &&
+ (pushed_string_list == (STRING_SAVER *)NULL)))
+#else /* !ALIAS && !DPAREN_ARITHMETIC */
+ if (!shell_input_line || !shell_input_line[shell_input_line_index])
+#endif /* !ALIAS && !DPAREN_ARITHMETIC */
+ {
+ line_number++;
+
+ restart_read:
+
+ /* Allow immediate exit if interrupted during input. */
+ QUIT;
+
+ i = 0;
+ shell_input_line_terminator = 0;
+
+ /* If the shell is interatctive, but not currently printing a prompt
+ (interactive_shell && interactive == 0), we don't want to print
+ notifies or cleanup the jobs -- we want to defer it until we do
+ print the next prompt. */
+ if (interactive_shell == 0 || SHOULD_PROMPT())
+ {
+#if defined (JOB_CONTROL)
+ /* This can cause a problem when reading a command as the result
+ of a trap, when the trap is called from flush_child. This call
+ had better not cause jobs to disappear from the job table in
+ that case, or we will have big trouble. */
+ notify_and_cleanup ();
+#else /* !JOB_CONTROL */
+ cleanup_dead_jobs ();
+#endif /* !JOB_CONTROL */
+ }
+
+#if defined (READLINE)
+ if (no_line_editing && SHOULD_PROMPT())
+#else
+ if (SHOULD_PROMPT())
+#endif
+ print_prompt ();
+
+ if (bash_input.type == st_stream)
+ clearerr (stdin);
+
+ while (1)
+ {
+ c = yy_getc ();
+
+ /* Allow immediate exit if interrupted during input. */
+ QUIT;
+
+ if (c == '\0')
+ {
+#if 0
+ internal_warning ("shell_getc: ignored null byte in input");
+#endif
+ continue;
+ }
+
+ 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 == 0)
+ shell_input_line_terminator = EOF;
+
+ shell_input_line[i] = '\0';
+ break;
+ }
+
+ shell_input_line[i++] = c;
+
+ if (c == '\n')
+ {
+ shell_input_line[--i] = '\0';
+ current_command_line_count++;
+ break;
+ }
+ }
+
+ shell_input_line_index = 0;
+ shell_input_line_len = i; /* == strlen (shell_input_line) */
+
+ set_line_mbstate ();
+
+#if defined (HISTORY)
+ 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
+ if (expansions != shell_input_line)
+ {
+ free (shell_input_line);
+ shell_input_line = expansions;
+ shell_input_line_len = shell_input_line ?
+ strlen (shell_input_line) : 0;
+ if (shell_input_line_len == 0)
+ current_command_line_count--;
+
+ /* We have to force the xrealloc below because we don't know
+ the true allocated size of shell_input_line anymore. */
+ shell_input_line_size = shell_input_line_len;
+
+ set_line_mbstate ();
+ }
+ }
+ /* Try to do something intelligent with blank lines encountered while
+ entering multi-line commands. XXX - this is grotesque */
+ else if (remember_on_history && shell_input_line &&
+ shell_input_line[0] == '\0' &&
+ current_command_line_count > 1)
+ {
+ if (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);
+ else
+ {
+ char *hdcs;
+ hdcs = history_delimiting_chars ();
+ if (hdcs && hdcs[0] == ';')
+ maybe_add_history (shell_input_line);
+ }
+ }
+
+#endif /* HISTORY */
+
+ if (shell_input_line)
+ {
+ /* Lines that signify the end of the shell's input should not be
+ echoed. */
+ if (echo_input_at_read && (shell_input_line[0] ||
+ shell_input_line_terminator != EOF))
+ fprintf (stderr, "%s\n", shell_input_line);
+ }
+ else
+ {
+ shell_input_line_size = 0;
+ prompt_string_pointer = ¤t_prompt_string;
+ if (SHOULD_PROMPT ())
+ prompt_again ();
+ goto restart_read;
+ }
+
+ /* Add the newline to the end of this string, iff the string does
+ not already end in an EOF character. */
+ if (shell_input_line_terminator != EOF)
+ {
+ if (shell_input_line_len + 3 > shell_input_line_size)
+ shell_input_line = (char *)xrealloc (shell_input_line,
+ 1 + (shell_input_line_size += 2));
+
+ shell_input_line[shell_input_line_len] = '\n';
+ shell_input_line[shell_input_line_len + 1] = '\0';
+
+ set_line_mbstate ();
+ }
+ }
+
+next_alias_char:
+ uc = shell_input_line[shell_input_line_index];
+
+ if (uc)
+ shell_input_line_index++;
+
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+ /* If UC is NULL, we have reached the end of the current input string. If
+ pushed_string_list is non-empty, it's time to pop to the previous string
+ because we have fully consumed the result of the last alias expansion.
+ Do it transparently; just return the next character of the string popped
+ to. */
+pop_alias:
+ if (uc == 0 && (pushed_string_list != (STRING_SAVER *)NULL))
+ {
+ pop_string ();
+ uc = shell_input_line[shell_input_line_index];
+ if (uc)
+ shell_input_line_index++;
+ }
+#endif /* ALIAS || DPAREN_ARITHMETIC */
+
+ if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
+ {
+ if (SHOULD_PROMPT ())
+ prompt_again ();
+ line_number++;
+ /* What do we do here if we're expanding an alias whose definition
+ includes an escaped newline? If that's the last character in the
+ alias expansion, we just pop the pushed string list (recall that
+ we inhibit the appending of a space in mk_alexpansion() if newline
+ is the last character). If it's not the last character, we need
+ to consume the quoted newline and move to the next character in
+ the expansion. */
+ if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0')
+ {
+ uc = 0;
+ goto pop_alias;
+ }
+ else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0')
+ {
+ shell_input_line_index++; /* skip newline */
+ goto next_alias_char; /* and get next character */
+ }
+ else
+ goto restart_read;
+ }
+
+ if (uc == 0 && shell_input_line_terminator == EOF)
+ return ((shell_input_line_index != 0) ? '\n' : EOF);
+
+ return (uc);
+}
+
+/* Put C back into the input for the shell. This might need changes for
+ HANDLE_MULTIBYTE around EOLs. Since we (currently) never push back a
+ character different than we read, shell_input_line_property doesn't need
+ to change when manipulating shell_input_line. The define for
+ last_shell_getc_is_singlebyte should take care of it, though. */
+static void
+shell_ungetc (c)
+ int c;
+{
+ if (shell_input_line && shell_input_line_index)
+ shell_input_line[--shell_input_line_index] = c;
+ else
+ eol_ungetc_lookahead = c;
+}
+
+#ifdef INCLUDE_UNUSED
+/* Back the input pointer up by one, effectively `ungetting' a character. */
+static void
+shell_ungetchar ()
+{
+ if (shell_input_line && shell_input_line_index)
+ shell_input_line_index--;
+}
+#endif
+
+/* Discard input until CHARACTER is seen, then push that character back
+ onto the input stream. */
+static void
+discard_until (character)
+ int character;
+{
+ int c;
+
+ while ((c = shell_getc (0)) != EOF && c != character)
+ ;
+
+ if (c != EOF)
+ shell_ungetc (c);
+}
+
+void
+execute_variable_command (command, vname)
+ char *command, *vname;
+{
+ char *last_lastarg;
+ sh_parser_state_t ps;
+
+ save_parser_state (&ps);
+ last_lastarg = get_string_value ("_");
+ if (last_lastarg)
+ last_lastarg = savestring (last_lastarg);
+
+ parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST);
+
+ restore_parser_state (&ps);
+ bind_variable ("_", last_lastarg, 0);
+ FREE (last_lastarg);
+
+ 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
+#define prompt_is_ps1 \
+ (!prompt_string_pointer || prompt_string_pointer == &ps1_prompt)
+
+/* 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 == 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
+ is the mail alarm reset; nothing takes place in check_mail ()
+ except the checking of mail. Please don't change this. */
+ if (prompt_is_ps1 && time_to_check_mail ())
+ {
+ check_mail ();
+ reset_mail_timer ();
+ }
+
+ /* Avoid printing a prompt if we're not going to read anything, e.g.
+ after resetting the parser with read_token (RESET). */
+ if (token_to_read == 0 && SHOULD_PROMPT ())
+ prompt_again ();
+ }
+
+ two_tokens_ago = token_before_that;
+ token_before_that = last_read_token;
+ last_read_token = current_token;
+ current_token = read_token (READ);
+
+ if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token)
+ {
+ current_token = yacc_EOF;
+ if (bash_input.type == st_string)
+ rewind_input_string ();
+ }
+ parser_state &= ~PST_EOFTOKEN;
+
+ return (current_token);
+}
+
+/* When non-zero, we have read the required tokens
+ which allow ESAC to be the next one read. */
+static int esacs_needed_count;
+
+void
+gather_here_documents ()
+{
+ int r;
+
+ r = 0;
+ while (need_here_doc)
+ {
+ parser_state |= PST_HEREDOC;
+ make_here_document (redir_stack[r++], line_number);
+ parser_state &= ~PST_HEREDOC;
+ need_here_doc--;
+ }
+}
+
+/* When non-zero, an open-brace used to create a group is awaiting a close
+ brace partner. */
+static int open_brace_count;
+
+#define command_token_position(token) \
+ (((token) == ASSIGNMENT_WORD) || (parser_state&PST_REDIRLIST) || \
+ ((token) != SEMI_SEMI && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && reserved_word_acceptable(token)))
+
+#define assignment_acceptable(token) \
+ (command_token_position(token) && ((parser_state & PST_CASEPAT) == 0))
+
+/* Check to see if TOKEN is a reserved word and return the token
+ value if it is. */
+#define CHECK_FOR_RESERVED_WORD(tok) \
+ do { \
+ if (!dollar_present && !quoted && \
+ reserved_word_acceptable (last_read_token)) \
+ { \
+ int i; \
+ for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \
+ if (STREQ (tok, word_token_alist[i].word)) \
+ { \
+ if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \
+ break; \
+ if (word_token_alist[i].token == TIME && time_command_acceptable () == 0) \
+ break; \
+ if (word_token_alist[i].token == ESAC) \
+ 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 == COND_END) \
+ parser_state &= ~(PST_CONDCMD|PST_CONDEXPR); \
+ else if (word_token_alist[i].token == COND_START) \
+ parser_state |= PST_CONDCMD; \
+ 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)
+
+#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 EXPAND_ALIASES is set, 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 char *
+mk_alexpansion (s)
+ char *s;
+{
+ int l;
+ char *r;
+
+ l = strlen (s);
+ r = xmalloc (l + 2);
+ strcpy (r, s);
+ /* If the last character in the alias is a newline, don't add a trailing
+ space to the expansion. Works with shell_getc above. */
+ if (r[l - 1] != ' ' && r[l - 1] != '\n')
+ r[l++] = ' ';
+ r[l] = '\0';
+ return r;
+}
+
+static int
+alias_expand_token (tokstr)
+ char *tokstr;
+{
+ char *expanded;
+ alias_t *ap;
+
+ if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) &&
+ (parser_state & PST_CASEPAT) == 0)
+ {
+ ap = find_alias (tokstr);
+
+ /* Currently expanding this token. */
+ if (ap && (ap->flags & AL_BEINGEXPANDED))
+ return (NO_EXPANSION);
+
+ /* mk_alexpansion puts an extra space on the end of the alias expansion,
+ so the lookahead by the parser works right. If this gets changed,
+ make sure the code in shell_getc that deals with reaching the end of
+ an expanded alias is changed with it. */
+ expanded = ap ? mk_alexpansion (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 */
+
+static int
+time_command_acceptable ()
+{
+#if defined (COMMAND_TIMING)
+ switch (last_read_token)
+ {
+ case 0:
+ case ';':
+ case '\n':
+ case AND_AND:
+ case OR_OR:
+ case '&':
+ case DO:
+ case THEN:
+ case ELSE:
+ case '{': /* } */
+ case '(': /* ) */
+ return 1;
+ default:
+ return 0;
+ }
+#else
+ return 0;
+#endif /* COMMAND_TIMING */
+}
+
+/* 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, or if we just parsed an arithmetic
+ `for' command.
+
+ `}' is recognized if there is an unclosed `{' present.
+
+ `-p' is returned as TIMEOPT if the last read token was TIME.
+
+ ']]' is returned as COND_END if the parser is currently parsing
+ a conditional expression ((parser_state & PST_CONDEXPR) != 0)
+
+ `time' is returned as TIME if and only if it is immediately
+ preceded by one of `;', `\n', `||', `&&', or `&'.
+*/
+
+static int
+special_case_tokens (tokstr)
+ char *tokstr;
+{
+ 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
+ (tokstr[0] == 'i' && tokstr[1] == 'n' && tokstr[2] == 0))
+ {
+ if (token_before_that == CASE)
+ {
+ parser_state |= PST_CASEPAT;
+ esacs_needed_count++;
+ }
+ return (IN);
+ }
+
+ if (last_read_token == WORD &&
+#if defined (SELECT_COMMAND)
+ (token_before_that == FOR || token_before_that == SELECT) &&
+#else
+ (token_before_that == FOR) &&
+#endif
+ (tokstr[0] == 'd' && tokstr[1] == 'o' && tokstr[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 (tokstr, "esac"))
+ {
+ parser_state &= ~PST_CASEPAT;
+ return (ESAC);
+ }
+ }
+
+ /* The start of a shell function definition. */
+ if (parser_state & PST_ALLOWOPNBRC)
+ {
+ parser_state &= ~PST_ALLOWOPNBRC;
+ if (tokstr[0] == '{' && tokstr[1] == '\0') /* } */
+ {
+ open_brace_count++;
+ function_bstart = line_number;
+ return ('{'); /* } */
+ }
+ }
+
+ /* We allow a `do' after a for ((...)) without an intervening
+ list_terminator */
+ if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == 'd' && tokstr[1] == 'o' && !tokstr[2])
+ return (DO);
+ if (last_read_token == ARITH_FOR_EXPRS && tokstr[0] == '{' && tokstr[1] == '\0') /* } */
+ {
+ open_brace_count++;
+ return ('{'); /* } */
+ }
+
+ if (open_brace_count && reserved_word_acceptable (last_read_token) && tokstr[0] == '}' && !tokstr[1])
+ {
+ open_brace_count--; /* { */
+ return ('}');
+ }
+
+#if defined (COMMAND_TIMING)
+ /* Handle -p after `time'. */
+ if (last_read_token == TIME && tokstr[0] == '-' && tokstr[1] == 'p' && !tokstr[2])
+ return (TIMEOPT);
+#endif
+
+#if 0
+#if defined (COMMAND_TIMING)
+ if (STREQ (token, "time") && ((parser_state & PST_CASEPAT) == 0) && time_command_acceptable ())
+ return (TIME);
+#endif /* COMMAND_TIMING */
+#endif
+
+#if defined (COND_COMMAND) /* [[ */
+ if ((parser_state & PST_CONDEXPR) && tokstr[0] == ']' && tokstr[1] == ']' && tokstr[2] == '\0')
+ return (COND_END);
+#endif
+
+ 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;
+
+#if defined (EXTENDED_GLOB)
+ /* Reset to global value of extended glob */
+ if (parser_state & PST_EXTPAT)
+ extended_glob = global_extglob;
+#endif
+
+ parser_state = 0;
+
+#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
+ if (pushed_string_list)
+ free_string_list ();
+#endif /* ALIAS || DPAREN_ARITHMETIC */
+
+ 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;
+
+ current_token = '\n'; /* XXX */
+ 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)
+ {
+ result = token_to_read;
+ if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD)
+ {
+ yylval.word = word_desc_to_read;
+ word_desc_to_read = (WORD_DESC *)NULL;
+ }
+ token_to_read = 0;
+ return (result);
+ }
+
+#if defined (COND_COMMAND)
+ if ((parser_state & (PST_CONDCMD|PST_CONDEXPR)) == PST_CONDCMD)
+ {
+ cond_lineno = line_number;
+ parser_state |= PST_CONDEXPR;
+ yylval.command = parse_cond_command ();
+ if (cond_token != COND_END)
+ {
+ cond_error ();
+ return (-1);
+ }
+ token_to_read = COND_END;
+ parser_state &= ~(PST_CONDEXPR|PST_CONDCMD);
+ return (COND_CMD);
+ }
+#endif
+
+#if defined (ALIAS)
+ /* 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 && shellblank (character))
+ ;
+
+ if (character == EOF)
+ {
+ EOF_Reached = 1;
+ return (yacc_EOF);
+ }
+
+ if MBTEST(character == '#' && (!interactive || interactive_comments))
+ {
+ /* A comment. Discard until EOL or EOF, and then return a newline. */
+ discard_until ('\n');
+ shell_getc (0);
+ character = '\n'; /* this will take the next if statement and return. */
+ }
+
+ if (character == '\n')
+ {
+ /* If we're about to return an unquoted newline, we can go and collect
+ the text of any pending here document. */
+ if (need_here_doc)
+ gather_here_documents ();
+
+#if defined (ALIAS)
+ parser_state &= ~PST_ALEXPNEXT;
+#endif /* ALIAS */
+
+ parser_state &= ~PST_ASSIGNOK;
+
+ return (character);
+ }
+
+ if (parser_state & PST_REGEXP)
+ goto tokword;
+
+ /* Shell meta-characters. */
+ if MBTEST(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 == '>')
+ parser_state &= ~PST_ALEXPNEXT;
+#endif /* ALIAS */
+
+ parser_state &= ~PST_ASSIGNOK;
+
+ 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. */
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '-')
+ return (LESS_LESS_MINUS);
+ else if MBTEST(peek_char == '<')
+ return (LESS_LESS_LESS);
+ else
+ {
+ shell_ungetc (peek_char);
+ return (LESS_LESS);
+ }
+
+ case '>':
+ return (GREATER_GREATER);
+
+ case ';':
+ parser_state |= PST_CASEPAT;
+#if defined (ALIAS)
+ parser_state &= ~PST_ALEXPNEXT;
+#endif /* ALIAS */
+
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '&')
+ return (SEMI_SEMI_AND);
+ else
+ {
+ shell_ungetc (peek_char);
+ return (SEMI_SEMI);
+ }
+
+ case '&':
+ return (AND_AND);
+
+ case '|':
+ return (OR_OR);
+
+#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
+ case '(': /* ) */
+ result = parse_dparen (character);
+ if (result == -2)
+ break;
+ else
+ return result;
+#endif
+ }
+ }
+ else if MBTEST(character == '<' && peek_char == '&')
+ return (LESS_AND);
+ else if MBTEST(character == '>' && peek_char == '&')
+ return (GREATER_AND);
+ else if MBTEST(character == '<' && peek_char == '>')
+ return (LESS_GREATER);
+ else if MBTEST(character == '>' && peek_char == '|')
+ return (GREATER_BAR);
+ else if MBTEST(character == '&' && peek_char == '>')
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '>')
+ return (AND_GREATER_GREATER);
+ else
+ {
+ shell_ungetc (peek_char);
+ return (AND_GREATER);
+ }
+ }
+ else if MBTEST(character == '|' && peek_char == '&')
+ return (BAR_AND);
+ else if MBTEST(character == ';' && peek_char == '&')
+ {
+ parser_state |= PST_CASEPAT;
+#if defined (ALIAS)
+ parser_state &= ~PST_ALEXPNEXT;
+#endif /* ALIAS */
+ return (SEMI_AND);
+ }
+
+ 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 MBTEST(character == ')' && last_read_token == '(' && token_before_that == WORD)
+ {
+ parser_state |= PST_ALLOWOPNBRC;
+#if defined (ALIAS)
+ parser_state &= ~PST_ALEXPNEXT;
+#endif /* ALIAS */
+ function_dstart = line_number;
+ }
+
+ /* 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 MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */
+ parser_state |= PST_SUBSHELL;
+ /*(*/
+ else if MBTEST((parser_state & PST_CASEPAT) && character == ')')
+ parser_state &= ~PST_CASEPAT;
+ /*(*/
+ else if MBTEST((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 MBTEST(posixly_correct || ((character != '>' && character != '<') || peek_char != '(')) /*)*/
+#endif /* PROCESS_SUBSTITUTION */
+ return (character);
+ }
+
+ /* Hack <&- (close stdin) case. Also <&N- (dup and close). */
+ if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
+ return (character);
+
+tokword:
+ /* Okay, if we got this far, we have to read a word. Read one,
+ and then check it against the known ones. */
+ result = read_token_word (character);
+#if defined (ALIAS)
+ if (result == RE_READ_TOKEN)
+ goto re_read_token;
+#endif
+ return result;
+}
+
+/*
+ * 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.
+ */
+#define P_FIRSTCLOSE 0x01
+#define P_ALLOWESC 0x02
+#define P_DQUOTE 0x04
+#define P_COMMAND 0x08 /* parsing a command, so look for comments */
+#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */
+#define P_ARRAYSUB 0x20 /* parsing a [...] array subscript for assignment */
+
+/* Lexical state while parsing a grouping construct or $(...). */
+#define LEX_WASDOL 0x001
+#define LEX_CKCOMMENT 0x002
+#define LEX_INCOMMENT 0x004
+#define LEX_PASSNEXT 0x008
+#define LEX_RESWDOK 0x010
+#define LEX_CKCASE 0x020
+#define LEX_INCASE 0x040
+#define LEX_INHEREDOC 0x080
+#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */
+#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */
+#define LEX_INWORD 0x400
+
+#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|')
+
+#define CHECK_NESTRET_ERROR() \
+ do { \
+ if (nestret == &matched_pair_error) \
+ { \
+ free (ret); \
+ return &matched_pair_error; \
+ } \
+ } while (0)
+
+#define APPEND_NESTRET() \
+ do { \
+ if (nestlen) \
+ { \
+ RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \
+ strcpy (ret + retind, nestret); \
+ retind += nestlen; \
+ } \
+ } while (0)
+
+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, tflags;
+ int nestlen, ttranslen, start_lineno;
+ char *ret, *nestret, *ttrans;
+ int retind, retsize, rflags;
+
+/*itrace("parse_matched_pair[%d]: open = %c close = %c flags = %d", line_number, open, close, flags);*/
+ count = 1;
+ tflags = 0;
+
+ if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0)
+ tflags |= LEX_CKCOMMENT;
+
+ /* RFLAGS is the set of flags we want to pass to recursive calls. */
+ rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE);
+
+ ret = (char *)xmalloc (retsize = 64);
+ retind = 0;
+
+ start_lineno = line_number;
+ while (count)
+ {
+ ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 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);
+ }
+
+ /* Possible reprompting. */
+ if (ch == '\n' && SHOULD_PROMPT ())
+ prompt_again ();
+
+ /* Don't bother counting parens or doing anything else if in a comment
+ or part of a case statement */
+ if (tflags & LEX_INCOMMENT)
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+
+ if (ch == '\n')
+ tflags &= ~LEX_INCOMMENT;
+
+ continue;
+ }
+
+ /* Not exactly right yet, should handle shell metacharacters, too. If
+ any changes are made to this test, make analogous changes to subst.c:
+ extract_delimited_string(). */
+ else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
+ tflags |= LEX_INCOMMENT;
+
+ if (tflags & LEX_PASSNEXT) /* last char was backslash */
+ {
+ tflags &= ~LEX_PASSNEXT;
+ if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
+ {
+ if (retind > 0)
+ retind--; /* swallow previously-added backslash */
+ continue;
+ }
+
+ RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+ if MBTEST(ch == CTLESC || ch == CTLNUL)
+ ret[retind++] = CTLESC;
+ ret[retind++] = ch;
+ continue;
+ }
+ /* If we're reparsing the input (e.g., from parse_string_to_word_list),
+ we've already prepended CTLESC to single-quoted results of $'...'.
+ We may want to do this for other CTLESC-quoted characters in
+ reparse, too. */
+ else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL))
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+ continue;
+ }
+ else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+ ret[retind++] = CTLESC;
+ ret[retind++] = ch;
+ continue;
+ }
+ else if MBTEST(ch == close) /* ending delimiter */
+ count--;
+ /* handle nested ${...} specially. */
+ else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */
+ count++;
+ else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */
+ count++;
+
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+
+ /* If we just read the ending character, don't bother continuing. */
+ if (count == 0)
+ break;
+
+ if (open == '\'') /* '' inside grouping construct */
+ {
+ if MBTEST((flags & P_ALLOWESC) && ch == '\\')
+ tflags |= LEX_PASSNEXT;
+ continue;
+ }
+
+ if MBTEST(ch == '\\') /* backslashes */
+ tflags |= LEX_PASSNEXT;
+
+#if 0
+ /* The big hammer. Single quotes aren't special in double quotes. The
+ problem is that Posix says the single quotes are semi-special:
+ within a double-quoted ${...} construct "an even number of
+ unescaped double-quotes or single-quotes, if any, shall occur." */
+ if MBTEST(open == '{' && (flags & P_DQUOTE) && ch == '\'') /* } */
+ continue;
+#endif
+
+ /* Could also check open == '`' if we want to parse grouping constructs
+ inside old-style command substitution. */
+ if (open != close) /* a grouping construct */
+ {
+ if MBTEST(shellquote (ch))
+ {
+ /* '', ``, or "" inside $(...) or other grouping construct. */
+ push_delimiter (dstack, ch);
+ if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */
+ nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags);
+ else
+ nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags);
+ pop_delimiter (dstack);
+ CHECK_NESTRET_ERROR ();
+
+ if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
+ {
+ /* Translate $'...' here. */
+ ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
+ xfree (nestret);
+
+ if ((rflags & P_DQUOTE) == 0)
+ {
+ nestret = sh_single_quote (ttrans);
+ free (ttrans);
+ nestlen = strlen (nestret);
+ }
+ else
+ {
+ nestret = ttrans;
+ nestlen = ttranslen;
+ }
+ retind -= 2; /* back up before the $' */
+ }
+ else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
+ {
+ /* Locale expand $"..." here. */
+ ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
+ xfree (nestret);
+
+ nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ free (ttrans);
+ nestlen = ttranslen + 2;
+ retind -= 2; /* back up before the $" */
+ }
+
+ APPEND_NESTRET ();
+ FREE (nestret);
+ }
+ else if ((flags & P_ARRAYSUB) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
+ goto parse_dollar_word;
+ }
+ /* Parse an old-style command substitution within double quotes as a
+ single word. */
+ /* XXX - sh and ksh93 don't do this - XXX */
+ else if MBTEST(open == '"' && ch == '`')
+ {
+ nestret = parse_matched_pair (0, '`', '`', &nestlen, rflags);
+
+ CHECK_NESTRET_ERROR ();
+ APPEND_NESTRET ();
+
+ FREE (nestret);
+ }
+ else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
+ /* check for $(), $[], or ${} inside quoted string. */
+ {
+parse_dollar_word:
+ if (open == ch) /* undo previous increment */
+ count--;
+ if (ch == '(') /* ) */
+ nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
+ else if (ch == '{') /* } */
+ nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
+ else if (ch == '[') /* ] */
+ nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
+
+ CHECK_NESTRET_ERROR ();
+ APPEND_NESTRET ();
+
+ FREE (nestret);
+ }
+ if MBTEST(ch == '$')
+ tflags |= LEX_WASDOL;
+ else
+ tflags &= ~LEX_WASDOL;
+ }
+
+ ret[retind] = '\0';
+ if (lenp)
+ *lenp = retind;
+/*itrace("parse_matched_pair[%d]: returning %s", line_number, ret);*/
+ return ret;
+}
+
+/* Parse a $(...) command substitution. This is messier than I'd like, and
+ reproduces a lot more of the token-reading code than I'd like. */
+static char *
+parse_comsub (qc, open, close, lenp, flags)
+ int qc; /* `"' if this construct is within double quotes */
+ int open, close;
+ int *lenp, flags;
+{
+ int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind;
+ int nestlen, ttranslen, start_lineno;
+ char *ret, *nestret, *ttrans, *heredelim;
+ int retind, retsize, rflags, hdlen;
+
+#if 0 /* XXX - bash-4.2 -- jwm@horde.net */
+ /* Assume $(( introduces arithmetic command and parse accordingly. */
+ peekc = shell_getc (0);
+ shell_ungetc (peekc);
+ if (peekc == '(')
+ return (parse_matched_pair (qc, open, close, lenp, 0));
+#endif
+
+/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/
+ count = 1;
+ tflags = LEX_RESWDOK;
+
+ if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0)
+ tflags |= LEX_CKCASE;
+ if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments))
+ tflags |= LEX_CKCOMMENT;
+
+ /* RFLAGS is the set of flags we want to pass to recursive calls. */
+ rflags = (flags & P_DQUOTE);
+
+ ret = (char *)xmalloc (retsize = 64);
+ retind = 0;
+
+ start_lineno = line_number;
+ lex_rwlen = lex_wlen = 0;
+
+ heredelim = 0;
+ lex_firstind = -1;
+
+ while (count)
+ {
+comsub_readchar:
+ ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+
+ if (ch == EOF)
+ {
+eof_error:
+ free (ret);
+ FREE (heredelim);
+ parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close);
+ EOF_Reached = 1; /* XXX */
+ return (&matched_pair_error);
+ }
+
+ /* If we hit the end of a line and are reading the contents of a here
+ document, and it's not the same line that the document starts on,
+ check for this line being the here doc delimiter. Otherwise, if
+ we're in a here document, mark the next character as the beginning
+ of a line. */
+ if (ch == '\n')
+ {
+ if ((tflags & LEX_HEREDELIM) && heredelim)
+ {
+ tflags &= ~LEX_HEREDELIM;
+ tflags |= LEX_INHEREDOC;
+ lex_firstind = retind + 1;
+ }
+ else if (tflags & LEX_INHEREDOC)
+ {
+ int tind;
+ tind = lex_firstind;
+ while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t')
+ tind++;
+ if (STREQN (ret + tind, heredelim, hdlen))
+ {
+ tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC);
+/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/
+ free (heredelim);
+ heredelim = 0;
+ lex_firstind = -1;
+ }
+ else
+ lex_firstind = retind + 1;
+ }
+ }
+
+ /* Possible reprompting. */
+ if (ch == '\n' && SHOULD_PROMPT ())
+ prompt_again ();
+
+ /* XXX -- possibly allow here doc to be delimited by ending right
+ paren. */
+ if ((tflags & LEX_INHEREDOC) && ch == close && count == 1)
+ {
+ int tind;
+/*itrace("parse_comsub: in here doc, ch == close, retind - firstind = %d hdlen = %d retind = %d", retind-lex_firstind, hdlen, retind);*/
+ tind = lex_firstind;
+ while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t')
+ tind++;
+ if (retind-tind == hdlen && STREQN (ret + tind, heredelim, hdlen))
+ {
+ tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC);
+/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/
+ free (heredelim);
+ heredelim = 0;
+ lex_firstind = -1;
+ }
+ }
+
+ /* Don't bother counting parens or doing anything else if in a comment */
+ if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC))
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+
+ if ((tflags & LEX_INCOMMENT) && ch == '\n')
+{
+/*itrace("parse_comsub:%d: lex_incomment -> 0 ch = `%c'", line_number, ch);*/
+ tflags &= ~LEX_INCOMMENT;
+}
+
+ continue;
+ }
+
+ if (tflags & LEX_PASSNEXT) /* last char was backslash */
+ {
+/*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ tflags &= ~LEX_PASSNEXT;
+ if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
+ {
+ if (retind > 0)
+ retind--; /* swallow previously-added backslash */
+ continue;
+ }
+
+ RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+ if MBTEST(ch == CTLESC || ch == CTLNUL)
+ ret[retind++] = CTLESC;
+ ret[retind++] = ch;
+ continue;
+ }
+
+ /* If this is a shell break character, we are not in a word. If not,
+ we either start or continue a word. */
+ if MBTEST(shellbreak (ch))
+ {
+ tflags &= ~LEX_INWORD;
+/*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ }
+ else
+ {
+ if (tflags & LEX_INWORD)
+ {
+ lex_wlen++;
+/*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/
+ }
+ else
+ {
+/*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ tflags |= LEX_INWORD;
+ lex_wlen = 0;
+ }
+ }
+
+ /* Skip whitespace */
+ if MBTEST(shellblank (ch) && lex_rwlen == 0)
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+ continue;
+ }
+
+ /* Either we are looking for the start of the here-doc delimiter
+ (lex_firstind == -1) or we are reading one (lex_firstind >= 0).
+ If this character is a shell break character and we are reading
+ the delimiter, save it and note that we are now reading a here
+ document. If we've found the start of the delimiter, note it by
+ setting lex_firstind. Backslashes can quote shell metacharacters
+ in here-doc delimiters. */
+ if (tflags & LEX_HEREDELIM)
+ {
+ if (lex_firstind == -1 && shellbreak (ch) == 0)
+ lex_firstind = retind;
+#if 0
+ else if (heredelim && (tflags & LEX_PASSNEXT) == 0 && ch == '\n')
+ {
+ tflags |= LEX_INHEREDOC;
+ tflags &= ~LEX_HEREDELIM;
+ lex_firstind = retind + 1;
+ }
+#endif
+ else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch))
+ {
+ if (heredelim == 0)
+ {
+ nestret = substring (ret, lex_firstind, retind);
+ heredelim = string_quote_removal (nestret, 0);
+ free (nestret);
+ hdlen = STRLEN(heredelim);
+/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/
+ }
+ if (ch == '\n')
+ {
+ tflags |= LEX_INHEREDOC;
+ tflags &= ~LEX_HEREDELIM;
+ lex_firstind = retind + 1;
+ }
+ else
+ lex_firstind = -1;
+ }
+ }
+
+ /* Meta-characters that can introduce a reserved word. Not perfect yet. */
+ if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && (shellmeta(ch) || ch == '\n'))
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+ peekc = shell_getc (1);
+ if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = peekc;
+/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/
+ tflags |= LEX_RESWDOK;
+ lex_rwlen = 0;
+ continue;
+ }
+ else if (ch == '\n' || COMSUB_META(ch))
+ {
+ shell_ungetc (peekc);
+/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/
+ tflags |= LEX_RESWDOK;
+ lex_rwlen = 0;
+ continue;
+ }
+ else if (ch == EOF)
+ goto eof_error;
+ else
+ {
+ /* `unget' the character we just added and fall through */
+ retind--;
+ shell_ungetc (peekc);
+ }
+ }
+
+ /* If we can read a reserved word, try to read one. */
+ if (tflags & LEX_RESWDOK)
+ {
+ if MBTEST(islower (ch))
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+ lex_rwlen++;
+ continue;
+ }
+ else if MBTEST(lex_rwlen == 4 && shellbreak (ch))
+ {
+ if (STREQN (ret + retind - 4, "case", 4))
+{
+ tflags |= LEX_INCASE;
+/*itrace("parse_comsub:%d: found `case', lex_incase -> 1 lex_reswdok -> 0", line_number);*/
+}
+ else if (STREQN (ret + retind - 4, "esac", 4))
+{
+ tflags &= ~LEX_INCASE;
+/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0 lex_reswdok -> 0", line_number);*/
+}
+ tflags &= ~LEX_RESWDOK;
+ }
+ else if MBTEST((tflags & LEX_CKCOMMENT) && ch == '#' && (lex_rwlen == 0 || ((tflags & LEX_INWORD) && lex_wlen == 0)))
+ ; /* don't modify LEX_RESWDOK if we're starting a comment */
+ else if MBTEST((tflags & LEX_INCASE) && ch != '\n')
+ /* If we can read a reserved word and we're in case, we're at the
+ point where we can read a new pattern list or an esac. We
+ handle the esac case above. If we read a newline, we want to
+ leave LEX_RESWDOK alone. If we read anything else, we want to
+ turn off LEX_RESWDOK, since we're going to read a pattern list. */
+{
+ tflags &= ~LEX_RESWDOK;
+/*itrace("parse_comsub:%d: lex_incase == 1 found `%c', lex_reswordok -> 0", line_number, ch);*/
+}
+ else if MBTEST(shellbreak (ch) == 0)
+{
+ tflags &= ~LEX_RESWDOK;
+/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/
+}
+ }
+
+ /* Might be the start of a here-doc delimiter */
+ if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<')
+ {
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+ peekc = shell_getc (1);
+ if (peekc == EOF)
+ goto eof_error;
+ if (peekc == ch)
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = peekc;
+ peekc = shell_getc (1);
+ if (peekc == EOF)
+ goto eof_error;
+ if (peekc == '-')
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = peekc;
+ tflags |= LEX_STRIPDOC;
+ }
+ else
+ shell_ungetc (peekc);
+ if (peekc != '<')
+ {
+ tflags |= LEX_HEREDELIM;
+ lex_firstind = -1;
+ }
+ continue;
+ }
+ else
+ ch = peekc; /* fall through and continue XXX */
+ }
+ else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0)))
+{
+/*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/
+ tflags |= LEX_INCOMMENT;
+}
+
+ if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */
+ {
+ RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+ ret[retind++] = CTLESC;
+ ret[retind++] = ch;
+ continue;
+ }
+#if 0
+ else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')')
+ tflags &= ~LEX_INCASE; /* XXX */
+#endif
+ else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */
+{
+ count--;
+/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/
+}
+ else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */
+{
+ count++;
+/*itrace("parse_comsub:%d: found open: count = %d", line_number, count);*/
+}
+
+ /* Add this character. */
+ RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+ ret[retind++] = ch;
+
+ /* If we just read the ending character, don't bother continuing. */
+ if (count == 0)
+ break;
+
+ if MBTEST(ch == '\\') /* backslashes */
+ tflags |= LEX_PASSNEXT;
+
+ if MBTEST(shellquote (ch))
+ {
+ /* '', ``, or "" inside $(...). */
+ push_delimiter (dstack, ch);
+ if MBTEST((tflags & LEX_WASDOL) && ch == '\'') /* $'...' inside group */
+ nestret = parse_matched_pair (ch, ch, ch, &nestlen, P_ALLOWESC|rflags);
+ else
+ nestret = parse_matched_pair (ch, ch, ch, &nestlen, rflags);
+ pop_delimiter (dstack);
+ CHECK_NESTRET_ERROR ();
+
+ if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
+ {
+ /* Translate $'...' here. */
+ ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen);
+ xfree (nestret);
+
+ if ((rflags & P_DQUOTE) == 0)
+ {
+ nestret = sh_single_quote (ttrans);
+ free (ttrans);
+ nestlen = strlen (nestret);
+ }
+ else
+ {
+ nestret = ttrans;
+ nestlen = ttranslen;
+ }
+ retind -= 2; /* back up before the $' */
+ }
+ else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0))
+ {
+ /* Locale expand $"..." here. */
+ ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
+ xfree (nestret);
+
+ nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ free (ttrans);
+ nestlen = ttranslen + 2;
+ retind -= 2; /* back up before the $" */
+ }
+
+ APPEND_NESTRET ();
+ FREE (nestret);
+ }
+ else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */
+ /* check for $(), $[], or ${} inside command substitution. */
+ {
+ if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */
+ count--;
+ if (ch == '(') /* ) */
+ nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE);
+ else if (ch == '{') /* } */
+ nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags);
+ else if (ch == '[') /* ] */
+ nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags);
+
+ CHECK_NESTRET_ERROR ();
+ APPEND_NESTRET ();
+
+ FREE (nestret);
+ }
+ if MBTEST(ch == '$')
+ tflags |= LEX_WASDOL;
+ else
+ tflags &= ~LEX_WASDOL;
+ }
+
+ FREE (heredelim);
+ ret[retind] = '\0';
+ if (lenp)
+ *lenp = retind;
+/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/
+ return ret;
+}
+
+/* XXX - this needs to handle functionality like subst.c:no_longjmp_on_fatal_error;
+ maybe extract_command_subst should handle it. */
+char *
+xparse_dolparen (base, string, indp, flags)
+ char *base;
+ char *string;
+ int *indp;
+ int flags;
+{
+ sh_parser_state_t ps;
+ int orig_ind, nc, sflags;
+ char *ret, *s, *ep, *ostring;
+
+ /*yydebug = 1;*/
+ orig_ind = *indp;
+ ostring = string;
+
+ sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
+ if (flags & SX_NOLONGJMP)
+ sflags |= SEVAL_NOLONGJMP;
+ save_parser_state (&ps);
+
+ /*(*/
+ parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/
+ shell_eof_token = ')';
+ parse_string (string, "command substitution", sflags, &ep);
+
+ restore_parser_state (&ps);
+ reset_parser ();
+ if (interactive)
+ token_to_read = 0;
+
+ /* Need to find how many characters parse_and_execute consumed, update
+ *indp, if flags != 0, copy the portion of the string parsed into RET
+ and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */
+
+ /*(*/
+ if (ep[-1] != ')')
+ {
+#if DEBUG
+ if (ep[-1] != '\n')
+ itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep);
+#endif
+ while (ep > ostring && ep[-1] == '\n') ep--;
+ }
+
+ nc = ep - ostring;
+ *indp = ep - base - 1;
+
+ /*(*/
+#if DEBUG
+ if (base[*indp] != ')')
+ itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base);
+#endif
+
+ if (flags & SX_NOALLOC)
+ return (char *)NULL;
+
+ if (nc == 0)
+ {
+ ret = xmalloc (1);
+ ret[0] = '\0';
+ }
+ else
+ ret = substring (ostring, 0, nc - 1);
+
+ return ret;
+}
+
+#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
+/* Parse a double-paren construct. It can be either an arithmetic
+ command, an arithmetic `for' command, or a nested subshell. Returns
+ the parsed token, -1 on error, or -2 if we didn't do anything and
+ should just go on. */
+static int
+parse_dparen (c)
+ int c;
+{
+ int cmdtyp, sline;
+ char *wval;
+ WORD_DESC *wd;
+
+#if defined (ARITH_FOR_COMMAND)
+ if (last_read_token == FOR)
+ {
+ arith_for_lineno = line_number;
+ cmdtyp = parse_arith_cmd (&wval, 0);
+ if (cmdtyp == 1)
+ {
+ wd = alloc_word_desc ();
+ wd->word = wval;
+ yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
+ return (ARITH_FOR_EXPRS);
+ }
+ else
+ return -1; /* ERROR */
+ }
+#endif
+
+#if defined (DPAREN_ARITHMETIC)
+ if (reserved_word_acceptable (last_read_token))
+ {
+ sline = line_number;
+
+ cmdtyp = parse_arith_cmd (&wval, 0);
+ if (cmdtyp == 1) /* arithmetic command */
+ {
+ wd = alloc_word_desc ();
+ wd->word = wval;
+ wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
+ yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
+ return (ARITH_CMD);
+ }
+ else if (cmdtyp == 0) /* nested subshell */
+ {
+ push_string (wval, 0, (alias_t *)NULL);
+ if ((parser_state & PST_CASEPAT) == 0)
+ parser_state |= PST_SUBSHELL;
+ return (c);
+ }
+ else /* ERROR */
+ return -1;
+ }
+#endif
+
+ return -2; /* XXX */
+}
+
+/* We've seen a `(('. Look for the matching `))'. If we get it, return 1.
+ If not, assume it's a nested subshell for backwards compatibility and
+ return 0. In any case, put the characters we've consumed into a locally-
+ allocated buffer and make *ep point to that buffer. Return -1 on an
+ error, for example EOF. */
+static int
+parse_arith_cmd (ep, adddq)
+ char **ep;
+ int adddq;
+{
+ int exp_lineno, rval, c;
+ char *ttok, *tokstr;
+ int ttoklen;
+
+ exp_lineno = line_number;
+ ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0);
+ rval = 1;
+ if (ttok == &matched_pair_error)
+ return -1;
+ /* Check that the next character is the closing right paren. If
+ not, this is a syntax error. ( */
+ c = shell_getc (0);
+ if MBTEST(c != ')')
+ rval = 0;
+
+ tokstr = (char *)xmalloc (ttoklen + 4);
+
+ /* if ADDDQ != 0 then (( ... )) -> "..." */
+ if (rval == 1 && adddq) /* arith cmd, add double quotes */
+ {
+ tokstr[0] = '"';
+ strncpy (tokstr + 1, ttok, ttoklen - 1);
+ tokstr[ttoklen] = '"';
+ tokstr[ttoklen+1] = '\0';
+ }
+ else if (rval == 1) /* arith cmd, don't add double quotes */
+ {
+ strncpy (tokstr, ttok, ttoklen - 1);
+ tokstr[ttoklen-1] = '\0';
+ }
+ else /* nested subshell */
+ {
+ tokstr[0] = '(';
+ strncpy (tokstr + 1, ttok, ttoklen - 1);
+ tokstr[ttoklen] = ')';
+ tokstr[ttoklen+1] = c;
+ tokstr[ttoklen+2] = '\0';
+ }
+
+ *ep = tokstr;
+ FREE (ttok);
+ return rval;
+}
+#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */
+
+#if defined (COND_COMMAND)
+static void
+cond_error ()
+{
+ char *etext;
+
+ if (EOF_Reached && cond_token != COND_ERROR) /* [[ */
+ parser_error (cond_lineno, _("unexpected EOF while looking for `]]'"));
+ else if (cond_token != COND_ERROR)
+ {
+ if (etext = error_token_from_token (cond_token))
+ {
+ parser_error (cond_lineno, _("syntax error in conditional expression: unexpected token `%s'"), etext);
+ free (etext);
+ }
+ else
+ parser_error (cond_lineno, _("syntax error in conditional expression"));
+ }
+}
+
+static COND_COM *
+cond_expr ()
+{
+ return (cond_or ());
+}
+
+static COND_COM *
+cond_or ()
+{
+ COND_COM *l, *r;
+
+ l = cond_and ();
+ if (cond_token == OR_OR)
+ {
+ r = cond_or ();
+ l = make_cond_node (COND_OR, (WORD_DESC *)NULL, l, r);
+ }
+ return l;
+}
+
+static COND_COM *
+cond_and ()
+{
+ COND_COM *l, *r;
+
+ l = cond_term ();
+ if (cond_token == AND_AND)
+ {
+ r = cond_and ();
+ l = make_cond_node (COND_AND, (WORD_DESC *)NULL, l, r);
+ }
+ return l;
+}
+
+static int
+cond_skip_newlines ()
+{
+ while ((cond_token = read_token (READ)) == '\n')
+ {
+ if (SHOULD_PROMPT ())
+ prompt_again ();
+ }
+ return (cond_token);
+}
+
+#define COND_RETURN_ERROR() \
+ do { cond_token = COND_ERROR; return ((COND_COM *)NULL); } while (0)
+
+static COND_COM *
+cond_term ()
+{
+ WORD_DESC *op;
+ COND_COM *term, *tleft, *tright;
+ int tok, lineno;
+ char *etext;
+
+ /* Read a token. It can be a left paren, a `!', a unary operator, or a
+ word that should be the first argument of a binary operator. Start by
+ skipping newlines, since this is a compound command. */
+ tok = cond_skip_newlines ();
+ lineno = line_number;
+ if (tok == COND_END)
+ {
+ COND_RETURN_ERROR ();
+ }
+ else if (tok == '(')
+ {
+ term = cond_expr ();
+ if (cond_token != ')')
+ {
+ if (term)
+ dispose_cond_node (term); /* ( */
+ if (etext = error_token_from_token (cond_token))
+ {
+ parser_error (lineno, _("unexpected token `%s', expected `)'"), etext);
+ free (etext);
+ }
+ else
+ parser_error (lineno, _("expected `)'"));
+ COND_RETURN_ERROR ();
+ }
+ term = make_cond_node (COND_EXPR, (WORD_DESC *)NULL, term, (COND_COM *)NULL);
+ (void)cond_skip_newlines ();
+ }
+ else if (tok == BANG || (tok == WORD && (yylval.word->word[0] == '!' && yylval.word->word[1] == '\0')))
+ {
+ if (tok == WORD)
+ dispose_word (yylval.word); /* not needed */
+ term = cond_term ();
+ if (term)
+ term->flags |= CMD_INVERT_RETURN;
+ }
+ else if (tok == WORD && yylval.word->word[0] == '-' && yylval.word->word[2] == 0 && test_unop (yylval.word->word))
+ {
+ op = yylval.word;
+ tok = read_token (READ);
+ if (tok == WORD)
+ {
+ tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
+ term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
+ }
+ else
+ {
+ dispose_word (op);
+ if (etext = error_token_from_token (tok))
+ {
+ parser_error (line_number, _("unexpected argument `%s' to conditional unary operator"), etext);
+ free (etext);
+ }
+ else
+ parser_error (line_number, _("unexpected argument to conditional unary operator"));
+ COND_RETURN_ERROR ();
+ }
+
+ (void)cond_skip_newlines ();
+ }
+ else if (tok == WORD) /* left argument to binary operator */
+ {
+ /* lhs */
+ tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
+
+ /* binop */
+ tok = read_token (READ);
+ if (tok == WORD && test_binop (yylval.word->word))
+ {
+ op = yylval.word;
+ if (op->word[0] == '=' && (op->word[1] == '\0' || (op->word[1] == '=' && op->word[2] == '\0')))
+ parser_state |= PST_EXTPAT;
+ else if (op->word[0] == '!' && op->word[1] == '=' && op->word[2] == '\0')
+ parser_state |= PST_EXTPAT;
+ }
+#if defined (COND_REGEXP)
+ else if (tok == WORD && STREQ (yylval.word->word, "=~"))
+ {
+ op = yylval.word;
+ parser_state |= PST_REGEXP;
+ }
+#endif
+ else if (tok == '<' || tok == '>')
+ op = make_word_from_token (tok); /* ( */
+ /* There should be a check before blindly accepting the `)' that we have
+ seen the opening `('. */
+ else if (tok == COND_END || tok == AND_AND || tok == OR_OR || tok == ')')
+ {
+ /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like
+ the test command. Similarly for [[ x && expr ]] or
+ [[ x || expr ]] or [[ (x) ]]. */
+ op = make_word ("-n");
+ term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL);
+ cond_token = tok;
+ return (term);
+ }
+ else
+ {
+ if (etext = error_token_from_token (tok))
+ {
+ parser_error (line_number, _("unexpected token `%s', conditional binary operator expected"), etext);
+ free (etext);
+ }
+ else
+ parser_error (line_number, _("conditional binary operator expected"));
+ dispose_cond_node (tleft);
+ COND_RETURN_ERROR ();
+ }
+
+ /* rhs */
+ if (parser_state & PST_EXTPAT)
+ extended_glob = 1;
+ tok = read_token (READ);
+ if (parser_state & PST_EXTPAT)
+ extended_glob = global_extglob;
+ parser_state &= ~(PST_REGEXP|PST_EXTPAT);
+
+ if (tok == WORD)
+ {
+ tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
+ term = make_cond_node (COND_BINARY, op, tleft, tright);
+ }
+ else
+ {
+ if (etext = error_token_from_token (tok))
+ {
+ parser_error (line_number, _("unexpected argument `%s' to conditional binary operator"), etext);
+ free (etext);
+ }
+ else
+ parser_error (line_number, _("unexpected argument to conditional binary operator"));
+ dispose_cond_node (tleft);
+ dispose_word (op);
+ COND_RETURN_ERROR ();
+ }
+
+ (void)cond_skip_newlines ();
+ }
+ else
+ {
+ if (tok < 256)
+ parser_error (line_number, _("unexpected token `%c' in conditional command"), tok);
+ else if (etext = error_token_from_token (tok))
+ {
+ parser_error (line_number, _("unexpected token `%s' in conditional command"), etext);
+ free (etext);
+ }
+ else
+ parser_error (line_number, _("unexpected token %d in conditional command"), tok);
+ COND_RETURN_ERROR ();
+ }
+ return (term);
+}
+
+/* This is kind of bogus -- we slip a mini recursive-descent parser in
+ here to handle the conditional statement syntax. */
+static COMMAND *
+parse_cond_command ()
+{
+ COND_COM *cexp;
+
+ global_extglob = extended_glob;
+ cexp = cond_expr ();
+ return (make_cond_command (cexp));
+}
+#endif
+
+#if defined (ARRAY_VARS)
+/* When this is called, it's guaranteed that we don't care about anything
+ in t beyond i. We do save and restore the chars, though. */
+static int
+token_is_assignment (t, i)
+ char *t;
+ int i;
+{
+ unsigned char c, c1;
+ int r;
+
+ c = t[i]; c1 = t[i+1];
+ t[i] = '='; t[i+1] = '\0';
+ r = assignment (t, (parser_state & PST_COMPASSIGN) != 0);
+ t[i] = c; t[i+1] = c1;
+ return r;
+}
+
+/* XXX - possible changes here for `+=' */
+static int
+token_is_ident (t, i)
+ char *t;
+ int i;
+{
+ unsigned char c;
+ int r;
+
+ c = t[i];
+ t[i] = '\0';
+ r = legal_identifier (t);
+ t[i] = c;
+ return r;
+}
+#endif
+
+static int
+read_token_word (character)
+ int character;
+{
+ /* The value for YYLVAL when a WORD is read. */
+ WORD_DESC *the_word;
+
+ /* Index into the token that we are building. */
+ int token_index;
+
+ /* ALL_DIGITS becomes zero when we see a non-digit. */
+ int all_digit_token;
+
+ /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
+ int dollar_present;
+
+ /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound
+ assignment. */
+ int compound_assignment;
+
+ /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
+ int quoted;
+
+ /* Non-zero means to ignore the value of the next character, and just
+ to add it no matter what. */
+ int pass_next_character;
+
+ /* The current delimiting character. */
+ int cd;
+ int result, peek_char;
+ char *ttok, *ttrans;
+ int ttoklen, ttranslen;
+ intmax_t lvalue;
+
+ if (token_buffer_size < TOKEN_DEFAULT_INITIAL_SIZE)
+ token = (char *)xrealloc (token, token_buffer_size = TOKEN_DEFAULT_INITIAL_SIZE);
+
+ token_index = 0;
+ all_digit_token = DIGIT (character);
+ dollar_present = quoted = pass_next_character = compound_assignment = 0;
+
+ for (;;)
+ {
+ if (character == EOF)
+ goto got_token;
+
+ if (pass_next_character)
+ {
+ pass_next_character = 0;
+ goto got_escaped_character;
+ }
+
+ cd = current_delimiter (dstack);
+
+ /* Handle backslashes. Quote lots of things when not inside of
+ double-quotes, quote some things inside of double-quotes. */
+ if MBTEST(character == '\\')
+ {
+ peek_char = shell_getc (0);
+
+ /* 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 the next character is to be quoted, note it now. */
+ if (cd == 0 || cd == '`' ||
+ (cd == '"' && peek_char >= 0 && (sh_syntaxtab[peek_char] & CBSDQUOTE)))
+ pass_next_character++;
+
+ quoted = 1;
+ goto got_character;
+ }
+ }
+
+ /* Parse a matched pair of quote characters. */
+ if MBTEST(shellquote (character))
+ {
+ push_delimiter (dstack, character);
+ ttok = parse_matched_pair (character, character, character, &ttoklen, (character == '`') ? P_COMMAND : 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_digit_token = 0;
+ quoted = 1;
+ dollar_present |= (character == '"' && strchr (ttok, '$') != 0);
+ FREE (ttok);
+ goto next_character;
+ }
+
+#ifdef COND_REGEXP
+ /* When parsing a regexp as a single word inside a conditional command,
+ we need to special-case characters special to both the shell and
+ regular expressions. Right now, that is only '(' and '|'. */ /*)*/
+ if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/
+ {
+ if (character == '|')
+ goto got_character;
+
+ push_delimiter (dstack, character);
+ ttok = parse_matched_pair (cd, '(', ')', &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;
+ FREE (ttok);
+ dollar_present = all_digit_token = 0;
+ goto next_character;
+ }
+#endif /* COND_REGEXP */
+
+#ifdef EXTENDED_GLOB
+ /* Parse a ksh-style extended pattern matching specification. */
+ if MBTEST(extended_glob && PATTERN_CHAR (character))
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '(') /* ) */
+ {
+ push_delimiter (dstack, peek_char);
+ ttok = parse_matched_pair (cd, '(', ')', &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;
+ token[token_index++] = peek_char;
+ strcpy (token + token_index, ttok);
+ token_index += ttoklen;
+ FREE (ttok);
+ dollar_present = all_digit_token = 0;
+ goto next_character;
+ }
+ else
+ shell_ungetc (peek_char);
+ }
+#endif /* EXTENDED_GLOB */
+
+ /* If the delimiter character is not single quote, parse some of
+ the shell expansions that must be read as a single word. */
+ if (shellexp (character))
+ {
+ peek_char = shell_getc (1);
+ /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
+ if MBTEST(peek_char == '(' || \
+ ((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
+ {
+ if (peek_char == '{') /* } */
+ ttok = parse_matched_pair (cd, '{', '}', &ttoklen, P_FIRSTCLOSE);
+ else if (peek_char == '(') /* ) */
+ {
+ /* XXX - push and pop the `(' as a delimiter for use by
+ the command-oriented-history code. This way newlines
+ appearing in the $(...) string get added to the
+ history literally rather than causing a possibly-
+ incorrect `;' to be added. ) */
+ push_delimiter (dstack, peek_char);
+ ttok = parse_comsub (cd, '(', ')', &ttoklen, P_COMMAND);
+ pop_delimiter (dstack);
+ }
+ 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_digit_token = 0;
+ goto next_character;
+ }
+ /* This handles $'...' and $"..." new-style quoted strings. */
+ else if MBTEST(character == '$' && (peek_char == '\'' || peek_char == '"'))
+ {
+ int first_line;
+
+ first_line = line_number;
+ push_delimiter (dstack, peek_char);
+ ttok = parse_matched_pair (peek_char, peek_char, peek_char,
+ &ttoklen,
+ (peek_char == '\'') ? P_ALLOWESC : 0);
+ pop_delimiter (dstack);
+ if (ttok == &matched_pair_error)
+ return -1;
+ if (peek_char == '\'')
+ {
+ ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
+ free (ttok);
+
+ /* Insert the single quotes and correctly quote any
+ embedded single quotes (allowed because P_ALLOWESC was
+ passed to parse_matched_pair). */
+ ttok = sh_single_quote (ttrans);
+ free (ttrans);
+ ttranslen = strlen (ttok);
+ ttrans = ttok;
+ }
+ else
+ {
+ /* Try to locale-expand the converted string. */
+ ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
+ free (ttok);
+
+ /* Add the double quotes back */
+ ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
+ free (ttrans);
+ ttranslen += 2;
+ ttrans = ttok;
+ }
+
+ RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
+ token_buffer_size,
+ TOKEN_DEFAULT_GROW_SIZE);
+ strcpy (token + token_index, ttrans);
+ token_index += ttranslen;
+ FREE (ttrans);
+ quoted = 1;
+ all_digit_token = 0;
+ goto next_character;
+ }
+ /* This could eventually be extended to recognize all of the
+ shell's single-character parameter expansions, and set flags.*/
+ else if MBTEST(character == '$' && peek_char == '$')
+ {
+ ttok = (char *)xmalloc (3);
+ ttok[0] = ttok[1] = '$';
+ ttok[2] = '\0';
+ RESIZE_MALLOCED_BUFFER (token, token_index, 3,
+ token_buffer_size,
+ TOKEN_DEFAULT_GROW_SIZE);
+ strcpy (token + token_index, ttok);
+ token_index += 2;
+ dollar_present = 1;
+ all_digit_token = 0;
+ FREE (ttok);
+ goto next_character;
+ }
+ else
+ shell_ungetc (peek_char);
+ }
+
+#if defined (ARRAY_VARS)
+ /* Identify possible array subscript assignment; match [...]. If
+ parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating
+ `sub' as if it were enclosed in double quotes. */
+ else if MBTEST(character == '[' && /* ] */
+ ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) ||
+ (token_index == 0 && (parser_state&PST_COMPASSIGN))))
+ {
+ ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB);
+ 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;
+ FREE (ttok);
+ all_digit_token = 0;
+ goto next_character;
+ }
+ /* Identify possible compound array variable assignment. */
+ else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index))
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '(') /* ) */
+ {
+ ttok = parse_compound_assignment (&ttoklen);
+
+ RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4,
+ token_buffer_size,
+ TOKEN_DEFAULT_GROW_SIZE);
+
+ token[token_index++] = '=';
+ token[token_index++] = '(';
+ if (ttok)
+ {
+ strcpy (token + token_index, ttok);
+ token_index += ttoklen;
+ }
+ token[token_index++] = ')';
+ FREE (ttok);
+ all_digit_token = 0;
+ compound_assignment = 1;
+#if 1
+ goto next_character;
+#else
+ goto got_token; /* ksh93 seems to do this */
+#endif
+ }
+ else
+ shell_ungetc (peek_char);
+ }
+#endif
+
+ /* When not parsing a multi-character word construct, shell meta-
+ characters break words. */
+ if MBTEST(shellbreak (character))
+ {
+ shell_ungetc (character);
+ goto got_token;
+ }
+
+ got_character:
+
+ if (character == CTLESC || character == CTLNUL)
+ token[token_index++] = CTLESC;
+
+ got_escaped_character:
+
+ all_digit_token &= DIGIT (character);
+ dollar_present |= character == '$';
+
+ token[token_index++] = character;
+
+ RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
+ TOKEN_DEFAULT_GROW_SIZE);
+
+ next_character:
+ if (character == '\n' && SHOULD_PROMPT ())
+ prompt_again ();
+
+ /* 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 (;;) */
+
+got_token:
+
+ token[token_index] = '\0';
+
+ /* 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 MBTEST(all_digit_token && (character == '<' || character == '>' || \
+ last_read_token == LESS_AND || \
+ last_read_token == GREATER_AND))
+ {
+ if (legal_number (token, &lvalue) && (int)lvalue == lvalue)
+ yylval.number = lvalue;
+ else
+ yylval.number = -1;
+ return (NUMBER);
+ }
+
+ /* Check for special case tokens. */
+ result = (last_shell_getc_is_singlebyte) ? special_case_tokens (token) : -1;
+ if (result >= 0)
+ return result;
+
+#if defined (ALIAS)
+ /* 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 MBTEST(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;
+ }
+
+ /* If not in Posix.2 mode, check for reserved words after alias
+ expansion. */
+ if MBTEST(posixly_correct == 0)
+#endif
+ CHECK_FOR_RESERVED_WORD (token);
+
+ the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
+ the_word->word = (char *)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; /*(*/
+ if (compound_assignment && token[token_index-1] == ')')
+ the_word->flags |= W_COMPASSIGN;
+ /* 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, (parser_state & PST_COMPASSIGN) != 0))
+ {
+ the_word->flags |= W_ASSIGNMENT;
+ /* Don't perform word splitting on assignment statements. */
+ if (assignment_acceptable (last_read_token) || (parser_state & PST_COMPASSIGN) != 0)
+ the_word->flags |= W_NOSPLIT;
+ }
+
+ if (command_token_position (last_read_token))
+ {
+ struct builtin *b;
+ b = builtin_address_internal (token, 0);
+ if (b && (b->flags & ASSIGNMENT_BUILTIN))
+ parser_state |= PST_ASSIGNOK;
+ else if (STREQ (token, "eval") || STREQ (token, "let"))
+ parser_state |= PST_ASSIGNOK;
+ }
+
+ yylval.word = the_word;
+
+ if (token[0] == '{' && token[token_index-1] == '}' &&
+ (character == '<' || character == '>'))
+ {
+ /* can use token; already copied to the_word */
+ token[token_index-1] = '\0';
+ if (legal_identifier (token+1))
+ {
+ strcpy (the_word->word, token+1);
+/*itrace("read_token_word: returning REDIR_WORD for %s", the_word->word);*/
+ return (REDIR_WORD);
+ }
+ }
+
+ result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT))
+ ? ASSIGNMENT_WORD : WORD;
+
+ switch (last_read_token)
+ {
+ case FUNCTION:
+ parser_state |= PST_ALLOWOPNBRC;
+ function_dstart = line_number;
+ break;
+ case CASE:
+ case SELECT:
+ case FOR:
+ if (word_top < MAX_CASE_NEST)
+ word_top++;
+ word_lineno[word_top] = line_number;
+ break;
+ }
+
+ return (result);
+}
+
+/* Return 1 if TOKSYM is a token that after being read would allow
+ a reserved word to be seen, else 0. */
+static int
+reserved_word_acceptable (toksym)
+ int toksym;
+{
+ switch (toksym)
+ {
+ case '\n':
+ case ';':
+ case '(':
+ case ')':
+ case '|':
+ case '&':
+ case '{':
+ case '}': /* XXX */
+ case AND_AND:
+ case BANG:
+ case BAR_AND:
+ case DO:
+ case DONE:
+ case ELIF:
+ case ELSE:
+ case ESAC:
+ case FI:
+ case IF:
+ case OR_OR:
+ case SEMI_SEMI:
+ case SEMI_AND:
+ case SEMI_SEMI_AND:
+ case THEN:
+ case TIME:
+ case TIMEOPT:
+ case COPROC:
+ case UNTIL:
+ case WHILE:
+ case 0:
+ return 1;
+ default:
+#if defined (COPROCESS_SUPPORT)
+ if (last_read_token == WORD && token_before_that == COPROC)
+ return 1;
+#endif
+ return 0;
+ }
+}
+
+/* Return the index of TOKEN in the alist of reserved words, or -1 if
+ TOKEN is not a shell reserved word. */
+int
+find_reserved_word (tokstr)
+ char *tokstr;
+{
+ int i;
+ for (i = 0; word_token_alist[i].word; i++)
+ if (STREQ (tokstr, 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
+ variable. */
+static void
+reset_readline_prompt ()
+{
+ char *temp_prompt;
+
+ if (prompt_string_pointer)
+ {
+ temp_prompt = (*prompt_string_pointer)
+ ? decode_prompt_string (*prompt_string_pointer)
+ : (char *)NULL;
+
+ if (temp_prompt == 0)
+ {
+ temp_prompt = (char *)xmalloc (1);
+ temp_prompt[0] = '\0';
+ }
+
+ 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
+ semi-colons. When concatenating multiple lines of history, the
+ newline separator for such tokens is replaced with a space. */
+static const int no_semi_successors[] = {
+ '\n', '{', '(', ')', ';', '&', '|',
+ CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, 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. Returns the string that should be added into the
+ history entry. */
+char *
+history_delimiting_chars ()
+{
+ register int i;
+
+ if (dstack.delimiter_depth != 0)
+ return ("\n");
+
+ /* We look for current_command_line_count == 2 because we are looking to
+ add the first line of the body of the here document (the second line
+ of the command). */
+ if (parser_state & PST_HEREDOC)
+ return (current_command_line_count == 2 ? "\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 == ')')
+ {
+ 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 */
+ }
+ else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
+ return " "; /* function def using `function name' without `()' */
+
+ else if (token_before_that == WORD && two_tokens_ago == FOR)
+ {
+ /* Tricky. `for i\nin ...' should not have a semicolon, but
+ `for i\ndo ...' should. We do what we can. */
+ for (i = shell_input_line_index; whitespace (shell_input_line[i]); i++)
+ ;
+ if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n')
+ return " ";
+ return ";";
+ }
+ else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT))
+ return " ";
+
+ for (i = 0; no_semi_successors[i]; i++)
+ {
+ if (token_before_that == no_semi_successors[i])
+ return (" ");
+ }
+
+ return ("; ");
+}
+#endif /* HISTORY */
+
+/* Issue a prompt, or prepare to issue a prompt when the next character
+ is read. */
+static void
+prompt_again ()
+{
+ char *temp_prompt;
+
+ if (interactive == 0 || expanding_alias ()) /* XXX */
+ return;
+
+ ps1_prompt = get_string_value ("PS1");
+ ps2_prompt = get_string_value ("PS2");
+
+ if (!prompt_string_pointer)
+ prompt_string_pointer = &ps1_prompt;
+
+ temp_prompt = *prompt_string_pointer
+ ? decode_prompt_string (*prompt_string_pointer)
+ : (char *)NULL;
+
+ if (temp_prompt == 0)
+ {
+ temp_prompt = (char *)xmalloc (1);
+ temp_prompt[0] = '\0';
+ }
+
+ current_prompt_string = *prompt_string_pointer;
+ prompt_string_pointer = &ps2_prompt;
+
+#if defined (READLINE)
+ if (!no_line_editing)
+ {
+ FREE (current_readline_prompt);
+ current_readline_prompt = temp_prompt;
+ }
+ else
+#endif /* READLINE */
+ {
+ FREE (current_decoded_prompt);
+ current_decoded_prompt = temp_prompt;
+ }
+}
+
+int
+get_current_prompt_level ()
+{
+ return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1);
+}
+
+void
+set_current_prompt_level (x)
+ int x;
+{
+ prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt;
+ current_prompt_string = *prompt_string_pointer;
+}
+
+static void
+print_prompt ()
+{
+ fprintf (stderr, "%s", current_decoded_prompt);
+ fflush (stderr);
+}
+
+/* Return a string which will be printed as a prompt. The string
+ may contain special characters which are decoded as follows:
+
+ \a bell (ascii 07)
+ \d the date in Day Mon Date format
+ \e escape (ascii 033)
+ \h the hostname up to the first `.'
+ \H the hostname
+ \j the number of active jobs
+ \l the basename of the shell's tty device name
+ \n CRLF
+ \r CR
+ \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 hh:mm am/pm format
+ \A the time in 24-hour hh:mm format
+ \D{fmt} the result of passing FMT to strftime(3)
+ \u your username
+ \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
+ \! the history number of this command
+ \# the command number of this command
+ \$ a $ or a # if you are root
+ \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 48
+char *
+decode_prompt_string (string)
+ char *string;
+{
+ WORD_LIST *list;
+ char *result, *t;
+ struct dstack save_dstack;
+ int last_exit_value, last_comsub_pid;
+#if defined (PROMPT_STRING_DECODE)
+ int result_size, result_index;
+ int c, n, i;
+ char *temp, octal_string[4];
+ struct tm *tm;
+ time_t the_time;
+ char timebuf[128];
+ char *timefmt;
+
+ result = (char *)xmalloc (result_size = PROMPT_GROWTH);
+ result[result_index = 0] = 0;
+ temp = (char *)NULL;
+
+ while (c = *string++)
+ {
+ if (posixly_correct && c == '!')
+ {
+ if (*string == '!')
+ {
+ temp = savestring ("!");
+ goto add_string;
+ }
+ else
+ {
+#if !defined (HISTORY)
+ temp = savestring ("1");
+#else /* HISTORY */
+ temp = itos (history_number ());
+#endif /* HISTORY */
+ string--; /* add_string increments string again. */
+ goto add_string;
+ }
+ }
+ if (c == '\\')
+ {
+ c = *string;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ strncpy (octal_string, string, 3);
+ octal_string[3] = '\0';
+
+ n = read_octal (octal_string);
+ temp = (char *)xmalloc (3);
+
+ if (n == CTLESC || n == CTLNUL)
+ {
+ temp[0] = CTLESC;
+ temp[1] = n;
+ temp[2] = '\0';
+ }
+ else if (n == -1)
+ {
+ temp[0] = '\\';
+ temp[1] = '\0';
+ }
+ else
+ {
+ temp[0] = n;
+ temp[1] = '\0';
+ }
+
+ for (c = 0; n != -1 && c < 3 && ISOCTAL (*string); c++)
+ string++;
+
+ c = 0; /* tested at add_string: */
+ goto add_string;
+
+ case 'd':
+ case 't':
+ case 'T':
+ case '@':
+ case 'A':
+ /* Make the current time/date into a string. */
+ (void) time (&the_time);
+ tm = localtime (&the_time);
+
+ if (c == 'd')
+ n = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm);
+ else if (c == 't')
+ n = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm);
+ else if (c == 'T')
+ n = strftime (timebuf, sizeof (timebuf), "%I:%M:%S", tm);
+ else if (c == '@')
+ n = strftime (timebuf, sizeof (timebuf), "%I:%M %p", tm);
+ else if (c == 'A')
+ n = strftime (timebuf, sizeof (timebuf), "%H:%M", tm);
+
+ if (n == 0)
+ timebuf[0] = '\0';
+ else
+ timebuf[sizeof(timebuf) - 1] = '\0';
+
+ temp = savestring (timebuf);
+ goto add_string;
+
+ case 'D': /* strftime format */
+ if (string[1] != '{') /* } */
+ goto not_escape;
+
+ (void) time (&the_time);
+ tm = localtime (&the_time);
+ string += 2; /* skip { */
+ timefmt = xmalloc (strlen (string) + 3);
+ for (t = timefmt; *string && *string != '}'; )
+ *t++ = *string++;
+ *t = '\0';
+ c = *string; /* tested at add_string */
+ if (timefmt[0] == '\0')
+ {
+ timefmt[0] = '%';
+ timefmt[1] = 'X'; /* locale-specific current time */
+ timefmt[2] = '\0';
+ }
+ n = strftime (timebuf, sizeof (timebuf), timefmt, tm);
+ free (timefmt);
+
+ if (n == 0)
+ timebuf[0] = '\0';
+ else
+ timebuf[sizeof(timebuf) - 1] = '\0';
+
+ if (promptvars || posixly_correct)
+ /* Make sure that expand_prompt_string is called with a
+ second argument of Q_DOUBLE_QUOTES if we use this
+ function here. */
+ temp = sh_backslash_quote_for_double_quotes (timebuf);
+ else
+ temp = savestring (timebuf);
+ goto add_string;
+
+ case 'n':
+ temp = (char *)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;
+
+ case 'v':
+ case 'V':
+ temp = (char *)xmalloc (16);
+ 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 efficient. */
+ char t_string[PATH_MAX];
+ int tlen;
+
+ temp = get_string_value ("PWD");
+
+ if (temp == 0)
+ {
+ if (getcwd (t_string, sizeof(t_string)) == 0)
+ {
+ t_string[0] = '.';
+ tlen = 1;
+ }
+ else
+ tlen = strlen (t_string);
+ }
+ else
+ {
+ tlen = sizeof (t_string) - 1;
+ strncpy (t_string, temp, tlen);
+ }
+ t_string[tlen] = '\0';
+
+#if defined (MACOSX)
+ /* Convert from "fs" format to "input" format */
+ temp = fnx_fromfs (t_string, strlen (t_string));
+ if (temp != t_string)
+ strcpy (t_string, temp);
+#endif
+
+#define ROOT_PATH(x) ((x)[0] == '/' && (x)[1] == 0)
+#define DOUBLE_SLASH_ROOT(x) ((x)[0] == '/' && (x)[1] == '/' && (x)[2] == 0)
+ /* Abbreviate \W as ~ if $PWD == $HOME */
+ if (c == 'W' && (((t = get_string_value ("HOME")) == 0) || STREQ (t, t_string) == 0))
+ {
+ if (ROOT_PATH (t_string) == 0 && DOUBLE_SLASH_ROOT (t_string) == 0)
+ {
+ t = strrchr (t_string, '/');
+ if (t)
+ strcpy (t_string, t + 1);
+ }
+ }
+#undef ROOT_PATH
+#undef DOUBLE_SLASH_ROOT
+ else
+ /* polite_directory_format is guaranteed to return a string
+ no longer than PATH_MAX - 1 characters. */
+ strcpy (t_string, polite_directory_format (t_string));
+
+ temp = trim_pathname (t_string, PATH_MAX - 1);
+ /* If we're going to be expanding the prompt string later,
+ quote the directory name. */
+ if (promptvars || posixly_correct)
+ /* Make sure that expand_prompt_string is called with a
+ second argument of Q_DOUBLE_QUOTES if we use this
+ function here. */
+ temp = sh_backslash_quote_for_double_quotes (t_string);
+ else
+ temp = savestring (t_string);
+
+ goto add_string;
+ }
+
+ case 'u':
+ if (current_user.user_name == 0)
+ get_current_user_info ();
+ temp = savestring (current_user.user_name);
+ goto add_string;
+
+ case 'h':
+ 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;
+
+ case '!':
+#if !defined (HISTORY)
+ temp = savestring ("1");
+#else /* HISTORY */
+ temp = itos (history_number ());
+#endif /* HISTORY */
+ goto add_string;
+
+ case '$':
+ t = temp = (char *)xmalloc (3);
+ if ((promptvars || posixly_correct) && (current_user.euid != 0))
+ *t++ = '\\';
+ *t++ = current_user.euid == 0 ? '#' : '$';
+ *t = '\0';
+ goto add_string;
+
+ case 'j':
+ temp = itos (count_all_jobs ());
+ goto add_string;
+
+ case 'l':
+#if defined (HAVE_TTYNAME)
+ temp = (char *)ttyname (fileno (stdin));
+ t = temp ? base_pathname (temp) : "tty";
+ temp = savestring (t);
+#else
+ temp = savestring ("tty");
+#endif /* !HAVE_TTYNAME */
+ goto add_string;
+
+#if defined (READLINE)
+ case '[':
+ case ']':
+ if (no_line_editing)
+ {
+ string++;
+ break;
+ }
+ temp = (char *)xmalloc (3);
+ n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
+ i = 0;
+ if (n == CTLESC || n == CTLNUL)
+ temp[i++] = CTLESC;
+ temp[i++] = n;
+ temp[i] = '\0';
+ goto add_string;
+#endif /* READLINE */
+
+ case '\\':
+ case 'a':
+ case 'e':
+ case 'r':
+ temp = (char *)xmalloc (2);
+ if (c == 'a')
+ temp[0] = '\07';
+ else if (c == 'e')
+ temp[0] = '\033';
+ else if (c == 'r')
+ temp[0] = '\r';
+ else /* (c == '\\') */
+ temp[0] = c;
+ temp[1] = '\0';
+ goto add_string;
+
+ default:
+not_escape:
+ temp = (char *)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; /* Freed in sub_append_string (). */
+ result[result_index] = '\0';
+ break;
+ }
+ }
+ else
+ {
+ RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH);
+ result[result_index++] = c;
+ result[result_index] = '\0';
+ }
+ }
+#else /* !PROMPT_STRING_DECODE */
+ 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. */
+ if (promptvars || posixly_correct)
+ {
+ last_exit_value = last_command_exit_value;
+ last_comsub_pid = last_command_subst_pid;
+ list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0);
+ free (result);
+ result = string_list (list);
+ dispose_words (list);
+ last_command_exit_value = last_exit_value;
+ last_command_subst_pid = last_comsub_pid;
+ }
+ else
+ {
+ t = dequote_string (result);
+ free (result);
+ result = t;
+ }
+
+ dstack = save_dstack;
+
+ return (result);
+}
+
+/************************************************
+ * *
+ * ERROR HANDLING *
+ * *
+ ************************************************/
+
+/* Report a syntax error, and restart the parser. Call here for fatal
+ errors. */
+int
+yyerror (msg)
+ const char *msg;
+{
+ report_syntax_error ((char *)NULL);
+ reset_parser ();
+ return (0);
+}
+
+static char *
+error_token_from_token (tok)
+ int tok;
+{
+ char *t;
+
+ if (t = find_token_in_alist (tok, word_token_alist, 0))
+ return t;
+
+ if (t = find_token_in_alist (tok, other_token_alist, 0))
+ return t;
+
+ t = (char *)NULL;
+ /* This stuff is dicy and needs closer inspection */
+ switch (current_token)
+ {
+ case WORD:
+ case ASSIGNMENT_WORD:
+ if (yylval.word)
+ t = savestring (yylval.word->word);
+ break;
+ case NUMBER:
+ t = itos (yylval.number);
+ break;
+ case ARITH_CMD:
+ if (yylval.word_list)
+ t = string_list (yylval.word_list);
+ break;
+ case ARITH_FOR_EXPRS:
+ if (yylval.word_list)
+ t = string_list_internal (yylval.word_list, " ; ");
+ break;
+ case COND_CMD:
+ t = (char *)NULL; /* punt */
+ break;
+ }
+
+ return t;
+}
+
+static char *
+error_token_from_text ()
+{
+ char *msg, *t;
+ int token_end, i;
+
+ t = shell_input_line;
+ i = shell_input_line_index;
+ token_end = 0;
+ msg = (char *)NULL;
+
+ if (i && t[i] == '\0')
+ i--;
+
+ while (i && (whitespace (t[i]) || t[i] == '\n'))
+ i--;
+
+ if (i)
+ token_end = i + 1;
+
+ while (i && (member (t[i], " \n\t;|&") == 0))
+ i--;
+
+ while (i != token_end && (whitespace (t[i]) || t[i] == '\n'))
+ i++;
+
+ /* Return our idea of the offending token. */
+ if (token_end || (i == 0 && token_end == 0))
+ {
+ if (token_end)
+ msg = substring (t, i, token_end);
+ else /* one-character token */
+ {
+ msg = (char *)xmalloc (2);
+ msg[0] = t[i];
+ msg[1] = '\0';
+ }
+ }
+
+ return (msg);
+}
+
+static void
+print_offending_line ()
+{
+ char *msg;
+ int token_end;
+
+ msg = savestring (shell_input_line);
+ token_end = strlen (msg);
+ while (token_end && msg[token_end - 1] == '\n')
+ msg[--token_end] = '\0';
+
+ parser_error (line_number, "`%s'", msg);
+ free (msg);
+}
+
+/* Report a syntax error with line numbers, etc.
+ Call here for recoverable errors. If you have a message to print,
+ then place it in MESSAGE, otherwise pass NULL and this will figure
+ out an appropriate message for you. */
+static void
+report_syntax_error (message)
+ char *message;
+{
+ char *msg;
+
+ if (message)
+ {
+ parser_error (line_number, "%s", message);
+ if (interactive && EOF_Reached)
+ EOF_Reached = 0;
+ last_command_exit_value = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
+ return;
+ }
+
+ /* If the line of input we're reading is not null, try to find the
+ objectionable token. First, try to figure out what token the
+ parser's complaining about by looking at current_token. */
+ if (current_token != 0 && EOF_Reached == 0 && (msg = error_token_from_token (current_token)))
+ {
+ parser_error (line_number, _("syntax error near unexpected token `%s'"), msg);
+ free (msg);
+
+ if (interactive == 0)
+ print_offending_line ();
+
+ last_command_exit_value = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
+ return;
+ }
+
+ /* If looking at the current token doesn't prove fruitful, try to find the
+ offending token by analyzing the text of the input line near the current
+ input line index and report what we find. */
+ if (shell_input_line && *shell_input_line)
+ {
+ msg = error_token_from_text ();
+ if (msg)
+ {
+ parser_error (line_number, _("syntax error near `%s'"), msg);
+ free (msg);
+ }
+
+ /* If not interactive, print the line containing the error. */
+ if (interactive == 0)
+ print_offending_line ();
+ }
+ else
+ {
+ 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 = parse_and_execute_level ? EX_BADSYNTAX : EX_BADUSAGE;
+}
+
+/* ??? Needed function. ??? We have to be able to discard the constructs
+ created during parsing. In the case of error, we want to return
+ 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;
+{
+}
+
+/************************************************
+ * *
+ * EOF HANDLING *
+ * *
+ ************************************************/
+
+/* Do that silly `type "bye" to exit' stuff. You know, "ignoreeof". */
+
+/* A flag denoting whether or not ignoreeof is set. */
+int ignoreeof = 0;
+
+/* The number of times that we have encountered an EOF character without
+ another character intervening. When this gets above the limit, the
+ shell terminates. */
+int eof_encountered = 0;
+
+/* The limit for eof_encountered. */
+int eof_encountered_limit = 10;
+
+/* If we have EOF as the only input unit, this user wants to leave
+ the shell. If the shell is not interactive, then just leave.
+ Otherwise, if ignoreeof is set, and we haven't done this the
+ required number of times in a row, print a message. */
+static void
+handle_eof_input_unit ()
+{
+ if (interactive)
+ {
+ /* shell.c may use this to decide whether or not to write out the
+ history, among other things. We use it only for error reporting
+ in this file. */
+ if (EOF_Reached)
+ EOF_Reached = 0;
+
+ /* If the user wants to "ignore" eof, then let her do so, kind of. */
+ if (ignoreeof)
+ {
+ if (eof_encountered < eof_encountered_limit)
+ {
+ fprintf (stderr, _("Use \"%s\" to leave the shell.\n"),
+ login_shell ? "logout" : "exit");
+ eof_encountered++;
+ /* Reset the parsing state. */
+ last_read_token = current_token = '\n';
+ /* Reset the prompt string to be $PS1. */
+ prompt_string_pointer = (char **)NULL;
+ prompt_again ();
+ return;
+ }
+ }
+
+ /* In this case EOF should exit the shell. Do it now. */
+ reset_parser ();
+ exit_builtin ((WORD_LIST *)NULL);
+ }
+ else
+ {
+ /* We don't write history files, etc., for non-interactive shells. */
+ EOF_Reached = 1;
+ }
+}
+
+/************************************************
+ * *
+ * STRING PARSING FUNCTIONS *
+ * *
+ ************************************************/
+
+/* It's very important that these two functions treat the characters
+ between ( and ) identically. */
+
+static WORD_LIST parse_string_error;
+
+/* Take a string and run it through the shell parser, returning the
+ resultant word list. Used by compound array assignment. */
+WORD_LIST *
+parse_string_to_word_list (s, flags, whom)
+ char *s;
+ int flags;
+ const char *whom;
+{
+ WORD_LIST *wl;
+ int tok, orig_current_token, orig_line_number, orig_input_terminator;
+ int orig_line_count;
+ int old_echo_input, old_expand_aliases;
+#if defined (HISTORY)
+ int old_remember_on_history, old_history_expansion_inhibited;
+#endif
+
+#if defined (HISTORY)
+ old_remember_on_history = remember_on_history;
+# if defined (BANG_HISTORY)
+ old_history_expansion_inhibited = history_expansion_inhibited;
+# endif
+ bash_history_disable ();
+#endif
+
+ orig_line_number = line_number;
+ orig_line_count = current_command_line_count;
+ orig_input_terminator = shell_input_line_terminator;
+ old_echo_input = echo_input_at_read;
+ old_expand_aliases = expand_aliases;
+
+ push_stream (1);
+ last_read_token = WORD; /* WORD to allow reserved words here */
+ current_command_line_count = 0;
+ echo_input_at_read = expand_aliases = 0;
+
+ with_input_from_string (s, whom);
+ wl = (WORD_LIST *)NULL;
+
+ if (flags & 1)
+ parser_state |= PST_COMPASSIGN|PST_REPARSE;
+
+ while ((tok = read_token (READ)) != yacc_EOF)
+ {
+ if (tok == '\n' && *bash_input.location.string == '\0')
+ break;
+ if (tok == '\n') /* Allow newlines in compound assignments */
+ continue;
+ if (tok != WORD && tok != ASSIGNMENT_WORD)
+ {
+ line_number = orig_line_number + line_number - 1;
+ orig_current_token = current_token;
+ current_token = tok;
+ yyerror (NULL); /* does the right thing */
+ current_token = orig_current_token;
+ if (wl)
+ dispose_words (wl);
+ wl = &parse_string_error;
+ break;
+ }
+ wl = make_word_list (yylval.word, wl);
+ }
+
+ last_read_token = '\n';
+ pop_stream ();
+
+#if defined (HISTORY)
+ remember_on_history = old_remember_on_history;
+# if defined (BANG_HISTORY)
+ history_expansion_inhibited = old_history_expansion_inhibited;
+# endif /* BANG_HISTORY */
+#endif /* HISTORY */
+
+ echo_input_at_read = old_echo_input;
+ expand_aliases = old_expand_aliases;
+
+ current_command_line_count = orig_line_count;
+ shell_input_line_terminator = orig_input_terminator;
+
+ if (flags & 1)
+ parser_state &= ~(PST_COMPASSIGN|PST_REPARSE);
+
+ if (wl == &parse_string_error)
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ if (interactive_shell == 0 && posixly_correct)
+ jump_to_top_level (FORCE_EOF);
+ else
+ jump_to_top_level (DISCARD);
+ }
+
+ return (REVERSE_LIST (wl, WORD_LIST *));
+}
+
+static char *
+parse_compound_assignment (retlenp)
+ int *retlenp;
+{
+ WORD_LIST *wl, *rl;
+ int tok, orig_line_number, orig_token_size, orig_last_token, assignok;
+ char *saved_token, *ret;
+
+ saved_token = token;
+ orig_token_size = token_buffer_size;
+ orig_line_number = line_number;
+ orig_last_token = last_read_token;
+
+ last_read_token = WORD; /* WORD to allow reserved words here */
+
+ token = (char *)NULL;
+ token_buffer_size = 0;
+
+ assignok = parser_state&PST_ASSIGNOK; /* XXX */
+
+ wl = (WORD_LIST *)NULL; /* ( */
+ parser_state |= PST_COMPASSIGN;
+
+ while ((tok = read_token (READ)) != ')')
+ {
+ if (tok == '\n') /* Allow newlines in compound assignments */
+ {
+ if (SHOULD_PROMPT ())
+ prompt_again ();
+ continue;
+ }
+ if (tok != WORD && tok != ASSIGNMENT_WORD)
+ {
+ current_token = tok; /* for error reporting */
+ if (tok == yacc_EOF) /* ( */
+ parser_error (orig_line_number, _("unexpected EOF while looking for matching `)'"));
+ else
+ yyerror(NULL); /* does the right thing */
+ if (wl)
+ dispose_words (wl);
+ wl = &parse_string_error;
+ break;
+ }
+ wl = make_word_list (yylval.word, wl);
+ }
+
+ FREE (token);
+ token = saved_token;
+ token_buffer_size = orig_token_size;
+
+ parser_state &= ~PST_COMPASSIGN;
+
+ if (wl == &parse_string_error)
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ last_read_token = '\n'; /* XXX */
+ if (interactive_shell == 0 && posixly_correct)
+ jump_to_top_level (FORCE_EOF);
+ else
+ jump_to_top_level (DISCARD);
+ }
+
+ last_read_token = orig_last_token; /* XXX - was WORD? */
+
+ if (wl)
+ {
+ rl = REVERSE_LIST (wl, WORD_LIST *);
+ ret = string_list (rl);
+ dispose_words (rl);
+ }
+ else
+ ret = (char *)NULL;
+
+ if (retlenp)
+ *retlenp = (ret && *ret) ? strlen (ret) : 0;
+
+ if (assignok)
+ parser_state |= PST_ASSIGNOK;
+
+ return ret;
+}
+
+/************************************************
+ * *
+ * SAVING AND RESTORING PARTIAL PARSE STATE *
+ * *
+ ************************************************/
+
+sh_parser_state_t *
+save_parser_state (ps)
+ sh_parser_state_t *ps;
+{
+ if (ps == 0)
+ ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t));
+ if (ps == 0)
+ return ((sh_parser_state_t *)NULL);
+
+ ps->parser_state = parser_state;
+ ps->token_state = save_token_state ();
+
+ ps->input_line_terminator = shell_input_line_terminator;
+ ps->eof_encountered = eof_encountered;
+
+ ps->current_command_line_count = current_command_line_count;
+
+#if defined (HISTORY)
+ ps->remember_on_history = remember_on_history;
+# if defined (BANG_HISTORY)
+ ps->history_expansion_inhibited = history_expansion_inhibited;
+# endif
+#endif
+
+ ps->last_command_exit_value = last_command_exit_value;
+#if defined (ARRAY_VARS)
+ ps->pipestatus = save_pipestatus_array ();
+#endif
+
+ ps->last_shell_builtin = last_shell_builtin;
+ ps->this_shell_builtin = this_shell_builtin;
+
+ ps->expand_aliases = expand_aliases;
+ ps->echo_input_at_read = echo_input_at_read;
+
+ return (ps);
+}
+
+void
+restore_parser_state (ps)
+ sh_parser_state_t *ps;
+{
+ if (ps == 0)
+ return;
+
+ parser_state = ps->parser_state;
+ if (ps->token_state)
+ {
+ restore_token_state (ps->token_state);
+ free (ps->token_state);
+ }
+
+ shell_input_line_terminator = ps->input_line_terminator;
+ eof_encountered = ps->eof_encountered;
+
+ current_command_line_count = ps->current_command_line_count;
+
+#if defined (HISTORY)
+ remember_on_history = ps->remember_on_history;
+# if defined (BANG_HISTORY)
+ history_expansion_inhibited = ps->history_expansion_inhibited;
+# endif
+#endif
+
+ last_command_exit_value = ps->last_command_exit_value;
+#if defined (ARRAY_VARS)
+ restore_pipestatus_array (ps->pipestatus);
+#endif
+
+ last_shell_builtin = ps->last_shell_builtin;
+ this_shell_builtin = ps->this_shell_builtin;
+
+ expand_aliases = ps->expand_aliases;
+ echo_input_at_read = ps->echo_input_at_read;
+}
+
+/************************************************
+ * *
+ * MULTIBYTE CHARACTER HANDLING *
+ * *
+ ************************************************/
+
+#if defined (HANDLE_MULTIBYTE)
+static void
+set_line_mbstate ()
+{
+ int i, previ, len, c;
+ mbstate_t mbs, prevs;
+ size_t mbclen;
+
+ if (shell_input_line == NULL)
+ return;
+ len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */
+ FREE (shell_input_line_property);
+ shell_input_line_property = (char *)xmalloc (len + 1);
+
+ memset (&prevs, '\0', sizeof (mbstate_t));
+ for (i = previ = 0; i < len; i++)
+ {
+ mbs = prevs;
+
+ c = shell_input_line[i];
+ if (c == EOF)
+ {
+ int j;
+ for (j = i; j < len; j++)
+ shell_input_line_property[j] = 1;
+ break;
+ }
+
+ mbclen = mbrlen (shell_input_line + previ, i - previ + 1, &mbs);
+ if (mbclen == 1 || mbclen == (size_t)-1)
+ {
+ mbclen = 1;
+ previ = i + 1;
+ }
+ else if (mbclen == (size_t)-2)
+ mbclen = 0;
+ else if (mbclen > 1)
+ {
+ mbclen = 0;
+ previ = i + 1;
+ prevs = mbs;
+ }
+ else
+ {
+ /* XXX - what to do if mbrlen returns 0? (null wide character) */
+ int j;
+ for (j = i; j < len; j++)
+ shell_input_line_property[j] = 1;
+ break;
+ }
+
+ shell_input_line_property[i] = mbclen;
+ }
+}
+#endif /* HANDLE_MULTIBYTE */
"Project-Id-Version: GNU bash 4.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-12-30 08:25-0500\n"
-"PO-Revision-Date: 2010-02-14 10:35+0900\n"
+"PO-Revision-Date: 2010-04-01 01:59+0900\n"
"Last-Translator: Yasuaki Taniguchi <yasuakit@gmail.com>\n"
"Language-Team: Japanese <translation-team-ja@lists.sourceforge.net>\n"
"MIME-Version: 1.0\n"
msgstr "%s: %s を読み出しすることができません"
#: builtins/bind.def:260
-#, fuzzy, c-format
+#, c-format
msgid "`%s': cannot unbind"
-msgstr "%s: コマンドが見つかりません"
+msgstr "`%s': 割り当て解除できません"
#: builtins/bind.def:295 builtins/bind.def:325
#, c-format
#: builtins/bind.def:303
#, c-format
msgid "%s is not bound to any keys.\n"
-msgstr ""
+msgstr "%s はどのキーにも割り当てられていません。\n"
#: builtins/bind.def:307
#, c-format
" -N\tDisplays the Nth entry counting from the right of the list shown by\n"
"\tdirs when invoked without options, starting with zero."
msgstr ""
+"現在記憶されているディレクトリスタックを表示します。ディレクトリは `pushd'\n"
+" コマンドによってスタックの一番上に保存されます。`popd'コマンドによって\n"
+" スタックから取り戻すことができます。\n"
+" \n"
+" オプション:\n"
+" -c\tディレクトリスタックからすべての要素を取り除き空にする\n"
+" -l\tホームディレクトリからの相対パスを ~ を利用した形式で\n"
+" \t表示しない\n"
+" -p\tディレクトリスタックの要素を1行毎に表示する\n"
+" -v\tディレクトリスタックの要素を1行ごとに番号をつけて\n"
+" \t表示する\n"
+" \n"
+" 引数:\n"
+" +N\tオプションなしで起動された場合にリストの先頭から数えて\n"
+" \tN番目の要素を表示します。開始番号は0です。\n"
+" \n"
+" -N\tオプションなしで起動された場合にリストの末尾から数えて\n"
+"\tN番目の要素を表示します。開始番号は0です。"
#: builtins/pushd.def:705
msgid ""
" \n"
" The `dirs' builtin displays the directory stack."
msgstr ""
+"ディレクトリスタックの先頭にディレクトリを追加します。またはディレクトリ\n"
+" スタックを回転します。新しいスタックの先頭がカレントディレクトリにな\n"
+" ります。引数なしで起動された場合、先頭の2つのディレクトリを交換します。\n"
+" \n"
+" オプション:\n"
+" -n\tスタックにディレクトリを追加した時に通常のディレクトリ変更\n"
+" \tを抑止します。よって、スタックのみ操作されます。\n"
+" \n"
+" 引数:\n"
+" +N\t先頭がN番目のディレクトリになるように回転します(`dirs'で\n"
+" \t表示されるスタックの先頭から数えた数です。開始番号は0です)。\n"
+" \n"
+" -N\t先頭がN番目のディレクトリになるように回転します(`dirs'で\n"
+" \t表示されるスタックの末尾から数えた数です。開始番号は0です)。\n"
+" \n"
+" ディレクトリ\tディレクトリをスタックの先頭に加え、そのディレク\n"
+" \tトリを新しいカレントディレクトリにします。\n"
+" \n"
+" `dirs' ビルトインコマンドでディレクトリスタックを表示します。"
#: builtins/pushd.def:730
msgid ""
" \n"
" The `dirs' builtin displays the directory stack."
msgstr ""
+"ディレクトリスタックから要素を削除します。引数が無い場合スタックの先頭から\n"
+" 削除し、新しいスタックの先頭ディレクトリに移動します。\n"
+" \n"
+" オプション:\n"
+" -n\tスタックからディレクトリを削除した時に通常のディレクトリ変更\n"
+" \tを抑止します。よって、スタックのみ操作されます。\n"
+" \n"
+" 引数:\n"
+" +N\tディレクトリスタック(`dirs' で表示される)の先頭から数えて\n"
+" \t N 番目の要素を削除します。開始番号は 0 です。例: `popd +0'\n"
+" \tは最初のディレクトリを削除します。`popd +1' は2番目です。\n"
+" \n"
+" -N\tディレクトリスタック(`dirs' で表示される)の最後から数えて\n"
+" \t N 番目の要素を削除します。開始番号は 0 です。例: `popd +0'\n"
+" \tは最後のディレクトリを削除します。`popd +1' は最後から2番目です。\n"
+" \n"
+" `dirs' ビルトインコマンドでディレクトリスタックを表示します。"
#: builtins/read.def:252
#, c-format
#: builtins/return.def:73
msgid "can only `return' from a function or sourced script"
-msgstr ""
+msgstr "`return' は関数または source されたスクリプト内のみで利用できます"
#: builtins/set.def:768
msgid "cannot simultaneously unset a function and a variable"
#: builtins/shopt.def:260
msgid "cannot set and unset shell options simultaneously"
-msgstr ""
+msgstr "シェルオプションを同時に有効かつ無効にできません"
#: builtins/shopt.def:325
#, c-format
#: builtins/type.def:337
#, c-format
msgid "%s is hashed (%s)\n"
-msgstr ""
+msgstr "%s はハッシュされている (%s)\n"
#: builtins/ulimit.def:372
#, c-format
#: expr.c:826
msgid "identifier expected after pre-increment or pre-decrement"
-msgstr ""
+msgstr "識別子は前置インクリメントまたは前置デクリメントが予期されます"
#: expr.c:854
msgid "missing `)'"
#: input.c:258
#, c-format
msgid "cannot allocate new file descriptor for bash input from fd %d"
-msgstr ""
+msgstr "新規ファイル記述子(fd) %d を bash の入力として割り当てられません"
#: input.c:266
#, c-format
#: jobs.c:1113
#, c-format
msgid "add_process: pid %5ld (%s) marked as still alive"
-msgstr ""
+msgstr "add_process: pid %5ld (%s) はまだ存在しています"
#: jobs.c:1401
#, c-format
#: jobs.c:1776
#, c-format
msgid "child setpgid (%ld to %ld)"
-msgstr ""
+msgstr "子プロセス setpgid (%ld から %ld)"
#: jobs.c:2104 nojobs.c:585
#, c-format
#: jobs.c:3059
msgid "waitchld: turning on WNOHANG to avoid indefinite block"
-msgstr ""
+msgstr "waitchld: 不定のブロックを避けるために WNOHANG をオンにしました。"
#: jobs.c:3508
#, c-format
msgstr "initialize_job_control: getpgrp が失敗しました"
#: jobs.c:3639
-#, fuzzy
msgid "initialize_job_control: line discipline"
msgstr "initialize_job_control: line discipline"
#: lib/malloc/malloc.c:296
#, c-format
msgid "malloc: failed assertion: %s\n"
-msgstr ""
+msgstr "malloc: 失敗したアサーション: %s\n"
#: lib/malloc/malloc.c:312
#, c-format
"\r\n"
"malloc: %s:%d: assertion botched\r\n"
msgstr ""
+"\\r\n"
+"malloc: %s:%d: アサーション失敗\\r\n"
#: lib/malloc/malloc.c:313
msgid "unknown"
#: make_cmd.c:659
#, c-format
msgid "here-document at line %d delimited by end-of-file (wanted `%s')"
-msgstr ""
+msgstr "ヒアドキュメントの %d 行目でファイル終了 (EOF) に達しました (`%s' が必要)"
#: make_cmd.c:756
#, c-format
#: pcomplib.c:179
#, c-format
msgid "progcomp_insert: %s: NULL COMPSPEC"
-msgstr ""
+msgstr "progcomp_insert: %s: NULL COMPSPEC"
#: print_cmd.c:290
#, c-format
msgstr "シェル オプション:\n"
#: shell.c:1801
-#, fuzzy
msgid "\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"
-msgstr "\t-irsD 又は コマンド\t\t(訴えのみ)\n"
+msgstr "\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"
#: shell.c:1816
#, c-format
msgid "\t-%s or -o option\n"
-msgstr "\t-%s 又は -o オプション\n"
+msgstr "\t-%s または -o オプション\n"
#: shell.c:1822
#, c-format
msgstr "アラーム時計"
#: siglist.c:111
-#, fuzzy
msgid "Terminated"
-msgstr "終了しました"
+msgstr "Terminated"
#: siglist.c:115
msgid "Urgent IO condition"
#: siglist.c:211
msgid "HFT sound sequence has completed"
-msgstr ""
+msgstr "HFT サウンドシーケンスが完了しました"
#: siglist.c:215
msgid "Information request"
-msgstr ""
+msgstr "情報要求"
#: siglist.c:223
msgid "Unknown Signal #"
#: subst.c:5907
#, c-format
msgid "%s: substring expression < 0"
-msgstr ""
+msgstr "%s: substring expression < 0"
#: subst.c:6965
#, c-format
#: trap.c:331
#, c-format
msgid "run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"
-msgstr ""
+msgstr "run_pending_traps: シグナルハンドラーは SIG_DFLです。, %d (%s) を自身に再送します。"
#: trap.c:380
#, c-format
#: version.c:91 version2.c:88
#, c-format
msgid "This is free software; you are free to change and redistribute it.\n"
-msgstr ""
+msgstr "This is free software; you are free to change and redistribute it.\n"
#: version.c:92 version2.c:89
#, c-format
msgid "There is NO WARRANTY, to the extent permitted by law.\n"
-msgstr ""
+msgstr "There is NO WARRANTY, to the extent permitted by law.\n"
#: version2.c:86
#, c-format
#: builtins.c:43
msgid "alias [-p] [name[=value] ... ]"
-msgstr "alias [-p] [名前[=値] ... ]"
+msgstr "alias [-p] [name[=value] ... ]"
#: builtins.c:47
msgid "unalias [-a] name [name ...]"
-msgstr "unalias [-a] 名前 [名前 ...]"
+msgstr "unalias [-a] name [name ...]"
#: builtins.c:51
msgid "bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]"
-msgstr ""
+msgstr "bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]"
#: builtins.c:54
msgid "break [n]"
#: builtins.c:58
msgid "builtin [shell-builtin [arg ...]]"
-msgstr "builtin [shell-builtin [引数 ...]]"
+msgstr "builtin [shell-builtin [arg ...]]"
#: builtins.c:61
msgid "caller [expr]"
-msgstr "caller [式]"
+msgstr "caller [expr]"
#: builtins.c:64
msgid "cd [-L|-P] [dir]"
-msgstr "cd [-L|-P] [ディレクトリ]"
+msgstr "cd [-L|-P] [dir]"
#: builtins.c:66
msgid "pwd [-LP]"
#: builtins.c:74
msgid "command [-pVv] command [arg ...]"
-msgstr "command [-pVv] コマンド [引数 ...]"
+msgstr "command [-pVv] command [arg ...]"
#: builtins.c:76
msgid "declare [-aAfFilrtux] [-p] [name[=value] ...]"
-msgstr "declare [-aAfFilrtux] [-p] [名前[=値] ...]"
+msgstr "declare [-aAfFilrtux] [-p] [name[=value] ...]"
#: builtins.c:78
msgid "typeset [-aAfFilrtux] [-p] name[=value] ..."
-msgstr "typeset [-aAfFilrtux] [-p] 名前[=値] ..."
+msgstr "typeset [-aAfFilrtux] [-p] name[=value] ..."
#: builtins.c:80
msgid "local [option] name[=value] ..."
-msgstr "local [オプション] 名前[=値] ..."
+msgstr "local [option] name[=value] ..."
#: builtins.c:83
msgid "echo [-neE] [arg ...]"
-msgstr "echo [-neE] [引数 ...]"
+msgstr "echo [-neE] [arg ...]"
#: builtins.c:87
msgid "echo [-n] [arg ...]"
-msgstr "echo [-n] [引数 ...]"
+msgstr "echo [-n] [arg ...]"
#: builtins.c:90
msgid "enable [-a] [-dnps] [-f filename] [name ...]"
-msgstr "enable [-a] [-dnps] [-f ファイル名] [名前 ...]"
+msgstr "enable [-a] [-dnps] [-f filename] [name ...]"
#: builtins.c:92
msgid "eval [arg ...]"
-msgstr "eval [引数 ...]"
+msgstr "eval [arg ...]"
#: builtins.c:94
msgid "getopts optstring name [arg]"
-msgstr "getopts optstring 名前 [引数]"
+msgstr "getopts optstring name [arg]"
#: builtins.c:96
msgid "exec [-cl] [-a name] [command [arguments ...]] [redirection ...]"
-msgstr "exec [-cl] [-a 名前] [コマンド [引数 ...]] [リダイレクト ...]"
+msgstr "exec [-cl] [-a name] [command [arguments ...]] [redirection ...]"
#: builtins.c:98
msgid "exit [n]"
-msgstr "終了 [n]"
+msgstr "exit [n]"
#: builtins.c:100
msgid "logout [n]"
-msgstr "ログアウト [n]"
+msgstr "logout [n]"
#: builtins.c:103
msgid "fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]"
-msgstr ""
+msgstr "fc [-e ename] [-lnr] [first] [last] または fc -s [pat=rep] [command]"
#: builtins.c:107
msgid "fg [job_spec]"
-msgstr "fg [ジョブ指定]"
+msgstr "fg [job_spec]"
#: builtins.c:111
msgid "bg [job_spec ...]"
-msgstr "bg [ジョブ指定 ...]"
+msgstr "bg [job_spec ...]"
#: builtins.c:114
msgid "hash [-lr] [-p pathname] [-dt] [name ...]"
-msgstr "hash [-lr] [-p パス名] [-dt] [名前 ...]"
+msgstr "hash [-lr] [-p pathname] [-dt] [name ...]"
#: builtins.c:117
msgid "help [-dms] [pattern ...]"
-msgstr "help [-dms] [パターン ...]"
+msgstr "help [-dms] [pattern ...]"
#: builtins.c:121
msgid "history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]"
-msgstr "history [-c] [-d オフセット] [n] または history -anrw [ファイル名] または history -ps 引数 [引数...]"
+msgstr "history [-c] [-d offset] [n] または history -anrw [filename] または history -ps arg [arg...]"
#: builtins.c:125
msgid "jobs [-lnprs] [jobspec ...] or jobs -x command [args]"
-msgstr "jobs [-lnprs] [ジョブ指定 ...] または jobs -x コマンド [引数]"
+msgstr "jobs [-lnprs] [jobspec ...] または jobs -x command [args]"
#: builtins.c:129
msgid "disown [-h] [-ar] [jobspec ...]"
-msgstr "disown [-h] [-ar] [ジョブ指定 ...]"
+msgstr "disown [-h] [-ar] [jobspec ...]"
#: builtins.c:132
msgid "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]"
-msgstr "kill [-s シグナル指定 | -n シグナル番号 | -シグナル指定] pid | ジョブ指定 ... または kill -l [シグナル指定]"
+msgstr "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... または kill -l [sigspec]"
#: builtins.c:134
msgid "let arg [arg ...]"
#: builtins.c:136
msgid "read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]"
-msgstr "read [-ers] [-a 配列] [-d 区切り文字] [-i テキスト] [-n 文字数] [-N 文字数] [-p プロンプト] [-t タイムアウト] [-u ファイル記述子] [名前 ...]"
+msgstr "read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]"
#: builtins.c:138
msgid "return [n]"
#: builtins.c:140
msgid "set [--abefhkmnptuvxBCHP] [-o option-name] [arg ...]"
-msgstr "set [--abefhkmnptuvxBCHP] [-o オプション名] [引数 ...]"
+msgstr "set [--abefhkmnptuvxBCHP] [-o option-name] [arg ...]"
#: builtins.c:142
msgid "unset [-f] [-v] [name ...]"
-msgstr "unset [-f] [-v] [名前 ...]"
+msgstr "unset [-f] [-v] [name ...]"
#: builtins.c:144
msgid "export [-fn] [name[=value] ...] or export -p"
-msgstr "export [-fn] [名前[=値] ...] または export -p"
+msgstr "export [-fn] [name[=value] ...] or export -p"
#: builtins.c:146
msgid "readonly [-af] [name[=value] ...] or readonly -p"
-msgstr "readonly [-af] [名前[=値] ...] または readonly -p"
+msgstr "readonly [-af] [name[=value] ...] or readonly -p"
#: builtins.c:148
msgid "shift [n]"
#: builtins.c:150
msgid "source filename [arguments]"
-msgstr "source ファイル名 [引数]"
+msgstr "source filename [arguments]"
#: builtins.c:152
msgid ". filename [arguments]"
-msgstr ". ファイル名 [引数]"
+msgstr ". filename [arguments]"
#: builtins.c:155
msgid "suspend [-f]"
#: builtins.c:158
msgid "test [expr]"
-msgstr "test [式]"
+msgstr "test [expr]"
#: builtins.c:160
msgid "[ arg... ]"
-msgstr "[ 引数... ]"
+msgstr "[ arg... ]"
#: builtins.c:162
msgid "times"
#: builtins.c:164
msgid "trap [-lp] [[arg] signal_spec ...]"
-msgstr "trap [-lp] [[引数] シグナル指定 ...]"
+msgstr "trap [-lp] [[arg] signal_spec ...]"
#: builtins.c:166
msgid "type [-afptP] name [name ...]"
-msgstr "type [-afptP] 名前 [名前 ...]"
+msgstr "type [-afptP] name [name ...]"
#: builtins.c:169
msgid "ulimit [-SHacdefilmnpqrstuvx] [limit]"
-msgstr "ulimit [-SHacdefilmnpqrstuvx] [上限]"
+msgstr "ulimit [-SHacdefilmnpqrstuvx] [limit]"
#: builtins.c:172
msgid "umask [-p] [-S] [mode]"
#: builtins.c:182
msgid "for NAME [in WORDS ... ] ; do COMMANDS; done"
-msgstr "for 変数名 [in 語 ... ] ; do コマンド群; done"
+msgstr "for NAME [in WORDS ... ] ; do COMMANDS; done"
#: builtins.c:184
msgid "for (( exp1; exp2; exp3 )); do COMMANDS; done"
-msgstr "for (( 式1; 式2; 式3 )); do コマンド群; done"
+msgstr "for (( exp1; exp2; exp3 )); do COMMANDS; done"
#: builtins.c:186
msgid "select NAME [in WORDS ... ;] do COMMANDS; done"
-msgstr "select 変数名 [in 語 ... ;] do コマンド群; done"
+msgstr "select NAME [in WORDS ... ;] do COMMANDS; done"
#: builtins.c:188
msgid "time [-p] pipeline"
-msgstr ""
+msgstr "time [-p] pipeline"
#: builtins.c:190
msgid "case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac"
-msgstr "case 語 in [パターン [| パターン]...) コマンド群 ;;]... esac"
+msgstr "case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac"
#: builtins.c:192
msgid "if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi"
-msgstr "if コマンド群; then コマンド群; [ elif コマンド群; then コマンド群; ]... [ else コマンド群; ] fi"
+msgstr "if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi"
#: builtins.c:194
msgid "while COMMANDS; do COMMANDS; done"
-msgstr "while コマンド群; do コマンド群; done"
+msgstr "while COMMANDS; do COMMANDS; done"
#: builtins.c:196
msgid "until COMMANDS; do COMMANDS; done"
-msgstr "until コマンド群; do コマンド群; done"
+msgstr "until COMMANDS; do COMMANDS; done"
#: builtins.c:198
msgid "coproc [NAME] command [redirections]"
-msgstr "coproc [名前] コマンド [リダイレクト]"
+msgstr "coproc [NAME] command [redirections]"
#: builtins.c:200
msgid "function name { COMMANDS ; } or name () { COMMANDS ; }"
-msgstr "function 関数名 { コマンド群 ; } または 関数名() { コマンド群 ; } "
+msgstr "function name { COMMANDS ; } または name () { COMMANDS ; }"
#: builtins.c:202
msgid "{ COMMANDS ; }"
-msgstr "{ コマンド群 ; }"
+msgstr "{ COMMANDS ; }"
#: builtins.c:204
msgid "job_spec [&]"
-msgstr "ジョブ指定 [&]"
+msgstr "job_spec [&]"
#: builtins.c:206
msgid "(( expression ))"
-msgstr "(( 式 ))"
+msgstr "(( expression ))"
#: builtins.c:208
msgid "[[ expression ]]"
-msgstr "[[ 式 ]]"
+msgstr "[[ expression ]]"
#: builtins.c:210
msgid "variables - Names and meanings of some shell variables"
-msgstr ""
+msgstr "変数 - 変数の名前とその意味"
#: builtins.c:213
msgid "pushd [-n] [+N | -N | dir]"
-msgstr "pushd [-n] [+N | -N | ディレクトリ]"
+msgstr "pushd [-n] [+N | -N | dir]"
#: builtins.c:217
msgid "popd [-n] [+N | -N]"
#: builtins.c:224
msgid "shopt [-pqsu] [-o] [optname ...]"
-msgstr "shopt [-pqsu] [-o] [オプション名 ...]"
+msgstr "shopt [-pqsu] [-o] [optname ...]"
#: builtins.c:226
msgid "printf [-v var] format [arguments]"
-msgstr "printf [-v var] 書式文字列 [引数]"
+msgstr "printf [-v var] format [arguments]"
#: builtins.c:229
msgid "complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]"
-msgstr ""
+msgstr "complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]"
#: builtins.c:233
msgid "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]"
-msgstr ""
+msgstr "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]"
#: builtins.c:237
msgid "compopt [-o|+o option] [-DE] [name ...]"
-msgstr "compopt [-o|+o オプション] [-DE] [名前 ...]"
+msgstr "compopt [-o|+o option] [-DE] [name ...]"
#: builtins.c:240
msgid "mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"
-msgstr ""
+msgstr "mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"
#: builtins.c:242
msgid "readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"
-msgstr ""
+msgstr "readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"
#: builtins.c:254
msgid ""
" Exit Status:\n"
" bind returns 0 unless an unrecognized option is given or an error occurs."
msgstr ""
+"Readline のキーバインディングと変数を設定します。\n"
+" \n"
+" キーシーケンスを Readline 関数またはマクロに関連付けを行うか、Readline\n"
+" 変数を設定します。オプションが無い引数の構文は ~/.inputrc の構文と\n"
+" 同様です。しかし、単一の引数として与えなければなりません。\n"
+" 例: bind '\"\\C-x\\C-r\": re-read-init-file'\n"
+" \n"
+" オプション:\n"
+" -m keymap Use KEYMAP as the keymap for the duration of this\n"
+" command. Acceptable keymap names are emacs,\n"
+" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n"
+" vi-command, and vi-insert.\n"
+" -l 関数名一覧を表示します。\n"
+" -P 関数名およびキーバインディング一覧を表示します。\n"
+" -p 関数名とキーバインディングを入力として再利用可能な\n"
+" 形式で一覧表示します。\n"
+" -S List key sequences that invoke macros and their values\n"
+" -s List key sequences that invoke macros and their values\n"
+" in a form that can be reused as input.\n"
+" -V 変数名と値の一覧を表示します。\n"
+" -v 変数名と値を入力として再利用可能な形式で一覧\n"
+" 表示します。\n"
+" -q function-name 関数名がどのキーによって起動されるか探索します\n"
+" -u function-name 関数名にバインドされたすべてのキーを解除します。\n"
+" -r keyseq KEYSEQ に対するバインドを解除します。\n"
+" -f filename FILENAME からキーバインドを読み込みます。\n"
+" -x keyseq:shell-command\tKEYSEQ が入力された時に SHELL-COMMAND \n"
+" \t\t\t\tが実行されるようにします。\n"
+" \n"
+" 終了ステータス:\n"
+" bind は解釈できないオプションが渡された場合およびエラーが発生した場合\n"
+" を除き 0 を返します。"
#: builtins.c:326
msgid ""
" N階層のループを終了します。\n"
" \n"
" 終了ステータス:\n"
-" N が1以上の場合を除き、終了ステータスは 0 です。"
+" N が1未満の場合を除き、終了ステータスは 0 です。"
#: builtins.c:338
msgid ""
" Exit Status:\n"
" The exit status is 0 unless N is not greater than or equal to 1."
msgstr ""
+"for, while, または until ループを再開します。\n"
+" \n"
+" FOR, WHILE または UNTIL ループの次の繰り返しを再開します。\n"
+" もし N が指定された場合、N 階層のループを再開します。\n"
+" \n"
+" 終了ステータス:\n"
+" N が1未満の場合を除き、終了ステータスは 0 です。"
#: builtins.c:350
msgid ""
" Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is\n"
" not a shell builtin.."
msgstr ""
+"シェル組み込みコマンドを実行します。\n"
+" \n"
+" コマンドを検索しないでシェル組み込みコマンドを ARG をつけて実行し\n"
+" ます。これはシェル組み込みコマンドをシェル関数として実装するが、関数\n"
+" 内で組み込みコマンドを実行する必要がある場合に役に立ちます。\n"
+" \n"
+" 終了ステータス:\n"
+" シェル組み込みコマンドの終了ステータスを返します。シェル組み込みコマ\n"
+" ンドが無い場合は false を返します。"
#: builtins.c:365
msgid ""
" Returns 0 unless the shell is not executing a shell function or EXPR\n"
" is invalid."
msgstr ""
+"現在のサブルーチン呼び出しのコンテキストを返します。\n"
+" \n"
+" EXPR が無い場合 \"$line $filename\" を返します。 EXPR がある場合、\n"
+" \"$line $subroutine $filename\" を返します。この追加の情報はスタックトレース\n"
+" を提供する時に利用します。\n"
+" \n"
+" EXPR の値は現在のフレームに戻るまでに何回フレームが呼び出されているかを\n"
+" 意味します。最上位のフレームは 0 です。\n"
+" \n"
+" 終了ステータス:\n"
+" シェルが関数を実行できないか式 EXPR が無効な場合を除き 0 を返します。\n"
+" is invalid."
#: builtins.c:383
msgid ""
" Exit Status:\n"
" Returns 0 if the directory is changed; non-zero otherwise."
msgstr ""
+"シェルのカレントディレクトリを変更します。\n"
+" \n"
+" カレントディレクトリを`ディレクトリ'に変更します。`ディレクトリ'の\n"
+" デフォルトは HOME シェル変数です。\n"
+" \n"
+" CDPATH はディレクトリが含まれる検索パスを定義します。CDPATH にはコロン(:)\n"
+" で区切られた代替ディレクトリを指定します。\n"
+" NULL のディレクトリ名はカレントディレクトリと同義です。ディレクトリが\n"
+" スラッシュ (/) から始まる場合は CDPATH は利用されません。\n"
+" \n"
+" ディレクトリが見つからなく、かつ `cdabl_vars' シェルオプションが設定されて\n"
+" いる場合、引数は変数名として扱われます。その変数に値がある場合、その値が\n"
+" DIR として扱われます。\n"
+" \n"
+" オプション:\n"
+" -L\tシンボリックリンクを強制的にたどります\n"
+" -P\tシンボリックリンクをたどらず物理構造を利用します\n"
+" \n"
+" デフォルトでは `-L' が指定された場合と同様シンボリックリンクをたどります\n"
+" \n"
+" 終了ステータス:\n"
+" ディレクトリを変更した場合は 0、そうでなければ 0 以外です。"
#: builtins.c:411
msgid ""
" Returns 0 unless an invalid option is given or the current directory\n"
" cannot be read."
msgstr ""
+"カレントディレクトリの名前を表示します。\n"
+" \n"
+" オプション:\n"
+" -L\t$PWD がカレントディレクトリの名前を指している場合は $PWD\n"
+" \tを表示します。\n"
+" -P\tシンボリックリンクを辿った物理的なディレクトリを表示します。\n"
+" \n"
+" デフォルトでは `pwd' は `-L' が指定されたように動作します。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションまたはカレントディレクトリを読み込めない場合を除き\n"
+" 0を返します。"
#: builtins.c:428
msgid ""
" Exit Status:\n"
" Returns exit status of COMMAND, or failure if COMMAND is not found."
msgstr ""
+"単純なコマンドを実行するかコマンドに関する情報を表示します。\n"
+" \n"
+" シェル関数の探索を抑止して COMMAND を引数 ARGS で実行します。または\n"
+" 指定した COMMANDs の情報を表示します。シェル関数と同じ名前のコマンド\n"
+" がディスク上に存在する時に使用します。\n"
+" \n"
+" オプション:\n"
+" -p\tuse a default value for PATH that is guaranteed to find all of\n"
+" \tthe standard utilities\n"
+" -v\t`type'組み込み関数と同様に COMMAND の説明を表示します。\n"
+" -V\tCOMMAND に対してより冗長な説明を表示します。\n"
+" \n"
+" 終了ステータス:\n"
+" COMMAND の終了ステータスを返します。または COMMAND が見つからない時に失敗を返します。"
#: builtins.c:476
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is supplied or an error occurs."
msgstr ""
+"変数の値および属性を設定します。\n"
+" \n"
+" 変数を宣言し、それに属性を与えます。NAME を指定しない場合\n"
+" すべての変数に対する属性と値を表示します。\n"
+" \n"
+" オプション:\n"
+" -f\trestrict action or display to function names and definitions\n"
+" -F\trestrict display to function names only (plus line number and\n"
+" \tsource file when debugging)\n"
+" -p\tdisplay the attributes and value of each NAME\n"
+" \n"
+" 属性を設定するオプション:\n"
+" -a\tNAME をインデックス型配列にします(サポートされている場合)\n"
+" -A\tNAME を連想配列にします(サポートされている場合)\n"
+" -i\tNAME に`整数型'の属性を設定します。\n"
+" -l\tNAME の設定時に値を小文字に変換します\n"
+" -r\tNAME を読み取り専用にします\n"
+" -t\tNAME に `trace' 属性を設定します\n"
+" -u\tNAME 設定時に値を大文字に設定します\n"
+" -x\tNAME をエクスポートします\n"
+" \n"
+" `-' の代わりに `+' を使用すると与えられた属性を無効にします。\n"
+" \n"
+" 整数属性を与えられた変数は値を割り当てられた時に、数値として評価され\n"
+" ます。(`let' コマンド参照してください。)\n"
+" \n"
+" 関数内で使用された場合は `local' コマンドを使用した時と同様に `declare' \n"
+" は NAME をローカル変数にします。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられたかエラーが発生しない限り成功を返します。"
#: builtins.c:512
msgid ""
" \n"
" Obsolete. See `help declare'."
msgstr ""
+"変数の値および属性を設定します。\n"
+" \n"
+" 旧式です。`help declare'を参照してください。"
#: builtins.c:520
msgid ""
" Returns success unless an invalid option is supplied, an error occurs,\n"
" or the shell is not executing a function."
msgstr ""
+"ローカル変数を定義します。\n"
+" \n"
+" NAME という名前のローカル変数を定義し値を VALUE に設定します。`declare'と\n"
+" 同じオプションを受け付けます。\n"
+" \n"
+" ローカル変数はシェル関数の中でのみ使用できます。宣言された関数の中およびそこ\n"
+" から呼び出された関数のみで参照できます。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられる、エラーが発生する、またはシェルが関数を実行できない\n"
+" 場合を除き成功を返します。"
#: builtins.c:537
msgid ""
" Exit Status:\n"
" Returns success unless a write error occurs."
msgstr ""
+"引数を標準出力に書き出します。\n"
+" \n"
+" 引数 ARG を最後に改行を加えて標準出力に表示します。\n"
+" \n"
+" オプション:\n"
+" -n\t最後に改行を加えない\n"
+" -e\t下記に示すバックスラッシュエスケープの解釈を有効にする\n"
+" -E\tバックスラッシュエスケープの解釈を明示的に無効にする\n"
+" \n"
+" `echo' では下記のバックスラッシュエスケープ文字を解釈します:\n"
+" \\a\tアラート (bell)\n"
+" \\b\tバックスペース\n"
+" \\c\t以降の出力を抑止\n"
+" \\e\tエスケープ文字\n"
+" \\f\tフォームフィード\n"
+" \\n\t改行\n"
+" \\r\tキャリッジリターン\n"
+" \\t\t水平タブ\n"
+" \\v\t垂直タブ\n"
+" \\\\\tバックスラッシュ\n"
+" \\0nnn\tASCII コードが NNN (8進数) の文字。 NNN は0から3個の8進数字\n"
+" \\xHH\t値が HH (16進数) の8ビット文字。HH は 1 または2個の16進数字\n"
+" \n"
+" 終了ステータス:\n"
+" 書き込みエラーが発生しない限り成功を返します。"
#: builtins.c:571
msgid ""
" Exit Status:\n"
" Returns success unless a write error occurs."
msgstr ""
+"引数を標準出力に書き出します。\n"
+" \n"
+" 引数 ARG を最後に改行を加えて標準出力に表示します。\n"
+" \n"
+" オプション:\n"
+" -n\t最後に改行を加えない\n"
+" \n"
+" 終了ステータス:\n"
+" 書き込みエラーが発生しない限り成功を返します。"
#: builtins.c:586
msgid ""
" Exit Status:\n"
" Returns success unless NAME is not a shell builtin or an error occurs."
msgstr ""
+"シェル組み込み関数を有効または無効にします。\n"
+" \n"
+" シェル組み込み関数を有効または無効にします。シェル組み込み関数を無効にすると\n"
+" ディスク上に存在するシェル組み込み関数と同じ名前のコマンドをフルパスを指定す\n"
+" ることなく実行することが出来ます。\n"
+" \n"
+" オプション:\n"
+" -a\t組み込み関数の一覧をそれぞれが有効か否かを含めて表示します\n"
+" -n\tNAME を無効にするか、または無効な組み込み関数一覧を表示します\n"
+" -p\t組み込み関数一覧を再利用可能な形式で表示します\n"
+" -s\tPosix で定義されている組み込み関数のみ表示します\n"
+" \n"
+" 動的ロードを制御するオプション:\n"
+" -f\t共有オブジェクト FILENAME から組み込み関数 NAME を読み込みます\n"
+" -d\t-f で読み込まれた組み込み関数を削除します\n"
+" \n"
+" オプション無しで起動された場合、各 NAME は有効になります。\n"
+" \n"
+" $PATH 上に存在する `test' をシェル組み込み関数の代わりに利用する場合は\n"
+" `enable -n test'と入力してください。\n"
+" \n"
+" 終了ステータス:\n"
+" NAME が組み込み関数ではないかエラーが発生しない限り成功を返します。"
#: builtins.c:614
msgid ""
" Exit Status:\n"
" Returns exit status of command or success if command is null."
msgstr ""
+"引数をシェルコマンドとして実行します。\n"
+" \n"
+" 引数を一つの文字列に連結し、その結果をシェルへの入力として使用し、\n"
+" その結果をコマンドとして実行します。\n"
+" \n"
+" 終了ステータス:\n"
+" コマンドの終了ステータスを返します。コマンドが null の場合は成功を\n"
+" 返します。"
#: builtins.c:626
+#, fuzzy
msgid ""
"Parse option arguments.\n"
" \n"
" Returns success if an option is found; fails if the end of options is\n"
" encountered or an error occurs."
msgstr ""
+"オプション引数を解析します。\n"
+" \n"
+" Getopts は位置パラメーターをオプションとして解析する際にシェルによっ\n"
+" て使用される手続です。\n"
+" \n"
+" OPTSTRING には認識されるオプションの文字が含まれます。文字の後に\n"
+" コロン(:)が続く場合は、オプションは空白文字でオプションから区切\n"
+" られた引数を持つと予期されます。\n"
+" \n"
+" Each time it is invoked, getopts will place the next option in the\n"
+" shell variable $name, initializing name if it does not exist, and\n"
+" the index of the next argument to be processed into the shell\n"
+" variable OPTIND. OPTIND is initialized to 1 each time the shell or\n"
+" a shell script is invoked. When an option requires an argument,\n"
+" getopts places that argument into the shell variable OPTARG.\n"
+" \n"
+" getopts reports errors in one of two ways. If the first character\n"
+" of OPTSTRING is a colon, getopts uses silent error reporting. In\n"
+" this mode, no error messages are printed. If an invalid option is\n"
+" seen, getopts places the option character found into OPTARG. If a\n"
+" required argument is not found, getopts places a ':' into NAME and\n"
+" sets OPTARG to the option character found. If getopts is not in\n"
+" silent mode, and an invalid option is seen, getopts places '?' into\n"
+" NAME and unsets OPTARG. If a required argument is not found, a '?'\n"
+" is placed in NAME, OPTARG is unset, and a diagnostic message is\n"
+" printed.\n"
+" \n"
+" If the shell variable OPTERR has the value 0, getopts disables the\n"
+" printing of error messages, even if the first character of\n"
+" OPTSTRING is not a colon. OPTERR has the value 1 by default.\n"
+" \n"
+" Getopts normally parses the positional parameters ($0 - $9), but if\n"
+" more arguments are given, they are parsed instead.\n"
+" \n"
+" Exit Status:\n"
+" Returns success if an option is found; fails if the end of options is\n"
+" encountered or an error occurs."
#: builtins.c:668
msgid ""
" Exit Status:\n"
" Returns success unless COMMAND is not found or a redirection error occurs."
msgstr ""
+"シェルを与えられたコマンドで置換します。\n"
+" \n"
+" 指定したプログラムでシェルを置換して COMMAND を実行します。ARGUMENTS は\n"
+" COMMAND の引数となります。もし COMMAND が指定されない場合は、現在のシェル\n"
+" に対する全てのリダイレクトが行われます。\n"
+" \n"
+" オプション:\n"
+" -a name\tNAME を COMMAND の 0 番目の引数として与えます\n"
+" -c\t\tCOMMAND を環境変数なしで実行します\n"
+" -l\t\tdash(-) を COMMAND の 0 番目の引数とします\n"
+" \n"
+" もしコマンドが実行できない場合、非対話的なシェルは終了し、対話的なシェルは\n"
+" オプション `execfail' が設定されます。\n"
+" \n"
+" 終了ステータス:\n"
+" COMMAND が見つからないかリダイレクトエラーが発生しない限り成功を返します。"
#: builtins.c:689
msgid ""
" Exits the shell with a status of N. If N is omitted, the exit status\n"
" is that of the last command executed."
msgstr ""
+"シェルを終了します。\n"
+" \n"
+" 終了ステータス N でシェルを終了します。 N を指定しない場合は\n"
+" 最後に実行したコマンドの終了ステータスになります。"
#: builtins.c:698
msgid ""
" Exits a login shell with exit status N. Returns an error if not executed\n"
" in a login shell."
msgstr ""
+"ログインシェルを終了します。\n"
+" \n"
+" 終了ステータス N でログインシェルを終了します。実行したのがログインシェル\n"
+" 内で無い場合はエラーを返します。"
#: builtins.c:708
msgid ""
" Exit Status:\n"
" Returns success or status of executed command; non-zero if an error occurs."
msgstr ""
+"ヒストリ一覧からコマンドを表示または実行します。\n"
+" \n"
+" fc はヒストリ一覧を表示または編集してコマンドを再実行するために使用します。\n"
+" FIRST および LAST は範囲を指定する数値です。FIRST は文字列を指定することも\n"
+" できます。その場合はその文字列で始まる直近に実行したコマンドを表します。\n"
+" \n"
+" オプション:\n"
+" -e ENAME\t使用するエディタを選択します。デフォルトは FCEDIT で、次は EDITOR、\n"
+" \t\tそして vi の順です。\n"
+" -l \t編集ではなく行を一覧表示します\n"
+" -n\t一覧表示時に行番号を表示しません\n"
+" -r\t行を逆順にします (最新のコマンドを最初にする)\n"
+" \n"
+" `fc -s [pat=rep ...] [command]' 形式を使用すると、COMMAND は\n"
+" OLD=NEW の置換が行われた後に再実行されます。\n"
+" \n"
+" これを使った使いやすいエイリアスは r='fc -s' です。これで `r cc' を実行する\n"
+" と最後に実行した cc で始まるコマンドが実行されます。`r' で直前のコマンドが\n"
+" 実行されます。\n"
+" \n"
+" 終了ステータス:\n"
+" 実行したコマンドのステータスまたは成功が帰ります。エラーが発生した場合は 0 \n"
+" 以外の値になります。"
#: builtins.c:738
msgid ""
" Exit Status:\n"
" Status of command placed in foreground, or failure if an error occurs."
msgstr ""
+"ジョブをフォアグランドにします。\n"
+" \n"
+" JOB_SPEC で識別されたジョブをフォアグランドにして、現在のジョブにします。\n"
+" もし JOB_SPEC が存在しない場合、シェルが現在のレントジョブとして考えている\n"
+" ものが利用されます。\n"
+" \n"
+" \n"
+" 終了ステータス:\n"
+" フォアグラウンドになったコマンドのステータスを返します。または、エラーが\n"
+" 発生した時に失敗を返します。"
#: builtins.c:753
msgid ""
" Exit Status:\n"
" Returns success unless job control is not enabled or an error occurs."
msgstr ""
+"ジョブをバックグラウンドにします。\n"
+" \n"
+" JOB_SPEC で識別されるジョブを `&' と共に始めた時のようにバックグラウンドに\n"
+" します。もし JOB_SPEC が存在しない場合、シェルが現在のジョブとして考えてい\n"
+" るものが利用されます。\n"
+" \n"
+" 終了ステータス:\n"
+" ジョブ制御が有効になっていないかエラーが発生しない限り成功を返します。"
#: builtins.c:767
msgid ""
" Exit Status:\n"
" Returns success unless NAME is not found or an invalid option is given."
msgstr ""
+"プログラムの位置を記憶または表示します。\n"
+" \n"
+" 各コマンド NAME のフルパスを決定し記憶します。もし引数が与えられなかった場合、\n"
+" 記憶しているコマンドの情報が表示されます。\n"
+" \n"
+" オプション:\n"
+" -d\t\t各 NAME に対して記憶している情報を消去します\n"
+" -l\t\t入力として再可能な形式で表示します\n"
+" -p pathname\tNAME のフルパス名として PATHNAME を使用します\n"
+" -r\t\t全ての記憶している位置情報を消去します\n"
+" -t\t\t各 NAME に対して記憶している位置を表示します。複数の NAME\n"
+" \t\tが与えられた場合、位置を表示する前に対象となる NAME を表示します。\n"
+" 引数:\n"
+" NAME\t\t各 NAME は $PATH の中を探索され、記録されたコマンド一覧に\n"
+" \t\t追加されます。\n"
+" \n"
+" 終了ステータス:\n"
+" NAME が見つからないか、無効なオプションが与えられない限り成功を返します。"
#: builtins.c:792
msgid ""
" Exit Status:\n"
" Returns success unless PATTERN is not found or an invalid option is given."
msgstr ""
+"組み込みコマンドの情報を表示します。\n"
+" \n"
+" 組み込みコマンドに関する簡潔な要約を表示します。もし PATTERN が\n"
+" 指定された場合は、PATTERN に一致する全てのコマンドに対する詳細な\n"
+" ヘルプを表示します。それ以外はヘルプトピックを表示します。\n"
+" \n"
+" オプション:\n"
+" -d\t各ヘルプトピックに対して短い説明を出力します\n"
+" -m\t使用法を擬似的な man ページ形式で表示します\n"
+" -s\t一致した各トピックに対して簡単な使用法のみを表示します\n"
+" \tPATTERN\n"
+" \n"
+" 引数:\n"
+" PATTERN\tヘルプトピックを指定するパターン\n"
+" \n"
+" 終了ステータス:\n"
+" PATTERN が見つからないか無効なオプションが与えられない限り成功を返します。"
#: builtins.c:816
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is given or an error occurs."
msgstr ""
+"ヒストリ一覧を表示または操作します。\n"
+" \n"
+" 行番号をつけてヒストリを表示します。操作した各項目には前に`*'が付きます。\n"
+" 引数 N がある場合は最後の N 個の項目のみを表示します。\n"
+" \n"
+" オプション:\n"
+" -c\tヒストリ一覧から全ての項目を削除します。\n"
+" -d offset\tOFFSET 番目のヒストリ項目を削除します。\n"
+" \n"
+" -a\tこのセッションからヒストリファイルに行を追加します\n"
+" -n\tヒストリファイルからまだ読み込まれていない行を全て読み込みます\n"
+" -r\tヒストリファイルを読み込み、内容をヒストリ一覧に追加します\n"
+" -w\t現在のヒストリをヒストリファイルに書き込みます。そしてそれらを\n"
+" \tヒストリ一覧に追加します\n"
+" \n"
+" -p\t各 ARG に対してヒストリ展開を実行し、結果をヒストリ一覧に追加し\n"
+" \tしないで表示します\n"
+" -s\tARG を単一の項目としてヒストリ一覧に追加します\n"
+" \n"
+" FILENAME を与えた場合、FILENAME がヒストリファイルをして使用されます。それが\n"
+" 無く、$HISTFILE に値がある場合その値が使用されます。そうでなければ \n"
+" ~/.bash_history が使用されます。\n"
+"\n"
+" もし $HISTTIMEFORMAT 変数が設定され、NULL で無ければ、strftime(3) の書式\n"
+" 文字列として各ヒストリ項目の時刻を表示する際に使用されます。それ以外は\n"
+" 時刻は表示されません。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるかエラーが発生しない限り成功を返します。"
#: builtins.c:852
msgid ""
" Returns success unless an invalid option is given or an error occurs.\n"
" If -x is used, returns the exit status of COMMAND."
msgstr ""
+"ジョブのステータスを表示します。\n"
+" \n"
+" アクティブなジョブを一覧表示します。JOBSPEC はジョブの出力を制限します。\n"
+" オプションがない場合全てのアクティブなジョブのステータスが表示されます。\n"
+" \n"
+" オプション:\n"
+" -l\t通常の情報に加えてプロセスIDを一覧表示します\n"
+" -n\t最後の通知からステータスが変更になったプロセスのみ一覧表示\n"
+" \tします\n"
+" -p\tプロセスIDのみを一覧表示します\n"
+" -r\t実行中のジョブの出力を制限します\n"
+" -s\t停止中のジョブの出力を制限します\n"
+" \n"
+" If -x is supplied, COMMAND is run after all job specifications that\n"
+" appear in ARGS have been replaced with the process ID of that job's\n"
+" process group leader.\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるかエラーが発生しない限り成功を返します。\n"
+" もし -x が使用された場合、COMMAND の終了ステータスを返します。"
#: builtins.c:879
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option or JOBSPEC is given."
msgstr ""
+"現在のシェルからジョブを削除します。\n"
+" \n"
+" アクティブなジョブのテーブルから各引数の JOBSPEC を削除します。JOBSPEC が指定\n"
+" されない場合、シェルが現在のジョブと考えている物が使用されます。\n"
+" \n"
+" オプション:\n"
+" -a\tJOBSPEC が与えられない時に全てのジョブを削除します\n"
+" -h\tシェルが SIGHUP を受け取った時に各 JOBSPEC のジョブに対して SIGHUP \n"
+" \tが送られないようにマークします\n"
+" -r\t実行中のジョブのみ削除します\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションか JOBSPEC が与えられない限り成功を返します。"
#: builtins.c:898
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is given or an error occurs."
msgstr ""
+"ジョブにシグナルを送ります。\n"
+" \n"
+" PID または JOBSPEC で識別されるプロセスに SIGSPEC または SIGNUM で名付けら\n"
+" れるシグナルを送ります。もし SIGSPEC も SIGNUM も指定されない場合、SIGTERM\n"
+" と見なされます。\n"
+" \n"
+" オプション:\n"
+" -s sig\tSIG はシグナル名です\n"
+" -n sig\tSIG はシグナル番号です\n"
+" -l\tシグナル名を一覧表示します。-l の後に引数が続いた場合、\n"
+" \tそれらは一覧表示されるべきシグナル番号であると見なされます\n"
+" \n"
+" Kill は次の2つの理由からシェル組み込み関数です。一つはプロセスIDの代わりに\n"
+" ジョブIDを使用できるようにするためです。もう一つは作成したプロセスが制限に\n"
+" 達した時にプロセスを kill することができるようにするためです。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるかエラーが発生しない限り成功を返します。"
#: builtins.c:921
msgid ""
" Exit Status:\n"
" If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.."
msgstr ""
+"数式表現を評価します。\n"
+" \n"
+" ARG を数式表現として評価します。評価は固定長の整数として評価され、桁溢れは\n"
+" 確認されません。しかし、0 で割り算をした場合は捕捉されエラーとしてフラグが\n"
+" 立ちます。下記の演算子一覧は同一優先順位の演算子毎にグループ化されています。\n"
+" 優先順位は降順になっています。\n"
+" \n"
+" \tid++, id--\t変数の後置インクリメント、デクリメント\n"
+" \t++id, --id\t変数の前置インクリメント、デクリメント\n"
+" \t-, +\t\t単項マイナス、プラス\n"
+" \t!, ~\t\t論理およびビット否定\n"
+" \t**\t\t指数演算\n"
+" \t*, /, %\t\t乗算、除算、剰余演算\n"
+" \t+, -\t\t加算、減算\n"
+" \t<<, >>\t\t左および右ビットシフト\n"
+" \t<=, >=, <, >\t比較\n"
+" \t==, !=\t\t等価、不等価\n"
+" \t&\t\tビット論理積\n"
+" \t^\t\tビット排他的論理和\n"
+" \t|\t\tビット論理和\n"
+" \t&&\t\t論理積\n"
+" \t||\t\t論理和\n"
+" \texpr ? expr : expr\n"
+" \t\t\t条件演算子\n"
+" \t=, *=, /=, %=,\n"
+" \t+=, -=, <<=, >>=,\n"
+" \t&=, ^=, |=\t値の割当\n"
+" \n"
+" シェル変数はオペランドとして使用できます。変数名は数式内で (強制的に\n"
+" 固定長整数の) 値に置き換えられます。変数は数式内で使用する時には必ずしも\n"
+" 整数属性を持っている必要はありません。\n"
+" \n"
+" 演算子は優先順位の順に評価されます。小括弧でくくられた数式は先に評価され、\n"
+" 上記の優先順位を上書きするかもしれません。\n"
+" \n"
+" 終了ステータス:\n"
+" ARG の評価値が 0 の場合 let は 1 を返します。それ以外の場合は let は 0 を返します。"
#: builtins.c:966
msgid ""
" The return code is zero, unless end-of-file is encountered, read times out,\n"
" or an invalid file descriptor is supplied as the argument to -u."
msgstr ""
+"標準入力から一行読み込みフィールド毎に分割します。\n"
+" \n"
+" 標準入力から一行読み込みます。または -u が指定されている場合はファイル記述子\n"
+" FD から読み込みます。行は単語分割によってフィールドに分割され、最初の単語が\n"
+" 最初の NAME に、2番目の単語が2番目に NAME にという順で割り当てられます。残っ\n"
+" た単語は全て最後の NAME に割り当てられます。変数 $IFS に設定された文字のみが\n"
+" 単語の区切りとして認識されます。\n"
+" \n"
+" もし NAME を指定しなかった場合、行は REPLY 変数に保存されます。\n"
+" \n"
+" オプション:\n"
+" -a array\t読み込んだ単語をインデックス型配列 ARRAY に順番に割り当てます。\n"
+" \t\t開始番号は 0 です。\n"
+" -d delim\t改行ではなく文字 DELIM が最初に現れるまで読み込みを続けます\n"
+" -e\t\t対話的シェルで行を得るのに Readline を使用します\n"
+" -i text\tReadline の初期テキストとして TEXT を使用します\n"
+" -n nchars\t改行が無くても文字数 NCHARS を読み込んだら復帰します。NCHARS\n"
+" \t\tより前に区切り文字 (DELIMITER) が現れた場合は区切り文字が\n"
+" \t\t優先されます\n"
+" -N nchars\t厳密に文字数 NCHARS を読み込み復帰します。ただし、ファイル終\n"
+" \t\t了(EOF) になるか読み込みタイムアウトが発生した場合は除きます。\n"
+" \t\t区切り文字 (DELIMITER) は無視されます\n"
+" -p prompt\t読み込み前に文字列 PROMPT を後ろに改行を付けないで表示します\n"
+" -r\t\tバックスペースで文字をエスケープすることを禁止します\n"
+" -s\t\t端末から読み込まれる文字をエコーバックしません\n"
+" -t timeout\tTIMEOUT 秒以内に入力行が完全に読み込まれなかった場合\n"
+" \t\tタイムアウトを発生させ失敗として復帰します。TMOUT 変数の値が\n"
+" \t\tデフォルトのタイムアウトです。TIMEOUT を小数にすることもでき\n"
+" \t\tます。もし TIMEOUT が 0 の場合、指定したファイル記述子からの\n"
+" \t\t入力が使用可能な場合にのみ読み込み、成功返します。タイムアウ\n"
+" \t\tト発生時の終了ステータスは128より大きくなります\n"
+" -u fd\t\t読み込みに標準入力ではなくファイル記述子 FD を使用します\n"
+" \n"
+" 終了ステータス:\n"
+" ファイル終了(EOF)、読み込みタイムアウト、-u に無効なファイル記述子が与え\n"
+" られた場合を除き0を返します。"
#: builtins.c:1009
msgid ""
" Exit Status:\n"
" Returns N, or failure if the shell is not executing a function or script."
msgstr ""
+"シェル関数から復帰します。\n"
+" \n"
+" N で指定した値を戻り値として関数または source されたスクリプトを終了します。\n"
+" N が指定されない場合、関数またはスクリプトで最後に実行したコマンドの戻り値\n"
+" が使用されます。\n"
+" \n"
+" 終了ステータス:\n"
+" 戻り値 N、またはシェルが関数またはスクリプトを実行していない場合は失敗を\n"
+" 返します。"
#: builtins.c:1022
+#, fuzzy
msgid ""
"Set or unset values of shell options and positional parameters.\n"
" \n"
" Exit Status:\n"
" Returns success unless an invalid option is given."
msgstr ""
+"シェルオプションや位置パラメーターの値を設定・消去します\n"
+" \n"
+" シェル属性や位置パラメーターの値を変更、またはシェル変数の名前と値\n"
+" を表示します。\n"
+" \n"
+" オプション:\n"
+" -a Mark variables which are modified or created for export.\n"
+" -b Notify of job termination immediately.\n"
+" -e コマンドの終了ステータスが 0 以外の場合は即時終了します。 \n"
+" -f Disable file name generation (globbing).\n"
+" -h Remember the location of commands as they are looked up.\n"
+" -k All assignment arguments are placed in the environment for a\n"
+" command, not just those that precede the command name.\n"
+" -m ジョブ制御を有効にします。\n"
+" -n コマンドを読み込みますが実行しません。\n"
+" -o option-name\n"
+" Set the variable corresponding to option-name:\n"
+" allexport same as -a\n"
+" braceexpand same as -B\n"
+" emacs use an emacs-style line editing interface\n"
+" errexit same as -e\n"
+" errtrace same as -E\n"
+" functrace same as -T\n"
+" hashall same as -h\n"
+" histexpand same as -H\n"
+" history enable command history\n"
+" ignoreeof the shell will not exit upon reading EOF\n"
+" interactive-comments\n"
+" allow comments to appear in interactive commands\n"
+" keyword same as -k\n"
+" monitor same as -m\n"
+" noclobber same as -C\n"
+" noexec same as -n\n"
+" noglob same as -f\n"
+" nolog currently accepted but ignored\n"
+" notify same as -b\n"
+" nounset same as -u\n"
+" onecmd same as -t\n"
+" physical same as -P\n"
+" pipefail the return value of a pipeline is the status of\n"
+" the last command to exit with a non-zero status,\n"
+" or zero if no command exited with a non-zero status\n"
+" posix change the behavior of bash where the default\n"
+" operation differs from the Posix standard to\n"
+" match the standard\n"
+" privileged same as -p\n"
+" verbose same as -v\n"
+" vi use a vi-style line editing interface\n"
+" xtrace same as -x\n"
+" -p Turned on whenever the real and effective user ids do not match.\n"
+" Disables processing of the $ENV file and importing of shell\n"
+" functions. Turning this option off causes the effective uid and\n"
+" gid to be set to the real uid and gid.\n"
+" -t Exit after reading and executing one command.\n"
+" -u Treat unset variables as an error when substituting.\n"
+" -v Print shell input lines as they are read.\n"
+" -x Print commands and their arguments as they are executed.\n"
+" -B the shell will perform brace expansion\n"
+" -C If set, disallow existing regular files to be overwritten\n"
+" by redirection of output.\n"
+" -E If set, the ERR trap is inherited by shell functions.\n"
+" -H Enable ! style history substitution. This flag is on\n"
+" by default when the shell is interactive.\n"
+" -P If set, do not follow symbolic links when executing commands\n"
+" such as cd which change the current directory.\n"
+" -T If set, the DEBUG trap is inherited by shell functions.\n"
+" - Assign any remaining arguments to the positional parameters.\n"
+" The -x and -v options are turned off.\n"
+" \n"
+" Using + rather than - causes these flags to be turned off. The\n"
+" flags can also be used upon invocation of the shell. The current\n"
+" set of flags may be found in $-. The remaining n ARGs are positional\n"
+" parameters and are assigned, in order, to $1, $2, .. $n. If no\n"
+" ARGs are given, all shell variables are printed.\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられない限り成功を返します。"
#: builtins.c:1104
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is given or a NAME is read-only."
msgstr ""
+"シェル変数および関数の値・属性を消去します。\n"
+" \n"
+" 各 NAMEに対して関連する値または関数を削除します。\n"
+" \n"
+" オプション:\n"
+" -f\t各 NAME をシェル関数として扱います\n"
+" -v\t各 NAME をシェル変数として扱います\n"
+" \n"
+" オプションが無い場合、最初に変数を消去しようと試みます。失敗した場合には\n"
+" 関数を消去しようと試みます。\n"
+" \n"
+" いくつかの変数は消去できません。`readonly' も参照してください。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるか NAME が読み取り専用の場合を除き成功を返します。"
#: builtins.c:1124
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is given or NAME is invalid."
msgstr ""
+"シェル変数に export 属性を設定します。\n"
+" \n"
+" 各 NAME に対して後に続けて実行されるコマンドの環境変数として自動的に\n"
+" エクスポートされるようにマークします。VALUE が与えられた場合はエクス\n"
+" ポートする前に値を設定します。\n"
+"\n"
+" オプション:\n"
+" -f\tシェル関数を参照します\n"
+" -n\t各 NAME に対してエクスポート属性を削除します\n"
+" -p\t全てのエクスポートされた変数・関数一覧を表示します\n"
+" \n"
+" 引数 `--' 以降はオプションとして処理されません。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるか、無効な NAME が与えられない限り成功\n"
+" を返します。"
#: builtins.c:1143
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is given or NAME is invalid."
msgstr ""
+"シェル変数を変更不可にします。\n"
+" \n"
+" 各 NAME を読み取り専用にします。これらの NAME の値はこれ以降の代入で\n"
+" 変更ができなくなります。VALUE が与えられた場合、読み取り専用にする前\n"
+" に値が設定されます。\n"
+" \n"
+" オプション:\n"
+" -a\tインデックス型配列変数を示します\n"
+" -A\t連想配列変数を示します\n"
+" -f\tシェル関数を示します\n"
+" -p\t全ての読み取り専用変数・関数の一覧を表示します\n"
+" \n"
+" 引数 `--' は以降のオプション処理を無効にします\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるか、与えられた NAME が無効な場合を除き成功\n"
+" を返します。"
#: builtins.c:1164
msgid ""
" Exit Status:\n"
" Returns success unless N is negative or greater than $#."
msgstr ""
+"位置パラメーターをシフトします。\n"
+" \n"
+" 位置パラメーター名 $N+1,$N+2 ... を $1,$2 ... に変更します。 \n"
+" N が与えられなかった場合、1 と見なされます。\n"
+" \n"
+" 終了ステータス:\n"
+" Nが負の値または $# より大きい場合を除き成功を返します。"
#: builtins.c:1176 builtins.c:1191
msgid ""
" Returns the status of the last command executed in FILENAME; fails if\n"
" FILENAME cannot be read."
msgstr ""
+"ファイルを読み込み現在のシェルでコマンドを実行します。\n"
+" \n"
+" FILENAME を読み込み現在のシェルでコマンドを実行します。$PATH の項目が\n"
+" FILENAME が含まれるディレクトリを見つけるために使用されます。引数\n"
+" ARGUMENTS が与えられた場合 FILENAME を実行する際の位置パラメーターと\n"
+" して使用されます。\n"
+" \n"
+" 終了ステータス:\n"
+" FILENAME で最後に実行したコマンドのステータスを返します。FILENAME が\n"
+" 読み込めなかった場合は失敗を返します。"
#: builtins.c:1207
msgid ""
" Exit Status:\n"
" Returns success unless job control is not enabled or an error occurs."
msgstr ""
+"シェルの実行を一時停止します。\n"
+" \n"
+" SIGCONT シグナルを受け取るまでこのシェルの実行を一時停止します。強制\n"
+" オプションが無い限りログインシェルは一時停止できません。\n"
+" \n"
+" オプション:\n"
+" -f\tシェルがログインシェルだとしても強制的に一時停止します\n"
+" \n"
+" 終了ステータス:\n"
+" ジョブ制御が有効でないかエラーが発生しない限り成功を返します。"
#: builtins.c:1223
msgid ""
" Returns success if EXPR evaluates to true; fails if EXPR evaluates to\n"
" false or an invalid argument is given."
msgstr ""
+"条件式を評価します。\n"
+" \n"
+" 式 EXPR の結果に応じて 0 (真、true) または 1 (偽、false) を返します。\n"
+" 式は単項演算子または二項演算子です。単項演算子はファイルのステータス\n"
+" を評価するために使用されます。文字列演算子に加えて数値比較演算子も\n"
+" 存在します。\n"
+" \n"
+" ファイル演算子:\n"
+" \n"
+" -a FILE ファイルが存在する時に真(true)。\n"
+" -b FILE ファイルがブロック特殊デバイスの時に真(true)。\n"
+" -c FILE ファイルがキャラクタ特殊デバイスの時に真(true)。\n"
+" -d FILE ファイルがディレクトリの時に真(true)。\n"
+" -e FILE ファイルが存在する時に真(true)。\n"
+" -f FILE ファイルが存在し、通常ファイルの時に真(true)。\n"
+" -g FILE ファイルに setgid が設定されている時に真(true)。\n"
+" -h FILE ファイルがシンボリックリンクの時に真(true)。\n"
+" -L FILE ファイルがシンボリックリンクの時に真(true)。\n"
+" -k FILE ファイルに sticky ビットが設定されている時に真(true)。\n"
+" -p FILE ファイルが名前付きパイプの時に真(true)。\n"
+" -r FILE ファイルがユーザに対して読み込み可能な時に真(true)。\n"
+" -s FILE ファイルが存在し、かつ空ファイルでない場合に真(true)。\n"
+" -S FILE ファイルがソケットの場合に真(true)。\n"
+" -t FD FD(ファイル識別子) が端末に開いている時に真(true)。\n"
+" -u FILE ファイルに setuid が設定されている時に真(true)。\n"
+" -w FILE ファイルがユーザに対して書き込み可能な時に真(true)。\n"
+" -x FILE ファイルがユーザに対して実行可能な時に真(true)。\n"
+" -O FILE ファイルをユーザが実効的に所有されている時に真(true)。\n"
+" -G FILE ファイルのグループにユーザが実効的に所属している時に真(true)。\n"
+" -N FILE ファイルを最後に読み込んだ以降に変更されている時に真(true)。\n"
+" \n"
+" FILE1 -nt FILE2 file1 が file2 より新しい時(更新時間に基づく)に真(true)。\n"
+" \n"
+" \n"
+" FILE1 -ot FILE2 file1 が file2 より古い時に真(true)。\n"
+" \n"
+" FILE1 -ef FILE2 file1 が file2 に対するハードリンクの時に真(true)。\n"
+" \n"
+" 文字列演算子:\n"
+" \n"
+" -z STRING 文字列が空の時に真(true)。\n"
+" \n"
+" -n STRING\n"
+" STRING 文字列が空でない時に真(true)。\n"
+" \n"
+" STRING1 = STRING2\n"
+" 文字列が同一の時に真(true)。\n"
+" STRING1 != STRING2\n"
+" 文字列が同一でない時に真(true)。\n"
+" STRING1 < STRING2\n"
+" 辞書順で STRING1 が STRING2 より前の時に真(true)。\n"
+" STRING1 > STRING2\n"
+" 辞書順で STRING1 が STRING2 より後の時に真(true)。\n"
+" \n"
+" その他演算子:\n"
+" \n"
+" -o OPTION シェルオプション OPTION が有効な時に真(true)。\n"
+" ! EXPR 式 expr が偽(fales)の時に真(true)。\n"
+" EXPR1 -a EXPR2 式 expr1 および expr2 の両方とも真(true)の時に真(true)。\n"
+" EXPR1 -o EXPR2 式 expr1 または expr2 のいずれかが真(true)の時に真(true)。\n"
+" \n"
+" arg1 OP arg2 数値比較演算を行います。OP は -eq, -ne, -lt, -le, -gt,\n"
+" または -ge のいずれかです。\n"
+" \n"
+" 数値演算二項演算子は ARG1 と ARG2 の関係がそれぞれ、等しい(-eq)、\n"
+" 等しくない(-ne)、より小さい(-lt)、以下(-le)、より大きい(-gt)、または\n"
+" 以上(-ge)の時に真(true)を返します。\n"
+" \n"
+" 終了ステータス:\n"
+" 式 EXPR の評価値が真(true)の時に成功を返します。EXPR の評価値が偽(false) または\n"
+" 引数が無効な場合に失敗を返します。"
#: builtins.c:1299
msgid ""
" This is a synonym for the \"test\" builtin, but the last argument must\n"
" be a literal `]', to match the opening `['."
msgstr ""
+"条件式を評価します。\n"
+" \n"
+" これは test 組み込み関数と同義語です。ただし、最後の引数に開始の`['と一致\n"
+" するように文字`]'を与えなければいけません。"
#: builtins.c:1308
msgid ""
" Exit Status:\n"
" Always succeeds."
msgstr ""
+"プロセスの時間を表示します。\n"
+" \n"
+" シェルとその子プロセスが使用したユーザー時間とシステム時間それぞれの累積を\n"
+" 表示します。\n"
+" \n"
+" 終了ステータス:\n"
+" 常に成功を返します。"
#: builtins.c:1320
msgid ""
" Exit Status:\n"
" Returns success unless a SIGSPEC is invalid or an invalid option is given."
msgstr ""
+"シグナルまたは他のイベントをトラップします。\n"
+" \n"
+" シェルがシグナルを受け取るか他の条件が発生した時に実行されるハンドラーを\n"
+" 定義および有効化します。\n"
+" \n"
+" ARG はシグナル SIGNAL_SPEC を受け取った時に読み込まれ実行されるコマンド\n"
+" です。もし ARG が無い (かつシグナル SIGNAL_SPEC が与えられた場合) または\n"
+" `-' の場合、各指定したシグナルはオリジナルの値にリセットされます。\n"
+" ARG が NULL 文字列の場合、各シグナル SIGNAL_SPEC はシェルにおよび起動さ\n"
+" れたコマンドによって無視されます。\n"
+" \n"
+" もし SIGNAL_SPEC が EXIT (0) の場合、ARG がシェルの終了時に実行されます。\n"
+" もし SIGNAL_SPEC が DEBUGの場合 ARG は単に毎回コマンドの前に実行されます。\n"
+" \n"
+" もし引数が与えられない場合、 trap は各シグナルに割り当てられたコマンドの\n"
+" 一覧を表示します。\n"
+" \n"
+" オプション:\n"
+" -l\tシグナル名とシグナル番号の対応一覧を表示します\n"
+" -p\t各 SIGNAL_SPEC に関連づけられた trap コマンドを表示します\n"
+" \n"
+" 各 SIGNAL_SPEC は <signal.h> にあるシグナル名かシグナル番号です。シグ\n"
+" ナル名は大文字小文字を区別しません。また SIG 接頭辞はオプションです。\n"
+" シグナルはシェルに対して \"kill -signal $$\" で送ることができます。\n"
+" \n"
+" 終了ステータス:\n"
+" SIGSPEC が無効か、無効なオプションを与えられない限り成功を返します。"
#: builtins.c:1352
msgid ""
" Exit Status:\n"
" Returns success if all of the NAMEs are found; fails if any are not found."
msgstr ""
+"コマンドの種類に関する情報を表示します。\n"
+" \n"
+" 各 NAME に対してコマンド名として使われた時にどのように解釈されるかを\n"
+" 示します。\n"
+" \n"
+" オプション:\n"
+" -a\tNAME という名前になっている実行可能なものの全ての位置を表示し\n"
+" \tます。これには `-p' が同時に指定されていない場合に限ってエイリアス、\n"
+" \t組み込み関数、シェル関数も含みます\n"
+" -f\tシェル関数の検索を抑止します\n"
+" -P\t各 NAME に対して PATH 探索を強制します。エイリアス、組み込み\n"
+" \t関数、シェル関数があったとしても実行されるディスク上のファイル名を\n"
+" \t返します\n"
+" -p\t実行されるディスク上のファイル名を返します。`type -t NAME'\n"
+" \tが `file' を返さない場合、何も返しません。\n"
+" -t\t次のいずれかの単語を返します。`alias', `keyword', `function',\n"
+" \t `builtin', `file' or `'。それぞれ NAME がエイリアス、シェル予約語、\n"
+" \tシェル関数、シェル組み込み関数、ディスク上のファイル、何も見つからない\n"
+" \tに対応します。\n"
+" \n"
+" 引数:\n"
+" NAME\t解釈するコマンドの名前です。\n"
+" \n"
+" 終了ステータス:\n"
+" 全ての NAME が見つかった場合に成功を返します。どれかが見つからなかった場合\n"
+" は失敗を返します。"
#: builtins.c:1383
msgid ""
" Exit Status:\n"
" Returns success unless an invalid option is supplied or an error occurs."
msgstr ""
+"シェルの資源制限を変更します。\n"
+" \n"
+" シェルおよびシェルが作成するプロセスが使用可能な資源に対する制御を提供します。\n"
+" ただし、システムがそのような制御を許可している場合です。\n"
+" \n"
+" オプション:\n"
+" -S\t`soft' 資源制限を使用します\n"
+" -H\t`hard' 資源制限を使用します\n"
+" -a\t現在の全ての資源制限を表示します\n"
+" -b\tソケットバッファサイズ\n"
+" -c\t作成されるコアファイルの最大サイズ\n"
+" -d\tプロセスデータセグメントの最大サイズ\n"
+" -e\tスケジュール優先度の最大値 (`nice')\n"
+" -f\tシェル及び子プロセスが書き込み可能なファイルサイズの最大値\n"
+" -i\t保留するシグナルの最大数\n"
+" -l\tメモリにロックできるプロセスの最大サイズ\n"
+" -m\t最大のメモリサイズ\n"
+" -n\tファイル記述子を開くことができる最大数\n"
+" -p\tパイプのバッファサイズ\n"
+" -q\tPOSIX message queues の最大バイト数\n"
+" -r\tリアルタイムスケジュール優先度の最大値\n"
+" -s\tスタックサイズの最大値\n"
+" -t\tCPU時間総量の最大値 (秒単位)\n"
+" -u\tユーザープロセスの最大数\n"
+" -v\t仮想メモリのサイズ\n"
+" -x\tファイルロックの最大数\n"
+" \n"
+" LIMIT が与えられた場合、指定した資源に対する新しい値になります。特別な\n"
+" LIMIT の値である `soft'、`hard'、および `unlimited' は現在の `soft' 制限\n"
+" 現在の`hard' 制限および制限なしをそれぞれ意味します。\n"
+" それ以外の場合、指定した資源の現在の値が表示されます。オプションが与え\n"
+" られなかった場合 -f と見なされます。\n"
+" \n"
+" 値は 1024 バイト単位で増加します。例外は -t が秒単位、-p が 512バイト\n"
+" 単位、および -u は1プロセス単位です。\n"
+" \n"
+" 終了ステータス:\n"
+" 無効なオプションが与えられるかエラーが発生しない限り成功を返します。"
#: builtins.c:1428
msgid ""
" Exit Status:\n"
" Returns success unless MODE is invalid or an invalid option is given."
msgstr ""
+"ファイルのモードマスクを表示または設定します。\n"
+" \n"
+" ユーザーがファイル作成時のマスクを MODE に設定します。MODE が指定されない場合\n"
+" 現在のマスクの値を表示します。\n"
+" \n"
+" MODE が数値で開始した場合8進数として解釈されます。それ以外は chmod(1) で受け\n"
+" 入れられるシンボルモードの文字列として扱われます。\n"
+" \n"
+" オプション:\n"
+" -p\tMODE が指定されない場合、入力として再利用可能な形式で表示します\n"
+" -S\tシンボルモードで出力します。それ以外は8進数で出力します\n"
+" \n"
+" 終了ステータス:\n"
+" MODE が無効か、無効なオプションが与えられない限り成功を返します。"
#: builtins.c:1448
msgid ""
" Returns the status of ID; fails if ID is invalid or an invalid option is\n"
" given."
msgstr ""
+"ジョブの実行完了を待ち、終了ステータスを返します。\n"
+" \n"
+" ID で識別されるプロセス (プロセスID または ジョブ指定) を待ち、その終了\n"
+" ステータスを返します。ID が与えられない場合、現在アクティブな全ての子プ\n"
+" ロセスを待ち 0 を返します。ID がジョブ指定の場合ジョブのパイプラインに\n"
+" ある全てのプロセスを待ちます。\n"
+" \n"
+" 終了ステータス:\n"
+" ID の終了ステータスを返します。IDが無効であるか、無効なオプションが\n"
+" 与えられた場合には失敗を返します。"
#: builtins.c:1466
msgid ""
" Returns the status of ID; fails if ID is invalid or an invalid option is\n"
" given."
msgstr ""
+"プロセスの実行完了を待ち、終了ステータスを返します。\n"
+" \n"
+" 指定されたプロセスを待ち、その終了ステータスを返します。PID が与えられ\n"
+" ない場合、現在アクティブな全ての子プロセスを待ち、0 を返します。PID は\n"
+" プロセスIDでなければなりません。\n"
+" \n"
+" 終了ステータス:\n"
+" IDの終了ステータスを返します。IDが無効か、無効なオプションが与えられた\n"
+" 場合はエラーを返します。"
#: builtins.c:1481
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"リストの各要素に対してコマンドを実行します。\n"
+" \n"
+" `for' ループではリストの各要素に対して一連のコマンドを実行します。\n"
+" `in WORDS ...;' が存在しない場合、`in \"$@\"' であると見なされます。\n"
+" WORDS の要素が NAME の値として代入され COMMANDS が実行されます。\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1495
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"算術 for ループ\n"
+" \n"
+" 以下と等価です。\n"
+" \t(( EXP1 ))\n"
+" \twhile (( EXP2 )); do\n"
+" \t\tCOMMANDS\n"
+" \t\t(( EXP3 ))\n"
+" \tdone\n"
+" EXP1、EXP2、および EXP3 は数式です。いずれかの数式を省略した場合、\n"
+" 値が 1 であるとして評価されます。\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1513
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"Select words from a list and execute commands.\n"
+" \n"
+" The WORDS are expanded, generating a list of words. The\n"
+" set of expanded words is printed on the standard error, each\n"
+" preceded by a number. If `in WORDS' is not present, `in \"$@\"'\n"
+" is assumed. The PS3 prompt is then displayed and a line read\n"
+" from the standard input. If the line consists of the number\n"
+" corresponding to one of the displayed words, then NAME is set\n"
+" to that word. If the line is empty, WORDS and the prompt are\n"
+" redisplayed. If EOF is read, the command completes. Any other\n"
+" value read causes NAME to be set to null. The line read is saved\n"
+" in the variable REPLY. COMMANDS are executed after each selection\n"
+" until a break command is executed.\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1534
msgid ""
" Exit Status:\n"
" The return status is the return status of PIPELINE."
msgstr ""
+"パイプラインを実行する時に消費された時間を報告します。\n"
+" \n"
+" PIPELINE を実行し、終了時に PIPELINE を実行するために費やされた実\n"
+" 時間、ユーザー CPU 時間、およびシステム CPU 時間の要約を表示します。\n"
+" \n"
+" オプション:\n"
+" -p\t移植性のある Posix 形式で時間の要約を表示します\n"
+" \n"
+" 変数 TIMEFORMAT の値が出力の形式として使用されます。\n"
+" \n"
+" 終了ステータス:\n"
+" PIPELINE の戻り値が終了ステータスとなります。"
#: builtins.c:1551
msgid ""
msgstr ""
#: builtins.c:1563
+#, fuzzy
msgid ""
"Execute commands based on conditional.\n"
" \n"
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"条件に従ってコマンドを実行します。\n"
+" \n"
+" The `if COMMANDS' list is executed. If its exit status is zero, then the\n"
+" `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is\n"
+" executed in turn, and if its exit status is zero, the corresponding\n"
+" `then COMMANDS' list is executed and the if command completes. Otherwise,\n"
+" the `else COMMANDS' list is executed, if present. The exit status of the\n"
+" entire construct is the exit status of the last command executed, or zero\n"
+" if no condition tested true.\n"
+" \n"
+" Exit Status:\n"
+" Returns the status of the last command executed."
#: builtins.c:1580
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"テストが成功する限りコマンドを実行します。\n"
+" \n"
+" `while' COMMANDS にある最後のコマンドの終了ステータスが 0 である間 \n"
+" COMMANDS を展開して実行します。\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1592
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"テストが失敗する限りコマンドを実行します。\n"
+" \n"
+" `until' COMMANDS にある最後のコマンドの終了ステータスが 0 でない間\n"
+" COMMANDS を展開して実行します。\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1604
msgid ""
" Exit Status:\n"
" Returns the exit status of COMMAND."
msgstr ""
+"NAME という名前の非同期プロセスを作成します。\n"
+" \n"
+" COMMAND を非同期で実行します。コマンドの標準出力および標準入力は実行\n"
+" しているシェルのインデックス型配列変数 NAME の要素添字 0、1 に設定\n"
+" されるファイル記述子へのパイプとして接続されます。\n"
+" デフォルトの NAME は \"COPROC\" です。\n"
+" \n"
+" 終了ステータス:\n"
+" COMMAND の終了ステータスを返します。"
#: builtins.c:1618
msgid ""
" Exit Status:\n"
" Returns success unless NAME is readonly."
msgstr ""
+"シェル関数を定義します。\n"
+" \n"
+" NAME という名前のシェル関数を作成します。単にコマンドとして起動された時は\n"
+" NAME は COMMANDs をシェルのコンテキスト内で呼び出します。NAME を起動した\n"
+" 時に引数は関数に $1...$n という位置パラメーターで、関数名は $FUNCNAME\n"
+" 変数として渡されます。\n"
+" \n"
+" 終了ステータス:\n"
+" NAME が読み取り専用でない限り成功を返します。"
#: builtins.c:1632
msgid ""
" Exit Status:\n"
" Returns the status of the last command executed."
msgstr ""
+"複数のコマンドを一つにグループ化します。\n"
+" \n"
+" 複数のコマンドをグループにして1セットとして実行します。これはコマンド\n"
+" のセット全体をリダイレクトする一つの方法です。\n"
+" \n"
+" 終了ステータス:\n"
+" 最後に実行したコマンドのステータスを返します。"
#: builtins.c:1644
msgid ""
" Exit Status:\n"
" Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise."
msgstr ""
+"算術式を評価します。\n"
+" \n"
+" 算術式の規定に基づいて EXPRESSION を評価します。\"let EXPRESSION\"\n"
+" と等価です。\n"
+" \n"
+" 終了ステータス:\n"
+" EXPRESSION の評価値が 0 の場合は 1、それ以外は 0 を返します。"
#: builtins.c:1671
msgid ""
" HISTIGNORE\tA colon-separated list of patterns used to decide which\n"
" \t\tcommands should be saved on the history list.\n"
msgstr ""
+"通常の変数名とその使用法。\n"
+" \n"
+" BASH_VERSION\tBashのバージョン情報。\n"
+" CDPATH\t`cd`の引数として与えられたディレクトリを検索する際に\n"
+" \t\t使用されるコロン (:) で区切られたディレクトリの一覧。\n"
+" GLOBIGNORE\tパス名を展開する時に無視されるコロン (:) で区切られた\n"
+" \t\tファイル名パターンの一覧。\n"
+" HISTFILE\tコマンドヒストリが保存されるファイル名。\n"
+" HISTFILESIZE\tヒストリファイルに保存することができる最大行数。\n"
+" HISTSIZE\t実行中のシェルがアクセスできる最大ヒストリ行数。\n"
+" HOME\tログインディレクトリの完全パス名。\n"
+" HOSTNAME\t現在のホスト名。\n"
+" HOSTTYPE\tこのバージョンの Bash を実行している CPU の種類。\n"
+" IGNOREEOF\tControls the action of the shell on receipt of an EOF\n"
+" \t\tcharacter as the sole input. If set, then the value\n"
+" \t\tof it is the number of EOF characters that can be seen\n"
+" \t\tin a row on an empty line before the shell will exit\n"
+" \t\t(default 10). When unset, EOF signifies the end of input.\n"
+" MACHTYPE\tA string describing the current system Bash is running on.\n"
+" MAILCHECK\tBash がメールを確認する頻度 (秒単位)。\n"
+" MAILPATH\tBash が新規メールを確認するコロン (:) で区切られた\n"
+" \t\tファイル名の一覧。\n"
+" OSTYPE\tこのバージョンの Bash を実行している OS のバージョン。\n"
+" PATH\tコマンドを検索する際に使用されるコロン (:) で区切ら\n"
+" \t\tれたディレクトリの一覧。\n"
+" PROMPT_COMMAND\tプライマリプロンプトが表示される前に毎回実行\n"
+" \t\tされるコマンド。\n"
+" PS1\t\tプライマリプロンプト文字列。\n"
+" PS2\t\tセカンダリプロンプト文字列。\n"
+" PWD\t\t現在のディレクトリの完全パス名。\n"
+" SHELLOPTS\tコロン (:) で区切られた有効なシェルオプション一覧。\n"
+" TERM\t現在の端末種類名。\n"
+" TIMEFORMAT\tThe output format for timing statistics displayed by the\n"
+" \t\t`time' reserved word.\n"
+" auto_resume\tNon-null means a command word appearing on a line by\n"
+" \t\titself is first looked for in the list of currently\n"
+" \t\tstopped jobs. If found there, that job is foregrounded.\n"
+" \t\tA value of `exact' means that the command word must\n"
+" \t\texactly match a command in the list of stopped jobs. A\n"
+" \t\tvalue of `substring' means that the command word must\n"
+" \t\tmatch a substring of the job. Any other value means that\n"
+" \t\tthe command must be a prefix of a stopped job.\n"
+" histchars\tCharacters controlling history expansion and quick\n"
+" \t\tsubstitution. The first character is the history\n"
+" \t\tsubstitution character, usually `!'. The second is\n"
+" \t\tthe `quick substitution' character, usually `^'. The\n"
+" \t\tthird is the `history comment' character, usually `#'.\n"
+" HISTIGNORE\tA colon-separated list of patterns used to decide which\n"
+" \t\tcommands should be saved on the history list.\n"
#: builtins.c:1754
msgid ""