From 49208bd78b2ad01c3279cec5efb641f3c507118e Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 13 Aug 2012 11:58:12 -0400 Subject: [PATCH] bash-20120727 remove leftover and stray files --- CWRU/CWRU.chlog~ | 14292 -------------------------- CWRU/POSIX.NOTES.old | 82 - CWRU/old/set.def.save | 544 - CWRU/save/unwind_prot.h.save | 50 - bashline.c~ | 4118 -------- builtins/cd.def~ | 555 - builtins/fc.def~ | 683 -- builtins/pushd.def~ | 778 -- builtins/ulimit.def~ | 779 -- cross-build/cygwin32.cache.old | 42 - ddd1~ | 979 -- doc/FAQ.orig | 1745 ---- doc/bash.1~ | 10187 ------------------ doc/bashref.texi~ | 8585 ---------------- doc/version.texi~ | 19 - eval.c~ | 283 - examples/loadables/Makefile.in.save | 238 - examples/scripts/adventure.sh.save1 | 549 - execute_cmd.c~ | 5354 ---------- externs.h~ | 502 - general.c~ | 1166 --- jobs.c~ | 4312 -------- lib/glob/glob.c~ | 1249 --- lib/malloc/getpagesize.h~ | 60 - lib/readline/callback.c~ | 289 - lib/readline/doc/Makefile.old | 76 - lib/readline/readline.c~ | 1317 --- lib/readline/rltty.c.save1 | 976 -- lib/readline/rltty.c~ | 977 -- lib/readline/signals.c~ | 724 -- lib/readline/util.c~ | 583 -- lib/sh/clktck.c~ | 59 - lib/sh/inet_aton.c~ | 212 - lib/sh/mailstat.c~ | 159 - lib/sh/oslib.c~ | 301 - lib/sh/pathcanon.c~ | 234 - lib/sh/pathphys.c~ | 296 - lib/sh/spell.c~ | 212 - lib/sh/strerror.c~ | 74 - mailcheck.c~ | 491 - mksyntax.c~ | 415 - patchlevel.h~ | 30 - shell.c~ | 1883 ---- sig.c~ | 692 -- subst.c~ | 9495 ----------------- test.c~ | 852 -- tests/RUN-ONE-TEST~ | 9 - tests/misc/regress/log.orig | 50 - tests/misc/regress/shx.orig | 10 - trap.c~ | 1151 --- 50 files changed, 78718 deletions(-) delete mode 100644 CWRU/CWRU.chlog~ delete mode 100644 CWRU/POSIX.NOTES.old delete mode 100644 CWRU/old/set.def.save delete mode 100644 CWRU/save/unwind_prot.h.save delete mode 100644 bashline.c~ delete mode 100644 builtins/cd.def~ delete mode 100644 builtins/fc.def~ delete mode 100644 builtins/pushd.def~ delete mode 100644 builtins/ulimit.def~ delete mode 100644 cross-build/cygwin32.cache.old delete mode 100644 ddd1~ delete mode 100644 doc/FAQ.orig delete mode 100644 doc/bash.1~ delete mode 100644 doc/bashref.texi~ delete mode 100644 doc/version.texi~ delete mode 100644 eval.c~ delete mode 100644 examples/loadables/Makefile.in.save delete mode 100755 examples/scripts/adventure.sh.save1 delete mode 100644 execute_cmd.c~ delete mode 100644 externs.h~ delete mode 100644 general.c~ delete mode 100644 jobs.c~ delete mode 100644 lib/glob/glob.c~ delete mode 100644 lib/malloc/getpagesize.h~ delete mode 100644 lib/readline/callback.c~ delete mode 100644 lib/readline/doc/Makefile.old delete mode 100644 lib/readline/readline.c~ delete mode 100644 lib/readline/rltty.c.save1 delete mode 100644 lib/readline/rltty.c~ delete mode 100644 lib/readline/signals.c~ delete mode 100644 lib/readline/util.c~ delete mode 100644 lib/sh/clktck.c~ delete mode 100644 lib/sh/inet_aton.c~ delete mode 100644 lib/sh/mailstat.c~ delete mode 100644 lib/sh/oslib.c~ delete mode 100644 lib/sh/pathcanon.c~ delete mode 100644 lib/sh/pathphys.c~ delete mode 100644 lib/sh/spell.c~ delete mode 100644 lib/sh/strerror.c~ delete mode 100644 mailcheck.c~ delete mode 100644 mksyntax.c~ delete mode 100644 patchlevel.h~ delete mode 100644 shell.c~ delete mode 100644 sig.c~ delete mode 100644 subst.c~ delete mode 100644 test.c~ delete mode 100755 tests/RUN-ONE-TEST~ delete mode 100644 tests/misc/regress/log.orig delete mode 100644 tests/misc/regress/shx.orig delete mode 100644 trap.c~ diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ deleted file mode 100644 index 3d51c98b1..000000000 --- a/CWRU/CWRU.chlog~ +++ /dev/null @@ -1,14292 +0,0 @@ - 7/27/2004 - --------- - -[bash-3.0 released] - - 7/28 - ---- -array.c - - in array_insert(), make sure the value to be added is non-NULL before - calling savestring() on it - -builtins/reserved.def - - fix description of `CDPATH' - -lib/readline/display.c - - when expanding a prompt that spans multiple lines with embedded - newlines, set prompt_physical_chars from the portion after the - final newline, not the preceding portion. Bug reported by - "Ralf S. Engelschall" - -make_cmd.c - - explicitly declare `lineno' in function prologue for make_case_command - -builtins/evalfile.c - - include `trap.h' for declaration for run_return_trap - -bashline.c - - fix a `return' without a value in enable_hostname_completion - -general.c - - include test.h for extern declaration for test_eaccess - -externs.h - - add declaration for zcatfd - -tests/{history,histexp}.tests - - unset HISTFILESIZE to avoid problems if a value of 0 is inherited - from the environment - - 7/30 - ---- -bashline.c - - small changes to glob_expand_word to perform tilde expansion before - attempting globbing - -builtins/Makefile.in - - fix the install-help target to not cd into the `helpfiles' - subdirectory, so a value of $INSTALL_DATA containing a relative - pathname (e.g., .././support/install.sh) remains valid - - 7/31 - ---- -subst.c - - new function, mbstrlen(s), returns length of a multibyte character - string - -include/shmbutil.h - - new macro, MB_STRLEN(s), calls mbstrlen or STRLEN as appropriate - -builtins/trap.def - - small change so that a first argument that's a valid signal number - (digits only -- no symbolic names) will be treated as a signal and - reverted back to the original handling disposition. Fixes debian - complaints - -subst.c - - call MB_STRLEN instead of STRLEN where appropriate in - parameter_brace_expand_length to handle multibyte characters properly - - call MB_STRLEN instead of strlen in verify_substring_values so that - negative substrings of strings with multibyte chars work properly - - 8/1 - --- -jobs.c - - describe_pid needs to write to stderr, not stdout (POSIX) - - start_job, since it's only used by builtins (fg/bg), needs to write - its output to stdout, not stderr (POSIX) - -sig.c - - add an `orig_flags' member to struct terminating_signal so the - original signal handling flags (SA_RESTART, etc.) can be preserved - on POSIX systems - - make sure to preserve the signal flags state in - initialize_terminating_signals and reset them for child processes - in reset_terminating_signals - -builtins/fc.def - - fixed an off-by-one error that caused `fc -l' to list one too many - history entries - - in posix mode, `fc' should not list any indication as to whether or - not history lines have been modified (POSIX) - - when in posix mode, the default editor for `fc' should be `ed' (POSIX) - -doc/bashref.texi - - updated the description of `trap' behavior when given a first - argument that is a valid signal number - - noted that `fc -l' won't indicate whether a history entry has been - modified if the shell is in posix mode - -builtins/command.def - - fixed bug: `command -v' is supposed to be silent if a command is not - found - -builtins/hash.def - - `hash' should print its `hash table empty' message to stderr - -lib/readline/misc.c - - back out 7/7 change to _rl_maybe_save_line; it breaks emacs-mode ^P - -general.c - - changed base_pathname so that it will return reasonable results for - non-absolute pathnames -- this is what is intended by all of its - callers - -arrayfunc.c - - fix array_variable_part to return NULL if it finds an invisible - variable in the hash table. Fixes seg fault caused by referring to - unset local variable using array notation - -{locale,variables}.c - - support LC_TIME as a special locale variable so HISTTIMEFORMAT tracks - the current locale - - 8/2 - --- -variables.c - - fixed small memory leak in makunbound() when a local array variable - is unset. Fix from William Park - -lib/readline/display.c - - fixed a problem when computing the number of invisible characters on - the first line of a prompt whose length exceeds the screen width - (should only happen when invisible characters occur after the - line wrap). Bug reported by agriffis@gentoo.org - -builtins/command.def - - `command -V' passes a new flag, CDESC_ABSPATH, which means to convert - to an absolute path - -builtins/type.def - - in posix mode, `type' and `command -v/-V' should not report - non-executable files, even if the execution code will attempt to - run them. Other posix shells do this - -doc/bashref.texi - - add note to POSIX Mode section describing behavior of type and command - when finding a non-executable file - -execute_cmd.c - - force extended_glob to 1 before calling binary_test in - execute_cond_node so that the right extended pattern matching gets - performed - - 8/3 - --- -braces.c - - make sure lhs[0] and rhs[0] are cast to `unsigned char' so chars - with values > 128 are handled correctly - -builtins/printf.def - - change bexpand() and printstr() to handle strings with a leading - '\0' whose length is non-zero, since that's valid input for the - `%b' format specifier - -subst.c - - fix a couple of instances of find_variable that didn't check the - result for an invisible variable - -variables.c - - BASH_ARGC, BASH_ARGV, BASH_SOURCE, BASH_LINENO no longer created as - invisible vars - -pcomplete.c - - make sure COMP_WORDS is not invisible when bind_comp_words returns - - ditto for COMPREPLY in gen_shell_function_matches - - 8/4 - --- -braces.c - - fix problem where ${ was ignored but did not increment the open - brace count. Bug reported by Tim Waugh - -variables.c - - if make_local_variable finds a variable in the correct context in - the right variable scope, make sure it's not invisible before - returning it - - 8/5 - --- -builtins/trap.def - - fixed usage message to show `action' as not optional, though it - actually is when not in posix mode (for a single argument) - - 8/7 - --- -configure.in - - kfreebsd-gnu has had its sbrk() problems fixed, and no longer needs - to be configured --without-gnu-malloc - -lib/readline/vi_mode.c - - in rl_vi_search, free any saved history line before starting the - search, so failure leaves you at that line, not the last line in - the history (assuming the current line is not the last history line). - Fix from llattanzi@apple.com to replace fix of 7/7 - - 8/9 - --- -support/Makefile.in - - renamed `mostly-clean' target to `mostlyclean' - - 8/11 - ---- -lib/readline/vi_mode.c - - make same change for EOL in multibyte character case of - rl_vi_change_char - - 8/12 - ---- -subst.c - - in verify_substring_values, fix off-by-one error checking bounds of - `offset', esp. in array values (e.g., getting the highest element - of an array) - - 8/16 - ---- -aclocal.m4 - - change BASH_CHECK_DEV_FD to make sure that file descriptors > 2 are - accessible via /dev/fd, unlike FreeBSD 5.x - -lib/sh/strftime.c - - make sure `zone' is initialized with gettimeofday before it is used - - work around HPUX lack of `altzone' and differing definitions of - `timezone' - -lib/malloc/malloc.c - - internal_memalign and memalign now take a `size_t' as their first - argument, which seems to be the prevailing standard - -lib/malloc/{malloc.c,shmalloc.h} - - change sh_memalign to take a `size_t' as its first argument - -builtins/echo.def - - if posixly_correct and xpg_echo are both set, don't try to interpret - any arguments at all, as POSIX/XOPEN requires (fix inspired by Paul - Eggert) - -doc/bashref.texi - - amend description of bash posix mode to include new echo behavior - -builtins/fg_bg.def - - allow bg to take multiple job arguments, as posix seems to specify, - placing them all in the background, returning the status of the last - one as the status of `bg' - -lib/readline/vi_mode - - fix _rl_vi_change_mbchar_case (multibyte-char version of `~' - command) to have the right behavior at EOL -- handle case where vi - mode backs up at the end of the line - - 8/18 - ---- -array.c - - check for an empty array in array_rshift before shifting elements - and adjusting max_index - - check for null array in array_subrange - -jobs.c - - fix raw_job_exit_status to not ignore exit status of the last - process in the pipeline when `set -o pipefail' is enabled - - 8/19 - ---- -lib/readline/mbutil.c - - make sure _rl_find_next_mbchar_internal has a valid multibyte - character before it checks whether or not it's a zero-width - wide character and adjusts point accordingly - - 8/24 - ---- -bashline.c - - new function, bash_directory_expansion, duplicates the expansions - performed on the directory name by rl_filename_completion_function - - call bash_directory_expansion in command_word_completion_function - if we decide we're doing tilde expansion (and any other - canonicalization) on the directory name being completed - - 8/25 - ---- -configure.in - - use new-style AC_CHECK_HEADER to check for sys/ptem.h (which requires - sys/stream.h). The correct checks are in the code, but autoconf - complains if sys/stream.h is not included, rather than simply - checking for the header's presence - - 8/26 - ---- -builtins/hash.def - - fix a bug that prevented `hash -d' from working right (as soon as - hash removed a command from the table, the bug caused it to be added - right back) - - 8/27 - ---- -doc/{bash.1,bashref.texi} - - explicitly note that conditional primaries that operate on files - operate on the targets of symbolic links rather than the links - themselves - - 8/30 - ---- -lib/readline/display.c - - fix multibyte calculation of `physchars' in prompt expansion, to - handle double-width multibyte characters correctly - - changes to rl_redisplay to handle prompts longer than the screenwidth - that might contain double-width multibyte characters. Fixes from - Tomohiro Kubota - - 9/6 - --- -subst.c - - change word_list_split to avoid really bad behavior caused by calling - list_append for each split word -- as the list gets long, you have - to traverse it every time. Keep a pointer to the end of the list and - and just tack onto it - - 9/8 - --- -lib/readline/complete.c - - change fnprint to calculate the displayed width of a filename in - the same way as fnwidth - -subst.c - - in verify_substring_values, when expanding ${array[@]:offset}, make - sure negative offsets count from one greater than the array's - maximum index so things like ${x[@}: -1} work to give the last element - (requires fixing array tests) - -builtins/common.c - - new error function, sh_wrerror(), for builtins to call when a write - error occurs - -builtins/common.h - - extern declaration for sh_wrerror() - -builtins/cd.def - - change builtin_error call to use sh_wrerror() - -builtins/echo.def - - report write errors with sh_wrerror() instead of just returning - failure - -builtins/printf.def - - change printstr to return failure (-1) or success (0) indication - rather than void - - report write errors when printstr() fails, return failure - - if any of the PF/printf calls fail, report write error and return - failure - -execute_cmd.c - - change execute_in_subshell so the subshell command inherits the - command timing flags from the enclosing COMMAND * - - 9/11 - ---- -[prayers for the victims of 9/11/2001] - -lib/sh/strnlen.c - - new file, implementation of GNU libc extension function strnlen - -lib/sh/Makefile.in, {config.h,configure,Makefile}.in, MANIFEST - - changes for strnlen - -configure.in - - version changed to 3.1-devel - -doc/bash.1, lib/readline/doc/rluser.texi - - added description of `-o plusdirs' to complete/compgen (thanks, - Arnold) - -parse.y - - new parser_state flag, PST_ASSIGNOK, if set indicates we're parsing - arguments to a builtin that accepts assignment statement arguments - - turn on PST_ASSIGNOK in read_token_word when appropriate - - turn off PST_ASSIGNOK in read_token when appropriate - - don't attempt to parse a compound assignment specially unless we're - in a position where an assignment statement is acceptable, or - PST_ASSIGNOK is set - - 9/13 - ---- -variables.c - - make BASH_ARGC, BASH_ARGV, BASH_LINENO, and BASH_SOURCE - non-unsettable, since the shell uses those values internally - -expr.c - - make exponentiation right-associative, as is apparently correct - - 9/16 - ---- -arrayfunc.c - - make sure convert_var_to_array marks the environment as needing - recreation if the converted variable was exported - - 9/17 - ---- -braces.c - - mark ${ as introducing an additional level of braces only if it's - not in a quoted string -- quoted strings are handled before brace - matching is done - -parse.y - - fixed an obscure problem in history_delimiting_chars where the `in' - in a case statement could have a semicolon added after it, if the - `case word' was on a previous line - -support/config.guess - - support for newest versions of tandem non-stop kernel - -lib/readline/display.c - - in compute_lcd_of_matches, explicitly cast `text' to `char *' before - passing it to rl_filename_dequoting_function - -lib/readline/terminal.c - - bind the key sequence sent by the keypad `delete' key to delete-char - (same as ^D in emacs mode) - -builtins/ulimit.def - - in print_all_limits, don't print anything if get_limit returns - -1/EINVAL, indicating that the kernel doesn't support that particular - limit - - add -i (max number of pending signals), -q (max size of posix msg - queues), -x (max number of file locks) for systems (Linux) that - support them - -doc/{bash.1,bashref.texi} - - fix description of correspondence between FUNCNAME, BASH_LINENO, - and BASH_SOURCE indices in description of BASH_LINENO - - 9/18 - ---- -lib/sh/shquote.c - - don't quote CTLESC and CTLNUL with CTLESC in sh_backslash_quote, as - long as the resultant string never gets sent to the word expansion - functions without going through the shell parser - -externs.h - - add extern declarations for strnlen and strpbkrk from lib/sh - -subst.[ch] - - changes to handle case where IFS consists of multibyte characters. - Changed: string_extract_verbatim, split_at_delims, - string_list_dollar_star, string_list_dollar_at, list_string, - get_word_from_string, setifs - - 9/19 - ---- -mailcheck.c - - change file_mod_date_changed to reset the cached mail file data if - the file size drops to zero - -lib/readline/complete.c - - change append_to_match so that a non-zero value for - rl_completion_suppress_append will cause no `/' to be appended to a - directory name - -bashline.c - - experimental change to suppress appending a slash for a completed - filename that is found in PATH as well as a directory in the current - directory under certain circumstances: a single instance found in - $PATH when `.' is not in $PATH, and multiple instances found in the - $PATH, even when `.' is in the $PATH - - 9/24 - ---- -command.h - - new word flag: W_ASSIGNRHS, means word is rhs of assignment statement - - new word flag: W_NOTILDE, means word is not to be tilde expanded - - new word flag (internal): W_ITILDE, means the next character is a - tilde that should be expanded - -general.c - - new set of tilde suffixes for use when parsing the RHS of an - assignment statement and =~ should not be subject to tilde expansion - - if ASSIGN_P argument to bash_tilde_expand is 2, use tilde prefixes - for parsing RHS of assignment statement - -general.[ch] - - new function bash_tilde_find_word, drop-in replacement for - tilde_find_word - -subst.c - - call bash_tilde_expand with secord argument of 2 when expanding rhs - of an assignment statement, so tildes after second and subsequent - `=' in an assignment are not expanded - - new function, expand_string_assignment, to expand the rhs of an - assignment statement - - add `~' to EXP_CHAR, the characters that will cause the word - expansion functions to be called - - move tilde expansion into expand_word_internal instead of many - different calls to bash_tilde_expand scattered across different - functions. NOTE: This means that double quotes surrounding a - {paramOPword} expansion will cause tilde expansion to NOT be - performed on `word'. I think this is right, what POSIX specifies, - and consistent with the behavior of other characters in the rhs - -execute_cmd.c - - take out calls to bash_tilde_expand before calling word expansion - functions - - 9/26 - ---- -execute_cmd.c - - make sure to call UNBLOCK_CHILD before returning on a pipe creation - failure in execute_pipeline - - 9/27 - ---- -variables.c - - change get_bash_command to deal with the_printed_command_except_trap - being NULL - -execute_cmd.c - - fix execute_simple_command to deal with the_printed_command being - NULL when assigning to the_printed_command_except_trap -- fixes - seg fault in savestring() - -parse.y - - change the parser so that the closing `)' in a compound variable - assignment delimits a token -- ksh93 does it this way - -doc/{bash.1,bashref.texi} - - change description of tilde expansion to note that expansion is - attempted only after the first =~ in an assignment statement - -builtins/declare.def - - when assigning to an array variable with declare -a x=(...), make - sure the last character in the rhs of the variable assignment is - `)', not just that it appears somewhere - - 9/28 - ---- -command.h - - add a `W_NOEXPAND' flag to inhibit all expansion except quote removal - - add a `W_COMPASSIGN' flag to denote a word is a compound assignment - statement - -parse.y - - set W_COMPASSIGN on words that appear to be compound assignments - -subst.c - - pass W_NOXPAND and W_COMPASSIGN through end of expand_word_internal - -subst.[ch] - - new function, expand_assignment_string_to_string, calls - expand_string_assignment and then string_list on the result - -variables.c - - assign_in_env now calls expand_assignment_string_to_string - - 9/30 - ---- -builtins/common.c - - change get_job_spec so the null job `%' once again means the current - job - - 10/1 - ---- -subst.c - - do_assignment_internal now takes a WORD_DESC * as its first - argument, and uses its `word' member as the assignment string - - change expand_word_list_internal to call do_word_assignment instead - of do_assignment, passing it `word' instead of, e.g., `word->word' - - change extract_array_assignment_list to just return the passed - string minus a trailing `)' if the last character is a right - paren - - change do_assignment_internal to call extract_array_assignment_list - -subst.[ch] - - change do_assignment and do_assignment_no_expand to take a `char *' - instead of `const char *' first argument; change extern prototypes - - new function, do_word_assignment, takes a WORD_DESC * and calls - do_assignment_internal on it; add extern declaration with prototype - -general.h - - new typedef, sh_wassign_func_t, like sh_assign_func_t but takes a - WORD_DESC * as its first argument - -variables.[ch] - - assign_in_env now takes a WORD_DESC * as its first argument - - 10/2 - ---- -command.h - - new word flag, W_ASSNBLTIN, denotes that the word is a builtin - command (in a command position) that takes assignment statements - as arguments, like `declare' - - new word flags, W_ASSIGNARG, denotes that word is an assignment - statement given as argument to assignment builtin - -execute_cmd.c - - set W_ASSNBLTIN flag in fix_assignment_words if necessary (if there - are any arguments that are assignment statements) - - set W_ASSIGNARG flag in fix_assignment_words if necessary - -subst.c - - new function, do_compound_assignment, encapsulates the necessary - code to perform a compound array assignment (including creation of - local variables); called from do_assignment_internal - - to fix the double-expansion problem with compound array assignments - that are arguments to builtins like `declare', changed - shell_expand_word_list to treat those arguments like assignment - statements (with proper creation of local variables inside shell - functions) and pass the attribute-setting portion of the statement - onto the builtin. This is what ksh93 appears to do, from inspection - of the `ksh93 -x' output - -execute_cmd.c - - fix execute_simple_command: in case of pipeline or async command, - when forking early, set `subshell_environment' so that it can contain - both SUBSHELL_PIPE and SUBSHELL_ASYNC -- the two should not be - mutually exclusive. Fixes bug reported by pierre.humblet@ieee.org - - remove references to last_pid, old_command_subst_pid; use NO_PID as - a sentinel value to decide whether or not a child process has been - created and needs to be waited for. Submitted by - pierre.humblet@ieee.org to fix recycling-pid problem on cygwin - -doc/{bash.1,bashref.texi} - - fixed documentation of `@(pattern)' extended globbing operator -- - it succeeds if the string matches one of the patterns, not exactly - one. This is what ksh93 does, too - -lib/readline/complete.c - - fixed rl_menu_complete so that a negative argument cycles backwards - through the list - - 10/3 - ---- -subst.c - - use W_COMPASSIGN flag in do_assignment_internal instead of deciding - lexically which assignments are compound array assignments - - 10/6 - ---- -support/shobj-conf - - additions for System V.5 from Boyd Gerber - -subst.c - - in command_substitute, if subshell_environment includes - SUBSHELL_ASYNC, call make_child with the `async_p' argument set to - non-zero. This keeps command substitutions for async commands or - pipelines from trying to give the terminal back to the shell's - pgrp. make sure to save and restore last_asynchronous_pid. Fix - suggested by - - 10/7 - ---- -config.h.in - - add a placeholder definition for WCONTINUED_BROKEN - - 10/9 - ---- -aclocal.m4 - - add BASH_CHECK_WCONTINUED, checks for glibc bug where WCONTINUED is - defined but rejected as invalid by waitpid(2) - -configure.in - - add call to BASH_CHECK_WCONTINUED, defines WCONTINUED_BROKEN - -redir.c - - experimental change to add_undo_redirect to save manipulations to - file descriptors >= SHELL_FD_BASE (10) on the list of redirections - to be undone even if `exec' causes the list to be discarded - -doc/{bash.1,bashref.texi} - - note that redirections using file descriptors > 9 should be used - carefully, because they might conflict with file descriptors the - shell uses internally - - 10/11 - ----- -parse.y - - fix pipeline_command production to handle case where `pipeline' - as `argument' of `!' or `time' is null (e.g., a syntax error not - handled by the grammar) - - 10/13 - ----- -lib/readline/readline.c - - new internal variable, _rl_bind_stty_chars; if non-zero, bind the - terminal special characters to readline equivalents at startup - - change readline_default_bindings() and reset_default_bindings() to - understand _rl_bind_stty_chars - -lib/readline/rlprivate.h - - new extern declaration for _rl_bind_stty_chars - -lib/readline/rltty.c - - change rl_prep_terminal to add support for _rl_bind_stty_chars - - 10/15 - ----- -lib/readline/bind.c - - new bindable variable, `bind-tty-special-chars', bound to value of - _rl_bind_stty_chars - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented new readline variable `bind-tty-special-chars' - -builtins/pushd.def - - make the first check for option `--' skip the rest of option - checking - - 10/16 - ----- -lib/readline/shell.c - - change sh_set_lines_and_columns to prefer setenv, which has - predictable memory allocation behavior, to putenv, which does not - - 10/19 - ----- -variables.c - - change push_exported_var so that a tempenv variable has to have the - export attribute set (which they all do -- something to look at) and - the `propagate' attribute set to be propagated down to the next - scope - -execute_cmd.c - - change execute_builtin so that if CMD_COMMAND_BUILTIN is set in the - passed flags argument, call pop_scope with a value that says the - builtin is not special, since `command' means that preceding variable - assignments don't persist in the environment. Fixes problem with - variable assignments preceding command preceding special builtin - keeping those variable assignments around (when in posix mode) - - 10/20 - ----- -lib/sh/shquote.c - - new function, sh_mkdoublequoted, brackets a given string with - double quotes and returns a new string. Flags argument, if non- - zero, means to quote embedded double quotes with backslashes - -externs.h - - new extern declaration for sh_mkdoublequoted - -parse.y - - use sh_mkdoublequoted after calling localeexpand() - -lib/sh/strtrans.c - - change ansicstr to understand that (flags & 4) != 0 means to remove - backslash from unrecognized escape sequences - -general.c - - fix logic problem in assignment() that caused non-variable-starter - characters to be allowed, resulting in things like `1=xxx' creating - a variable `1' in the hash table - - 10/21 - ----- -bashline.c - - don't call programmable_completions with an assignment statement - argument - - 10/22 - ----- -lib/readline/rltty.c - - in prepare_terminal_settings, turn echoing on (readline_echoing_p) - if get_tty_settings fails because the input is not a terminal - - 10/24 - ----- -lib/readline/util.c - - include rlmbutil.h for multibyte definitions - - new function, _rl_walphabetic, wide char version of rl_alphabetic - -lib/readline/mbutil.c - - new function, _rl_char_value(buf, ind), returns value of (possibly - multibyte) character at buf[ind] - -lib/readline/rlmbutil.h - - extern defines for _rl_walphabetic and _rl_char_value for when - multibyte chars are not being used - - new wrapper definitions for _rl_find_next_mbchar (MB_NEXTCHAR) and - _rl_find_prev_mbchar (MB_PREVCHAR) that try to avoid unneeded - function calls - -lib/readline/text.c - - fix rl_foward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - fix rl_backward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - 10/26 - ----- -parse.y - - fix parse_matched_pair so that it doesn't swallow \ when - parsing a $'...' construct (call shell_getc with different arg) - - 10/28 - ----- -lib/glob/glob.c - - after some (compiled-in) threshold, glob_vector will stop using - alloca to allocate `struct globval's and will switch to using - malloc, with appropriate cleanup before returning - -subst.c - - don't expand tildes after `=' in expand_word_internal, even if the - W_TILDEEXP flag is set, unless it's the first tilde in a word - marked W_ASSIGNMENT - - 10/31 - ----- -lib/readline/text.c - - make sure rl_point doesn't go below 0 in rl_delete_horizontal_space - (from SUSE, but not sent in) - -shell.c - - make sure shell_is_restricted skips over a single leading `-' in - the shell name (from SUSE, but not sent in) - -lib/readline/display.c - - disable `fast redisplay' at the end of the line if in a locale that - supports multibyte characters (from SUSE, but not sent in) - -lib/readline/histexpand.c - - fix a problem with finding the delimiter of a `?' substring when - compiled for multibyte characters (from SUSE, but not sent in) - - 11/1 - ---- -lib/readline/display.c - - correct some assignments to _rl_last_c_pos: when in a multibyte - locale, it's used as an absolute cursor position; when not using - multibyte characters, it's a buffer offset. I should have caught - this when the multibyte character support was donated - - 11/5 - ---- -general.c - - change `assignment()' to accept `+=' assignment operator - -arrayfunc.[ch] - - bind_array_variable and assign_array_element both take a new `flags' - argument - - assign_array_var_from_string, assign_array_from_string, and - assign_array_var_from_word_list now all take a new `flags' argument - - change assign_array_var_from_word_list to understand how to append - to an array variable - - change assign_array_var_from_string to understand how to append - to an array variable. It does not unset the previous value if - appending, allowing both old values to be changed and new ones to - be added - -subst.h - - new flag #defines to use for evaluating assignment statements - -{subst,variables}.c, builtins/{declare,read}.def - - change callers of assign_array_element and bind_array_variable - - change do_compound_assignment to understand assignment flags - - change do_assignment_internal to set assignment flags and pass them - to underlying functions - -pcomplete.c,builtins/{declare,read}.def - - fix callers of assign_array_var_from_string, assign_array_var_from_word_list - -variables.[ch] - - make_variable_value now takes a new `flags' argument - - make_variable_value now understands how to append to a particular - variable, using the old value - - bind_variable_value now takes a new `flags' argument - - change make_variable_value to understand ASS_APPEND flag - - bind_variable now takes a new `flags' argument - - bind_variable_internal now takes a new `flags' argument - -arrayfunc.c - - change callers of make_variable_value to add flags arg - -builtins/declare.def - - change callers of bind_variable_value to add flags arg - -{execute_cmd,mailcheck,pcomplete,shell,subst,variables}.c,parse.y -builtins/{cd,command,declare,getopts,read,set,setattr}.def - - change callers of bind_variable to add flags arg - -variables.c - - change callers of bind_variable_internal - - change bind_variable_internal to pass assignment flags on to - make_variable_value - - change assign_in_env to treat `var+=value' like `var=value' - -arrayfunc.c - - break code that actually constructs the new value and assigns it - to a particular array index out into a new functions: - bind_array_var_internal. This fakes out make_variable_value by - passing a dummy SHELL_VAR * so it can do proper appending and other - += processing - - changes to assign_array_var_from_string to accept and process as if - they were `standalone' assignment statements array assignment words - of the form [ind]+=val - - 11/7 - ---- -builtins/declare.def - - added support for `declare [flags] var+=value'. `Flags' are applied - before the assignment is performed, which has implications for things - like `-i' -- if -i is supplied, arithmetic evaluation and increment - will be performed - -builtins/setattr.def - - add support for `+=' assignment for rest of `assignment builtins': - export, readonly - - 11/12 - ----- -lib/readline/display.c - - make sure prompt_physical_chars and prompt_invis_chars_first_line - are reset to 0 if the prompt string passed to rl_expand_prompt is - NULL or empty - - 11/14 - ----- -{configure,config.h}.in - - check for `raise', define HAVE_RAISE if available - -lib/intl/dcigettext.c - - make sure `raise' is defined if HAVE_RAISE is not before - eval-plurah.h is included - -lib/malloc/trace.c - - put extern declaration for imalloc_fopen inside the MALLOC_TRACE - #ifdef - - 11/16 - ----- -lib/intl/Makefile.in - - make sure SHELL is defined to cpp - -lib/intl/dcigettext.c - - make sure we use getcwd() even if HAVE_GETCWD is not defined after - including config.h; if SHELL is defined, #define HAVE_GETCWD - - 11/18 - ----- -trap.[ch] - - new function, int signal_in_progress(int sig), returns TRUE if the - trap handler for signal SIG is currently executing - - 11/19 - ----- -redir.c - - slightly change do_redirection_internal to set the close-on-exec - flag for file descriptors > 2 used to save file descriptors < 2 - using explicit redirections (e.g., `exec 3>&1'). This keeps file - descriptors pointing to pipes from being left open but doesn't - change the shell's file descriptor semantics - - 11/20 - ----- -doc/{bash.1,bashref.texi} - - correct some minor typos, forwarded from doko@debian.org - - 11/22 - ----- -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented detail that yank-last-arg and yank-nth-arg use the history - arg expansion code (and, as a result, are subject to restrictions - of the history-comment character) - - 11/23 - ----- -execute_cmd.c - - changes so that BASH_COMMAND preserves its value into a DEBUG trap: - for commands, arithmetic for command expressions, select commands, - case commands, (( commands, [[ commands, simple commands - - 11/24 - ----- -doc/{bash.1,bashref.texi} - - changed description of `set' builtin slightly so that it is clear - that only variables are displayed in posix mode and that read-only - variables can't be reset by simply sourcing the output of `set' - -lib/sh/strftime.c - - don't try to redefine `inline' if it's already defined - - 11/26 - ----- -execute_cmd.c - - fix execute_function to check funcname_a after function execution, - since FUNCNAME can be changed or unset within a function - - 11/27 - ----- -builtins/evalfile.c - - make same changes as 11/26, this time to _evalfile - -execute_cmd.c - - change execute_function to run the return trap after a function - completes execution even if the shell is compiled without DEBUGGER - defined - -trap.c - - change reset_or_restore_signal_handlers so that the RETURN trap is - not inherited by command substitution when DEBUGGER is not defined - - 11/30 - ----- -lib/readline/misc.c - - fix memory leaks in _rl_free_history_entry and rl_maybe_replace_line - caused by not freeing `timestamp' member of history entry - - make sure timestamp is initialized to NULL in rl_maybe_save_line - - 12/1 - ---- -execute_cmd.c - - fix execute_function so a function calling `return' will run the - RETURN trap, if one's defined - -doc/{bash.1,bashref.texi} - - fix description of RETURN trap in various places to indicate that it's - only inherited by shell functions if function tracing is on globally - or has been enabled for that function - - fix documentation to indicate that the DEBUG and RETURN traps are - inherited under the same conditions - -execute_cmd.c - - a function does not inherit the RETURN trap if a DEBUG trap is - currently running - - 12/2 - ---- -lib/glob/xmbsrtowcs.c - - change xmbsrtowcs to handle the one case where malloc can fail - (though it should not matter) -- don't try to free a null pointer - - 12/9 - ---- -subst.c - - fix get_var_and_type to handle var[@], where `var' is a scalar - variable, identically to var -- all calling expansions can now - handle var[@] like var. Bug reported by agriffis@gentoo.org - - 12/10 - ----- -lib/readline/bind.c - - make new-style "\M-x" keybindings obey `convert-meta' settings - (bug reported by twaugh@redhat.com) - - 12/14 - ----- -builtins/set.def - - added description of `-' option to help text - -builtins/shopt.def - - fix bug that caused `gnu_errfmt' to not be compiled in unless - READLINE is defined - - 12/16 - ----- -subst.c - - fixed a typo in string_extract_verbatim in first call to MBLEN - (used `slen - 1' instead of `slen - i') - - 12/17 - ----- -subst.c - - avoid some calls to strlen if the value is only being used for - ADVANCE_CHAR and MB_CUR_MAX == 1 (since ADVANCE_CHAR doesn't need - it unless multibyte characters are possible) - - change string_extract_verbatim so it takes the length of the string - as a parameter, so we don't have to recompute the length of the same - string over and over again when doing word splitting (that kills if - it's a long string) - - 12/18 - ----- -subst.c - - in string_list_dollar_star, make sure to null-terminate the - separator if the character is longer than one byte - - 12/22 - ----- -doc/{bash.1,bashref.texi} - - changed text in quoting section explaining that double quotes do - not prevent history expansion from taking place, and that backslashes - escaping ! are not removed - - 12/28 - ----- -shell.c - - set gnu_error_format to 1 if running under emacs. This should allow - the emacs `next-error' stuff to work, at least for interactive shells - -parse.y - - change yy_stream_get to set interrupt_immediately before calling - getc_with_restart when the shell is interactive. This avoids the - synchronization problem caused by the call to QUIT in read_a_line, - which results in the first character after a SIGINT/^C to be - dropped - - 12/30 - ----- -builtins/mkbuiltins.c - - changes to write long documentation to arrays as a single string by - default, rather than an array of strings -- enabled by default - - new option, -S, to restore old behavior of writing multiple strings - for long documentation - - changes to avoid filenames written when the separate-filenames option - (-H) has been supplied being run through gettext - -configure.in - - new cofiguration option, --enable-single-help-strings (on by default), - causes help text to be stored as a single string (or smaller set than - one string per line) - -builtins/Makefile.in - - pass `-S' to mkbuiltins if single-help-strings is turned off - -doc/bashref.texi - - documented new `single-help-strings' configure option - - 1/3/2005 - -------- -jobs.c - - make wait_for return a non-zero status if the job or processed - waited for is suspended. Returns 128 + stop signal. This fixes - the problem with `echo one && sleep 5 && echo two' displaying - `two' after the sleep is suspended - - 1/5 - --- -print_cmd.c - - change indirection_level_string so the code duplicates the first - character of $PS4 to indicate the indirection level, rather than - the first byte - - 1/8 - --- -variables.c - - new special variable hook function for COMP_WORDBREAKS; sets - rl_completer_word_break_characters back to NULL when the variable - is unset - - change bind_variable_value to understand dynamic variables with - assign_function set, and handle them correctly. If the variable is - being appended to, use make_variable_value to create the new - value - - change bind_variable_internal to understand dynamic variables with - assign_function set, and handle them the same way - - RANDOM and LINENO now get the integer attribute, so appending works - as expected - - ditto for HISTCMD, MAILCHECK, OPTIND - -lib/readline/display.c - - change _rl_make_prompt_for_search to set prompt_physical_chars - appropriately - - rl_save_prompt and rl_restore_prompt save and restore - prompt_prefix_length - - change redraw_prompt to use rl_save_prompt and rl_restore_prompt - - change rl_restore_prompt to set the `save' variables back to - NULL/0 so code can check whether or not the prompt has been saved - - change rl_message and rl_clear_message to save and restore the - prompt if the caller has not already done it (using a simple - semaphore-like variable) - - change rl_message to call expand_prompt, so that local_prompt and - local_prompt prefix are set before calling the redisplay functions, - in case the prompt is longer than a screenwidth (fixes bug - reported to debian by epl@unimelb.edu.au) - -lib/readline/doc/rltech.texi - - make sure to note that rl_save_prompt should be called before - rl_message, and rl_restore_prompt before rl_clear_message - -pcomplete.c - - make sure to save and restore the parser state around the call to - execute_shell_function in gen_shell_function_matches. Fixes bug - reported by a050106.1.keeLae3x@captaincrumb.com (cute) - -lib/readline/readline.c - - fix _rl_dispatch_subseq in the case where we're recursing back up - the chain (r == -2) and we encounter a key shadowed by a keymap, - but originally bound to self-insert. Calling rl_dispatch with - ANYOTHERKEY as the first argument will call rl_insert, but with - ANYOTHERKEY (256) as the char to insert. Use the shadow keymap - and set things up to dispatch to rl_insert with the shadowed key - as the argument. Fixes the bug reported by Thomas Glanzmann - (sithglan@stud.uni-erlangen.de) - - 1/13 - ---- -command.h - - new word flag: W_HASQUOTEDNULL - -make_cmd.c - - new function to allocate a WORD_DESC * without doing anything with a - containing string: alloc_word_desc - -make_cmd.h - - extern declaration for alloc_word_desc - -dispose_cmd.c - - new function to just free a WORD_DESC * without freeing the contained - string: dispose_word_desc - -dispose_cmd.h - - extern declaration for dispose_word_desc - -subst.c - - change some places to use alloc_word_desc - - make same changes to word_list_quote_removal as were made to - word_list_split - - set W_HASQUOTEDNULL when a word is created with w->word[0] == - CTLNUL and w->word[1] == '\0' - -subst.c - - parameter_brace_expand_word now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_indir now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_rhs now returns a WORD_DESC * -- changed - callers to understand - - remove W_HASQUOTEDNULL from a word's flags when remove_quoted_nulls - is called on the word's enclosed string - - 1/15 - ---- -subst.c - - param_expand now returns a WORD_DESC * -- changed callers to - understand - - parameter_brace_expand now returns a WORD_DESC * -- changed - callers to understand - - in expand_word_internal, only call remove_quoted_nulls after a word - is returned with W_HASQUOTEDNULL - - changes to pass W_HASQUOTEDNULL flag out of expand_word_internal; - changed callers to call remove_quoted_nulls only if return value has - W_HASQUOTEDNULL set. This is a mostly-complete fix for the - long-standing CTLNUL confusion between a quoted null expansion and - the expansion of a variable with a literal '\177' in its value - - change string_list_dollar_at to compute the separator character the - same way as string_list_dollar_star: using the already-computed - values generated in setifs() - - when expanding unquoted $*, if $IFS is empty, check whether or not - we're eventually going to split the results (e.g., on the rhs of an - assignment statement) and concatenate the positional parameters as - if the expansion were within double quotes if we're not going to - split - -tests/iquote.tests - - test cases based on old bug reports about the quoted-null vs. 0177 - problem the recent code fixes - - 1/16 - ---- -dispose_cmd.c - - set w->word to 0 before putting a WORD_DESC * back in the cache in - dispose_word_desc; changed callers to delete those assignments - -variables.c - - change assign_random and get_random_value so that the random number - generator only gets re-seeded once in a subshell environment, and - assigning a value to RANDOM counts as seeding the generator. This - makes the sequences a little more predictable - - 1/20 - ---- -lib/readline/history.c - - fix replace_history_entry, remove_history to return NULL if - passed index is < 0 - - 1/22 - ---- -lib/sh/netconn.c - - fix isnetconn() to understand that getpeername can return ENOTCONN - to indicate that an fd is not a socket - -configure.in - - set BUILD_DIR to contain backslashes to escape any spaces in the - directory name -- this is what make will accept in targets and - prerequisites, so it's better than trying to use double quotes - - set SIZE to the appropriate value if some cross-compiling tool - chain is being used; `size' by default (can be overridden by - SIZE environment variable) - -Makefile.in - - use $(SIZE) instead of size; set SIZE from configure - - 1/31 - ---- -arrayfunc.c - - in array_value_internal, return NULL right away if the variable's - value is NULL, instead of passing a null string to add_string_to_list - - 2/1 - --- -jobs.h - - new struct to hold stats and counters for child processes and jobs - - change some uses of global and static variables to use members of - new struct (struct jobstats) - - 2/2 - --- - -jobs.[ch] - - change PRUNNING to PALIVE - - new define INVALID_JOB - - new macro get_job_by_jid(ind), currently expands to jobs[ind] - - new define J_JOBSTATE, operates on a JOB * like JOBSTATE operates on - a job index - - new function, reset_job_indices, called from delete_job if - js.j_lastj or js.j_firstj are removed - - change various functions to keep counters and stats in struct jobstats - -pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def - - change global variables (e.g., job_slots) to struct members - (e.g., js.j_jobslots) - - use INVALID_JOB define where appropriate - - use get_job_by_jid and J_JOBSTATE where appropriate - -trap.c - - change reset_or_restore_signal_handler to not free the exit trap - string if the function pointer is reset_signal, which is used when - the trap strings shouldn't be freed, like in command substitution - - 2/4 - --- -jobs.c - - new function, realloc_jobs_list, copies jobs array to newly-allocated - memory shrinking (or growing) size to have next multiple of JOB_SLOTS - greater than js.j_njobs - - change compact_jobs_list to just call reap_dead_jobs and then - realloc_jobs_list, simplifying it considerably - - discard_pipeline now returns `int': the number of processes freed - - slightly changed the logic deciding whether or not to call - compact_jobs_list: now non-interactive shells will compact the - list if it reaches MAX_JOBS_IN_ARRAY in size - -parse.y - - move test for backslash-newline after pop_string in shell_getc so - that things like - - ((echo 5) \ - (echo 6)) - - work right - - 2/8 - --- -jobs.h - - new structs for holding status of exited background processes, as - POSIX specifies - - new job flag: J_ASYNC - -jobs.c - - new functions to manipulate struct holding status of exited - background processes - - new members in struct jobstats to hold pointer to last created job - and last created asynchronous job - - initialize js.c_childmax in initialize_job_control - - if the `async' arg to stop_pipeline is non-null, set the J_ASYNC - flag in the job struct - - set js.j_last_made_job and js.j_last_asynchronous_job in - stop_pipeline - - new function: find_last_proc, returns the PROCESS * to the last proc - in a job's pipeline - - changed find_last_pid to call find_last_proc - - change delete_job to call bgp_add on the last proc of the job being - deleted - - change delete_all_jobs and wait_for_background_pids to call bgp_clear - - 2/9 - --- -jobs.c - - change wait_for_single_pid to look for pid in bgpids.list (using - bgp_search()) if find_pipeline returns NULL - - 2/10 - ---- -support/shobj-conf - - change the solaris-gcc stanza so that it auto-selects the appropriate - options for ld depending on which `ld' gcc says it's going to run - - 2/11 - ---- -jobs.h - - add support for PS_RECYCLED as a process state, add PRECYCLED macro - to test it. Change PALIVE and PRUNNING macros to not count processes - in PS_RECYCLED state - -execute_cmd.c - - restore use of last_pid as sentinel value; use NO_PID as sentinel - only if RECYCLES_PIDS is defined - -jobs.c - - change find_job to return a pointer to the PROCESS the desired pid - belongs to, analogous to find_pipeline returning pointer to JOB - - change find_job callers to add extra argument - - change running_only arguments to find_pipeline and find_job to - alive_only, since we don't want recycled pids returned here and it - better describes the result - - new function find_process, calls find_pipeline and searches the - returned pipeline for the PROCESS * describing the desired pid - - in make_child, if fork() returns the same pid as the value of - last_asynchronous_pid when RECYCLES_PIDS is defined, avoid pid - aliasing by resetting last_asynchronous_pid to 1 - - use PRUNNING instead of child->running, since we, for the most - part, don't want to consider recycled pids (e.g., in make_child()) - - call find_process instead of find_pipeline in waitchld() - - use PEXITED(p) instead of testing p->running == PS_DONE - - in make_child, call bgp_delete to remove a just-created pid from the - last of saved pid statuses - - in add_process, check whether or not pid being added is already in - the_pipeline or the jobs list (using find_process) and mark it as - recycled if so - - This set of fixes mostly came from Pierre Humblet - to fix pid aliasing and reuse problems on - cygwin - -variables.c - - set $_ from the environment if we get it there, set to $0 by - default if not in env - -doc/{bashref.texi,bash.1} - - a couple of clarifying changes to the description of $_ based on - comments from Glenn Morris - - 2/15 - ---- -shell.c - - use strstr instead of strmatch when checking whether $EMACS contains - `term' -- simpler and faster - - 2/18 - ---- -builtins/cd.def - - implement posix requirement that `pwd -P' set $PWD to a directory - name containing no symlinks - - add new function, setpwd(), just sets (and changes exported value) - of PWD - -doc/bashref.texi - - add note to posix mode section about pwd -P setting $PWD - -doc{bash.1,bashref.texi} - - added note that BASH_ARGC and BASH_ARGV are only set in extended - debug mode - - expand description of extdebug option to include everything changed - by extended debug mode - - 2/19 - ---- -pathexp.h - - new flag macro, FNMATCH_IGNCASE, evaluates to FNM_CASEFOLD if the - match_ignore_case variable is non-zero - -execute_cmd.c - - new variable, match_ignore_case - - change call to strmatch() in execute_case_command so it includes - FNMATCH_IGNCASE - -test.c - - change call to strmatch() in patcomp() so that pattern matching - calls for [[ ... ]] obey the match_ignore_case variable - -lib/sh/shmatch.c - - if match_ignore_case is set, enable REG_ICASE in the regexp match - flags - -builtins/shopt.def - - new settable option, `nocasematch', controls the match_ignore_case - variable. Currently alters pattern matching for case and [[ ... ]] - commands (==, !=, and =~ operators) - -doc/{bashref.texi,bash.1} - - updated descriptions of [[ and case to include reference to - nocasematch option - - 2/22 - ---- -builtins/mkbuiltins.c - - add `times' to the list of posix special builtins - - 2/23 - ---- -builtins/cd.def - - posix mode no longer turns on effect of -P option on $PWD if a - directory is chosen from CDPATH - -doc/bashref.texi - - clarified that in posix mode, reserved words are not alias expanded - only in a reserved word context - - removed item about cd, $CDPATH, and -P from posix mode section - - 2/24 - ---- -builtins/reserved.def - - minor cleanups to the description of `if' - - 3/2 - --- -subst.c - - change list_string and get_word_from_string to explicitly treat an - IFS character that is not space, tab, or newline *and any adjacent - IFS white space* as a single delimiter, as SUSv3/XPG6 says - -builtins/read.def - - check whether or not the number of fields is exactly the same as - the number of variables instead of just assigning the rest of the - line (minus any trailing IFS white space) to the last variable. - This parses a field and checks whether or not it consumes all of - the input (including any trailing field delimiters), falling back - to the previous behavior if it does not. This is what POSIX.2 - specifies, I believe (and the consensus of the austin-group list). - This requires a few tests in read.tests to be changed: backslashes - escaping IFS whitespace characters at the end of input cause the - whitespace characters to be preserved in the value assigned to the - variable, and the trailing non-whitespace field delimiter issue - - 3/7 - --- -configure.in - - add -D_POSIX_SOURCE to the LOCAL_CFLAGS for Interix - - 3/8 - --- -bashline.c - - make bash_directory_expansion a void function, since it doesn't have - any return value - - 3/9 - --- -builtins/read.def - - when testing for a pipe, use `fd' instead of hard-coding 0, since we - can read from other file descriptors now - -lib/sh/zread.c - - in zsyncfd, only set lind and lused to 0 if the lseek succeeds. - If the lseek fails, we might steal input from other programs, but - a failed lseek won't cause us to erroneously discard input - - 3/11 - ---- -builtins/evalstring.c - - don't allow parse_and_execute to short-circuit and call exec() if - the command's return value is being inverted - - 3/15 - ---- -builtins/printf.def - - new macro PC to call putchar and increment number of chars printed - - fixes bug in computation of value for %n format char - - `tw' is now a global var so printstr can modify it using PC() - - convert PF macro to use asprintf into a local buffer - Preparation for printf -v var - - add code to add the text printed to a `variable buffer' if -v option - supplied. The buffer grows as needed - - printf now takes a `-v var' option to put the output into the variable - VAR rather than sending it to stdout. It does not: - print partial output on error (e.g., format string error) - handle NULs in the variable value, as usual - - 3/16 - ---- -parse.y - - fix bug in prompt string decoding that caused a core dump when PS1 - contained \W and PWD was unset (null pointer deref) - -builtins/printf.def - - changed -v var behavior so it stores partial output into the named - variable upon an error - - 3/24 - ---- -lib/readline/bind.c - - bool_to_int now takes a `const char *' argument - -support/{printenv,recho,zecho}.c - - include config.h - - include "bashansi.h" for appropriate extern function declarations - -configure.in - - on MacOS X 10.4, compensate for loader not allowing static library - to override existing system dynamic library when compiling -dynamic - (affects readline and history libraries); so use absolute pathname - instead of -lreadline as library name - -lib/glob/{glob,sm_loop,smatch}.c - - make sure to cast arguments to (char *) or (unsigned char *) as - appropriate to avoid gcc4 warnings - -lib/glob/smatch.c - - collsym (single-byte version) now takes a (CHAR *) first argument to - match callers; cast argument to strncmp appropriately - -lib/sh/snprintf.c - - fix ldfallback and dfallback to handle width and precision specs in - the format passed to sprintf() - - fix STAR_ARGS macro to deal with negative field widths and precisions - - 3/25 - ---- -builtins/printf.def - - since a negative precision in a "x.x[fFgGeE]" format specifier should - be allowed but treated as if the precision were missing, let it - through - -lib/sh/snprintf.c - - fix * code to deal with a negative precision by treating it as if - the `.' and any digit string in the precision had not been specified - - fix format parsing code to deal with a negative inline precision, - e.g., "%4.-4f" by treating it as if the `'. and any digit string in - the precision had not been specified - - a `+' in a format specifier should only act as a flag if it comes - before a `.' (otherwise it is ignored) - -lib/readline/vi_mode.c - - new function, rl_vi_rubout, to rl_rubout as rl_vi_delete is to - rl_delete; saves deleted text for possible reinsertion as with any - vi-mode `text modification' command (fixes problem with `X' reported - by beat.wieland@gmx.ch) - -lib/readline/vi_keymap.c - - bind `X' in vi command mode to rl_vi_rubout - -lib/readline/funmap.c - - add a bindable `vi-rubout' command, runs rl_vi_rubout - -lib/readline/text.c - - rewrote internals of _rl_rubout_char to make structure cleaner - -lib/readline/{complete,text}.c - - changed code to remove #ifdef HANDLE_MULTIBYTE where possible - - 3/28 - ---- -lib/readline/examples/rl.c - - include instead of posixstat.h if READLINE_LIBRARY not - defined - -subst.c - - fix mbstrlen to treat invalid multibyte sequences as sequences of - single-byte characters - - 4/8 - --- -configure.in - - default SIZE to `:' if cross-compiling and an appropriate size for - the target is not found - - 4/11 - ---- -subst.c - - change match_upattern and match_wpattern to check whether or not the - supplied pattern matches anywhere in the supplied string, prefixing - and appending the pattern with `*' if necessary. If it doesn't we - can short-circuit immediately rather than waste time doing up to - N-1 unsuccessful calls to strmatch/wcsmatch (which kills for long - strings, even if the pattern is short) - - 4/12 - ---- -configure.in - - make sure the special case for MacOS X 10.4 only kicks in if the - `--with-installed-readline' option isn't supplied - -lib/readline/{callback,readline,signals}.c - - make sure rl_prep_term_function and rl_deprep_term_function aren't - dereferenced if NULL (as the documentation says) - -builtins/mkbuiltins.c - - don't bother with the special HAVE_BCOPY code; just use straight - assignments - -builtins/ulimit.def - - use _POSIX_PIPE_BUF in pipesize() if it's defined and PIPE_BUF is - not - - 4/13 - ---- -execute_cmd.c - - add cm_function_def to the list of control structures for which - child processes are forked when pipes come in or out - - 4/14 - ---- -builtins/read.def - - make sure the ^As added for internal quoting are not counted as - characters read when -n is supplied - - 4/20 - ---- -redir.c - - fix redir_open so that the repeat open on failure that AFS support - adds restores the correct value of errno for any error message - - 4/26 - ---- - -Makefile.in - - make sure mksignames and mksyntax are invoked with the $(EXEEXT) - extension - - 4/28 - ---- -lib/readline/readline.h - - new state variable: RL_STATE_CALLBACK, means readline is using the - callback interface - -lib/readline/callback.c - - set RL_STATE_CALLBACK in rl_callback_handler_install, unset in - rl_callback_handler_remove - - 4/29 - ---- -config-top.h - - DONT_REPORT_SIGPIPE is now on by default, since it apparently - interferes with scripts - -configure.in - - arrange things so PGRP_PIPE is defined on Linux-2.4+ and version 3 - kernels (ones that apparently schedule children to run before their - parent) - - 4/30 - ---- -builtins/caller.def - - add call to no_options, so it can handle `--' option - -doc/{bash.1,bashref.texi} - - note explicitly that test, :, true, and false don't understand -- - as meaning the end of options - - 5/7 - --- -support/shobj-conf - - darwin 8 needs the same LDFLAGS setting as darwin 7 - -parse.y - - in save_parser_state, make sure we cast the return value from - xmalloc() to the right type - - remove casts to (char *) in calls to yyerror() - -lib/readline/signals.c - - make SIGQUIT and SIGALRM code conditional on their definition - - use raise() to send a signal if we don't have kill() - -lib/readline/display.c - - some MS-DOS and MINGW changes from the cygwin and mingw folks - -config.h.in - - add HAVE_PWD_H for - - add HAVE_FCNTL, HAVE_KILL for respective system calls - - add HAVE_GETPW{ENT,NAM,UID} for passwd functions - -configure.in - - add check for - - add checks for fcntl, kill system calls - - add checks for getpw{ent,nam,uid} C library functions - - pass a flag indicating we're cross compiling through to - CFLAGS_FOR_BUILD in Makefile.in - -lib/readline/complete.c - - guard inclusion of with HAVE_PWD_H - - don't provide a missing declaration for getpwent if we don't have it - - guard calls to {get,end}pwent with HAVE_GETPWENT - -lib/readline/shell.c - - guard inclusion of with HAVE_PWD_H - - guard inclusion of with HAVE_FCNTL_H - - don't provide a missing declaration for getpwuid if we don't have it - - guard calls to getpwuid with HAVE_GETPWUID - - don't bother with body of sh_unset_nodelay_mode if we don't have - fcntl - -lib/tilde/tilde.c - - guard inclusion of with HAVE_PWD_H - - guard calls to getpw{nam,uid} with HAVE_GETPW{NAM,UID} - - guard calls to {get,end}pwent with HAVE_GETPWENT - -Makefile.in,builtins/Makefile.in - - @CROSS_COMPILE@ is substituted into CFLAGS_FOR_BUILD (equal to - -DCROSS_COMPILING if bash is being cross-compiled) - - 5/9 - --- -aclocal.m4 - - print version as `0.0' in RL_LIB_READLINE_VERSION if the - `rl_gnu_readline_p' variable isn't 1 (accept no imitations) - - 5/11 - ---- -lib/readline/rlprivate.h - - definition of a readline `search context', to be use for incremental - search initially and other types of search later. Original from - Bob Rossi as part of work on incremental searching problems when - using callback interface - -lib/readline/isearch.c - - functions to allocate and free search contexts - - function to take a search context and a character just read and - `dispatch' on it: change search parameters, add to search string, - search further, etc. - - isearch is now completely context-driven: a search context is - allocated and passed to the rest of the functions - - 5/12 - ---- -lib/readline/isearch.c - - an additional `isearch cleanup' function that can be called from - the callback interface functions when the search is to be terminated - - an additional `isearch callback' function that can be called from - rl_callback_read_char when input is available - - short-circuit from rl_search_history after initialization if - the callback interface is being used - -lib/readline/callback.c - - in rl_callback_read_char(), if RL_STATE_ISEARCH is set, call - _rl_isearch_callback to read the character and dispatch on it. - If RL_STATE_ISEARCH is unset when that call returns, and there is - input pending, call rl_callback_read_char() again so we don't - have to wait for new input to pick it up - -support/shobj-conf,configure.in - - add support for dragonfly bsd, the same as freebsd - - 5/13-5/15 - --------- -lib/readline/callback.c - - support for readline functions to `register' a function that will - be called when more input is available, with a generic data - structure to encapsulate the arguments and parameters. Primarily - intended for functions that read a single additional character, - like quoted-insert - - support for callback code reading numeric arguments in a loop, - using readline state and an auxiliary variable - - support for callback code performing non-incremental searches using - the same search context struct as the isearch code - -lib/readline/{callback,display}.c - - if a callback function sets `_rl_redisplay_wanted', the redisplay - function will be called as soon as it returns - -lib/readline/input.c - - changes to _rl_read_mbchar to handle reading the null multibyte - character and translating it into '\0' - -lib/readline/misc.c - - break rl_digit_loop() into component functions that can be called - individually from the callback code more easily - - share some of the functions with rl_digit_loop1() in vi_mode.c - -lib/readline/readline.h - - change the version #defines to reflect readline 5.1 - -lib/readline/search.c - - break code into smaller functions that can be composed to work with - the callback code more easily - -lib/readline/text.c - - in rl_quoted_insert(), don't mess around with the tty signals if - running in `callback mode' - -lib/readline/vi_mode.c - - changed set-mark, goto-mark, change-char, and char-search to work - when called by callback functions - - 5/17 - ---- - -lib/readline/rlprivate.h - - new struct declaration for a `reading key sequence' context - -lib/readline/readline.c - - new variable, _rl_dispatching_keymap, keeps track of which keymap - we are currently searching - - functions to allocate and deallocate contexts for reading multi-char - key sequences - - 5/18 - ---- -lib/readline/rlprivate.h - - new struct defining a context for multiple-key key sequences (the - base case is escape-prefixed commands) - -lib/readline/readline.c - - change structure of _rl_dispatch_subseq to allow for callback code - to use it - rudimentary support for supporting the existing - recursion using a stack of contexts, each with a reference to the - previous - - fix so that ^G works when in callback mode - -lib/readline/callback.c - - call the appropriate multiple-key sequence callback if the state is - set - - 5/19 - ---- -lib/readline/readline.c - - broke code from _readline_internal_char after call to rl_dispatch - out into separate function: _rl_internal_char_cleanup, callable by - other parts of the code - - change _rl_internal_char_cleanup to unset _rl_want_redisplay after - it calls (*rl_redisplay_func) - -lib/readline/callback.c - - call _rl_internal_char_cleanup from rl_callback_read_char when - appropriate - - 5/24 - ---- -lib/readline/callback.c - - use _rl_dispatch_callback and a chain of _rl_keyseq_contexts to - simulate the recursion used to decode multicharacter key sequences - (even things like ESC- as meta-prefix) - - call setjmp in rl_callback_read_char to give things like rl_abort - a place to jump, since the saved location in readline() will not - be valid - - keep calling _rl_dispatch_callback from rl_callback_read_char while - we are still decoding a multi-key key sequence - - keep calling readline_internal_char from rl_callback_read_char while - we are reading characters from a macro - -lib/readline/macro.c - - use a slightly different strategy upon encountering the end of a macro - when using the callback interface: when the last character of a - macro is read, and we are reading a command, pop the macro off the - stack immediately so the loop in rl_callback_read_char terminates - when it should - -lib/readline/readline.c - - if longjmp() is called and we end up at the saved location while - using the callback interface, just return -- don't go back into a - blocking read - - new function to dispose a chain of rl_keyseq_cxts - - only read new input in _rl_dispatch_callback if the KSEQ_DISPATCHED - flag is not set in the current keyseq context -- if it is, we are - traversing the chain back up and should use what we already saved - - use -3 as a magic value from _rl_dispatch_subseq to indicate that - we're allocating a new context and moving downward in the chain - (a special return value for the benefit of _rl_dispatch_callback) - -lib/readline/rlprivate.h - - new extern declaration for _rl_keyseq_chain_dispose - - 6/1 - --- -builtins/read.def - - fixed a bug that occurred when reading a set number of chars and - the nth char is a backslash (read one too many). Bug reported by - Chris Morgan - -execute_cmd.c - - fix execute_builtin so the `unset' builtin also operates on the - temporary environment in POSIX mode (as well as source and eval), - so that unsetting variables in the temporary environment doesn't - leave them set when unset completes. Report by Eric Blake - - -array.c - - fix from William Park for array_rshift when shifting right on an - empty array -- corrects calculation of array->max_index - -builtins/exec.def - - if an exec fails and the execfail option is set, don't call - restart_job_control unless the shell is interactive or job_control - is set - -jobs.c - - add a run-time check for WCONTINUED being defined in header files - but rejected with EINVAL by waitpid(). Fix from Maciej Rozycki - - - 6/20 - ---- -bashhist.c - - make sure calls to sv_histchars are protected by #ifdef BANG_HISTORY - - ditto for calls to history_expand_line_internal - - 6/23 - ---- -doc/bashref.texi - - remove extra blank lines in @menu constructs - -variables.c - - assign export_env to environ (extern char **) every time it changes - (mostly in add_to_export_env define), so maybe getenv will work on - systems that don't allow it to be replaced - - 6/29 - ---- -bashline.c - - in bash_directory_completion_hook, be careful about not turning `/' - into `//' and `//' into `///' for benefit of those systems that treat - `//' as some sort of `network root'. Fix from Eric Blake - - -lib/readline/complete.c - - in to_print, do the right thing after stripping the trailing slash - from full_pathname: // doesn't turn into /, and /// doesn't become - //. Fix from Eric Blake - - 6/30 - ---- -lib/malloc/trace.c - - include if it's available for a definition of size_t - -jobs.c - - in wait_for, if a child process is marked as running but waitpid() - returns -1/ECHILD (e.g., when the bash process is being traced by - strace), make sure to increment c_reaped when marking the child as - dead - - in without_job_control, make sure to close the pgrp pipe after - calling start_pipeline - - 7/1 - --- -Makefile.in - - only remove pathnames.h when the other files created by running - configure are removed (e.g., Makefile). Fix from William Park - -lib/sh/shquote.c - - since backslash-newline disappears when within double quotes, don't - add a backslash in front of a newline in sh_double_quote. Problem - reported by William Park - -jobs.c - - in notify_of_job_status, don't print status messages about - terminated background processes unless job control is active - -bashhist.c - - new variable, hist_last_line_pushed, set to 0 in really_add_history - (used by `history -s' code) - -bashhist.h - - new extern declaration for history -s - -builtins/history.def - - don't remove last history entry in push_history if it was added by - a call to push_history -- use hist_last_line_pushed as a sentinel - and set it after adding history entry. This allows multiple - calls to history -s to work right: adding all lines to the history - rather than deleting all but the last. Bug reported by Matthias - Schniedermeyer - - pay attention to hist_last_line_pushed in expand_and_print_history() - so we don't delete an entry pushed by history -s - - 7/4 - --- -print_cmd.c - - fix print_arith_for_command to not print so many blanks between - expressions in ((...)) - -command.h - - new word flag: W_DQUOTE. Means word should be treated as if double - quoted - -make_cmd.c - - add W_DQUOTE to word flags in make_arith_for_expr - -parse.y - - add W_DQUOTE to word flags for (( ... )) arithmetic commands - -subst.c - - don't perform tilde expansion on a word with W_DQUOTE flag set - - don't perform process substitution on a word with W_DQUOTE flag set - -arrayfunc.c - - expand an array index within [...] the same way as an arithmetic - expansion between (( ... )) - -lib/readline/input.c - - use getch() instead of read() on mingw - -lib/readline/readline.c - - add a few key bindings for the arrow keys on mingw - -lib/readline/rldefs.h - - if on mingw, define NO_TTY_DRIVER - -lib/readline/rltty.c - - compile in the stub functions for _rl_{disable,restore}_tty_signals - if on mingw - - compile in stub function for rl_restart_output on mingw - - make sure enough functions and macros are defined to compile if - NO_TTY_DRIVER is defined (lightly tested - builds on MacOS X, at - least) - - 7/7 - --- -command.h - - add a `flags' member to the PATTERN_LIST structure - -make_cmd.c - - intialize the `flags' member of a PATTERN_LIST when it's created - -builtins/psize.c - - protect extern declaration of errno with usual #ifdef errno - -configure.in, variables.c - - changes for QNX 6.x - - 7/9 - --- -parse.y - - fix parse_matched_pair to handle single and double quoted strings - inside old-style command substitution (``) since they can each - quote the ` and embedded $-expansions. Report by Eric Blake - - -{configure,Makefile}.in - - TILDE_LIB is now substituted into Makefile by configure - -configure.in - - if configuring --with-installed-readline on cygwin, set TILDE_LIB - to the empty string to avoid multiply-defined symbols. Cygwin - doesn't allow undefined symbols in dynamic libraries. Report by - Eric Blake - - 7/11 - ---- -input.c - - in duplicate_buffered_stream, don't call free_buffered_stream if the - two buffered streams share the same b_buffer object (e.g., if they - had already been duplicated with a previous call). Fixes Debian bug - reported by eero17@bigfoot.com - - 7/12 - ---- -shell.c - - make set_shell_name more resistant to a NULL argument - - in bind_args, use < instead of != when counting the arguments and - making the arg list - - in main(), make sure arg_index is not initialized to a value greater - than argc - - 7/14 - ---- -lib/readline/display.c - - in expand_prompt, don't set the location of the last invisible - char if the sequence is zero length (\[\]) - - 7/15 - ---- -doc/{bash.1,bashref.texi} - - document that the shell uses $TMPDIR when creating temporary files - - 7/20 - ---- -[bash-3.1-alpha1 frozen] - - 7/29 - ---- -builtins/evalstring.c - - make sure that parse_and_execute saves and restores the value of - loop_level, so loops in sourced scripts and eval'd strings don't - mess up the shell's parser state - -bashline.c - - change command_subst_completion_function to suppress appending - any character to a unique completion, instead of a space, unless - the last word in the quoted command substitution completes to a - directory name. In that case we append the expected slash - - 8/1 - --- -builtins/printf.def - - make sure variables are initialized if their values are tested later - -[bash-3.1-alpha1 updated and re-frozen] - - 8/2 - --- -variables.c - - make sure to call stifle_history with an `int' instead of an intmax_t. - Sometimes it makes a difference - - 8/3 - --- -[bash-3.1-alpha1 released] - -support/mksignames.c - - add `SIGSTKFLT' (RHE3) - - add `SIGXRES' (Solaris 9) - - 8/4 - --- -builtins/ulimit.def - - fix typo to make `x' the right option for locks - - add new options to short help synopsis - -variables.c - - use get_variable_value instead of direct reference to value_cell - in make_variable_value when appending to the current value, so - references to array variables without subscripts will be equivalent - to element 0 - -lib/readline/text.c - - rewrote rl_change_case to correctly change the case of multibyte - characters where appropriate - - 8/5 - --- -configure.in - - remove call to obsolete macro AC_ACVERSION - - remove special calls to AC_CYGWIN and AC_MINGW32; AC_CANONICAL_HOST - takes care of those cases - -general.h - - include `chartypes.h' for definition of ISALPHA - - fix definitions of ABSPATH and RELPATH for cygwin - - fix definition of ISDIRSEP for cygwin to allow backslash as a - directory name separator - - 8/9 - --- -builtins/setattr.def - - when setting a variable from the temporary environment in - set_var_attribute (e.g., `LC_ALL=C export LC_ALL'), make sure to - call stupidly_hack_special_variables after binding the variable in - the current context - -builtins/printf.def - - make sure to call stupidly_hack_special_variables if using `printf -v' - to put formatted output in a shell variable - - 8/11 - ---- -support/shobj-conf - - new variable: SHLIB_LIBPREF, prefix for shared library name (defaults - to `lib' - - new variable: SHLIB_DLLVERSION, used on Cygwin to set the library - version number - - new variable: SHLIB_DOT, separator character between library name and - suffix and version information (defaults to `.') - - new stanza for cygwin to generate windows-compatible dll - - 8/14 - ---- -variables.c - - new special variable function for Cygwin, so the export environment - is remade when HOME is changed. The environment is the only way to - get information from the shell to cygwin dlls, for instanace, when - bash is compiled to use an already-installed libreadline - -variables.h - - new extern declaration for sv_home - - 8/15 - ---- -lib/readline/display.c - - call init_line_structures from rl_redisplay if vis_lbreaks == 0 - to avoid consequences of a poorly-timed SIGWINCH - - 8/16 - ---- -subst.c - - fix logic for performing tilde expansion when in posix mode (don't - rely on W_TILDEEXP flag always being set, because it won't be when - expanding the RHS of assignment statement). Use W_TILDEEXP only - when deciding to expand a word marked as W_ASSIGNMENT that doesn't - precede a command name - - 8/17 - ---- -execute_cmd.c - - in execute_function, when subshell == 1, don't short-cut by using - the command contained in the group command -- if you do, any - redirections attached to the group command (function) don't get - executed - -general.h - - new #define, FS_READABLE, indicates file is readable by current - user - -findcmd.c - - rewrote file_status to use S_xxx POSIX file mode bits and to add - support for FS_READABLE (affects ./source and searching $PATH for - scripts whose names are supplied as arguments on the command line) - - change find_path_file to look for readable files -- source requires - it - - change find_in_path_element to do the right thing when FS_READABLE - is supplied as a flag - -doc/bashref.texi - - remove note about posix non-compliance in `.': we now require and - look for readable files when searching $PATH - - 8/20 - ---- -subst.c - - fix setifs to handle case where passed variable is non-zero but - v->value == 0 (as in an unset local variable); treat IFS as unset - in this case - -jobs.c - - in kill_pid, if asked to killpg a process or pgrp whose pgrp is - recorded as the same as the shell's, just call killpg and let the - chips fall where they may -- there may be other processes in that - pgrp that are not children of the shell, so killing each process - in the pipeline will not do a complete job, and killpg'ing each - such process will send too many signals in the majority of cases - -builtins/cd.def - - in posix mode, pwd needs to check that the value it prints and `.' - are the same file - -builtins/read.def - - if reading input from stdin in a non-interactive shell and calling - `read', call sync_buffered_stream to seek backward in the input - stream if necessary (XXX - should we do this for all shell builtins?) - - 8/23 - ---- -builtins/cd.def - - in posix mode, if canonicalization of the absolute pathname fails - because the path length exceeds PATH_MAX, but the length of the passed - (non-absolute) pathname does not, attempt the chdir, just as when - not in posix mode - -builtins/type.def - - don't have describe_command call sh_makepath if the full path found - is already an absolute pathname (sh_makepath will stick $PWD onto the - front of it) - - 8/24 - ---- - -jobs.c - - in posix mode, don't have start_job print out and indication of - whether the job started by `bg' is the current or previous job - - change start_job to return success if a job to be resumed in the - background is already running. This means that bg won't fail when - asked to bg a background job, as SUSv3/XPG6 requires - - new function, init_job_stats, to zero out the global jobstats struct - -{jobs,nojobs}.c - - change kill_pid to handle pids < -1 by killing process groups - -jobs.h - - extern declaration for init_job_stats - -lib/readline/history.c - - check whether or not the history list is null in remove_history - -builtins/history.def - - delete_last_history is no longer static so fc builtin can use it - -builtins/fc.def - - use free_history_entry in fc_replhist instead of freeing struct - members individually - - call delete_last_history from fc_replhist instead of using inline - code - - if editing (-l not specified), make sure the fc command that caused - the editing is removed from the history list, as POSIX specifies - -builtins/kill.def - - just call kill_pid with any pid argument and let it handle pids < -1 - This is the only way to let kill_pid know whether a negative pid or - a job spec was supplied as an argument to kill - -builtins/fg_bg.def - - force fg_bg to return EXECUTION_SUCCESS explicitly if called by bg - and start_job returns successfully - - bg now returns success only if all the specified jobs were resumed - successfully - -execute_cmd.c - - call init_job_stats from initialize_subshell to zero out the global - job stats structure - - 8/25 - ---- -bashline.c - - change vi_edit_and_execute_command to just call vi when in posix - mode, instead of checking $FCEDIT and $EDITOR - -lib/readline/search.c - - if in vi_mode, call rl_free_undo_list in make_history_line_current - to dispose of undo list accumulated while reading the search string - (if this isn't done, since vi mode leaves the current history - position at the entry which matched the search, the call to - rl_revert_line in rl_internal_teardown will mangle the matched - history entry using a bogus rl_undo_list) - - call rl_free_undo_list after reading a non-incremental search string - into rl_line_buffer -- that undo list should be discarded - -lib/readline/rlprivate.h - - add UNDO_LIST * member to search context struct - -lib/readline/isearch.c - - initialize UNDO_LIST *save_undo_list member of search context struct - - 8/27 - ---- -lib/readline/bind.c - - change rl_parse_and_bind to strip whitespace from the end of a - variable value assignment before calling rl_variable_bind - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - clarified the language concerning parsing values for boolean - variables in assignment statements - - 8/28 - ---- -lib/sh/pathphys.c - - fix small memory leak in sh_realpath reported by Eric Blake - - 8/31 - ---- -doc/bashref.texi - - add additional notes to posix mode section - - 9/3 - --- -parse.y - - if $'...' occurs within a ${...} parameter expansion within - double quotes, don't single-quote the expanded result -- the double - quotes will cause it to be expanded incorrectly - - 9/4 - --- -builtins/fc.def - - if STRICT_POSIX is defined, the posix mode default for the editor to - use is $FCEDIT, then ed - -shell.c - - if STRICT_POSIX is defined, initialize `posixly_correct' to 1 - -config.h.in - - add #undef STRICT_POSIX - - 9/5 - --- -configure.in - - add new option argument, --enable-strict-posix-default, configures - bash to be posix-conformant (including defaulting echo to posix - conformance) by default - -builtins/echo.def - - if STRICT_POSIX is defined, default echo to xpg-style - -doc/bashref.texi - - describe the --enable-strict-posix-default option to configure - - 9/10 - ---- -builtins/mkbuiltins.c - - change to not generate N_(""), because the translated empty string is - special to GNU gettext - - 9/13 - ---- -lib/readline/complete.c - - a negative value for rl_completion_query_items means to not ask - -lib/readline/doc/{{rltech,rluser}.texi,readline.3} - - documented new semantics for rl_completion_query_items/ - completion-query-items - - 9/14 - ---- -bashline.c - - bind M-TAB in emacs mode to dynamic-complete-history even if the - current binding is `tab-insert' (which is what it is by default), - not just if it's unbound - - 9/15 - ---- -eval.c - - call QUIT before calling dispose_command on current_command after - the `exec_done' label. If we dispose current_command first, the - longjmp might restore the value of current_command after we've - disposed it, and the subsequent call to dispose_command from the - DISCARD case will free memory twice - - 9/16 - ---- -lib/sh/strto[iu]max.c - - make sure the function being declared is not a cpp define before - defining it -- should fix problems on HP-UX - - 9/19 - ---- -Makefile.in - - make sure the binaries for the tests are at the front of $PATH - - 9/22 - ---- -parse.y - - new flag for parse_matched_pair: P_COMMAND, indicating that the - text being parsed is a command (`...`, $(...)) - - change calls to parse_matched_pair to include P_COMMAND where - appropriate - - if P_COMMAND flag is set and the text is unquoted, check for comments - and don't try to parse embedded quoted strings if in a comment (still - not exactly right yet) - - 9/24 - ---- -builtins/history.def - - if running history -n, don't count these new lines as history lines - for the current session if the `histappend' shell option is set. - If we're just appending to the history file, the issue that caused - history_lines_this_session to be recalculated doesn't apply -- the - history file won't be missing any entries - -lib/readline/isearch.c - - fix C-w handler for isearch string reader to handle multibyte chars - -lib/readline/rlmbutil.h - - new defines for _rl_to_wupper and _rl_to_wlower - -lib/readline/text.c - - use _rl_to_wupper and _rl_to_wlower as appropriate - - 9/26 - ---- -execute_cmd.c - - in shell_execve, if the exec fails due to E2BIG or ENOMEM, just print - the appropriate error message instead of checking out any interpreter - specified with #! - - 9/30 - ---- -bashhist.c - - make $HISTCMD available anytime remember_on_history is non-zero, - which indicates that we're saving commands to the history, and - let it evaluate to 1 if we're not - - 10/4 - ---- -lib/sh/snprintf.c - - in floating(), make sure d != 0 before calling chkinfnan -- gcc on the - version of Solaris 9 I have translates 0 to -inf on the call - -[bash-3.1-beta1 frozen] - - 10/6 - ---- -jobs.c - - set the_pipeline to NULL right away in cleanup_the_pipeline, and - dispose a copy of the pointer so we don't mess with the_pipeline - while we're in the process of destroying it - - block and unblock SIGCHLD around manipulating the_pipeline in - cleanup_the_pipeline - - 10/7 - ---- -[bash-3.1-beta1 released] - -lib/readline/isearch.c - - when switching directions, make sure we turn off the SF_REVERSE - flag in the search context's flags word if we're going from reverse - to forward i-search - -lib/readline/bind.c - - new function, rl_variable_value, returns a string representing a - bindable readline variable's value - - new auxiliary function, _rl_get_string_variable_value, encapsulates - everything needed to get a bindable string variable's value - - rewrote rl_variable_dumper to use _rl_get_string_variable_value - -lib/readline/readline.h - - new extern declaration for rl_variable_value - -lib/readline/doc/rltech.texi - - documented rl_variable_value - -bashline.c - - in command_word_completion_function, if readline sets - rl_completion_found_quote, but doesn't set rl_completion_quote_character, - we have an embedded quoted string or backslash-escaped character in - the passed text. We need to dequote that before calling - filename_completion_function. So far, this is in place only for - absolute program names (those containing a `/') - - in command_word_completion_function, use rl_variable_value to decide - whether or not we should ignore case, and use strncasecmp instead of - strncmp where appropriate - - 10/11 - ----- -builtins/fc.def - - fixed a typo when using POSIX_FC_EDIT_COMMAND - -redir.h - - new flag values for redirections: RX_INTERNAL and RX_USER (currently - unused) - -redir.c - - add_undo_redirect and add_undo_close_redirect now set RX_INTERNAL - flag when making new redirects - - in do_redirection_internal, only set file descriptors > 2 to CLEXEC - if they're marked as RX_INTERNAL - - 10/12 - ----- -jobs.c - - in wait_for_single_pid, if in posix mode, remove the waited-for pid - from the list of background pids, forgetting it entirely. POSIX - conformance tests test for this. - -lib/readline/{readline.h,vi_mode.c} - - new state flag, RL_STATE_VICMDONCE, set after entering vi command - mode the first time; reset on each call to readline() - - 10/13 - ----- -lib/readline/undo.c - - in rl_revert_line, make sure that revert-line in vi mode leaves - rl_point set to 0 no matter the state of the line buffer - -lib/readline/vi_mode.c - - when entering vi_command mode for the first time, free any existing - undo list so the previous insertions won't be undone by the `U' - command. This is how POSIX.2 says `U' should work (and the test - suite tests for it) - -lib/readline/bind.c - - change rl_parse_and_bind so only `set' commands involving boolean - readline variables have trailing whitespace stripped from the value - string - - 10/16 - ----- -lib/glob/sm_loop.c - - fix patscan() to correctly scan backslash-escaped characters - - 10/18 - ----- -lib/sh/{winsize.c,Makefile.in},{jobs,nojobs}.c,Makefile.in,externs.h - - moved get_new_window_size from jobs.c/nojobs.c to new file, - lib/sh/winsize.c, made function global - -{jobs,nojobs,sig}.c,{jobs,sig}.h - - moved SIGWINCH handling code to sig.c rather than duplicate it in - jobs.c and nojobs.c - - call set_sigwinch_handler from sig.c code rather than job control - signal initialization - -sig.[ch] - - new variable, sigwinch_received, acts like interrupt_state for - SIGWINCH, set by sigwinch_sighandler. sigwinch_sighandler no longer - calls get_new_window_size - -parse.y - - add call to get_new_window_size if sigwinch_received at top of - shell_getc - - 10/19 - ----- -lib/malloc/malloc.c - - to avoid orphaning memory on free if the right bucket is busy, use a - new function xplit(mem, bucket) to split the block into two or more - smaller ones and add those to the right bucket (appropriately marking - it as busy) - - audit bsplit(), bcoalesce(), and xsplit() for proper use of busy[], - since they're dealing with two separate buckets - - 10/22 - ----- -subst.c - - new flag for string_extract: EX_REQMATCH, means to return an error - if a matching/closing character is not found before EOS - - new static flag variables: extract_string_error and extract_string_fatal - - change expand_word_internal to check for new error returns from - string_extract and return errors if appropriate - - 10/23 - ----- -builtins/cd.def - - make sure we free TDIR in change_to_directory after calling - set_working_directory (which allocates new memory) and other places - we short-circuit and return - - 10/24 - ----- -subst.c - - modified fix from 10/22 to allow bare ` to pass through (for - some backwards compatibility and more correctness) - - 10/27 - ----- -conftypes.h - - make MacOS X use the RHAPSODY code that gets HOSTTYPE, et al. - at build rather than configure time, to support universal binaries - (fix from llattanzi@apple.com) - - 10/30 - ----- -builtins/evalstring.c - - make sure we don't turn on CMD_NO_FORK in parse_and_execute if - we're running a trap command on signal receipt or exit - -execute_cmd.c - - in shell_execve, improve the error message a little bit if the - interpreter name in a #! exec header ends with a ^M (as in a DOS- - format file) - - 11/1 - ---- -lib/readline/vi_mode.c - - fix vi-mode `r' command to leave the cursor in the right place - -[bash-3.1-rc1 frozen] - - 11/5 - ---- -execute_cmd.c - - make sure a DEBUG trap doesn't overwrite a command string passed to - make_child in execute_simple_command - -bashline.c - - rearrange some code in bash_quote_filename so filenames with leading - tildes containing spaces aren't tilde-expanded before being - returned to the caller - - 11/6 - ---- -lib/readline/display.c - - when deciding where to move the cursor in rl_redisplay and needing - to move the cursor back after moving it vertically and compensate - for invisible characters in the prompt string, make sure that - _rl_last_c_pos is treated as an absolute cursor position in a - multibyte locale and the wrap offset (number of invisible characters) - is added explicitly when deciding how many characters to backspace - - 11/10 - ----- -lib/readline/terminal.c - - _rl_set_screen_size now interprets a lines or columns argument < 0 - as an indication not to change the current value - - 11/11 - ----- - -lib/readline/terminal.c - - new function, rl_reset_screen_size, calls _rl_get_screen_size to - reset readline's idea of the terminal size - - don't call _rl_get_screen_size in _rl_init_terminal_io if both - _rl_screenheight and _rl_screenwidth are > 0 - - don't initialize _rl_screenheight and _rl_screenwidth to 0 in - _rl_init_terminal_io; let caller take care of it - - set _rl_screenheight and _rl_screenwidth to 0 before calling - _rl_init_terminal_io - -lib/readline/readline.h - - new extern declaration for rl_reset_screen_size - -lib/readline/doc/rltech.texi - - documented rl_reset_screen_size - -variables.c - - if readline is being used, compile in a special var function for - assignments to LINES and COLUMNS that calls rl_set_screen_size or - rl_reset_screen_size as appropriate. Only do this in posix mode - and only when STRICT_POSIX is defined at compile time - - new semaphore variable, winsize_assignment, set while doing an - assignment to LINES or COLUMNS - - new variable, winsize_assigned, says LINES or COLUMNS was assigned - to or found in the environment - - if in the middle of an assignment to LINES or COLUMNS, make - sh_set_lines_and_columns a no-op - -lib/sh/winsize.c - - get_new_window_size now takes two int * arguments, to return the - screen dimensions - -externs.h - - change extern declaration for get_new_window_size - -{jobs,nojobs}.c, parse.y - - change callers of get_new_window_size - - 11/12 - ----- -lib/readline/terminal.c - - new variable, rl_prefer_env_winsize, gives LINES and COLUMNS - precedence over values from the kernel when computing window size - -lib/readline/readline.h - - extern declaration for rl_prefer_env_winsize - -lib/readline/doc/rltech.texi - - document rl_prefer_env_winsize - - 11/13 - ----- -lib/readline/rltty.c - - change rl_prep_terminal to make sure we set and reset the tty - special characters in the vi insertion keymap if in vi mode. This - matters if we get accept-line for the previous line while in vi - command mode - - 11/14 - ----- -builtins/pushd.def - - make sure any call to cd_builtin includes a leading `--' from the - argument list (or constructs one) - - 11/16 - ----- -pcomplete.c - - fix small memory leak in gen_wordlist_matches - -[bash-3.1-rc2 frozen] - - 11/21 - ----- -[bash-3.1-rc2 released] - - 11/23 - ----- -lib/readline/display.c - - changes to rl_redisplay to compensate for update_line updating - _rl_last_c_pos without taking invisible characters in the line into - account. Important in multibyte locales where _rl_last_c_pos is an - absolute cursor position - - changes to _rl_move_cursor_relative to account for _rl_last_c_pos - being an absolute cursor position in a multibyte character locale - - rewrote _rl_move_cursor_relative to make it a little simpler - - 11/29 - ----- -lib/readline/display.c - - changes to rl_redisplay and update_line for update_line to communicate - upward that it took the number of invisible characters on the current - line into account when modifying _rl_last_c_pos - - in update_line, adjust _rl_last_c_pos by wrap_offset before calling - _rl_move_cursor_relative, so we pass correct information about the - true cursor position - - 12/1 - ---- -configure.in - - changed release status to `release' - -[bash-3.1 frozen] - - 12/8 - ---- -[bash-3.1 released] - - 12/9 - ---- -doc/{bash.1,version.texi},lib/readline/doc/version.texi - - remove `beta1' from man page footer and texinfo documents - -variables.c - - make sure winsize_assignment is protected by #ifdef READLINE, so - minimal shell will compile - -builtins/read.def - - make sure error cases free memory and run any unwind-protects to - avoid memory leaks - - 12/10 - ----- -execute_cmd.c - - change execute_command_internal to set $PIPESTATUS for ((...)) and - [[ ... ]] commands - -doc/{bash.1,bashref.texi,version.texi} - - add documentation for ulimit -[iqx] and bump revision date - - 12/12 - ----- -parse.y - - make sure parse_compound_assignment saves and restores the - PST_ASSIGNOK parser state flag around its calls to read_token. - Fixes bug reported by Mike Frysinger - - 12/13 - ----- -parse.y - - change parse_compound_assignment to save and restore the value of - last_read_token. Not sure why it was set unconditionally in the - first place after parsing the complete compound assignment - - 12/14 - ----- -lib/readline/text.c - - don't use return value of rl_kill_text (which always succeeds and - returns the number of characters killed) in rl_delete as an indication - of success or failure - - ditto for return value of rl_delete_text - -lib/readline/readline.c - - don't return the value of the called readline function as the return - value from _rl_dispatch_subseq; -1 means something different to the - callers (return 0 all the time to indicate that a readline function - was found and dispatched). Fix from Andreas Schwab for - bug in callback interface first reported by Mike Frysinger - -execute_cmd.c - - fixed a typo in execute_case_command - - 12/15 - ----- -aclocal.m4 - - add check for wctype() to BASH_CHECK_MULTIBYTE, define HAVE_WCTYPE - -config.h.in - - add HAVE_WCTYPE #define - -config-bot.h - - add HAVE_WCTYPE to the set of checks for HANDLE_MULTIBYTE. This - should catch the deficient NetBSD multibyte support - - 12/16 - ----- -parse.y - - use CTLESC instead of literal '\001' when decode_prompt_string - prefixes RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE - - 12/20 - ----- -lib/readline/display.c - - don't treat RL_PROMPT_START_IGNORE specially inside a sequence of - ignored characters - - keep track of the start of the current sequence of ignored - characters; make sure that an empty sequence of such characters - really is an empty sequence, not one that happens to end with '\001' - (RL_PROMPT_START_IGNORE) - - 12/21 - ----- -subst.c - - change expand_word_internal to process rest of `tilde-word' as a - regular part of the word if tilde expansion leaves the tilde-word - unchanged. This means that ~$USER expands to ~chet, which seems - more intuitive, and is effectively what bash-3.0 did - - 12/23 - ----- -subst.c - - when making a local array variable in do_compound_assignment, make - sure that we don't use a variable of the same name from a previous - context - -doc/bash.1 - - documented expansions for word and patterns in case statement - -builtins/ulimit.def,doc/{bashref.texi,bash.1} - - added new -e and -r (nice and rtprio) options to ulimit; documented - them - - 12/26 - ----- -variables.c - - use `hmax' instead of `num' in sv_histsize to avoid integer overflow - problems with intmax_t - -builtins/read.def - - add unwind-protect to restore rl_attempted_completion_function in - case of a timeout - -{bashline,variables}.c - - move initialization of HISTSIZE from initialization path to - load_history, so it can be overridden by a value assigned in a - startup file - -lib/readline/misc.c - - add a missing `return r' so that rl_digit_loop returns a meaningful - value - -lib/readline/{bind,callback,display,isearch,rltty,search,text,vi_mode}.c - - minor cleanups to satisfy compiler warnings, mostly removing unused - variables - - 12/27 - ----- -support/Makefile.in - - add LIBS_FOR_BUILD support; defaults to ${LIBS} - -Makefile.in - - add LIBS_FOR_BUILD with no default value; use when linking programs - using CC_FOR_BUILD (e.g., bashversion) - - 12/28 - ----- -lib/readline/bind.c - - fix rl_translate_keyseq bad translation of \M-\C-x sequences - -execute_cmd.c - - in execute_arith_command, if the expression expands to more than one - word, make sure we join the words into a single string and pass the - entire thing to evalexp() - -expr.c - - new functions: _is_arithop(c), returns true if C is a valid single- - character arithmetic operator; _is_multiop(c), returns true if C is - a token corresponding to a valid multi-character arithmetic operator - - if we encounter a character that isn't a valid arithmetic - operator, throw an error. Try to be intelligent about what type of - error message to print - -subst.c - - new function, expand_arith_string, calls expand_string_if_necessary; - used where an arithmetic expression needs to be expanded - -subst.h - - new extern declaration for expand_arith_string - -arrayfunc.c - - in array_expand_index, call expand_arith_string to expand the - subscript in a fashion consistent with other arithmetic expressions - -subst.c - - fix parameter_brace_patsub so that we don't try to anchor the pattern - at the beginning or end of the string if we're doing global - replacement -- that combination doesn't doesn't make sense, and - the changed behavior is compatible with ksh93 - -doc/{bash.1,bashref.texi} - - changed description of pattern substitution to match the new - semantics - -tests/new-exp.tests - - change tests to remove all ${pat//#rep} and ${pat//%rep} - expansions, since they don't mean the same thing anymore - - 12/29 - ----- -support/signames.c - - new file, initialize_signames() function from old mksignames.c. This - file builds the signal_names array - -support/mksignames.c - - strip out initialize_signames(), move to signames.c. This file only - writes signames.h - - set up to only write a stub signames.h if CROSS_COMPILING is defined, - with extern declaration for initialize_signames - - if not cross compiling, #define initialize_signames to nothing - -Makefile.in - - mksignames is now linked from mksignames.o and buildsignames.o - - add rules to build signames.o, assuming we're building it as part - of the shell (cross-compiling) - -trap.c - - call initialize_signames from initialize_traps - -configure.in - - set SIGNAMES_O to nothing (normal) or signames.o (cross-compiling), - substitute into Makefile - - don't set SIGNAMES_H if cross-compiling any more - - 12/30 - ----- -command.h - - new word flag: W_NOPROCSUB, inhibits process substitution on a word - -subst.c - - change expand_word_internal to suppress process substitution if the - word has the W_NOPROCSUB flag - -shell.c - - --wordexp turns on W_NOPROCSUB in addition to W_NOCOMSUB - -subst.c - - change string_list_dollar_at and string_list_dollar_star so that - MB_CUR_MAX is used to size an array only when using gcc, since gcc - can handle non-constant array sizes using a mechanism like alloca. - Other compilers, e.g. Sun's compiler, do not implement that - extension - - 12/31 - ----- -builtins/mkbuiltins.c - - when cross-compiling, don't include , since it's for the - target rather than the host system. Instead, choose a reasonable - set of default #defines based on a minimal POSIX system - -jobs.c - - change find_process to handle a NULL return value from find_pipeline - - return immediately from delete_job if jobs[index] is already NULL or - if it has a null pipeline associated with it - - in delete_job, if find_last_proc returns NULL, don't try to call - bgp_delete - - 1/7/2006 - -------- -doc/bash.1 - - patch from Tim Waugh to replace some literal single quotes with - \(aq, the groff special character for it - -jobs.c - - in realloc_jobs_list, make sure to zero out slots after j_lastj - in the new list - - 1/9 - --- -support/mksignames.c - - make sure to include to get right value of NSIG from - (usually) - - 1/10 - ---- -parse.y - - when calling parse_matched_pair on a $(...) command substitution, - don't pass the P_DQUOTE flag so that single quotes don't get - stripped from $'...' inside the command substitution. Bug report - and fix from Mike Stroyan - -jobs.c - - start maintaining true count of living children in js.c_living - - call reset_current in realloc_jobs_list, since old values for current - and previous job are most likely incorrect - - don't allocate a new list in realloc_jobs_list if the old size and - new size are the same; just compact the existing list - - make sure realloc_jobs_list updates value of js.j_njobs - - add some more itrace messages about non-null jobs after j_lastj in - jobs array - - 1/11 - ---- -bashjmp.h - - new value for second argument to longjmp: SIGEXIT. Reserved for - future use - - 1/12 - ---- -jobs.c - - add logic to make_child to figure out when pids wrap around - - turn second argument to delete_job into flags word, added flag to - prevent adding proc to bgpids list - - 1/13 - ---- -lib/readline/vi_mode.c - - move code that moves forward a character out of rl_vi_append_mode - into a separate function, _rl_vi_append_forward - - change _rl_vi_append_mode to save `a' as the last command, so it - can be redone properly - - new function _rl_vi_backup, moves point back a character taking - multibyte locales into account - - change rl_vi_redo to handle redoing an `a' command specially -- - it should be redone like `i' but after moving forward a character - - change rl_vi_redo to use _rl_vi_backup to move point backward - after redoing `i' or `a' - -jobs.c - - new function, delete_old_job (pid), checks whether or not PID is in - a job in the jobs list. If so, and the job is dead, it just removes - the job from the list. If so, and the job is not dead, it zeros - the pid in the appropriate PROCESS so pid aliasing doesn't occur - - make_child calls delete_old_job to potentially remove an already-used - instance of the pid just forked from the jobs list if pids have - wrapped around. Finally fixes the bug reported by Tim Waugh - - -trap.c - - new define, GETORIGSIG(sig), gets the original handling for SIG and - sets SIG_HARD_IGNORE if that handler is SIG_IGN - - call GETORIGSIG from initialize_traps, get_original_signal, and - set_signal - -jobs.c - - in wait_for, if the original SIGINT handler is SIG_IGN, don't set - the handler to wait_sigint_handler. This keeps scripts started in - the background (and ignoring SIGINT) from dying due to SIGINT while - they're waiting for a child to exit. Bug reported by Ingemar - Nilsson - -lib/readline/vi_mode.c - - don't save text to buffer unless undo pointer points to a record of - type UNDO_INSERT; zero it out instead. This fixes bug reported by - Craig Turner with redoing `ctd[ESC]' (empty - insert after change to) - -shell.c - - change set_shell_name so invocations like "-/bin/bash" are marked as - login shells - -doc/bash.1 - - add note about destroying functions with `unset -f' to the section - on shell functions - -lib/readline/terminal.c - - if readline hasn't been initialized (_rl_term_autowrap == -1, the - value it's now initialized with), call _rl_init_terminal_io from - _rl_set_screen_size before deciding whether or not to decrement - _rl_screenwidth. Fixes bug from Mike Frysinger - - 1/14 - ---- -lib/readline/input.c - - allow rl_set_keyboard_input_timeout to set the timeout to 0, for - applications that want to use select() like a poll without any - waiting - -lib/readline/doc/rltech.texi - - documented valid values for timeout in rl_set_keyboard_input_timeout - -jobs.c - - in stop_pipeline, don't have the parent shell call give_terminal_to - if subshell_environment contains SUBSHELL_ASYNC (no background - process should ever give the terminal to anything other than - shell_pgrp) - - in make_child, don't give the terminal away if subshell_environment - contains SUBSHELL_ASYNC - - 1/15 - ---- -subst.c - - in parameter_brace_expand, if extracting ${#varname}, only allow - `}' to end the expansion, since none of the other expansions are - valid. Fixes Debian bug reported by Jan Nordhorlz - - 1/17 - ---- -parse.y - - in parse_matched_pair, protect all character tests with the MBTEST - macro - - in parse_dparen, take out extra make_word after call to alloc_word_desc - (mem leak) - - 1/18 - ---- -parse.y - - in parse_matched_pair, add P_ALLOWESC to flags passed to recursive - parse_matched_pair call when encountering a single or double quote - inside a ``-style command substitution - -execute_cmd.c - - add call to QUIT at beginning of execute_command_internal; better - responsiveness to SIGINT - - 1/21 - ---- -lib/readline/bind.c - - change rl_invoking_keyseqs_in_map to honor the setting of - convert-meta when listing key bindings, since if convert-meta is off, - using '\M-' as the prefix for bindings in, for instance, - emacs-escape-keymap, is wrong. This affects `bind -p' output - - change rl_untranslate_keyseq to add '\e' instead of '\C-[' for - ESC - -execute_cmd.c - - add call to QUIT at end of execute_command - - 1/23 - ---- -lib/readline/display.c - - changed two places in update_line where a check of whether the cursor - is before the last invisible character in the prompt string to - differentiate between the multibyte character case (where - _rl_last_c_pos is a physical cursor position) and the single-byte - case (where it is a buffer index). This prevents many unnecessary - \r-redraw the line sequences. Reported by Dan Jacobson. - - 1/24 - ---- -quit.h - - wrap QUIT macro in do...while(0) like other compound statement - macros - - CHECK_TERMSIG define (placeholder for now); future use will be to - handle any received signals that should cause the shell to - terminate (e.g., SIGHUP) - -{input,jobs,nojobs}.c - - add calls to CHECK_TERMSIG where appropriate (reading input and - waiting for children) - - include quit.h if necessary - - 1/25 - ---- -parse.y - - undo change that makes `)' in a compound assignment delimit a token. - It messes up arithmetic expressions in assignments to `let', among - other things - -sig.h,{jobs,nojobs,sig,trap}.c,builtins/trap.def - - rename termination_unwind_protect to termsig_sighandler - -sig.c - - split termsig_sighandler into two functions: termsig_sighandler, which - runs as a signal handler and sets a flag noting that a terminating - signal was received, and termsig_handler, which runs when it is `safe' - to handle the signal and exit - - new terminate_immediately variable, similar to interrupt_immediately - - termsig_sighandler calls termsig_handler immediately if - terminate_immediately is non-zero - -quit.h - - change CHECK_TERMSIG macro to check terminating_signal and call - termsig_handler if it's non-zero - - add same check of terminating_signal and call to termsig_handler to - QUIT macro - -{jobs,nojobs}.c - - change call to termsig_sighandler to call termsig_handler directly, - as was intended - -parse.y,builtins/read.def - - set terminate_immediately to non-zero value when reading interactive - input, as is done with interrupt_immediately - - 1/26 - ---- -doc/{bash.1,bashref.texi} - - reworded the POSIX standard references to remove mention of POSIX.2 - or 1003.2 -- it's all the 1003.1 standard now. Recommended by - Arnold Robbins - - 1/27 - ---- -lib/readline/complete.c - - move call to filename dequoting function into - rl_filename_completion_function; call only if directory completion - hook isn't set. This means that directory-completion-hook now needs - to dequote the directory name. We don't want to dequote the directory - name before calling the directory-completion-hook. Bug reported by - Andrew Parker - -bashline.c - - add necessary directory name dequoting to bash_directory_expansion - and bash_directory_completion_hook - -lib/readline/doc/rltech.texi - - add note to description of rl_directory_completion_hook that it - needs to dequote the directory name even if no other expansions are - performed - - 1/28 - ---- -braces.c - - make sure that we skip over braces that don't start a valid matched - brace expansion construct in brace_expand -- there might be a valid - brace expansion after the unmatched `{' later in the string - - brace_gobbler now checks that when looking for a `}' to end a brace - expansion word, there is an unquoted `,' or `..' that's not inside - another pair of braces. Fixes the a{b{c,d}e}f problem reported by - Tim Waugh - -builtins/declare.def - - when not in posix mode, and operating on shell functions, typeset - and declare do not require their variable operands to be valid - shell identifiers. The other `attribute' builtins work this way. - Fixes inconsistency reported by Mike Frysinger - -{configure,config.h}.in - - add test for setregid, define HAVE_SETREGID and HAVE_DECL_SETREGID - as appropriate - - add test for eaccess, define HAVE_EACCESS if found - -lib/sh/eaccess.c - - new file, with sh_stat and sh_eaccess functions, moved from test.c - - renamed old sh_eaccess as sh_stataccess, since it uses the stat(2) - information to determine file accessibility - - new function, sh_euidaccess, to call when uid != euid or gid != egid; - temporarily swaps uid/euid and gid/egid around call to access - - rewrote sh_eaccess to call eaccess, access, sh_euidaccess or - sh_stataccess as appropriate. access(2) will take into account - things like ACLs, read-only file systems, file flags, and so on. - -lib/sh/Makefile.in,Makefile.in - - add necessary entries for eaccess.[co] - -test.c - - change calls to test_stat to call sh_stat - -{test,general}.c - - change calls to test_eaccess to call sh_eaccess - -externs.h - - new extern declaration for sh_eaccess - -test.[ch] - - remove test_stat and test_eaccess - - 1/29 - ---- -braces.c - - make change from 1/28 dependant on CSH_BRACE_COMPAT not being - defined (since old bash behavior is what csh does, defining - CSH_BRACE_COMPAT will produce old bash behavior) - - 1/30 - ---- -bashline.c - - last argument of bash_default_completion is now a flags word: - DEFCOMP_CMDPOS (in command position) is only current value - - attempt_shell_completion now computes flags before calling - bash_default_completion - - if no_empty_command_completion is set, bash does not attempt command - word completion even if not at the beginning of the line, as long - as the word to be completed is empty and start == end (catches - beginning of line and all whitespace preceding point) - - 2/4 - --- -lib/readline/display.c - - change _rl_make_prompt_for_search to use rl_prompt and append the - search character to it, so the call to expand_prompt in rl_message - will process the non-printing characters correctly. Bug reported - by Mike Stroyan - - 2/5 - --- -lib/readline/display.c - - fix off-by-one error when comparing against PROMPT_ENDING_INDEX, - which caused a prompt with invisible characters to be redrawn one - extra time in a multibyte locale. Change from <= to < fixes - multibyte locale, but I added 1 to single-byte definition of - PROMPT_ENDING_INDEX (worth checking) to compensate. Bug reported - by Egmont Koblinger - - 2/8 - --- -lib/readline/terminal.c - - call _emx_get_screensize with wr, wc like ioctl code for consistency - - new function, _win_get_screensize, gets screen dimensions using - standard Windows API for mingw32 (code from Denis Pilat) - - call _win_get_screensize from _rl_get_screen_size on mingw32 - -lib/readline/rlconf.h - - define SYS_INPUTRC (/etc/inputrc) as system-wide default inputrc - filename - -support/shobj-conf - - changes to make loadable builtins work on MacOS X 10.[34] - -builtins/pushd.def - - changes to make it work as a loadable builtin compiled with gcc4 - - 2/9 - --- -lib/readline/bind.c - - add SYS_INPUTRC as last-ditch default (if DEFAULT_INPUTRC does not - exist or can't be read) in rl_read_init_file - -lib/readline/doc/rluser.texi - - add description of /etc/inputrc as ultimate default startup file - - 2/10 - ---- -lib/readline/bind.c - - fix problem with rl_function_of_keyseq that returns a non-keymap - bound to a portion of the passed key sequence without processing - the entire thing. We can bind maps with existing non-map - functions using the ANYOTHERKEY binding code. - -variables.c - - shells running in posix mode do not set $HOME, as POSIX apparently - requires - - 2/15 - ---- -braces.c - - mkseq() now takes the increment as an argument; changed callers - - 2/16 - ---- -builtins/hash.def - - print `hash table empty' message to stdout instead of stderr - - 2/17 - ---- -lib/readline/readline.c - - when resetting rl_prompt in rl_set_prompt, make sure rl_display_prompt - is set when the function returns - - 2/18 - ---- -lib/readline/display.c - - further fixes to _rl_make_prompt_for_search from Eric Blake to deal - with multiple calls to expand_prompt - - 2/21 - ---- -builtins/hash.def - - don't print `hash table empty' message in posix mode - - 2/27 - ---- -lib/glob/sm_loop.c - - change extmatch() to turn off FNM_PERIOD in flags passed to recursive - calls to gmatch() when calling it with a substring after the start - of the string it receives. Changed `+', `*', `?, `@', and `!' cases - to do the right thing. Fixes bug reported by Benoit Vila - - -braces.c - - add QUIT; statements to mkseq to make large sequence generation - interruptible - - 2/28 - ---- -lib/glob/glob.c - - initialize nalloca in glob_vector - - 3/1 - --- -lib/glob/glob.c - - in glob_vector, when freeing up the linked list after some error, - make sure to set `tmplink' to 0 if `firstlink' is set to 0, else we - get multiple-free errors - - 3/5 - --- -trap.c - - inheritance of the DEBUG, RETURN, and ERR traps is now dependent - only on the `functrace' and `errtrace' shell options, as the - documentation says, rather than on whether or not the shell is in - debugging mode. Reported by Philip Susi - -parse.y - - in parse_matched_pair, don't recursively parse ${...} or other - ${...} constructs inside `` - - in parse_matched_pair, remove special code that recursively parses - quoted strings inside `` constructs. For Bourne shell compatibility - - 3/6 - --- -builtins/pushd.def - - let get_directory_stack take take an `int flags' argument and convert - $HOME to ~ if flags&1 is non-zero - -builtins/common.h - - change extern declaration for get_directory_stack - -variables.c - - call get_directory_stack with an arg of 0 to inhibit converting - $HOME to ~ in the result. Fixes cd ${DIRSTACK[1]} problem - reported by Len Lattanzi (cd fails because - the tildes won't be expanded after variable expansion) - -jobs.c - - changed hangup_all_jobs slightly so stopped jobs marked J_NOHUP - won't get a SIGCONT - -general.c - - changed check_binary_file() to check for a NUL byte instead of a - non-printable character. Might at some point want to check - entire (possibly multibyte) characters instead of just bytes. Hint - from ksh via David Korn - - 3/7 - --- -builtins/reserved.def - - changed runs of spaces to tabs in variables help text to make - indentation better when displayed - -builtins/mkbuiltins.c - - changes to avoid the annoying extra space that keeps gettext from - being passed an empty string - - 3/9 - --- -lib/glob/glob.c - - make sure globbing is interrupted if the shell receives a terminating - signal - - 3/14 - ---- -lib/readline/search.c - - call rl_message with format argument of "%" in _rl_nsearch_init - to avoid `%' characters in the prompt string from being interpreted - as format specifiers to vsnprintf/vsprintf - - 3/19 - ---- -parse.y, eval.c, input.h - - change execute_prompt_command to execute_variable_command; takes the - variable name as a new second argument - - 3/25 - ---- -bashline.c - - command_word_completion_function keeps track of when it's searching - $PATH and doesn't return directory names as matches in that case. - Problem reported by Pascal Terjan - - command_word_completion_function returns what it's passed as a - possible match if it's the name of a directory in the current - directory (only non-absolute pathnames are so tested). - - 3/27 - ---- -subst.c - - expand_arith_string takes a new argument: quoted. Either 0 (outside - subst.c) or Q_DOUBLE_QUOTES (substitution functions); changed callers - -subst.h - - changed extern declaration for expand_arith_string - -arrayfunc.c - - changed call to expand_arith_string in array_expand_index - - 3/31 - ---- -lib/readline/histfile.c - - change read_history_range to allow windows-like \r\n line endings - -execute_cmd.c - - add new variable, line_number_for_err_trap, currently set but not - used - - 4/2 - --- -lib/sh/strtrans.c - - add code to echo -e and echo with xpg_echo enabled to require - a leading 0 to specify octal constants - - 4/3 - --- -subst.c - - slight change to wcsdup() replacement: use memcpy instead of wcscpy - -parse.y - - before turning on W_COMPASSIGN, make sure the final character in the - token is a `(' (avoids problems with things like a=(4*3)/2) - - 4/4 - --- -lib/sh/snprintf.c - - in number() and lnumber(), turn off PF_ZEROPAD if explicit precision - supplied in format - - change number() and lnumber() to correctly implement zero-padding - specified by a non-zero `.precision' part of the format - -subst.c - - new flag for extract_delimited_string: EX_COMMAND. For $(...), so - we can do things like skip over delimiters in comments. Added to - appropriate callers - - changes to extract_delimited_string to skip over shell comments when - extracting a command for $(...) (EX_COMMAND is contained in the - flags argument) - - 4/5 - --- -subst.c - - first argument to skip_single_quoted is now a const char * - - new function, chk_arithsub, checks for valid arithmetic expressions - by balancing parentheses. Fix based on a patch from Len Lattanzi - - 4/6 - --- -{configure,config.h}.in - - add separate test for isnan in libc, instead of piggybacking on - isinf-in-libc test - -lib/sh/snprintf.c - - separate the isnan replacement function so it's guarded by its own - HAVE_ISNAN_IN_LIBC define - -lib/sh/wcsdup.c - - new file, contains replacement wcsdup library function from subst.c - with change back to using wcscpy - -Makefile.in,lib/sh/Makefile.in - - make sure wcsdup.c is compiled and linked in - -subst.c - - wcsdup now found in libsh; removed static definition - - 4/10 - ---- -lib/readline/callback.c - - loop over body of rl_callback_read_char as long as there is additional - input rather than just calling readline_internal_char, which does - not handle multi-character key sequences or escape-prefixed chars - -lib/readline/macro.c - - make sure we turn off RL_STATE_MACROINPUT when the macro stack is - empty if we are reading additional input with RL_STATE_MOREINPUT - -support/shobj-conf - - Mac OS X no longer likes the `-bundle' option to gcc when creating a - dynamic shared library - - 4/11 - ---- -lib/tilde/tilde.c - - don't try to dereference user_entry if HAVE_GETPWENT isn't defined - -lib/readline/input.c - - make sure chars_avail is not used without being assigned a value in - rl_gather_tyi - - use _kbhit() to check for available input on Windows consoles, in - rl_gather_tyi and _rl_input_available - - 4/21 - ---- -lib/readline/display.c - - calculate (in expand_prompt) and keep track of length of local_prompt - in local_prompt_len; use where appropriate - - when using o_pos to check whether or not we need to adjust - _rl_last_c_pos after calling update_line, assume that it's correct - (a buffer index in non-multibyte locales and a cursor position in - multibyte locales) and adjust with wrap_offset as appropriate - - in update_line, set cpos_adjusted to 1 after calling - _rl_move_cursor_relative to move to the end of the displayed prompt - string - - in _rl_move_cursor_relative, check that the multibyte display - position is after the last invisible character in the prompt string - before offsetting it by the number of invisible characters in the - prompt (woff) - - 4/26 - ---- -lib/readline/doc/{rluser.texi,readline.3} - - make sure to note that key bindings don't allow any whitespace - between the key name or sequence to be bound and the colon - - 4/28 - ---- -lib/readline/display.c - - in update_line, make sure we compare _rl_last_c_pos as strictly less - than PROMPT_ENDING_INDEX, since it's 0-based, to avoid multiple - prompt redraws - - 5/4 - --- -parse.y - - in decode_prompt_string, only prefix the expansion of \[ or \] - with CTLESC if the corresponding readline escape character is - CTLESC (coincidentally the same as \[) or CTLNUL. Bug report sent - by Mike Frysinger prompted the discovery - -aclocal.m4 - - slight change to test for /dev/fd to compensate for a linux - failing; suggested by Mike Frysinger - - 5/9 - --- -arrayfunc.c - - broke assign_array_var_from_string into two functions: - expand_compound_array_assignment and assign_compound_array_list; - assign_array_var_from_string just calls those functions now - -arrayfunc.h - - new extern declarations for expand_compound_array_assignment and - assign_compound_array_list - -subst.c - - in do_compound_assignment, call expand_compound_array_assignment - before creating the local variable so a previous inherited - value can be used when expanding the rhs of the compound assignment - statement - - 5/11 - ---- -doc/{bash.1,bashref.texi} - - clarifed `trap' description to make it clear that trapped signals - that are not set to SIG_IGN are reset when a subshell is created - - 5/18 - ---- -locale.c - - change reset_locale_vars to call setlocale (LC_ALL, "") if LANG - is unset or NULL - - if LANG is unset or NULL, reset the export environment before - calling setlocale in reset_locale_vars, and trust that it will - change the environment setlocale() inspects - - 5/21 - ---- -lib/readline/history.c - - new function, HIST_ENTRY *alloc_history_entry (char *string, char *ts); - creates a new history entry with text STRING and timestamp TS (both - of which may be NULL) - - new function, HIST_ENTRY *copy_history_entry (HIST_ENTRY *hist), - which copies the line and timestamp entries to new memory but just - copies the data member, since that's an opaque pointer - - new function, void replace_history_data (int which, histdata_t *old, histdata_t *new) - which replaces the `data' member of specified history entries with - NEW, as long as it is OLD. WHICH says which history entries to - modify - - add calls to replace_history_data in rl_free_undo_list and - rl_do_undo - -lib/readline/undo.c - - new function, alloc_undo_entry (enum undo_code what, int start, int end, char *text) - takes care of allocating and populating a struct for an individual - undo list entry - - new function: _rl_copy_undo_entry(UNDO_LIST *entry) - - new function: _rl_copy_undo_list(UNDO_LIST *head) - -lib/readline/rlprivate.h - - new extern declarations for _rl_copy_undo_{entry,list} - -execute_cmd.c - - change execute_cond_node so that quoting the rhs of the =~ - operator forces string matching, like the == and != operators - - 5/23 - ---- -redir.c - - add_undo_redirect now takes as an additional argument the type of - redirection we're trying to undo - - don't add a "preservation" redirection for fds > SHELL_FD_BASE if - the redirection is closing the fd - - 5/24 - ---- -subst.c - - make sure that parameter_brace_substring leaves this_command_name - set to either NULL or its previous value after setting it so that - arithmetic evaluation errors while expanding substring values - contain meaningful information - - 6/9 - --- -execute_cmd.c - - make sure that SUBSHELL_ASYNC and SUBSHELL_PIPE are set as flag bits - in subshell_environment, rather than setting only a single value - - change execute_subshell_builtin_or_function to give the `return' - builtin a place to longjmp to when executed in a subshell or pipeline - (mostly as the last command in a pipeline). Bug reported by - Oleg Verych - - in execute_simple_command, make sure to call execute_disk_command - with the_printed_command_except_trap to keep DEBUG trap command - strings from overwriting the command strings associated with jobs - and printed in job control messages. Bug reported by Daniel Kahn - Gillmor - -[bash-3.2-alpha frozen] - - 6/22 - ---- -syntax.h - - add new CBLANK (for [:blank:] class) flag value for syntax table and - shellblank(c) character test macro - -mksyntax.c - - add support for setting CBLANK flag in the syntax table depending on - whether or not isblank(x) returns true for character x - -locale.c - - change locale_setblanks to set or unset CBLANK flag for each - character when locale changes - -parse.y - - change call to whitespace(c) in lexical analyzer (read_token()) to - call shellblank(c) instead, so locale-specific blank characters are - treated as white space. Fixes bug reported by Serge van deb Boom - - -print_cmd.c - - when printing redirections, add a space between <, >, and <> and the - following word, to avoid conflicts with process substitution. Bug - reported by Ittay Dror - - 6/26 - ---- -configure.in - - set CROSS_COMPILE to the empty string by default, so we don't inherit - a random value from the environment. Bug reported by - Lee Revell - - 6/29 - ---- -lib/glob/xmbsrtowcs.c - - make sure destp is non-null before assigning a 0 to *destp in - xdupmbstowcs. Fix from Louiwa Salem - -execute_cmd.c - - fix execute_in_subshell to make sure asynchronous isn't set to 0 - before subshell_environment is set appropriately and - setup_async_signals is run. Based on report by Louiwa Salem - - -lib/readline/bind.c - - in rl_generic_bind(), make sure that the keys array is freed before - an error return. Fix from Louiwa Salem - - 7/1 - --- -builtins/read.def - - make sure all editing code is protected with #ifdef READLINE, esp. - unwind-protect that restores the default completion function - -lib/readline/display.c - - make sure to set local_prompt_len in rl_message() [in bash-3.2-alpha] - - 7/5 - --- -builtins/printf.def - - add more of echo's write error handling to printf. Suggested by - martin.wilck@fujitsu-siemens.com - - 7/7 - --- -lib/readline/display.c - - save and restore local_prompt_len in rl_{save,restore}_prompt - [in bash-3.2-alpha] - - 7/8 - --- -[bash-3.2-alpha released] - - 7/9 - --- -lib/readline/display.c - - make sure that _rl_move_cursor_relative sets cpos_adjusted when it - offsets `dpos' by wrap_offset in a multi-byte locale. Bug reported - by Andreas Schwab and Egmont Koblinger - -subst.c - - make sure that the call to mbstowcs in string_extract_verbatim is - passed a string with enough space for the closing NUL. Reported - by Andreas Schwab - - 7/18 - ---- -lib/readline/{display,terminal}.c - - remove #ifdefs for HACK_TERMCAP_MOTION so we can use - _rl_term_forward_char in the redisplay code unconditionally - -lib/readline/rlprivate.h - - new extern declaration for _rl_term_forward_char - -lib/readline/display.c - - in _rl_move_cursor_relative, use `dpos' instead of `new' when - deciding whether or not a CR is faster than moving the cursor from - its current position - - in _rl_move_cursor_relative, we can use _rl_term_forward_char to - move the cursor forward in a multibyte locale, if it's available. - Since that function doesn't have a handle on where the cursor is in - the display buffer, it has to output a cr and print all the data. - Fixes rest of problem reported by Egmont Koblinger - - change variable denoting the position of the cursor in the line buffer - from c_pos (variable local to rl_redisplay) to cpos_buffer_position - (variable local to file) for future use by other functions - - 7/25 - ---- -lib/malloc/{stats,table}.h - - include for prototypes for memset, strlen - -lib/termcap/{termcap,tparam}.c - - include and provide macro replacement for bcopy if - necessary - - 7/27 - ---- -lib/readline/histexpand.c - - add support for `<<<' here-string redirection operator to - history_tokenize_word. Bug reported by agriffis@gentoo.org - -externs.h - - don't add prototype for strerror() if HAVE_STRERROR defined - - 7/29 - ---- -subst.c - - in list_string, use `string' instead of `s' -- s is not initialized - - 8/9 - --- -subst.c - - fix parameter_brace_expand to set W_HASQUOTEDNULL in the WORD_DESC it - returns if the result of parameter_brace_substring is a quoted null - ("\177"). Fixes bug reported by Igor Peshansky - - 8/16 - ---- -lib/readline/readline.h - - new #define, READERR, intended to be used to denote read/input errors - -lib/readline/input.c - - in rl_getc, if read() returns an error other than EINTR (after the - EWOULDBLOCK/EAGAIN cases are handled), return READERR rather than - converting return value to EOF if readline is reading a top-level - command (RL_STATE_READCMD) - -lib/readline/readline.c - - if rl_read_key returns READERR to readline_internal_char[loop], - abort as if it had read EOF on an empty line, without any conversion - to newline, which would cause a partial line to be executed. This - fixes the bug reported by Mathieu Bonnet - -aclocal.m4 - - when testing for validity of /dev/fd/3, use /dev/null instead of - standard input, since the standard input fails with linux and `su'. - Bug reported by Greg Shafer - - 8/17 - ---- -Makefile.in - - switch the TAGS and tags targets so TAGS is the output of `etags' and - tags is the output of `ctags'. Suggested by Masatake YAMATO - - 8/25 - ---- -execute_cmd.c - - change code to match documentation: set BASH_COMMAND (which takes its - value from the_printed_command_except_trap) only when not running a - trap. Rocky says the debugger is ok with this, and this is what his - original diffs did - - 8/29 - ---- -variables.c - - change set_if_not to create shell_variables if it is NULL, since - -o invocation options can cause variables to be set before the - environment is scanned - -[bash-3.2-beta frozen] - - 9/5 - --- -[bash-3.2-beta released] - - 9/8 - --- -variables.c - - change dispose_used_env_vars to call maybe_make_export_env - immediately if we're disposing a temporary environment, since - `environ' points to the export environment and getenv() will use - that on systems that don't allow getenv() to be replaced. This - could cause the temporary environment to affect the shell. Bug - reported by Vasco Pedro - -builtins/echo.def,doc/{bash.1,bashref.texi} - - clarify that `echo -e' and echo when the `xpg_echo' shell option is - enabled require the \0 to precede any octal constant to be expanded. - Reported by Vasco Pedro - - 9/12 - ---- -builtins/printf.def - - make sure `%q' format specifier outputs '' for empty string arguments - Bug reported by Egmont Koblinger - -make_cmd.c - - change make_here_document to echo lines in here-doc if set -v has - been executed. Reported by Eduardo Ochs - -aclocal.m4 - - change BASH_CHECK_MULTIBYTE: - o replace check for wctomb with check for wcrtomb - o add checks for wcscoll, iswctype, iswupper, iswlower, - towupper, towlower - o add call to AC_FUNC_MBRTOWC to check for mbrtowc and mbstate_t - define HAVE_MBSTATE_T manually - o add checks for wchar_t, wctype_t, wint_t - -config.h.in - - add defines for wcscoll, iswctype, iswupper, iswlower, towupper, - towlower functions - - replace define for wctomb with one for wcrtomb - - add defines for wchar_t, wint_t, wctype_t types - -config-bot.h, lib/readline/rlmbutil.h - - add check for HAVE_LOCALE_H before defining HANDLE_MULTIBYTE - - add checks for: ISWCTYPE, ISWLOWER, ISWUPPER, TOWLOWER, TOWUPPER - - add checks for: WCTYPE_T, WCHAR_T, WCTYPE_T - - 9/13 - ---- -lib/readline/display.c - - when displaying prompts longer than the screenwidth in rl_redisplay, - and looking for the index of the last character whose buffer index - is <= the screen width to set up the inv_lbreaks array, make sure to - catch the case where the index == the screen width (an off-by-one - error occurs otherwise with prompts one character longer than the - screen width). Bug reported by Alexey Toptygin - -configure.in - - change DEBUGGER_START_FILE to start with ${ac_default_prefix}/share, - like bashdb installs itself. Reported by Nick Brown - - - 9/14 - ---- -lib/readline/display.c - - make multibyte code that computes the buffer indices of line breaks - for a multi-line prompt dependent on MB_CUR_MAX, so we don't take - the function call hit unless we're in a locale that can have - multibyte characters - - 9/19 - ---- -subst.c - - make dequote_list extern so other parts of the shell can use it - -subst.h - - extern declaration for dequote_list - -builtins/read.def - - call dequote_list before assigning words read to array variable if - we saw an escape character. Old code left spurious CTLESCs in the - string after processing backslashes. Bug reported by Daniel Dawson - - - 9/21 - ---- -[bash-3.2 frozen] - - 10/9 - ---- -support/shobj-coonf - - change -fpic to -fPIC for FreeBSD systems (needed for SPARC at least) - - 10/11 - ----- -[bash-3.2 released] - - 10/12 - ----- -parse.y - - change parse_matched_pair to make sure `` command substitution does - not check for shell comments while parsing. Bug reported against - bash-3.2 by Greg Schaefer - - 10/14 - ----- -parse.y - - add new parser_state flag: PST_REGEXP; means we are parsing a - regular expression following the =~ conditional operator - - cond_node sets PST_REGEXP after reading the `=~' operator - - change read_token to call read_token_word immediately if the - PST_REGEXP bit is set in parser_state - - change read_token_word to skip over `(' and `|' if PST_REGEXP is - set, since those characters are legitimate regexp chars (but still - parse matched pairs of parens) - - 10/16 - ----- -builtins/ulimit.def - - add -e and -r to $SHORT_DOC usage string - -po/ru.po - - fix encoding; Russian text in the file is actually encoded in KOI8-R - - 10/23 - ----- -shell.c - - make sure that the call to move_to_high_fd in open_shell_script - passes 1 for the `check_new' parameter so open high file descriptors - don't get closed and reused. Bug reported by Mike Stroyan - - -doc/bashref.texi - - fixes for typos and misspellings sent in by Brian Gough - - 10/24 - ----- -support/shobj-conf - - make netbsd shared library creation like openbsd's until I hear - differently (called using `gcc -shared') - - 10/26 - ----- -subst.c - - fix bug in parameter_brace_patsub so if the first character of the - expanded pattern is a `/', it is not taken as a global replacement - specifier. Bug reported on forums.nekochan.net - - 10/27 - ----- -builtins/printf.def - - if we need an extern declaration for asprintf, make sure we include - stdarg.h or varargs.h, whichever is appropriate - - if we do not have asprintf, add an extern declaration using - stdarg format. This fixes the bugs with %G on IRIX reported by - Matthew Woehlke and Stuart Shelton - - - -lib/sh/snprintf.c - - add note to not call log_10 with 0 argument -- we don't want to do - what real log10 does (-infinity/raise divide-by-zero exception) - - make sure numtoa (used by dtoa) takes the precision into account - when computing the fractional part with an argument of `0.0' - - make sure `g' and `G' formats don't print radix char if there are - no characters to be printed after it (change to floating()) - - change callers of log_10 (exponent, 'g' and 'G' cases in - vsnprintf_internal) to not call it with 0 for argument. This fixes - the hang reported on IRIX by Matthew Woehlke - and Stuart Shelton - - 10/28 - ----- -builtins/{caller,pushd}.def - - changed longdoc strings in loadable builtin section to be single - strings, as put in the build directory builtins.c file, to aid - translators - - 11/1 - ---- -execute_cmd.c - - reset subshell_environment to 0 after make_child() call in - execute_null_command. Fix provided by Roy Marples - - - 11/7 - ---- -lib/tilde/tilde.c -lib/readline/{util,undo,callback,input,isearch,kill}.c - - make sure that memory allocated with xmalloc is freed with xfree - - 11/9 - ---- -lib/readline/display.c - - make sure that _rl_redisplay_after_sigwinch clears the last displayed - line instead of the current line (instead of assuming that the - cursor is on the last line). Fixes bug reported by Egmont - Koblinger - - 11/10 - ----- -lib/readline/display.c - - make sure that _rl_col_width is never called with MB_CUR_MAX == 1, - since it doesn't count invisible characters and they are not - compensated for. Added a warning in _rl_col_width if called when - MB_CUR_MAX == 1. Bug reported and solution suggested by Eric - Blake - - 11/11 - ----- -lib/readline/display.c - - make sure _rl_wrapped_line is initialized to inv_lbsize int chars. - inv_lbsize and vis_lbsize are the same at that point, but it makes - the intent clearer. Fix from jan.kratochvil@redhat.com. - - in rl_redisplay, make sure we call memset on _rl_wrapped_line with - its full initialized size: inv_lbsize*sizeof(int). Fix from - jan.kratochvil@redhat.com. - - wrap the invisible and visible line variables and _rl_wrapped_line - into line_state structures, which can be swapped more efficiently. - Have to watch the wrapped_line field, since there's now one for - each struct. Changes from jan.kratochvil@redhat.com. - -lib/readline/complete.c - - in stat_char, check for `//server' on cygwin and return `/', since - it will always behave as a directory. Fix from Eric Blake - -lib/readline/histfile.c - - Cygwin's mmap() works in recent versions, so don't #undef HAVE_MMAP. - Recommendation from Eric Blake - -lib/readline/rlwinsize.h - - make sure tcflow() is defined on SCO Unix. Fix from William Bader - -aclocal.m4 - - add check for localeconv to AM_INTL_SUBDIR macro - -config.h.in - - add HAVE_LOCALECONV - -lib/sh/snprintf.c - - add check for HAVE_LOCALECONV for GETLOCALEDATA macro - -general.[ch] - - first argument to legal_number is now `const char *' - - 11/14 - ----- -lib/readline/{readline,rlprivate}.h - - move rl_display_prompt declaration from rlprivate.h to readline.h - -lib/readline/util.h - - new function: rl_free(void *mem), for use by users of readline dlls - on Windows - -lib/readline/readline.h - - new extern declaration for rl_free - -lib/readline/doc/rltech.texi - - document rl_free and rl_display_prompt for use by application writers - - 11/15 - ----- -aclocal.m4 - - change tests for /dev/fd and /dev/stdin to use constructs of the form - (exec test ... ) instead of test ... to avoid bash's /dev/fd and - /dev/stdin emulation - - 11/16 - ----- -jobs.c - - in delete_job, reset_current was being called before the job slot - was cleared -- moved after job_slots[job] was set to NULL. Fixes - bug reported by Dan Jacobson - - 11/19 - ----- -findcmd.c - - when the checkhash option is set, fix the check for the hashed - pathname being an existing executable file. Old code required a - hash table deletion and re-addition. Bug reported by Linda - Walsh - - 11/21 - ----- -subst.c - - in pos_params, handle case of `start' == 0 by making the list of - positional parameters begin with $0 - - in parameter_brace_substring, increment `len' if start == 0, since - we will be adding $0 to the beginning of the list when we process it - -doc/{bash.1,bashref.texi} - - document new behavior of `0' offset when using substring expansion - with the positional parameters - -support/shobj-conf - - changes to shared object creation for loadable builtins on Mac OS X - 10.4 to use libtool instead of ld by specifying -dynamiclib - argument and changing options to be appropriate for libtool. This - winds up creating a dynamic shared library instead of an executable - - 11/24 - ----- -{jobs,nojobs}.c - - don't set last_asynchronous_pid to the child's pid in the child - for asynchronous jobs (for compatibility -- all other posix shells - seem to do it this way). This means that (echo $! )& echo $! should - display two different pids. Fix from discussion on the - austin-group-l list - -builtins/mkbuiltins.c - - change builtins.c file generation so short doc strings are marked for - gettext and available for subsequent translation. Suggestion by - Benno Schulenberg - -builtins/{bind,cd,hash,inlib,printf,pushd,test,times,ulimit}.def -lib/malloc/malloc.c -{shell,subst}.c - - fix a few strings that were not marked as translatable. Fix from - Benno Schulenberg - -lib/readline/misc.c - - new function, _rl_revert_all_lines(void). Goes through history, - reverting all entries to their initial state by undoing any undo - lists. - -lib/readline/rlprivate.h - - extern declaration for _rl_revert_all_lines - -rldefs.h - - add #undef HAVE_STRCOLL if STRCOLL_BROKEN is defined, prep to move - from config.h.in. Problem reported by Valerly Ushakov - - - 11/25 - ----- -lib/readline/readline.c - - call _rl_revert_all_lines from readline_internal_teardown if the - variable _rl_revert_all_at_newline is non-zero - - declare _rl_revert_all_lines initially 0 - - 11/27 - ----- -doc/{bash.1,bashref.texi} - - make sure to be explicit that `typeset +r' cannot remove the readonly - attribute from a variable - - 11/28 - ----- -lib/sh/zmapfd.c - - new file, implements zmapfd(), which takes a file and returns its - contents in a string - -externs.h - - extern declaration for zmapfd - - 11/29 - ----- -builtins/evalfile.c - - in _evalfile, use zmapfd to read the contents of the file into a - string, rather than using the size reported by stat and reading that - many characters, if the file is not a regular file (for things like - named pipes, stat reports the size as 0) - - 12/3 - ---- -lib/sh/snprintf.c - - make sure number() sets the FL_UNSIGNED flag for %x and %X, so - fmtulong treats them as unsigned numbers. Fixes bug reported by - James Botte - - 12/13 - ----- -lib/readline/util.c - - new function, _rl_ttymsg, for internal warning messages -- does - redisplay after printing message - - new function, _rl_errmsg, for internal warning/error messages -- - does not do redisplay after printing message - -lib/readline/rlprivate.h - - new extern declaration for _rl_ttymsg, _rl_errmsg - -lib/readline/{bind,callback,complete,display,rltty}.c - - use _rl_ttymsg/_rl_errmsg instead of direct writes to stderr - -lib/sh/tmpfile.c - - in get_tmpdir(), make sure that $TMPDIR names a writable directory; - otherwise skip it. This catches names longer than PATH_MAX, but in - case it doesn't test that the length does not exceed PATH_MAX. Fixes - heap overrun bug reported by Eric Blake - - 12/16 - ----- -builtin/{set,declare,shopt,trap,wait,bind,complete,enable,fc,history,read,setattr}.def -doc/{bash.1,bashref.texi} - - improvements and clarifications to the help text associated with - several builtins, in some cases bringing them into line with the - man page text. From Benno Schulenberg - -doc/{bash.1,bashref.texi} - - add `E' and `T' to the synopsis of the set builtin. - From Benno Schulenberg - -builtins/{break,exit,fg_bg,hash,jobs,type,ulimit}.def -builtins/{common,evalfile}.c -{error,expr,jobs,mksyntax,nojobs,shell,subst,version,siglist}.c - - add gettextizing marks to untranslated strings - From Benno Schulenberg - - 12/19 - ----- -builtins/common.c - - change display_signal_list (used by `trap -l' and `kill -l') to use - five columns instead of 4 to display signal names - -builtins/help.def - - use the true terminal width instead of assuming 80 when displaying - help topics, leaving two characters of whitespace between horizontal - descriptions instead of 1 - - change to print in columns with entries sorted down rather than across - (that is, like `ls' rather than `ls -x'). Change inspired by Benno - Schulenberg - -jobs.h - - give values to the JOB_STATE enumerations so they can be used as - bitmasks, too - - 12/22 - ----- -doc/{bash.1,bashref.texi} - - change description of `set' to make it clearer that you can use - `+' to turn off options - - clarify in the description of word splitting that sequences of - IFS whitespace at the beginning or end of the string are ignored - - 12/26 - ----- -doc/bashref.texi - - move `shopt' builtin to its own section; change internal references - from `Bash Builtins' to the new shopt builtin - - new section for builtins that modify shell behavior in `Shell - Builtin Commands'; move set and shopt to new section. Changes - inspired by Benno Schulenberg - -{redir,subst}.c - - add MT_USETMPDIR flag to calls to sh_mktmpfd and sh_mktmpname. Bug - reported by Eric Blake - -{configure,Makefile}.in - - changes so that the pathname for DEBUGGER_START_FILE is substituted - into pathnames.h at make time (allowing more flexibility in setting - `prefix' or `datadir') instead of at configure time. Suggested by - Nick Brown - -shell.c - - declaration for have_devfd; initialized from HAVE_DEV_FD - - declaration for check_jobs_at_exit; initialized to 0 - - declaration for autocd; initialized to 0 - -variables.c - - new dynamic variable, BASHPID, always set from return value from - getpid() (changes even when $$ doesn't change). Idea from Bruce - Korb - -builtins/exit.def - - if check_jobs_at_exit is non-zero, list jobs if there are any stopped - or running background jobs; don't exit shell if any running jobs - -execute_cmd.c - - in execute_simple_command, if the first word of a simple command is - a directory name (after looking for builtins, so `.' isn't caught) - that isn't found in $PATH, and `autocd' is non-zero, prefix a "cd" - to the command words - -builtins/shopt.def - - new `checkjobs' option, changes value of check_jobs_at_exit - - new `autocd' option, changes value of autocd - -pcomplete.c - - add COMP_TYPE, set to rl_completion_type, to list of variables set - by bind_compfunc_variables and unset by unbind_compfunc_variables - -doc/{bash.1,bashref.texi} - - document BASHPID - - document new shopt `checkjobs' option - - document new shopt `autocd' option - - document COMP_TYPE completion variable - - 12/29 - ----- -aclocal.m4 - - in BASH_SYS_SIGLIST, check HAVE_DECL_SYS_SIGLIST instead of the - obsolete and no-longer-supported SYS_SIGLIST_DECLARED - - 12/30 - ----- -lib/readline/vi_mode.c - - add ` (backquote) to the list of vi motion characters - - in rl_vi_delete_to, rl_vi_change_to, and rl_vi_yank_to, don't delete - character under the cursor if the motion command moves the cursor - backward, so add F and T to the commands that don't cause the - mark to be adjusted - - add ` to the characters that don't cause the mark to be adjusted - when used as a motion command, since it's defined to behave that way - - when a motion character that may adjust the mark moves point - backward, don't adjust the mark so the character under the cursor - isn't deleted - -lib/readline/complete.c - - add variable rl_sort_completion_matches; allows application to - inhibit match list sorting - - add variable rl_completion_invoking_key; allows applications to - discover the key that invoked rl_complete or rl_menu_complete - -lib/readline/readline.h - - extern declarations for rl_completion_invoking_key and - rl_sort_completion_matches - -lib/readline/doc/rltech.texi - - documented rl_completion_invoking_key and rl_sort_completion_matches - -pcomplete.c - - export variable COMP_KEY to completion functions; initialized from - rl_completion_invoking_key; unset along with rest of completion - variables - -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document COMP_KEY - -[many files] - - changes to make variables and function parameters `const' for better - text sharing. Changes originally from Andreas Mohr - - - 1/4/2007 - -------- -lib/intl/Makefile.in - - use cmp before copying libgnuintl.h to libintl.h -- maybe save a few - rebuilds - -lib/builtins/Makefile - - fixes to build LIBINTL_H if necessary, dependency on this for - mkbuiltins.o prevented `make -j 6' from working correctly - - 1/8 - --- -subst.c - - new function, fifos_pending(), returns the count of FIFOs in - fifo_list (process substitution) - -subst.h - - extern declaration for fifos_pending() - -execute_cmd.c - - in execute_simple_command, if CMD_NO_FORK is set before we call - execute_disk_command, make sure there are no FIFOs in the expanded - words (from process substitution) and turn off CMD_NO_FORK if there - are, so they can get unlinked when the command finishes - - 1/10 - ---- -subst.c - - read_comsub now takes a flags parameter and returns appropriate W_* - flags in it - - command_substitute now returns a WORD_DESC *, with the string it used - to return as the `word' and `flags' filled in appropriately - -subst.h - - changed extern declaration for command_substitute - -{pcomplete,subst}.c - - changed callers of command_substitute appropriately - -subst.c - - string_extract_verbatim now takes an additional int flags argument; - changed callers - - 1/11 - ---- -support/texi2html - - fix problem that caused index links to not be generated if the first - index node had a name different than the node name - -doc/bashref.texi - - encapsulated all indexes into a single `Indexes' appendix; works - around bug fixed in texi2html - - 1/12 - ---- -subst.c - - add call to sv_histtimefmt in initialize_variables so HISTTIMEFORMAT - from the environment is honored. Fix from Ark Submedes (heh) - - -lib/readline/histfile.c - - make sure that the first character following the history comment - character at the beginning of a line is a digit before interpreting - it as a timestamp for the previous line - -doc/{bash.1,bashref.texi},lib/readline/doc/hsuser.texi - - added detail to make it clear exactly how history timestamps are - saved to and read from the history file - -subst.c - - change quote_escapes to add CTLESC before spaces if IFS is null, - just in case we have to split on literal spaces later on (e.g., in - case of unquoted $@). Corresponding changes to dequote_escapes. - Fixes a couple of problems reported by Brett Stahlman - - - 1/14 - ---- -subst.c - - make same change to read_comsub to add CTLESC before ' ' if $IFS is - null, since we will split on literal spaces later - - 1/15 - ---- -array.c - - new function, array_quote_escapes (ARRAY *a), calls quote_escapes - on each element of the array in the same way array_quote calls - quote_string - - call array_quote_escapes if match is not quoted in array_patsub - - array_slice is now used, so remove the #ifdef INCLUDE_UNUSED define - - change structure of array_subrange to call array_slice to create a - new array with the desired subset of elements, then call array_quote - or array_quote_escapes as necessary, like array_patsub. Convert to - a string by calling array_to_string on the sliced-out array - -array.h - - new extern declaration for array_quote_escapes - -subst.c - - since array_patsub now calls quote_escapes as necessary, callers - don't need to call it after array_patsub returns. Fixes first bug - reported by Brett Stahlman - - since array_subrange now calls quote_escapes as necessary, callers - don't need to call it after array_patsub returns. Same fix as - for array_patsub - - 1/31 - ---- -configure.in - - add -DSOLARIS to LOCAL_CFLAGS for solaris x - -config-bot.h - - don't #undef HAVE_GETCWD if GETCWD_BROKEN and SOLARIS are both - defined. Solaris's loopback mount implementation breaks some of the - file system assumptions the replacement getcwd uses. - -builtins/common.c - - if GETCWD_BROKEN is defined, call getcwd with PATH_MAX for the size - argument, so it will allocate a buffer for the current working dir - with that size, instead of one that's `big enough' - -config.h.in - - add #undef PRI_MACROS_BROKEN for AIX 4.3.3 - -pathexp.h - - new flag value for quote_string_for_globbing: QGLOB_REGEXP (quoting - an ERE for matching as a string) - -pathexp.c - - change quote_string_for_globbing to understand QGLOB_REGEXP - -execute_cmd.c - - change execute_cond_node to pass 2 (regexp match), 1 (shell pattern - match), or 0 (no matching) to cond_expand_word - -subst.c - - change cond_expand_word to translate SPECIAL==2 into passing - QGLOB_REGEXP to quote_string_for_globbing - -locale.c - - by default, if all else fails, set shell's idea of locale to "" - instead of its idea of `default_locale' -- the library functions - behave better with that value - - 2/2 - --- -builtins/printf.def - - if PRI_MACROS_BROKEN is defined, #undef PRIdMAX (AIX 4.3.3 broken) - - 2/3 - --- -Makefile.in,{builtins,doc}/Makefile.in,lib/*/Makefile.in - - add assignment for datarootdir as per GNU coding standards - -Makefile.in,builtins/Makefile.in,lib/intl/Makefile.in,po/Makefile.in.in - - use @localedir@ instead of $(datadir)/locale in assignment - - 2/13 - ---- -jobs.c - - fix compact_jobs_list to not return js.j_lastj, since that is in use - and should not be overwritten. Fix from Len Lattanzi - - - 2/16 - ---- -lib/readline/text.c - - change rl_forward_char to allow moving to the end of the line when - using the arrow keys in vi insertion mode, rather than having the - behavior identical between vi command and insertion modes. Change - suggested by Hugh Sasse - - 2/19 - ---- -CWRU/audit-patch - - patch from Steve Grubb of RedHat to make bash - audit root's behavior by logging commands using his audit - framework. Enabled if the shell's name is `aubash'. - - 3/8 - --- -jobs.c - - use WSTATUS (p->status) instead of bare p->status. Fix from - Jim Brown - - 3/9 - --- -lib/readline/{complete,input,isearch,misc,readline,text,vi_mode}.c - - make sure cases where rl_read_key returns -1 (usually due to EIO - because the controlling tty has gone away) are handled correctly. - Prompted by report from Thomas Loeber - - 3/10 - ---- -sig.c - - new function, top_level_cleanup, callable from contexts where some - cleanup needs to be performed before a non-fatal call to - jump_to_top_level - -sig.h - - new extern declaration for top_level_cleanup - -builtins/common.c - - add calls to top_level_cleanup before calls to jump_to_top_level - in a builtin command context (no_args(), get_numeric_arg()). Fixes - bug reported by Ian Watson - -lib/readline/display.c - - in _rl_move_cursor_relative, use `new' when comparing against - the last invisible character in the prompt, since they both denote - buffer indices when in a multibyte locale, whereas `dpos' is a - display position - - 3/13 - ---- -lib/readline/complete.c - - set rl_completion_append_character to the default (' ') in - set_completion_defaults(). Fixes bug reported by David Emerson - - - 3/23 - ---- -builtins/evalfile.c - - make sure read() returns a value >= 0 before using it as an index - into string[] - - use a variable of type `ssize_t' for return value from read() - - only try to read the entire contents of a regular file in one shot - if the file size is less than SSIZE_MAX. These fix problems - reported by hooanon05@yahoo.co.jp. - -include/typemax.h - - define SSIZE_MAX as 32767 if it's not defined - -lib/readline/display.c - - in rl_redisplay() and update_line(), if redrawing the prompt because - it contains invisible characters, make sure we redraw the character - indicating a modified history line and take it into account when - computing _rl_last_c_pos - - in update_line, if deleting characters and redrawing the new text, - make sure we adjust _rl_last_c_pos by wrap_offset in a multibyte - locale if the text we're drawing starts before or at the last - invisible character in the prompt string. Fixes bug reported on - bug-readline by J Pelkey - -parse.y - - when adding at CTLESC character to the current token, do not - escape it with CTLESC if pass_next_character indicates that the - CTLESC was escaped by a backslash. Fixes bug reported by - Paul Bagshaw . - - 3/25 - ---- -lib/readline/text.c - - in rl_forward_char, short-circuit the loop if in emacs mode and - rl_point == rl_end. Fixes problem with multibyte locales - reported by Len Lattanzi - - 3/29 - ---- -command.h - - new flag for subshell_environment: SUBSHELL_PROCSUB, for process - substitution - -subst.c - - add SUBSHELL_PROCSUB to subshell_environment in process_substitute - - 3/30 - ---- -doc/Makefile.in - - fix installation of bash.info to understand that it is in the build - directory, not the source directory - -mailcheck.c - - new function, init_mail_dates, calls remember_mail_dates only if - there are no mailboxes in `mailfiles' - - new function, init_mail_file, initializes a FILEINFO, using the - last time mail was checked as the mtime and atime (or the time the - shell was started if last_time_mail_checked is uninitialized) - - call init_mail_file instead of update_mail_file in add_mail_file, - called from remember_mail_dates (which is supposed to initialize - the list of mail files) - - new convenience functions, alloc_mail_file and dispose_mail_file to - allocate and free FILEINFO structs - -mailcheck.h - - extern declaration for init_mail_dates - -shell.c - - call init_mail_dates instead of remember_mail_dates - - 4/4 - --- -builtins/read.def - - changes to print $PS2 when a line is continued with a backslash in - an interactive shell. This is as POSIX requires - - 4/5 - --- -subst.c - - make sure quote_escapes is only ever called when the word to be - escaped is not marked as double-quoted -- cleaner, and allows us - to make certain assumptions - - 4/6 - --- -subst.c - - change all EX_* defines to begin with SX_ - - new flag, SX_NOCTLESC, obeyed by string_extract_verbatim, tells it - to not obey CTLESC quoting - - change quote_escapes to not quote CTLESC with CTLESC if one of the - chars in $IFS is CTLESC, since the return value from quote_string - will be passed to word splitting and filename generation - - change read_comsub to do the same thing for unquoted command - substitutions - - change list_string to pass SX_NOCTLESC if CTLESC is one of the - chars in $IFS, so it will split on CTLESC instead of using it as a - quote character - - 4/7 - --- -subst.c - - slight change to string_extract_verbatim to allow CTLESC to quote - CTLNUL even if SX_NOCTLESC is set in the flags passed, to protect - the CTLNULs from future calls to remove_quoted_nulls. Only - matters when $IFS contains CTLESC - - changes to cope with $IFS containing CTLNUL in the same way as the - CTLESC changes - -builtins/read.def - - changes to cope with $IFS containing CTLNUL in the same way as the - CTLESC changes - - 4/16 - ---- -lib/sh/strftime.c - - a couple of fixes to the `%z' code - -eval.c - - add an fflush after printing the auto-logout message - - 4/24 - ---- -subst.c - - add call to top_level_cleanup in exp_jump_to_top_level to get things - like unwind-protects and the loop levels cleaned up - -{arrayfunc,expr,variables}.c - - add calls to top_level_cleanup before jump_to_top_level() - - 4/27 - ---- -builtins/complete.def - - make sure the `command' argument to the -C option is printed with - single quotes, since multi-word commands will require them. Bug - reported by martin@snowplow.org - -execute_cmd.c - - change execute_builtin_or_function and execute_subshell_builtin_or_function - to call fflush(stdout) after the builtin or function returns, to - make sure that all output is flushed before the call returns. It - matters on cygwin. Fix suggested by Eric Blake - -redir.c - - in do_redirection_internal, if the file descriptor being acted upon - is the same one used by the stdout stream, call fflush(stdout) to - make sure all output is flushed before changing the underlying fd - out from underneath stdio. Fix suggested by Eric Blake - - - 4/30 - ---- - -builtins/common.c - - new function, sh_chkwrite(int), fflushes stdout and checks for error; - printing an error message and returning a new exit status if there's - an error on stdout. Takes exit status as argument; returns new exit - status (EXECUTION_FAILURE if write error) - -builtins/common.h - - new extern declaration for sh_chkwrite - -builtins/{alias,cd,complete,echo,fc,history,pushd,shopt,times,trap,type,ulimit,umask}.def - - change to use sh_chkwrite to report write errors - -builtins/fc.def - - if an error occurs while writing commands from the history to a file - to be executed, report a write error and return failure without - attempting to execute any commands - - 5/1 - --- -builtins/{bind,declare,set,setattr}.def - - change to use sh_chkwrite to report write errors - - 5/2 - --- -lib/readline/input.c - - fix off-by-one errors in _rl_get_char (pop_index) and rl_stuff_char - (push_index) that caused the 511th character in the buffer to be - discarded. Fixes bug reported by Tom Bjorkholm - - 5/8 - --- -subst.c - - fix parameter_brace_remove_pattern to pass getpattern() newly-allocated - memory. If word expansions (particularly brace expansions) are - required, the expansion code will free the string passed to - expand_word_internal, and we don't want to free unallocated memory - (patstr++) or have duplicate frees (patstr). Fixes bug reported on - Red Hat bugzilla - - 5/9 - --- -lib/readline/signals.c - - fix bug in rl_set_signals that caught SIGINT twice and didn't catch - SIGTERM. Bug reported by Ed Kwan - - 5/18 - ---- -jobs.c - - change compact_jobs_list to return 1 if js.j_lastj == 0 and there is - a job in jobs[0]; compact_jobs_list should never return an index - already occupied - - change reset_job_indices to avoid infinite looping when js.j_firstj - == 0 or js.j_firstj == js.j_jobslots upon function entry. Fixes - bug reported by osicka@post.cz - - 5/20 - ---- - -execute_cmd.c - - new variable, executing_builtin, keeps track of number of "levels" - of builtins being executed; incremented by execute_builtin; saved - and restored by execute_simple_command - -subst.c - - new variable, assigning_in_environment, set and unset around calls - to assign_in_env by the expansion code - -variables.c - - use executing_builtin and assigning_in_environment to decide whether - or not to look into temporary_env when calling find_variable_internal. - Fixes problem reported by Kevin Quinn - - 5/22 - ---- -redir.c - - change add_undo_redirect to differentiate between file descriptors - greater than SHELL_FD_BASE (currently 10) used internally to save - others and then being the targets of user redirection and fds that - are just the target of user redirections. The former need to have - an `exec undo' redirect added to undo it in case exec throws away - redirections; the latter does not. We use the close-on-exec flag - for this: if it's set, we assume that the file descriptor is being - used internally to save another. Fixes problem reported by Ian - Jackson - -shell.c - - new function, init_interactive_script(), does interactive initialization - for a script run with `bash -i script' -- does everything the same - as init_interactive except set `interactive == 1', which causes the - shell to read from the standard input, after calling - init_noninteractive - - call init_interactive_script if a script is run as `bash -i script'. - Fixes problem reported by Joseph Michaud - - 5/24 - ---- -builtins/printf.def - - change vbadd to only call FASTCOPY if the passed buffer length is - > 1 - - if the `-v' option is supplied and `vbuf' is already non-null from a - previous `printf -v var' call, set vbuf[0]=0 explicitly instead of - relying on vbadd to do it -- vbadd may not be called. - - fix PRETURN macro to set vbuf[0] == 0 if vbuf is not freed. These - should fix problem reported by Elmar Stellnberger - -lib/readline/display.c - - fix update_line to deal with the case where col_lendiff > 0 (meaning - the new string takes up more screen real estate than the old) but - lendiff < 0 (meaning that it takes fewer bytes to do so). This can - happen when a multibyte prompt string is replaced with a longer one - containing only single-byte characters (e.g., when doing a reverse - i-search). Fixes gentoo bug reported by Peter Volkov - - -builtins/read.def - - make sure we only print $PS2 if the standard input is a terminal - - new function, read_mbchar, to read a multibyte character so we - can make sure we read entire multibyte chars when `read -n' is - used, rather than bytes. Only called when -n is supplied. - Fixes problem reported by Stanislav Brabec - - 5/25 - ---- -externs.h - - new #defines for third argument to named_function_string: - FUNC_MULTILINE (don't suppress newlines) and FUNC_EXTERNAL (convert - to external display form) - -subst.h - - new extern declaration for remove_quoted_escapes - -subst.c - - remove_quoted_escapes is now global - -print_cmd.c - - in named_function_string, if FUNC_EXTERNAL is in the flags argument, - call remove_quoted_escapes to convert from internal to external form. - Fixes bug reported by Bo Andresen - -variables.c,builtins/{declare,setattr,type}.def - - use FUNC_MULTILINE in calls to named_function_string as appropriate - - add FUNC_EXTERNAL to calls to named_function_string as appropriate - - 5/27 - ---- -{make_cmd,variables}.c - - changes to enable the shell to compile when debugger support is - configured out (function_def hash table and access functions). Fixes - bug reported by Horst Wente - -builtins/help.def - - fix bug in `help' two-column printing to avoid referencing - shell_builtins[num_shell_builtins] - -error.c - - in get_name_for_error, use dollar_vars[0] if the name returned from - looking in $BASH_SOURCE[0] is the empty string as well as if it's - null - - 5/31 - ---- -arrayfunc.c - - change array_value_internal to set *RTYPE to 1 if the reference is - array[*] and 2 if the reference is array[@] - -subst.c - - in parameter_brace_expand_word, set the flags returned by the word - desc to include W_HASQUOTEDNULL if array_value returns QUOTED_NULL - for an array reference like x[*] and the word is quoted. Fixes bug - reported by Christophe Martin - - 6/1 - --- -jobs.c - - several changes to preserve errno if tcgetpgrp/tcgetattr/tcsetattr - fail, for subsequent error messages - - change initialize_job_control to turn off job control if the terminal - pgrp == -1 or is not equal to shell_pgrp (with an error message) - - in initialize_job_control, if the shell has been forced interactive - with -i, make sure stderr is hooked to a tty before using it as - the controlling terminal. If it's not, try to open /dev/tty and - assign it to shell_tty. Fixes problems reported by Derek Fawcus - - - 6/13 - ---- -support/shobj-conf - - changes to support shared object and shared library creation on AIX - 5.x and later versions. From Niklas Edmundsson - - 6/17 - ---- -builtins/mkbuiltins.c - - new array of builtins, posix_builtins, containing builtins listed - as special to the command search order by POSIX - - add POSIX_BUILTIN to the builtin flags if the builtin name is one - that's special to the posix command search order - -builtins.h - - new define, POSIX_BUILTIN, means that a builtin is special to the - posix command search order - - 6/22 - ---- -lib/readline/display.c - - new macro, WRAP_OFFSET, intended to replace W_OFFSET. Takes prompt - strings longer than one physical line with invisible characters on - the second line into account when calculating the number of - invisible characters on the current screen line - - use WRAP_OFFSET where appropriate (update_line, _rl_move_cursor_relative) - - change update_line to deal with adjusting _rl_last_c_pos in a - multibyte environment when the prompt has invisible chars on the - second line and redisplay has output the invisible characters - - change _rl_move_cursor_relative to adjust _rl_last_c_pos in a - multibyte environment when the prompt has invisible chars on the - second line and the redisplay draws the invisible character. Fixes - redisplay bug reported by Andreas Schwab - - - 7/11 - ---- - -lib/readline/rltty.c - - enable flush-output code for systems other than AIX 4.1. Problem - reported by Jan Kratochvil - - 7/12 - ---- -lib/readline/display.c - - set prompt_invis_chars_first_line from the portion of the prompt - following the final newline, instead of from the prefix. Fixes - bug reported on the Ubuntu bug list by dAniel hAhler - - - 7/13 - ---- -variables.c - - use native __QNX__ and __QNXNTO__ cpp defines instead of qnx and - qnx6, respectively. Patch from Sean Boudreau - -lib/sh/getcwd.c - - #undef HAVE_LSTAT on qnx, so it uses stat instead. Patch from - Sean Boudreau - - 7/21 - ---- -builtins/common.c - - change sh_invalidnum to be a little smarter about octal and hex - numbers and change the message appropriately. Bug originally - reported on coreutils list by Jürgen Niinre - - 7/26 - ---- -test.c - - make sure the string passed to test_unop has only a single character - following the `-'. Fixes bug reported by Michael A. Smith - - -parse.y - - better input validation: make sure a word looks like a conditional - unary operator (-X) before calling test_unop - - 7/28 - ---- -trap.c - - in trap_handler, if it's called directly from the signal handler - (e.g., SIGINT sighandler, set by set_sigint_handler), but the - trap disposition has been reset to the default between the - assignment and receipt of the signal, check that the signal is - trapped and issue a warning if the shell was compiled with - debugging enabled. Fixes bug reported by Fergus Henderson - - - 8/1 - --- -lib/readline/{util,histexpand}.c - - fixes for small memory leaks from Michael Snyder - - 8/18 - ---- -Makefile.in - - add dependency on builtins/builtext.h to nojobs.o list. Fixes - `make -j 5' issue reported by Chris MacGregor - -examples/loadables/Makefile.in - - add @LDFLAGS@ to SHOBJ_LDFLAGS assignment -- experimental. Suggested - by Mike Frysinger - -examples/loadables/{basename,cut,dirname,finfo,head,ln,logname,mkdir,pathchk,print,printenv,push,realpath,rmdir,sleep,tee,truefalse,tty,uname,unlink,whoami}.c - - fix up some includes. Fix from Mike Frysinger - - 8/21 - ---- -histexpand.c - - fix another memory leak in history_find_word. Bug report originally - from Michael Snyder ; test case suggested by Jim - Blandy - - 8/26 - ---- -subst.c - - change to do_assignment_internal to make an assignment to a variable - with the `noassign' internal attribute not a variable assignment - error. - - fix do_assignment_internal so assignment to a `noassign' variable - does not cause it to suddenly become visible if it's currently - invisible - - 9/3 - --- -stringlib.c - - change strsub to check whether or not temp is non-null before - trying to null-terminate it. Also make sure temp is allocated - even if the pattern and replacement strings are empty, and set - to a copy of string (like ${foo//}) - Bug report from Timo Lindfors - - 9/10 - ---- -{config.h,Makefile,configure}.in,aclocal.m4 - - new tests for fpurge and __fpurge - -lib/sh/fpurge.c, externs.h - - new file, fpurge(3) implementation with external decl in externs.h - -builtins/common.c - - add call to fpurge(stdout) to sh_chkwrite - -{redir,execute_cmd}.c - - add call to fpurge(stdout) after fflush(stdout) before changing - stdout file descriptor and after a builtin or function executes - - 9/12 - ---- -expr.c - - make sure noeval is set to 0 when a longjmp occurs, since it will - not be reset otherwise, and it can be set to 1 while processing - a {pre,post}-increment or {pre,post}-decrement token - - set noeval to 0 at the beginning of evalexp, since it's never - called recursively - - 9/14 - ---- -config-top.h - - new builder-modifiable define: DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS - Turning it on will cause errors from EPIPE to not be reported by - the normal shell write error message mechanism - -builtins/common.c - - if DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS is defined, don't print an - error message from sh_wrerror if errno == EPIPE. Suggestion from - Petr Sumbera - - 9/19 - ---- -{jobs,nojobs}.c,jobs.h - - add code to retry fork() after EAGAIN, with a progressively longer - sleep between attempts, up to FORKSLEEP_MAX (16) seconds. Suggested - by Martin Koeppe - - 9/21 - ---- -version.c - - change copyright year to 2007 - - 9/25 - ---- -pathexp.c - - change quote_string_for_globbing to add a backslash in front of a - backslash appearing in the pathname string, since the globbing - code will interpret backslashes as quoting characters internally. - Bug reported by on the debian list - (443685) - - 10/8 - ---- -lib/readline/display.c - - in update_line, make sure _rl_last_c_pos is > 0 before setting - cpos_adjusted (or we actually moved the cursor to column 0 in - _rl_move_cursor_relative). Fixes redisplay bug with prompt with - only invisible characters reported by dAniel hAhler - - - 10/10 - ----- -lib/readline/display.c - - in rl_redisplay, when calculating the new physical cursor position - in a multibyte locale (`tx'), do not call rl_backspace if tx ends - up < 0. Rest of fix for bug reported by dAniel hAhler - - - 10/12 - ----- -lib/sh/getcwd.c - - fix memory overwrite problem that's possible if buf is NULL and - passed size is greater than the pathname length. Reported by - Ian Campbell - -builtins/ulimit.def - - change the multiplier for the -c and -f options (`blocks') to 512, - the traditional value (and the one POSIX specifies). Bug reported - by Pete Graner - -braces.c - - pass process substitution through unchanged the same as command - substitution. Prompted by suggestion from Stephane Chazelas - - -lib/readline/input.c - - in rl_unget_char, fix off-by-one error when resetting pop_index if - it's < 0. Bug reported by Uwe Doering - -builtins/type.def - - change exit status of `type' to not successful if any of the - requested commands are not found. Reported by Stephane Chazleas - - -pcomplete.c - - change command_line_to_word_list to use rl_completer_word_break_characters - instead of the shell metacharacters to split words, so programmable - completion does the same thing readline does internally. Reported - by Vasily Tarasov - - 10/16 - ----- -bashline.c - - When completing a command name beginning with a tilde and containing - escaped specical characters, dequote the filename before prefixing - it to the matches, so the escapes are not quoted again. Reported - by neil@s-z.org - - 10/17 - ----- -expr.c - - in readtok(), don't reset lasttp if we've consumed the whitespace - at the end of the expression string. Fixes error message problem - reported by - - 11/1 - ---- -builtins/printf.def - - change asciicode() to return intmax_t; add multibyte character - support instead of assuming ASCII (depending on behavior of system - multibyte support functions). Fixes bug reported by Rich - Felker - - 11/5 - ---- -execute_cmd.c - - if redirections attached to a compound command fail, make sure to - set last_command_exit_value when returning EXECUTION_FAILURE. - Fixes bug reported separately by Andreas Schwab - and Paul Eggert - - 11/9 - ---- -builtins/read.def - - make sure the return value from get_word_from_string is freed if - non-null. Fixes memory leak bug reported by Lars Ellenberg - - - 11/10 - ----- -variables.c - - use getpid() as value of seeded_subshell to avoid problems with - random number generator not getting re-seeded correctly when - subshells are created. Fix from Tomas Janousek - -lib/readline/display.c - - in update_line(), when outputting characters at the end of the line, - e.g., when displaying the prompt string, adjust _rl_last_c_pos by - wrap_offset if the text we're drawing begins before the last - invisible character in the line. Similar to fix from 5/24. Fixes - bug reported by Miroslav Lichvar - - 11/14 - ----- -subst.c - - fix $[ expansion case to deal with extract_arithmetic_subst - returning NULL (if the `]' is missing) and return the construct - unchanged in that case. Fixes tab completion bug reported by - Heikki Hokkanen (debian bug 451263) - -lib/readline/mbutil.c - - fix _rl_find_next_mbchar_internal to deal with invalid multibyte - character sequences when finding non-zero-length chars. Fixes - bug reported by Morita Sho - - 11/15 - ----- -variables.c - - add new function `seedrand' to seed the bash random number - generator from more random data. Suggestion from Steve Grubb - - - replace the rng in brand() with a slightly better one from FreeBSD - (filtered through Mac OS X 10.5). Replacement suggested by - Steve Grubb - - 11/21 - ----- -configure.in - - darwin 9 also requires linking against libreadline.a and - libhistory.a because of Apple's questionable decision to ship a - libreadline "replacement" that doesn't provide all functions - -doc/{bash.1,bashref.texi} - - slight change to the text describing the effect of set -e when - in a || or && list - - 12/5 - ---- -jobs.c - - fix raw_job_exit_status to correct mixing of int/WAIT values (need - to return a WAIT) - - arrange so that children run as part of command substitutions also - set the SIGINT handler to wait_sigint_handler, since they effectively - don't do job control - - in wait_for, if a child run as part of a command substitution exits - due to SIGINT, resend the SIGINT to the waiting shell with kill(2). - This makes sure the exit status propagates - -doc/{bash.1,bashref.texi} - - tighten up the language describing when bash tries to see if its - stdin is a socket, so it can run the startup files. Suggested by - Vincent Lefevre - -eval.c - - in the DISCARD case of a longjmp to top_level, make sure - last_command_exit_value is set to EXECUTION_FAILURE if it's 0, - but leave existing non-zero values alone - -subst.c - - in command_substitute, don't reset pipeline_pgrp in the child - process -- this means that second and subsequent children spawned by - this comsub shell get put into the wrong process group, not the - shell's. Fix for bug reported by Ingo Molnar - - 12/6 - ---- -support/shobj-conf - - make sure the cases for darwin8.x (Mac OS X 10.4.x) are extended to - darwin9.x (Mac OS X 10.5.x). Fixes problem originally reported - against readline-5.2 by schneecrash@gmail.com - - 12/8 - ---- -subst.c - - make sure to add the results of (successful) tilde expansion as a - quoted string, to inhibit pathname expansion and word splitting. - From recent Austin Group interpretation. - -include/shtty.h, lib/sh/shtty.c - - add ttfd_onechar, ttfd_noecho, ttfd_eightbit, ttfd_nocanon, and - ttfd_cbreak to set tty attributes associated with a particular - file descriptor (which is presumed to point to a terminal). Support - for fix for bug reported by b_bashbug@thebellsplace.com - -lib/readline/display.c - - make sure we only use rl_invis_chars_first_line when the number of - physical characters exceeds the screen width, since that's the - only time expand_prompt sets it to a valid value - - 12/12 - ----- -builtins/set.def - - change set_minus_o_option to return EX_USAGE if an invalid option - name is supplied. All callers can handle it. - - change set_builtin to return what set_minus_o_option returns if it's - not EXECUTION_SUCCESS. This allows EX_USAGE errors to abort a - shell running in posix mode - - 12/14 - ----- -builtins/read.def - - generalize the calls to the tty attribute functions to maintain a - local copy of the terminal attributes and use the fd supplied as - the argument to the -u option (default 0). Fix for bug reported - by b_bashbug@thebellsplace.com - -doc/bashref.texi, lib/readline/doc/{history,rlman,rluser,rluserman}.texi - - Slight changes to conform to the latest FSF documentation standards. - Patch from Karl Berry - - 12/20 - ----- -execute_cmd.c - - after calling clear_unwind_protect_list, make sure we reset - parse_and_execute_level to 0, since there's nothing left to - restore it if top_level_cleanup tests it. Fixes bug reported - by Len Lattanzi - - 12/31 - ----- -lib/sh/getcwd.c - - new function, _path_checkino, checks whether the inode corresponding - to the path constructed from the first two arguments is the same as - the inode number passed as the third argument - - if BROKEN_DIRENT_D_INO is defined, meaning the d_ino/d_fileno - member of struct dirent doesn't contain valid values, use - _path_checkino instead of directly comparing against d_fileno. - Fixes Interix problem reported by Michael Haubenwallner - - - 1/7/2008 - -------- -array.c - - fix array_subrange to separate elements in returned string with - first char of $IFS if QUOTED is non-zero, since this indicates - the caller used ${array[@]:foo}. Fixes bug reported by Lea - Wiemann - - 1/8 - --- -subst.c - - new function returning a string containing the first character of - $IFS: char *ifs_firstchar(int *) - -subst.h - - extern declaration for ifs_firstchar() - -array.c - - call ifs_firstchar() to get first character of $IFS when needed - (array_subrange() and array_patsub()) - - 1/11 - ---- -lib/readline/display.c - - use sentinel variable set at end of init_line_structures to decide - whether to call it from rl_redisplay, since early SIGWINCH on - Mac OS X that hits during this function can cause _rl_wrapped_line - to be referenced before initialization. Fix for bug reported by - Len Lattanzi - -subst.[ch] - - skip_to_delim is now compiled into the shell all the time, not just - when readline is linked in - -subst.c - - use skip_to_delim to find the `/' denoting the end of a pattern - in pattern substitution, since it knows more shell syntax than - quoted_strchr and understands multibyte characters. Fixes bug - reported by Dmitry V Golovashkin - - 1/15 - ---- -subst.c - - add `flags' argument to skip_to_delim telling it whether or not to - set no_longjmp_on_fatal_error; set this flag when calling from the - readline completion code - -subst.h - - update extern declaration for skip_to_delim - - 1/17 - ---- -subst.c - - expand_prompt_string takes a third argument: the initial flags for - the WORD - -subst.h - - change extern declaration for expand_prompt_string to add third arg - -bashline.c - - pass W_NOCOMSUB as third argment to expand_prompt_string when - calling from bash_directory_completion_hook, since we don't want - to do command substitution from the completion code - -parse.y - - change call to expand_prompt_string - - 1/18 - ---- -doc/Makefile.in - - added an `install_builtins' rule to install the builtins.1 man page, - preprocessing it with sed to force `.so man1/bash.1', which some - versions of man require. Suggestion from Peter Breitenlohner - - - new target `install_everything' that will install normal documentation - and builtins man page - - changed uninstall target to remove bash_builtins page from man - directory - -lib/readline/vi_mode.c - - new function, rl_vi_insert_mode, which calls rl_vi_start_inserting - to make sure the value of `last command to repeat' is set correctly. - Fix from Thomas Janousek - - add support for redoing inserts made with the `I' command. Fix - from Thomas Janousek - - add support for redoing inserts made with the `A' command - -lib/readline/readline.h - - new extern declaration for rl_vi_insert_mode - -lib/readline/{misc,readline,vi_mode,vi_keymap}.c - - change calls to rl_vi_insertion_mode to rl_vi_insert_mode - - 1/19 - ---- -builtins/read.def - - change timeout behavior when not reading from a tty device to save - any partial input in the variable list, but still return failure. - This also causes variables specified as arguments to read to be - set to null when there is no input available. Fix inspired by - Brian Craft - - 1/21 - ---- -builtins/fc.def - - change computation of last_hist to use remember_on_history instead - of a hard-coded `1'. This keeps fc -l -1 in PROMPT_COMMAND from - looking too far back - - 1/25 - ---- -lib/readline/complete.c - - fix fnwidth to use string[pos] instead of *string when testing the - current character for a control character or rubout - - 2/2 - --- -general.c - - change posix_initialize to turn off source/. searching $PWD when - the file sourced is not found in $PATH. Fixes bug reported by - Paolo Bonzini and Eric Blake - - 2/9 - --- -builtins/*.def - - changes to text and formatting suggested by Jan Schampera - - - 2/16 - ---- -bashline.c - - change command_word_completion_function to use the word completion - found by readline, which matters only when ignoring case is on - and the completion found in the file system differs in case from - the text the user typed (this is what readline does for normal - filename completion). Fixes issue reported by Jian Wang - . - - 2/18 - ---- -builtins/source.def - - if the filename passed as an argument contains a `/', don't search - $PATH. Not sure why it wasn't like this before - - 2/21 - ---- -lib/readline/terminal.c - - change rl_crlf so that the MINT system on ATARI systems adds a - carriage return before the \n - - 2/22 - ---- -doc/{bash.1,bashref.texi} - - added text to the EXIT STATUS section noting that exit statuses - fall between 0 and 255, inclusive - -support/mkversion.sh - - output a #define for DEFAULT_COMPAT_LEVEL (${major}${minor}; e.g. 32) - to version.h - -version.c - - int variable, shell_compatibility_level, set to DEFAULT_COMPAT_LEVEL - by default - -builtins/shopt.def - - new shopt variable, compat31, sets shell_compatibility_level to 31 - (or back to default if unset) - -execute_cmd.c - - in execute_cond_node, restore bash-3.1 behavior of quoted rhs of - regexp matches if shell_compatibility_level == 31 - - 2/28 - ---- -lib/readline/rltty.c - - set readline_echoing_p = 1 if tcgetattr fails and sets errno to - EINVAL, as Linux does when the fd is a pipe. Reported by Mike - Frysinger - - 3/6 - --- -{MANIFEST,Makefile.in},lib/sh/{casemod,uconvert,ufuncs}.c - - new library sources from bash-4.0-devel tree - -lib/sh/spell.c - - moved cdspell() here from builtins/cd.def, renamed dirspell() - -externs.h - - new declarations for extern functions from new library files - - new extern declaration for lib/sh/spell.c:dirspell() - -builtins/cd.def - - call extern library function dirspell(); remove static cdspell() - -builtins/read.def - - when read times out, make sure input_string is null-terminated before - assigning any partial input read to the named variables - - 3/10 - ---- -lib/glob/xmbsrtowcs.c - - cut the number of memory allocations in xdupmbstowcs by not keeping - track of the indices if the caller hasn't asked for it - - 3/17 - ---- -builtins/fc.def - - make sure the adjustment to i in fc_gethnum uses the same formula - fc_builtin uses to calculate last_hist - - make sure that every time fc_gethnum is called, the fc command last - in the history list has not yet been deleted, since fc_gethnum - assumes that it has not. Fix from John Haxby - -lib/readline/complete.c - - new private library function, _rl_reset_completion_state(), used to - reset any completion state internal to the library when a signal - is received - - call _rl_reset_completion_state() before returning from - rl_complete_internal - -lib/readline/rlprivate.h - - new extern declaration for _rl_reset_completion_state - -lib/readline/signals.c - - call _rl_reset_completion_state from rl_signal_handler on SIGINT. - This fixes one of the problems identified by Mika Fischer - - -pcomplete.c - - programmable_completions now saves pointer to the compspec it's - working with in new global variable CURCS - - new function, pcomp_set_readline_variables, that sets or unsets - readline variables based on a passed flags value (COPT_FILENAMES, - etc.) - - new function, pcomp_set_compspec_options, to set or unset bits in - the options word of a passed compspec (default CURCS) - - only call bash_dequote_filename (via rl_filename_dequoting_function) - from pcomp_filename_completion_function if the readline state - word indicates word completion is in progress - -pcomplete.h - - new extern declaration for curcs - - new extern declaration for pcomp_set_readline_variables - - new extern declaration for pcomp_set_compspec_options - -bashline.c - - fix bash_dequote_filename to implement shell quoting conventions: - 1. Inhibit backslash stripping within single quotes - 2. Inhibit backslash stripping within double quotes only if - the following character is one of the special ones - - call pcomp_set_readline_variables from attempt_shell_completion - instead of doing the equivalent inline - - 3/18 - ---- -bracecomp.c - - make sure we sort array of matches in byte order (using strcmp). so - the brace calculations work correctly even when the locale orders - characters like aAbBcC...zZ. Fixes bug reported by Torsten Nahm - - - 3/20 - ---- -lib/readline/{rltty,signals}.c - - move block_sigint and release_sigint from rltty.c to signals.c; add - _rl_ prefix to make them public to the library; change callers. - From Jan Kratochvil - -lib/readline/rlprivate.h - - new extern declarations for _rl_block_sigint and _rl_release_sigint - -lib/readline/display.c - - add calls to _rl_block_sigint and _rl_release_sigint to rl_redisplay, - since it maniupluates global data structures. Fix from Jan - Kratochvil - -builtins/printf.def - - change calls to asprintf and manually adding to vbuf to use calls - to vsnprintf against vbuf directly -- if the number of characters - to be written overflows the buffer, realloc the buffer and use - vsnprintf again. This should reduce the memory used by printf. - Idea from Yuya Katayama - -lib/readline/doc/rltech.texi - - documented rest of readline's state flags, including RL_STATE_CALLBACK - - documented rl_save_state and rl_restore_state - - 3/27 - ---- -lib/readline/{rlprivate.h,{display,readline,rltty,terminal,text}.c} - - rename readline_echoing_p to _rl_echoing_p for namespace consistency - -lib/readline/{rlprivate.h,{callback,readline,util}.c} - - rename readline_top_level to _rl_top_level for namespace consistency - -builtins/ulimit.def - - new -b (socket buffer size) and -T (number of threads) options - -array.c - - fix bug in calculation of the array element assignment string length: - use length of `is' instead of `indstr'. Reported as ubuntu bug - #202885 by John McCabe-Dansted - -builtins/setattr.def - - new function, show_all_var_attributes, displays attributes and - values for all shell variables (or shell functions) in a reusable - format - -builtins/common.h - - new extern declaration for show_all_var_attributes - -builtins/declare.def - - change `declare -p' to print out all variable attributes and values, - and `declare -fp' to print out all function attributes and - definitions. Inspired by request from John Love-Jensen - - -doc/{bash.1,bashref.texi} - - document new -b and -T options to ulimit - - tighten up language describing AND and OR lists - - add description of new behavior of `declare -p' - - 3/28 - ---- -pcomplete.c - - rename curcs -> pcomp_curcs - - new global completion variable, pcomp_curcmd, the current command - name being completed - -builtins/complete.def - - new builtin, compopt, allows completion options for command names - supplied as arguments or the current completion being executed to - be modified. Suggested by Mika Fischer - - 3/30 - ---- -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document new compopt builtin - - 4/5 - --- -support/shobj-conf - - change solaris10 stanza to use -fPIC to fix 64-bit sparc_v9/solaris10 - compilations. Fix from Fabian Groffen - -builtins/read.def - - added `-i text' option, inserts `text' into line if using readline. - Suggested by many, used some ideas from Kevin Pulo - -doc/{bash.1,bashref.texi} - - document new `-i text' option to read builtin - - 4/7 - --- -lib/readline/bind.c - - new settable variable, `history-size', sets the max number of - entries in the history list - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - document new `history-size' settable readline variable - - 4/8 - --- -builtins/complete.def - - change build_actions calling sequence to take a struct with `other' - (non-action) flag arguments (-p, -r) - - add support for `-E' option to build_actions and complete builtin -- - modifies or displays (internal) `_EmptycmD_' completion spec - -bashline.c - - change attempt_shell_completion to try programmable completion on an - `empty' command line and return the results - -doc/bash.1,lib/readline/doc/rluser.texi - - documented new `-E' option to `complete' - - 4/9 - --- -bashhist.c - - new variable, `enable_history_list', used to reflect setting of - `-o history' option - - change bash_history_{enable,disable,reinit} to set enable_history_list - as well as remember_on_history - -builtins/set.def - - use `enable_history_list' instead of `remember_on_history' to keep - value of `-o history' option - -builtins/evalstring.c - - instead of unwind-protecting remember_on_history, use a function to - restore it to the value of `enable_history_list' after - parse_and_execute runs the commands in the string. This allows - history to be turned off in a startup file, for instance. Problem - reported by Dan Jacobson - - 4/11 - ---- -bashline.c - - limited support for completing command words with globbing characters - (only a single match completed on TAB, absolute or relative - pathnames supported, no $PATH searching, some support for displaying - possible matches, can be used with menu completion). - Suggested by Harald Koenig - -print_cmd.c - - change redirection printing to output r_err_and_out as `&>file', - since the man page says that's the preferred form - - 4/12 - ---- -builtins/*.def - - change long doc so the first line is a short description - - add `Exit Status:' section to each longdoc describing exit values - -builtins/help.def - - new `-d' option to print short description of each utility - - new `-m' option to print description of each builtin in a - pseudo-manpage format (inspired by ksh93) - -doc/{bash.1,bashref.texi} - - document new `-d' and `-m' options to `help' - -builtins/mapfile.def - - new builtin, `mapfile', imported from bash-4.0-devel branch - -tests/{mapfile.{data,right,tests},run-mapfile} - - tests for `mapfile' builtin - -doc/{bash.1,bashref.texi} - - added description of `mapfile' builtin - -MANIFEST,Makefile.in,builtins/Makefile.in - - added entries for mapfile source files - -arrayfunc.[ch] - - new function, bind_array_element, to support mapfile builtin - - 4/20 - ---- -expr.c - - fix operator precendence in expcond(): term after the `:' is - a conditional-expression, not a logical-OR-expression (using C - terminology). Bug reported by - - 4/22 - ---- -bashintl.h - - new P_ define for using ngettext to decide on plural forms - (currently unused) - - 4/25 - ---- -execute_cmd.c - - in execute_disk_command, if the command is not found, search for - a shell function named `command_not_found_handle' and call it - with the words in the command as arguments. Inspired by Debian - feature. - -doc/{bash.1,bashref.texi} - - document new command_not_found_handle behavior in COMMAND EXECUTION - section - -configure.in - - change default version to bash-4.0-devel - - 4/28 - ---- -variables.c - - change push_func_var and push_exported_var to call - stupidly_hack_special_variables if the temporary variable is going - to be disposed. This undoes any internal changes caused by a local - variable assignment in the environment or in a shell function. Bug - reported by Morita Sho in - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=478096 - - 5/3 - --- -builtins/fc.def - - fixed a problem caused by change of 1/21 to use remember_on_history, - since it's turned off by parse_and_execute(), but can cause the - last command in history to be deleted and leave last_hist pointing - beyond the end of the history list. edit_and_execute_command can - do this. - -bashline.c - - new define, RL_BOOLEAN_VAR_VALUE, to take a readline boolean variable - and get its value as 0 or 1 (consider making readline global) - - put tty back into canonical mode before calling parse_and_execute in - edit_and_execute_command and then back into raw mode after it - returns. Fixes problem identified by . - - 5/4 - --- -lib/glob/glob.c - - code to support `globstar' option: GX_GLOBSTAR and two internal - flags. Changes to skipname, glob_vector, mbskipname, glob_filename. - New function finddirs(). - -lib/glob/glob.h - - new defines to support globstar code - -builtins/shopt.def - - new shell option, `globstar', enables special handling of `**' in - glob patterns -- matches all directories recursively - -pathexp.h - - extern declaration for glob_star - -pathexp.c - - break inline code out of quote_globbing_chars into a separate - function to decide whether a character is a globbing char: - glob_char_p - - change shell_glob_filename to call glob_filename with the - GX_GLOBSTAR flag if glob_star is set - -doc/{bash.1,bashref.texi} - - document new `globstar' shell option - -arrayfunc.c - - new function, broken out of quote_array_assignment_chars: - quote_assign; extended from old code to make sure that globbing - chars and chars in $IFS are quoted when displaying assignment - statements, especially in compound array assignments - - 5/5 - --- -bashline.c - - new variable, dircomplete_spelling, controls spelling correction - of directory names when doing filename completion - - change bash_directory_completion_hook to incorporate spelling - correction if initial canonicalization of directory name fails - -builtins/shopt.def - - new shell option, `dirspell', enables and disables spelling - correction of directory names during word completion - -builtins/read.def - - support for fractional timeout values (ival.uval); uses uconvert - and falarm/setitimer - -config.h.in - - new `HAVE_SETITIMER' define - -configure.in - - look for setitimer(2), define HAVE_SETITIMER if found - -doc/{bash.1,bashref.texi} - - document new `dirspell' shopt option - - document new fractional values to `read -t timeout' - - 5/6 - --- -assoc.[ch] - - new files, basic support for associative array implementation - -general.h - - new extern declarations for sh_openpipe, sh_closepipe, trim_pathname - -general.c - - new functions: sh_openpipe to create a pipe and move the file - descriptors to a high range; sh_closepipe, to close pipe fds and - clean up, and trim_pathname, to replace portions of a pathname - with `...' (for prompting) - -jobs.c - - don't set last_asynchronous_pid in child shell (messes up $!, among - other things) - -parse.y,parser.h - - moved definitions of parser flags to parser.h - -array.c - - imported array_modcase (case-changing operations on arrays) from - 4.0-devel branch - -array.h - - new extern declaration for array_modcase - -lib/readline/complete.c - - new variable, rl_menu_completion_entry_function, generator for - rl_menu_complete - - new menu completion `browsing' implementation, with several - improvements over the old code. Inspired by Sami Pietila - - -lib/readline/readline.h - - extern declaration for rl_menu_completion_entry_function - - 5/8 - --- -lib/readline/complete.c - - add support for a third argument to fnprint and print_filename, - which supports replacing a specified portion of the pathnames - printed when displaying possible completions with a `...' (or - `___', if the prefix would be confused with a portion of the - filename) - - new variable, _rl_completion_prefix_display_length, sets the - number of characters in a common prefix to be replaced with an - ellipsis when displaying possible completions - - add support to _rl_display_match_list to find the length of the - common prefix of all items being displayed, and passing that - value to print_filename for possible replacement with an ellipsis - if that length is longer than _rl_completion_prefix_display_length - -lib/readline/bind.c - - add support for retrieving value of history-size variable to - _rl_get_string_variable_value - - new bindable variable, completion-prefix-display-length. When - displaying possible completions, matches with a common prefix - longer than this value have the common prefix replaced with an - ellipsis - - support for retrieving value of completion-prefix-display-length - variable to _rl_get_string_variable_value - - new bindable variable, revert-all-at-newline: if enabled, causes - all changes in history lines to be undone before readline returns - after processing a newline - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - document new `completion-prefix-display-length' variable - - document new `revert-all-at-newline' variable - -execute_cmd.c - - change execute_builtin to not inherit the `-e' flag into commands - executed by the `command' or `source/.' builtins if we are supposed - to be ignoring the return value. This is like `eval'. Fixes bug - reported by Hiroshi Fujishima - - 5/10 - ---- -variables.c - - when reading the initial environment, don't create variables with - names that are not valid shell identifiers. Fixes bug reported by - Stephane Chazleas - - 5/13 - ---- -subst.c - - fix string_quote_removal to gracefully handle the case where a - backslash is the final character in the string (leaves the backslash - in place). Fixes bug reported by Ian Robertson - - - 5/16 - ---- -support/checkbashisms - - Perl script that purports to check for bash-specific features in a - shell script. Lifted from Debian via ubuntu - - 5/20 - ---- -lib/readline/display.c - - in update_line, when deciding whether or not to adjust _rl_last_c_pos - in a multibyte environment after printing the last line of a multiline - prompt with invisible characters on the first and last lines, use - the number of inivisible chars on the first line in the calculation - deciding whether or not we're past the last invisible character and - need to adjust the cursor position. Old code used the number of - invisible chars on the last prompt line. Fixes bug reported by - stuff@slinkp.com. - - in update_line, when fixing _rl_last_c_pos after drawing the first - line of the prompt, use the number of invisible chars on the first - line as the offset, instead of the total number of invisible chars - - use prompt_multibyte_characters, the number of multibyte chars in - the prompt string, to short-circuit some relatively expensive - multibyte text processing in rl_redisplay - - 5/21 - ---- -variables.c - - new function, reinit_special_variables(), a hook for special - vars that need their hook functions called when they're unset as - a result of the shell reinitializing itself to run a script - -shell.c - - shell_reinitialize now calls reinit_special_variables - - shell_reinitialize now calls bashline_reset - -variables.h - - new extern declaration for reinit_special_variables - -bashline.c - - new function, bashline_reset(), called when the shell reinitializes - in shell_reinitialize. Right now, just resets - bash_readline_initialized to 0. - -bashline.h - - new extern declaration for bashline_reset() - - 5/23 - ---- -bashhist.c - - new function, bash_clear_history, clears the history and resets any - associated internal bash state - -bashhist.h - - extern declaration for bash_clear_history - -builtins/history.def - - call bash_clear_history instead of clear_history for `history -c'. - Fixes part of problem reported by Scott McDermott - - - decrement history_lines_this_session in delete_histent, called for - `history -d' - -builtins/history.def,bashhist.[ch] - - move delete_histent() to bashhist.c; rename to bash_delete_histent - - move delete_last_history() to bashhist.c; rename to - bash_delete_last_history() - - 5/25 - ---- -braces.c - - add another parameter to mkseq(), the number of digits to put into - each member of a numeric sequence (width), changes to determine - any zero-padding go into expand_seqterm - - changes to expand_seqterm to allow user-specified increments - -bashline.[ch],shell.c,sig.c - - switched names of bashline_reinitialize and bashline_reset to better - reflect their functions - - when searching $PATH for directories to use for command completion, - make sure to free `current_path' before going out of scope - - new bindable function `dabbrev-expand', which is more or less - menu completion using dynamic history completion as the generator - - changes to bash_execute_unix_command to set variables for the - executed command like programmable completion: READLINE_LINE - (rl_line_buffer) and READLINE_POINT (rl_point) - - change to bash_execute_unix_command to allow the executed command - to change the readline line buffer by modifying the value of - READLINE_LINE and to change rl_point by modifying the value of - READLINE_POINT - -common.h - - new SEVAL_ defines for later parse_string changes from 4.0-devel - branch - -command.h - - new defines for new &>> r_append_err_and_out redirection - -builtins/evalstring.c - - new function, parse_string, parses a command from a passed string - and returns the number of characters consumed. For satisfying - Posix rules when parsing command substitutions, from bash-4.0-devel - branch - - split out common prolog code from parse_string and - parse_and_execute into a separate function called from both - -parse.y - - small changes to add symbols needed for parse_string - - parser change to add `|&' as synonym for `2>&1 |'; translation is - performed at parse time so |& never shows up in output of - print_command, for instance. Picked up from zsh, merged in from - bash-4.0-devel branch - -parse.y,{redir,copy_cmd,dispose_cmd,make_cmd,print_cmd}.c - - implement new &>> r_append_err_and_out (like >>foo 2>&1); merged - in from bash-4.0-devel branch - -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document new optional increment in brace expansion - - document new zero-padded fixed-width integer brace expansion - - document new `dabbrev-expand' bindable readline command - - document new effects of `bind -x' setting and reading the values of - READLINE_LINE and READLINE_POINT - - document new |& synonym for `2>&1 |' pipeline operator - - 5/26 - ---- -parse.y - recognize new ;& and ;;& case action list terminator tokens and - implement them in the grammar, setting CASEPAT_FALLTHROUGH and - CASEPAT_TESTNEXT flags as appropriate - -print_cmd.c - - print new ;& and ;;& case clause action list terminators as - appropriate - -execute_cmd.c - - implement new case clause action list terminators: - ;& - fall through to actions associated with next pattern list - ;;& - fall through to tests in next pattern list - -doc/{bash.1,bashref.texi} - - document new ;& and ;;& case clause action list terminators - - 5/28 - ---- -jobs.c - - change waitchld so it treats SIGCHLD like SIGINT if `wait' is being - executed, and allows wait to jump out before running any trap set - on SIGCHLD. Fixes debian bug #483016 reported by Miroslav Rudisin - - - run_sigchld_trap is no longer static, so the trap code in trap.c - can call it - - change run_sigchld_trap to call set_impossible_sigchld_trap instead - of just using a call to restore_default_signal - -jobs.h - - new extern declaration for run_sigchld_trap - -trap.c - - fix run_pending_traps to run a SIGCHLD trap if the trap handler isn't - set to IMPOSSIBLE_TRAP_HANDLER - - in trap_handler, don't reset the SIGCHLD trap handler to trap_handler - if MUST_REINSTALL_SIGHANDLERS is defined - - new function, set_impossible_sigchld_handler, sets the trap string - associated with SIGCHLD to IMPOSSIBLE_TRAP_HANDLER; used as a sentinel - by run_sigchld_trap and maybe_set_sigchld_handler - - change maybe_set_sigchld_handler to set the SIGCHLD trap string only - if the current value is IMPOSSIBLE_TRAP_HANDLER. This ensures that - any traps on SIGCHLD set in a SIGCHLD handler will persist. Fixes - debian bug #483016 reported by Miroslav Rudisin - - -trap.h - - new extern declaration for set_impossible_sigchld_trap - - 5/31 - ---- -parse.y - - new function: parse_comsub(), parses $(...) by parsing command - between parens and making sure the next token is `)'. From - the bash-4.0-devel branch - - new function: xparse_dolparen, helper function for parsing - command substitutions in $(...). Called from subst.c to extract - a command substitution during word expansion. From bash-4.0-devel - branch - - new function: rewind_input_stream(). Rewinds bash_input.location.string - back to where it was before the shell parsed a $() command - substitution. From bash-4.0-devel branch - - changes to parse_matched_pair to combine most of the flag variables - (was_dollar, in_comment, and so on) into a local flags word - - 6/2 - --- -parse.y - - call trim_pathname, which retains only the last $PROMPT_DIRTRIM - directories and replaces the intervening characters with `...', - when expanding \w and \W - -doc/{bash.1,bashref.texi} - - document the effect of setting PROMPT_DIRTRIM - - 6/3 - --- -builtins/ulimit.def - - make the multiplier (block size) for -c and -f 512 bytes only if in - Posix mode and 1024 bytes otherwise (as in previous versions). Uses - POSIXBLK and BLOCK_SIZE defines to parameterize size based on value - of posixly_correct - -doc/bashref.texi - - document this addition to posix mode - -builtins/common.c - - change get_numeric_arg to have a calling sequence and return value - more closely mimicking general.c:legal_number(), with the addition - of a flags word - - add extra value for `fatal' argument to get_numeric_arg to force it - to return failure to the caller rather than longjmping - -builtins/common.h - - change prototype declaration for get_numeric_arg - -builtins/{break,shift}.def - - change calls to get_numeric_arg to deal with new semantics and calling - sequence - -builtins/history.def - - display_history now returns an int - - change calling sequence for get_numeric_arg in display_history - - display_history now returns failure to the caller if get_numeric_arg - detects an invalid number, rather than jumping back to the top level - - use value returned by display_history as return status of history - builtin, filtered through sh_chkwrite - - history no longer aborts compound commands on invalid arguments. - fixes problem reported by Chu Li - -{braces,subst}.c - - extract_command_subst now takes a third flags argument; passed flags - are ORd into flags passed to other functions; changed callers - -subst.h - - move SX_* defines here from subst.c so parse.y:xparse_dolparen can - see them and behave appropriately - - extract_command_subst now takes a third flags argument; change - prototype - -subst.c - - change extract_command_subst to call xparse_dolparen when extracting - a $() construct - - change calls to extract_delimited_string to extract_command_subst - as appropriate - - if command_substitute returns a NULL word desc, don't call - dispose_word_desc on it - -parse.y - - change xparse_dolparen to use the SX_* flags now in subst.h - - 6/16 - ---- -subst.c - - in quote_list, set W_HASQUOTEDNULL flag in the word if quote_string - turns "" into CTLNUL - - in dequote_list, turn off W_HASQUOTEDNULL flag in the word if - dequote_string turns CTLNUL into "" - - new function, string_list_pos_params, encapsulates everything - needed to turn the positional parameters or an array indexed with - '@' or '*' into a string, including taking care of quoting and - using the first char of $IFS, when used in another expansion like - pattern removal or pattern substitution - - change list_remove_pattern, pos_params, pos_params_pat_subst to - call string_list_pos_params. Fixes problems reported by - Stephane Chazelas - - 6/22 - ---- -variables.h - - include assoc.h for associative arrays - - defines for case-modifying expansions and associative array variables - - sh_var_assign_func_t functions now take an extra char * parameter - - 6/25 - ---- -variables.c - - change declarations and definitions of sh_var_assign_func_t functions - to add the extra char * parameter: null_assign, null_array_assign, - assign_seconds, assign_random, assign_lineno, assign_subshell, - assign_dirstack - - change calls to var->assign_func to add extra char * argument - - broke part of body of dispose_variable out into a new function, - dispose_variable_value, which knows how to free all kinds of shell - variable data - - changes to deal with variables with the internal `nofree' attribute - -arrayfunc.c - - change calls to var->assign_func to add extra char * argument - - bind_array_var_internal now takes an extra `char *key' argument - - additions for associative array implementation; from bash-4.0-devel - tree - -arrayfunc.[ch],subst.c - - expand_compound_array_assignment now takes the variable as the first - argument (SHELL_VAR *); changed function definition and callers - -builtins/set.def - - changes to handle associative arrays in `unset' - -{execute_cmd,command}.h - - definitions for coproc implementation; from bash-4.0-devel tree - -variables.c - - new functions for associative arrays: make_new_assoc_variable, - make_local_assoc_variable - - 6/26 - ---- -variables.c - - more infrastructure for associative arrays; from bash-4.0-devel tree - - infrastructure for handling assignments to variables with - case-modifying attributes; from bash-4.0-devel tree - -config.h.in - - add #defines controlling case-modifying variable attributes and word - expansions - -configure.in - - add enable options for case-modifying variable attributes and word - expansions (--enable-casemod-attributes and --enable-casemod-expansions, - respectively); from bash-4.0-devel tree - -execute_cmd.c - - add code to fix_assignment_words to handle assignment statements to - "assignment builtins" that seem to be associative arrays. Imperfect - -subst.c - - array_remove_pattern now takes a SHELL_VAR * as its first argument - instead of an ARRAY *; from the bash-4.0-devel tree - - changes to array_length_reference for associative arrays; from the - bash-4.0-devel tree - - changes to get_var_and_type for associative arrays; from the - bash-4.0-devel tree - - changes to parameter_brace_substring for associative arrays; from the - bash-4.0-devel tree - - changes to param_expand for associative arrays; from the - bash-4.0-devel tree - -builtins/declare.def - - changes for associative arrays: new `-A' option, changes to make - local and global associative array variables; from the bash-4.0-devel - tree - - 6/27 - ---- -execute_cmd.c - - in execute_command_internal, when short-circuiting execution - because `breaking' or `continuing' is non-zero, preserve the exit - status by returning `last_command_exit_value' instead of an - unconditional EXECUTION_SUCCESS. Fixes bug reported by Roman - Rakus - - 6/28 - ---- -variables.c - - fix get_var_and_type to appropriately handle references like - ${varname[0]}, where `varname' is a scalar variable - -make_cmd.[ch],parse.y - - make_here_document now takes a second argument: the current line - number; changed caller (gather_here_documents) - -builtins/setattr.def - - added support for associative arrays and the `-A' variable attribute - option; from the bash-4.0-devel tree - -subst.c - - change code that transforms `declare -A xxx=(yyy)' to perform the - internal `declare -A xxx' before doing the variable assignment, - because associative arrays have to be declared before being assigned - to as such; uses new function make_internal_declare - - 6/30 - ---- -subst.[ch] - - dequote_escapes is now external; add declaration in subst.h - - remove_quoted_nulls is now external; add declaration in subst.h - -array.[ch] - - new functions for completeness: array_dequote, array_dequote_escapes, - array_remove_quoted_nulls - - array_subrange now calls array_remove_quoted_nulls for "${array[*]}". - Fixes bug reported by Vitor De Araujo - - array_patsub now calls array_remove_quoted_nulls for "${array[*]}" - - array_modcase now calls array_remove_quoted_nulls for "${array[*]}" - - array_patsub now handles the mflags&MATCH_QUOTED case appropriately - (that implies "${array[@]}") - -subst.c - - new functions for case-modifying word expansion suppport: - pos_params_casemod, parameter_brace_casemod; from bash-4.0-devel branch - -assoc.c - - new functions for completeness: assoc_remove_quoted_nulls - - assoc_patsub now calls assoc_remove_quoted_nulls for "${assoc[*]}" - - assoc_modcase now calls assoc_remove_quoted_nulls for "${array[*]}" - - assoc_patsub now handles the mflags&MATCH_QUOTED case appropriately - (that implies "${assoc[@]}") - - 7/1 - --- -assoc.[ch] - - new function, assoc_subrange: takes a hash table, converts it to a - word list, and performs the subrange and indexing on that list - - new functions for completeness: assoc_dequote, assoc_dequote_escapes - -subst.c - - verify_substring_values now takes the variable SHELL_VAR * as its - new first argument; changed callers - - change verify_substring_values to handle associative arrays using the - number of elements as the upper bound - - brought in code to do case-modifying word expansions from - bash-4.0-devel branch, conditional on CASEMOD_EXPANSIONS - -input.c - - if the read(2) in getc_with_restart returns -1/EAGAIN, turn off - non-blocking mode on the file descriptor and try again. Fixes - problem reported by Glynn Clements - - 7/2 - --- -doc/{bash.1,bashref.texi} - - documented new case-modifying word expansions - -make_cmd.c - - change make_here_document to display a warning message including the - start line of a here document if it ends up delimited by EOF. - Addresses issue raised by Richard Neill - -subst.c - - in do_assignment_internal, make sure the `invisible' attribute is - unset before returning success - - 7/3 - --- -config-top.h - - add `CASEMOD_CAPCASE' define to include or exclude the ~[~] word - expansion and the `capcase' variable attribute (declare -c) - -builtins/declare.def - - add support for manipulating the case-modifying attributes (new - declare -clu); from bash-4.0-devel branch - -builtins/setattr.def - - add support for reporting case-modifying attributes (-clu attributes); - from bash-4.0-devel branch - -doc/{bash.1,bashref.texi} - - specify that the read builtin timing out results in a return value - greater than 128 - - document new `-l' and `-u' options to declare/typeset/local. Leave - `-c' undocumented for now - - 7/4 - --- -make_cmd.[ch] - - make_coproc_command: construct a coproc; from bash-4.0-devel tree - -dispose_cmd.c - - dispose coproc command; from bash-4.0-devel tree - -copy_cmd.c - - copy a coproc command; from bash-4.0-devel tree - -print_cmd.c - - print a coproc command; from bash-4.0-devel tree - -shell.c - - dispoe the current coproc on shell exit; from bash-4.0-devel tree - -redir.c - - when closing redirects as part of user redirections, check whether - or not active coprocess fds are being closed and close the coproc - if so; from bash-4.0-devel tree - -config.h.in - - add define for COPROCESS_SUPPORT to include coprocesses - -configure.in - - add support for configuring coprocesses into and out of the build - -jobs.c - - in waitchld, check whether or not a coproc processs has exited; - from the bash-4.0-devel tree - - 7/5 - --- -doc/bashref.texi - - document new --enable-coprocesses option that includes coprocess - support - -execute_cmd.c - - add functions for coprocess support, including execute_coproc and - code to call it when command->type == cm_coproc; from - bash-4.0-devel tree - -lib/sh/fdprintf.c - - new library function fdprintf(int fd, const char *format, ...); - printf to a file descriptor - -{configure,config.h}.in - - support for detecting fdprintf and compiling in replacement - -Makefile.in,lib/sh/Makefile.in - - add rules to include fdprintf.o - -doc/{bash.1,bashref.texi} - - documented coprocesses and `coproc' reserved word - - 7/7 - --- -subst.c - - fix array_length_reference to use MB_STRLEN instead of STRLEN, so - multibyte characters in array values are computed correctly. Fixes - bug reported by Wang Xin - - 7/10 - ---- -jobs.c - - new function, maybe_give_terminal_to (old, new, flags), sets the - terminal pgrp to NEW if and only if it's currently set to OLD - - call maybe_give_terminal_to when the parent sets the terminal pgrp - to the pipeline pgrp in stop_pipeline, so we don't give the - terminal to the new job's pgrp unless it's currently owned by the - shell. Fixes race condition described by Joe Peterson - , where parent bash may change tty pgrp after a - grandchild (interactive bash child of su) has changed it to - something else. The call to maybe_give_terminal_to makes explicit - a previously-implicit assumption - -aclocal.m4 - - remove dependency on writable /tmp by creating directories in - build directory - -shell.c - - make changes to how bash sets no_line_editing and running_under_emacs - to deal with various emacs terminal emulators; use better check - for `eterm', since bash sends $PWD to eterm with control sequences - that confuse other programs. Problem reported by Micah Cowan - - - - 7/12 - ---- -print_cmd.c - - break code that prints here-documents into two functions: - print_heredoc_header, which prints the operator and delimiter, and - print_heredoc_body, which prints the body text and closing delimiter - - change print_redirection to call print_heredoc_{header,body} - - sentinel variable, printing_connection, used when printing a command - of type `connection' (|, &&, ||, etc.) - - change print_redirection_list to save any here documents it finds - while printing a connection and save them in `deferred_heredocs' - - new function, print_deferred_heredocs, called from print_redirection - in the cm_connection case, calls print_heredoc_header for all the - here documents, then prints the operator (|, &&, ||, etc.), then - the here-document body. This preserves syntactic correctness; the - old code printed the control operator after the body of the here - document. Fixes bug reported by - - 7/16 - ---- -locale.c - - in set_locale_var, print a warning message if setlocale() fails any - time it's called -- required some code restructuring - - 7/19 - ---- -support/shobj-conf - - support for mingw32, contributed by Carlo Bramix - - - 7/23 - ---- -execute_cmd.c - - added support (currently unused) to manage a list of coprocs - - 7/25 - ---- -bashline.c - - add extern declarations for literal_history and force_append_history - -builtins/shopt.def - - include "bashhist.h" instead of having extern declarations for the - appropriate history variables - -parser.h - - new parser_state value: PST_HEREDOC, set when reading body of here- - document in parse.y:read_secondary_line - -parse.y - - set PST_HEREDOC bit in parser_state when reading a secondary line - for the body of a here-document - - change read_secondary_line to save lines in the body of a here- - document in the shell history list if remember_on_history is - set. Fixes bug reported by Gene Golub - - 8/4 - --- -configure.in - - changed to 4.0-alpha - -lib/readline/readline.h - - changed constants to reflect readline-6.0 version - - 8/11 - ---- -lib/readline/signals.c - - make sure we don't use SIGWINCH without checking whether or not it's - defined. Fix from Pedro Alves - - 8/12 - ---- - -COPYING - - updated to GPLv3; edits in every file with a copyright or license - declaration to update to gpl3 - -version.c - - update extended version info to latest gnu standard - - 8/17 - ---- -subst.c - - change exp_jump_to_top_level to only call top_level_cleanup if - parse_and_execute_level is 0. If it's not, the longjmp to - parse_and_execute will run the unwind-protect stack. Fixes bug - most recently reported by Roman Rakus - - 8/18 - ---- -support/config.{guess,sub} - - updated to newer versions from autoconf-2.62 distribution - - 8/20 - ---- -subst.c - - fixed parameter_brace_substring to differentiate between indexed and - associative arrays when computing second offset, instead of - assuming indexed array - - 8/21 - ---- -support/xcase.c - - simple program to convert input from lower to uppercase and vice - versa. Now used by coproc test suite, since `tr -u' is not - portable. - - 8/22 - ---- -doc/bash.1 - - fixed description of the bindable edit-and-execute commands to note - they check $VISUAL first, instead of $FCEDIT. Fixed bug reported - by - -[bash-4.0-alpha frozen] - - 8/28 - ---- -[bash-4.0-alpha released] - - 9/1 - --- -builtins/evalstring.c - - fixed typo in parse_string (ostring used uninitialized). Bug - reported by Andreas Schwab - -subst.c - - fix return value of parameter_brace_expand to set the - W_HASQUOTEDNULL flag in the returned WORD_DESC * if the return value - from parameter_brace_remove_pattern is a quoted null string. Fixes - bug reported by Andreas Schwab - - set the W_HASQUOTEDNULL flag in the return value from - parameter_brace_expand if the return value from parameter_brace_patsub - is a quoted null string - - 9/6 - --- -builtins/read.def - - change read -t 0 to return success if there is input available to be - read -- allows scripts to poll for input. Uses input_avail libsh - function - - 9/9 - --- -externs.h - - fix extern fpurge declaration -- use HAVE_DECL_FPURGE instead of - NEED_FPURGE_DECL, since the former is set by `configure' - -jobs.h - - add extern declaration for close_pgrp_pipe - - add a new job state JNONE (-1) to the enum - -jobs.c - - include execute_cmd.h for extern declarations for coproc functions - -subst.c - - include builtins/builtext.h for extern declarations for functions - implementing builtins (e.g., declare_builtin) - -arrayfunc.c - - include "pathexp.h" for extern declaration for glob_char_p - -braces.c - - add extern declaration for `asprintf' - -lib/readline/rlprivate.h - - add extern declarations for _rl_trace, _rl_tropen - -lib/sh/zgetline.c - - add extern declarations for zread, zreadc - -lib/sh/mktime.c - - include "bashansi.h" for string function declarations - -builtins/common.h - - add extern declaration for parse_string - -trap.c - - include jobs.h for extern declaration for run_sigchld_trap - -general.c - - fix call to strtoimax in legal_number; if ep == string when function - returns, the number was not converted, even if errno is not set. - Fix from Paul Jarc - - 9/11 - ---- -[prayers for the victims of 9/11/2001] - -builtins/return.def - - call no_options, as Posix requires. This also has the effect of - disallowing negative return values unless they're prefixed by `--' - - 9/13 - ---- -builtins/bind.def - - add an error message when bind is used without line editing active, - instead of just returning an error status - -variables.c - - make sure make_local_variable never creates visible variables with - a value, whether or not a variable with the same name existed in a - previous context. This is consistent with ksh93. Fix from - - - 9/16 - ---- -execute_cmd.c - - add call to CHECK_TERMSIG in shell_execve after the call to execve - returns. Recommended by Roman Rakus - - add QUIT check in execute_connection after executing first command - in a `&' connection - - 9/22 - ---- -execute_cmd.c - - new semaphore variable, executing_list, incremented every time a - list (command1;command2 or command1 || command2 or command1 && - command2) is executed; used as sentinel for rest of shell - -sig.c,builtins/evalstring.c - - set executing_list to 0 when throwing execution back to top level; - make sure to unwind-protect it in appropriate places - -jobs.c - - if a pipeline is killed by SIGINT while executing a list (when - executing_list is non-zero), make sure the shell acts as if an - interrupt occurred. The behavior is dependent on the shell - compatibility level being > 32 (bash-4.0 and above) - - 9/23 - ---- -redir.c - - don't bother reporting an error with a file descriptor, even if - the errno is EBADF, if the redirection error (e.g., NOCLOBBER) - can't have anything to do with the fd. Fixes bug reported by - "David A. Harding" , debian bug #499633. - - 9/24 - ---- -builtins/declare.def - - make `declare [option] var' (and the `typeset' equivalent) create - invisible variables, instead of assigning the null string to a - visible variable. Fixes bug reported by Bernd Eggink - - 9/25 - ---- -builtins/common.[ch] - - new function, builtin_warning(), like builtin_error but for warning - messages - -builtins/bind.def - - experimental: print a warning, but go on, if line editing not active - when bind is invoked. Suggested by Rocky Bernstein - - - 10/3 - ---- -test.c - - use same_file instead of directly comparing st_dev and st_ino when - comparing files in filecomp(). From mingw32 patches submitted - by Hector Chu - - 10/4 - ---- - -redir.c - - in redirection_error(), use `error' instead of errno when comparing - against EBADF. From mingw32 patches submitted by Hector Chu - - -shell.c - - in unset_bash_input(), reset bash_input.type to st_none after - closing the default buffered fd. From mingw32 patches submitted - by Hector Chu - -builtins/cd.def - - ignore CDPATH when in privileged mode. Suggested by Paul Jarc - - -variables.c - - change sv_globignore to only act if privileged mode is not enabled. - Suggested by Paul Jarc - -doc/bash.1,bashref.texi - - document new treatment of CDPATH and GLOBIGNORE when privileged - mode is enabled - -builtins/read.def - - change prompt printing to occur after terminal is set to no-echo - mode. Based on suggestion from Stephane Chazelas - - -lib/readline/signals.c - - new variables to keep track of special characters corresponding to - SIGINT, SIGQUIT, and SIGTSTP - - new variable to keep track of whether tty is echoing control - characters corresponding to SIGINT, SIGQUIT, and SIGTSTP - - new function, _rl_echo_signal_char(int sig) to display the tty - special char generating SIGINT, SIGQUIT, or SIGTSTP. Based on - idea and code from Joe Peterson - - call rl_echo_signal_char in rl_signal_handler: if the terminal - settings indicate it, readline will echo characters that generate - keyboard signals - -lib/readline/rltty.c - - set _rl_intr_char, _rl_quit_char, and _rl_susp_char to special - characters that generate signals from keyboard - - set _rl_echoctl if ECHOCTL tty flag is set - -lib/readline/rlprivate.h - - extern declarations for _rl_intr_char, _rl_quit_char, and - _rl_susp_char - - extern declaration for _rl_echoctl - -lib/readline/readline.h - - extern declaration for rl_echo_signal_char() - -lib/readline/doc/rltech.texi - - document rl_echo_signal_handler(): available for applications - that install their own signal handlers - - 10/5 - ---- -execute_cmd.c - - fix errexit logic to not cause the shell to exit when a command in - a pipeline fails. Fixes bug reported by Marcin Owsiany - - - 10/14 - ----- -builtins/evalstring.c - - don't short-circuit execution in parse_and_execute if we want to - run an exit trap. Fixes bug reported by Steffen Kiess - - - 10/18 - ----- -parse.y - - fix error production to only call YYACCEPT if the shell is currently - interactive and not in parse_and_execute (so parser errors in - things like eval will correctly set $?). Fixes bug reported by - marco-oweber@gmx.de - -execute_cmd.c - - make sure variable name errors in execute_for_command and non- - identifier function names in execute_intern_function set the - return status to EX_BADUSAGE (2), not EX_USAGE (258) - -parser.h - - new parser state, PST_REPARSE - -parse.y - - turn PST_REPARSE on in parse_string_to_word_list - - in parse_matched_pair, if parsing a single-quoted string and - PST_REPARSE is set, don't requote CTLESC or CTLNUL. Fixes bug with - compound array assignment using $'\x7f' reported by Antonio Macchi - - - 10/23 - ----- -configure.in - - define LOCAL_LDFLAGS as `-z interpose' on Solaris 8, 9, and 10 to - allow the bash malloc to interpose the libc malloc when called by - library functions pre-bound to the libc malloc. Suggested by - Serge Dussud - - 10/26 - ----- -doc/bash.1 - - add single-sentence descriptions to rest of parameter expansions. - Suggested by Ken Irving - - 10/27 - ----- -subst.c - - rearrange code in skip_to_delims to allow quote characters and other - shell expansion characters to be delimiters - - add new flags value for inverting search: skip to the next character - NOT in the set of delimiters passed as an argument - -subst.h - - define for new SD_INVERT flag value for skip_to_delims - - 10/28 - ----- -bashline.c - - new bindable functions: shell-forward-word and shell-backward-word. - Like forward-word and backward-word, but understand shell quoting - and use shell metacharacters and whitespace as delimiters. - Suggested by Andre Majorel - - new bindable functions: shell-kill-word and shell-backward-kill-word. - Like kill-word and backward-kill-word, but understand shell quoting - and use shell metacharacters and whitespace as delimiters. - Suggested by Andre Majorel - -doc/bash.1,lib/readline/doc/rluser.texi - - documented shell-forward-word and shell-backward-word - - documented shell-kill-word and shell-backward-kill-word - - 11/1 - ---- -redir.c - - add extra argument to add_undo_redirect: fdbase. FD used to save - a file descriptor must be > fdbase if fdbase >= SHELL_FD_BASE. A - value of -1 for fdbase means to just use SHELL_FD_BASE. Fixes bug - with 0<&10 reported by Clark Jian Wang - - 11/5 - ---- -unwind_prot.c - - new function: have_unwind_protects(); returns 1 if unwind_protect_list - is not empty - -unwind_prot.h - - extern declaration for have_unwind_protects - -builtins/evalstring.c - - in parse_and_execute_cleanup, make sure that we don't call - run_unwind_frame and expect it to decrement parse_and_execute_level - if there's no unwind_protect_list, since there's a while loop in - throw_to_top_level that calls parse_and_execute_cleanup as long as - parse_and_execute_level is non-zero - - 11/9 - ---- -variables.c - - fix the assign function for COMP_WORDBREAKS to allocate new memory - to store as the variable's value, to avoid freeing memory twice - if the variable is unset after rl_completer_word_break_characters - is freed and reallocated. Fix from Mike Stroyan - - 11/20 - ----- -general.c - - new 'file_exists(fn)' primitive; just calls stat(2) - -general.h - - new extern declaration for file_exists - -bashline.c - - add `~' to rl_filename_quote_characters so make_quoted_replacement - will call bash_quote_filename for words containing `~'. Then - bash_quote_filename can make choices based on that - - change quote_word_break_chars to backslash-quote the tilde in a - filename with a leading tilde that exists in the current directory, - since we want to inhibit tilde expansion in this case - -execute_cmd.c - - call file_isdir from shell_execve instead of stat(2) directly - -bashhist.c - - use file_exists and file_isdir primitives instead of calling stat - - 11/21 - ----- -redir.c - - When undoing saving of non-standard file descriptors (>=3) using - file descriptors >= SHELL_FD_BASE, we set the saving fd to be - close-on-exec and use a flag (RX_SAVCLEXEC) to decide how to set - close-on-exec when the fd is restored. Set flag in add_undo_redirect, - check in do_redirection_internal. Fixes problem reported by Andreas - Schwab - - 11/26 - ----- -subst.c - - fix param_expand to have expansions of $@ and $* exit the shell if - there are no positional parameters and `set -u' is enabled. Fixes - bug reported by Dan Jacobson - - 11/27 - ----- -lib/readline/display.c - - fix update_line to not call space_to_eol if current cursor position - (_rl_last_c_pos) indicates that we're already at end of line. - Partial fix for bug reported by Mike Frysinger - - in update_line, don't call insert_some_chars if that will start - before the last invisible character in the prompt string and not - draw the entire prompt string. More of the partial fix for bug - reported by Mike Frysinger - - fix update_line to adjust _rl_last_c_pos by wrap_offset when adding - characters beginning before the last invisible character in the - prompt. New code is same as previously existed in a different code - path. Rest of fix for bug from Mike Frysinger - - fix assignment of newline breaks (inv_lbreaks) to correctly account - for prompts longer than two screen lines containing invisible - characters. The assumption is that part of the invisible characters - are on the first line (prompt_invis_chars_first_line) and the - remainder are on the last (wrap_offset - prompt_invis_chars_first_line). - Fix is in rl_redisplay. part of fix for bug reported by - "Wesley J. Landaker" in - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=265182 - [TENTATIVE] - - fix _rl_move_cursor_relative to correctly offset `dpos' by `woff' - when there are invisible characters on lines after the second by - using (_rl_screenwidth*_rl_last_v_pos) when seeing whether or not - we just wrote some invisible characters. Rest of fix for bug - reported in http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=265182 - [TENTATIVE] - - 12/11 - ----- -sig.c - - reset the execution context before running the exit trap in - termsig_handler - -general.c - - set and unset terminate_immediately like interrupt_immediately in - bash_tilde_expand - -builtins/read.def - - change terminate_immediately to a counter instead of a flag, as - interrupt_immediately is used - -lib/readline/display.c - - slight change to fix from 11/27 to deal with prompts longer than a - screen line where the invisible characters all appear after the - line wrap. Fixes bug reported by Andreas Schwab - -builtins/{echo,printf}.def - - increment terminate_immediately at entry; decrement before returning. - Fix for bug reported by Ralf.Wildenhues@gmx.de - - 12/16 - ----- -subst.c - - fix off-by-one error in /dev/fd version of add_fifo_list; make - sure we add to totfds when it is == fd, not just when fd > totfds. - Fixes bug reported by marciso@gmail.com - -[bash-4.0-beta2 frozen] - - 12/29 - ----- -doc/{bash.1,bashref.texi} - - document more clearly that when not in Posix mode, command - substitution does not inherit the -e option. From bug report from - Freddy Vulto - -{execute_cmd,sig,builtins/evalstring}.c - - sentinel variable to keep track of whether or not we're supposed to - ignore the failure status of a command executed in a command - substitution even if the `-e' option is set: comsub_ignore_return - - increment and decrement comsub_ignore_return in execute_simple_command - before calling expand_words - - in parse_and_execute, if comsub_ignore_return is non-zero and the - SUBSHELL_COMSUB bit is set in subshell_environment, enable the - CMD_IGNORE_RETURN flag in every command executed from the passed - string. Fixes problem reported by Freddy Vulto - - make sure to reset comsub_ignore_return every time we throw to the - top level, like executing_list flag - - 1/2/2009 - -------- -parse.y - - fix to rewind_input_stream to handle case of $(...) command - substitution followed by a quoted literal newline. Report and fix - from Andreas Schwab - - 1/7 - --- - -subst.c - - fix match_wpattern and match_upattern to prefix a `*' to the - pattern even if it starts with a `*(' (if extglob is enabled) - before checking whether or not it can match anywhere in the - string. Fixes bug reported by os@sernet.de. - -[bash-4.0-rc1 frozen] - - 1/9 - --- -locale.c - - since setlocale() doesn't set errno to anything meaningful, - don't include the strerror() result in the error message if - it fails - - make sure the error messages printed when setlocale fails are - localizable - - 1/11 - ---- -lib/readline/histexpand.c - - make sure that every time history_no_expand_chars is tested, we - also call the history_inhibit_expansion_function if it's set. - Fixes bug reported by Yang Zhang - - 1/12 - ---- -trap.c - - make sure to call parse_and_execute with the SEVAL_RESETLINE bit - set in the flags so it will reset the line number when running - the trap commands. Partial fix for bug reported by - peter360@fastmail.us - - 1/14 - ---- -builtins/reserved.def - - document `coproc' so it can be used with `help' builtin. Pointed - out by Pierre Gaston - -lib/sh/casemod.c - - added two new flags: CASE_UPFIRST and CASE_LOWFIRST to casemod - the first character of the passed string and pass the rest - through unchanged. Fixes bug reported by Jan Schampera - - -externs.h - - new defines for CASE_UPFIRST and CASE_LOWFIRST - -subst.c - - use CASE_UPFIRST for ^ and CASE_LOWFIRST for , casemod operators - -builtins/mapfile.def - - call zreset() before calling first zgetline(), to clean out any - remaining data in local buffer used by zreadc. Fixes bug - reported by Pierre Gaston - - 1/15 - ---- -lib/sh/zread.c - - renamed zreadintr to zreadretry -- not perfect, but better - - new functions: zreadintr, which just calls read so it can be - interruptible, and zreadcintr, which is like zreadc but uses - zreadintr to fill the buffer - -lib/sh/zgetline.c - - in zgetline, when zread/zreadc return <= 0, make sure line is - non-null before assigning to line[nr] - -builtins/mapfile.def - - return an error right away if the supplied array variable name - refers to a readonly or noassign array - - set interrupt_immediately so calls to zgetline can be - interrupted. Fixes bug reported by Pierre Gaston - - - if interactive, pass the SEVAL_INTERACT and SEVAL_NOHIST flags - to parse_and_execute when calling callbacks. Fixes bug reported - by Pierre Gaston - - add `readarray' as a synonym for mapfile - -doc/{bash.1,bashref.texi} - - document behavior of mapfile builtin adding index of array element - to be assigned as additional argument to callback string. Reported - by Pierre Gaston - - document readarray as synonym for mapfile - -builtins/common.c - - new error function, sh_ttyerror(set), prints an error message having - to do with setting or getting terminal attributes - -builtins/read.def - - print error message if read fails to set terminal attributes - - 1/16 - ---- -execute_cmd.c - - new function, coproc_reap, calls coproc_dispose if sh_coproc is - marked as COPROC_DEAD - - new function, cpl_reap, disposes coprocs marked as COPROC_DEAD - from coproc list - - change coproc_pidchk to just mark the coproc as dead instead of - calling coproc_dispose, so we don't call unsafe functions from - a signal handler. Fixes bug reported by Andreas Schwab - - -execute_cmd.h - - new extern declaration for coproc_reap - -command.h - - new flags for c_flags member of a struct coproc - -{jobs,nojobs}.c - - add call to coproc_reap in cleanup_dead_jobs, which will do the - right queueing or blocking of SIGCHLD - -trap.c - - modify change from 1/12 to not reset the line number when running - the DEBUG and RETURN traps - - 1/18 - ---- -lib/sh/casemod.c - - change default operations to work on entire passed string instead - of breaking into words at non-alpha-numerics. Use new - CASE_USEWORDS flag to enable by-word behavior. Fixes bug reported - by Jan Schampera - -builtins/printf.def - - in vbprintf, bracket each call to vsnprintf (which uses the args - passed to vbprintf) with SH_VA_START and va_end, so we can - reninitialize the argument list for each call. This is actually - what the C standard requires. Fixes bug that caused printf -b - to `ignore' first % format specifier if it came first in the - string. Reported by David Leverton - -builtins/mapfile.def - - start the line count at 1, since it doesn't get incremented before - (or after) reading the first line, so things like - `mapfile -n 5 -c 1 -C 'echo foo' array < file' work right and call - the callback after the first line is read. Fixes bug reported by - Pierre Gaston - - 1/22 - ---- -lib/readline/complete.c - - set _rl_interrupt_immediately non-zero before reading from the file - system or calling an application-defined completion function - -lib/readline/signals.c - - renamed rl_signal_handler to _rl_handle_signal; new version of - rl_signal_handler that just calls _rl_handle_signal (for now) - - new function _rl_signal_handler that calls _rl_handle_signal without - any checking - -lib/readline/rlprivate.h - - new extern declaration for _rl_signal_handler - - new define, RL_CHECK_SIGNALS, checks whether or not _rl_caught_signal - is set and calls _rl_signal_handler if so - -lib/readline/{bind,input,readline}.c - - add RL_CHECK_SIGNALS in appropriate places - -lib/readline/signals.c - - change rl_signal_handler to set a flag and return rather than - run through the entire signal handling process. If - _rl_interrupt_immediately is set, call the signal handling code - right away instead of setting the flag. Initial fix for crash - bug reported by Roman Rakus - -aclocal.m4 - - new macro, BASH_TYPE_SIG_ATOMIC_T, tests for sig_atomic_t in - , defines as int if not defined - -configure.in - - call BASH_TYPE_SIG_ATOMIC_T - - call AC_C_VOLATILE - -config.h.in - - empty define for sig_atomic_t - - empty define for volatile - - 1/27 - ---- -subst.c - - audit calls to add_character and change to add_ifs_character (which - quotes characters in $IFS). Affects primarily `:', `=', and `~'. - Fixes bug reported by Jan Schampera ; fix - suggested by Stephane Chazelas - - 2/1 - --- -configure.in - - call AC_C_RESTRICT - -config.h.in - - add empty defintion for `restrict' - -pcomplete.c - - use unwind_protects around call to execute_shell_function in - gen_shell_function_matches to prevent data corruption if - throw_to_top_level is called. Bug report and fix from - werner@suse.de. - -execute_cmd.c - - don't clamp CPU usage at 100% in print_formatted_time. Bug reported - by Linda Walsh - - 2/5 - --- -locale.c - - in set_locale_var, set errno to 0 before calling setlocale(), and - print strerror (errno) if setlocale fails and errno ends up non-zero - - 2/6 - --- -configure.in - - backed out of solaris change from 10/23/2008 (adding `-z interpose' - to LDFLAGS) due to solaris updates to fix a linker problem. - Updatted by Serge Dussud - - 2/12 - ---- -execute_cmd.c - - change execute_connection so failure of a pipeline will cause the - shell to exit if -e is on. From discussion on austin-group - mailing list - - change execute_command_internal so failure of a user-specified - subshell will cause the shell to exit if -e is on. From discussion - on austin-group mailing list - - 2/13 - ---- -doc/{bash.1,bashref.texi} - - clarified description of set -e option to accurately reflect current - implementation - - 2/19 - ---- -print_cmd.c - - fix print_deferred_heredocs to not print a space if the separator - string is null - - change print_deferred_heredocs to set `was_heredoc' after printing - something - - change connection printing code to only print the `;' separator - if we haven't just printed a here-document - - change connection printing code to print any deferred here - documents after the rhs of the connection. Fixes bug reported by - Bo Andresen - -[bash-4.0 frozen] - - 2/20 - ---- - -[bash-4.0 released] - - 2/22 - ---- - -parse.y - - fix parse_comsub to not test a character for being a possible shell - metacharacter if LEX_PASSNEXT flag is set. Fixes bug reported by - Mike Frysinger - -pcomplete.c - - add call to save_parser_state (accidentally dropped from patch) to - gen_shell_function_matches. Fixes bug with bash_completion and - file/directory completion reported by phil@Arcturus.universe - -Makefile.in - - fix assignment to LDFLAGS_FOR_BUILD to match those in subdir - Makefiles. Fixes bug reported by Mike Frysinger - -builtins/mapfile.def - - make sure the callback quantum (-c option argument) is > 0. Fixes - bug reported by Stephane Chazleas - - 2/23 - ---- -parse.y - - fix save_token_state and restore_token_state to save and restore - current_token. Fixes bug reported by Bernd Eggink - - -builtins/exit.def - - check jobs[i] before checking whether or not it's running when - the checkjobs option is set and we're looking for running jobs - at exit. Fixes bug reported by Mike Frysinger - - 2/24 - ---- -siglist.c - - include bashintl.h for definition of _. Fixes bug reported by - Greg Wooledge - - 2/25 - ---- -subst.c - - new function, skip_matched_pair. Similar to skip_to_delim and - the extract_XXX family - - move skipsubscript here from arrayfunc.c; re-implement in terms of - skip_matched_pair. Fixes bugs reported by - -arrayfunc.c - - remove skipsubscript; moved to subst.c - -parse.y - - change reset_parser to set current_token to '\n'. Rest of fix for - bug reported by Bernd Eggink ; earlier fix on - 2/23 - - 2/26 - ---- -builtins/declare.def - - when given something like array[x]=y (which sets making_array_special - to 1), don't convert an associative array to an indexed array (line - 493). Part of fix for bug reported by Pierre Gaston - - - if offset == 0, indicating that we do not have a valid assignment, - make sure any `name' containing a `[' is a valid array reference - before trying to go on. Not doing this leads to creating crazy - variables like `name[foo[bar]=bax'. Rest of fix for bug reported - by Pierre Gaston - -assoc.c - - change assoc_to_assign to single-quote the array keys if `quoted' is - non-zero. Makes things easier to read with weird characters in the - key - -parse.y - - fix parse_comsub to not set LEX_HEREDELIM when it sees "<<<". Fixes - bug reported by Mike Frysinger - - 2/27 - ---- -parse.y - - fix report_syntax_error to set last_command_exit_value to - EX_BADUSAGE (2) instead of EX_USAGE (258), since there's nothing - that will translate that to something < 128 before reading the - next command. Partial fix for bug reported by Mike Frysinger - - -sig.c - - fix sigint_sighandler to set last_command_exit_value to sig+128 - before calling throw_to_top_level. Rest of fix for bug reported - by Mike Frysinger - -jobs.c - - if fork() fails, set last_command_exit_value to 126 before calling - throw_to_top_level - -execute_cmd.c - - defer calling unlink_fifo_list in parent branch of - execute_disk_command if we're executing in a shell function - - change execute_function to call unlink_fifo_list before returning - if it's the top-level function - - 3/2 - --- -builtins/read.def - - if read times out, make sure we remove the top element from the - unwind-protect stack (the free of input_string) and run the rest, - to reset the tty and readline and alarm states. Then we jump to - assigning the variables to any partial input. Fixes bug reported - by Christopher F. A. Johnson - - 3/3 - --- -parse.y - - break comment checking code into a common COMMENT_BEGIN define so - we can use it in multiple places in parse_comsub - - in parse_comsub, don't alter the LEX_RESWDOK flag if we read a - `#' and we're checking comments, even though `#' isn't a `shell break' - character. Fixes bug reported by Mike Frysinger - -braces.c - - in expand_seqterm, decrease the total length of the rhs by the length - of any (optional) increment, so we don't end up with unwanted zero - padding because the rhs length is wrong. Fixes bug reported by - Carl Albing - - 3/4 - --- -doc/{bash.1,bashref.texi} - - changes to clean up some of the language describing the effects of - terminal process groups on the ability to read from and write to - the terminal - - 3/5 - --- -support/shobj-conf - - add host_vendor to string tested in switch to handle things like - gentoo/freebsd - - beginning with version 7, FreeBSD no longer has /usr/bin/objformat - or a.out binaries and libraries. It's always ELF. Fix from - Timothy Redaelli - -parse.y - - in parse_comsub, allow comments if we are ready to read a - reserved word (tflags & LEX_RESWDOK), haven't read anything from - one yet (lex_rwlen == 0) and the current character is a '#' - - 3/6 - --- -parse.y - - new lex flag for parse_comsub: LEX_INWORD. Turn it off when - we see a shell break character; turn it on or keep it on when - not a break character. Keep track of word length (reset to 0 - when we turn on LEX_INWORD when it was off). - - don't use COMMENT_BEGIN in parse_comsub any more; test - whether or not LEX_INWORD is set and lex_wlen == 0 in addition - to tests for LEX_RESWDOK and lex_rwlen. Comments are valid - when at the start of a word - - move LEX_PASSNEXT code to the top of parse_comsub, so the rest - of the function doesn't have to check for the flag at different - places - - 3/7 - --- -parse.y - - in parse_comsub, when looking for a reserved word (LEX_RESWDOK - non-zero), and in a case statement, we can see either an esac - or a pattern list. We handle an esac separately. We should - turn off LEX_RESWDOK if we see anything but a newline, since - we'll be reading a pattern list. Other part of fix for bug - reported by Mike Frysinger (rest of fix - on 3/3) - - 3/10 - ---- -{.,lib/readline}/doc/fdl.texi - - updated to FDL version 1.3 - - 3/11 - ---- -parse.y - - when using the |& construct with a simple command preceding it, add - the implicit redirection to the simple command's redirection list, - since the redirections associated with the command struct are never - executed. Fixes bug reported by Matt Zyzik - - 3/14 - ---- -execute_cmd.c - - in execute_case_command, if ;& is used with no following pattern - list, make sure we don't reference a NULL pointer. Bug report and - fix from Clark Jian Wang - -parse.y - - make parser_state global, so other files can use it - - command_word_acceptable now returns non-zero if PST_REDIRLIST bit - set in parser_state, so we accept assignment statements and - perform alias expansion. Fix for bug reported by Vincent - Lefevre (2/24/2009) - -parser.h - - add PST_REDIRLIST flag, notes that parser is currently parsing a - redirection list preceding a simple command - -make_cmd.c - - make_simple_command now turns on PST_REDIRLIST in parser_state when - creating a new simple command - - make_simple_command turns off PST_REDIRLIST in parser_state if it - adds a non-redirection to the command it's building - - clean_simple_command turns off PST_REDIRLIST to make sure it's off - -subst.c - - new flag for param_expand: PF_IGNUNBOUND, means to not exit if the - variable is unbound even if `set -u' is enabled - - change param_expand to not call err_unboundvar if the `pflags' - argument has the PF_IGNUNBOUND bit set - - parameter_brace_expand_word now takes an extra `pflags' argument to - pass down to param_expand; changed callers - - changed call to parameter_brace_expand_word in parameter_brace_expand - to add PF_IGNUNBOUND flag so ${@:-foo} doesn't cause the shell to - exit (but ${@} does) when there are no positional parameters. Fixes - Debian bug 519165 from Dan Jacobson - -parse.y - - add code to parse_comsub to allow here-documents within command - substitutions to be delimited by the closing right paren, with the - usual warning about here documents delimited by EOF on execution. - Fixes regression from bash-3.2 noted in Red Hat bugzilla 485664 by - Ralf Corsepius - - 3/15 - ---- -subst.c - - string_list_dollar_at now checks for Q_PATQUOTE, which getpattern() - uses to denote Q_DOUBLE_QUOTES (?). Fixes a=abcd echo "${a#$*}" - when IFS= and args are `a b' as noted by Stephane Chazleas - - - param_expand now checks for Q_PATQUOTE and treats it identically - to Q_DOUBLE_QUOTES when expanding $* - - expand_word_unsplit now sets W_NOSPLIT in the flags of the word it - passes to expand_word_internal if $IFS is NULL - - expand_word_leave_quoted now sets expand_no_split_dollar_star and - the W_NOSPLIT bit in the word flags before calling - expand_word_internal if $IFS is NULL, just like expand_word_unsplit. - It is now virtually identical to expand_word_unsplit. Rest of fix for - problems reported by Stephane Chazleas - - 3/20 - ---- -trap.c - - in _run_trap_internal, don't pass SEVAL_RESETLINE as flag to - parse_and_execute if running the ERR trap (further modification - of change from 1/12) - -execute_cmd.c - - in execute_simple_command, set line_number to line_number_for_err_trap - before calling run_error_trap. Part of fix for bug reported by - Brian J. Murrell - - change other places calling run_error_trap() to set and use - line_number_for_err_trap - - 3/21 - ---- -builtins/fc.def - - Even though command substitution through parse_and_execute turns - off remember_on_history, command substitution in a shell when - set -o history has been enabled (interactive or not) should use it - in the last_hist calculation as if it were on. Same calculation - in fc_gethnum and fc_builtin. Fixes bug reported by - Ian Kelling - -sig.c - - change termsig_sighandler to terminate immediately if it gets called - twice with the same signal before termsig_handler gets called. This - fixes the `looping on SIGSEGV' phenomenon reported by Linux users. - -parse.y - - in read_secondary_line, don't try to add NULL lines to the history - list. Report and patch from Lubomir Rintel - - 3/22 - ---- -sig.c - - Augment change from 3/21 with explicit check for signals we *don't* - want this to happen for. Patch from Lubomir Rintel - - 3/28 - ---- -array.c - - in array_reference, return NULL immediately if the desired index - is larger than the maximum - - add cache of last array referenced and last array element referenced; - use in array_reference to optimize case of sequential access; - invalidated where necessary in other functions - - array_rshift needs to set max_index to 0 if the array was empty - before shifting in the new element 0 - - array_shift needs to use element_index(a->head->prev) to set the - max_index, not a simple decrement, to deal with sparse arrays - - 4/1 - --- -bashline.c - - in bash_dequote_filename, return right away after copying the - backslash if the last character in the string to be expanded - is a backslash. The old code copied an extra NUL and overwrote - the bounds checking. Fixes bug reported by Shawn Starr - https://bugzilla.redhat.com/show_bug.cgi?id=488649 - - 4/3 - --- -subst.c - - in pat_subst.c, make sure to copy one character from the input - string in the case of a null pattern match, since we substitute - on the null match and then increment past the current character. - Not doing this means that each character of the original string - is replaced because of the null matches. Fixes debian bug - reported bhy Louis-David Mitterrand - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522160 - -lib/sh/winsize.c - - incorporate contents of readline/rlwinsize.h to get all the various - system dependencies right when trying to find TIOCGWINSZ. Fixes - bug reported by Dan Price - - 4/6 - --- -doc/{bash.1,bashref.texi} - - fix description of conditional `>' and `<' to remove statement that - the comparison pays attention to the current locale -- it has - always used strcmp - -lib/glob/glob.c - - fixed a bug in glob_filename that caused glob_dir_to_array to be - called to prepend a (globbed) directory name onto the results from - glob_vector, which, if we were globbing `**', glob_vector has - already done. Effect is to have the directory name(s) on there - twice. Fixes "dir*/**" bug reported by Matt Zyzik - - - 4/8 - --- -doc/{bash.1,bashref.texi} - - fix short syntax summary of for command to reflect full bash - syntax (which is a superset of Posix syntax). Fixes bug reported - by Reuben Thomas - - 4/10 - ---- -{expr,subst}.c - - make sure last_command_exit_value is set to EXECUTION_FAILURE - before calling err_unboundvar, in case set -e is enabled and - the shell exits from there. Fixes bug reported by Freddy - Vulto and Piotr Zielinski - - - 4/11 - ---- -jobs.c - - in restore_pipeline, don't call discard_pipeline with a NULL - argument - -trap.c - - in run_debug_trap, make sure to save and restore the pipeline, - pipeline_pgrp, and state of the pipeline around running the debug - trap, then remove any job created by running the debug trap from - the jobs table when it completes. Fixes for two bugs reported - by lex@upc.ua - - 4/12 - ---- -lib/readline/signals.c - - new functions to block and release SIGWINCH like the SIGINT blocking - and releasing functions - -lib/readline/rlprivate.h - - new extern declarations for _rl_block_sigwinch and _rl_release_sigwinch - -lib/readline/display.c - - block SIGWINCH during redisplay like SIGINT. Should fix bug reported - by Nicolai Lissner - - 4/13 - ---- -lib/readline/readline.h - - new readline state variable: RL_STATE_REDISPLAYING - -lib/readline/display.c - - in rl_redisplay, don't block SIGWINCH during redisplay; just set - the REDISPLAYING state - -lib/readline/terminal.c - - in rl_resize_terminal, don't call rl_redisplay_after_sigwinch() if - we're already in the middle of redisplay (RL_STATE_REDISPLAYING). - Fix for bug reported by Nicolai Lissner - - 4/15 - ---- -parse.y - - fix parse_comsub to add check for \n when seeing whether the current - character can change to a state where a reserved word is legal, - since it is not a shell meta character. Fixes bug reported by - Bernd Eggink . - - 4/17 - ---- -jobs.c - - new functions to save and restore the pgrp_pipe (since there's only - one): save_pgrp_pipe and restore_pgrp_pipe - -trap.c - - run_debug_trap now saves and restores the pgrp_pipe before and - after calling the debug trap - - run_debug_trap now makes sure the terminal is owned by the pipeline - pgrp after the debug trap runs. Rest of fix for bug reported by - Oleksly Melnyk (lex@upc.ca) - - 4/19 - ---- -include/posixselect.h - - new include file, encapsulates select(2) includes and defines for - bash and readline. Inspired by patch from Mike Frysinger - - -lib/sh/input_avail.c - - include "posixselect.h" - -lib/readline/{input,parens}.c - - include "posixselect.h" instead of using inline includes - - use new USEC_TO_TIMEVAL define to make sure that values for timeouts - greater than one second are handled properly - -lib/sh/fpurge.c - - updated implementation, taken from gnulib - - 4/21 - ---- -lib/glob/glob.c - - in finddirs, don't try to free a return value of glob_error_return - from glob_vector. Bug and fix from werner@suse.de - -lib/readline/signals.c - - in rl_echo_signal_char, check that SIGQUIT and SIGTSTP are defined - before trying to use them. Bug report and fix from Volker Grabsch - - - 4/24 - ---- -aclocal.m4 - - add conditional inclusion of to BASH_CHECK_TYPE - -bashtypes.h,lib/sh/strto[iu]max.c - - include if present for any existing declaration of - intmax_t and uintmax_t. Fixes Interix problem reported by - Markus Duft - -lib/sh/strindex.c,externs.h,builtins/common.h - - renamed strindex to strcasestr to agree with other implementations - (e.g., BSD, MacOS X, gnulib); changed callers - -lib/sh/{strindex.c,Makefile.in},Makefile.in - - renamed strindex.c to strcasestr.c - -configure.in - - add strcasestr to call to AC_REPLACE_FUNCS, take advantage of - existing libc implementations - -config.h.in - - add define for HAVE_STRCASESTR - -lib/sh/mbscmp.c - - fix mbscmp to return correct values when the strings do not contain - valid multibyte characters. Ideas from gnulib - -xstrchr.c - - only compare current character against C if mblength == 1 - -{shell,variables}.c - - changed some xstrchr calls back to strchr when the arguments cannot - contain multibyte characters - -lib/sh/{xstrchr.c,Makefile.in},Makefile.in - - renamed xstrchr to mbschr; renamed file to mbschr.c - -aclocal.m4 - - change BASH_CHECK_MULTIBYTE to use AC_REPLACE_FUNCS(mbschr) - -externs.h - - extern declarations for mbscmp and mbschr, conditional on the usual - HAVE_MBSCMP and HAVE_MBSCHR defines - -general.h,{alias,arrayfunc,bashline,general,execute_cmd,subst}.c - - changed calls to xstrchr to mbschr - -doc/bash.1 - - use `pathname expansion' consistently, not `filename expansion' or - `filename generation' - -doc/bashref.texi - - use the phrase `filename expansion' consistently (since this is - what the Gnu people prefer) instead of `pathname expansion' or - `filename generation' - -aclocal.m4,config.h.in - - check for mbscasecmp in BASH_CHECK_MULTIBYTE, define HAVE_MBSCASECMP - if found - -lib/sh/{mbscasecmp.c,Makefile.in} - - new file, case-insensitive multibyte string comparison - -externs.h - - extern declaration for mbscasecmp - - 4/25 - ---- -lib/readline/display.c - - in _rl_move_cursor_relative, don't adjust dpos by woff if it's - already less than woff (don't want it less than 0) - - in _rl_move_cursor_relative, short-circuit right away if the cursor - is at columns 0 and `new' is 0 (doesn't matter if it's a multibyte - locale or not, or whether there are invisible chars in the prompt) - - in _rl_move_cursor_relative, go ahead and adjust dpos if - prompt_physical_chars >= _rl_screenwidth (previous check was just > ) - Fixes bug reported by Andreas Schwab - - 4/28 - ---- -lib/glob/glob.c - - in glob_vector, don't add an empty pathname ("") if we're adding the - currect directory to the dirlist and GX_NULLDIR is set -- we can just - ignore it, since the passed directory name (".") was created by - the caller. Fixes bug reported by Matt Zyzik - - 5/5 - --- -subst.c - - make expansion of $@ and $* when set -u is in effect and there are - no positional parameters be a non-fatal error. This is the - consensus of the austin group, though it is not historical practice. - Message from Geoff Clare <20090505091501.GA10097@squonk.masqnet> of - 5 May 2009 and http://austingroupbugs.net/view.php?id=155 - - - 5/20 - ---- -lib/glob/glob.c - - tentative fix to glob_filename to compensate for glob_vector putting - null pathname at front of result vector when dflags&GX_NULLDIR. - Current fix manually removes empty string element from front of - result vector; a better fix would be to use a flag so glob_vector - doesn't add it at all. Augments patch from 4/28, which appears to - have broken some things. Fixes bug reported by Matt Zyzik - - - 5/22 - ---- - -lib/glob/glob.c - - better fix for glob_filename; supersedes patch of 5/20. Now the - code does not set GX_ADDCURDIR if directory_len == 0 and the - function has not been called recursively ((flags & GX_ALLDIRS) == 0). - Better fix for bug reported by Matt Zyzik - -Makefile.in - - fix build race condition that occurs in some makes caused by - libreadline.a and libhistory.a containing some of the same files - (e.g., xmalloc.o) and conflicting when trying to build both at - the same time. Reported by Mike Frysinger - - 5/25 - ---- -lib/readline/vi_mode.c - - fix _rl_vi_initialize_line so that the loop counter is not - unsigned (it doesn't matter, but it eliminates a compiler warning). - Bug reported by Dave Caroline - - 5/26 - ---- -doc/{bash.1,bashref.texi} - - add text to the description of array variables making it clear - that an array variable is not considered set until a subscript - has been assigned a value - - 5/29 - ---- -lib/readline/text.c - - fix rl_change_case to handle case where mbrtowc doesn't find a - valid multibyte character - -lib/readline/vi_mode.c - - fix _rl_vi_change_mbchar_case to handle case where mbrtowc doesn't - find a valid multibyte character - -lib/sh/casemod.c - - fix sh_modcase to handle case where mbrtowc doesn't find a valid - multibyte character - -lib/readline/mbutil.c - - fix _rl_find_next_mbchar_internal to not call mbrtowc at the end of - the string, since implementations return different values -- just - break the loop immediately - -lib/readline/display.c - - fix rl_redisplay to make same sort of cursor position adjustments - based on multibyte locale and _rl_last_c_pos when performing - horizontal scrolling rather than line wrapping. Probably still - more to do. Fixes bug reported by jim@jim.sh - - 6/5 - --- -doc/{bash.1,bashref.texi} - - added some more explanation of the inheritance of the ERR trap at - the suggestion of Thomas Pospisek - -findcmd.c - - use eaccess(2) if available in file_status to take other file - access mechanisms such as ACLs into account. Patch supplied - by werner@suse.de - - 6/12 - ---- -xmalloc.c - - also calculate lowest brk() value the first time xmalloc/xrealloc - (and their sh_ counterparts) are called - - error messages consolidated into a single function (allocerr/ - sh_allocerr) to avoid string duplication - - 6/16 - ---- -variables.c - - changes to allow variables.c to be compiled if ALIAS is not defined. - Bug and fix from John Gatewood Ham - -lib/sh/getcwd.c - - fix so systems defining BROKEN_DIRENT_D_INO have the necessary - defines. Fix from Jay Krell - -configure.in - - add -D_ALL_SOURCE to interix CFLAGS for struct timezone definition. - Bug and fix from John Gatewood Ham - - 6/29 - ---- -variables.c - - change initialize_shell_variables to add environment variables with - invalid names to the variables hash table, but marking them as - invisible and imported - - new function, export_environment_candidate. Used when creating the - export environment for commands to include variables with invalid - names inherited from the initial environment. Apparently this - behavior is widespread - - change make_var_export_array to use export_environment_candidate - rather than visible_and_exported to test variables for inclusion - in the export environment - - 7/1 - --- -builtins/read.def - - fix a memory leak where the number of fields is not the same as - the number of variables passed to `read'. Bug report from - werner@suse.de - -builtins/command.def - - move section of code that sets PATH from -p option before the - verbose-handling section, so command -v and command -V honor - the PATH set by command -p. Bug report and fix from - ohki@gssm.otsuka.tsukuba.ac.jp - - 7/9 - --- -subst.c - - change brace_expand_word_list to defer brace expansion on compound - array assignments that are arguments to builtins like `declare', - deferring the expansion until the assignment statement is processed. - Fixes inconsistency reported by agriffis@n01se.net - - 7/16 - ---- -bashline.c - - fix bash_execute_unix_command to set rl_point correctly based on - READLINE_POINT. The old method of using save_point will not - work because maybe_make_readline_line will change rl_point. Bug - reported by Henning Bekel - -trap.c - - fix _run_trap_internal and run_pending_traps to save and restore - value of subst_assign_varlist so the dispose_words on it doesn't - leave dangling pointers after the trap handler runs. Fixes bug - reported by Marc Herbert - - 7/22 - ---- -subst.c - - fix off-by-one error in pos_params when computing positional - parameters beginning with index 0. Bug and fix from Isaac Good - - - 7/24 - ---- -lib/readline/display.c - - add code to _rl_move_cursor_relative and _rl_col_width to short- - circuit a few special cases: prompt string and prompt string plus - line contents, both starting from 0. Saves a bunch of calls to - multibyte character functions using already-computed information. - As a side effect, fixes bug reported by Lasse Karkkainen - - -subst.c - - fixed a problem in split_at_delims that could leave *cwp set to -1 - if the line ends in IFS whitespace and SENTINEL is one of those - whitespace characters. Fixes problem with setting COMP_CWORD for - programmable completion reported by Ville Skytta - -bashline.c - - change bash_execute_unix_command to clear the current line (if the - terminal supplies the "ce" attribute) instead of moving to a new - line. Inspired by report from Henning Bekel - -builtins/printf.def - - changes to allow printf -v var to assign to array indices, the way - the read builtin can. Suggested by Christopher F. A. Johnson - - -lib/readline/complete.c - - fix rl_old_menu_complete and rl_menu_complete to appropriately set - and unset RL_STATE_COMPLETING while generating the list of matches. - Fixes debian bug #538013 reported by Jerome Reybert - - - 7/25 - ---- -execute_cmd.c - - change execute_builtin to temporarily turn off and restore the ERR - trap for the eval/source/command builtins in the same way as we - temporarily disable and restore the setting of the -e option. - Fixes bug reported by Henning Garus - - 7/27 - ---- -shell.c - - add fflush(stdout) and fflush(stderr) to exit_shell before closing - any file descriptors at exit time (e.g., coproc pipes) - - 7/30 - ---- -lib/readline/complete.c - - new function rl_backward_menu_complete, just passes negative count - argument to rl_menu_complete - - change rl_menu_complete to act appropriately if rl_last_command is - rl_backward_menu_complete, so we can cycle forward and backward - through the list of completions - -lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 - - document new "menu-complete-backward" bindable readline function. - Suggested by Jason Spiro - -lib/readline/vi_keymap.c - - add binding of C-n to menu-complete and C-p to menu-complete-backward - in vi-insert keymap, as suggested by Jason Spiro - - -pcomplete.c - - fixed a bug in programmable_completions: the options it returned from - the compspec it found were set before generating the completions, - which meant that any changes made by "compopt" were overridden and - only in effect for the duration of the executing shell function - rather than the entire completion. Fixes bug reported by Ville - Skytta - - 7/31 - ---- -lib/readline/keymaps.c - - fixed memory leak in rl_discard_keymap by freeing storage associated - with hierarchical keymaps - - new convenience function, rl_free_keymap, that calls rl_discard_keymap - and frees the keymap passed as an argument - -lib/readline/util.c - - new bindable keymap function, _rl_null_function, to be used internally - -lib/readline/rlprivate.h - - extern declaration for _rl_null_function - -lib/readline/bind.c - - fix rl_generic_bind in the case where we are trying to override a - keymap with a null function (e.g., when trying to unbind it). We - can't use a NULL function pointer in ANYOTHERKEY since that's - indistinguishable from the keymap not having been overridden at all. - We use _rl_null_function instead, which simply does nothing. We - could add an rl_ding to it later. Fixes problem with hitting ESC - repeatedly while in vi command mode reported by James Rowell - - -builtins/bind.def - - call rl_bind_keyseq instead of rl_set_key for -r option - -lib/readline/readline.c - - Set vi_movement_keymap[ESC] to _rl_null_function after binding the - arrow keys in bind_arrow_keys() to allow vi-mode users to hit ESC - multiple times in vi command mode while still allowing the arrow - keys to work - - 8/2 - --- -bashline.c - - fix clear_hostname_list by setting hostname_list_initialized to 0 - after freeing all list members. Fixes bug reported by Freddy - Vulto - -lib/readline/display.c - - in update_line, if we copy data from one line to another because we - are wrapping a multibyte character from, say, the first line to the - second, we need to update OMAX and the line indices to account for - the moved data. Bug report and fix from Martin Hamrle - - - 8/3 - --- -pcomplete.h - - defines for EMPTYCMD ("_EmptycmD_") and DEFAULTCMD ("_DefaultCmD_") - -builtins/complete.def - - change compopt_builtin to make -E work on the "empty" command - completion - - fix print_compitem and print_compopts to replace EMPTYCMD with -E - - added -D (default) option to complete/compgen/compopt. No supporting - code yet - -doc/bash.1,lib/readline/doc/rluser.texi - - document new -D, -E options to compopt - - document new -D option to complete/compgen - -shell.h - - new define, EX_WEXPCOMSUB, value of 125 - - new define, EX_RETRYFAIL, value of 124 (for programmable completion) - -subst.c - - use EX_WEXPCOMSUB instead of literal 125 as exit status when a shell - invoked to run wordexp(3) with the -n option supplied attempts a - command substitution - -pcomplete.c - - new define, PCOMP_RETRYFAIL, used to indicate a "failure, retry with - next completion" status to the programmable completion code - - 8/4 - --- -pcomplete.c - - changed gen_shell_function_matches to take an extra parameter - indicating whether the specified shell function was not found or - returned the special "fail/retry" status, and, if it was either, - to not bother returning any matches list - - changed gen_compspec_completions to take an extra parameter to pass - through the "found" status from gen_shell_function_completions - - new function gen_progcomp_completions to take care of searching for - and evaluating a compspec for a particular word, saving its status, - and returning to its caller (programmable_completions) whether or - not to retry completion. This function also checks whether a - retry changed the compspec associated with a command and short- - circuits the retry if it has not - - changed programmable_completions to try default completion (if set) - if a specific completion was not found for a command - - changed programmable_completions to implement "fail/retry" semantics - for a shell function that returns 124 and changes the compspec - associated with the command. All based on proposal and changes from - Behdad Esfahbod (Red Hat bugzilla 475229) - -doc/bash.1,lib/readline/doc/rluser.texi - - documented new dynamic programmable completion functionality - - 8/5 - --- -stringlib.c - - first argument to substring() is now `const char *' - -externs.h - - changed extern declaration for substring() - -subst.c - - skipsubscript now takes a third FLAGS argument, passes to - skip_matched_pair - - skip_matched_pair now interprets flags&1 to mean not to parse - matched pairs of quotes, backquotes, or shell word expansion - constructs - -{subst,general,expr}.c - - changed skipsubscript() callers - -assoc.c - - changed assoc_to_assign to double-quote the key if it contains any - shell metacharacters - -arrayfunc.c - - use skipsubscript in quote_assign rather than quote any glob - characters in the subscript of an array assignment - - in assign_compound_array_list, call skipsubscript with a flags - argument of 1 if assigning an associative array to avoid trying - to re-parse quoted strings - -redir.c - - set expanding_redir before expanding body of here documents and - here strings to avoid looking for variables in temporary env - - 8/7 - --- -lib/readline/readline.c - - in _rl_dispatch_callback, return value of -3 means that we have - added to a key sequence, but there are previous matches in the - sequence. Don't call _rl_subseq_result if we get a -3 from a - previous context in the chain; just go back up the chain. Report - and fix from - -bashline.c - - fixes to history_completion_generator and bash_dabbrev_expand to - make dabbrev-expand inhibit suppressing of appending space char - to matches. Have to do it with the generator too because - rl_menu_complete turns off suppressing the appended space in - set_completion_defaults(). Suggestion from Dan Nicolaescu - - - suppress completion match sorting in bash_dabbrev_expand by - setting rl_sort_completion_matches = 0. Suggestion from Dan - Nicolaescu - - don't qsort history match list in build_history_completion_array - if dabbrev_expand_active == 1 - - start the loop in build_history_completion_array that gathers words - from history for possible completions from the end of the list - rather than the beginning. It doesn't matter where you start if - the results are sorted, and dabbrev-expand is supposed to offer - the most recent completions first - - 8/12 - ---- -execute_cmd.c - - change to execute_command_internal to make [[ ... ]] conditional - command subject to settings of `set -e' and the ERR trap - - 8/14 - ---- -execute_cmd.c - - change to execute_command_internal to make (( ... )) arithmetic - command subject to settings of `set -e' and the ERR trap - -lib/readline/text.c - - new bindable function, rl_skip_csi_sequence, reads the characters - that make up a control sequence as defined by ECMA-48. Sequences - are introduced by the Control Sequence Indicator (CSI) and - contain a defined set of characters. Insert, End, Page Up and so - on are CSI sequences. Report and code from Andy Koppe - - -lib/readline/readline.h - - extern declaration for rl_skip_csi_sequence - -lib/readline/funmap.c - - new bindable command "skip-csi-sequence", runs rl_skip_csi_sequence - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented new bindable command "skip-csi-sequence", unbound by - default - -builtins/evalfile.c - - fix _evalfile to remove embedded null bytes from the file read - into the string. Report and proposed fix from Roman Rakus - - -{configure,config.h}.in - - check for syslog(3), define HAVE_SYSLOG - - check for syslog.h, define HAVE_SYSLOG_H - -config-top.h - - new define SYSLOG_HISTORY, disabled by default - -config-bot.h - - if HAVE_SYSLOG or HAVE_SYSLOG_H are not defined, undef SYSLOG_HISTORY - -bashhist.c - - if SYSLOG_HISTORY is defined, call bash_syslog_history with the - line added to the history in bash_add_history. - - new function, bash_syslog_history(line), sends line to syslog at - user.info. The line is truncated to send no more than 600 - (SYSLOG_MAXLEN) bytes to syslog. Feature requested by many, and - required by some national laws - -sig.c - - in termsig_handler, resend SIGHUP to children if subshell_environment - indicates we're a shell performing command or process substitution - -jobs.c - - add CHECK_TERMSIG calls to wait_for in addition to the ones in - waitchld() - -builtins/shopt.def - - new functions set_bashopts, parse_bashopts, and initialize_bashopts - to manage new environment variable $BASHOPTS, like $SHELLOPTS but - for shopt options - - change toggle_shopts to call set_bashopts after setting options, so - $BASHOPTS reflects new values - -shell.c - - call initialize_bashopts after calling initialize_shell_options at - shell startup - -configure.in - - new configure `enable' option --enable-exended-glob-default, to - set the initial default value of the `extglob' shell option - -config.h - - new define, EXTGLOB_DEFAULT, controlled by the `extended-glob-default' - configure option - -pathexp.c - - initialize extended_glob variable to EXTGLOB_DEFAULT - -doc/{bash.1,bashref.texi} - - document new $BASHOPTS variable and its behavior - -doc/bashref.texi - - document new --enable-extended-glob-default configure option - - 8/16 - ---- -print_cmd.c - - new variables: xtrace_fd and xtrace_fp, the file descriptor and - FILE * to which we send `set -x' tracing output. If fd == -1 - then fp == STDERR, the default mode - - new function xtrace_init, sets xtrace_fd == -1 and xtrace_fp = stderr - - new function xtrace_set (fd, fp), sets xtrace_fd and xtrace_fp - to the arguments - - new function xtrace_reset, handles closing old xtrace fd/fp and - moving them back to -1/stderr - - new function xtrace_fdchck, calls xtrace_reset if the fd passed as - an argument is xtrace_fd - - change xtrace functions to fprintf to xtrace_fp instead of stderr - -shell.c - - call xtrace_init() very early in main() - -variables.c - - new special variable, BASH_XTRACEFD, holds file descriptor used for - set -x trace output. Inspired by suggestion from Bruce Korb - - -doc/{bash.1,bashref.texi} - - added description of new BASH_XTRACEFD variable - -redir.c - - add calls to xtrace_fdchk to the redirections that close file - descriptors, so we notice if we close BASH_XTRACEFD and compensate - accordingly (same places that call coproc_fdchk()) - - 8/18 - ---- -lib/readline/text.c - - change to _rl_replace_text to add error checks: start must be <= - end, and we don't call rl_insert_text if passed the empty string - -config.h.in - - add define for HAVE_ICONV, already found by intl autoconf macros - - add define for HAVE_LOCALE_CHARSET - -aclocal.m4 - - add check for locale_charset() to BASH_CHECK_MULTIBYTE - -lib/sh/fnxform.c - - new file with two public function: fnx_tofs and fnx_fromfs. - Primarily intended for use on MacOS X, they use iconv to convert - between whatever the current locale encoding is and "UTF-8-MAC", - a special encoding on OS X in which all characters are - decomposed unicode, as the HFS+ filesystem stores them. These - functions return a pointer to a local buffer, allocated once and - resized as necessary, to avoid too many allocations; callers - should not free the return value, since it may be the string - passed - -Makefile.in - - make sure LIBICONV is set by autoconf (@LIBICONV@) and added to - list of link libraries - -externs.h - - new extern declarations for fnx_fromfs and fnx_tofs - -lib/glob/glob.c - - convert the filename read using readdir() in glob_vector() using - fnx_fromfs and use that value in the call to strmatch. This - ensures that we're using the precomposed Unicode value of the - filename rather than the native decomposed form. Original bug - report from Len Lattanzi ; fix inspired by - Guillaume Outters - - 8/19 - ---- -lib/readline/complete.c - - new completion hook: rl_filename_rewrite_hook, can rewrite or modify - filenames read from the filesystem before they are compared to the - word to be completed - -lib/readline/readline.h - - extern declaration for rl_filename_rewrite_hook - -lib/readline/doc/rltech.texi - - document rl_filename_rewrite_hook - -bashline.c - - new function, bash_filename_rewrite_hook, assigned to - rl_filename_rewrite_hook. Calls fnx_fromfs to convert from - filesystem format to "input" format. This makes completing - filenames with accented characters work on Mac OS X - - 8/20 - ---- -lib/readline/bind.c - - new bindable variable "skip-completed-text", bound to - _rl_skip_completed_text. If enabled, it means to note when - completing before the end of a word and skipping over characters - after rl_point that match in both the completion to be inserted - and the word being completed. It means that completing - `Makefile' with the cursor after the `e' results in `Makefile' - instead of `Makefilefile'. Inspired by an idea from Jared - Yanovich from back in 2004 - -lib/readline/rlprivate.h - - extern declaration for _rl_skip_completed_text - -lib/readline/complete.c - - implement semantics of _rl_skip_completed_text in insert_match: - skip characters in `replacement' that match chars in rl_line_buffer - from the start of the word to be completed - - 8/21 - ---- -error.c - - change parser_error to set last_command_exit_value to 2 before - calling exit_shell (if set -e is enabled), so any exit or ERR - trap gets the right value of $?. Suggestion from Stefano - Lattarini - -braces.c - - fix expand_seqterm so that a non-zero-prefixed term that's longer - than a zero-prefixed term determines the length of each term - in the brace-expanded sequence. This means that things like - {01..100} will have three digits in all the elements of the - expanded list. Fixes bug reported by Jeff Haemer - - - 8/24 - ---- -{arrayfunc,variables}.c - - when inserting a value into an associative array using syntax like - T=v where T is an already-declared associative array using key "0", - make sure the key is in newly-allocated memory so it can be freed - when the variable is unset. Fixes bug reported as redhat 518644 - by Jon Fairbairn - - 8/26 - ---- -lib/readline/funmap.c - - add "old-menu-complete" binding for rl_old_menu_complete - -lib/readline/readline.h - - add extern declaration for rl_old_menu_complete - -subst.c - - fix memory leak when processing ${!prefix@}. Need to dispose all - words in the word list created from all matching variable. Fixes - bug reported by muszi@muszi.kite.hu. - - 8/29 - ---- -execute_cmd.c - - add fflush(stdout) and fflush(stderr) to child coproc code before - calling exit after execute_in_subshell - - 8/31 - ---- -lib/readline/{{bind,readline}.c,rlprivate.h} - - new bindable variable, "echo-control-characters", enabled by default. - This controls whether or not readline honors the tty ECHOCTL bit - and displays characters corresponding to keyboard-generated signals. - Controlled by _rl_echo_control_chars variable, declared in readline.c - -lib/readline/signals.c - - if _rl_echo_control_chars == 0, don't go through _rl_echo_signal_char - - -lib/readline/doc/{readline.3,rluser.texi} - - document "echo-control-characters" bindable variable - - 9/1 - --- -lib/readline/histexpand.c - - hist_string_extract_single_quoted now takes an additional argument: - a flags word. The only defined value (flags & 1) allows backslash - to quote the single quote. This is to inhibit history expansion - inside $'...' containing an escaped single quote. - - change history_expand to call hist_string_extract_single_quoted - with flags == 1 if it sees $'. Fixes bug reported by Sean - Donner - - 9/2 - --- -builtins/printf.def - - add a call to sh_wrerror if ferror() succeeds in the PRETURN macro, - to print an error message in the case that the final fflush fails - (for instance, because it attempts to write data that didn't have a - trailing newline). Fixes bug reported by Stefano Lattarini - - - 9/7 - --- -arrayfunc.c - - some fixes to assign_compound_array_list to avoid null pointer - dereferences pointed out by clang/scan-build - -lib/glob/glob.c - - fixes to udequote_pathname and wdequote_pathname to avoid possible - null pointer dereferences pointed out by clang/scan-build - -lib/readline/undo.c - - fix to _rl_copy_undo_list (function unused) to avoid deref of - uninitialized pointer pointed out by clang/scan-build - -general.c - - fix string_to_rlimtype so it works if passed a null pointer (though - it never is) - -builtins/mapfile.def - - fix to mapfile() to avoid possible null pointer dereference pointed - out by clang/scan-build - -variables.c - - fix to valid_exportstr to avoid possible null pointer dereferences - pointed out by clang/scan-build - -bashline.c - - fix to bash_execute_unix_command to avoid possible null pointer - dereference if READLINE_LINE or READLINE_POINT is not bound - - 9/11 - ---- -[Prayers for the victimes of 9/11/2001] - -command.h - - add `rflags' member to struct redirect to hold private flags and - state information - - change redirector to a REDIRECTEE instead of int to prepare for - possible future changes - -{copy_cmd,dispose_cmd,make_cmd,print_cmd,redir}.c - - changes resulting from type change of `redirector' member of struct - redirect: change x->redirector to x->redirector.dest and add code - where appropriate to deal with x->redirector.filename - -make_cmd.h - - change extern declaration for make_redirection - -make_cmd.c - - first argument of make_redirection is now a `REDIRECTEE' to prepare - for possible future changes. First arg is now assigned directly to - redirector member instead of assigning int to redirector.dest - -{make_cmd,redir}.c,parse.y - - changes resulting from type change of first argument to - make_redirection from int to REDIRECTEE. In general, changes are - using REDIRECTEE sd and assigning old argument to sd.dest, then - passing sd to make_redirection - -make_cmd.[ch],parse.y - - add fourth argument to make_redirection: flags. Sets initial value - of `rflags' member of struct redirect - - changed all callers of make_redirection to add fourth argument of 0 - - 9/15 - ---- -parse.y - - change read_token_word to return REDIR_WORD for tokens of the form - {var} where `var' is a valid shell identifier and the character - following the } is a `<' or `>' - - add REDIR_WORD versions of all input and output file redirections - and here documents - -print_cmd.c - - change input and output file redirection direction and here - document cases of print_redirection to print a varname - specification of the form {var} when appropriate. Still need - to fix rest of cases - -redir.c - - implement REDIR_VARASSIGN semantics for file input and output - redirections and here documents - - 9/16 - ---- -parse.y - - added REDIR_WORD versions of remaining redirection constructs except - for err_and_out ones - -redir.c - - handle REDIR_VARASSIGN semantics for rest of redirection constructs - - accommodate REDIR_VARASSIGN when translating redirections - - new function, redir_varvalue, does variable lookup for {v} when - redirection needs the value (e.g., r_close_this) - -print_cmd.c - - fix rest of cases to print {varname} when REDIR_VARASSIGN is set in - redirect->rflags - -doc/{bash.1,bashref.texi} - - document new {varname} REDIR_VARASSIGN form of redirections - -tests/vredir.{right,tests},vredir[1-5].sub - - tests for new {varname} REDIR_VARASSIGN form of redirections - - 9/18 - ---- -subst.c - - new flags argument to split_at_delims: these flags are ORd with - SD_NOJMP and passed to skip_to_delim - - change skip_to_delim to honor new SD_NOQUOTEDELIM flag by not - checking whether or not single and double quotes are delimiters - if it's set in passed flags until after skipping quoted strings. - -subst.h - - change extern declaration for split_at_delims - - new define for SD_NOQUOTEDELIM flag - -pcomplete.c - - pass SD_NOQUOTEDELIM in flags argument to split_at_delims so single - and double quotes, even though they're in - rl_completer_word_break_characters, don't act as word delimiters - for programmable completion. Fixes bug reported by Freddy - Vulto - -lib/glob/glob.c - - in glob_filename, after recursively scanning a directory specified - with `**', turn off GX_ALLDIRS|GX_ADDCURDIR before calling - glob_vector on the rest of the pathname, since it may not apply to - the rest of the pattern. Turned back on if the filename makes it - appropriate. Fixes bug reported by Anders Kaseorg - -redir.c - - change execute_null_command to fork a child to execute if any of - the commands redirections have the REDIR_VARASSIGN flag set, since - those commands are not supposed to have side effects - -test.c - - < and > binary operators will obey the locale by using strcoll if - the TEST_LOCALE flag is passed to binary_test - -test.h - - new define for TEST_LOCALE - -execute_cmd.c - - execute_cond_node sets TEST_LOCALE so [[ str1 < str2 ]] (and >) - obey the locale. Fixes bug/incompatibility reported by Greg - Wooledge - -doc/{bash.1,bashref.texi} - - documented [[ command new locale-sensitive treatment of < and > - - 9/24 - ---- -configure.in - - add "darwin10" cases like darwin8 and darwin9 to handle linking with - included readline and history libraries - - 9/26 - ---- -lib/readline/display.c - - modify change of 7/24 to use prompt_physical_chars instead of - prompt_visible_length to account for visible multibyte characters in - the line (usually in the prompt). Fixes debian bug #547264 - reported by Pietro Battiston - - add flags argument to _rl_col_width; changed callers. flags > 0 - means that it's ok to use the already-computed prompt information; - flags == 0 means that we're expanding the prompt and we should not - short-circuit - -parse.y - - in decode_prompt_string, when expanding \w and \W on Mac OS X, - use fnx_fromfs to convert from "filesystem" form to "input" form. - This makes $PWD with multibyte characters work in the prompt - string on Mac OS X - -lib/sh/fnxform.c - - in fnx_fromfs and fnx_tofs, use templen instead of outlen as last - argument in calls to iconv, since outlen is used to keep track of - the size of the buffer, and iconv potentially modifies its - `outbytesleft' argument - - 9/29 - ---- -subst.c - - make skip_to_delim understand how to skip over process substitution - constructs the way it skips $(...) command substitution - - 9/30 - ---- -lib/readline/terminal.c - - don't set the `terminal has meta key' flag if the `MT' capability is - available; that means something completely different - - 10/1 - ---- -builtins/help.def - - make sure width is at least 7, since we pass `width/2 - 3' to strncpy - as the length argument. Terminal widths <= 6 are converted to 80. - Fixes bug reported by Chris Hall - -configure.in - - changed version to 4.1-alpha - -subst.h - - new flag for skip_to_delim: SD_NOSKIPCMD, which means to not skip - over embedded command and process substitutions, but rather to look - for delimiters within them - -subst.c - - implement semantics of SD_NOSKIPCMD in skip_to_delim - -bashline.c - - call skip_to_delim with SD_NOSKIPCMD from find_cmd_start, so - programmable completion can use the completion defined for `b' for - command lines like "a $(b c". Fixes inconsistency/bug reported by - Freddy Vulto - -parser.h - - replace unused PST_CMDTOKEN parser state value with PST_EXTPAT, - means currently parsing an extended glob pattern (extglob) - -parse.y - - fix cond_node() so that extended_glob is set before parsing the - rhs of the `==' or `!=' operators. For ksh93 compatibility. - - reset extended_glob to global value (saved in parse_cond_command()) - in reset_parser() - - 10/5 - ---- -jobs.c - - change waitchld() to only interrupt the wait builtin when the shell - receives SIGCHLD in Posix mode. It's a posix requirement, but - makes easy things hard to do, like run a SIGCHLD trap for every - exiting child. Change prompted by question from Alex Efros - - -doc/bashref.texi - - document new posix mode behavior about SIGCHLD arriving while the - wait builtin is executing when a trap on SIGCHLD has been set - - 10/6 - ---- -lib/readline/histexpand.c - - fix hist_expand to keep from stopping history expansion after the - first multibyte character (a `break' instead of a `continue'). - Fixes debian bug (#549933) reported by Nikolaus Schulz - - - 10/8 - ---- -builtins/read.def - - implement new `-N nchars' option: read exactly NCHARS characters, - ignoring any delimiter, and don't split the result on $IFS. - Feature requested by Richard Stallman - -doc/{bash.1,bashref.texi} - - document new `read -N' option - - 10/9 - ---- -lib/readline/bind.c - - new bindable variable, "enable-meta-key", controls whether or not - readline enables any meta modifier key the terminal claims to - support. Suggested by Werner Fink - -lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 - - document new readline "enable-meta-key" bindable variable - - 10/10 - ----- -trap.c - - new function, free_trap_string(), does what it says and turns off - SIG_TRAPPED flag without changing signal disposition - -[bash-4.1-alpha frozen] - - 10/16 - ----- -builtins/mapfile.def - - return an error if the variable passed is not an indexed array. - Fixes bug reported by Nick Hobson - - change help text to make it clear that an indexed array is required - -doc/{bash.1,bashref.texi} - - changed description of mapfile to note that the array variable - argument must be an indexed array, and mapfile will return an - error if it is not - -subst.c - - change expand_string_unsplit and expand_string_leave_quoted to - add the (previously unused) W_NOSPLIT2 flag to the created word - - change expand_word_internal to understand W_NOSPLIT2 to mean that - we're not going to split on $IFS, so we should not quote any - characters in IFS that we add to the result string. Fixes bug - reported by Enrique Perez-Terron - - change cond_expand_word similarly. Fixes rest of bug reported by - Enrique Perez-Terron - -parse.y - - save and restore value of last_command_subst_pid around call to - expand_prompt_string in decode_prompt_string. Fixes bug that causes - $? to be set wrong when using a construct like false || A=3 when - set -x is enabled and $PS4 contains a command substitution. Reported - by Jeff Haemer - - 10/17 - ----- -execute_cmd.c - - in execute_in_subshell, make sure we set setjmp(return_catch) before - running the command, in case the command or its word expansion - calls jump_to_top_level. Fixes bug reported by Nils Bernhard - - -subst.c - - new PF_NOSPLIT2 flag for param_expand - - parameter_brace_expand takes a new `pflags' argument, before the - `output' parameters; passes to param_expand as necessary - - change parameter_brace_expand to call parameter_brace_expand_word - with the PF_NOSPLIT2 flag if the pflags argument to - parameter_brace_expand has it set - -parse.y - - change report_syntax_error to set last_command_exit_value to - EX_BADSYNTAX if parse_and_execute_level is > 0, indicating a - syntax error while we're executing a dot script, eval string, - trap command, etc. - -builtins/evalstring.c - - in parse_and_execute, if parse_command() returns non-zero, - indicating a parse error, print a warning message if the conditions - would require a posix-mode shell to abort (parse error in a `.' - script or eval string) - - 10/19 - ----- -builtins/evalfile.c - - even if the `check binary' flag is not passed to _evalfile, return an - error after reading 128 null characters if called by `source', on - the assumption that it's probably a binary file. [This will be in - bash-4.1-beta] - - 10/24 - ----- -[bash-4.1-alpha released] - -bashline.c - - don't call command_substitution_completion_function if we're - completing a substring delimited by a single quote. Fixes bug - reported by bash-bugs@atu.cjb.net - -lib/readline/complete.c - - make sure _rl_skip_completed_text defaults to 0, as the - documentation states (incorrect in bash-4.1-alpha) - - in insert_match, skip over a close quote in the replacement text if - the character at point when completion is invoked is a single - quote. Fixes complaint from bash-bugs@atu.cjb.net - - 10/26 - ----- -shell.c - - in main, make sure "$EMACS" is non-null before calling strstr on its - value. Fixes Red Hat bug 530911 submitted by Mitchell Berger - -builtins/mapfile.def - - don't save callback commands in shell history. Suggested by - Jan Schampera - -mailcheck.c - - in file_mod_date_changed, make sure the modification time is later - than the saved modification date, not just that it's not equal. - Fix from Evgeniy Dushistov - - in file_access_date_changed, make sure the access time is later - than the saved access time, not just that it's not equal - - 10/27 - ----- -builtins/shopt.def - - added new `compat40' compatibility variable, with associated changes - to shell_compatibility_level(), since the default compatibility level - is now 41 - -test.c - - make the < and > operators to [[ use strcoll() only if the shell - compatibility level is greater than 40 (it is 41 by default in - bash-4.1) - - 10/28 - ----- -support/shobj-conf - - decrease the default version of FreeBSD that creates shared libraries - to 4.x. Advice from Peter Jeremy - - 11/2 - ---- -parse.y - - change parse_comsub to free `heredelim' and set it to 0 whenever the - comsub scanner finds the end of a here document. Really need to - implement a stack of here doc delimiters like in the parser (can we - use redir_stack here, too?) - - fix parse_comsub to not attempt to read another here doc delimiter - after seeing a shell break character (that is not newline) if we - already have one. Fixes Debian bash bug #553485, submitted by - Samuel Hym - - 11/3 - ---- -variables.c - - fix bind_variable_internal to call a variable's dynamic 'set function' - with the right arguments depending on whether it's an associative - array, an indexed array, or a scalar. Fixes Ubuntu bug #471504 - https://bugs.launchpad.net/ubuntu/+source/bash/+bug/471504 reported - by AJ Slater - -[bash-4.1-beta frozen] - - 11/11 - ----- -builtins/printf.def - - in getintmax(), in the case of a conversion error, return the partial - value accumulated so far, which is suppose to be what - strtoimax/strtoll/strtol returns - - 11/17 - ----- -[bash-4.1-beta released] - - 11/18 - ----- -builtins/{common.h,shopt.def},shell.c - - changed shopt variable "set functions" to take the option name as - the first argument; changed function prototypes and callers - -builtins/shopt.def - - change set_compatibility_level() to turn off other compatNN options - when one is set -- enforce mutual exclusivity. Fixes problem noted - by Jan Schampera - - 11/19 - ----- -lib/readline/rltty.c - - make sure prepare_terminal_settings() tests for the presence of - ECHOCTL before using it. Fixes bug reported by Joachim Schmitz - - -config-top.h - - new WORDEXP_OPTION define (off by default) - -shell.c - - don't include the --wordexp option or the supporting function - (run_wordexp) if WORDEXP_OPTION is not defined. Suggested by - Aharon Robbins - -execute_cmd.c - - in execute_cond_node, turn on comsub_ignore_return if the flags - indicate we're ignoring the return value before calling - cond_expand_word. Fixes bug reported by Anirban Sinha - - - 11/20 - ----- -lib/sh/snprintf.c,builtins/printf.def - - change check for HAVE_ASPRINTF and HAVE_SNPRINTF to check if value - is 1 or 0 rather than whether they are defined or not. This allows - a value of 0 to enable function replacement - -configure.in,aclocal.m4 - - new autoconf macro, BASH_FUNC_SNPRINTF, checks for snprintf present - and working as C99 specifies with a zero length argument. Idea - from Greg Wooledge - - new macro BASH_FUNC_VSNPRINTF, does same thing for vsnprintf - - 11/25 - ----- -subst.c - - in command_substitute, only tell parse_and_execute to reset the line - number in an interactive shell if sourcelevel == 0 -- we'll use the - line numbers from the sourced file - -execute_cmd.c - - in execute_simple_command, only subtract function_line_number from - line_number if sourcelevel == 0. If sourcing, we'll use the line - numbers from the sourced file. Fixes bug reported by Hugo - Mildenberger - -builtins/declare.def - - in declare_internal, call bind_assoc_variable instead of - bind_array_variable in the case of declare -A foo=bar. Fixes bug - reported by Bernd Eggink . - - 11/27 - ----- -lib/readline/util.c - - change declaration for _rl_walphabetic to use prototype, assuming - that any system with multibyte characters has a compiler that can - handle prototypes. Fix for AIX compilation problem reported by - Nick Hillman - - 11/28 - ----- -execute_cmd.c - - make funcnest file-scope static and unwind-protect its value in - execute_function, so it can be used as a real measure of function - call nesting - -general.c - - fix off-by-one error in trim_pathname that caused it to short-circuit - when PROMPT_DIRTRIM == number of directories - 1. Fixes bug - reported by Dennis Williamson - - 11/29 - ----- -jobs.c - - when fork() returns -1/EAGAIN, call waitchld(-1, 0) so the shell can - reap any dead jobs before trying fork again. Currently disabled - until bash-4.2 development starts - -lib/readline/complete.c - - when incrementing _rl_interrupt_immediately, make sure it's greater - than 0 before decrementing it. In practice, not a problem, but - the right way to do it. Suggested by Jan Kratochvil - - -lib/readline/signals.c - - make sure rl_signal_handler doesn't set rl_caught_signal if - _rl_interrupt_immediately is set, so RL_CHECK_SIGNALS doesn't - cause it to be processed twice. Suggested by Jan Kratochvil - - - if the callback interface is being used, use the code path that - immediately handles signals. This restores the readline-5.2 - behavior. Fixes GDB readline bug reported by Jan Kratochvil - - - 12/18 - ----- -[bash-4.1-rc1 released] - - 12/22 - ----- -config-top.h - - don't have SYSLOG_HISTORY enabled by default - -lib/sh/Makefile.in - - add explicit dependency on pathnames.h for parallel make support - -externs.h - - add extern declaration for xtrace_fdchk - -lib/sh/snprintf.c - - add local prototype declarations for isinf, isnan if we are providing - local definitions - -lib/sh/fnxform.c - - add extern declaration for get_locale_var if HAVE_LOCALE_CHARSET not - defined - -execute_cmd.c - - define NEED_FPURGE_DECL so we pick up any extern declaration for - fpurge (e.g., if the system doesn't provide it) - -builtins/shopt.def - - correct prototype and declaration for set_shellopts_after_change so - it's the correct type for shopt_set_func_t - - add new function shopt_enable_hostname_completion that is the correct - type for shopt_set_func_t; just calls enable_hostname_completion and - returns its result - - 12/26 - ----- -doc/{bash.1,bashref.texi} - - add \E and \" escape sequences to ANSI-C quoting description. - Suggested by Aharon Robbins - - 12/29 - ----- -doc/bash.1 - - make sure shell and environment variable names are always in - `small caps' bold. Suggested by Aharon Robbins - - 12/30 - ----- -{execute_cmd.c,parse.y,Makefile} - - changes for building minimal configuration from Matthias Klose - - -[bash-4.1 frozen] - - 12/31 - ----- -[bash-4.1 released] - - 1/5/2010 - -------- -doc/bashref.texi - - document compat32 and compat40 shopt options. Omission pointed out - by Dilyan Palauzov - - 1/6 - --- -lib/readline/complete.c - - use `convfn' (converted filename) instead of entry->d_name (filename - read from file system) when adding partial or full completions to - the command line. Bug and fix from Guillaume Outters - - - 1/7 - --- -builtins/printf.def - - fix prototype in extern declaration for vsnprintf. Fix for bug - reported by Yann Rouillard - - 1/9 - --- -parse.y - - fix shell_getc to handle alias expansions containing quoted - newlines. Problems in bash-4.1 with aliases containing quoted - newlines in the middle of and at the end of their expansion. - Fix for bug reported by Jonathan Claggett - - - change mk_alexpansion to not append a space to an alias - expansion ending with a newline. Works with shell_getc - - 1/11 - ---- -lib/glob/Makefile.in - - add dependencies on shell.h and pathnames.h. From Mike Frysinger - - - 1/15 - ---- -doc/{bash.1,{bashref,version}.texi},lib/readine/doc/rluser.texi - - some typo fixes from Aharon Robbins - - added descriptions of ENV, COPROC, and MAPFILE variables - - added descriptions of READLINE_LINE and READLINE_POINT - - 1/21 - ---- -arrayfunc.c - - free `akey', the word-expanded index into the assoc array to avoid - mem leak in array_value_internal - - free index into assoc array in unbind_array_element - - change array_value_internal to take an additional argument: an - arrayind_t *. If not null, an index to an indexed array is - returned there. If not an indexed array or subscript is @ or - *, the value is unchanged - - 1/22 - ---- -builtins/ulimit.def - - include if we found it during configure and we don't - have resources. Fixes omission reported by Joachim Schmitz - - -{configure,config.h}.in - - check for , define HAVE_ULIMIT_H if found - -lib/sh/oslib.c - - include for extern declaration for kill(2) if - HAVE_KILLPG not defined - -jobs.c - - if HAVE_KILLPG is not defined, add an extern prototype decl for - killpg() - - 1/24 - ---- -print_cmd.c - - when printing here-string redirections, don't quote the string. The - original quotes, if any, are still in place and don't need to be - requoted. Fixes bug reported by Arfrever Frehtes Taifersar Arahesis - - -subst.c - - fix array_length_reference to return 0 for variables that have not - been assigned a value. Fixes bug reported by Mart Frauenlab - , but is not backwards compatible - -arrayfunc.[ch] - - change array_value to take a new arrayind_t *indp parameter like - get_array_value; changed extern prototype declaration - -subst.c - - changed callers of array_value to add extra parameter - -expr.c - - change expr_streval to set a new `lvalue' parameter with information - about the string being evaluated: string, value, array index (if - any), variable evaluated (if set). - - saving and restoring current context now saves and restores the - current `lvalue' - - new function expr_bind_array_element, binds an array element with an - already-computed index to a specified value - - anywhere we set the current token to a string (STR), save and set - the current lvalue - - change calls to expr_bind_variable to check whether or not the - current lvalue indicates an indexed array was evaluated, and, if so, - call expr_bind_array_element using the already-computed index - (curlval.ind). Fixes problems with dynamic variables (e.g., RANDOM) - in array indices with {pre,post}-{inc,dec}rement and op= - operators reported by - - 1/25 - ---- -expr.c - - fix subexpr() to initialize curlval and lastlval when resetting all - of the rest of the expression-parsing variables - - 1/26 - ---- -builtins/setattr.def - - in show_var_attributes, if the variable is not set (value == 0), - don't print `name=""', just print `name'. Pointed out by - Mart Frauenlab - -arrayfunc.c - - fix array_keys to return NULL if the variable is not set or - invisible. Pointed out by Mart Frauenlab - - change array_value_internal to return NULL for variable which has - not been set - - 1/30 - ---- -bashline.c - - in command_word_completion_function, don't call glob_pattern_p - on hint -- use the already-computed `globpat'. At this point, - hint might contain an already-dequoted globbing character, but - glob_matches will be NULL. Fixes bug reported by - coyote@wariat.org.pl - - 2/5 - --- -builtins/exec.def - - set extern variable "exec_argv0" to the argument to -a - -shell.c - - if exec_argv0 is set, set dollar_vars[0] to it and set it to NULL, - assuming it was set by `exec -a'. `exec -a foo' now sets $0 to - foo in an executable shell script without a leading `#!' (fixes - longstanding bug) - - 2/8 - --- -variables.c - - in push_func_var, if a variable is in a special builtin's temporary - environment and needs to be propagated because we're in Posix mode, - or we just need to propagate a variable, and we are executing in a - function without any local variables (so the function-local variable - context has no variable hash table), make sure we create a hash - table so we have a place to save the variable to be propagated. - Fixes bug reported by Crestez Dan Leonard . - - 2/18 - ---- -builtins/hash.def - - change add_hashed_command to remove the command being looked up from - the hash table before trying to add it. That way, if it's not found, - there won't be anything remaining in the hash table - - 2/26 - ---- -trap.[ch] - - move IMPOSSIBLE_TRAP_HANDLER define to trap.h so other parts of the - shell can use it - -parse.y - - change yy_readline_get to use IMPOSSIBLE_TRAP_HANDER instead of NULL - as a sentinel value for the SIGINT signal handler - - make sure yy_readline_get resets interrupt_immediately to 0 after - calling readline() using the same criteria it used to set it to 1 - before the call -- make the code symmetric. Suggested by Werner - Fink - -builtins/read.def - - move assignment to `retval' before decrement of interrupt_immediately - and terminate_immediately and call to discard_unwind_frame - - move assign_vars label before decrement of interrupt_immediately and - terminate_immediately so those variables get reset appropriately - if read -t times out - -subst.h - - new define for Q_DOLBRACE, indicates double-quoted ${...} - -subst.c - - in parameter_brace_expand, before calling parameter_brace_expand_rhs, - add Q_DOLBRACE to `quoted' if we're within double quotes. - - in expand_word_internal, if the Q_DOLBRACE flag is set, remove a - backslash escaping a }. Result of a Posix discussion on the - austin-group list - - 2/27 - ---- -variables.c - - new functions to save and restore the PIPESTATUS variable's internal - array: save_pipestatus_array and restore_pipestatus_array - -variables.h - - new extern declarations for save_pipestatus_array and - restore_pipestatus_array - -trap.c - - in run_pending_traps, _run_trap_internal, and run_exit_trap, save - and restore $PIPESTATUS while traps are running. Fixes bug - reported by Florian Bruhin - -parse.y - - use save_pipestatus_array and restore_pipestatus_array in - save_parser_state and restore_parser_state, respectively, replacing - inline code - -lib/readline/histfile.c - - fix callers of history_filename to be prepared to cope with it - returning NULL - - change history_filename to return NULL if $HOME is not set, rather - than trying to write the history file in the current directory. - This is the default directory, used only if the application does - not specify a history filename. Changed due to long-ago (unsent) - bug report from OpenBSD - -{Makefile,config.h,configure}.in,externs.h,lib/sh/{dprintf.c,Makefile.in} - - change fdprintf to dprintf, which is the Posix standard interface, - look for it with configure, replace it if not available - - 2/28 - ---- -command.h - - add new subshell flag, SUBSHELL_RESETTRAP. Indicates to the trap - builtin that the shell is executing a command substitution and - should free the trap strings we left unfreed by reset_signal_handlers() - -trap.c - - free_trap_string() and free_trap_strings() are now compiled in - -builtins/trap.def - - if changing a signal disposition and the SUBSHELL_RESETTRAP flag is - set in subshell_environment, free the trap strings left unfreed by - reset_signal_handlers - -subst.c - - in command_substitute, set the SUBSHELL_RESETTRAP flag. This change - is for Austin Group Posix interpretation 53 - (http://austingroupbugs.net/view.php?id=53) - - 3/7 - --- -lib/sh/{Makefile.in,strchrnul.c},Makefile.in - - implementation of strchrnul, from gnulib - -configure.in,config.h.in - - look for strchrnul and compile in version in lib/sh/strchrnul.c if - not available - - look for mbsnrtowcs and define HAVE_MBSNRTOWCS if available - -lib/sh/xmbsrtowcs.c - - new function, xdupmbstowcs2, fast version of xdupmbstowcs used when - mbsnrtowcs is available and the indices are not required. Called - from xdupmbstowcs as required. Initial patch from - <0xe2.0x9a.0x9b@gmail.com> - - 3/22 - ---- -print_cmd.c - - call print_deferred_heredocs virtually every time a recursive call - to make_command_string_internal is made so here documents get - printed correctly when they are attached to commands inside compound - commands such as for and while. Fixes bug reported by Mike - Frysinger - - 3/25 - ---- -builtins/printf.def - - fix have_precision case in PF macro to call printf with precision - instead of fieldwidth argument. Fixes bug reported by Rob Robason - - - 3/26 - ---- -trap.[ch] - - new function, signal_is_hard_ignored, returns true if the shell - inherited SIG_IGN as a signal's disposition - - new function, set_original_signal (sig, handler), provides interface - for rest of shell to set original_signals[sig] = handler - -execute_cmd.c - - execute_disk_command needs to call reset_terminating_signals in the - child process before resetting traps with restore_original_signals - -builtins/trap.def - - call initialize_terminating_signals before calling display_traps for - trap -p or trap without any other arguments. Possible future use - -lib/readline/complete.c - - rl_filename_completion_function needs to call - rl_filename_dequoting_function with `dirname' (which has already - been tilde-expanded) instead of `users_dirname', because it calls - opendir with `dirname'. Fixes bug reported by Stefan H. Holek - - - 3/27 - ---- -sig.c - - experimental change to set_signal_handler: when setting the SIGCHLD - handler, set the SA_RESTART flag so that interruptible system calls - get restarted after a child dies. Fixes bug reported by Tomas - Trnka , but needs further evaluation - -lib/sh/eaccess.c - - eaccess(2) apparently does only half the job: it does not check that - the permission bits on a file actually allow, for instance, execution. - Need to augment with a call to sh_stataccess if eaccess returns - success on FreeBSD. Fixes FreeBSD problem reported by Johan Hattne - - - 3/28 - ---- -parse.y,bashline.c,externs.h - - history_delimiting_chars now takes a const char * as an argument: - the line being added to the history. Changed callers - -parse.y - - bash_add_history should not add a semicolon separator if the current - history entry already ends in a newline. It can introduce syntax - errors (e.g., when it results in a null command before a close brace). - Fixes bug reported by Andreas Schwab - -parse.y - - history_delimiting_chars needs to return a newline instead of a - semicolon if it thinks the current line starts a here document - (if it contains `<<'). Also keeps track of the fact with a new - static variable, LAST_WAS_HEREDOC, so it can return the right - sequence of newlines later for the here-document body. Fixes bug - reported by Andreas Schwab - - 3/29 - ---- -lib/sh/eaccess.c - - if the system has faccessat, sh_eaccess will now use it in - preference to all other options - - 3/30 - ---- -subst.h - - new string_extract and extract_dollar_brace_string flag value: - SX_POSIXEXP, set if the shell is expanding one of the new Posix - pattern removal word expansions - -parser.h - - new definitions for "word expansion state", shared between parse.y - and subst.c - -subst.c - - include parser.h - - 4/9 - --- -builtins/declare.def - - make sure declare_internal calls bind_assoc_variable with newly- - allocated memory for the key argument when using an implicit key - of "0". Bug report and fix from Andreas Schwab - - - 4/14 - ---- -lib/readline/input.c - - restructure the rl_event_hook loop in rl_read_key to call the - event hook after rl_gather_tyi() returns and rl_get_char has - a chance to collect the input. Previous behavior was to call - the event hook before attempting to read input. Problem - reported by Anant Shankar - - 4/15 - ---- -builtins/fc.def - - fc_builtin needs to check whether the calculation of last_hist - leaves hlist[last_hist] == 0, and keep decrementing it until it - leaves a non-null history entry or goes < 0. Currently only - does this if saved_command_line_count > 0, indicating we're - trying to edit a multi-line command. Fixes bug reported by - Roman Rakus - - 4/17 - ---- -subst.c - - new process substitution helper functions: - unlink_fifo - closes a single FD or FIFO - num_fifos - returns number of open FDs or active FIFOs - copy_fifo_list - returns a bitmap of open FDs or active FIFOs - by index into appropriate list (dev_fd_list or fifo_list) - close_new_fifos - take a bitmap saved by copy_fifo_list and - call unlink_fifo on any FD or FIFO open at the time of the - call that is not marked as active in list - -execute_cmd.c - - execute_builtin_or_function: use new framework to close process - substitution FDs or FIFOs created by a shell builtin or shell - function. Fixes bug reported by Charles Duffy - -doc/{bash.1,bashref.texi} - - document 'C and "C constants for printf builtin - - 4/22 - ---- -lib/readline/complete.c - - new function to return screenwidth for use when displaying possible - matches: complete_get_screenwidth; changed uses of _rl_screenwidth - to use complete_get_screenwidth(). - - change complete_get_screenwidth to query (readline-private) - _rl_completion_colums, $COLUMNS, then _rl_screenwidth in that order - - change rl_display_match_list to deal with limit < 0 (which implies - that cols == 0) when _rl_screenwidth > 0 - -lib/readline/bind.c - - new bindable variable: completion-display-width, controls the - number of columns used when displaying completions with new - sv_compwidth function to call when value is set or unset - -lib/readline/doc/{readline.3,rltech.texi} - - documented completion-display-width variable - - 4/23 - ---- -execute_cmd.c - - change execute_in_subshell to reset trap handlers without freeing - the trap strings and set SUBSHELL_RESETTRAP. In line with Austin - Group interp #53 (trap in a subshell). - - ditto for execute_simple_command where it can be determined that - the shell is going to run a builtin or function in a subshell - -trap.c - - new function, get_all_original_signals, retrieves the original - signal disposition for all signals - -trap.h - - extern declaration for get_all_original_signals - -builtins/trap.def - - change showtrap to display signals that are "hard ignored" as - trap commands to ignore them, even though that trap command would - be a no-op. Partial fix for feature request from Siddhesh - Poyarekar - - change trap_builtin to call get_all_original_signals before displaying - traps. This will show inherited ignored signals. Rest of feature - request from Siddhesh Poyarekar - -lib/readline/histexpand.c - - fix history_tokenize_word so that it understands $(...) and the - <(...) and >(...) expansions as a single word - - change history_tokenize_word so that it understands extended shell - globbing patterns as a single word. Code is very similar to - $(...) code above. Bug reported by Rajeev V. Pillai - - - 4/24 - ---- -lib/readline/vi_mode.c - - add checks to rl_vi_char_search to make sure we've already done a - search if the command is `;' or `,', and return immediately if we - have not. Fixes bug reported by Eric Ho - -lib/readline/text.c - - make sure `dir' is in the valid range before searching in - _rl_char_search_internal. Range checks in the code depend on it - being non-zero - - 5/3 - --- -lib/readline/complete.c - - in rl_complete_internal, if show-all-if-ambiguous or - show-all-if-unmodified are set (what_to_do == '!' or '@', - respectively), and the common match prefix is shorter than the - text being completed, inhibit inserting the match. - The guess is that replacing text with a shorter match will not - be wanted - - 5/20 - ---- -lib/sh/unicode.c - - new file, with unicode character conversion-related code. Will be - used to implement \u and \U escapes where appropriate, and for - other unicode-related functions in the future - - 5/21 - ---- -builtins/printf.def - - add code to handle \u and \U escapes in format strings and arguments - processed by the %b format specifier - -lib/sh/strtrans.c - - add code to handle \u and \U escapes as unicode characters, works for - both `echo -e' and $'...' - -doc/{bash.1,bashref.texi} - - document new \u and \U escape sequences for $'...' and echo (printf - defers to the system's man page or Posix) - - 5/24 - ---- -execute_cmd.c - - change execute_disk_command to return a status, instead of just - leaving it in `last_command_exit_value', since the parent's return - value is sometimes used (e.g., when a restricted shell refuses to - run a command with a `/'). Fixes bug reported by David Pitt - - - 5/25 - ---- -bashline.c - - change bash completion functions to save and restore the value of - rl_ignore_some_completions_function, and set it to the bash default - of filename_completion_ignore where appropriate. Fixes bug - reported by Henning Bekel - -variables.c - - new convenience function: find_global_variable (name). Looks for - NAME in the global variables table, skipping any local and - temporary environment variables - -builtins/declare.def - - add new -g option to declare/typeset/local, forces variables to be - created or modified at the global scope when executing inside a - shell function. Requested by many, most recently by - konsolebox@gmail.com - - 5/27 - ---- -test.c - - added new `-v var' unary test operator; returns TRUE if var is set - (i.e., has been assigned a value). Works in both test builtin and - [[ conditional command - -doc/{bash.1,bashref.texi} - - documented new `-v var' unary conditional operator - -tests/test.tests - - added tests for new -v var operator - -builtins/kill.def - - change kill builtin so -PID (pgrp specification) following a - -s sig or -n sig option is not interpreted as a signal specification. - Fixes bug reported by Roman Rakus - -builtins/evalstring.c - - in parse_and_execute, if parse_command() returns non-zero, - indicating a parse error, exit the shell if the conditions require - a posix-mode non-interactive shell to abort (parse error in a `.' - script or eval string). Bash-4.1 only printed a warning. This is - from Austin Group interp 114 - -doc/bashref.texi - - add note to the posix mode section of the texinfo manual noting - the changed behavior for `.' and `eval' - -parse.y - - change time_command_acceptable to allow TIME token to appear after - BANG token (to allow `! time foo', which is supposed to be valid) - - change pipeline_command production to allow multiple instances of - `!' (which toggle inverting the return status) and `time' (which - have no effect) - -execute_cmd.c - - In posix mode, `time' without a following pipeline prints the - elapsed user, system, and real time for the shell and its - children since the shell was invoked. - It's like `times' but obeys the setting of TIMEFORMAT. A future - revision of Posix will require this - -doc/{bashref.texi,bash.1} - - document new posix mode use of `time' - -parse.y - - add production to pipeline_command that permits `!' by itself to - be equivalent to `false' (and, with the changes above, permits - `! !' to be roughly equivalent to `true'). A future revision of - Posix will require this - - 5/28 - ---- -parse.y - - fix \W prompt expansion to use memmove instead of strcpy, since the - source and target strings overlap (though you think it wouldn't - matter, since the overlapping regions are never touched at the same - time). Fixes bug reported by Stéphane Jourdoi - - -parse.y - - Posix interp 217 states that $(( must be parsed first as an - arithmetic expansion, so avoid attempting to parse it as a nested - command substitution. Fixes bug reported by several, most recently - - -subst.c - - change extract_delimited_string to process nested $( as a possible - command substitution, but only if already parsing an arithmetic - expansion. Rest of fix for Posix interp 217 - - change parameter_brace_expand_rhs to make the := expansion operator - perform quote removal and both assign the result to the variable and - return it as the result of the expansion, rather than assign the - value after quote removal but return the value before quote removal. - Posix interp 221 - - introduce new internal quoting flag: Q_DOLBRACE. Denotes a double- - quoted ${...} expansion. In this case, Posix interp 221 requires - that a backslash quoting an embedded `}' be removed, even though it's - not one of the characters marked as special inside double quotes. - Set in parameter_brace_expand, used by expand_word_internal. - -parse.y - - introduce new parsing state, P_DOLBRACE, set when parsing a ${...} - expansion - - set a "dolbrace operator state" in parse_matched_pair to decide - whether the lexer is reading the param, op, or word in - ${paramOPword}. Will be used to decide whether or not to treat - single quotes specially in a double-quoted "${...} - - 5/29 - ---- -parse.y - - change parse_matched_pair so that a single quote appearing in a - double-quoted ${...} expansion is not special unless the expansion - operator is `#[#]' or `%[%]'. Posix interp 221 - -subst.c - - change string_extract_double_quoted so that a single quote appearing - in a double-quoted ${...} expansion is not special unless the - expansion operator is `#[#]' or `%[%]'. Posix interp 221 - -doc/bashref.texi - - document posix-mode effects of Posix interp 221 - - add section describing GNU parallel as requested by Stallman - -lib/readline/complete.c - - broke code that compares filenames read from the file system (and - possibly converted) to words being completed out into a separate - function: complete_fncmp - - augment complete_fncmp to treat hyphen and underscore as equivalent - when comparing filenames if _rl_completion_case_map is set - -lib/readline/rlprivate.h - - new extern declaration for _rl_completion_case_map - -lib/readline/util.c - - change _rl_strnicmp to return the difference between the characters, - like strcasecmp, and not modify the pointers it is passed - - change _rl_stricmp to not modify the pointers it is passed - -lib/readline/bind.c - - new bindable variable, "completion-case-map", toggles value of - _rl_completion_case_map - -lib/readline/doc/{rluser.texi,readline.3} - - document new bindable readline variable "completion-case-map" - -execute_cmd.c - - change execute_function to reset funcnest and jump back to top level - if funcnest exceeds funcnest_max - - use funcnest_max as a max function nesting level, if set to numeric - value greater than 0 (defaults to 0, so inactive) - -variables.c - - new variable FUNCNEST, controls funcnest_max value if set to numeric - value > 0 -sig.c - - reset funcnest to 0 when throw_to_top_level occurs - -doc/{bash.1,bashref.texi} - - document FUNCNEST variable and its effect on function execution - -lib/readline/funmap.c - - add new bindable command names to avoid case-insensitive matching - problems between, for instance, vi-fword and vi-fWord: - - vi-forward-word - vi-forward-bigword - vi-backward-word - vi-backward-bigword - vi-end-word - vi-end-bigword - - Suggested in a different form in 2006 (!) by Servatius Brandt - - -builtins/mapfile.def - - run_callback now takes a new third argument: curline, the line - currently being read and about to be assigned - - the callback function/command now takes an additional argument: - the line to be assigned to the array index. Feature suggested by - Dennis Williamson - -doc/{bash.1,bashref.texi} - - document new additional `line' argument to mapfile callback - - 5/30 - ---- -builtins/printf.def - - add new %(fmt)T format specifier, where FMT is a strftime format. - Argument is number of seconds since the epoch, with -1 meaning - current time (roughly date +%s) and -2 meaning shell start time - (roughly $SECONDS, unless it's been assigned a value or unset). - Fieldwidth and precision are preserved, strftime result is printed - as with %[-][[fieldwidth][.[precision]]]s - -doc/{bash.1,bashref.texi} - - document new %(datefmt)T printf format specifier and special - arguments - -builtins/hash.def - - don't permit programs with slashes to be entered into the hash table - at all, even with the -p option. Inconsistency pointed out by - Jan Schampera - -builtins/shopt.def - - add `compat41' option in preparation for bash-4.2 - - 6/6 - --- -lib/readline/vi_mode.c - - finish restructuring rl_vi_domove and the functions that call it so - it works in callback mode, including numeric arguments. Requested - a long time ago by Bob Rossi - -lib/readline/callback.c - - arrange to call appropriate callback when readline state indicates - RL_STATE_VIMOTION, so vi motion commands like `cw' and `d2w' are - handled in callback mode - -lib/sh/wcswidth.c - - replacement wcswidth implementation - -aclocal.m4 - - add REPLACE_FUNCS(wcswidth) to BASH_CHECK_MULTIBYTE - -execute_cmd.c - - fix select_query and print_index_and_element to compute correct - display width of select list elements in presence of multibyte - characters. Bug reported by Bernd Eggink - -builtins/cd.def - - add posix-mandated -e option; currently ignored in most circumstances - -doc/{bash.1,bashref.texi} - - document new `cd -e' option - - 6/12 - ---- -arrayfunc.c - - change array_value_internal to treat negative subscripts to indexed - arrays, offset from array_max_index(x) + 1, so foo[-1] is the last - element of $foo - -subst.c - - Change verify_substring_values to allow negative length specifications - when using string variables or array members. Negative lengths - mean to return characters from OFFSET until (${#var} - N) for - {var:offset:-N}. Feature requested by Richard Neill - - -doc/{bash.1,bashref.texi} - - document new behavior of negative subscripts to indexed arrays - - document new behavior of negative LENGTH in substring expansion - -configure.in - - change version to bash-4.2-devel - -variables.c - - make sure initialize_shell_variables calls sv_xtracefd if - BASH_XTRACEFD is inherited in the shell environment. Fixes but - reported by - - 6/13 - ---- -lib/readline/complete.c - - change get_y_or_n to always return 1 when in callback mode, so we - don't do a blocking read. Have to wait until readline-7.0 to add - a state so we can use callbacks, since that will change public - interface - - 6/17 - ---- -subst.c - - fix memory leak in parameter_brace_expand: when performing pattern - removal with parameter_brace_remove_pattern, make sure `name' is - freed. Fixes bug reported by oyvindh@dhampir.no - - 6/23 - ---- -{parse.y,subst.c} - - make the ${param//pat/rep}, ${param^pat}, and ${param,pat} expansions - require single quotes and double quotes to match when within double - quotes. This way every expansion except the Posix ones behaves as - bash has always behaved - -subst.c - - change remove_upattern and remove_wpattern to return their first - argument if nothing matches, change callers to allocate memory - appropriately - - change remove_pattern to short-circuit and return copy of PARAM - if remove_wpattern returns its first argument (indicating no match) - rather than convert back to multibyte string, allocating new memory - twice and calling wcsrtombs - - 6/24 - ---- -execute_cmd.c - - add missing initializers for sh_coproc to eliminate a compiler - warning. Patch from Werner Fink - - 6/27 - ---- -parse.y - - add `TIMEIGN' token to handle `time -p -- ...'. Pointed out by - Laszlo Ersek on austin-group list - - 6/28 - ---- -jobs.c - - treat a shell with (subshell_environment&SUBSHELL_PIPE) != 0 like - a command substitution in wait_for and act like we received a - SIGINT if a job we're waiting for dies of SIGINT. Fixes bug - reported by Ilya Basin - - 7/2 - --- -jobs.c - - if fork() fails in make_child, try to reap some dead children before - retrying - -execute_cmd.c - - change execute_pipeline to run the last command of a non-asynchronous - pipeline in the current shell environment if the `lastpipe' shell - option is enabled and job control is not active. Code from - Werner Fink - -parse.y - - Posix says (issue 267) that time is not recognized as a keyword - if the next token begins with a `-' - -doc/{bash.1,bashref.texi} - - changed the descriptions of BASH_SOURCE, BASH_LINENO, and FUNCNAME - as proposed in Ubuntu bug 591677. - - document new `lastpipe' shell option that runs last command of a - pipeline in the current shell environment - - document new posix-mode behavior with `time -p' - - 7/5 - --- -aclocal.m4 - - new autoconf test WEXITSTATUS_OFFSET, bit offset in status word - returned by wait() of the process's exit status - -jobs.[ch] - - change stop_pipeline to return the actual index of the job just - created and added to the jobs table, instead of the current job - - job_exit_status and job_exit_signal are now global functions, with - extern declarations in jobs.h - - append_process: new utility function for use by the lastpipe code, - takes info, creates a PROCESS from them, and adds it to the end of - the passed job id's pipeline. lastpipe code uses it to add a dummy - process for the last command in the pipeline - - freeze_jobs_list: new utility function so rest of shell can freeze - the jobs list. Used by the lastpipe code - -execute_cmd.c - - changes to lastpipe code to make `pipefail' option, $PIPESTATUS, and - $? work correctly. Uses append_process and job_exit_status - - 7/10 - ---- -subst.c - - when performing pattern substitution word expansions, a `&' in the - replacement string is replaced by the text matched by the pattern. - The `&' can be quoted with a backslash to inhibit the expansion. - CURRENTLY DISABLED - - 7/13 - ---- -pcomplib.[ch] - - new member for struct compspec: lcommand. for future use - - 7/15 - ---- -parse.y - - fix problem in parse_comsub where extra space was added to here-doc - delimiter if the first word in the comsub contained a `/'. Fixes - bug reported by Alex Khesin - - 7/20 - ---- -parse.y - - change reserved_word_acceptable to return success if the last two - tokens read were `function WORD'. Allows function definitions like - function good [[ -x foo ]];. Fixes bug reported by Linda Walsh - - -doc/{bash.1,bashref.texi} - - change function definition meta-syntax to make it clearer, rather - than let the text note the optional portions - - 7/24 - ---- -bashhist.c - - change bash_history_inhibit_expansion() to suppress history expansion - for $! parameter expansion. Fixes debian bug #589745 submitted by - Frank Heckenbach - -lib/readline/terminal.c - - change rl_resize_terminal to always fetch the new terminal size and - only force the redisplay if _rl_echoing_p is non-zero. Fixes bug - reported by Balazs Kezes - - 7/25 - ---- -lib/readline/xfree.c - - new file, contains definition of xfree moved from xmalloc.c - - 7/28 - ---- -variables.c - - check suspect return values from bind_variable before trying to use - the returned SHELL_VAR *. Changes to: initialize_shell_variables, - bind_int_variable, FIND_OR_MAKE_VARIABLE. Fixes bug reported by - Roman Rakus - - 7/31 - ---- -lib/readline/rltty.c - - fix rl_prep_terminal and rl_deprep_terminal to use fileno(stdout) - if rl_instream is NULL. Fixes bug reported by Otto Allmendinger - otto.allmendinger@googlemail.com - - 8/2 - --- -lib/sh/casemod.c - - if the passed string is NULL or empty, return it immediately. Fixes - bug reported by Dennis Williamson - -subst.c - - fix pat_subst to cope with the passed string being NULL - -arrayfunc.h - - added flag values for array_value_internal and its callers; converted - array_value_internal `allow_all' parameter into a general flags word - - get_array_value now takes a flags value - - changed array_value internal to use *indp as an index to use if the - AV_USEIND flag is set, rather than recomputing it - -subst.c - - get_var_and_type takes two new parameters: a flags word and an index - that represents an already-computed index for an array reference - (just indexed arrays so far). Index is used and passed to array_value - if flags includes AV_USEIND - - parameter_brace_expand_word takes a new argument: the already- - computed index; returns W_ARRAYIND if word expanded is being used - as an array index - - changed parameter_brace_casemod, parameter_brace_patsub, - parameter_brace_substring, parameter_brace_remove_pattern to take new - flags and index arguments from parameter_brace_expand_word. They - pass the new parameters along to get_var_and_type to use an - already-computed array index if necessary. Fixes bug where array - indexes are computed twice reported by Andrew Benton - - -doc/bash.1,lib/readline/doc/{history.3,hsuser.texi} - - modified description of history event designators to clarify that - all non-absolute event designators are relative to the current - position in the history list. Question raised by Frank - Heckenbach as debian bash bug 590012 - - 8/5 - --- -subst.c - - remove code that does not add a quoted null when the input string - is partially quoted; subsequent word splitting may require it. - Fixes bug reported by Eric Blake - - 8/12 - ---- -lib/glob/gmisc.c - - move match_pattern_wchar and match_pattern_char to new file in - glob library - - new functions: wmatchlen(pat, max) and umatchlen(pat, max), computes - number of characters PAT will match. Returns the number of chars - that will be matched or -1 if the match length is indeterminate - (i.e., contains a `*') - -subst.c - - use umatchlen/wmatchlen in match_upattern/match_wpattern to bound - the number of match attempts in large strings to (usually) one, - depending on match length. Fixes performance problems with - pattern substitution in large strings noted by Yi Yan - . Can be applied to remove_[uw]pattern also - - 8/13 - ---- -bashhist.c - - in maybe_append_history, change check for history_lines_this_session - so that we append the lines to the file if it's equal to the value - returned by where_history(). This means that without this change, - the history won't be appended if all the lines in the history list - were added in the current session since the last time the history - file was read or written. Fixes bug reported by Bruce Korb - - -shell.h,parse.y - - add prompt_string_pointer to the parser_state struct saved and - restored by {save,restore}_parser_state. Fixes both bugs exposed - by bash_completion and completion of open backquotes reported by - Egmont Koblinger - -subst.h - - new flag for skip_to_delim: SD_EXTGLOB. Skip extended globbing - patterns while looking for ending delimiter - -subst.c - - when passed the SD_EXTGLOB flag, skip_to_delim skips over extended - globbing patterns (when extended_glob is set) while looking for a - character in the delimiter set - -pathexp.c - - split_ignorespec: new function to replace calls to extract_colon_unit - in setup_ignore_patterns. uses skip_to_delim with the SD_EXTGLOB - flag to skip over extended globbing patterns in variables like - HISTIGNORE and GLOBIGNORE. Fixes bug reported by Dimitar DIMITROV - and Greg Wooledge - - 8/28 - ---- -lib/readline/rlprivate.h - - add members to search_cxt to save _rl_keymap - - new flag for isearch context: SF_CHGKMAP, set if we changed the - keymap while reading a character for the search string that - translated to a command - -lib/readline/isearch.c - - save current readline keymap in cxt->keymap and cxt->okeymap - in _rl_scxt_alloc - - in _rl_isearch_dispatch, only check for cxt->lastc as a member of - cxt->search_terminators if it's > 0 (i.e., not an isearch opcode) - - 9/3 - --- -support/signames.c - - add Solaris SIGJVM1 and SIGJVM2. Update from Stefan Teleman - - -shell.c - - instead of closing all fds 3-20 at shell startup, just set them to - be close-on-exec. Report from Rainer Mülle - -lib/readline/isearch.c - - in _rl_isearch_dispatch, if the current character maps to ISKMAP, - move to the indicated keymap (using cxt->keymap) and go on to - read another character. Fixes problem reported by Davor - Cubranic - - in _rl_isearch_dispatch, after translating key to possible opcode, - restore _rl_keymap from cxt->okeymap if necessary - - in _rl_isearch_dispatch, use key sequences that map to default - functions that ^G, ^W, and ^Y map to as equivalent to those chars - -lib/readline/complete.c - - new variable, _rl_menu_complete_prefix_first, zero by default - - change menu_complete to display common prefix (matches[0]) first - before cycling through rest of match list if - _rl_menu_complete_prefix_first is non-zero. Suggested by Sami - Pietila - -lib/readline/bind.c - - new bindable readline variable, "menu-complete-display-prefix", - controls setting of _rl_menu_complete_prefix_first - -doc/{bash.1,bashref.texi},lib/readline/doc/{readline.3,rluser.texi} - - added description of menu-complete-display-prefix bindable - readline variable - - 9/17 - ---- -configure.in - - remove AM_PATH_LISPDIR call since we don't use that bash debugger - any more. Suggested by Mike Frysinger - - 10/6 - ---- -findcmd.c - - change executable_file to set errno to EISDIR if the passed name - is a directory - -builtins/exec.def - - change exec_builtin to report appropriate error message if the - file argument is a directory. Noted by Eric Blake - in a message to austin-group - -builtins/source.def - - change source_builtin to make sure the shell exits if the file is - not found when in a non-interactive shell running in posix mode - and source_searches_cwd == 0 (as posix mode makes it by default). - Pointed out in http://thread.gmane.org/gmane.comp.shells.dash/291/focus=392 - by Jilles Tjoelker - -execute_cmd.c - - set executing_command_builtin in execute_builtin if the builtin is - command_builtin. Unwind-protected in execute_function_or_builtin - (like executing_builtin variable). Available for rest of shell - -builtins/{source.def,evalfile.c} - - make sure that non-interactive posix mode shells exit if the file - argument to `.' is not found only if they are not being executed - by the command builtin (executing_command_builtin == 0). This is - how `command' can cancel effects of special builtin exit properties - in the case of `dot file not found' - - 10/13 - ----- -lib/sh/strtrans.c - - pass \c through unchanged if not escaping for `echo -e' and they are - the final two characters in the string - - 10/15 - ----- -subst.c - - extract_dollar_brace_string: fix problem with single quotes - in unquoted ${...} for Posix compliance - - 10/16 - ----- -builtins/exec.def - - catch return value from shell_execve; don't print duplicate error - message if return value is EX_NOTFOUND. Make sure exit status - from exec is 127 if command is not found - -execute_cmd.c - - fix typo (`saved_redirects' should be `saved redirects') in - execute_function_or_builtin `command exec' case. Typo caused - too much of the unwind-protect stack to be discarded - - in same execute_function_or_builtin case, don't discard the - `saved redirects' frame unconditionally; only discard it if - saved_redirects is non-null in the `command exec' case. Fixes - sh -c 'command exec; exit 1' hanging bug uncovered by FreeBSD - sh test cases - - 10/18 - ----- -subst.c - - when in posix mode, shell should not exit if a variable assignment - error (e.g., assigning to readonly variable) occurs preceding a - command that is not a special builtin. Fixes bug uncovered by - FreeBSD sh test cases - - when in posix mode, the ${!?} and ${!#} expansions are not indirect - expansions, but posix word expansions involving the `!' variable - -parse.y - - fix parse_comsub so that it does not skip backslash-newline when - parsing a comment - - 10/19 - ----- -subst.c - - fix parameter_brace_expand so that an attempt to use the % or # - expansions on an unset variable with -u set will cause a non- - interactive shell to abort. Posix change - - fix parameter_brace_expand so that an attempt to use pattern - substitution or case modification expansions on an unset variable - with -u set will cause and unbound variable error and make a - non-interactive shell abort - - change parameter_brace_expand_length to return INTMAX_MIN if a - positional parameter is unset and -u is set - - if parameter_brace_expand_length returns INTMAX_MIN when -u is set, - treat it as an unbound variable error and make a non-interactive - shell abort. Posix change - - change parameter_brace_expand_length to return INTMAX_MIN if an - implicit reference to array[0] is made ${#array} and array[0] is - not set when -u is set - - 10/20 - ----- -builtins/cd.def - - Posix 2008 says that if no matching directories are found in $CDPATH, - use the directory name passed as an operand and go on. Posix change - -doc/bashref.texi - - change Posix mode section with latest additions and removals - - 11/4 - ---- -lib/readline/complete.c - - fix rl_menu_complete and rl_old_menu_complete to keep incrementing - match_list_index by match_list_size as long as it's < 0. Fixes - bug reported by jeenuv@gmail.com - -braces.c - - make mkseq() take intmax_t arguments for sequence start and end - and make sure it's passed intmax_t values. Fixes bug reported by - Pete Gregory - -sig.c - - if termsig_handler is called when terminate_immediately == 1, - assume we're being called as a signal handler and set - history_lines_this_session to 0 to inhibit history file being - written on shell exit. Fixes long-standing bug most recently - observed by Andreas Schwab - - 11/5 - ---- -redir.c - - add_undo_close_redirect now returns int, 0 on success, non-zero on - failure. Currently always succeeds - - new macro REDIRECTION_ERROR to make do_redirection_internal return - value of errno - - change do_redirection_internal to call REDIRECTION_ERROR after - saving file descriptor and make do_redirection_internal return error - if add_undo_redirect or add_undo_close redirect fails. This makes - failure to save a file descriptor a redirection error and the shell - behaves appropriately. Fixes bug reported by Eric Blake - - -bashline.c - - modify bash_forward_shellword to correctly handle quoted strings, - especially if point is in a quoted string when function is invoked. - Fixes bug reported by Daniel Colascione - -configure.in - - change version to 4.2-alpha - - 11/7 - ---- -lib/readline/text.c - - in rl_insert, if we're not in the multibyte code path, don't try to - optimize and insert all of the available typeahead input if we're - reading input from a macro. Fixes bug reported by Andre Majorel - - -lib/readline/text.c - - break out multibyte guts of rl_forward_char into a separate function - _rl_forward_char_internal that does nothing but calculate the new - value of point - - change rl_forward_char to call _rl_forward_char_internal instead of - having equivalent code inline - -lib/readline/rlprivate.h - - new extern declaration for _rl_forward_char_internal - -lib/readline/vi_mode.c - - change _rl_vi_append_forward to call _rl_forward_char_internal to - set rl_point, instead of calling rl_forward_char. When at the end - of the line, rl_forward_char will ring the bell. Fixes debian - bash bug 601042, reported by Alan J. Greenberger - - 11/14 - ----- -subst.c - - fix match_upattern to use correct test to immediately break out of - loop (when potential match length is greater than number of chars - remaining in the string) in MATCH_ANY case - - 11/15 - ----- -subst.c - - include "typemax.h" to make sure we have a definition of INTMAX_MIN - - 11/16 - ----- -lib/sh/unicode.c - - make sure `localconv' isn't declared on machines without iconv - - add stub_charset for systems that don't have locale_charset: looks - up LC_CTYPE, returns everything after last `.', "UTF-8" if the - value is exactly "UTF-8", and "ASCII" otherwise - - 11/20 - ----- -lib/readline/vi_mode.c - - in rl_domove_motion_callback, make sure to use m->key instead of - key, which is not initialized and should not be used. Bug report - from Andreas Schwab - - in rl_vi_domove, make assignment to `m' explicit instead of - relying on evaluation order semantics, since the C standard leaves - them unspecified. Bug report from Andreas Schwab - - - 11/21 - ----- -lib/sh/shquote.c - - sh_single_quote and sh_double_quote now take a const char * - argument. Fixes problem pointed out by Joachim Schmitz - - -externs.h - - change extern declarations for sh_single_quote and sh_double_quote - -lib/sh/strchrnul.c - - make sure that return value is cast to (char *) if we're using a - part of the passed (const char *) argument. Fixes problem pointed - out by Joachim Schmitz - -lib/glob/gmisc.c - - fix a typo that mixed up defines for LPAREN and RPAREN. Bug and - fix from Andreas Schwab - - use WLPAREN and WRPAREN in multibyte character environments - - fixed typos using L'cc' in a non-wide-char environment - -lib/readline/complete.c - - fix rl_filename_completion_function to dequote users_dirname if - there is a filename dequoting function (as well as dirname), since - users_dirname gets tacked back onto the beginning of the possible - completions and then requoted. Bug reported by Andreas Schwab - - - 11/22 - ----- -lib/readline/parens.c - - the `blink-matching-paren' variable should default to off - - 11/23 - ----- -subst.h - - add extern declaration for close_new_fifos() - -lib/sh/fnxform.c - - fix curencoding to return the character past the `.', not a string - beginning with `.' - -lib/sh/unicode.c - - fix stub_charset to do the same cut-off at `@' as curencoding(). - These two functions should be combined - -builtins/printf.def - - document new %(datefmt)T modifier in help text - - 11/24 - ----- -parse.y - - fix `W' case in decode_prompt_string: memmove was copying one too - few bytes and missed the closing NUL. Bug report from Tim Mooney - - - 11/26 - ----- -subst.c - - in expand_word_internal, don't add quoted nulls to partially- - quoted strings if the word will not be subjected to word splitting - later (which will remove the quoted null). Fixes bug reported by - Rocky Bernstein - - 11/28 - ----- -subst.c - - change multibyte case of match_pattern to revert to match_upattern - if neither the pattern nor the string has any multibyte characters - -alias.c - - fix tests of backslash-escaped characters in skipquotes, skipws, - rd_token to check for backslash at EOS and not go past the end. - Fixes debian bug 603696 reported by Tim Small - -include/shmbchar.h - - new file, mbchar.h from gnulib minus the include - -lib/sh/shmbchar.c - - new file, mbchar.c from gnulib with additions - - moved mbstrlen from subst.c to here, changed initialization of mbs - - change mbstrlen to use is_basic to avoid calls to mbrlen for ASCII - chars; code hints from gnulib - - don't copy mbs and mbsbak if we're not calling mbrlen - - 11/29 - ----- -lib/glob/smatch.c - - change xstrmatch to use internal_strmatch() if the pattern and - string don't have any multibyte characters - - 11/30 - ----- -include/shmbutil.h - - change ADVANCE_CHAR and ADVANCE_CHAR_P macros to use is_basic and - only call mbrlen and copy state and state_bak if is_basic returns - false (non-ASCII). Called all over the place. - - change rest of macros except BACKUP_CHAR and BACKUP_CHAR_P in the - same way - - 12/2 - ---- -subst.c - - audit all calls to string_list and make sure caller can handle a - NULL return value. Fixes bug reported by David Rochberg - - -general.h - - change sh_wassign_func_t to take an additional argument: an int - flags word - -subst.c - - change do_word_assignment to take an additional argument to match - wassign_func_t; change callers - - change call to (*assign_func) in expand_word_list_internal to match - new wassign_func_t prototype - - (*assign_func) passes 1 as additional arg if the simple command is - a builtin or function, in which case the assignment to the - temporary env should take effect - -variables.c - - change assign_in_env to take an additional argument to match - wassign_func_t; change callers - - move call to sv_ifs from dispose_temporary_env to - dispose_used_env_vars; we don't need to do it if called from - merge_temporary_env - - 12/3 - ---- -variables.c - - change dispose_temporary_env to maintain a list (tempvar_list) of - variables that need to be handled specially. If a variable that - gets freed by push_temp_var or propagate_temp_var is one of the - variables that the shell handles specially (IFS, LANG, etc.), it's - stored on the list. For each variable in this list, - dispose_temp_var calls stupidly_hack_special_variables. - - assign_in_env calls stupidly_hack_special_variables if flags arg - is non-zero, so variable assignments affect current shell - execution environment if a builtin or function is being executed. - Fixes bug reported by Bruno Haible - - 12/5 - ---- -subst.c - - use mbsmbchar on both string and pattern in match_pattern instead - of strlen and mbstrlen; only go through the strings once - - 12/6 - ---- -lib/readline/kill.c - - in rl_yank_last_arg, only switch directions if the `count' - argument is < 0, not < 1. This makes explicit count arguments of - 0 work as expected. Fixes bug reported by Dennis Williamson - - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - fix documentation for yank-last-arg to make it clear how the count - argument is set and how second and subsequent calls treat any - numeric argument - -doc/{bash.1,bashref.texi} - - slight changes to the description of test - - change \(bv to `|'; it seems that many `internationalized' versions - of groff don't render that as a vertical bar. Fixes Debian bug - 603805 - - 12/10 - ----- -configure.in - - changed release status to 4.2-beta - - 12/14 - ----- -[bash-4.2-beta frozen] - - 12/18 - ----- -redir.c - - change REDIRECTION_ERROR macro to accept a third argument: an - additional file descriptor to close before returning and error (pass - -1 to do nothing) - - change calls to REDIRECTION_ERROR to close appropriate file - descriptors. Fixes bug reported by Andreas Schwab - - - make sure to close any file descriptors opened for REDIR_VARASSIGN - before returning an error - - 12/19 - ----- -expr.c - - move processing of unary `-' and `+' to exp1 from exp0 to avoid - precedence problems. Fixes bug reported by <12bric@gmail.com> - - 12/22 - ----- -lib/sh/fpurge.c - - updated version from gnulib, inlined gnulib stdio-impl.h - - 12/24 - ----- -doc/bash.1 - - change the description of while and until to use `list-1' and - `list-2', similar to the Posix description. Suggested by - Jeff Haemer - - 12/27 - ----- -execute_cmd.c - - slight changes to execute_command_internal and how it captures the - exit status of (command) and shell control structures with pipes to - avoid multiple variable assignments to last_command_exit_value - - change to execute_simple_command so that parent branches of shells - forked to execute commands in pipelines don't change $? to 0 - (if (pipe_out != NO_PIPE) result = last_command_exit_value). Fixes - bug reported by Damien Nadà - - 12/28 - ----- -configure.in - - changed version to bash-4.2-rc1 - - 1/2/2011 - -------- -lib/readline/complete.c - - fix rl_filename_completion_function to dequote and save users_dirname - before calling any function to transform the directory name passed - to opendir(). Fix from Andreas Schwab - -lib/readline/doc/ - - make sure to note that rl_directory_completion_hook cannot modify - the directory name argument if it returns 0 - -bashline.c - - make sure that bash_directory_completion_hook consistently returns - non-zero whenever it modifies its directory name argument - -lib/readline/terminal.c - - don't bother with the declarations (extern or not) for PC, BS, and - UP if NCURSES_VERSION is defined, since ncurses defines local - versions of those symbols in the library. Fixes bug most recently - reported by Kevin Scott against Mac OS X - -include/filecntl.h - - make sure O_TEXT and O_BINARY are defined to avoid Windows-specific - (or cygwin-specific) code. This and the following changes from - Eric Blake for current cygwin systems - -input.h - - add a B_TEXT flag to note when the underlying file descriptor is - opened in O_TEXT mode - -lib/sh/tmpfile.c - - make sure temporary files are opened in binary mode (O_BINARY) on - systems where it matters - -input.c - - make sure to set the B_TEXT flag if the file descriptor has O_TEXT - in its flags (returned by fcntl) - - change b_fill_buffer to compensate for lseek() and read() returning - different offsets on files opened in O_TEXT mode - - cygwin now is able to lseek on files and set the unbuffered and text - flags appropriately, so can use the general test for a seekable fd - - now that cygwin uses O_TEXT or O_BINARY appropriately, we no longer - have to manually translate \r\n to \n - -redir.c - - remove the Cygwin-1.1 code from here_document_to_fd; cygwin is now - up to version 1.7 and can unlink an open file descriptor - - make sure temporary files used for here documents are opened in - binary mode (O_BINARY) on systems where it matters - -execute_cmd.c,parse.y - - make sure error messages use all printable characters in filenames - and strings - -{builtins/evalfile,shell,subst}.c - - remove cygwin-specific calls to setmode to force file descriptors - into text mode, since we're using text or binary mode according to - the mode of the mount point - -execute_cmd.c - - when creating pipes and making them stdin and stdout, make sure to - tell stdio that the mode of the underlying file descriptor may have - changed from text to binary - -subst.c - - when creating pipes for command substitution, make sure to - tell stdio that the mode of the underlying file descriptor may have - changed from text to binary - - 1/3 - --- -doc/{bash.1,bashref.texi} - - changes to the readonly documentation suggested by Jan Schampera - - - 1/4 - --- -builtins/read.def - - change bind_read_variable to consistently return NULL if there is some - kind of variable assignment error (e.g., assigning to a readonly or - noassign var) - - change read builtin to only call stupidly_hack_special_variables if - bind_read_variable returns non-NULL - - change read_builtin to return EXECUTION_FAILURE if there is an - assignment error (e.g., assigning to a readonly or noassign var). - Fixes bug reported by Jan Schampera - - 1/5 - --- -builtins/{help.def,common.c} - - change uses of a builtin's `short_doc' member to go through gettext - for possible translation before being displayed. Suggestion from - - - 1/6 - --- -shell.h - - new exit status define: EX_MISCERROR (2) - -builtins/getopts.def - - change getopts_bind_variable to return error if an attempt is made - to assign to a variable with the `noassign' attribute - - change getopts_bind_variable to return EX_MISCERROR if attempt is - made to assign to readonly or noassign variable - -builtins/cd.def - - change setpwd to return an int and return failure when PWD is - readonly; success otherwise - - change bindpwd to return failure if setpwd returns EXECUTION_FAILURE. - Inspired by message from Eric Blake - - change pwd builtin to return failure if PWD is readonly (and setpwd - returns EXECUTION_FAILURE) - - 1/8 - --- -lib/sh/eaccess.c - - on FreeBSD and Solaris, check the result of access(2) with mode X_OK - for root by checking sh_stataccess(). Same code as was added to - check result of eaccess(). Fixes Solaris 11 problem reported by - - - 1/10 - ---- -builtins/set.def - - add description of `--' to help text - -[bash-4.2-rc1 released] - - 1/14 - ---- -lib/readline/readline.h - - fix/update description of rl_directory_rewrite_hook - -lib/readline/complete.c - - if there are no directory rewrite or completion hooks, set dirname - to a duplicate copy of users_dirname instead of calling the - dequoting function again - -bashline.c - - use rl_directory_rewrite_hook instead of rl_directory_completion_hook - to avoid changing the directory name the user typed, other than - dequoting it. Fixes bug introduced by changes to directory - completion hook, pointed out first by William Bader - - - 1/16 - ---- -lib/sh/strftime.c - - portability and other (int->long) updates from Aharon Robbins - - -configure.in - - change release level to rc2 - - 1/17 - ---- -execute_cmd.c - - short-circuit select builtin if read_builtin returns anything but - EXECUTION_SUCCESS, not just EXECUTION_FAILURE. Fixes bug reported - by Pierre Gaston - - 1/19 - ---- -execute_cmd.c - - change execute_simple_command to save and restore the values of - executing_builtin and executing_command_builtin before discarding - the unwind-protect frame. Bug and fix from Werner Fink - - - 1/24 - ---- -variables.c - - change brand to set rseed to a known, constant value if it's 0, - so the sequence is known. Fixes issue reported by Olivier - Mehani - - 2/2 - --- -braces.c - - make sure to pass an `int' argument to asprintf in mkseq. Fixes - bug reported by Mike Frysinger - - 2/5 - --- -lib/glob/gmisc.c - - fix wmatchlen and umatchlen to initialize all state variables. Fix - from Andreas Schwab - -jobs.c - - change wait_for to call restore_sigint_handler right after exiting - the wait loop, instead of right before function returns. Reduces - the window for a SIGINT to be lost because a child does not exit - due to SIGINT - - 2/7 - --- -configure.in - - changed release status to `release' - - 2/9 - --- -execute_cmd.c - - make sure some variables are declared as volatile if necessary. Bug - report and fix from Eric Blake - -[bash-4.2 frozen] - - 2/11 - ---- -print_cmd.c - - in indirection_level_string, change to simpler test of result of - MBLEN (< 0 instead of MB_INVALIDCH) - - 2/14 - ---- -[bash-4.2 released] - - 2/15 - ---- -lib/glob/gmisc.c - - fix wmatchlen and umatchlen to avoid going past the end of the - string on an incomplete bracket expression that ends with a - NUL. Partial fix for bug reported by Clark Wang - - 2/16 - ---- -subst.h - - new string extract flag value: SX_WORD. Used when calling - extract_dollar_brace_string to skip over the word in - ${param op word} from parameter_brace_expand - -subst.c - - change parameter_brace_expand to add SX_WORD to flags passed to - extract_dollar_brace_string - - change parameter_brace_expand to use SX_POSIXEXP for all non-posix - word expansion operators that treat single quotes as special, not - just % and # - - change extract_dollar_brace_string to initialize dolbrace_state to - DOLBRACE_WORD if SX_WORD flag supplied and we shouldn't use - DOLBRACE_QUOTE. Fixes bug reported by Juergen Daubert - -doc/{bash.1,bashref.texi} - - document the exact expansions here strings undergo - - 2/17 - ---- -lib/readline/vi_mode.c - - make sure that `dd', `cc', and `yy' call vidomove_dispatch from - rl_domove_read_callback. Fixes bug reported by Clark Wang - - -lib/readline/callback.c - - make sure _rl_internal_char_cleanup is called after the - vi-motion callbacks (rl_vi_domove_callback) in rl_callback_read_char. - Companion to above fix - -doc/{bash.1,bashref.texi} - - make sure that the text describing the rhs of the == and =~ - operators to [[ states that only the quoted portion of the pattern - is matched as a string - - 2/18 - ---- -lib/glob/gmisc.c - - better fix for umatchlen/wmatchlen: keep track of the number of - characters in a bracket expression as the value to increase - matchlen by if the bracket expression is not well-formed. Fixes - bug reported by Clark Wang - -subst.c - - change expand_string_for_rhs so that it sets the W_NOSPLIT2 flag - in the word flags. We will not perform word splitting or quote - removal on the result, so we do not want to add quoted nulls if - we see "" or ''. Fixes bug reported by Mike Frysinger - - - 2/19 - ---- -variables.c - - new function, int chkexport(name), checks whether variable NAME is - exported and remakes the export environment if necessary. Returns - 1 if NAME is exported and 0 if not - - call chkexport(name) to get tzset to look at the right variable in - the environment when modifying TZ in sv_tz. Don't call tzset if - chkexport doesn't indicate that the variable is exported - -variables.h - - new extern declaration for chkexport - - -{parse.y,builtins/printf.def} - - call sv_tz before calling localtime() when formatting time strings - in prompt strings or using printf. Fixes bug reported by - Dennis Williamson - -execute_cmd.c - - modify fix of 2/9 to add casts when those variables are passed to - functions; some compilers throw errors instead of warnings. Report - and fix from Joachim Schmitz - -support/shobj-conf - - add a stanza for nsk on the Tandem from Joachim Schmitz - - -{shell,lib/readline/shell}.c - - Tandem systems should use getpwnam (getlogin()); for some reason - they don't do well with using getuid(). Fix from Joachim Schmitz - - - 3/1 - --- -variables.c - - make sure that the return value from find_variable is non-null - before trying to use it in chkexport. Fixes bug reported by - Evangelos Foutras - - 3/3 - --- -parse.y - - when adding $$ to the current token buffer in read_token_word(), - don't xmalloc a buffer for two characters and then strcpy it, just - copy the characters directly into the token buffer. Fix from - Michael Whitten - -execute_cmd.c - - fix expand_word_unsplit to add the W_NOSPLIT2 flag to the word to - be expanded, so "" doesn't add CTLNUL. Similar to fix of 2/18 to - expand_string_for_rhs. Fixes bug reported by Nathanael D. Noblet - and Matthias Klose - -parse.y - - fix extended_glob case of read_token_word to allocate an extra - space in the buffer for the next character read after the extended - glob specification if it's a CTLESC or CTLNUL. Report and fix from - Michael Witten - - fix shell expansions case of read_token_word to allocate an extra - space in the buffer for the next character read after the shell - expansion if it's a CTLESC or CTLNUL. Report and fix from - Michael Witten - - TENTATIVE: fix read_token_word to reduce the amount of buffer space - required to hold the translated and double-quoted value of $"..." - strings. Report and fix from Michael Witten - - change code around got_character and got_escaped_character labels to - make sure that we call RESIZE_MALLOCED_BUFFER before adding the - CTLESC before a CTLESC or CTLNUL, and before adding the character if - we're not adding a CTLESC. Report and fix from - Michael Witten - -subst.c - - new param flags value, PF_ASSIGNRHS, mirrors W_ASSIGNRHS, noting that - parameter expansion is on rhs of assignment statement. That inhibits - word splitting - - change param_expand to call string_list_dollar_at with quoted == 1 - if PF_ASSIGNRHS is set, so it will quote IFS characters in the - positional parameter before separating them with the first char of - $IFS. This keeps the rhs from being split inappropriately. Fixes - bug reported by Andres Perera - - 3/4 - --- -lib/readline/bind.c - - add a missing free of `names' in rl_function_dumper. Bug report - and fix from Michael Snyder - - 3/5 - --- -lib/readline/rltty.c - - change rl_deprep_terminal so it uses fileno (stdin) for the tty fd - if rl_instream is not set, like rl_prep_terminal - - 3/6 - --- -lib/readline/display.c - - fix rl_message to use a dynamically-allocated buffer instead of a - fixed-size buffer of 128 chars for the `local message prompt'. Bug - report and fix from Micah Cowan - - 3/7 - --- -jobs.c - - add sentinel to wait_sigint_handler so it only sets wait_sigint_received - if waiting_for_child is non-zero; otherwise, it restores the old - SIGINT handler and sends itself the SIGINT - - set waiting_for_child around the calls to waitchld that use it to - synchronously wait for a process - - change logic that decides whether or not the child process blocked - or handled SIGINT based on whether or not waitpid returns -1/EINTR - and the shell receives a SIGINT and the child does not exit. If - the child later exits due to SIGINT, cancel the assumoption that it - was handled - - instead of testing whether or not the child exited due to SIGINT - when deciding whether the shell should act on a SIGINT it received - while waiting, test whether or not we think the child caught - SIGINT. If it did, we let it go (unless the shell has it trapped); - if it did not catch it, the shell acts on the SIGINT. Fix from - Linus Torvalds , bug report originally - from Oleg Nesterov - - 3/8 - --- -shell.c - - initialize no_line_editing to 1 if READLINE is not defined -- we - can't have line editing without readline - - 3/12 - ---- -lib/readline/signals.c - - add SIGHUP to the set of signals readline handles - -lib/readline/doc/rltech.texi - - document that SIGHUP is now part of the set of signals readline - handles - -lib/readline/input.c - - if _rl_caught_signal indicates that read() was interrupted by a - SIGHUP or SIGTERM, return READERR or EOF as appropriate - - call rl_event_hook, if it's set, if call to read in rl_getc - returns -1/EINTR. If rl_event_hook doesn't do anything, this - continues the loop as before. This handles the other fatal - signals - -execute_cmd.c - - add a couple of QUIT; calls to execute_disk_command and - execute_simple_command to improve responsiveness to interrupts - and fatal signals - -input.c - - rearrange getc_with_restart so that the return values from read() - are handled right - -parse.y - - don't need to set terminate_immediately in yy_stream_get, since - getc_with_restart checks for terminating signals itself - - since readline returns READERR on SIGHUP or SIGTERM, don't need - to set terminate_immediately. Still doesn't handle other - signals well -- will have to check that some more - -bashline.c - - new function, bash_event_hook, for rl_event_hook. Just checks for - terminating signals and acts on them using CHECK_TERMSIG. - - set rl_event_hook to bash_event_hook - -builtins/read.def - - take out setting terminate_immediately; add calls to CHECK_TERMSIG - after read calls - -doc/{bash.1,bashref.texi} - - move the text describing the effect of negative subscripts used to - reference indexed array elements to the paragraphs describing - ${parameter[subscript]}, since that's where they are implemented. - Pointed out by Christopher F. A. Johnson - -arrayfunc.[ch],subst.c - - array_expand_index now takes a new first argument: a SHELL_VAR * - of the array variable being subscripted. Can be used later to fully - implement negative subscripts - - 3/14 - ---- -lib/glob/glob.c - - fix mbskipname to not turn the directory entry name into a wide char - string if the conversion of the pattern to a wide char string fails - - fix mbskipname to call skipname if either the pattern or the filename - can't be converted into a wide-char string - -lib/glob/xmbsrtowcs.c - - fix xdupmbstowcs2 to handle return value of 0 from mbsnrtowcs and - short-circuit with failure in that case. Fixes bug reported by - Roman Rakus - - 3/15 - ---- -bashline.c - - new variable, bash_filename_quote_characters to store the value - assigned to rl_filename_quote_characters so it can be restored - if changed. - - change bashline_reset and attempt_shell_completion to restore - rl_filename_quote_characters if not set to default - - 3/22 - ---- -lib/glob/glob.c - - wdequote_pathname falls back to udequote_pathname if xdupmbstowcs - fails to convert the pathname to a wide-character string - -lib/glob/xmbsrtowcs.c - - xdupmbstowcs2: change to fix problem with leading '\\' (results in - nms == 0, which causes it to short-circuit with failure right - away). Fixes bug pointed out by Werner Fink - - xdupmbstowcs2: compensate for mbsnrtowcs returning 0 by taking the - next single-byte character and going on - - xdupmbstowcs2: change memory allocation to increase by WSBUF_INC - bytes; try to avoid calls to realloc (even if they don't actually - result in more memory being allocated) - - 3/24 - ---- -doc/{bash.1,bashref.texi} - - slightly modify BASH_SUBSHELL description based on complaint from - Sam Liddicott - - 3/25 - ---- -trap.c - - change free_trap_strings to not call free_trap_string for signals - that are being ignored, like reset_or_restore_signal_handlers. - Fixes bug reported by Satoshi Takahashi - - 3/26 - ---- -lib/readline/rltypedefs.h - - remove old Function/VFunction/CPFunction/CPPFunction typedefs as - suggested by Tom Tromey - -lib/readline/rlstdc.h - - move defines for USE_VARARGS/PREFER_STDARG/PREFER_VARARGS from - config.h.in to here because declaration of rl_message in - readline.h uses the defines. This makes it hard for another packages - to use after the header files are installed, since config.h is not - one of the installed files. Suggested by Tom Tromey - - - 3/27 - ---- -print_cmd.c - - change indirection_string from a static buffer to a dynamic one - managed by indirection_level_string(), so we don't end up truncating - PS4. Suggested by Dennis Williamson - -lib/readline/shell.c - - change sh_set_lines_and_columns to use static buffers instead of - allocating the buffers to pass to setenv/putenv - -lib/readline/terminal.c - - change _rl_get_screen_size to not call sh_set_lines_and_columns if - ignore_env == 0 - - _rl_sigwinch_resize_terminal: new function to just retrieve terminal - size, ignoring environment - -lib/readline/rlprivate.h - - new external declaration for _rl_sigwinch_resize_terminal() (currently - unused) - -lib/readline/signals.c - - rl_sigwinch_handler: set _rl_caught_signal to SIGWINCH - - rl_sigwinch_handler: don't immediately call rl_resize_terminal; just - leave _rl_caught_signal set for RL_CHECK_SIGNALS to handle - - _rl_signal_handler: call rl_resize_terminal if sig == SIGWINCH. - Should fix hang when sending multiple repeated SIGWINCH reported by - Henning Bekel - - 3/29 - ---- -lib/sh/snprintf.c - - include math.h for any defines for isinf/isnan - - use code from gnulib documentation to implement isinf/isnan if they - are not defined - -configure.in - - don't check for isinf or isnan; c99 says they're macros anyway - -config.h.in - - remove defines for ISINF_IN_LIBC and ISNAN_IN_LIBC, no longer used - by snprintf.c - - 4/2 - --- -braces.c - - brace_gobbler: fix to understand double-quoted command substitution, - since the shell understands unquoted comsubs. Fixes bug reported - by Michael Whitten - -lib/readline/display.c - - include on MDOS - - get and set screen size using DJGPP-specific calls on MSDOS - - move cursor up clear screen using DJGPP-specific calls - - don't call tputs on DJGPP; there is no good terminfo support - -lib/readline/terminal.c - - include on MDOS - - get and set screen size using DJGPP-specific calls on MSDOS - - use DJGPP-specific initialization on MSDOS, zeroing all the - _rl_term_* variables - - don't call tputs on DJGPP; there is no good terminfo support - DJGPP support from Eli Zaretskii - - 4/6 - --- - -config-top.h - - change DEFAULT_PATH_VALUE to something more useful and modern - - 4/8 - --- -tests/printf2.sub - - make sure LC_ALL and LC_CTYPE are set so LANG assignment takes effect. - Reported by Cedric Arbogast - - 4/11 - ---- -include/chartypes.h - - fix a couple of dicey defines (though ones that don't cause any - compiler warnings) in IN_CTYPE_DOMAIN - -doc/{bashref.texi,bash.1} - - add note referring to duplicating file descriptors in sections - describing redirecting stdout and stderr and appending to stdout - and stderr. Suggested by Matthew Dinger - -pcomplete.c - - it_init_helptopics: new function to support completing on help topics, - not just builtins - - it_helptopics: new programmable completion list of help topics - - build list of helptopic completions in gen_action_completions on - demand - -pcomplete.h - - new extern declaration for it_helptopics - -builtins/complete.def - - the `helptopic' action now maps to CA_HELPTOPIC intead of CA_BUILTIN, - since there are more help topics than just builtins. Suggested by - Clark Wang - - 4/12 - ---- -print_cmd.c - - fix print_arith_for_command to add a call to PRINT_DEFERRED_HEREDOCS - before ending the body of the command, so heredocs get attached to - the right command instead of to the loop. From gentoo bug 363371 - http://bugs.gentoo.org/show_bug.cgi?id=363371 - -execute_cmd.c - - change coproc_pidchk to unset the appropriate shell variables when - the (currently single) known coproc pid terminates - - cleanup and new functions to fully support multiple coprocesses when - and if I decide to go there - - 4/13 - ---- -print_cmd.c - - fix print_group_command to add a call to PRINT_DEFERRED_HEREDOCS - after call to make_command_string_internal before printing closing - `}' - - fix make_command_string_internal to add a call to - PRINT_DEFERRED_HEREDOCS after recursive call to - make_command_string_internal in case cm_subshell before printing - closing `)' - - 4/14 - ---- -print_cmd.c - - change overlapping strcpy in named_function_string to memmove - -sig.h - - UNBLOCK_SIGNAL: convenience define, same as UNBLOCK_CHILD, just - restores an old signal mask - -trap.c - - set_signal: instead of setting the signal handler to SIG_IGN while - installing the new trap handler, block the signal and unblock it - after the new handler is installed. Fixes bug reported by Roman - Rakus - - 4/15 - ---- -doc/{bash.1,bashref.texi} - - make it clear that enabling monitor mode means that all jobs run in - separate process groups - - 4/18 - ---- -builtins/fc.def - - update fix of 4/15/2010 to not take saved_command_line_count into - account when stepping down the history list to make sure that - last_hist indexes something that is valid. Fixes bug reported by - - - 4/19 - ---- -builtins/fc.def - - fc_gethnum: make sure the calculation to decide the last history - entry is exactly the same as fc_builtin. Fixes bug uncovered by - fix of 4/18 to stop seg fault - - 4/22 - ---- -lib/readline/terminal.c - - change _rl_enable_meta_key to set a flag indicating that it sent the - enable-meta sequence - - _rl_disable_meta_key: new function to turn off meta mode after we - turned it on with _rl_enable_meta_key - -lib/readline/rlprivate.h - - extern declaration for _rl_disable_meta_key - -configure.in - - if not cross-compiling, set CFLAGS_FOR_BUILD from any CFLAGS inherited - from the environment. Fixes HP/UX build problem reported by - "Daniel Richard G." - - 4/26 - ---- -config-top.h - - define MULTIPLE_COPROCS to 0 so the code is still disabled but easy - to enable via configure option or editing this file - - 4/29 - ---- -lib/sh/eaccess.c - - freebsd provides faccessat, with the same misfeature as their eaccess - and access implementations (X_OK returns true for uid==0 regardless - of the actual file permissions), so reorganize code to check the - file permissions as with eaccess. Report and fix from Johan Hattne - - - 5/2 - --- -doc/{bash.1,bashref.texi} - - add forward reference to `Pattern Matching' from `Pathname - Expansion', suggested by Greg Wooledge - - 5/5 - --- -pcomplib.c - - the bash_completion project now distributes over 200 completions - for various programs, with no end in sight, so increase the value - of COMPLETE_HASH_BUCKETS from 32 to 128 - -pathexp.c - - quote_string_for_globbing: make sure CTLESC quoting CTLESC is - translated into \ even if the flags include QGLOB_REGEXP. - We don't want to process the second CTLESC as a quote character. - Fixes bug reported by Shawn Bohrer - - 5/6 - --- -builtins/printf.def - - change PRETURN to not call fflush if ferror(stdout) is true - - if a call to one of the stdio functions or printstr leaves - ferror(stdout) true, and PRETURN is going to be called, let PRETURN - print the error message rather than doubling up the messages. Fixes - problem reported by Roman Rakus - - 5/9 - --- -doc/{bash.1,bashref.texi} - - add note to the effect that lists inside compound command can be - terminated by newlines as well as semicolons. Suggested by - Roman Byshko - - 5/10 - ---- -subst.c - - remove_quoted_nulls: fix problem that caused it to skip over the - character after a CTLNUL, which had the effect of skipping every - other of a series of CTLNULs. Fixes bug reported by - Marten Wikstrom - - 5/11 - ---- -subst.c - - extract_process_subst: add SX_COMMAND flag to call to - extract_delimited_string, since we're expanding the same sort of - command as command substitution. Fixes bug reported in Ubuntu - bug 779848 - - 5/12 - ---- -configure.in - - set the prefer_shared and prefer_static variables appropriately - depending on the value of $opt_static_link - -aclocal.m4 - - AC_LIB_LINKFLAGS_BODY: change to not prefer shared versions of the - libraries it's searching for if the prefer_shared variable is "no". - Fixes problem reported by Cedric Arbogast - - 5/13 - ---- -lib/readline/readline.c - - _rl_internal_teardown: add call to _rl_disable_meta_key to make the - meta key active only for the duration of the call to readline() - - _rl_internal_setup: move call to _rl_enable_meta_key here from - readline_initialize_everything so the meta key is active only for - the duration of the call to readline(). Suggestion from Miroslav - Lichvar - -builtins/help.def - - help_builtin: change strncmp to strcmp so that `help read' no longer - matches `readonly'. Suggested by Clark Wang - -config.h.in - - add define for GLIBC21, checked using jm_GLIBC21 as part of the tests - for libintl - -lib/malloc/malloc.c - - internal_free: don't use the cached value of memtop when deciding - whether or not to adjust the break and give memory back to the kernel - when using the GNU C library, since glibc uses sbrk for its own - internal purposes. From Debian bug 614815, reported by Samuel - Thibault - -aclocal.m4 - - BASH_STRUCT_WEXITSTATUS_OFFSET: change AC_RUN_IFELSE to AC_TRY_RUN - to avoid warning about not using AC_LANG_SOURCE - - 5/14 - ---- -bashline.[ch] - - two new functions, bashline_set_event_hook and bashline_reset_event_hook, - to set rl_event_hook to bash_event_hook and back to NULL, respectively - - don't set rl_event_hook unconditionally - -sig.c - - termsig_sighandler: if the shell is currently interactive and - readline is active, call bashline_set_event_hook to cause - termsig_handler to be called via bash_event_hook when the shell - returns from the signal handler - - 5/15 - ---- -lib/readline/display.c - - _rl_col_width: Mac OS X has a bug in wcwidth: it does not return 0 - for UTF-8 combining characters. Added workaround dependent on - MACOSX. Fixes problem pointed out by Thomas De Contes - - - 5/16 - ---- -lib/readline/rlmbutil.h - - WCWIDTH: wrapper for wcwidth that returns 0 for Unicode combining - characters on systems where wcwidth is broken (e.g., Mac OS X). - -lib/readline/{complete,display,mbutil}.c - - use WCWIDTH instead of wcwidth - - 5/17 - ---- -lib/readline/display.c - - update_line: after computing ofd and nfd, see whether the next - character in ofd is a zero-width combining character. If it is, - back ofd and nfd up one, so the base characters no longer compare - as equivalent. Fixes problem reported by Keith Winstein - - -lib/readline/nls.c - - _rl_utf8locale: new flag variable, set to non-zero if the current - locale is UTF-8 - - utf8locale(): new function, returns 1 if the passed lspec (or the - current locale) indicates that the locale is UTF-8. Called from - _rl_init_eightbit - -lib/readline/rlprivate.h - - extern declaration for _rl_utf8locale - -locale.c - - locale_utf8locale: new flag variable, set to non-zero if the current - locale is UTF-8 (currently unused) - - locale_isutf8(): new function, returns 1 if the passed lspec (or the - current locale) indicates that the locale is UTF-8. Should be called - whenever the locale or LC_CTYPE value is modified - -aclocal.m4 - - BASH_WCWIDTH_BROKEN: new test for whether or not wcwidth returns - zero-width characters like unicode combining characters as having - display length 1; define WCWIDTH_BROKEN in this case - -config.h.in - - WCWIDTH_BROKEN: new define - -lib/readline/rlmbutil.h - - change WCWIDTH macro to use _rl_utf8locale and the full range of - Unicode combining characters (U+0300-U+036F) - - 5/19 - ---- -lib/readline/rlprivate.h - - _rl_search_context: new member, prevc, will hold character read - prior to lastc - -lib/readline/isearch.c - - _rl_isearch_dispatch: if the character causes us to index into - another keymap, save that character in cxt->prevc - - _rl_isearch_dispatch: if we index into another keymap, but don't - find a function that's special to i-search, and the character that - caused us to index into that keymap would have terminated the - search, push back cxt->prevc and cxt->lastc to make it appear as - if `prevc' terminated the search, and execute lastc as a command. - We have to push prevc back so we index into the same keymap before - we read lastc. Fixes bug report from Davor Cubranic - - - 5/20 - ---- -expr.c - - expr_bind_variable: pay attention to the return value from - bind_variable and check whether or not we should error out due to - a readonly or noassign variable. Fixes bug reported by Eric - Blake - - 5/26 - ---- - -lib/readline/search.c - - include histlib.h for ANCHORED_SEARCH defines - - rl_history_search_flags: new variable, holds ANCHORED_SEARCH flag for - the duration of a history search - - rl_history_search_reinit: takes a new flags variable, defines whether - or not the search is anchored; assigned to rl_history_search_flags - - rl_history_serarch_reinit: if ANCHORED_SEARCH flag passed, add ^ to - beginning of search string; otherwise search string is unmodified - - rl_history_search_internal: set rl_point appropriately based on - whether or not rl_history_search_flags includes ANCHORED_SEARCH - - rl_history_substr_search_forward: new function, for non-anchored - substring search forward through history for string of characters - preceding rl_point - - rl_history_substr_search_backward: new function, for non-anchored - substring search backward through history for string of characters - preceding rl_point. Original code from Niraj Kulkarni - - -lib/readline/readline.h - - extern declarations for rl_history_substr_search_{for,back}ward - -lib/readline/funmap.c - - history-substring-search-forward: new bindable command, invokes - rl_history_substr_search_forward - - history-substring-search-backward: new bindable command, invokes - rl_history_substr_search_backward - -lib/readline/doc/{rluser.texi,readline.3} - - document history-substring-search-forward and - history-substring-search-backward - - 5/27 - ---- -{nojobs,jobs}.c - - add support for DONT_REPORT_SIGTERM so that the shell doesn't print - a message when a job exits due to SIGTERM since that's the default - signal sent by the kill builtin. Suggested by Marc Herbert - - -config-top.h - - DONT_REPORT_SIGTERM: new user-modifiable setting. Commented out - by default - - 5/28 - ---- -lib/readline/bind.c - - _rl_skip_to_delim: skip to a closing double quote or other delimiter, - allowing backslash to quote any character, including the delimiter - - rl_parse_and_bind: call _rl_skip_to_delim instead of using inline - code - - rl_parse_and_bind: allow quoted strings as the values of string - variables. Variable values without double quotes have trailing - whitespace removed (which still allows embedded whitespace, for - better or worse). Fixes problem with string variables not matching - in `set' command if values happen to have trailing spaces or tabs - (debian bash bug #602762), but introduces slight incompatibility. - - 5/29 - ---- -doc/{bash.1,bashref.texi} - - clarify unset description to specify that without options, a - variable, then a shell function if there is no variable by that - name, is unset. Fixes discrepancy reported by Mu Qiao - - - 6/4 - ---- -doc/{bash.1,bashref.texi} - - clarify description of LINES and COLUMNS (and checkwinsize shopt - option) to make it clear that only interactive shells set a - handler for SIGWINCH and update LINES and COLUMNS. Original - report submitted by Jonathan Nieder - -arrayfunc.c - - expand_compound_array_assignment: defer expansion of words between - parens when performing compound assignmnt to an associative array - variable - - assign_compound_array_list: perform the same expansions when doing - a compound array assignment to an associative array variable as - when doing a straight array index assignment. The idea is that - foo=( [ind1]=bar [ind2]=quux) - is the same as - foo[ind1]=bar ; foo[ind2]=quux - - This fixes problems with double-expansion and quote removal being - performed on the array indices - - 6/13 - ---- -doc/{bash.1,bashref.texi} - - Add a little text to make it clear that the locale determines how - range expressions in glob patterns are handled. - - - 6/21 - ---- -builtins/read.def - - display a message and return error status if -a is used with an - existing associative array. Fixes bug reported by Curtis Doty - - - 6/24 - ---- -{jobs,nojobs}.c - - non-interactive shells now react to the setting of checkwinsize - and set LINES and COLUMNS after a foreground job exits. From a - suggestion by Leslie Rhorer - -doc/{bash.1,bashref.texi} - - checkwinsize: remove language saying that only interactive shells - check the window size after each command - -lib/readline/histfile.c - - history_backupfile: new file, creates a backup history file name - given a filename (appending `-') - - history_do_write: when overwriting the history file, back it up - before writing. Restore backup file on a write error. Suggested - by chkno@chkno.net - -bashline.c - - find_cmd_name: two new arguments, return the start and end of the - actual text string used to find the command name, without taking - whitespace into account - - attempt_shell_completion: small changes to make sure that completion - attempted at the beginning of a non-empty line does not find a - programmable completion, even if the command name starts at point - - attempt_shell_completion: small change to make sure that completion - does not find a progcomp when in whitespace before the command - name - - attempt_shell_completion: small change to make sure that completion - does not find a progcomp when point is at the first character of a - command name, even when there is leading whitespace (similar to - above). Fixes problems noted by Ville Skytta - -subst.c - - brace_expand_word_list: since the individual strings in the strvec - returned by brace_expand are already allocated, don't copy them to - newly-allocated memory when building the WORD_LIST, just use them - intact - -locale.c - - locale_mb_cur_max: cache value of MB_CUR_MAX when we set or change - the locale to avoid a function call every time we need to read it - -shell.h - - new struct to save shell_input_line and associated variables: - shell_input_line_state_t - - add members of sh_parser_state_t to save and restore token and the - size of the token buffer - -parse.y - - {save,restore}_input_line_state: new functions to save and restore - shell_input_line and associated variables - - {save,restore}_parser_state: add code to save and restore the token - and token buffer size - - xparse_dolparen: call save_ and restore_input_line_state to avoid - problems with overwriting shell_input_line when we recursively - call the parser to parse a command substitution. Fixes bug - reported by Rui Santos - -include/shmbutil.h - - use locale_mb_cur_max instead of MB_CUR_MAX in ADVANCE_CHAR and - similar macros - -lib/glob/smatch.c - - rangecmp,rangecmp_wc: change to take an additional argument, which - forces the use of strcoll/wscoll when non-zero. If it's 0, a new - variable `glob_asciirange' controls whether or not we use strcoll/ - wscoll. If it's non-zero, we use straight C-locale-like ordering. - Suggested by Aharon Robbins - - 6/30 - ---- -execute_cmd.c - - execute_pipeline: make sure the lastpipe code is protected by - #ifdef JOB_CONTROL. Fixes problem reported by Thomas Cort - - - 7/2 - --- -lib/readline/complete.c - - EXPERIMENTAL: remove setting of _rl_interrupt_immediately around - completion functions that touch the file system. Idea from Jan - Kratochvil and the GDB development - team - -lib/readline/signals.c - - rl_signal_handler: if we're in callback mode, don't interrupt - immediately on a SIGWINCH - - 7/3 - --- -bashline.c - - set_directory_hook: and its siblings are a new set of functions to - set, save, and restore the appropriate directory completion hook - - change callers to use {set,save,restore}_directory_hook instead of - manipulating rl_directory_rewrite_hook directly - - dircomplete_expand: new variable, defaults to 0, if non-zero causes - directory names to be word-expanded during word and filename - completion - - change {set,save,restore}_directory_hook to look at dircomplete_expand - and change rl_directory_completion_hook or rl_directory_rewrite_hook - appropriately - -bashline.h - - extern declaration for set_directory_hook so shopt code can use it - - 7/6 - --- -builtins/shopt.def - - globasciiranges: new settable shopt option, makes glob ranges act - as if in the C locale (so b no longer comes between A and B). - Suggested by Aharon Robbins - - 7/7 - --- -doc/{bash.1,bashref.texi} - - document new `globasciiranges' shopt option - - 7/8 - --- -builtins/shopt.def - - direxpand: new settable option, makes filename completion expand - variables in directory names like bash-4.1 did. - - shopt_set_complete_direxpand: new function, does the work for the - above by calling set_directory_hook - -doc/{bash.1,bashref.texi} - - document new `direxpand' shopt option - - 7/15 - ---- -lib/readline/isearch.c - - _rl_isearch_dispatch: when adding character to search string, use - cxt->lastc (which we use in the switch statement) instead of c, - since lastc can be modified earlier in the function - - 7/18 - ---- -lib/readline/rlprivate.h - - _rl_search_context: add another member to save previous value of - (multibyte) lastc: pmb is to mb as prevc is to lastc - -lib/readline/isearch.c: - - _rl_isearch_dispatch: if a key sequence indexes into a new keymap, - but doesn't find any bound function (k[ind].function == 0) or is - bound to self-insert (k[ind].function == rl_insert), back up and - insert the previous character (the one that caused the index into a - new keymap) and arrange things so the current character is the next - one read, so both of them end up in the search string. Fixes bug - reported by Clark Wang - - _rl_isearch_dispatch: a couple of efficiency improvements when adding - characters to the isearch string - - 7/24 - ---- -lib/readline/isearch.c - - _rl_isearch_dispatch: save and restore cxt->mb and cxt->pmb - appropriately when in a multibyte locale - -doc/{bash.1,bashref.texi} - - correct description of {x}>file (and other redirection operators - that allocate a file descriptor) to note the the fd range is - greater than or equal to 10. Fixes problem reported by - Christian Ullrich - -lib/readline/signals.c - - rl_signal_handler: don't interrupt immediately if in callback mode - -lib/readline/callback.c - - rl_callback_read_char: install signal handlers only when readline - has control in callback mode, so readline's signal handlers aren't - called when the application is active (e.g., between the calls to - rl_callback_handler_install and rl_callback_read_char). If the - readline signal handlers only set a flag, which the application - doesn't know about, the signals will effectively be ignored until - the next time the application calls into the readline callback - interface. Fixes problem of calling unsafe functions from signal - handlers when in callback mode reported by Jan Kratochvil - - -execute_cmd.c - - fix_assignment_words: when in Posix mode, the `command' builtin - doesn't change whether or not the command name it protects is an - assignment builtin. One or more instances of `command' - preceding `export', for instance, doesn't make `export' treat its - assignment statement arguments differently. Posix interpretation - #351 - -doc/{bash.1,bashref.texi} - - document new Posix-mode behavior of `command' when preceding builtins - that take assignment statements as arguments - -builtins/printf.def - - printstr: if fieldwidth or precision are < 0 or > INT_MAX when - supplied explicitly (since we take care of the `-' separately), - clamp at INT_MAX like when using getint(). Fixes issue reported - by Ralph Coredroy - - 7/25 - ---- -lib/readline/chardefs.h - - isxdigit: don't define if compiling with c++; declared as a c++ - template function. Fixes bug reported by Miroslav Lichvar - - -builtins/printf.def - - getint: if garglist == 0, return whatever getintmax returns (0). - Fixes bug reported by Ralph Coredroy - - 7/28 - ---- -doc/{bash.1,bashref.texi} - - minor changes to the descriptions of the cd and pushd builtins - -lib/sh/zread.c - - zsyncfd: change variable holding return value from lseek to - off_t. Bug report and fix from Gregory Margo - - 8/1 - --- -expr.c - - don't check for division by 0 when in a context where no evaluation - is taking place. Fixes bug reported by dnade.ext@orange-ftgroup.com - - 8/6 - --- -execute_cmd.c - - execute_command_internal: the parent branch of the subshell code - (where the child calls execute_in_subshell) should not close all - open FIFOs with unlink_fifo_list if it's part of a shell function - that's still executing. Fixes bug reported by Maarten Billemont - - - 8/9 - --- -builtins/common.c - - get_exitstat: return EX_BADUSAGE (2) on a non-numeric argument - -builtins/return.def - - return_builtin: just call get_exitstat to get the return status, - let it handle proper parsing and handling of arguments. Fixes - issue most recently raised by Linda Walsh . - Reverses change from 9/11/2008 (see above) - - 8/16 - ---- -doc/{bash.1,bashref.texi} - - clean up `set -e' language to make it clearer that any failure of - a compound command will cause the shell to exit, not just subshells - and brace commands - - 8/17 - ---- -configure.in - - make the various XXX_FOR_BUILD variables `precious' to autoconf to - avoid stale data - - change how CC_FOR_BUILD is initialized when cross-compiling and not, - but do not change behavior - - initialize CFLAGS_FOR_BUILD to -g when cross-compiling - - initialize LIBS_FOR_BUILD to $(LIBS) when not cross-compiling, empty - when cross-compiling - - create AUTO_CFLAGS variable to hold basic CFLAGS defaults; used when - CFLAGS not inherited from environment (like effect of old - auto_cflags variable) - - substitute LIBS_FOR_BUILD into output Makefiles - [changes inspired by bug report from Nathan Phillip Brink - -- gentoo bug 378941] - -builtins/Makefile.in - - substitute LIBS_FOR_BUILD from configure, not strictly initialized - to $(LIBS) - - 8/27 - ---- -doc/{bash.1,bashref.texi} - - minor changes to the here string description to clarify the - expansions performed on the word - -support/shobj-conf - - handle compilation on Lion (Mac OS X 10.7/darwin11) with changes - to darwin stanzas. Fixes readline bug reported by Vincent - Sheffer - -lib/sh/strtrans.c - - ansic_wshouldquote: check a string with multi-byte characters for - characters that needs to be backslash-octal escaped for $'...' - - ansic_shouldquote: if is_basic fails for one character, let - ansic_wshouldquote examine the rest of the string and return what - it returns. From a patch sent by Roman Rakus - - 8/30 - ---- -lib/sh/strtrans.c - - ansic_quote: changes to quote (or not) multibyte characters. New - code converts them to wide characters and uses iswprint to check - valid wide chars. From a patch sent by Roman Rakus - - - 9/7 - --- -lib/sh/shquote.c - - sh_backslash_quote: change to be table-driven so we can use a - different table if we want to - - sh_backslash_quote: takes a second char table[256] argument; - -externs.h - - sh_backslash_quote: add second argument to function prototype - -bashline.c,braces.c,parse.y,builtins/printf.def - - change callers of sh_backslash_quote to add second argument - -bashline.c - - filename_bstab: table of characters to pass to sh_backslash_quote; - characters with value 1 will be backslash-quoted - - set_filename_bstab: turn on characters in filename backslash-quote - table according to passed string argument - - call set_filename_bstab every time rl_filename_quote_characters is - assigned a value - - bash_quote_filename: call sh_backslash_quote with filename_bstab - as second argument. This allows other characters in filenames to - be quoted without quoting, for instance, a dollar sign in a shell - variable reference - - 9/8 - --- -bashline.c - - complete_fullquote: new variable, controls table passed to - sh_backslash_quote. If non-zero (the default), the standard set - of shell metacharacters -- as in bash versions up to and including - bash-4.2 -- gets backslash-quoted by the completion code. If zero, - sh_backslash_quote gets the table with the characters in the - variable reference removed, which means they are removed from the - set of characters to be quoted in filenames - - 9/10 - ---- -bashline.c - - bash_filename_stat_hook: new function, designed to expand variable - references in filenames before readline passes them to stat(2) - to determine whether or not they are a directory - - 9/15 - ---- -builtins/declare.def - - if assign_array_element fails due to a bad (or empty) subscript, mark - it as an assignment error and don't attempt any further processing - of that declaration. Fixes segfault bug reported by Diego Augusto - Molina - - 9/19 - ---- -expr.c - - exppower: replace the simple exponentiation algorithm with an - implementation of exponentiation by squaring. Inspired by report - from Nicolas ARGYROU - -bashline.c - - bash_quote_filename: check for rtext being non-null before - dereferencing it - - set_saved_history: operate_and_get_next assumes that the previous - line was added to the history, even when the history is stifled and - at the max number of entries. If it wasn't, make sure the history - number is incremented properly. Partial fix for bug reported by - gregrwm - -doc/{bash.1,bashref.texi},lib/readline/doc/{hsuser,rluser}.texi - - minor editorial changes inspired by suggestions from - Roger Zauner - - 9/20 - ---- -lib/intl/localealias.c - - read_alias_file: close resource leak (fp) when returning on error - - 9/22 - ---- -execute_command.c - - execute_intern_function: implement Posix interpretation 383 by making - it an error to define a function with the same name as a special - builtin when in Posix mode. - http://austingroupbugs.net/view.php?id=383#c692 - - 9/25 - ---- -doc/{bash.1,bashref.texi} - - formatting and some content changes from Benno Schulenberg - - - document new posix-mode behavior from interp 383 change of 9/22 - - 9/30 - ---- -execute_cmd.c - - shell_execve: add strerror to error message about executable file - that shell can't execute as a shell script. From suggestion by - daysleeper - - 10/1 - ---- -bashhist.c - - maybe_add_history: act as if literal_history is set when parser_state - includes PST_HEREDOC, so we save the bodies of here-documents just - as they were entered. Fixes bug reported by Jonathan Wakely - - - bash_add_history: make sure that the second and subsequent lines of - a here document don't have extra newlines or other delimiting - chars added, since they have the trailing newline preserved, when - `lithist' is set and history_delimiting_chars isn't called - -execute_cmd.c - - execute_command_internal: avoid fd exhaustion caused by using - process substitution in loops inside shell functions by using - copy_fifo_list and close_new_fifos (). Fixes debian bash bug - 642504 - -lib/readline/complete.c - - new variable, rl_filename_stat_hook, used by append_to_match. If - filename completion is desired, and rl_filename_stat_hook points - to a function, call that function to expand the filename in an - application-specific way before calling stat. - -bashline.c - - bash_default_completion: if variable completion returns a single - match, use bash_filename_stat_hook and file_isdir to determine - whether or not the variable name expands to a directory. If it - does, set the filename_append_character to `/'. This is not - perfect, so we will see how it works out. Adds functionality - requested by Peter Toft and Patrick Pfeifer - - - rl_filename_stat_hook: assigned bash_filename_stat_hook, so things - like $HOME/Downloads (after completion) have a slash appended. - In general, this causes the stat hook to be called whenever - filename completion is appended. Adds functionality requested by - Patrick Pfeifer - -lib/readline/readline.h - - new extern declaration for rl_filename_stat_hook - -lib/readline/doc/rltech.texi - - rl_directory_rewrite_hook: now documented - - rl_filename_stat_hook: document - -pcomplete.c - - gen_action_completions: in the CA_DIRECTORY case, turn off - rl_filename_completion_desired if it was off before we called - rl_filename_completion_function and we didn't get any matches. - Having it on causes readline to quote the matches as if they - were filenames. Adds functionality requested by many, - including Clark Wang - -assoc.[ch] - - assoc_replace: new function, takes the same arguments as - assoc_insert, but returns the old data instead of freeing it - - assoc_insert: if the object returned by hash_insert doesn't have - the same value for its key as the key passed as an argument, we - are overwriting an existing value. In this case, we can free the - key. Fixes bug reported by David Parks - - 10/5 - ---- -print_cmd.c - - indirection_level_string: small change to only re-enable `x' - option after calling decode_prompt_string if it was on before. In - normal mode, it will be, but John Reiser - has a novel use for that code in conjunction with a pre-loaded - shared library that traces system call usage in shell scripts - - 10/10 - ----- -Makefile.in - - Fix from Mike Frysinger to avoid trying to - build y.tab.c and y.tab.h with two separate runs of yacc if - parse.y changes. Problem with parallel makes - - Fix from Mike Frysinger to avoid subdirectory - builds each trying to make version.h (and all its dependencies) - -lib/sh/Makefile.in - - remove some dependencies on version.h where it doesn't make sense - -variables.c - - initialize_shell_variables: while reading the environment, a shell - running in posix mode now checks for SHELLOPTS being readonly (it - gets set early on in main()) before trying to assign to it. It - saves an error message and the variable gets parsed as it should. - Fixes bug reported by Len Giambrone - - 10/14 - ----- -doc/{bash.1,bashref.texi} - - add to the "duplicating file descriptors" description that >&word - doesn't redirect stdout and stderr if word expands to `-' - - add to the "appending standard output and standard error" - description a note that >&word, where word is a number or `-', - causes other redirection operators to apply for sh and Posix - compatibility reasons. Suggested by Greg Wooledge - - - 10/15 - ----- -pcomplete.c - - change pcomp_filename_completion_function to only run the filename - dequoting function in the cases (as best as it can figure) where - readline won't do it via rl_filename_completion_function. Based - on reports from - - 10/19 - ----- -bashline.c - - attempt_shell_completion: add call to set_directory_hook() to make - sure the rewrite functions are correct. It's cheap and doesn't - hurt - - command_word_completion_function: if completing a command name that - starts with `.' or `..', temporarily suppress the effects of the - `direxpand' option and restore the correct value after calling - rl_filename_completion_function. If it's enabled, the directory - name will be rewritten and no longer match `./' or `../'. Fixes - problem reported by Michael Kalisz - - 10/22 - ----- -builtins/history.def - - push_history: make sure remember_on_history is enabled before we - try to delete the last history entry -- the `history -s' command - might not have been saved. Fixes bug reported by - lester@vmw-les.eng.vmware.com - -lib/readline/complete.c - - rl_callback_read_char: add calls to a macro CALLBACK_READ_RETURN - instead of straight return; add same call at end of function. - Placeholder for future work in deinstalling signal handlers when - readline is not active - - 10/25 - ----- -expr.c - - exp2: catch arithmetic overflow when val1 == INTMAX_MIN and val2 == -1 - for DIV and MOD and avoid SIGFPE. Bug report and pointer to fix - from Jaak Ristioja - - expassign: same changes for arithmetic overflow for DIV and MOD - - 10/28 - ----- -subst.c - - parameter_brace_expand: allow pattern substitution when there is an - expansion of the form ${var/} as a no-op: replacing nothing with - nothing - - parameter_brace_patsub: don't need to check for PATSUB being NULL; - it never is - -flags.c - - if STRICT_POSIX is defined, initialize history_expansion to 0, since - history expansion (and its treatment of ! within double quotes) is - not a conforming posix environment. From austin-group issue 500 - -lib/readline/histexpand.c - - history_expand: when processing a string within double quotes - (DQUOTE == 1), make the closing double quote inhibit history - expansion, as if the word were outside double quotes. In effect, - we assume that the double quote is followed by a character in - history_no_expand_chars. tcsh and csh seem to do this. This - answers a persistent complaint about history expansion - - 10/29 - ----- -make_cmd.c - - make_arith_for_command: use skip_to_delim to find the next `;' - when breaking the string between the double parens into three - separate components instead of a simple character loop. Fixes - bug reported by Dan Douglas - - 11/2 - ---- -Makefile.in - - make libbuiltins.a depend on builtext.h to serialize its creation - and avoid conflict between multiple invocations of mkbuiltins. - Fix from Mike Frysinger - - 11/5 - ---- -findcmd.c - - user_command_matches: if stat(".", ...) returns -1, set st_dev - and st_ino fields in dotinfo to 0 to avoid same_file matches - - find_user_command_in_path: check stat(2) return the same way - -lib/glob/glob.c - - glob_vector: don't call strlen(pat) without checking pat == 0 - - glob_dir_to_array: make sure to free `result' and all allocated - members before returning error due to malloc failure - - glob_vector: make sure to free `nextname' and `npat' on errors - (mostly when setting lose = 1) - - glob_vector: if flags & GX_MATCHDIRS but not GX_ALLDIRS, make - sure we free `subdir' - - glob_filename: when expanding ** (GX_ALLDIRS), make sure we - free temp_results (return value from glob_vector) - -lib/glob/xmbsrtowcs.c - - xdupmbstowcs: fix call to realloc to use sizeof (char *) instead - of sizeof (char **) when assigning idxtmp - -execute_cmd.c - - print_index_and_element: return 0 right away if L == 0 - - is_dirname: fix memory leak by freeing `temp' - - time_command: don't try to deref NULL `command' when assigning - to `posix_time' - - shell_execve: null-terminate `sample' after READ_SAMPLE_BUF so it's - terminated for functions that expect that - -builtins/read.def - - read_builtin: don't call bind_read_variable with a potentially-null - string - -pcomplete.c - - gen_command_matches: don't call dispose_word_desc with a NULL arg - - gen_compspec_completions: fix memory leak by freeing `ret' before - calling gen_action_completions (tcs, ...). happens when - performing directory completion as default and no completions - have been generated - - gen_progcomp_completions: make sure to set foundp to 0 whenever - returning NULL - - it_init_aliases: fix memory leak by freeing alias_list before - returning - -bashline.c - - command_word_completion_function: don't call restore_tilde with a - NULL directory_part argument - - bash_directory_expansion: bugfix: don't throw away results of - rl_directory_rewrite_hook if it's set and returns non-zero - - bind_keyseq_to_unix_command: free `kseq' before returning error - -arrayfunc.c - - assign_array_element_internal: make sure `akey' is freed if non-null - before returning error - - assign_compound_array_list: free `akey' before returning error - - array_value_internal: free `akey' before returning error - - unbind_array_element: free `akey' before returning error - -subst.c - - array_length_reference: free `akey' before returning error in case - of expand_assignment_string_to_string error - - array_length_reference: free `akey' after call to assoc_reference - - skip_to_delim: if skipping process and command substitution, free - return value from extract_process_subst - - parameter_brace_substring: free `val' (vtype == VT_VARIABLE) before - returning if verify_substring_values fails - - parameter_brace_expand: remove two duplicate lines that allocate - ret in parameter_brace_substring case - - parameter_brace_expand: convert `free (name); name = xmalloc (...)' - to use `xrealloc (name, ...)' - - parameter_brace_expand: free `name' before returning when handling - ${!PREFIX*} expansion - - split_at_delims: fix memory leak by freeing `d2' before returning - -redir.c - - redirection_error: free `filename' if the redirection operator is - REDIR_VARASSIGN by assigning allocname - -eval.c - - send_pwd_to_eterm: fix memory leak by freeing value returned by - get_working_directory() - -builtins/cd.def - - change_to_directory: fix memory leak by freeing return value from - resetpwd() - - cd_builtin: fix memory leak by freeing value returned by dirspell() - - cd_builtin: fix memory leak by freeing `directory' if appropriate - before overwriting with return value from resetpwd() - -builtins/type.def - - describe_command: free `full_path' before overwriting it with return - value from sh_makepath - -builtins/complete.def - - compgen_builtin: fix memory leak by calling strlist_dispose (sl) - before overwriting sl with return value from completions_to_stringlist - -builtins/hash.def - - list_hashed_filename_targets: fix memory leak by freeing `target' - -make_cmd.c - - make_arith_for_command: free `init', `test', and `step' before - returning error on parse error - -jobs.c - - initialize_job_control: don't call move_to_high_fd if shell_tty == -1 - -general.c - - check_dev_tty: don't call close with an fd < 0 - - legal_number: deal with NULL `string' argument, return invalid - -lib/sh/fmtulong.c - - fmtulong: if the `base' argument is invalid, make sure we index - buf by `len-1' at maximum - -print_cmd.c - - print_deferred_heredocs: don't try to dereference a NULL `cstring' - - cprintf: make sure to call va_end (args) - -variables.c - - push_dollar_vars: fix call to xrealloc to use sizeof (WORD_LIST *) - instead of sizeof (WORD_LIST **) - -lib/sh/zmapfd.c - - zmapfd: if read returns error, free result and return -1 immediately - instead of trying to reallocate it - - 11/6 - ---- -execute_cmd.c - - cpl_reap: rewrote to avoid using pointer after freeing it; now builds - new coproc list on the fly while traversing the old one and sets the - right values for coproc_list when done - - 11/12 - ----- -builtins/set.def - - if neither -f nor -v supplied, don't allow a readonly function to - be implicitly unset. Fixes bug reported by Jens Schmidt - - -lib/readline/callback.c - - change CALLBACK_READ_RETURN to clear signal handlers before returning - from rl_callback_read_char so readline's signal handlers aren't - installed when readline doesn't have control. Idea from Jan - Kratochvil and the GDB development - team - -pcomplete.h - - COPT_NOQUOTE: new complete/compgen option value - -builtins/complete.def - - noquote: new complete/compgen option; will be used to disable - filename completion quoting - -pcomplete.c - - pcomp_set_readline_variables: pay attention to COPT_NOQUOTE; turns - of rl_filename_quoting_desired if set; turns it on if unset (value - is inverted, since default is on) - -doc/bash.1,lib/readline/doc/rluser.texi - - document new -o noquote option to complete/compgen/compopt - -pathexp.c - - quote_string_for_globbing: if QGLOB_REGEXP, make sure characters - between brackets in an ERE bracket expression are not inappropriately - quoted with backslashes. This is a pretty substantial change, - should be stressed when opening bash up for alpha and beta tests. - Fixes bug pointed out by Stephane Chazleas - - -doc/{bash.1,bashref.texi} - - document that regexp matches can be inconsistent when quoting - characters in bracket expressions, since usual quoting characters - lose their meaning within brackets - - note that regular expression matching when the pattern is stored - in a shell variable which is quoted for expansion causes string - matching - -redir.h - - RX_SAVEFD: new flag value; notes that a redirection denotes an - fd used to save another even if it's not >= SHELL_FD_BASE - -redir.c - - do_redirection_internal: when deciding whether or not to reset the - close-on-exec flag on a restored file descriptor, trust the value - of redirect->flags & RX_SAVCLEXEC even if the fd is < SHELL_FD_BASE - if the RX_SAVEFD flag is set - - add_undo_redirect: set the RX_SAVEFD flag if the file descriptor - limit is such that the shell can't duplicate to a file descriptor - >= 10. Fixes a limitation that tripped a coreutils test reported - by Paul Eggert - - 11/19 - ----- -doc/{bash.1,bashref.texi},lib/readline/doc/hsuser.texi - - make it clear that bash runs HISTFILESIZE=$HISTSIZE after reading - the startup files - - make it clear that bash runs HISTSIZE=500 after reading the - startup files - - make it clear that setting HISTSIZE=0 causes commands to not be - saved in the history list - - make it clear that setting HISTFILESIZE=0 causes the history file - to be truncated to zero size - -variables.c - - sv_histsize: change so setting HISTSIZE to a value less than 0 - causes the history to be `unstifled' - - sv_histsize: change so setting HISTFILESIZE to a value less than 0 - results in no file truncation - - make it clear that numeric values less than 0 for HISTFILESIZE or - HISTSIZE inhibit the usual functions - - 11/23 - ----- -parse.y - - save_input_line_state: add missing `return ls' at the end, since the - function is supposed to return its argument. Pointed out by - Andreas Schwab - -builtins/read.def - - skip over NUL bytes in input, as most modern shells seem to. Bug - report by Matthew Story - -lib/readline/vi_mode.c - - rl_vi_replace: set _rl_vi_last_key_before_insert to invoking key - - 11/25 - ----- -builtins/read.def - - read_builtin: if xrealloc returns same pointer as first argument, - don't bother with the remove_unwind_protect/add_unwind_protect pair - - read_builtin: set a flag (`reading') around calls to zread/zreadc - and readline() - - sigalrm: change to set flag (`sigalrm_seen') and only longjmp if - currently in read(2) (reading != 0) - - CHECK_ALRM: new macro, checks sigalrm_seen and longjmps if non-zero, - behavior of old SIGALRM catching function - - read_builtin: call CHECK_ALRM in appropriate places while reading - line of input. Fixes bug reported by Pierre Gaston - - -lib/readline/vi_mode.c - - rl_vi_replace: initialize characters before printing characters in - vi_replace_keymap to their default values in vi_insertion_keymap, - since we're supposed to be in insert mode replacing characters - - rl_vi_replace: call rl_vi_start_inserting to set last command to - `R' for undo - - rl_vi_replace: set _rl_vi_last_key_before_insert to `R' for future - use by _rl_vi_done_inserting - - vi_save_insert_buffer: new function, broke out code that copies text - into vi_insert_buffer from _rl_vi_save_insert - - _rl_vi_save_replace: new function, saves text modified by - rl_vi_replace (using current point and vi_replace_count to figure - it out) to vi_replace_buffer - - _rl_vi_save_insert: call vi_save_insert_buffer - - _rl_vi_done_inserting: if _rl_vi_last_key_before_insert == 'R', call - _rl_vi_save_replace to save text modified in replace mode (uses - vi_save_insert_buffer) - - _rl_vi_replace_insert: new function, replaces the number of chars - in vi_insert_buffer after rl_point with contents ov vi_insert_buffer - - rl_vi_redo: call _rl_vi_replace_insert if last command == 'R' and - there's something in vi_insert_buffer. Fixes bug with `.' not - redoing the most recent `R' command, reported by Geoff Clare - in readline area on savannah - - 11/26 - ----- -lib/readline/rlprivate.h - - RL_SIG_RECEIVED(): evaluate to non-zero if there is a pending signal - to be handled - - RL_SIGINT_RECEIVED(): evaluate to non-zero if there is a pending - SIGINT to be handled - -lib/readline/complete.c - - remove all mention of _rl_interrupt_immediately - - rl_completion_matches: check RL_SIG_RECEIVED after each call to - the entry function, call RL_CHECK_SIGNALS if true to handle the - signal - - rl_completion_matches: if RL_SIG_RECEIVED evaluates to true, free - and zero out the match_list this function allocated - - rl_completion_matches: if the completion entry function is - rl_filename_completion_function, free the contents of match_list, - because that function does not keep state and will not free the - entries; avoids possible memory leak pointed out by - Garrett Cooper - - gen_completion_matches: if RL_SIG_RECEIVED evalutes to true after - calling rl_attempted_completion_function, free the returned match - list and handle the signal with RL_CHECK_SIGNALS; avoids - possible memory leak pointed out by Garrett Cooper - - - gen_completion_matches: if RL_SIG_RECEIVED evaluates to true after - calling rl_completion_matches, free the returned match list and - handle the signal with RL_CHECK_SIGNALS - -lib/readline/util.c - - rl_settracefp: new utility function to set the tracing FILE * - -lib/readline/signals.c - - _rl_sigcleanup: pointer to a function that will be called with the - signal and a void * argument from _rl_handle_signal - - _rl_sigcleanarg: void * that the rest of the code can set to have - passed to the signal cleanup function - - _rl_handle_signal: if _rl_sigcleanup set, call as - (*_rl_sigcleanup) (sig, _rl_sigcleanarg) - -lib/readline/rlprivate.h - - extern declarations for _rl_sigcleanup and _rl_sigcleanarg - -lib/readline/complete.c - - _rl_complete_sigcleanup: signal cleanup function for completion code; - calls _rl_free_match_list on _rl_sigcleanarg if signal == SIGINT - - rl_complete_internal: before calling display_matches if what_to_do - == `?', set _rl_sigcleanup to _rl_complete_sigcleanup so the match - list gets freed on SIGINT; avoids possible memory leak pointed out - by Garrett Cooper - - rl_complete_internal: in default switch case, call _rl_free_match_list - before returning to avoid memory leak - -doc/bashref.texi - - start at a set of examples for the =~ regular expression matching - operator, touching on keeping the pattern in a shell variable and - quoting portions of the pattern to remove their special meaning - - 12/1 - ---- -lib/glob/gmisc.c - - extglob_pattern: new function, returns 1 if pattern passed as an - argument looks like an extended globbing pattern - -lib/glob/glob.c - - skipname: return 0 immediately if extglob_pattern returns non-zero, - let the extended globbing code do the right thing with skipping - names beginning with a `.' - - mbskipname: return 0 immediately if extglob_pattern returns non-zero, - let the extended globbing code do the right thing with skipping - names beginning with a `.'. Fixes bug reported by Yongzhi Pan - - - 12/2 - ---- -lib/glob/smatch.c - - patscan, patscan_wc: no longer static so other parts of the glob - library can use them, renamed to glob_patscan, glob_patscan_wc - -lib/glob/glob.c - - extern declarations for glob_patscan, glob_patscan_wc - - wchkname: new function, does skipname on wchar_t pattern and dname, - old body of mbskipname after converting to wide chars - - extglob_skipname: new function, checks all subpatterns in an extglob - pattern to determine whether or not a filename should be skipped. - Calls skipname for each subpattern. Dname is only skipped if all - subpatterns indicate it should be. Better fix for bug reported by - Yongzhi Pan - - wextglob_skipname: wide-char version of extglob_skipname, calls - wchkname instead of calling back into mbskipname for each - subpattern to avoid problems with char/wchar_t mismatch - - skipname: call extglob_skipname if extglob_pattern returns non-zero - - mbskipname: call wextglob_skipname if extglob_pattern returns non-zero - - mbskipname: short-circuit immediately if no multibyte chars in - pattern or filename - -execute_cmd.c - - execute_cond_node: added parens to patmatch assignment statement to - make intent clearer - - 12/3 - ---- -configure.in,config.h.in - - check for imaxdiv, define HAVE_IMAXDIV if present - -expr.c - - expassign, exp2: use imaxdiv if available. Doesn't help with checks - for overflow from 10/25 - - 12/6 - ---- -lib/readline/complete.c - - compute_lcd_of_matches: if we're ignoring case in the matches, only - use what the user typed as the lcd if it matches the first match - (after sorting) up to the length of what was typed (if what the - user typed is longer than the shortest of the possible matches, use - the shortest common length of the matches instead). If it doesn't - match, use the first of the list of matches, as if case were not - being ignored. Fixes bug reported by Clark Wang - - - 12/7 - ---- -builtins/cd.def - - cd_builtin: add code to return error in case cd has more than one - non-option argument, conditional on CD_COMPLAINS define (which is - not defined anywhere) - -doc/{bash.1,bashref.texi} - - note that additional arguments to cd following the directory name - are ignored. Suggested by Vaclav Hanzl - - 12/10 - ----- -lib/readline/input.c - - rl_read_key: don't need to increment key sequence length here; doing - it leads to an off-by-one error - -lib/readline/macro.c - - rl_end_kbd_macro: after off-by-one error with rl_key_sequence_length - fixed, can decrement current_macro_index by rl_key_sequence_length - (length of key sequence that closes keyboard macro) - -lib/readline/readline.c - - _rl_dispatch_subseq: fix extra increment of rl_key_sequence_length - when ESC maps to a new keymap and we're converting meta characters - to ESC+key - - _rl_dispatch_subseq: better increment of rl_key_sequence_length - before we dispatch to a function in the ISFUNC case (where the - second increment above should have happened) - - rl_executing_keyseq: the full key sequence that ended up executing - a readline command. Available to the calling application, maintained - by _rl_dispatch_subseq, indexed by rl_key_sequence_length - - rl_executing_key: the key that was bound to the currently-executing - readline command. Same as the `key' argument to the function - -lib/readline/readline.h - - rl_executing_keyseq: extern declaration - - rl_executing_key: extern declaration - - rl_key_sequence_length: declaration moved here from rlprivate.h, - now part of public interface - -lib/readline/rlprivate.h - - new extern declaration for _rl_executing_keyseq_size, buffer size - for rl_executing_keyseq - -lib/readline/doc/rltech.texi - - documented new variables: rl_executing_key, rl_executing_keyseq, - rl_key_sequence_length - - 12/13 - ----- -bashline.c - - bash_execute_unix_command: replace ad-hoc code that searches - cmd_xmap for correct command with call to rl_function_of_keyseq - using rl_executing_keyseq; now supports key sequences longer - than two characters. Fixes bug reported by Michael Kazior - - - 12/15 - ----- -make_cmd.c - - make_function_def: don't null out source_file before calling - make_command so it can be used later on when the function definition - is executed - -execute_cmd.c - - execute_intern_function: second argument is now FUNCTION_DEF * - instead of COMMAND * - - execute_command_internal: call execute_intern_function with the - new second argument (the entire FUNCTION_DEF instead of just the - command member) - - execute_intern_function: if DEBUGGER is defined, call - bind_function_def before calling bind_function, just like - make_function_def does (might be able to take out the call in - make_function_def depending on what the debugger does with it). - Fixes bug reported by - -expr.c - - more minor changes to cases of INTMAX_MIN % -1 and INTMAX_MIN / 1; - fix typos and logic errors - - 12/16 - ----- -bashline.c - - find_cmd_start: change flags to remove SD_NOSKIPCMD so it skips over - command substitutions and doesn't treat them as command separators - - attempt_shell_completion: instead of taking first return from - find_cmd_name as command name to use for programmable completion, - use loop to skip over assignment statements. Fixes problem reported - by Raphael Droz - - attempt_shell_completion: if we don't find a command name but the - command line is non-empty, assume the other words are all assignment - statements and flag that point is in a command position so we can - do command name completion - - attempt_shell_completion: if the word being completed is the first - word following a series of assignment statements, and the - command line is non-empty, flag that point is in a command position - so we can do command name completion - -lib/readline/history.c - - history_get_time: atol -> strtol - - 12/18 - ----- -parse.y - - parser_in_command_position: external interface to the - command_token_position macro for use by other parts of the shell, - like the completion mechanism - -externs.h - - extern declaration for parser_in_command_position - - 12/19 - ----- - -builtins/read.def - - read_builtin: make sure all calls to bind_read_variable are passed - a non-null string. Fixes bug reported by Dan Douglas - - -bashline.c - - attempt_shell_completion: mark that we're in a command position if - we're at the start of the line and the parser is ready to accept - a reserved word or command name. Feature most recently suggested - by Peng Yu - - 12/21 - ----- -lib/readline/bind.c - - _rl_escchar: return the character that would be backslash-escaped - to denote the control character passed as an argument ('\n' -> 'n') - - _rl_isescape: return 1 if character passed is one that has a - backslash escape - - _rl_untranslate_macro_value: new second argument: use_escapes, if - non-zero translate to backslash escapes where possible instead of - using straight \C-x for control character `x'. Change callers - - _rl_untranslate_macro_value: now global - -lib/readline/rlprivate.h - - _rl_untranslate_macro_value: extern declaration - -lib/readline/{macro.c,readline.h} - - rl_print_last_kbd_macro: new bindable function, inspired by patch - from Mitchel Humpherys - -lib/readline/funmap.c - - print-last-kbd-macro: new bindable command, bound to - rl_print_last_kbd_macro - -lib/readline/doc/{rluser.texi,readline.3},doc/bash.1 - - print-last-kbd-macro: document. - -lib/readline/text.c - - _rl_insert_next: if we're defining a macro, make sure the key gets - added to the macro text (should really audit calls to rl_read_key() - and make sure the right thing is happening for all of them) - -bashline.[ch] - - print_unix_command_map: new function, prints all bound commands in - cmd_xmap using rl_macro_dumper in a reusable format - -builtins/bind.def - - new -X option: print all keysequences bound to Unix commands using - print_unix_command_map. Feature suggested by Dennis Williamson - (2/2011) - -doc/{bash.1,bashref.texi} - - document new `bind -X' option - - 12/24 - ----- - -doc/{bash.1,bashref.texi} - - add a couple of sentences to the description of the case modification - operators making it clearer that each character of parameter is - tested against the pattern, and that the pattern should only attempt - to match a single character. Suggested by Bill Gradwohl - - - 12/28 - ----- -shell.c - - init_noninteractive: instead of calling set_job_control(0) to - unconditionally turn off job control, turn on job control if - forced_interactive or jobs_m_flag is set - - shell_initialize: call initialize_job_control with jobs_m_flag as - argument so `bash -m script' enables job control while running the - script - -jobs.c - - initialize_job_control: if the `force' argument is non-zero, turn on - job control even if the shell is not currently interactive - (interactive == 0) - - 12/29 - ----- - -flags.h - - new extern declaration for jobs_m_flag - -builtins/{cd,set}.def,doc/{bash.1,bashref.texi} - - added text clarifying the descriptions of cd -L and -P, suggested by - Padraig Brady - - slight change to the description of `set -P' about resolving symbolic - links - -lib/readline/doc/rluser.texi - - Added an example to the programmable completion section: _comp_cd, - a completion function for cd, with additional verbiage. Text - includes a reference to the bash_completion project - - 1/1/2012 - -------- -jobs.c - - set_job_status_and_cleanup: note that a job is stopped due to - SIGTSTP (any_tstped) if job_control is set; there's no need to - test interactive - - 1/5 - --- -quit.h - - LASTSIG(): new macro, expands to signal number of last terminating - signal received (terminating_signal or SIGINT) - -trap.c - - first_pending_trap: returns lowest signal number with a trap pending - - trapped_signal_received: set to the last trapped signal the shell - received in trap_handler(); reset to 0 in run_pending_traps - -builtins/read.def - - read_builtin: changes to posix-mode (posixly_correct != 0) to make - `read' interruptible by a trapped signal. After the trap runs, - read returns 128+sig and does not assign the partially-read line - to the named variable(s). From an austin-group discussion started - by David Korn - - 1/11 - ---- -doc/{bash.1,bashref.texi} - - slight changes to the descriptions of the compat32 and compat40 shell - options to clarify their meaning - - 1/12 - ---- -lib/readline/{colors.[ch],parse-colors.[ch]} - - new files, part of color infrastructure support - -Makefile.in,lib/readline/Makefile.in - - arrange to have colors.o and parse-colors.o added to readline - library - -{configure,config.h}.in - - check for stdbool.h, define HAVE_STDBOOL_H if found - - 1/14 - ---- -lib/readline/bind.c - - colored_stats: new bindable variable, enables using colors to - indicate file type when listing completions - -lib/readline/complete.c - - _rl_colored_stats: new variable, controlled by colored-stats bindable - variable - - colored_stat_start, colored_stat_end: new functions to set and reset - the terminal color appropriately depending on the type of the - filename to be printed - - print_filename: changes to print colors if `colored-stats' variable - set. Changes contributed by Raphael Droz - - -lib/readline/readline.c - - rl_initialize_everything: add call to _rl_parse_colors to parse - color values out of $LS_COLORS. May have to add to rl_initialize - to make more dynamic if LS_COLORS changes (which doesn't happen - very often, if at all) - -lib/readline/rlprivate.h - - _rl_colored_stats: new extern declaration - -lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 - - colored-stats: document new bindable readline variable - -lib/readline/colors.c - - _rl_print_color_indicator: call rl_filename_stat_hook before calling - lstat/stat so we can get color indicators for stuff like - $HOME/Applications - -lib/readline/complete.c - - stat_char: call rl_filename_stat_hook before calling lstat/stat - -findcmd.[ch],execute_cmd.c - - search_for_command: now takes a second `flags' argument; changed - header function prototype and callers - - search_for_command: if (flags & 1), put the command found in $PATH - into the command hash table (previous default behavior) - -execute_cmd.c - - is_dirname: call search_for_command with flags argument of 0 so it - doesn't try to put something in the command hash table - -bashline.c - - bash_command_name_stat_hook: a hook function for readline's - filename_stat_hook that does $PATH searching the same way that - execute_cmd.c:execute_disk_command() does it, and rewrites the - passed filename if found. Does not put names into command hash - table. This allows command name completion to take advantage - of `visible-stats' and `colored-stats' settings. - - executable_completion: new function, calls the directory completion - hook to expand the filename before calling executable_file or - executable_or_directory; change command_word_completion_function to - call executable_completion. This allows $HOME/bin/[TAB] to do - command completion and display alternatives - - 1/17 - ---- -pcomplete.c - - gen_command_matches: now takes a new second argument: the command - name as deciphered by the programmable completion code and used - to look up the compspec; changed callers (gen_compspec_completions) - - gen_shell_function_matches: now takes a new second argument: the - command that originally caused the completion function to be - invoked; changed callers (gen_compspec_completions)) - - build_arg_list: now takes a new second argument: the command name - corresponding to the current compspec; changed callers - (gen_command_matches, gen_shell_function_matches) - - build_arg_list: now uses `cmd' argument to create $1 passed to - invoked command or shell function - - gen_compspec_completions: if we skipped a null command at the - beginning of the line (e.g., for completing `>'), add a new word for - it at the beginning of the word list and increment nw and cw - appropriately. This is all a partial fix for the shortcoming - pointed out by Sung Pae - - 1/18 - ---- - -{configure,config.h}.in - - new check: check for AUDIT_USER_TTY defined in , - define HAVE_DECL_AUDIT_USER_TTY if both are found - -lib/readline/rlconf.h - - ENABLE_TTY_AUDIT_SUPPORT: new define, allows use of the Linux kernel - tty auditing system if it's available and enabled - -lib/readline/util.c - - _rl_audit_tty: new function, send a string to the kernel tty audit - system - -lib/readline/rlprivate.h - - _rl_audit_tty: new extern declaration - -lib/readline/readline.c - - readline: call _rl_audit_tty with line to be returned before returning - it if the Linux tty audit system is available and it's been enabled - in rlconf.h Original patch from Miroslav Trmac; recent request - from Miroslav Lichvar - - 1/21 - ---- - -lib/readline/readline.c: - - _rl_dispatch_subseq: add an inter-character timeout for multi-char - key sequences. Suggested by . Still needs - work to make a user-settable variable - -parse.y - - shell_getc: make code that uses the pop_alias dependent on ALIAS - define - -variables.h - - sv_tz: extern define should only depend on HAVE_TZSET - -expr.c - - expr_streval: if ARRAY_VARS is not defined, set lvalue->ind to -1; - move assignment to `ind' inside define - - expr_bind_array_element: declaration and uses need to be #ifdef - ARRAY_VARS - -arrayfunc.h - - AV_ALLOWALL, AV_QUOTED, AV_USEIND: define to 0 if ARRAY_VARS not - defined; used in subst.c unconditionally - -sig.h - - make the signal blocking functions not dependent on JOB_CONTROL - -sig.c - - sigprocmask: make the replacement definition not dependent on - JOB_CONTROL - -trap.c - - use BLOCK_SIGNAL/UNBLOCK_SIGNAL instead of code dependent on - HAVE_POSIX_SIGNALS and BSD signals - - 1/24 - ---- - -print_cmd.c - - print_redirection_list: change the conditions under which - r_duplicating_output_word is mapped to r_err_and_out to more or - less match those used in redir.c. Fixes bug pointed out by - Dan Douglas - - - 1/29 - ---- -lib/readline/signals.c - - _rl_block_sigwinch,_rl_release_sigwinch: don't compile in bodies - unless SIGWINCH is defined. Fixes bug reported by Pierre Muller - - -doc/{bash.1,bashref.texi} - - small modifications to the introduction to the REDIRECTION section - to describe how redirections can modify file handles - - small modification to the section describing base#n to make it - clearer that n can be denoted using non-numerics. From a posting - by Linda Walsh - - 2/2 - --- -builtins/printf.def - - printf_builtin: make sure vbuf is intialized and non-null when -v - is supplied, since other parts of the code assume that it's not - null (e.g., bind_printf_variable()). Fixes bug reported by Jim - Avera - - 2/4 - --- -lib/readline/undo.c - - _rl_free_undo_list: new function, old body of rl_free_undo_list, - frees undo entries in UNDO_LIST * passed as argument - - rl_free_undo_list: call _rl_free_undo_list - -lib/readline/rlprivate.h - - _rl_free_undo_list: new extern declaration - - _rl_keyseq_timeout: new extern declaration (see below) - -lib/readline/misc.c - - rl_clear_history: new function. Clears the history list and frees - all associated data similar to history.c:clear_history(), but - takes rl_undo_list into account and frees and UNDO_LISTs saved as - `data' members of a history list entry - -lib/readline/doc/rltech.texi - - rl_clear_history: documented - -lib/readline/readline.c - - _rl_keyseq_timeout: new variable to hold intra-key timeout value - from 1/21 fix; specified in milliseconds. Default value is 500 - - _rl_dispatch_subseq: change to use _rl_keyseq_timeout as intra-key - timeout if it's greater than 0; no timeout if <= 0 - - _rl_dispatch_subseq: don't check for queued keyboard input if we have - pushed or pending input, or if we're reading input from a macro - -lib/readline/bind.c - - keyseq-timeout: new bindable variable, shadows _rl_keyseq_timeout - - string_varlist: add keyseq-timeout - - sv_seqtimeout: new function to modify value of _rl_keyseq_timeout; - clamps negative values at 0 for now - - _rl_get_string_variable_value: return value for keyseq-timeout - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - keyseq-timeout: documented - -lib/readline/isearch.c - - _rl_isearch_dispatch: modification to fix from 7/18 to not use - cxt->keymap and cxt->okeymap, since by the time this code is - executed, they are equal. Use `f' to check for rl_insert or - unbound func - - _rl_isearch_dispatch: if we're switching keymaps, not in - callback mode, and don't have pending or pushed input, use - _rl_input_queued to resolve a potentially ambiguous key sequence. - Suggested by Roger Zauner - - _rl_isearch_dispatch: if we have changed keymaps and resolved to - an editing function (not self-insert), make sure we stuff the - right characters back onto the input after changing the keymap - back so the right editing function is executed after the search - is terminated. Rest of fix for bug reported by Roger Zauner - - - 2/5 - --- -builtins/gen-helpfiles.c - - new file: reads struct builtin and writes the long docs to files - in the `helpdirs' subdirectory. The filename is given in the - previously-unused `handle' member of the struct builtin. Links - with `tmpbuiltins.o', which is created by Makefile to have the - right long documentation. When not cross-compiling, gets the - right #defines based on configuration options from config.h instead - of trying to parse conditional parts of def files. Fixes - shortcoming pointed out by Andreas Schwab - -builtins/Makefile.in - - tmpbuiltins.c: new generated file, created to enable creation of - separate helpfiles based on correct #defines instead of trying to - parse conditional parts of def files - - gen-helpfiles: new program to generate helpfiles, links with - tmpbuiltins.o - - HELPFILES_TARGET: new target, substituted by configure to `helpdoc' - if separate helpfiles requested - - targets: new target, libbuiltins.a and $(HELPFILES_TARGET) - - CREATED_OBJECTS: new variable, holds created object files for - make clean; changed make clean to remove created objects - - helpdoc: changed to call gen-helpfiles instead of mkbuiltins - -Makefile.in - - when building libbuiltins.a, recursively call make with `targets' - argument to make sure separate helpfiles get built - -configure.in - - substitute `helpdoc' as value of HELPFILES_TARGET if - --enable-separate-helpfiles supplied as configure argument - -builtins/mkbuiltins.c - - `-nofunctions': new argument, causes mkbuiltins to not write value - for function implementing a particular builtin to struct builtin - and to write document file name to `handle' member of struct builtin - - no longer writes separate helpfiles; that is left to gen-helpfiles - - 2/8 - --- -subst.c - - make sure last_command_exit_value is set to a non-zero value before - any calls to report_error, since `-e' set will short-circuit - report_error. Fixes bug reported by Ewan Mellor - - -variables.c - - make_local_array_variable: added second argument; if non-zero, - function will return an existing local associative array variable - instead of insisting on an indexed array - -variable.h,subst.c - - make_local_array_variable: changed prototype and caller - -builtins/declare.def - - declare_internal: add second arg to call to make_local_array_variable; - making_array_special, which indicates we're processing an - assignment like declare a[b]=c. Fixes seg fault resulting from - a being an already-declared local associative array variable in a - function. Ubuntu bash bug 928900. - - 2/14 - ---- - -execute_cmd.c - - execute_command_internal: if redirections into or out of a loop fail, - don't try to free ofifo_list unless saved_fifo is non-zero. It's - only valid if saved_fifo is set - - 2/15 - ---- -{arrayfunc,braces,variables}.c - - last_command_exit_value: make sure it's set before any calls to - report_error, since -e will cause that to exit the shell - -builtins/common.c - - get_job_by_name: call internal_error instead of report_error so this - doesn't exit the shell - - 2/18 - ---- -builtins/evalstring.c - - parse_and_execute: make sure the file descriptor to be redirected to - is 1 before calling cat_file. One fix for bug reported by Dan Douglas - - -parse.y - - read_token_word: don't return NUMBER if a string of all digits - resolves to a number that overflows the bounds of an intmax_t. - Other fix for bug reported by Dan Douglas - - 2/19 - ---- -lib/sh/strtrans.c - - ansicstr: use 0x7f as the boundary for characters that translate - directly from ASCII to unicode (\u and \U escapes) instead of - UCHAR_MAX, since everything >= 0x80 requires more than one byte. - Bug and fix from John Kearney - -builtins/printf.def - - tescape: ditto for printf \u and \U escape sequences - - 2/20 - ---- -lib/sh/unicode.c - - u32toutf8: fix to handle encodings up to six bytes long correctly - (though technically UTF-8 only has characters up to 4 bytes long). - Report and fix from John Kearney - - u32toutf8: first argument is now an unsigned 32-bit quantity, - changed callers (u32cconv) to pass c instead of wc - - u32reset: new function, resets local static state to uninitialized - (locale information, currently) - -locale.c - - call u32reset whenever LC_CTYPE/LC_ALL/LANG is changed to reset the - cached locale information used by u32cconv. From a report from - John Kearney - - 2/21 - ---- -doc/{bash,builtins}.1 - - minor changes from Bjarni Ingi Gislason - -lib/sh/unicode.c - - u32cconv: only assume you can directly call wctomb on the passed - value if __STDC_ISO_10646__ is defined and the value is <= - 0x7fffffff - - stub_charset: return locale as default instead of "ASCII", let - rest of code decide what to do with it - -lib/readline/parens.c - - _rl_enable_paren_matching: make paren matching work in vi insert - mode. Bug report from - - 2/22 - ---- -lib/sh/shquote.c - - sh_backslash_quote: quote tilde in places where it would be - expanded. From a report from John Kearney - - 2/23 - ---- -execute_cmd.c - - execute_pipeline: wrap the discard_unwind_frame call in #ifdef - JOB_CONTROL, since the frame is only created if JOB_CONTROL is - defined. Bug and fix from Doug Kehn - - 2/25 - ---- -error.c - - report_error: make sure last_command_exit_value is non-zero before - we call exit_shell, since the exit trap may reference it. Call - exit_shell with last_command_exit_value to allow exit statuses - other than 1 - -unicode.c - - stub_charset: use local static buffer to hold charset, don't change - value returned by get_locale_var. Based on idea and code from - John Kearney - - u32toutf16: function to convert unsigned 32-bit value (unicode) to - UTF-16. From John Kearney - - u32cconv: call u32toutf16 if __STDC_ISO_10646__ defined and wchar_t - is two bytes, send result to wcstombs, return if not encoding error. - From John Kearney - - u32cconv: return UTF-8 conversion if iconv conversion to local - charset is unsupported - - 3/2 - --- -lib/readline/complete.c - - print_filename: if there is no directory hook, but there is a stat - hook, and we want to append a slash to directories, call the stat - hook before calling path_isdir on the expanded directory name. - Report and pointer to fix from Steve Rago - - 3/3 - --- -builtins/evalstring.c - - parse_and_execute: fix to change of 2/18: make sure the file - descriptor being redirected to is 0 before calling cat_file when - we see something like $(< file). Real fix for bug reported by - Dan Douglas - -subst.c - - parameter_brace_patsub: run the replacement string through quote - removal even if the expansion is within double quotes, because - the parser and string extract functions treat the quotes and - backslashes as special. If they're treated as special, quote - removal should remove them (this is the Posix position and - compatible with ksh93). THIS IS NOT BACKWARDS COMPATIBLE. - - 3/4 - --- -lib/readline/complete.c - - rl_menu_complete: fix to make show-all-if-ambiguous and - menu-complete-display-prefix work together if both are set. Fix - from Sami Pietila - - 3/5 - --- -bashline.c - - dircomplete_expand_relpath: new variable, if non-zero, means that - `shopt -s direxpand' should expand relative pathnames. Zero by - default, not user-settable yet - - bash_directory_completion_hook: if we have a relative pathname that - isn't changed by canonicalization or spell checking after being - appended to $PWD, then don't change what the user typed. Controlled - by dircomplete_expand_relpath - - 3/7 - --- -m4/timespec.m4 - - new macros, cribbed from gnulib and coreutils: find out whether we - have `struct timespec' and what file includes it - -m4/stat-time.m4 - - new macros, cribbed from gnulib and coreutils: find out whether the - mtime/atime/ctime/etctime fields of struct stat are of type - struct timespec, and what the name is - -include/stat-time.h - - new file, cribbed from gnulib, with additions from coreutils: include - the right file to get the struct timespec define, or provide our own - replacement. Provides a bunch of inline functions to turn the - appropriate members of struct stat into `struct timespec' values, - zeroing out the tv_nsec field if necessary - -test.c - - include "stat-time.h" for the nanosecond timestamp resolution stuff - - stat_mtime: new function, returns struct stat and the mod time - normalized into a `struct timespec' for the filename passed as the - first argument - - filecomp: call stat_mtime instead of sh_stat for each filename - argument to get the mtime as a struct timespec - - filecomp: call timespec_cmp instead of using a straight arithmetic - comparison for the -nt and -ot operators, using timespec returned by - stat_mtime. Added functionality requested by by Werner Fink - for systems that can support it - - 3/10 - ---- -include/posixdir.h - - REAL_DIR_ENTRY: remove dependency on _POSIX_SOURCE, only use feature - test macros to decide whether dirent.d_ino is present and usable; - define D_INO_AVAILABLE. Report and fix from Fabrizion Gennari - - - D_FILENO_AVAILABLE: define if we can use dirent.d_fileno - -lib/sh/getcwd.c - - use D_FILENO_AVAILABLE to decide whether or not to compile in - _path_checkino and whether or not to call it. Report and initial - fix from Fabrizion Gennari - -lib/readline/signals.c - - make sure all occurrences of SIGWINCH are protected by #ifdef - -sig.c - - make sure all occurrences of SIGCHLD are protected by #ifdef - -nojobs.c - - make sure SA_RESTART is defined to 0 if the OS doesn't define it - -version.c - - show_shell_version: don't use string literals in printf, use %s. - Has added benefit of removing newline from string to be translated - -trap.c - - queue_sigchld_trap: new function, increments the number of pending - SIGCHLD signals by the argument, which is by convention the number - of children reaped in a call to waitchld() - -trap.h - - queue_sigchld_trap: new extern declaration - -jobs.c - - waitchld: if called from the SIGCHLD signal handler (sigchld > 0), - then call queue_sigchld_trap to avoid running the trap in a signal - handler context. Report and original fix from Siddhesh Poyarekar - - -lib/sh/unicode.c - - u32tocesc: take an unsigned 32-bit quantity and encode it using - ISO C99 string notation (\u/\U) - - u32cconv: call u32tocesc as a fallback instead of u32cchar - - u32cconv: call u32tocesc if iconv cannot convert the character. - Maybe do the same thing if iconv_open fails - - u32reset: call iconv_close on localconv if u32init == 1 - - 3/11 - ---- -config-top.h - - CHECKWINSIZE_DEFAULT: new define, set to initial value of - check_window_size (shopt checkwinsize): 0 for off, 1 for on. - Default is 0 - -{jobs,nojobs}.c - - check_window_size: default initial value to CHECKWINSIZE_DEFAULT - - 3/13 - ---- -doc/bashref.texi - - change text referring to the copying restrictions to that - recommended by the FSF (no Front-Cover Texts and no Back-Cover - Texts) - -lib/readline/doc/{history,rlman,rluserman}.texi - - change text referring to the copying restrictions to that - recommended by the FSF (no Front-Cover Texts and no Back-Cover - Texts) - - 3/15 - ---- -array.c - - LASTREF_START: new macro to set the starting position for an array - traversal to `lastref' if that's valid, and to the start of the array - if not. Used in array_reference, array_insert, array_remove - - array_remove: try to be a little smarter with lastref instead of - unconditionally invalidating it - - 3/16 - ---- -array.c - - array_insert: fix memory leak by deleting element to be added in the - case of an error - - 3/18 - ---- -lib/sh/mbschr.c - - mbschr: don't call mbrlen unless is_basic is false; devolves to a - straight character-by-character run through the string - - 3/19 - ---- -stringlib.c - - substring: use memcpy instead of strncpy, since we know the length - and are going to add our own NUL terminator - - 3/20 - ---- -subst.c - - parameter_brace_expand_rhs: if expand_string_for_rhs returns a quoted - null string (a list with one element for which - QUOTED_NULL(list->word->word) returns true), return the quoted null - and set the flags in the returned word to indicate it. Fixes bug - reported by Mark Edgar - -lib/sh/tmpfile.c - - use random(3) instead of get_random_number to avoid perturbing the - random sequence you get using $RANDOM. Bug report and fix from - Jurij Mihelic - - 3/21 - ---- -config-top.h - - OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT: define to 1 to optimize - sequential indexed array assignment patterns. Defined to 1 by - default - -array.c - - array_insert: if OPTIMIZE_SEQUENTIAL_ARRAY_ASSIGNMENT is defined, - start the search at lastref (see change from 3/15) - - 3/27 - ---- -print_cmd.c - - debug_print_word_list: new debugging function, prints a word list - preceded by an optional string and using a caller-specified - separator - - 4/1 - --- -command.h - - W_ASSNGLOBAL: new flag, set to indicate declare -g - -execute_cmd.c - - fix_assignment_words: note that we have a -g argument to an assignment - builtin and set the W_ASSNGLOBAL flag in the variable word - -subst.c - - dump_word_flags: print out W_ASSNGLOBAL if present - - do_assignment_internal: only set ASS_MKLOCAL if W_ASSIGNARG is set - and W_ASSNGLOBAL is not. Don't want to create a local variable even - if variable_context is non-zero if ASSNGLOBAL is set. Fixes bug - reported by Bill Gradwohl - - 4/7 - --- -lib/readline/readline.c - - _rl_dispatch_subseq: make the `keyseq-timeout' variable apply to - ESC processing when in vi mode. After hitting ESC, readline will - wait up to _rl_keyseq_timeout*1000 microseconds (if set) for - additional input before dispatching on the ESC and switching to - command/movement mode. Completes timeout work suggested by - ; this prompted by report from Barry Downes - - -lib/sh/shmbchar.c - - sh_mbsnlen: new function, returns the number of (possibly multibyte) - characters in a passed string with a passed length, examining at most - maxlen (third argument) bytes - -externs.h - - sh_mbsnlen: extern declaration for new function - -shell.c - - exit_shell: call maybe_save_shell_history if remember_on_history is - set, not just in interactive shells. That means the history is - saved if history is enabled, regardless of whether or not the shell - is interactive - -doc/{bash.1,bashref.texi} - - TMOUT: fix description to make it explicit that TMOUT is the timeout - period for a complete line of input, not just any input. Fixes - problem reported in Ubuntu bug 957303: - https://bugs.launchpad.net/ubuntu/+source/bash/+bug/957303 - - HISTFILE: document change to write history list to history file in - any shell with history enabled, not just interactive shells. This - seems to be more logical behavior. Suggested by Greg Wooledge - - - 4/12 - ---- -lib/readline/colors.h - - only include stdbool.h if HAVE_STDBOOL_H is defined - - if HAVE_STDBOOL_H is not defined, provide enough definition for the - library to use `bool', `true', and `false' - -lib/readline/parse-colors.[ch] - - don't try to include at all; rely on colors.h to do it - -lib/sh/snprintf.c - - vsnprintf_internal: only treat '0' as a flag to indicate zero padding - if `.' hasn't been encountered ((flags&PF_DOT) == 0); otherwise treat - it as the first digit of a precision specifier. Fixes bug reported - by Petr Sumbera - - 4/15 - ---- -lib/sh/snprintf.c - - vsnprintf_internal: if the '0' and '-' flags both occur, the '0' - flag is ignored -- Posix. Start of a series of fixes based on - tests and patches from Petr Sumbera - - PUT_PLUS: make sure PF_PLUS flag is specified before putting the `+' - - vsnprintf_internal: when '+' is read as a flag, don't set right- - justify flag if the LADJUST (`-') flag has already been supplied - - floating: make sure to output space padding before the `+', zero - padding after - - exponent: make sure to output space padding before the `+', zero - padding after - - exponent: only subtract one from the width for the decimal point - if we're really going to print one - - floating: use presence of PF_PLUS flag to decide whether to account - for the `+' in the padded field width. Ditto for exponent() - - 4/16 - ---- -lib/sh/snprintf.c - - vsnprint_internal: only reduce precision by 1 when processing the `g' - format if it's > 0. A precision of 0 should stay 0; otherwise it - gets set to -1 (NOT_FOUND) and converted to the default - - number, lnumber: if an explicit precision is supplied, turn off the - zero-padding flag and set the pad character back to space - - number, lnumber: only account for a `+' when performing the field - width calculation if the coversion is base 10; we don't add a `+' - for other bases - - 4/18 - ---- -tests/printf3.sub - - try using "perl -e 'print time'" to get the current time in seconds - since the epoch if "date +%s" is not available (solaris 8-10) - - 4/19 - ---- -tests/run-printf - - use cat -v instead of relying on diff -a being available to convert - control characters to ascii and avoid the dreaded "Binary files - /tmp/xx and printf.right differ" - - 4/20 - ---- -lib/sh/strftime.c - - incoporated new version from Aharon Robbins - - 4/22 - ---- -doc/{bash.1,bashref.texi} - - slight change to the description of /dev/tcp and /dev/udp - -subst.c - - match_wpattern: logic fix to the calculation of `simple' (was |=, - needs to be &=). Bug report from Mike Frysinger , - fix from Andreas Schwab - -bashline.c - - bash_filename_stat_hook: add code from bash_directory_completion_hook - that performs pathname canonicalization in the same way that cd and - other builtins will do - - 4/25 - ---- -execute_cmd.c - - execute_pipeline: change the call to move_to_high_fd to make it use - getdtablesize() and to not stomp on existing open file descriptors, - like the fd the shell is using to read a script. Bug report from - Greg Wooledge - - 5/6 - --- -subst.c - - expand_word_internal: case '$': after calling param_expand and - setting had_quoted_null, set TEMP to null. The code that builds the - returned string at the end of the function will take care of making - and returning a quoted null string if there's nothing else in - ISTRING. If there is, the quoted null should just go away. Part of - fix for bug reported by Ruediger Kuhlmann - - expand_word_internal: when processing ISTRING to build return value, - only set W_HASQUOTEDNULL in the returned word flags if the word is - a quoted null string AND had_quoted_null is set. Rest of fix - - 5/9 - --- -variables.c - - bind_variable_internal: if we get an array variable here (implicit - assignment to index 0), call make_array_variable_value, which - dummies up a fake SHELL_VAR * from array[0]. This matters when - we're appending and have to use the current value - - bind_variable_internal: after computing the new value, treat assoc - variables with higher precedence than simple array variables; it - might be that a variable has both attributes set - -arrayfunc.c - - bind_array_var_internal: break code out that handles creating the - new value to be assigned to an array variable index into a new - function, make_array_variable_value. This handles creating a - dummy SHELL_VAR * for implicit array[0] assignment. Fixes bug - reported by Dan Douglas - -arrayfunc.h - - make_array_variable_value: new extern declaration - - 5/19 - ---- -variables.c - - bind_int_variable: if an assignment statement like x=y comes in - from the expression evaluator, and x is an array, handle it like - x[0]=y. Fixes bug reported by Dan Douglas - - 5/24 - ---- - -braces.c - - mkseq: handle possible overflow and break the sequence generating - loop if it occurs. Fixes OpenSUSE bug 763591: - https://bugzilla.novell.com/show_bug.cgi?id=763591 - - 5/25 - ---- -Makefile.in - - LDFLAGS_FOR_BUILD: add to compilation recipes for build tools - buildversion, mksignames, mksyntax - - LDFLAGS_FOR_BUILD: add to compilation recipes for test tools - recho, zecho, printenv, xcase - -builtins/Makefile.in - - LDFLAGS_FOR_BUILD: add to compilation recipes for build tools - gen-helpfiles, psize.aux - -variables.c - - bind_int_variable: if LHS is a simple variable name without an array - reference, but resolves to an array variable, call - bind_array_variable with index 0 to make x=1 equivalent to x[0]=1. - Fixes bug reported by Dan Douglas - - 5/27 - ---- -subst.c - - expand_word_internal: make sure has_dollar_at doesn't get reset before - recursive calls to param_expand or expand_word_internal, since it has - to save state of what came before. Use temp variable and make sure - has_dollar_at is incremented if recursive call processes "$@". - Fixes bug reported by gregrwm and - supplemented by Dan Douglas - -doc/{bash.1,bashref.texi} - - changes to the description of substring expansion inspired by - suggestions from Bill Gradwohl - -doc/bashref.texi - - added substring expansion examples inspired by suggestions from - Bill Gradwohl - -variables.c - - find_shell_variable: search for a variable in the list of shell - contexts, ignore the temporary environment - - find_variable_tempenv: search for a variable in the list of shell - contexts, force search of the temporary environment - - find_variable_notempenv: search for a variable in the list of shell - contexts, don't force search of the temporary environment - -variables.h - - find_shell_variable: extern declaration - - find_variable_tempenv: extern declaration - - find_variable_notempenv: extern declaration - -arrayfunc.c - - bind_array_variable: call find_shell_variable instead of calling - var_lookup directly - -findcmd.c - - search_for_command: call find_variable_tempenv instead of - find_variable_internal directly - - _find_user_command_internal: call find_variable_tempenv instead of - find_variable_internal directly - -builtins/setattr.def - - set_var_attribute: call find_variable_notempenv instead of - find_variable_internal directly - - show_name_attributes: call find_variable_tempenv instead of - find_variable_internal directly - - 6/1 - --- -sig.c - - termsig_handler: don't try to save the shell history on a terminating - signal any more, since it just causes too many problems on Linux - systems using glibc and glibc malloc - -lib/readline/vi_mode.c - - rl_vi_change_to: change to correctly redo `cc', since `c' is not a vi - motion character. From Red Hat bug 813289 - - rl_vi_delete_to: change to correctly redo `dd', since `d' is not a vi - motion character - - rl_vi_yank_to: change to correctly redo `yy', since `y' is not a vi - motion character - - 6/4 - --- -lib/sh/mktime.c - - current versions of VMS do not need to include . Fix from - John E. Malmberg - - 6/5 - --- -lib/sh/eaccess.c - - sh_stat: instead of using a static buffer to do the DEV_FD_PREFIX - translation, use a dynamically-allocated buffer that we keep - resizing. Fixes potential security hole reported by David Leverton - - - 6/5 - --- -braces.c - - expand_seqterm: check errno == ERANGE after calling strtoimax for - rhs and incr. Part of a set of fixes from Scott McMillan - - - expand_seqterm: incr now of type `intmax_t', which changes - arguments to mkseq - - mkseq: a better fix for detecting overflow and underflow since it's - undefined in C and compilers `optimize' out overflow checks. Uses - ADDOVERFLOW and SUBOVERFLOW macros - - mkseq: use sh_imaxabs (new macro) instead of abs() for intmax_t - variables - - mkseq: don't allow incr to be converted to -INTMAX_MIN - - mkseq: make sure that strvec_create isn't called with a size argument - greater than INT_MAX, since it only takes an int - - 6/6 - --- -braces.c - - mkseq: try and be smarter about not overallocating elements in - the return array if the increment is not 1 or -1 - - 6/7 - --- -parse.y - - history_delimiting_chars: if the parser says we're in the middle of - a compound assignment (PST_COMPASSIGN), just return a space to avoid - adding a stray semicolon to the history entry. Fixes bug reported - by "Davide Brini" - - 6/8 - --- -bashline.c - - bash_directory_completion_hook: don't attempt spelling correction - on the directory name unless the direxpand option is set and we are - going to replace the directory name with the corrected one in the - readline line. Suggested by Linda Walsh - -lib/sh/shquote.c - - sh_backslash_quote: now takes a third argument: flags. If non-zero, - tildes are not backslash-escaped. Have to handle both printf %q, - where they should be escaped, and filename completion, where they - should not when used as usernames - -externs.h - - sh_backslash_quote: declaration now takes a third argument - -builtins/printf.def - - printf_builtin: call sh_backslash_quote with 1 as third argument - so tildes get escaped - -{bashline,bracecomp}.c - - call sh_backslash_quote with 0 as third argument so tildes are not - escaped in completed words - -doc/bash.1 - - add `coproc' to the list of reserved words. From a report by - Jens Schweikhardt - - 6/10 - ---- -execute_cmd.c - - line_number_for_err_trap: now global, so parse_and_execute can save - and restore it with unwind-protect - -builtins/evalstring.c - - parse_prologue: save and restore line_number_for_err_trap along - with line_number - - restore_lastcom: new function, unwind-protect to restore - the_printed_command_except_trap - - parse_prologue: use restore_lastcom to save and restore the value - of the_printed_command_except_trap around calls to parse_and_execute - (eval/source/.) - - 6/15 - ---- -lib/readline/complete.c - - complete_fncmp: change filename comparison code to understand - multibyte characters, even when doing case-sensitive or case-mapping - comparisons. Fixes problem reported by Nikolay Shirokovskiy - - - 6/20 - ---- -builtins/mapfile.def - - mapfile: move the line count increment and check for having read - the specified number of lines to the end of the loop to avoid - reading an additional line with zgetline. Fixes bug reported by - Dan Douglas - - 6/21 - ---- - -execute_cmd.c - - execute_pipeline: make sure `lastpipe_flag' is initialized to 0 on - all systems, since it's tested later in the function. Fixes bug - reported by John E. Malmberg - - 6/22 - ---- -mailcheck.c - - file_mod_date_changed: return 0 right away if mailstat() does not - return success. Fixes bug with using uninitialized values reported - by szymon.kalasz@uj.edu.pl - -builtins/set.def - - the `monitor' option is not available when the shell is compiled - without job control, since the underlying `m' flag is not available - -nojobs.c - - job_control: now declared as int variable, initialized to 0, never - modified - -jobs.h - - job_control: extern declaration no longer dependent on JOB_CONTROL - -execute_cmd.c - - execute_pipeline: made necessary changes so `lastpipe' shell option - is now available in all shells, even those compiled without - JOB_CONTROL defined - - 6/23 - ---- -lib/glob/glob.c - - glob_filename: check for interrupts before returning if glob_vector - returns NULL or an error. Bug reported by Serge van den Boom - , fix from Andreas Schwab - - call run_pending_traps after each call to QUIT or test of - interrupt_state, like we do in mainline shell code - - glob_vector: don't call QUIT; in `if (lose)' code block; just free - memory, return NULL, and let callers deal with interrupt_state or - other signals and traps - - 6/25 - ---- -lib/readline/input.c - - rl_read_key: restructure the loop that calls the event hook a little, - so that the hook is called only after rl_gather_tyi returns no input, - and any pending input is returned first. This results in better - efficiency for processing pending input without calling the hook - on every input character as bash-4.1 did. From a report from - Max Horn - - 6/26 - ---- -trap.c - - signal_is_pending: return TRUE if SIG argument has been received and - a trap is waiting to execute - -trap.h - - signal_is_pending: extern declaration - -lib/glob/glob.c - - glob_vector: check for pending SIGINT trap each time through the loop, - just like we check for interrupt_state or terminating_signal, and - set `lose = 1' so we clean up after ourselves and interrupt the - operation before running the trap. This may require a change later, - maybe call run_pending_traps and do that if run_pending_traps returns? - -variables.c - - sv_histtimefmt: set history_comment_character to default (`#') if - it's 0 when we're turning on history timestamps. The history code - uses the history comment character to prefix timestamps, and - leaving it at 0 effectively removes them from the history. From a - report to help-bash by Dennis Williamson - - 6/27 - ---- -lib/readline/signals.c - - rl_maybe_restore_sighandler: new function, sets handler for SIG to - HANDLER->sa_handler only if it's not SIG_IGN. Needs to be called - on same signals set using rl_maybe_set_sighandler, which does not - override an existing SIG_IGN handler (SIGALRM is ok since it does - the check inline; doesn't mess with SIGWINCH) - - 6/30 - ---- -variables.h - - additional defines for the new `nameref' variable attribute - (att_nameref): nameref_p, nameref_cell, var_setref - -variables.c - - find_variable_nameref: resolve SHELL_VAR V through chain of namerefs - - find_variable_last_nameref: resolve variable NAME until last in a - chain of possibly more than one nameref starting at shell_variables - - find_global_variable_last_nameref: resolve variable NAME until last - in a chain of possibly more than one nameref starting at - global_variables - - find_nameref_at_context: resolve SHELL_VAR V through chain of namerefs - in a specific variable context (usually a local variable hash table) - - find_variable_nameref_context: resolve SHELL_VAR V through chain of - namerefs following a chain of varible contexts - - find_variable_last_nameref_context: resolve SHELL_VAR V as in - find_variable_last_context, but return the final nameref instead of - what the final nameref resolves to - - find_variable_tempenv, find_variable_notempenv, find_global_variable, - find_shell_variable, find_variable: modified to follow namerefs - - find_global_variable_noref: look up a global variable without following - any namerefs - - find_variable_noref: look up a shell variable without following any - namerefs - - bind_variable_internal: modify to follow a chain of namerefs in the - global variables table; change to handle assignments to a nameref by - following nameref chain - - bind_variable: modify to follow chain of namerefs when binding to a - local variable - - unbind_variable: changes to unset nameref variables (unsets both - nameref and variable it resolves to) - -subst.c - - parameter_brace_expand_word: change to handle expanding nameref whose - value is x[n] - - parameter_brace_expand_indir: change to expand in ksh93-compatible - way if variable to be indirected is nameref and a simple (non-array) - expansion - - param_expand: change to expand $foo where foo is a nameref whose value - is x[n] - -execute_cmd.c - - execute_for_command: changes to implement ksh93 semantics when index - variable is a nameref - -builtins/setattr.def - - show_var_attributes: change to add `n' to flags list if att_nameref - is set - -builtins/set.def - - unset_builtin: changes to error messages to follow nameref variables - -builtins/declare.def - - document new -n option - - declare_internal: new `-n' and `+n' options - - declare_internal: handle declare -n var[=value] and - declare +n var[=value] for existing and non-existant variables. - Enforce restriction that nameref variables cannot be arrays. - Implement semi-peculiar ksh93 semantics for typeset +n ref=value - - 7/5 - --- -variables.c - - unbind_variable: unset whatever a nameref resolves to, leaving the - nameref variable itself alone - - unbind_nameref: new function, unsets a nameref variable, not the - variable it references - -variables.h - - unbind_nameref: extern declaration - -builtins/set.def - - unset_builtin: modify to add -n option, which calls unbind_nameref - leaving unbind_variable for the usual case. This required slight - changes and additions to the test suite - -doc/{bash.1,bashref.texi} - - document namerefs and typeset/declare/local/unset -n - - 7/13 - ---- -lib/sh/casemod.c - - include shmbchar.h for is_basic and supporting pieces - - sh_casemod: use _to_wupper and _to_wlower to convert wide character - case instead of TOUPPER and TOLOWER. Fixes bug reported by - Dennis Williamson , fix from - Andreas Schwab - - cval: short-circuit and return ascii value if is_basic tests true - - sh_casemod: short-circuit and use non-multibyte case modification - and toggling code if is_basic tests true - -lib/readline/signals.c - - _rl_{block,release}_sigint: remove the code that actually blocks and - releases the signals, since we defer signal handling until calls to - RL_CHECK_SIGNALS() - -lib/readline/{callback,readline,util}.c - - if HAVE_POSIX_SIGSETJMP is defined, use sigsetjmp/siglongjmp without - saving and restoring the signal mask instead of setjmp/longjmp - -lib/readline/rltty.c - - prepare_terminal_settings: don't mess with IXOFF setting if - USE_XON_XOFF defined - -doc/{bash.1,bashref.texi} - - add some text to the description of set -e clarifying its effect - on shell functions and shell function execution. Suggested by - Rainer Blome - -bashline.c - - edit_and_execute_command: increment current_command_line_count before - adding partial line to command history (for command-oriented-history - because of rl_newline at beginning of function), then reset it to 0 - before adding the dummy history entry to make sure the dummy entry - doesn't get added to previous incomplete command. Partial fix for - problem reported by Peng Yu - - 7/24 - ---- -configure.in - - interix: define RECYCLES_PIDS. Based on a report from Michael - Haubenwallner - - 7/26 - ---- -jobs.c - - make_child: call bgp_delete on the newly-created pid unconditionally. - Some systems reuse pids before cycling through an entire set of - CHILD_MAX/_SC_CHILD_MAX unique pids. This is no longer dependent - on RECYCLES_PIDS. Based on a report from Michael Haubenwallner - - -support/shobj-conf - - Mac OS X: drop MACOSX_DEPLOYMENT_TARGET=10.3 from the LDFLAGS. We - can finally kill Panther - - 7/28 - ---- -subst.c - - command_substitute: make sure last_made_pid gets reset if make_child - fails - -execute_cmd.c - - execute_command_internal: case cm_simple: decide whether or not to - wait_for a child if already_making_children is non-zero, indicates - that there is an unwaited-for child. More of fix for bug report - from Michael Haubenwallner - -jobs.c - - make_child: call delete_old_job (new_pid) unconditionally, don't - bother to check whether or not pid wrap occurred. Rest of fix for - bug report from Michael Haubenwallner - - - 7/29 - ---- -shell.c - - subshell_exit: new function, exits the shell (via call to sh_exit()) - after calling any defined exit trap - -externs.h - - subshell_exit: new extern declaration - -execute_cmd.c - - execute_command_internal: make sure to call subshell_exit for - {} group commands executed asynchronously (&). Part of fix for - EXIT trap bug reported by Maarten Billemont - -sig.c - - reset_terminating_signals: make sure to set termsigs_initialized back - to 0, so a subsequent call to initialize_terminating_signals works - right. Rest of fix for bug reported by Maarten Billemont - - -{execute_cmd,general,jobs,mailcheck,mksyntax,test}.c -builtins/{cd,fc,pushd,ulimit}.def -lib/malloc/getpagesize.h - - make inclusion of dependent on HAVE_SYS_PARAM_H - consistently diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old deleted file mode 100644 index 1707ab10c..000000000 --- a/CWRU/POSIX.NOTES.old +++ /dev/null @@ -1,82 +0,0 @@ -Starting bash with the `--posix' command-line option or executing -`set -o posix' while bash is running will cause bash to conform more -closely to the Posix.2 standard by changing the behavior to match that -specified by Posix.2 in areas where the bash default differs. - -The following list is what's changed when `posix mode' is in effect: - -1. When a command in the hash table no longer exists, bash will re-search - $PATH to find the new location. This is also available with - `shopt -s checkhash'. - -2. The >& redirection does not redirect stdout and stderr. - -3. The message printed by the job control code and builtins when a job - exits with a non-zero status is `Done(status)'. - -4. Reserved words may not be aliased. - -5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and - `!!' -> `!' are enabled, and parameter expansion is performed on - the value regardless of the setting of the `promptvars' option. - -6. Interactive comments are enabled by default. (Note that bash has - them on by default anyway.) - -7. The Posix.2 startup files are executed ($ENV) rather than the normal - bash files. - -8. Tilde expansion is only performed on assignments preceding a command - name, rather than on all assignment statements on the line. - -9. The default history file is ~/.sh_history (default value of $HISTFILE). - -10. The output of `kill -l' prints all the signal names on a single line, - separated by spaces. - -11. Non-interactive shells exit if `file' in `. file' is not found. - -12. Redirection operators do not perform pathname expansion on the word - in the redirection unless the shell is interactive - -13. Function names must be valid shell identifiers. That is, they may not - contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal name - causes a fatal syntax error in non-interactive shells. - -14. Posix.2 `special' builtins are found before shell functions during command - lookup. - -15. If a Posix.2 special builtin returns an error status, a non-interactive - shell exits. The fatal errors are those listed in the POSIX.2 standard, - and include things like passing incorrect options, redirection errors, - variable assignment errors for assignments preceding the command name, - and so on. - -16. The environment passed to executed commands is not sorted. Neither is - the output of `set'. This is not strictly Posix.2 behavior, but sh - does it this way. Ksh does not. It's not necessary to sort the - environment; no program should rely on it being sorted. - -17. If the `cd' builtin finds a directory to change to using $CDPATH, the - value it assigns to $PWD does not contain any symbolic links, as if - `cd -P' had been executed. - -18. A non-interactive shell exits with an error status if a variable - assignment error occurs when no command name follows the assignment - statements. A variable assignment error occurs, for example, when - trying to assign a value to a read-only variable. - -19. A non-interactive shell exits with an error status if the iteration - variable in a for statement or the selection variable in a select - statement is a read-only variable. - -20. Process substitution is not available. - -21. Assignment statements preceding POSIX.2 `special' builtins persist in - the shell environment after the builtin completes. - -There is other Posix.2 behavior that bash does not implement. Specifically: - -1. Assignment statements affect the execution environment of all builtins, - not just special ones. diff --git a/CWRU/old/set.def.save b/CWRU/old/set.def.save deleted file mode 100644 index 87b78d7cc..000000000 --- a/CWRU/old/set.def.save +++ /dev/null @@ -1,544 +0,0 @@ -This file is set.def, from which is created set.c. -It implements the "set" and "unset" builtins in Bash. - -Copyright (C) 1987, 1989, 1991 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 1, 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; see the file COPYING. If not, write to the Free Software -Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -$PRODUCES set.c - -#include -#include "../shell.h" -#include "../flags.h" - -#include "bashgetopt.h" - -extern int interactive; -extern int noclobber, posixly_correct; -#if defined (READLINE) -extern int rl_editing_mode, no_line_editing; -#endif /* READLINE */ - -$BUILTIN set -$FUNCTION set_builtin -$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...] - -a Mark variables which are modified or created for export. - -b Notify of job termination immediately. - -e Exit immediately if a command exits with a non-zero status. - -f Disable file name generation (globbing). - -h Locate and remember function commands as functions are - defined. Function commands are normally looked up when - the function is executed. - -i Force the shell to be an "interactive" one. Interactive shells - always read `~/.bashrc' on startup. - -k All keyword arguments are placed in the environment for a - command, not just those that precede the command name. - -m Job control is enabled. - -n Read commands but do not execute them. - -o option-name - Set the variable corresponding to option-name: - allexport same as -a - braceexpand same as -B -#if defined (READLINE) - emacs use an emacs-style line editing interface -#endif /* READLINE */ - errexit same as -e - histexpand same as -H - ignoreeof the shell will not exit upon reading EOF - interactive-comments - allow comments to appear in interactive commands - monitor same as -m - noclobber disallow redirection to existing files - noexec same as -n - noglob same as -f - nohash same as -d - notify save as -b - nounset same as -u - physical same as -P - posix change the behavior of bash where the default - operation differs from the 1003.2 standard to - match the standard - privileged same as -p - verbose same as -v -#if defined (READLINE) - vi use a vi-style line editing interface -#endif /* READLINE */ - xtrace same as -x - -p Turned on whenever the real and effective user ids do not match. - Disables processing of the $ENV file and importing of shell - functions. Turning this option off causes the effective uid and - gid to be set to the real uid and gid. - -t Exit after reading and executing one command. - -u Treat unset variables as an error when substituting. - -v Print shell input lines as they are read. - -x Print commands and their arguments as they are executed. - -l Save and restore the binding of the NAME in a FOR command. - -d Disable the hashing of commands that are looked up for execution. - Normally, commands are remembered in a hash table, and once - found, do not have to be looked up again. -#if defined (BRACE_EXPANSION) - -B the shell will perform brace expansion -#endif /* BRACE_EXPANSION */ -#if defined (BANG_HISTORY) - -H Enable ! style history substitution. This flag is on - by default. -#endif /* BANG_HISTORY */ - -C If set, disallow existing regular files to be overwritten - by redirection of output. - -P If set, do not follow symbolic links when executing commands - such as cd which change the current directory. - -Using + rather than - causes these flags to be turned off. The -flags can also be used upon invocation of the shell. The current -set of flags may be found in $-. The remaining n ARGs are positional -parameters and are assigned, in order, to $1, $2, .. $n. If no -ARGs are given, all shell variables are printed. -$END - -/* An a-list used to match long options for set -o to the corresponding - option letter. */ -struct { - char *name; - int letter; -} o_options[] = { - { "allexport", 'a' }, -#if defined (BRACE_EXPANSION) - { "braceexpand",'B' }, -#endif - { "errexit", 'e' }, - { "histexpand", 'H' }, - { "monitor", 'm' }, - { "noexec", 'n' }, - { "noglob", 'f' }, - { "nohash", 'd' }, -#if defined (JOB_CONTROL) - { "notify", 'b' }, -#endif /* JOB_CONTROL */ - {"nounset", 'u' }, - {"physical", 'P' }, - {"privileged", 'p' }, - {"verbose", 'v' }, - {"xtrace", 'x' }, - {(char *)NULL, 0}, -}; - -#define MINUS_O_FORMAT "%-15s\t%s\n" - -void -list_minus_o_opts () -{ - register int i; - char *on = "on", *off = "off"; - - printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); - - if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) - printf (MINUS_O_FORMAT, "ignoreeof", on); - else - printf (MINUS_O_FORMAT, "ignoreeof", off); - - printf (MINUS_O_FORMAT, "interactive-comments", - interactive_comments ? on : off); - - printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); - -#if defined (READLINE) - if (no_line_editing) - { - printf (MINUS_O_FORMAT, "emacs", off); - printf (MINUS_O_FORMAT, "vi", off); - } - else - { - /* Magic. This code `knows' how readline handles rl_editing_mode. */ - printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off); - printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off); - } -#endif /* READLINE */ - - for (i = 0; o_options[i].name; i++) - { - int *on_or_off, zero = 0; - - on_or_off = find_flag (o_options[i].letter); - if (on_or_off == FLAG_UNKNOWN) - on_or_off = &zero; - printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off); - } -} - -set_minus_o_option (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - int option_char = -1; - - if (STREQ (option_name, "noclobber")) - { - if (on_or_off == FLAG_ON) - bind_variable ("noclobber", ""); - else - unbind_variable ("noclobber"); - stupidly_hack_special_variables ("noclobber"); - } - else if (STREQ (option_name, "ignoreeof")) - { - unbind_variable ("ignoreeof"); - unbind_variable ("IGNOREEOF"); - if (on_or_off == FLAG_ON) - bind_variable ("IGNOREEOF", "10"); - stupidly_hack_special_variables ("IGNOREEOF"); - } - -#if defined (READLINE) - else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) - { - if (on_or_off == FLAG_ON) - { - rl_variable_bind ("editing-mode", option_name); - - if (interactive) - with_input_from_stdin (); - no_line_editing = 0; - } - else - { - int isemacs = (rl_editing_mode == 1); - if ((isemacs && STREQ (option_name, "emacs")) || - (!isemacs && STREQ (option_name, "vi"))) - { - if (interactive) - with_input_from_stream (stdin, "stdin"); - no_line_editing = 1; - } - else - builtin_error ("not in %s editing mode", option_name); - } - } -#endif /* READLINE */ - else if (STREQ (option_name, "interactive-comments")) - interactive_comments = (on_or_off == FLAG_ON); - else if (STREQ (option_name, "posix")) - { - posixly_correct = (on_or_off == FLAG_ON); - unbind_variable ("POSIXLY_CORRECT"); - unbind_variable ("POSIX_PEDANTIC"); - if (on_or_off == FLAG_ON) - { - bind_variable ("POSIXLY_CORRECT", ""); - stupidly_hack_special_variables ("POSIXLY_CORRECT"); - } - } - else - { - register int i; - for (i = 0; o_options[i].name; i++) - { - if (STREQ (option_name, o_options[i].name)) - { - option_char = o_options[i].letter; - break; - } - } - if (option_char == -1) - { - builtin_error ("%s: unknown option name", option_name); - return (EXECUTION_FAILURE); - } - if (change_flag (option_char, on_or_off) == FLAG_ERROR) - { - bad_option (option_name); - return (EXECUTION_FAILURE); - } - } - return (EXECUTION_SUCCESS); -} - -/* Set some flags from the word values in the input list. If LIST is empty, - then print out the values of the variables instead. If LIST contains - non-flags, then set $1 - $9 to the successive words of LIST. */ -set_builtin (list) - WORD_LIST *list; -{ - int on_or_off, flag_name, force_assignment = 0; - - if (!list) - { - SHELL_VAR **vars; - - vars = all_shell_variables (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - vars = all_shell_functions (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - return (EXECUTION_SUCCESS); - } - - /* Check validity of flag arguments. */ - if (*list->word->word == '-' || *list->word->word == '+') - { - register char *arg; - WORD_LIST *save_list = list; - - while (list && (arg = list->word->word)) - { - char c; - - if (arg[0] != '-' && arg[0] != '+') - break; - - /* `-' or `--' signifies end of flag arguments. */ - if (arg[0] == '-' && - (!arg[1] || (arg[1] == '-' && !arg[2]))) - break; - - while (c = *++arg) - { - if (find_flag (c) == FLAG_UNKNOWN && c != 'o') - { - char s[2]; - s[0] = c; s[1] = '\0'; - bad_option (s); - if (c == '?') - builtin_usage (); - return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - } - list = list->next; - } - list = save_list; - } - - /* Do the set command. While the list consists of words starting with - '-' or '+' treat them as flags, otherwise, start assigning them to - $1 ... $n. */ - while (list) - { - char *string = list->word->word; - - /* If the argument is `--' or `-' then signal the end of the list - and remember the remaining arguments. */ - if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2]))) - { - list = list->next; - - /* `set --' unsets the positional parameters. */ - if (string[1] == '-') - force_assignment = 1; - - /* Until told differently, the old shell behaviour of - `set - [arg ...]' being equivalent to `set +xv [arg ...]' - stands. Posix.2 says the behaviour is marked as obsolescent. */ - else - { - change_flag ('x', '+'); - change_flag ('v', '+'); - } - - break; - } - - if ((on_or_off = *string) && - (on_or_off == '-' || on_or_off == '+')) - { - int i = 1; - while (flag_name = string[i++]) - { - if (flag_name == '?') - { - builtin_usage (); - return (EXECUTION_SUCCESS); - } - else if (flag_name == 'o') /* -+o option-name */ - { - char *option_name; - WORD_LIST *opt; - - opt = list->next; - - if (!opt) - { - list_minus_o_opts (); - continue; - } - - option_name = opt->word->word; - - if (!option_name || !*option_name || (*option_name == '-')) - { - list_minus_o_opts (); - continue; - } - list = list->next; /* Skip over option name. */ - - if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS) - return (EXECUTION_FAILURE); - } - else - { - if (change_flag (flag_name, on_or_off) == FLAG_ERROR) - { - char opt[3]; - opt[0] = on_or_off; - opt[1] = flag_name; - opt[2] = '\0'; - bad_option (opt); - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - } - } - else - { - break; - } - list = list->next; - } - - /* Assigning $1 ... $n */ - if (list || force_assignment) - remember_args (list, 1); - return (EXECUTION_SUCCESS); -} - -$BUILTIN unset -$FUNCTION unset_builtin -$SHORT_DOC unset [-f] [-v] [name ...] -For each NAME, remove the corresponding variable or function. Given -the `-v', unset will only act on variables. Given the `-f' flag, -unset will only act on functions. With neither flag, unset first -tries to unset a variable, and if that fails, then tries to unset a -function. Some variables (such as PATH and IFS) cannot be unset; also -see readonly. -$END - -#define NEXT_VARIABLE() any_failed++; list = list->next; continue; - -unset_builtin (list) - WORD_LIST *list; -{ - int unset_function, unset_variable, unset_array, opt, any_failed; - char *name; - - unset_function = unset_variable = unset_array = any_failed = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "fv")) != -1) - { - switch (opt) - { - case 'f': - unset_function = 1; - break; - case 'v': - unset_variable = 1; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - - list = loptend; - - if (unset_function && unset_variable) - { - builtin_error ("cannot simultaneously unset a function and a variable"); - return (EXECUTION_FAILURE); - } - - while (list) - { - SHELL_VAR *var; - int tem; -#if defined (ARRAY_VARS) - char *t; -#endif - - name = list->word->word; - -#if defined (ARRAY_VARS) - if (!unset_function && valid_array_reference (name)) - { - t = strchr (name, '['); - *t++ = '\0'; - unset_array++; - } -#endif - - var = unset_function ? find_function (name) : find_variable (name); - - if (var && !unset_function && non_unsettable_p (var)) - { - builtin_error ("%s: cannot unset", name); - NEXT_VARIABLE (); - } - - /* Posix.2 says that unsetting readonly variables is an error. */ - if (var && readonly_p (var)) - { - builtin_error ("%s: cannot unset: readonly %s", - name, unset_function ? "function" : "variable"); - NEXT_VARIABLE (); - } - - /* Unless the -f option is supplied, the name refers to a variable. */ -#if defined (ARRAY_VARS) - if (var && unset_array) - { - if (array_p (var) == 0) - { - builtin_error ("%s: not an array variable", name); - NEXT_VARIABLE (); - } - else - tem = unbind_array_element (var, t); - } - else -#endif /* ARRAY_VARS */ - tem = makunbound (name, unset_function ? shell_functions : shell_variables); - - /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v - is specified, the name refers to a variable; if a variable by - that name does not exist, a function by that name, if any, - shall be unset.'' */ - if ((tem == -1) && !unset_function && !unset_variable) - tem = makunbound (name, shell_functions); - - if (tem == -1) - any_failed++; - else if (!unset_function) - stupidly_hack_special_variables (name); - - list = list->next; - } - - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); -} diff --git a/CWRU/save/unwind_prot.h.save b/CWRU/save/unwind_prot.h.save deleted file mode 100644 index 998fd72b6..000000000 --- a/CWRU/save/unwind_prot.h.save +++ /dev/null @@ -1,50 +0,0 @@ -/* unwind_prot.h - Macros and functions for hacking unwind protection. */ - -/* Copyright (C) 1993 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 2, 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; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (_UNWIND_PROT_H) -#define _UNWIND_PROT_H - -/* Run a function without interrupts. */ -extern void begin_unwind_frame (); -extern void discard_unwind_frame (); -extern void run_unwind_frame (); -extern void add_unwind_protect (); -extern void remove_unwind_protect (); -extern void run_unwind_protects (); -extern void unwind_protect_var (); - -/* Define for people who like their code to look a certain way. */ -#define end_unwind_frame() - -/* How to protect an integer. */ -#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int)) - -/* How to protect a pointer to a string. */ -#define unwind_protect_string(X) \ - unwind_protect_var ((int *)&(X), (X), sizeof (char *)) - -/* How to protect any old pointer. */ -#define unwind_protect_pointer(X) unwind_protect_string (X) - -/* How to protect the contents of a jmp_buf. */ -#define unwind_protect_jmp_buf(X) \ - unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t)) - -#endif /* _UNWIND_PROT_H */ diff --git a/bashline.c~ b/bashline.c~ deleted file mode 100644 index 8d4c1c181..000000000 --- a/bashline.c~ +++ /dev/null @@ -1,4118 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2012 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 . -*/ - -#include "config.h" - -#if defined (READLINE) - -#include "bashtypes.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_GRP_H) -# include -#endif - -#if defined (HAVE_NETDB_H) -# include -#endif - -#include -#include "chartypes.h" -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "input.h" -#include "builtins.h" -#include "bashhist.h" -#include "bashline.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "pathexp.h" -#include "shmbutil.h" - -#include "builtins/common.h" - -#include -#include -#include - -#include - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -/* These should agree with the defines for emacs_mode and vi_mode in - rldefs.h, even though that's not a public readline header file. */ -#ifndef EMACS_EDITING_MODE -# define NO_EDITING_MODE -1 -# define EMACS_EDITING_MODE 1 -# define VI_EDITING_MODE 0 -#endif - -#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') - -#if defined (BRACE_COMPLETION) -extern int bash_brace_completion __P((int, int)); -#endif /* BRACE_COMPLETION */ - -/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ -extern int tputs __P((const char *string, int nlines, int (*outx)(int))); - -/* Forward declarations */ - -/* Functions bound to keys in Readline for Bash users. */ -static int shell_expand_line __P((int, int)); -static int display_shell_version __P((int, int)); -static int operate_and_get_next __P((int, int)); - -static int bash_ignore_filenames __P((char **)); -static int bash_ignore_everything __P((char **)); - -#if defined (BANG_HISTORY) -static char *history_expand_line_internal __P((char *)); -static int history_expand_line __P((int, int)); -static int tcsh_magic_space __P((int, int)); -#endif /* BANG_HISTORY */ -#ifdef ALIAS -static int alias_expand_line __P((int, int)); -#endif -#if defined (BANG_HISTORY) && defined (ALIAS) -static int history_and_alias_expand_line __P((int, int)); -#endif - -static int bash_forward_shellword __P((int, int)); -static int bash_backward_shellword __P((int, int)); -static int bash_kill_shellword __P((int, int)); -static int bash_backward_kill_shellword __P((int, int)); - -/* Helper functions for Readline. */ -static char *restore_tilde __P((char *, char *)); - -static char *bash_filename_rewrite_hook __P((char *, int)); - -static void bash_directory_expansion __P((char **)); -static int bash_filename_stat_hook __P((char **)); -static int bash_command_name_stat_hook __P((char **)); -static int bash_directory_completion_hook __P((char **)); -static int filename_completion_ignore __P((char **)); -static int bash_push_line __P((void)); - -static int executable_completion __P((const char *, int)); - -static rl_icppfunc_t *save_directory_hook __P((void)); -static void restore_directory_hook __P((rl_icppfunc_t)); - -static void cleanup_expansion_error __P((void)); -static void maybe_make_readline_line __P((char *)); -static void set_up_new_line __P((char *)); - -static int check_redir __P((int)); -static char **attempt_shell_completion __P((const char *, int, int)); -static char *variable_completion_function __P((const char *, int)); -static char *hostname_completion_function __P((const char *, int)); -static char *command_subst_completion_function __P((const char *, int)); - -static void build_history_completion_array __P((void)); -static char *history_completion_generator __P((const char *, int)); -static int dynamic_complete_history __P((int, int)); -static int bash_dabbrev_expand __P((int, int)); - -static void initialize_hostname_list __P((void)); -static void add_host_name __P((char *)); -static void snarf_hosts_from_file __P((char *)); -static char **hostnames_matching __P((char *)); - -static void _ignore_completion_names __P((char **, sh_ignore_func_t *)); -static int name_is_acceptable __P((const char *)); -static int test_for_directory __P((const char *)); -static int return_zero __P((const char *)); - -static char *bash_dequote_filename __P((char *, int)); -static char *quote_word_break_chars __P((char *)); -static void set_filename_bstab __P((const char *)); -static char *bash_quote_filename __P((char *, int, char *)); - -static int putx __P((int)); -static int bash_execute_unix_command __P((int, int)); -static void init_unix_command_map __P((void)); -static int isolate_sequence __P((char *, int, int, int *)); - -static int set_saved_history __P((void)); - -#if defined (ALIAS) -static int posix_edit_macros __P((int, int)); -#endif - -static int bash_event_hook __P((void)); - -#if defined (PROGRAMMABLE_COMPLETION) -static int find_cmd_start __P((int)); -static int find_cmd_end __P((int)); -static char *find_cmd_name __P((int, int *, int *)); -static char *prog_complete_return __P((const char *, int)); - -static char **prog_complete_matches; -#endif - -/* Variables used here but defined in other files. */ -#if defined (BANG_HISTORY) -extern int hist_verify; -#endif - -extern int current_command_line_count, saved_command_line_count; -extern int last_command_exit_value; -extern int array_needs_making; -extern int posixly_correct, no_symbolic_links; -extern char *current_prompt_string, *ps1_prompt; -extern STRING_INT_ALIST word_token_alist[]; -extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; - -/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual - completion functions which indicate what type of completion should be - done (at or before point) that can be bound to key sequences with - the readline library. */ -#define SPECIFIC_COMPLETION_FUNCTIONS - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static int bash_specific_completion __P((int, rl_compentry_func_t *)); - -static int bash_complete_filename_internal __P((int)); -static int bash_complete_username_internal __P((int)); -static int bash_complete_hostname_internal __P((int)); -static int bash_complete_variable_internal __P((int)); -static int bash_complete_command_internal __P((int)); - -static int bash_complete_filename __P((int, int)); -static int bash_possible_filename_completions __P((int, int)); -static int bash_complete_username __P((int, int)); -static int bash_possible_username_completions __P((int, int)); -static int bash_complete_hostname __P((int, int)); -static int bash_possible_hostname_completions __P((int, int)); -static int bash_complete_variable __P((int, int)); -static int bash_possible_variable_completions __P((int, int)); -static int bash_complete_command __P((int, int)); -static int bash_possible_command_completions __P((int, int)); - -static char *glob_complete_word __P((const char *, int)); -static int bash_glob_completion_internal __P((int)); -static int bash_glob_complete_word __P((int, int)); -static int bash_glob_expand_word __P((int, int)); -static int bash_glob_list_expansions __P((int, int)); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -static int edit_and_execute_command __P((int, int, int, char *)); -#if defined (VI_MODE) -static int vi_edit_and_execute_command __P((int, int)); -static int bash_vi_complete __P((int, int)); -#endif -static int emacs_edit_and_execute_command __P((int, int)); - -/* Non-zero once initalize_readline () has been called. */ -int bash_readline_initialized = 0; - -/* If non-zero, we do hostname completion, breaking words at `@' and - trying to complete the stuff after the `@' from our own internal - host list. */ -int perform_hostname_completion = 1; - -/* If non-zero, we don't do command completion on an empty line. */ -int no_empty_command_completion; - -/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the - only possible matches. Set to 0 if you want to match filenames if they - are the only possible matches, even if FIGNORE says to. */ -int force_fignore = 1; - -/* Perform spelling correction on directory names during word completion */ -int dircomplete_spelling = 0; - -/* Expand directory names during word/filename completion. */ -int dircomplete_expand = 0; -int dircomplete_expand_relpath = 0; - -/* When non-zero, perform `normal' shell quoting on completed filenames - even when the completed name contains a directory name with a shell - variable referene, so dollar signs in a filename get quoted appropriately. - Set to zero to remove dollar sign (and braces or parens as needed) from - the set of characters that will be quoted. */ -int complete_fullquote = 1; - -static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; -static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; -/* )) */ - -static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ -static char *custom_filename_quote_characters = 0; -static char filename_bstab[256]; - -static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; - -static int dot_in_path = 0; - -/* Set to non-zero when dabbrev-expand is running */ -static int dabbrev_expand_active = 0; - -/* What kind of quoting is performed by bash_quote_filename: - COMPLETE_DQUOTE = double-quoting the filename - COMPLETE_SQUOTE = single_quoting the filename - COMPLETE_BSQUOTE = backslash-quoting special chars in the filename -*/ -#define COMPLETE_DQUOTE 1 -#define COMPLETE_SQUOTE 2 -#define COMPLETE_BSQUOTE 3 -static int completion_quoting_style = COMPLETE_BSQUOTE; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. - Called when the shell is put into or out of `posix' mode. */ -void -posix_readline_initialize (on_or_off) - int on_or_off; -{ - if (on_or_off) - rl_variable_bind ("comment-begin", "#"); -#if defined (VI_MODE) - rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); -#endif -} - -void -reset_completer_word_break_chars () -{ - rl_completer_word_break_characters = perform_hostname_completion ? savestring (bash_completer_word_break_characters) : savestring (bash_nohostname_word_break_characters); -} - -/* When this function returns, rl_completer_word_break_characters points to - dynamically allocated memory. */ -int -enable_hostname_completion (on_or_off) - int on_or_off; -{ - int old_value; - char *at, *nv, *nval; - - old_value = perform_hostname_completion; - - if (on_or_off) - { - perform_hostname_completion = 1; - rl_special_prefixes = "$@"; - } - else - { - perform_hostname_completion = 0; - rl_special_prefixes = "$"; - } - - /* Now we need to figure out how to appropriately modify and assign - rl_completer_word_break_characters depending on whether we want - hostname completion on or off. */ - - /* If this is the first time this has been called - (bash_readline_initialized == 0), use the sames values as before, but - allocate new memory for rl_completer_word_break_characters. */ - - if (bash_readline_initialized == 0 && - (rl_completer_word_break_characters == 0 || - rl_completer_word_break_characters == rl_basic_word_break_characters)) - { - if (on_or_off) - rl_completer_word_break_characters = savestring (bash_completer_word_break_characters); - else - rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters); - } - else - { - /* See if we have anything to do. */ - at = strchr (rl_completer_word_break_characters, '@'); - if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) - return old_value; - - /* We have something to do. Do it. */ - nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); - - if (on_or_off == 0) - { - /* Turn it off -- just remove `@' from word break chars. We want - to remove all occurrences of `@' from the char list, so we loop - rather than just copy the rest of the list over AT. */ - for (nv = nval, at = rl_completer_word_break_characters; *at; ) - if (*at != '@') - *nv++ = *at++; - else - at++; - *nv = '\0'; - } - else - { - nval[0] = '@'; - strcpy (nval + 1, rl_completer_word_break_characters); - } - - free (rl_completer_word_break_characters); - rl_completer_word_break_characters = nval; - } - - return (old_value); -} - -/* Called once from parse.y if we are going to use readline. */ -void -initialize_readline () -{ - rl_command_func_t *func; - char kseq[2]; - - if (bash_readline_initialized) - return; - - rl_terminal_name = get_string_value ("TERM"); - rl_instream = stdin; - rl_outstream = stderr; - - /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "Bash"; - - /* Add bindable names before calling rl_initialize so they may be - referenced in the various inputrc files. */ - rl_add_defun ("shell-expand-line", shell_expand_line, -1); -#ifdef BANG_HISTORY - rl_add_defun ("history-expand-line", history_expand_line, -1); - rl_add_defun ("magic-space", tcsh_magic_space, -1); -#endif - - rl_add_defun ("shell-forward-word", bash_forward_shellword, -1); - rl_add_defun ("shell-backward-word", bash_backward_shellword, -1); - rl_add_defun ("shell-kill-word", bash_kill_shellword, -1); - rl_add_defun ("shell-backward-kill-word", bash_backward_kill_shellword, -1); - -#ifdef ALIAS - rl_add_defun ("alias-expand-line", alias_expand_line, -1); -# ifdef BANG_HISTORY - rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); -# endif -#endif - - /* Backwards compatibility. */ - rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); - - rl_add_defun ("operate-and-get-next", operate_and_get_next, -1); - rl_add_defun ("display-shell-version", display_shell_version, -1); - rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); - -#if defined (BRACE_COMPLETION) - rl_add_defun ("complete-into-braces", bash_brace_completion, -1); -#endif - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_add_defun ("complete-filename", bash_complete_filename, -1); - rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); - rl_add_defun ("complete-username", bash_complete_username, -1); - rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); - rl_add_defun ("complete-hostname", bash_complete_hostname, -1); - rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); - rl_add_defun ("complete-variable", bash_complete_variable, -1); - rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); - rl_add_defun ("complete-command", bash_complete_command, -1); - rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); - rl_add_defun ("glob-complete-word", bash_glob_complete_word, -1); - rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); - rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); -#endif - - rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); - rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -1); - - /* Bind defaults before binding our custom shell keybindings. */ - if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) - rl_initialize (); - - /* Bind up our special shell functions. */ - rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); - -#ifdef BANG_HISTORY - rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); -#endif - - rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap); - rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); - - /* In Bash, the user can switch editing modes with "set -o [vi emacs]", - so it is not necessary to allow C-M-j for context switching. Turn - off this occasionally confusing behaviour. */ - kseq[0] = CTRL('J'); - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); - kseq[0] = CTRL('M'); - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) - rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); -#if defined (VI_MODE) - rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); -#endif - -#if defined (BRACE_COMPLETION) - rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/ -#endif /* BRACE_COMPLETION */ - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); - - /* Have to jump through hoops here because there is a default binding for - M-~ (rl_tilde_expand) */ - kseq[0] = '~'; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tilde_expand) - rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); - - rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); - - rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap); - rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); - rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); - - /* Tell the completer that we want a crack first. */ - rl_attempted_completion_function = attempt_shell_completion; - - /* Tell the completer that we might want to follow symbolic links or - do other expansion on directory names. */ - set_directory_hook (); - - rl_filename_rewrite_hook = bash_filename_rewrite_hook; - - rl_filename_stat_hook = bash_filename_stat_hook; - - /* Tell the filename completer we want a chance to ignore some names. */ - rl_ignore_some_completions_function = filename_completion_ignore; - - /* Bind C-xC-e to invoke emacs and run result as commands. */ - rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); -#if defined (VI_MODE) - rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); -# if defined (ALIAS) - rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); -# endif - - rl_bind_key_in_map ('\\', bash_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('*', bash_vi_complete, vi_movement_keymap); - rl_bind_key_in_map ('=', bash_vi_complete, vi_movement_keymap); -#endif - - rl_completer_quote_characters = "'\""; - - /* This sets rl_completer_word_break_characters and rl_special_prefixes - to the appropriate values, depending on whether or not hostname - completion is enabled. */ - enable_hostname_completion (perform_hostname_completion); - - /* characters that need to be quoted when appearing in filenames. */ - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - - rl_filename_quoting_function = bash_quote_filename; - rl_filename_dequoting_function = bash_dequote_filename; - rl_char_is_quoted_p = char_is_quoted; - -#if 0 - /* This is superfluous and makes it impossible to use tab completion in - vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() - should already have called posix_readline_initialize() when - posixly_correct was set. */ - if (posixly_correct) - posix_readline_initialize (1); -#endif - - bash_readline_initialized = 1; -} - -void -bashline_reinitialize () -{ - bash_readline_initialized = 0; -} - -void -bashline_set_event_hook () -{ - rl_event_hook = bash_event_hook; -} - -void -bashline_reset_event_hook () -{ - rl_event_hook = 0; -} - -/* On Sun systems at least, rl_attempted_completion_function can end up - getting set to NULL, and rl_completion_entry_function set to do command - word completion if Bash is interrupted while trying to complete a command - word. This just resets all the completion functions to the right thing. - It's called from throw_to_top_level(). */ -void -bashline_reset () -{ - tilde_initialize (); - rl_attempted_completion_function = attempt_shell_completion; - rl_completion_entry_function = NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - - set_directory_hook (); - rl_filename_stat_hook = bash_filename_stat_hook; -} - -/* Contains the line to push into readline. */ -static char *push_to_readline = (char *)NULL; - -/* Push the contents of push_to_readline into the - readline buffer. */ -static int -bash_push_line () -{ - if (push_to_readline) - { - rl_insert_text (push_to_readline); - free (push_to_readline); - push_to_readline = (char *)NULL; - rl_startup_hook = old_rl_startup_hook; - } - return 0; -} - -/* Call this to set the initial text for the next line to read - from readline. */ -int -bash_re_edit (line) - char *line; -{ - FREE (push_to_readline); - - push_to_readline = savestring (line); - old_rl_startup_hook = rl_startup_hook; - rl_startup_hook = bash_push_line; - - return (0); -} - -static int -display_shell_version (count, c) - int count, c; -{ - rl_crlf (); - show_shell_version (0); - putc ('\r', rl_outstream); - fflush (rl_outstream); - rl_on_new_line (); - rl_redisplay (); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Readline Stuff */ -/* */ -/* **************************************************************** */ - -/* If the user requests hostname completion, then simply build a list - of hosts, and complete from that forever more, or at least until - HOSTFILE is unset. */ - -/* THIS SHOULD BE A STRINGLIST. */ -/* The kept list of hostnames. */ -static char **hostname_list = (char **)NULL; - -/* The physical size of the above list. */ -static int hostname_list_size; - -/* The number of hostnames in the above list. */ -static int hostname_list_length; - -/* Whether or not HOSTNAME_LIST has been initialized. */ -int hostname_list_initialized = 0; - -/* Initialize the hostname completion table. */ -static void -initialize_hostname_list () -{ - char *temp; - - temp = get_string_value ("HOSTFILE"); - if (temp == 0) - temp = get_string_value ("hostname_completion_file"); - if (temp == 0) - temp = DEFAULT_HOSTS_FILE; - - snarf_hosts_from_file (temp); - - if (hostname_list) - hostname_list_initialized++; -} - -/* Add NAME to the list of hosts. */ -static void -add_host_name (name) - char *name; -{ - if (hostname_list_length + 2 > hostname_list_size) - { - hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); - hostname_list = strvec_resize (hostname_list, hostname_list_size); - } - - hostname_list[hostname_list_length++] = savestring (name); - hostname_list[hostname_list_length] = (char *)NULL; -} - -#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) - -static void -snarf_hosts_from_file (filename) - char *filename; -{ - FILE *file; - char *temp, buffer[256], name[256]; - register int i, start; - - file = fopen (filename, "r"); - if (file == 0) - return; - - while (temp = fgets (buffer, 255, file)) - { - /* Skip to first character. */ - for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) - ; - - /* If comment or blank line, ignore. */ - if (buffer[i] == '\0' || buffer[i] == '#') - continue; - - /* If `preprocessor' directive, do the include. */ - if (strncmp (buffer + i, "$include ", 9) == 0) - { - char *incfile, *t; - - /* Find start of filename. */ - for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) - ; - - /* Find end of filename. */ - for (t = incfile; *t && cr_whitespace (*t) == 0; t++) - ; - - *t = '\0'; - - snarf_hosts_from_file (incfile); - continue; - } - - /* Skip internet address if present. */ - if (DIGIT (buffer[i])) - for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); - - /* Gobble up names. Each name is separated with whitespace. */ - while (buffer[i]) - { - for (; cr_whitespace (buffer[i]); i++) - ; - if (buffer[i] == '\0' || buffer[i] == '#') - break; - - /* Isolate the current word. */ - for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) - ; - if (i == start) - continue; - strncpy (name, buffer + start, i - start); - name[i - start] = '\0'; - add_host_name (name); - } - } - fclose (file); -} - -/* Return the hostname list. */ -char ** -get_hostname_list () -{ - if (hostname_list_initialized == 0) - initialize_hostname_list (); - return (hostname_list); -} - -void -clear_hostname_list () -{ - register int i; - - if (hostname_list_initialized == 0) - return; - for (i = 0; i < hostname_list_length; i++) - free (hostname_list[i]); - hostname_list_length = hostname_list_initialized = 0; -} - -/* Return a NULL terminated list of hostnames which begin with TEXT. - Initialize the hostname list the first time if neccessary. - The array is malloc ()'ed, but not the individual strings. */ -static char ** -hostnames_matching (text) - char *text; -{ - register int i, len, nmatch, rsize; - char **result; - - if (hostname_list_initialized == 0) - initialize_hostname_list (); - - if (hostname_list_initialized == 0) - return ((char **)NULL); - - /* Special case. If TEXT consists of nothing, then the whole list is - what is desired. */ - if (*text == '\0') - { - result = strvec_create (1 + hostname_list_length); - for (i = 0; i < hostname_list_length; i++) - result[i] = hostname_list[i]; - result[i] = (char *)NULL; - return (result); - } - - /* Scan until found, or failure. */ - len = strlen (text); - result = (char **)NULL; - for (i = nmatch = rsize = 0; i < hostname_list_length; i++) - { - if (STREQN (text, hostname_list[i], len) == 0) - continue; - - /* OK, it matches. Add it to the list. */ - if (nmatch >= (rsize - 1)) - { - rsize = (rsize + 16) - (rsize % 16); - result = strvec_resize (result, rsize); - } - - result[nmatch++] = hostname_list[i]; - } - if (nmatch) - result[nmatch] = (char *)NULL; - return (result); -} - -/* The equivalent of the Korn shell C-o operate-and-get-next-history-line - editing command. */ -static int saved_history_line_to_use = -1; -static int last_saved_history_line = -1; - -#define HISTORY_FULL() (history_is_stifled () && history_length >= history_max_entries) - -static int -set_saved_history () -{ - /* XXX - compensate for assumption that history was `shuffled' if it was - actually not. */ - if (HISTORY_FULL () && - hist_last_line_added == 0 && - saved_history_line_to_use < history_length - 1) - saved_history_line_to_use++; - - if (saved_history_line_to_use >= 0) - { - rl_get_previous_history (history_length - saved_history_line_to_use, 0); - last_saved_history_line = saved_history_line_to_use; - } - saved_history_line_to_use = -1; - rl_startup_hook = old_rl_startup_hook; - return (0); -} - -static int -operate_and_get_next (count, c) - int count, c; -{ - int where; - - /* Accept the current line. */ - rl_newline (1, c); - - /* Find the current line, and find the next line to use. */ - where = where_history (); - - if (HISTORY_FULL () || (where >= history_length - 1)) - saved_history_line_to_use = where; - else - saved_history_line_to_use = where + 1; - - old_rl_startup_hook = rl_startup_hook; - rl_startup_hook = set_saved_history; - - return 0; -} - -/* This vi mode command causes VI_EDIT_COMMAND to be run on the current - command being entered (if no explicit argument is given), otherwise on - a command from the history file. */ - -#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" -#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -static int -edit_and_execute_command (count, c, editing_mode, edit_command) - int count, c, editing_mode; - char *edit_command; -{ - char *command, *metaval; - int r, rrs, metaflag; - sh_parser_state_t ps; - - rrs = rl_readline_state; - saved_command_line_count = current_command_line_count; - - /* Accept the current line. */ - rl_newline (1, c); - - if (rl_explicit_arg) - { - command = (char *)xmalloc (strlen (edit_command) + 8); - sprintf (command, "%s %d", edit_command, count); - } - else - { - /* Take the command we were just editing, add it to the history file, - then call fc to operate on it. We have to add a dummy command to - the end of the history because fc ignores the last command (assumes - it's supposed to deal with the command before the `fc'). */ - /* This breaks down when using command-oriented history and are not - finished with the command, so we should not ignore the last command */ - using_history (); - bash_add_history (rl_line_buffer); - bash_add_history (""); - history_lines_this_session++; - using_history (); - command = savestring (edit_command); - } - - metaval = rl_variable_value ("input-meta"); - metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); - - /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the - temporary file should be placed into the history. We don't do that - yet. */ - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - save_parser_state (&ps); - r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); - restore_parser_state (&ps); - if (rl_prep_term_function) - (*rl_prep_term_function) (metaflag); - - current_command_line_count = saved_command_line_count; - - /* Now erase the contents of the current line and undo the effects of the - rl_accept_line() above. We don't even want to make the text we just - executed available for undoing. */ - rl_line_buffer[0] = '\0'; /* XXX */ - rl_point = rl_end = 0; - rl_done = 0; - rl_readline_state = rrs; - - rl_forced_update_display (); - - return r; -} - -#if defined (VI_MODE) -static int -vi_edit_and_execute_command (count, c) - int count, c; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); -} -#endif /* VI_MODE */ - -static int -emacs_edit_and_execute_command (count, c) - int count, c; -{ - return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); -} - -#if defined (ALIAS) -static int -posix_edit_macros (count, key) - int count, key; -{ - int c; - char alias_name[3], *alias_value, *macro; - - c = rl_read_key (); - alias_name[0] = '_'; - alias_name[1] = c; - alias_name[2] = '\0'; - - alias_value = get_alias_value (alias_name); - if (alias_value && *alias_value) - { - macro = savestring (alias_value); - rl_push_macro_input (macro); - } - return 0; -} -#endif - -/* Bindable commands that move `shell-words': that is, sequences of - non-unquoted-metacharacters. */ - -#define WORDDELIM(c) (shellmeta(c) || shellblank(c)) - -static int -bash_forward_shellword (count, key) - int count, key; -{ - size_t slen; - int sindex, c, p; - DECLARE_MBSTATE; - - if (count < 0) - return (bash_backward_shellword (-count, key)); - - /* The tricky part of this is deciding whether or not the first character - we're on is an unquoted metacharacter. Not completely handled yet. */ - /* XXX - need to test this stuff with backslash-escaped shell - metacharacters and unclosed single- and double-quoted strings. */ - - p = rl_point; - slen = rl_end; - - while (count) - { - if (p == rl_end) - { - rl_point = rl_end; - return 0; - } - - /* Are we in a quoted string? If we are, move to the end of the quoted - string and continue the outer loop. We only want quoted strings, not - backslash-escaped characters, but char_is_quoted doesn't - differentiate. */ - if (char_is_quoted (rl_line_buffer, p) && p > 0 && rl_line_buffer[p-1] != '\\') - { - do - ADVANCE_CHAR (rl_line_buffer, slen, p); - while (p < rl_end && char_is_quoted (rl_line_buffer, p)); - count--; - continue; - } - - /* Rest of code assumes we are not in a quoted string. */ - /* Move forward until we hit a non-metacharacter. */ - while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c)) - { - switch (c) - { - default: - ADVANCE_CHAR (rl_line_buffer, slen, p); - continue; /* straight back to loop, don't increment p */ - case '\\': - if (p < rl_end && rl_line_buffer[p]) - ADVANCE_CHAR (rl_line_buffer, slen, p); - break; - case '\'': - p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); - break; - case '"': - p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); - break; - } - - if (p < rl_end) - p++; - } - - if (rl_line_buffer[p] == 0 || p == rl_end) - { - rl_point = rl_end; - rl_ding (); - return 0; - } - - /* Now move forward until we hit a non-quoted metacharacter or EOL */ - while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0) - { - switch (c) - { - default: - ADVANCE_CHAR (rl_line_buffer, slen, p); - continue; /* straight back to loop, don't increment p */ - case '\\': - if (p < rl_end && rl_line_buffer[p]) - ADVANCE_CHAR (rl_line_buffer, slen, p); - break; - case '\'': - p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); - break; - case '"': - p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); - break; - } - - if (p < rl_end) - p++; - } - - if (p == rl_end || rl_line_buffer[p] == 0) - { - rl_point = rl_end; - return (0); - } - - count--; - } - - rl_point = p; - return (0); -} - -static int -bash_backward_shellword (count, key) - int count, key; -{ - size_t slen; - int sindex, c, p; - DECLARE_MBSTATE; - - if (count < 0) - return (bash_forward_shellword (-count, key)); - - p = rl_point; - slen = rl_end; - - while (count) - { - if (p == 0) - { - rl_point = 0; - return 0; - } - - /* Move backward until we hit a non-metacharacter. */ - while (p > 0) - { - c = rl_line_buffer[p]; - if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) - BACKUP_CHAR (rl_line_buffer, slen, p); - break; - } - - if (p == 0) - { - rl_point = 0; - return 0; - } - - /* Now move backward until we hit a metacharacter or BOL. */ - while (p > 0) - { - c = rl_line_buffer[p]; - if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) - break; - BACKUP_CHAR (rl_line_buffer, slen, p); - } - - count--; - } - - rl_point = p; - return 0; -} - -static int -bash_kill_shellword (count, key) - int count, key; -{ - int p; - - if (count < 0) - return (bash_backward_kill_shellword (-count, key)); - - p = rl_point; - bash_forward_shellword (count, key); - - if (rl_point != p) - rl_kill_text (p, rl_point); - - rl_point = p; - if (rl_editing_mode == 1) /* 1 == emacs_mode */ - rl_mark = rl_point; - - return 0; -} - -static int -bash_backward_kill_shellword (count, key) - int count, key; -{ - int p; - - if (count < 0) - return (bash_kill_shellword (-count, key)); - - p = rl_point; - bash_backward_shellword (count, key); - - if (rl_point != p) - rl_kill_text (p, rl_point); - - if (rl_editing_mode == 1) /* 1 == emacs_mode */ - rl_mark = rl_point; - - return 0; -} - - -/* **************************************************************** */ -/* */ -/* How To Do Shell Completion */ -/* */ -/* **************************************************************** */ - -#define COMMAND_SEPARATORS ";|&{(`" -/* )} */ -#define COMMAND_SEPARATORS_PLUS_WS ";|&{(` \t" -/* )} */ - -/* check for redirections and other character combinations that are not - command separators */ -static int -check_redir (ti) - int ti; -{ - register int this_char, prev_char; - - /* Handle the two character tokens `>&', `<&', and `>|'. - We are not in a command position after one of these. */ - this_char = rl_line_buffer[ti]; - prev_char = rl_line_buffer[ti - 1]; - - if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || - (this_char == '|' && prev_char == '>')) - return (1); - else if (this_char == '{' && prev_char == '$') /*}*/ - return (1); -#if 0 /* Not yet */ - else if (this_char == '(' && prev_char == '$') /*)*/ - return (1); - else if (this_char == '(' && prev_char == '<') /*)*/ - return (1); -#if defined (EXTENDED_GLOB) - else if (extended_glob && this_char == '(' && prev_char == '!') /*)*/ - return (1); -#endif -#endif - else if (char_is_quoted (rl_line_buffer, ti)) - return (1); - return (0); -} - -#if defined (PROGRAMMABLE_COMPLETION) -/* - * XXX - because of the <= start test, and setting os = s+1, this can - * potentially return os > start. This is probably not what we want to - * happen, but fix later after 2.05a-release. - */ -static int -find_cmd_start (start) - int start; -{ - register int s, os; - - os = 0; - /* Flags == SD_NOJMP only because we want to skip over command substitutions - in assignment statements. Have to test whether this affects `standalone' - command substitutions as individual words. */ - while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/)) <= start) && - rl_line_buffer[s]) - os = s+1; - return os; -} - -static int -find_cmd_end (end) - int end; -{ - register int e; - - e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP); - return e; -} - -static char * -find_cmd_name (start, sp, ep) - int start; - int *sp, *ep; -{ - char *name; - register int s, e; - - for (s = start; whitespace (rl_line_buffer[s]); s++) - ; - - /* skip until a shell break character */ - e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP); - - name = substring (rl_line_buffer, s, e); - - if (sp) - *sp = s; - if (ep) - *ep = e; - - return (name); -} - -static char * -prog_complete_return (text, matchnum) - const char *text; - int matchnum; -{ - static int ind; - - if (matchnum == 0) - ind = 0; - - if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) - return (char *)NULL; - return (prog_complete_matches[ind++]); -} - -#endif /* PROGRAMMABLE_COMPLETION */ - -/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are - at START and END. Return an array of matches, or NULL if none. */ -static char ** -attempt_shell_completion (text, start, end) - const char *text; - int start, end; -{ - int in_command_position, ti, saveti, qc, dflags; - char **matches, *command_separator_chars; - - command_separator_chars = COMMAND_SEPARATORS; - matches = (char **)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - - rl_filename_quote_characters = default_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - set_directory_hook (); - rl_filename_stat_hook = bash_filename_stat_hook; - - /* Determine if this could be a command word. It is if it appears at - the start of the line (ignoring preceding whitespace), or if it - appears after a character that separates commands. It cannot be a - command word if we aren't at the top-level prompt. */ - ti = start - 1; - saveti = qc = -1; - - while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) - ti--; - -#if 1 - /* If this is an open quote, maybe we're trying to complete a quoted - command name. */ - if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) - { - qc = rl_line_buffer[ti]; - saveti = ti--; - while (ti > -1 && (whitespace (rl_line_buffer[ti]))) - ti--; - } -#endif - - in_command_position = 0; - if (ti < 0) - { - /* Only do command completion at the start of a line when we - are prompting at the top level. */ - if (current_prompt_string == ps1_prompt) - in_command_position++; - else if (parser_in_command_position ()) - in_command_position++; - } - else if (member (rl_line_buffer[ti], command_separator_chars)) - { - in_command_position++; - - if (check_redir (ti) == 1) - in_command_position = 0; - } - else - { - /* This still could be in command position. It is possible - that all of the previous words on the line are variable - assignments. */ - } - - /* Check that we haven't incorrectly flagged a closed command substitution - as indicating we're in a command position. */ - if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && - *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) - in_command_position = 0; - - /* Special handling for command substitution. If *TEXT is a backquote, - it can be the start or end of an old-style command substitution, or - unmatched. If it's unmatched, both calls to unclosed_pair will - succeed. Don't bother if readline found a single quote and we are - completing on the substring. */ - if (*text == '`' && rl_completion_quote_character != '\'' && - (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && - unclosed_pair (rl_line_buffer, end, "`")))) - matches = rl_completion_matches (text, command_subst_completion_function); - -#if defined (PROGRAMMABLE_COMPLETION) - /* Attempt programmable completion. */ - if (matches == 0 && (in_command_position == 0 || text[0] == '\0') && - prog_completion_enabled && (progcomp_size () > 0) && - current_prompt_string == ps1_prompt) - { - int s, e, s1, e1, os, foundcs; - char *n; - - /* XXX - don't free the members */ - if (prog_complete_matches) - free (prog_complete_matches); - prog_complete_matches = (char **)NULL; - - os = start; - n = 0; - s = find_cmd_start (os); - e = find_cmd_end (end); - do - { - /* Skip over assignment statements preceding a command name. If we - don't find a command name at all, we can perform command name - completion. If we find a partial command name, we should perform - command name completion on it. */ - FREE (n); - n = find_cmd_name (s, &s1, &e1); - s = e1 + 1; - } - while (assignment (n, 0)); - s = s1; /* reset to index where name begins */ - - if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ - foundcs = 0; - else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ - foundcs = 0; - else if (e == 0 && e == s && text[0] == '\0') /* beginning of empty line */ - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) - foundcs = 0; /* whitespace before command name */ - else if (e > s && assignment (n, 0) == 0) - prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); - else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) - { - foundcs = 0; /* empty command name following assignments */ - in_command_position = 1; - } - else if (s == start && e == end && STREQ (n, text) && start > 0) - { - foundcs = 0; /* partial command name following assignments */ - in_command_position = 1; - } - else - foundcs = 0; - FREE (n); - /* XXX - if we found a COMPSPEC for the command, just return whatever - the programmable completion code returns, and disable the default - filename completion that readline will do unless the COPT_DEFAULT - option has been set with the `-o default' option to complete or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 1); - /* Turn what the programmable completion code returns into what - readline wants. I should have made compute_lcd_of_matches - external... */ - matches = rl_completion_matches (text, prog_complete_return); - if ((foundcs & COPT_DEFAULT) == 0) - rl_attempted_completion_over = 1; /* no default */ - if (matches || ((foundcs & COPT_BASHDEFAULT) == 0)) - return (matches); - } - } -#endif - - if (matches == 0) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - char **matches, *t; - - matches = (char **)NULL; - - /* New posix-style command substitution or variable name? */ - if (!matches && *text == '$') - { - if (qc != '\'' && text[1] == '(') /* ) */ - matches = rl_completion_matches (text, command_subst_completion_function); - else - { - matches = rl_completion_matches (text, variable_completion_function); - if (matches && matches[0] && matches[1] == 0) - { - t = savestring (matches[0]); - bash_filename_stat_hook (&t); - /* doesn't use test_for_directory because that performs tilde - expansion */ - if (file_isdir (t)) - rl_completion_append_character = '/'; - free (t); - } - } - } - - /* If the word starts in `~', and there is no slash in the word, then - try completing this word as a username. */ - if (matches == 0 && *text == '~' && mbschr (text, '/') == 0) - matches = rl_completion_matches (text, rl_username_completion_function); - - /* Another one. Why not? If the word starts in '@', then look through - the world of known hostnames for completion first. */ - if (matches == 0 && perform_hostname_completion && *text == '@') - matches = rl_completion_matches (text, hostname_completion_function); - - /* And last, (but not least) if this word is in a command position, then - complete over possible command names, including aliases, functions, - and command names. */ - if (matches == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - matches = (char **)NULL; - rl_ignore_some_completions_function = bash_ignore_everything; - } - else - { -#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) - - dot_in_path = 0; - matches = rl_completion_matches (text, command_word_completion_function); - - /* If we are attempting command completion and nothing matches, we - do not want readline to perform filename completion for us. We - still want to be able to complete partial pathnames, so set the - completion ignore function to something which will remove - filenames and leave directories in the match list. */ - if (matches == (char **)NULL) - rl_ignore_some_completions_function = bash_ignore_filenames; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) - /* There are multiple instances of the same match (duplicate - completions haven't yet been removed). In this case, all of - the matches will be the same, and the duplicate removal code - will distill them all down to one. We turn on - rl_completion_suppress_append for the same reason as above. - Remember: we only care if there's eventually a single unique - completion. If there are multiple completions this won't - make a difference and the problem won't occur. */ - { - rl_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* This could be a globbing pattern, so try to expand it using pathname - expansion. */ - if (!matches && glob_pattern_p (text)) - { - matches = rl_completion_matches (text, glob_complete_word); - /* A glob expression that matches more than one filename is problematic. - If we match more than one filename, punt. */ - if (matches && matches[1] && rl_completion_type == TAB) - { - strvec_dispose (matches); - matches = (char **)0; - } - } - - return (matches); -} - -static int -bash_command_name_stat_hook (name) - char **name; -{ - char *cname, *result; - - cname = *name; - /* XXX - we could do something here with converting aliases, builtins, - and functions into something that came out as executable, but we don't. */ - result = search_for_command (cname, 0); - if (result) - { - *name = result; - return 1; - } - return 0; -} - -static int -executable_completion (filename, searching_path) - const char *filename; - int searching_path; -{ - char *f; - int r; - - f = savestring (filename); - bash_directory_completion_hook (&f); - - r = searching_path ? executable_file (f) : executable_or_directory (f); - free (f); - return r; -} - -/* This is the function to call when the word to complete is in a position - where a command word can be found. It grovels $PATH, looking for commands - that match. It also scans aliases, function names, and the shell_builtin - table. */ -char * -command_word_completion_function (hint_text, state) - const char *hint_text; - int state; -{ - static char *hint = (char *)NULL; - static char *path = (char *)NULL; - static char *val = (char *)NULL; - static char *filename_hint = (char *)NULL; - static char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case, globpat; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp, *cval; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - rl_filename_stat_hook = bash_command_name_stat_hook; - - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); - - if (glob_matches) - { - free (glob_matches); - glob_matches = (char **)NULL; - } - - globpat = glob_pattern_p (hint_text); - - /* If this is an absolute program name, do not check it against - aliases, reserved words, functions or builtins. We must check - whether or not it is unique, and, if so, whether that filename - is executable. */ - if (globpat || absolute_program (hint_text)) - { - /* Perform tilde expansion on what's passed, so we don't end up - passing filenames with tildes directly to stat(). */ - if (*hint_text == '~') - { - hint = bash_tilde_expand (hint_text, 0); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - istate = 0; - - if (globpat) - { - mapping_over = 5; - goto globword; - } - else - { - if (dircomplete_expand && path_dot_or_dotdot (filename_hint)) - { - dircomplete_expand = 0; - set_directory_hook (); - dircomplete_expand = 1; - } - mapping_over = 4; - goto inner; - } - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 0; - - /* Initialize the variables for each type of command word. */ - local_index = 0; - - if (varlist) - free (varlist); - - varlist = all_visible_functions (); - -#if defined (ALIAS) - if (alias_list) - free (alias_list); - - alias_list = all_aliases (); -#endif /* ALIAS */ - } - - /* mapping_over says what we are currently hacking. Note that every case - in this list must fall through when there are no more possibilities. */ - - switch (mapping_over) - { - case 0: /* Aliases come first. */ -#if defined (ALIAS) - while (alias_list && alias_list[local_index]) - { - register char *alias; - - alias = alias_list[local_index++]->name; - - if (STREQN (alias, hint, hint_len)) - return (savestring (alias)); - } -#endif /* ALIAS */ - local_index = 0; - mapping_over++; - - case 1: /* Then shell reserved words. */ - { - while (word_token_alist[local_index].word) - { - register char *reserved_word; - - reserved_word = word_token_alist[local_index++].word; - - if (STREQN (reserved_word, hint, hint_len)) - return (savestring (reserved_word)); - } - local_index = 0; - mapping_over++; - } - - case 2: /* Then function names. */ - while (varlist && varlist[local_index]) - { - register char *varname; - - varname = varlist[local_index++]->name; - - if (STREQN (varname, hint, hint_len)) - return (savestring (varname)); - } - local_index = 0; - mapping_over++; - - case 3: /* Then shell builtins. */ - for (; local_index < num_shell_builtins; local_index++) - { - /* Ignore it if it doesn't have a function pointer or if it - is not currently enabled. */ - if (!shell_builtins[local_index].function || - (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) - continue; - - if (STREQN (shell_builtins[local_index].name, hint, hint_len)) - { - int i = local_index++; - - return (savestring (shell_builtins[i].name)); - } - } - local_index = 0; - mapping_over++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned on - regular completion. */ - if (globpat) - { - if (state == 0) - { - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - - if (GLOB_FAILED (glob_matches) || glob_matches == 0) - { - glob_matches = (char **)NULL; - return ((char *)NULL); - } - - local_index = 0; - - if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ - return ((char *)NULL); - } - - while (val = glob_matches[local_index++]) - { - if (executable_or_directory (val)) - { - if (*hint_text == '~' && directory_part) - { - temp = restore_tilde (val, directory_part); - free (val); - val = temp; - } - return (val); - } - free (val); - } - - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* Repeatedly call filename_completion_function while we have - members of PATH left. Question: should we stat each file? - Answer: we call executable_file () on each file. */ - outer: - - istate = (val != (char *)NULL); - - if (istate == 0) - { - char *current_path; - - /* Get the next directory from the path. If there is none, then we - are all done. */ - if (path == 0 || path[path_index] == 0 || - (current_path = extract_colon_unit (path, &path_index)) == 0) - return ((char *)NULL); - - searching_path = 1; - if (*current_path == 0) - { - free (current_path); - current_path = savestring ("."); - } - - if (*current_path == '~') - { - char *t; - - t = bash_tilde_expand (current_path, 0); - free (current_path); - current_path = t; - } - - if (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - free (current_path); /* XXX */ - } - - inner: - val = rl_filename_completion_function (filename_hint, istate); - if (mapping_over == 4 && dircomplete_expand) - set_directory_hook (); - - istate = 1; - - if (val == 0) - { - /* If the hint text is an absolute program, then don't bother - searching through PATH. */ - if (absolute_program (hint)) - return ((char *)NULL); - - goto outer; - } - else - { - int match, freetemp; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - temp = restore_tilde (val, directory_part); - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ -#if 0 - /* If we're not searching $PATH and we have a relative pathname, we - need to re-canonicalize it before testing whether or not it's an - executable or a directory so the shell treats .. relative to $PWD - according to the physical/logical option. The shell already - canonicalizes the directory name in order to tell readline where - to look, so not doing it here will be inconsistent. */ - /* XXX -- currently not used -- will introduce more inconsistency, - since shell does not canonicalize ../foo before passing it to - shell_execve(). */ - if (match && searching_path == 0 && *val == '.') - { - char *t, *t1; - - t = get_working_directory ("command-word-completion"); - t1 = make_absolute (val, t); - free (t); - cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - } - else -#endif - cval = val; - - if (match && executable_completion ((searching_path ? val : cval), searching_path)) - { - if (cval != val) - free (cval); - free (val); - val = ""; /* So it won't be NULL. */ - return (temp); - } - else - { - if (freetemp) - free (temp); - if (cval != val) - free (cval); - free (val); - goto inner; - } - } -} - -/* Completion inside an unterminated command substitution. */ -static char * -command_subst_completion_function (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static const char *orig_start; - static char *filename_text = (char *)NULL; - static int cmd_index, start_len; - char *value; - - if (state == 0) - { - if (filename_text) - free (filename_text); - orig_start = text; - if (*text == '`') - text++; - else if (*text == '$' && text[1] == '(') /* ) */ - text += 2; - /* If the text was quoted, suppress any quote character that the - readline completion code would insert. */ - rl_completion_suppress_quote = 1; - start_len = text - orig_start; - filename_text = savestring (text); - if (matches) - free (matches); - - /* - * At this point we can entertain the idea of re-parsing - * `filename_text' into a (possibly incomplete) command name and - * arguments, and doing completion based on that. This is - * currently very rudimentary, but it is a small improvement. - */ - for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) - if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) - break; - if (value <= filename_text) - matches = rl_completion_matches (filename_text, command_word_completion_function); - else - { - value++; - start_len += value - filename_text; - if (whitespace (value[-1])) - matches = rl_completion_matches (value, rl_filename_completion_function); - else - matches = rl_completion_matches (value, command_word_completion_function); - } - - /* If there is more than one match, rl_completion_matches has already - put the lcd in matches[0]. Skip over it. */ - cmd_index = matches && matches[0] && matches[1]; - - /* If there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 1; - } - - if (matches == 0 || matches[cmd_index] == 0) - { - rl_filename_quoting_desired = 0; /* disable quoting */ - return ((char *)NULL); - } - else - { - value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); - - if (start_len == 1) - value[0] = *orig_start; - else - strncpy (value, orig_start, start_len); - - strcpy (value + start_len, matches[cmd_index]); - - cmd_index++; - return (value); - } -} - -/* Okay, now we write the entry_function for variable completion. */ -static char * -variable_completion_function (text, state) - const char *text; - int state; -{ - static char **varlist = (char **)NULL; - static int varlist_index; - static char *varname = (char *)NULL; - static int namelen; - static int first_char, first_char_loc; - - if (!state) - { - if (varname) - free (varname); - - first_char_loc = 0; - first_char = text[0]; - - if (first_char == '$') - first_char_loc++; - - if (text[first_char_loc] == '{') - first_char_loc++; - - varname = savestring (text + first_char_loc); - - namelen = strlen (varname); - if (varlist) - strvec_dispose (varlist); - - varlist = all_variables_matching_prefix (varname); - varlist_index = 0; - } - - if (!varlist || !varlist[varlist_index]) - { - return ((char *)NULL); - } - else - { - char *value; - - value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); - - if (first_char_loc) - { - value[0] = first_char; - if (first_char_loc == 2) - value[1] = '{'; - } - - strcpy (value + first_char_loc, varlist[varlist_index]); - if (first_char_loc == 2) - strcat (value, "}"); - - varlist_index++; - return (value); - } -} - -/* How about a completion function for hostnames? */ -static char * -hostname_completion_function (text, state) - const char *text; - int state; -{ - static char **list = (char **)NULL; - static int list_index = 0; - static int first_char, first_char_loc; - - /* If we don't have any state, make some. */ - if (state == 0) - { - FREE (list); - - list = (char **)NULL; - - first_char_loc = 0; - first_char = *text; - - if (first_char == '@') - first_char_loc++; - - list = hostnames_matching ((char *)text+first_char_loc); - list_index = 0; - } - - if (list && list[list_index]) - { - char *t; - - t = (char *)xmalloc (2 + strlen (list[list_index])); - *t = first_char; - strcpy (t + first_char_loc, list[list_index]); - list_index++; - return (t); - } - - return ((char *)NULL); -} - -/* - * A completion function for service names from /etc/services (or wherever). - */ -char * -bash_servicename_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) - return ((char *)NULL); -#else - static char *sname = (char *)NULL; - static struct servent *srvent; - static int snamelen, firstc; - char *value; - char **alist, *aentry; - int afound; - - if (state == 0) - { - FREE (sname); - firstc = *text; - - sname = savestring (text); - snamelen = strlen (sname); - setservent (0); - } - - while (srvent = getservent ()) - { - afound = 0; - if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) - break; - /* Not primary, check aliases */ - for (alist = srvent->s_aliases; *alist; alist++) - { - aentry = *alist; - if (STREQN (sname, aentry, snamelen)) - { - afound = 1; - break; - } - } - - if (afound) - break; - } - - if (srvent == 0) - { - endservent (); - return ((char *)NULL); - } - - value = afound ? savestring (aentry) : savestring (srvent->s_name); - return value; -#endif -} - -/* - * A completion function for group names from /etc/group (or wherever). - */ -char * -bash_groupname_completion_function (text, state) - const char *text; - int state; -{ -#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) - return ((char *)NULL); -#else - static char *gname = (char *)NULL; - static struct group *grent; - static int gnamelen; - char *value; - - if (state == 0) - { - FREE (gname); - gname = savestring (text); - gnamelen = strlen (gname); - - setgrent (); - } - - while (grent = getgrent ()) - { - if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) - break; - } - - if (grent == 0) - { - endgrent (); - return ((char *)NULL); - } - - value = savestring (grent->gr_name); - return (value); -#endif -} - -/* Functions to perform history and alias expansions on the current line. */ - -#if defined (BANG_HISTORY) -/* Perform history expansion on the current line. If no history expansion - is done, pre_process_line() returns what it was passed, so we need to - allocate a new line here. */ -static char * -history_expand_line_internal (line) - char *line; -{ - char *new_line; - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; - new_line = pre_process_line (line, 0, 0); - hist_verify = old_verify; - - return (new_line == line) ? savestring (line) : new_line; -} -#endif - -/* There was an error in expansion. Let the preprocessor print - the error here. */ -static void -cleanup_expansion_error () -{ - char *to_free; -#if defined (BANG_HISTORY) - int old_verify; - - old_verify = hist_verify; - hist_verify = 0; -#endif - - fprintf (rl_outstream, "\r\n"); - to_free = pre_process_line (rl_line_buffer, 1, 0); -#if defined (BANG_HISTORY) - hist_verify = old_verify; -#endif - if (to_free != rl_line_buffer) - FREE (to_free); - putc ('\r', rl_outstream); - rl_forced_update_display (); -} - -/* If NEW_LINE differs from what is in the readline line buffer, add an - undo record to get from the readline line buffer contents to the new - line and make NEW_LINE the current readline line. */ -static void -maybe_make_readline_line (new_line) - char *new_line; -{ - if (strcmp (new_line, rl_line_buffer) != 0) - { - rl_point = rl_end; - - rl_add_undo (UNDO_BEGIN, 0, 0, 0); - rl_delete_text (0, rl_point); - rl_point = rl_end = rl_mark = 0; - rl_insert_text (new_line); - rl_add_undo (UNDO_END, 0, 0, 0); - } -} - -/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ -static void -set_up_new_line (new_line) - char *new_line; -{ - int old_point, at_end; - - old_point = rl_point; - at_end = rl_point == rl_end; - - /* If the line was history and alias expanded, then make that - be one thing to undo. */ - maybe_make_readline_line (new_line); - free (new_line); - - /* Place rl_point where we think it should go. */ - if (at_end) - rl_point = rl_end; - else if (old_point < rl_end) - { - rl_point = old_point; - if (!whitespace (rl_line_buffer[rl_point])) - rl_forward_word (1, 0); - } -} - -#if defined (ALIAS) -/* Expand aliases in the current readline line. */ -static int -alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = alias_expand (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} -#endif - -#if defined (BANG_HISTORY) -/* History expand the line. */ -static int -history_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = history_expand_line_internal (rl_line_buffer); - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* Expand history substitutions in the current line and then insert a - space (hopefully close to where we were before). */ -static int -tcsh_magic_space (count, ignore) - int count, ignore; -{ - int dist_from_end, old_point; - - old_point = rl_point; - dist_from_end = rl_end - rl_point; - if (history_expand_line (count, ignore) == 0) - { - /* Try a simple heuristic from Stephen Gildea . - This works if all expansions were before rl_point or if no expansions - were performed. */ - rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; - rl_insert (1, ' '); - return (0); - } - else - return (1); -} -#endif /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#if defined (ALIAS) - if (new_line) - { - char *alias_line; - - alias_line = alias_expand (new_line); - free (new_line); - new_line = alias_line; - } -#endif /* ALIAS */ - - if (new_line) - { - set_up_new_line (new_line); - return (0); - } - else - { - cleanup_expansion_error (); - return (1); - } -} - -/* History and alias expand the line, then perform the shell word - expansions by calling expand_string. This can't use set_up_new_line() - because we want the variable expansions as a separate undo'able - set of operations. */ -static int -shell_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - WORD_LIST *expanded_string; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#if defined (ALIAS) - if (new_line) - { - char *alias_line; - - alias_line = alias_expand (new_line); - free (new_line); - new_line = alias_line; - } -#endif /* ALIAS */ - - if (new_line) - { - int old_point = rl_point; - int at_end = rl_point == rl_end; - - /* If the line was history and alias expanded, then make that - be one thing to undo. */ - maybe_make_readline_line (new_line); - free (new_line); - - /* If there is variable expansion to perform, do that as a separate - operation to be undone. */ - new_line = savestring (rl_line_buffer); - expanded_string = expand_string (new_line, 0); - FREE (new_line); - if (expanded_string == 0) - { - new_line = (char *)xmalloc (1); - new_line[0] = '\0'; - } - else - { - new_line = string_list (expanded_string); - dispose_words (expanded_string); - } - - maybe_make_readline_line (new_line); - free (new_line); - - /* Place rl_point where we think it should go. */ - if (at_end) - rl_point = rl_end; - else if (old_point < rl_end) - { - rl_point = old_point; - if (!whitespace (rl_line_buffer[rl_point])) - rl_forward_word (1, 0); - } - return 0; - } - else - { - cleanup_expansion_error (); - return 1; - } -} - -/* If FIGNORE is set, then don't match files with the given suffixes when - completing filenames. If only one of the possibilities has an acceptable - suffix, delete the others, else just return and let the completer - signal an error. It is called by the completer when real - completions are done on filenames by the completer's internal - function, not for completion lists (M-?) and not on "other" - completion types, such as hostnames or commands. */ - -static struct ignorevar fignore = -{ - "FIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *) 0, -}; - -static void -_ignore_completion_names (names, name_func) - char **names; - sh_ignore_func_t *name_func; -{ - char **newnames; - int idx, nidx; - char **oldnames; - int oidx; - - /* If there is only one completion, see if it is acceptable. If it is - not, free it up. In any case, short-circuit and return. This is a - special case because names[0] is not the prefix of the list of names - if there is only one completion; it is the completion itself. */ - if (names[1] == (char *)0) - { - if (force_fignore) - if ((*name_func) (names[0]) == 0) - { - free (names[0]); - names[0] = (char *)NULL; - } - - return; - } - - /* Allocate space for array to hold list of pointers to matching - filenames. The pointers are copied back to NAMES when done. */ - for (nidx = 1; names[nidx]; nidx++) - ; - newnames = strvec_create (nidx + 1); - - if (force_fignore == 0) - { - oldnames = strvec_create (nidx - 1); - oidx = 0; - } - - newnames[0] = names[0]; - for (idx = nidx = 1; names[idx]; idx++) - { - if ((*name_func) (names[idx])) - newnames[nidx++] = names[idx]; - else if (force_fignore == 0) - oldnames[oidx++] = names[idx]; - else - free (names[idx]); - } - - newnames[nidx] = (char *)NULL; - - /* If none are acceptable then let the completer handle it. */ - if (nidx == 1) - { - if (force_fignore) - { - free (names[0]); - names[0] = (char *)NULL; - } - else - free (oldnames); - - free (newnames); - return; - } - - if (force_fignore == 0) - { - while (oidx) - free (oldnames[--oidx]); - free (oldnames); - } - - /* If only one is acceptable, copy it to names[0] and return. */ - if (nidx == 2) - { - free (names[0]); - names[0] = newnames[1]; - names[1] = (char *)NULL; - free (newnames); - return; - } - - /* Copy the acceptable names back to NAMES, set the new array end, - and return. */ - for (nidx = 1; newnames[nidx]; nidx++) - names[nidx] = newnames[nidx]; - names[nidx] = (char *)NULL; - free (newnames); -} - -static int -name_is_acceptable (name) - const char *name; -{ - struct ign *p; - int nlen; - - for (nlen = strlen (name), p = fignore.ignores; p->val; p++) - { - if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) - return (0); - } - - return (1); -} - -#if 0 -static int -ignore_dot_names (name) - char *name; -{ - return (name[0] != '.'); -} -#endif - -static int -filename_completion_ignore (names) - char **names; -{ -#if 0 - if (glob_dot_filenames == 0) - _ignore_completion_names (names, ignore_dot_names); -#endif - - setup_ignore_patterns (&fignore); - - if (fignore.num_ignores == 0) - return 0; - - _ignore_completion_names (names, name_is_acceptable); - - return 0; -} - -/* Return 1 if NAME is a directory. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* Remove files from NAMES, leaving directories. */ -static int -bash_ignore_filenames (names) - char **names; -{ - _ignore_completion_names (names, test_for_directory); - return 0; -} - -static int -return_zero (name) - const char *name; -{ - return 0; -} - -static int -bash_ignore_everything (names) - char **names; -{ - _ignore_completion_names (names, return_zero); - return 0; -} - -/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL - is an expanded filename. DIRECTORY_PART is the tilde-prefix portion - of the un-tilde-expanded version of VAL (what the user typed). */ -static char * -restore_tilde (val, directory_part) - char *val, *directory_part; -{ - int l, vl, dl2, xl; - char *dh2, *expdir, *ret; - - vl = strlen (val); - - /* We need to duplicate the expansions readline performs on the directory - portion before passing it to our completion function. */ - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - ret = (char *)xmalloc (dl2 + 2 + l); - strcpy (ret, dh2); - strcpy (ret + dl2, val + xl); - - free (dh2); - return (ret); -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if ((rl_directory_rewrite_hook) && (*rl_directory_rewrite_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* If necessary, rewrite directory entry */ -static char * -bash_filename_rewrite_hook (fname, fnlen) - char *fname; - int fnlen; -{ - char *conv; - - conv = fnx_fromfs (fname, fnlen); - if (conv != fname) - conv = savestring (conv); - return conv; -} - -/* Functions to save and restore the appropriate directory hook */ -/* This is not static so the shopt code can call it */ -void -set_directory_hook () -{ - if (dircomplete_expand) - { - rl_directory_completion_hook = bash_directory_completion_hook; - rl_directory_rewrite_hook = (rl_icppfunc_t *)0; - } - else - { - rl_directory_rewrite_hook = bash_directory_completion_hook; - rl_directory_completion_hook = (rl_icppfunc_t *)0; - } -} - -static rl_icppfunc_t * -save_directory_hook () -{ - rl_icppfunc_t *ret; - - if (dircomplete_expand) - { - ret = rl_directory_completion_hook; - rl_directory_completion_hook = (rl_icppfunc_t *)NULL; - } - else - { - ret = rl_directory_rewrite_hook; - rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; - } - - return ret; -} - -static void -restore_directory_hook (hookf) - rl_icppfunc_t *hookf; -{ - if (dircomplete_expand) - rl_directory_completion_hook = hookf; - else - rl_directory_rewrite_hook = hookf; -} - -/* Expand a filename before the readline completion code passes it to stat(2). - The filename will already have had tilde expansion performed. */ -static int -bash_filename_stat_hook (dirname) - char **dirname; -{ - char *local_dirname, *new_dirname, *t; - int should_expand_dirname, return_value; - WORD_LIST *wl; - struct stat sb; - - local_dirname = *dirname; - should_expand_dirname = return_value = 0; - if (t = mbschr (local_dirname, '$')) - should_expand_dirname = '$'; - else if (t = mbschr (local_dirname, '`')) /* XXX */ - should_expand_dirname = '`'; - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ - if (wl) - { - free (new_dirname); - new_dirname = string_list (wl); - /* Tell the completer we actually expanded something and change - *dirname only if we expanded to something non-null -- stat - behaves unpredictably when passed null or empty strings */ - if (new_dirname && *new_dirname) - { - *dirname = new_dirname; - return_value = STREQ (local_dirname, *dirname) == 0; - } - else - free (new_dirname); - free (local_dirname); - dispose_words (wl); - } - else - free (new_dirname); - } - - /* This is very similar to the code in bash_directory_completion_hook below, - but without spelling correction and not worrying about whether or not - we change relative pathnames. */ - if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) - { - char *temp1, *temp2; - - t = get_working_directory ("symlink-hook"); - temp1 = make_absolute (local_dirname, t); - free (t); - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return return_value; - } - - free (local_dirname); - *dirname = temp2; - free (temp1); - } - - return (return_value); -} - -/* Handle symbolic link references and other directory name - expansions while hacking completion. This should return 1 if it modifies - the DIRNAME argument, 0 otherwise. It should make sure not to modify - DIRNAME if it returns 0. */ -static int -bash_directory_completion_hook (dirname) - char **dirname; -{ - char *local_dirname, *new_dirname, *t; - int return_value, should_expand_dirname, nextch, closer; - WORD_LIST *wl; - struct stat sb; - - return_value = should_expand_dirname = nextch = closer = 0; - local_dirname = *dirname; - - if (t = mbschr (local_dirname, '$')) - { - should_expand_dirname = '$'; - nextch = t[1]; - /* Deliberately does not handle the deprecated $[...] arithmetic - expansion syntax */ - if (nextch == '(') - closer = ')'; - else if (nextch == '{') - closer = '}'; - else - nextch = 0; - } - else if (local_dirname[0] == '~') - should_expand_dirname = '~'; - else - { - t = mbschr (local_dirname, '`'); - if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) - should_expand_dirname = '`'; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ - if (wl) - { - *dirname = string_list (wl); - /* Tell the completer to replace the directory name only if we - actually expanded something. */ - return_value = STREQ (local_dirname, *dirname) == 0; - free (local_dirname); - free (new_dirname); - dispose_words (wl); - local_dirname = *dirname; - /* XXX - change rl_filename_quote_characters here based on - should_expand_dirname/nextch/closer. This is the only place - custom_filename_quote_characters is modified. */ - if (rl_filename_quote_characters && *rl_filename_quote_characters) - { - int i, j, c; - i = strlen (default_filename_quote_characters); - custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); - for (i = j = 0; c = default_filename_quote_characters[i]; i++) - { - if (c == should_expand_dirname || c == nextch || c == closer) - continue; - custom_filename_quote_characters[j++] = c; - } - custom_filename_quote_characters[j] = '\0'; - rl_filename_quote_characters = custom_filename_quote_characters; - set_filename_bstab (rl_filename_quote_characters); - } - } - else - { - free (new_dirname); - free (local_dirname); - *dirname = (char *)xmalloc (1); - **dirname = '\0'; - return 1; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - return_value = STREQ (local_dirname, new_dirname) == 0; - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - /* no_symbolic_links == 0 -> use (default) logical view of the file system. - local_dirname[0] == '.' && local_dirname[1] == '/' means files in the - current directory (./). - local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames - in the current directory (e.g., lib/sh). - XXX - should we do spelling correction on these? */ - - /* This is test as it was in bash-4.2: skip relative pathnames in current - directory. Change test to - (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) - if we want to skip paths beginning with ./ also. */ - if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) - { - char *temp1, *temp2; - int len1, len2; - - /* If we have a relative path - (local_dirname[0] != '/' && local_dirname[0] != '.') - that is canonical after appending it to the current directory, then - temp1 = temp2+'/' - That is, - strcmp (temp1, temp2) == 0 - after adding a slash to temp2 below. It should be safe to not - change those. - */ - t = get_working_directory ("symlink-hook"); - temp1 = make_absolute (local_dirname, t); - free (t); - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - /* Try spelling correction if initial canonicalization fails. Make - sure we are set to replace the directory name with the results so - subsequent directory checks don't fail. */ - if (temp2 == 0 && dircomplete_spelling && dircomplete_expand) - { - temp2 = dirspell (temp1); - if (temp2) - { - free (temp1); - temp1 = temp2; - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - return_value |= temp2 != 0; - } - } - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return return_value; - } - len1 = strlen (temp1); - if (temp1[len1 - 1] == '/') - { - len2 = strlen (temp2); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - temp2 = (char *)xrealloc (temp2, len2 + 2); - temp2[len2] = '/'; - temp2[len2 + 1] = '\0'; - } - } - - /* dircomplete_expand_relpath == 0 means we want to leave relative - pathnames that are unchanged by canonicalization alone. - *local_dirname != '/' && *local_dirname != '.' == relative pathname - (consistent with general.c:absolute_pathname()) - temp1 == temp2 (after appending a slash to temp2) means the pathname - is not changed by canonicalization as described above. */ - if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) - return_value |= STREQ (local_dirname, temp2) == 0; - free (local_dirname); - *dirname = temp2; - free (temp1); - } - - return (return_value); -} - -static char **history_completion_array = (char **)NULL; -static int harry_size; -static int harry_len; - -static void -build_history_completion_array () -{ - register int i, j; - HIST_ENTRY **hlist; - char **tokens; - - /* First, clear out the current dynamic history completion list. */ - if (harry_size) - { - strvec_dispose (history_completion_array); - history_completion_array = (char **)NULL; - harry_size = 0; - harry_len = 0; - } - - /* Next, grovel each line of history, making each shell-sized token - a separate entry in the history_completion_array. */ - hlist = history_list (); - - if (hlist) - { - for (i = 0; hlist[i]; i++) - ; - for ( --i; i >= 0; i--) - { - /* Separate each token, and place into an array. */ - tokens = history_tokenize (hlist[i]->line); - - for (j = 0; tokens && tokens[j]; j++) - { - if (harry_len + 2 > harry_size) - history_completion_array = strvec_resize (history_completion_array, harry_size += 10); - - history_completion_array[harry_len++] = tokens[j]; - history_completion_array[harry_len] = (char *)NULL; - } - free (tokens); - } - - /* Sort the complete list of tokens. */ - if (dabbrev_expand_active == 0) - qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); - } -} - -static char * -history_completion_generator (hint_text, state) - const char *hint_text; - int state; -{ - static int local_index, len; - static const char *text; - - /* If this is the first call to the generator, then initialize the - list of strings to complete over. */ - if (state == 0) - { - if (dabbrev_expand_active) /* This is kind of messy */ - rl_completion_suppress_append = 1; - local_index = 0; - build_history_completion_array (); - text = hint_text; - len = strlen (text); - } - - while (history_completion_array && history_completion_array[local_index]) - { - if (strncmp (text, history_completion_array[local_index++], len) == 0) - return (savestring (history_completion_array[local_index - 1])); - } - return ((char *)NULL); -} - -static int -dynamic_complete_history (count, key) - int count, key; -{ - int r; - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - - rl_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - - /* XXX - use rl_completion_mode here? */ - if (rl_last_func == dynamic_complete_history) - r = rl_complete_internal ('?'); - else - r = rl_complete_internal (TAB); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - - return r; -} - -static int -bash_dabbrev_expand (count, key) - int count, key; -{ - int r, orig_suppress, orig_sort; - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - - orig_func = rl_menu_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - orig_suppress = rl_completion_suppress_append; - orig_sort = rl_sort_completion_matches; - - rl_menu_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_filename_completion_desired = 0; - rl_completion_suppress_append = 1; - rl_sort_completion_matches = 0; - - /* XXX - use rl_completion_mode here? */ - dabbrev_expand_active = 1; - if (rl_last_func == bash_dabbrev_expand) - rl_last_func = rl_menu_complete; - r = rl_menu_complete (count, key); - dabbrev_expand_active = 0; - - rl_last_func = bash_dabbrev_expand; - rl_menu_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - rl_completion_suppress_append = orig_suppress; - rl_sort_completion_matches = orig_sort; - - return r; -} - -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) -static int -bash_complete_username (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_username_internal (rl_completion_mode (bash_complete_username)); -} - -static int -bash_possible_username_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_username_internal ('?'); -} - -static int -bash_complete_username_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, rl_username_completion_function); -} - -static int -bash_complete_filename (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_filename_internal (rl_completion_mode (bash_complete_filename)); -} - -static int -bash_possible_filename_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_filename_internal ('?'); -} - -static int -bash_complete_filename_internal (what_to_do) - int what_to_do; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_icppfunc_t *orig_dir_func; - rl_compignore_func_t *orig_ignore_func; - /*const*/ char *orig_rl_completer_word_break_characters; - int r; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - orig_rl_completer_word_break_characters = rl_completer_word_break_characters; - - orig_dir_func = save_directory_hook (); - - rl_completion_entry_function = rl_filename_completion_function; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_ignore_some_completions_function = filename_completion_ignore; - rl_completer_word_break_characters = " \t\n\"\'"; - - r = rl_complete_internal (what_to_do); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - rl_completer_word_break_characters = orig_rl_completer_word_break_characters; - - restore_directory_hook (orig_dir_func); - - return r; -} - -static int -bash_complete_hostname (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_hostname_internal (rl_completion_mode (bash_complete_hostname)); -} - -static int -bash_possible_hostname_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_hostname_internal ('?'); -} - -static int -bash_complete_variable (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_variable_internal (rl_completion_mode (bash_complete_variable)); -} - -static int -bash_possible_variable_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_variable_internal ('?'); -} - -static int -bash_complete_command (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_command_internal (rl_completion_mode (bash_complete_command)); -} - -static int -bash_possible_command_completions (ignore, ignore2) - int ignore, ignore2; -{ - return bash_complete_command_internal ('?'); -} - -static int -bash_complete_hostname_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, hostname_completion_function); -} - -static int -bash_complete_variable_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, variable_completion_function); -} - -static int -bash_complete_command_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, command_word_completion_function); -} - -static char *globtext; -static char *globorig; - -static char * -glob_complete_word (text, state) - const char *text; - int state; -{ - static char **matches = (char **)NULL; - static int ind; - int glen; - char *ret, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - matches = shell_glob_filename (globtext); - if (GLOB_FAILED (matches)) - matches = (char **)NULL; - ind = 0; - } - - ret = matches ? matches[ind] : (char *)NULL; - ind++; - return ret; -} - -static int -bash_glob_completion_internal (what_to_do) - int what_to_do; -{ - return bash_specific_completion (what_to_do, glob_complete_word); -} - -/* A special quoting function so we don't end up quoting globbing characters - in the word if there are no matches or multiple matches. */ -static char * -bash_glob_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) - return (savestring (s)); - else - return (bash_quote_filename (s, rtype, qcp)); -} - -static int -bash_glob_complete_word (count, key) - int count, key; -{ - int r; - rl_quote_func_t *orig_quoting_function; - - if (rl_editing_mode == EMACS_EDITING_MODE) - rl_explicit_arg = 1; /* force `*' append */ - orig_quoting_function = rl_filename_quoting_function; - rl_filename_quoting_function = bash_glob_quote_filename; - - r = bash_glob_completion_internal (rl_completion_mode (bash_glob_complete_word)); - - rl_filename_quoting_function = orig_quoting_function; - return r; -} - -static int -bash_glob_expand_word (count, key) - int count, key; -{ - return bash_glob_completion_internal ('*'); -} - -static int -bash_glob_list_expansions (count, key) - int count, key; -{ - return bash_glob_completion_internal ('?'); -} - -static int -bash_specific_completion (what_to_do, generator) - int what_to_do; - rl_compentry_func_t *generator; -{ - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - rl_compignore_func_t *orig_ignore_func; - int r; - - orig_func = rl_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - orig_ignore_func = rl_ignore_some_completions_function; - rl_completion_entry_function = generator; - rl_attempted_completion_function = NULL; - rl_ignore_some_completions_function = orig_ignore_func; - - r = rl_complete_internal (what_to_do); - - rl_completion_entry_function = orig_func; - rl_attempted_completion_function = orig_attempt_func; - rl_ignore_some_completions_function = orig_ignore_func; - - return r; -} - -#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ - -#if defined (VI_MODE) -/* Completion, from vi mode's point of view. This is a modified version of - rl_vi_complete which uses the bash globbing code to implement what POSIX - specifies, which is to append a `*' and attempt filename generation (which - has the side effect of expanding any globbing characters in the word). */ -static int -bash_vi_complete (count, key) - int count, key; -{ -#if defined (SPECIFIC_COMPLETION_FUNCTIONS) - int p, r; - char *t; - - if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) - { - if (!whitespace (rl_line_buffer[rl_point + 1])) - rl_vi_end_word (1, 'E'); - rl_point++; - } - - /* Find boundaries of current word, according to vi definition of a - `bigword'. */ - t = 0; - if (rl_point > 0) - { - p = rl_point; - rl_vi_bWord (1, 'B'); - r = rl_point; - rl_point = p; - p = r; - - t = substring (rl_line_buffer, p, rl_point); - } - - if (t && glob_pattern_p (t) == 0) - rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ - FREE (t); - - if (key == '*') /* Expansion and replacement. */ - r = bash_glob_expand_word (count, key); - else if (key == '=') /* List possible completions. */ - r = bash_glob_list_expansions (count, key); - else if (key == '\\') /* Standard completion */ - r = bash_glob_complete_word (count, key); - else - r = rl_complete (0, key); - - if (key == '*' || key == '\\') - rl_vi_start_inserting (key, 1, 1); - - return (r); -#else - return rl_vi_complete (count, key); -#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ -} -#endif /* VI_MODE */ - -/* Filename quoting for completion. */ -/* A function to strip unquoted quote characters (single quotes, double - quotes, and backslashes). It allows single quotes to appear - within double quotes, and vice versa. It should be smarter. */ -static char * -bash_dequote_filename (text, quote_char) - char *text; - int quote_char; -{ - char *ret, *p, *r; - int l, quoted; - - l = strlen (text); - ret = (char *)xmalloc (l + 1); - for (quoted = quote_char, p = text, r = ret; p && *p; p++) - { - /* Allow backslash-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *p; - - *r++ = *++p; - if (*p == '\0') - return ret; /* XXX - was break; */ - continue; - } - /* Close quote. */ - if (quoted && *p == quoted) - { - quoted = 0; - continue; - } - /* Open quote. */ - if (quoted == 0 && (*p == '\'' || *p == '"')) - { - quoted = *p; - continue; - } - *r++ = *p; - } - *r = '\0'; - return ret; -} - -/* Quote characters that the readline completion code would treat as - word break characters with backslashes. Pass backslash-quoted - characters through without examination. */ -static char * -quote_word_break_chars (text) - char *text; -{ - char *ret, *r, *s; - int l; - - l = strlen (text); - ret = (char *)xmalloc ((2 * l) + 1); - for (s = text, r = ret; *s; s++) - { - /* Pass backslash-quoted characters through, including the backslash. */ - if (*s == '\\') - { - *r++ = '\\'; - *r++ = *++s; - if (*s == '\0') - break; - continue; - } - /* OK, we have an unquoted character. Check its presence in - rl_completer_word_break_characters. */ - if (mbschr (rl_completer_word_break_characters, *s)) - *r++ = '\\'; - /* XXX -- check for standalone tildes here and backslash-quote them */ - if (s == text && *s == '~' && file_exists (text)) - *r++ = '\\'; - *r++ = *s; - } - *r = '\0'; - return ret; -} - -/* Use characters in STRING to populate the table of characters that should - be backslash-quoted. The table will be used for sh_backslash_quote from - this file. */ -static void -set_filename_bstab (string) - const char *string; -{ - const char *s; - - memset (filename_bstab, 0, sizeof (filename_bstab)); - for (s = string; s && *s; s++) - filename_bstab[*s] = 1; -} - -/* Quote a filename using double quotes, single quotes, or backslashes - depending on the value of completion_quoting_style. If we're - completing using backslashes, we need to quote some additional - characters (those that readline treats as word breaks), so we call - quote_word_break_chars on the result. This returns newly-allocated - memory. */ -static char * -bash_quote_filename (s, rtype, qcp) - char *s; - int rtype; - char *qcp; -{ - char *rtext, *mtext, *ret; - int rlen, cs; - - rtext = (char *)NULL; - - /* If RTYPE == MULT_MATCH, it means that there is - more than one match. In this case, we do not add - the closing quote or attempt to perform tilde - expansion. If RTYPE == SINGLE_MATCH, we try - to perform tilde expansion, because single and double - quotes inhibit tilde expansion by the shell. */ - - cs = completion_quoting_style; - /* Might need to modify the default completion style based on *qcp, - since it's set to any user-provided opening quote. We also change - to single-quoting if there is no user-provided opening quote and - the word being completed contains newlines, since those are not - quoted correctly using backslashes (a backslash-newline pair is - special to the shell parser). */ - if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n')) - cs = COMPLETE_SQUOTE; - else if (*qcp == '"') - cs = COMPLETE_DQUOTE; - else if (*qcp == '\'') - cs = COMPLETE_SQUOTE; -#if defined (BANG_HISTORY) - else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && mbschr (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && mbschr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - switch (cs) - { - case COMPLETE_DQUOTE: - rtext = sh_double_quote (mtext); - break; - case COMPLETE_SQUOTE: - rtext = sh_single_quote (mtext); - break; - case COMPLETE_BSQUOTE: - rtext = sh_backslash_quote (mtext, complete_fullquote ? 0 : filename_bstab, 0); - break; - } - - if (mtext != s) - free (mtext); - - /* We may need to quote additional characters: those that readline treats - as word breaks that are not quoted by backslash_quote. */ - if (rtext && cs == COMPLETE_BSQUOTE) - { - mtext = quote_word_break_chars (rtext); - free (rtext); - rtext = mtext; - } - - /* Leave the opening quote intact. The readline completion code takes - care of avoiding doubled opening quotes. */ - if (rtext) - { - rlen = strlen (rtext); - ret = (char *)xmalloc (rlen + 1); - strcpy (ret, rtext); - } - else - { - ret = (char *)xmalloc (rlen = 1); - ret[0] = '\0'; - } - - /* If there are multiple matches, cut off the closing quote. */ - if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) - ret[rlen - 1] = '\0'; - free (rtext); - return ret; -} - -/* Support for binding readline key sequences to Unix commands. */ -static Keymap cmd_xmap; - -static int -putx(c) - int c; -{ - return (putc (c, rl_outstream)); -} - -static int -bash_execute_unix_command (count, key) - int count; /* ignored */ - int key; -{ - Keymap ckmap; /* current keymap */ - Keymap xkmap; /* unix command executing keymap */ - rl_command_func_t *func; - int type; - register int i, r; - intmax_t mi; - sh_parser_state_t ps; - char *cmd, *value, *l, *l1, *ce; - SHELL_VAR *v; - char ibuf[INT_STRLEN_BOUND(int) + 1]; - - /* First, we need to find the right command to execute. This is tricky, - because we might have already indirected into another keymap, so we - have to walk cmd_xmap using the entire key sequence. */ - cmd = (char *)rl_function_of_keyseq (rl_executing_keyseq, cmd_xmap, &type); - - if (cmd == 0 || type != ISMACR) - { - rl_crlf (); - internal_error (_("bash_execute_unix_command: cannot find keymap for command")); - rl_forced_update_display (); - return 1; - } - - ce = rl_get_termcap ("ce"); - if (ce) /* clear current line */ - { - fprintf (rl_outstream, "\r"); - tputs (ce, 1, putx); - fflush (rl_outstream); - } - else - rl_crlf (); /* move to a new line */ - - v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); - if (v) - VSETATTR (v, att_exported); - l = v ? value_cell (v) : 0; - value = inttostr (rl_point, ibuf, sizeof (ibuf)); - v = bind_int_variable ("READLINE_POINT", value); - if (v) - VSETATTR (v, att_exported); - array_needs_making = 1; - - save_parser_state (&ps); - r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); - restore_parser_state (&ps); - - v = find_variable ("READLINE_LINE"); - l1 = v ? value_cell (v) : 0; - if (l1 != l) - maybe_make_readline_line (value_cell (v)); - v = find_variable ("READLINE_POINT"); - if (v && legal_number (value_cell (v), &mi)) - { - i = mi; - if (i != rl_point) - { - rl_point = i; - if (rl_point > rl_end) - rl_point = rl_end; - else if (rl_point < 0) - rl_point = 0; - } - } - - unbind_variable ("READLINE_LINE"); - unbind_variable ("READLINE_POINT"); - array_needs_making = 1; - - /* and restore the readline buffer and display after command execution. */ - rl_forced_update_display (); - return 0; -} - -int -print_unix_command_map () -{ - Keymap save; - - save = rl_get_keymap (); - rl_set_keymap (cmd_xmap); - rl_macro_dumper (1); - rl_set_keymap (save); - return 0; -} - -static void -init_unix_command_map () -{ - cmd_xmap = rl_make_bare_keymap (); -} - -static int -isolate_sequence (string, ind, need_dquote, startp) - char *string; - int ind, need_dquote, *startp; -{ - register int i; - int c, passc, delim; - - for (i = ind; string[i] && whitespace (string[i]); i++) - ; - /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ - if (need_dquote && string[i] != '"') - { - builtin_error (_("%s: first non-whitespace character is not `\"'"), string); - return -1; - } - - /* We can have delimited strings even if NEED_DQUOTE == 0, like the command - string to bind the key sequence to. */ - delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; - - if (startp) - *startp = delim ? ++i : i; - - for (passc = 0; c = string[i]; i++) - { - if (passc) - { - passc = 0; - continue; - } - if (c == '\\') - { - passc++; - continue; - } - if (c == delim) - break; - } - - if (delim && string[i] != delim) - { - builtin_error (_("no closing `%c' in %s"), delim, string); - return -1; - } - - return i; -} - -int -bind_keyseq_to_unix_command (line) - char *line; -{ - Keymap kmap; - char *kseq, *value; - int i, kstart; - - if (cmd_xmap == 0) - init_unix_command_map (); - - kmap = rl_get_keymap (); - - /* We duplicate some of the work done by rl_parse_and_bind here, but - this code only has to handle `"keyseq": ["]command["]' and can - generate an error for anything else. */ - i = isolate_sequence (line, 0, 1, &kstart); - if (i < 0) - return -1; - - /* Create the key sequence string to pass to rl_generic_bind */ - kseq = substring (line, kstart, i); - - for ( ; line[i] && line[i] != ':'; i++) - ; - if (line[i] != ':') - { - builtin_error (_("%s: missing colon separator"), line); - FREE (kseq); - return -1; - } - - i = isolate_sequence (line, i + 1, 0, &kstart); - if (i < 0) - { - FREE (kseq); - return -1; - } - - /* Create the value string containing the command to execute. */ - value = substring (line, kstart, i); - - /* Save the command to execute and the key sequence in the CMD_XMAP */ - rl_generic_bind (ISMACR, kseq, value, cmd_xmap); - - /* and bind the key sequence in the current keymap to a function that - understands how to execute from CMD_XMAP */ - rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap); - - free (kseq); - return 0; -} - -/* Used by the programmable completion code. Complete TEXT as a filename, - but return only directories as matches. Dequotes the filename before - attempting to find matches. */ -char ** -bash_directory_completion_matches (text) - const char *text; -{ - char **m1; - char *dfn; - int qc; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - dfn = bash_dequote_filename ((char *)text, qc); - m1 = rl_completion_matches (dfn, rl_filename_completion_function); - free (dfn); - - if (m1 == 0 || m1[0] == 0) - return m1; - /* We don't bother recomputing the lcd of the matches, because it will just - get thrown away by the programmable completion code and recomputed - later. */ - (void)bash_ignore_filenames (m1); - return m1; -} - -char * -bash_dequote_text (text) - const char *text; -{ - char *dtxt; - int qc; - - qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; - dtxt = bash_dequote_filename ((char *)text, qc); - return (dtxt); -} - -static int -bash_event_hook () -{ -#if defined (DEBUG) -itrace("bash_event_hook"); -#endif - CHECK_TERMSIG; -} - -#endif /* READLINE */ diff --git a/builtins/cd.def~ b/builtins/cd.def~ deleted file mode 100644 index 88e09ab06..000000000 --- a/builtins/cd.def~ +++ /dev/null @@ -1,555 +0,0 @@ -This file is cd.def, from which is created cd.c. It implements the -builtins "cd" and "pwd" in Bash. - -Copyright (C) 1987-2011 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 . - -$PRODUCES cd.c -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashtypes.h" -#include "posixdir.h" -#include "posixstat.h" -#ifndef _MINIX -#include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include -#include - -#include "../shell.h" -#include "../flags.h" -#include "maxpath.h" -#include "common.h" -#include "bashgetopt.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; -extern int array_needs_making; -extern const char * const bash_getcwd_errstr; - -static int bindpwd __P((int)); -static int setpwd __P((char *)); -static char *resetpwd __P((char *)); -static int change_to_directory __P((char *, int)); - -/* Change this to 1 to get cd spelling correction by default. */ -int cdspelling = 0; - -int cdable_vars; - -static int eflag; /* file scope so bindpwd() can see it */ - -$BUILTIN cd -$FUNCTION cd_builtin -$SHORT_DOC cd [-L|[-P [-e]]] [dir] -Change the shell working directory. - -Change the current directory to DIR. The default DIR is the value of the -HOME shell variable. - -The variable CDPATH defines the search path for the directory containing -DIR. Alternative directory names in CDPATH are separated by a colon (:). -A null directory name is the same as the current directory. If DIR begins -with a slash (/), then CDPATH is not used. - -If the directory is not found, and the shell option `cdable_vars' is set, -the word is assumed to be a variable name. If that variable has a value, -its value is used for DIR. - -Options: - -L force symbolic links to be followed: resolve symbolic links in - DIR after processing instances of `..' - -P use the physical directory structure without following symbolic - links: resolve symbolic links in DIR before processing instances - of `..' - -e if the -P option is supplied, and the current working directory - cannot be determined successfully, exit with a non-zero status - -The default is to follow symbolic links, as if `-L' were specified. -`..' is processed by removing the immediately previous pathname component -back to a slash or the beginning of DIR. - -Exit Status: -Returns 0 if the directory is changed, and if $PWD is set successfully when --P is used; non-zero otherwise. -$END - -/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */ -static int -setpwd (dirname) - char *dirname; -{ - int old_anm; - SHELL_VAR *tvar; - - old_anm = array_needs_making; - tvar = bind_variable ("PWD", dirname ? dirname : "", 0); - if (tvar && readonly_p (tvar)) - return EXECUTION_FAILURE; - if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("PWD=", 4, dirname ? dirname : ""); - array_needs_making = 0; - } - return EXECUTION_SUCCESS; -} - -static int -bindpwd (no_symlinks) - int no_symlinks; -{ - char *dirname, *pwdvar; - int old_anm, r; - SHELL_VAR *tvar; - - r = sh_chkwrite (EXECUTION_SUCCESS); - -#define tcwd the_current_working_directory - dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("cd"); -#undef tcwd - - old_anm = array_needs_making; - pwdvar = get_string_value ("PWD"); - - tvar = bind_variable ("OLDPWD", pwdvar, 0); - if (tvar && readonly_p (tvar)) - r = EXECUTION_FAILURE; - - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("OLDPWD=", 7, pwdvar); - array_needs_making = 0; - } - - if (setpwd (dirname) == EXECUTION_FAILURE) - r = EXECUTION_FAILURE; - if (dirname == 0 && eflag) - r = EXECUTION_FAILURE; - - if (dirname && dirname != the_current_working_directory) - free (dirname); - - return (r); -} - -/* Call get_working_directory to reset the value of - the_current_working_directory () */ -static char * -resetpwd (caller) - char *caller; -{ - char *tdir; - - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - tdir = get_working_directory (caller); - return (tdir); -} - -#define LCD_DOVARS 0x001 -#define LCD_DOSPELL 0x002 -#define LCD_PRINTPATH 0x004 -#define LCD_FREEDIRNAME 0x008 - -/* This builtin is ultimately the way that all user-visible commands should - change the current working directory. It is called by cd_to_string (), - so the programming interface is simple, and it handles errors and - restrictions properly. */ -int -cd_builtin (list) - WORD_LIST *list; -{ - char *dirname, *cdpath, *path, *temp; - int path_index, no_symlinks, opt, lflag; - -#if defined (RESTRICTED_SHELL) - if (restricted) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif /* RESTRICTED_SHELL */ - - eflag = 0; - no_symlinks = no_symbolic_links; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - no_symlinks = 1; - break; - case 'L': - no_symlinks = 0; - break; - case 'e': - eflag = 1; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - - lflag = (cdable_vars ? LCD_DOVARS : 0) | - ((interactive && cdspelling) ? LCD_DOSPELL : 0); - if (eflag && no_symlinks == 0) - eflag = 0; - - if (list == 0) - { - /* `cd' without arguments is equivalent to `cd $HOME' */ - dirname = get_string_value ("HOME"); - - if (dirname == 0) - { - builtin_error (_("HOME not set")); - return (EXECUTION_FAILURE); - } - lflag = 0; - } -#if defined (CD_COMPLAINS) - else if (list->next) - { - builtin_error (_("too many arguments")); - return (EXECUTION_FAILURE); - } -#endif - else if (list->word->word[0] == '-' && list->word->word[1] == '\0') - { - /* This is `cd -', equivalent to `cd $OLDPWD' */ - dirname = get_string_value ("OLDPWD"); - - if (dirname == 0) - { - builtin_error (_("OLDPWD not set")); - return (EXECUTION_FAILURE); - } -#if 0 - lflag = interactive ? LCD_PRINTPATH : 0; -#else - lflag = LCD_PRINTPATH; /* According to SUSv3 */ -#endif - } - else if (absolute_pathname (list->word->word)) - dirname = list->word->word; - else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH"))) - { - dirname = list->word->word; - - /* Find directory in $CDPATH. */ - path_index = 0; - while (path = extract_colon_unit (cdpath, &path_index)) - { - /* OPT is 1 if the path element is non-empty */ - opt = path[0] != '\0'; - temp = sh_makepath (path, dirname, MP_DOTILDE); - free (path); - - if (change_to_directory (temp, no_symlinks)) - { - /* POSIX.2 says that if a nonempty directory from CDPATH - is used to find the directory to change to, the new - directory name is echoed to stdout, whether or not - the shell is interactive. */ - if (opt && (path = no_symlinks ? temp : the_current_working_directory)) - printf ("%s\n", path); - - free (temp); -#if 0 - /* Posix.2 says that after using CDPATH, the resultant - value of $PWD will not contain `.' or `..'. */ - return (bindpwd (posixly_correct || no_symlinks)); -#else - return (bindpwd (no_symlinks)); -#endif - } - else - free (temp); - } - -#if 0 - /* changed for bash-4.2 Posix cd description steps 5-6 */ - /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't - try the current directory, so we just punt now with an error - message if POSIXLY_CORRECT is non-zero. The check for cdpath[0] - is so we don't mistakenly treat a CDPATH value of "" as not - specifying the current directory. */ - if (posixly_correct && cdpath[0]) - { - builtin_error ("%s: %s", dirname, strerror (ENOENT)); - return (EXECUTION_FAILURE); - } -#endif - } - else - dirname = list->word->word; - - /* When we get here, DIRNAME is the directory to change to. If we - chdir successfully, just return. */ - if (change_to_directory (dirname, no_symlinks)) - { - if (lflag & LCD_PRINTPATH) - printf ("%s\n", dirname); - return (bindpwd (no_symlinks)); - } - - /* If the user requests it, then perhaps this is the name of - a shell variable, whose value contains the directory to - change to. */ - if (lflag & LCD_DOVARS) - { - temp = get_string_value (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - return (bindpwd (no_symlinks)); - } - } - - /* If the user requests it, try to find a directory name similar in - spelling to the one requested, in case the user made a simple - typo. This is similar to the UNIX 8th and 9th Edition shells. */ - if (lflag & LCD_DOSPELL) - { - temp = dirspell (dirname); - if (temp && change_to_directory (temp, no_symlinks)) - { - printf ("%s\n", temp); - free (temp); - return (bindpwd (no_symlinks)); - } - else - FREE (temp); - } - - builtin_error ("%s: %s", dirname, strerror (errno)); - return (EXECUTION_FAILURE); -} - -$BUILTIN pwd -$FUNCTION pwd_builtin -$SHORT_DOC pwd [-LP] -Print the name of the current working directory. - -Options: - -L print the value of $PWD if it names the current working - directory - -P print the physical directory, without any symbolic links - -By default, `pwd' behaves as if `-L' were specified. - -Exit Status: -Returns 0 unless an invalid option is given or the current directory -cannot be read. -$END - -/* Non-zero means that pwd always prints the physical directory, without - symbolic links. */ -static int verbatim_pwd; - -/* Print the name of the current working directory. */ -int -pwd_builtin (list) - WORD_LIST *list; -{ - char *directory; - int opt, pflag; - - verbatim_pwd = no_symbolic_links; - pflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - verbatim_pwd = pflag = 1; - break; - case 'L': - verbatim_pwd = 0; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - list = loptend; - -#define tcwd the_current_working_directory - - directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd) - : get_working_directory ("pwd"); - - /* Try again using getcwd() if canonicalization fails (for instance, if - the file system has changed state underneath bash). */ - if ((tcwd && directory == 0) || - (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0)) - { - if (directory && directory != tcwd) - free (directory); - directory = resetpwd ("pwd"); - } - -#undef tcwd - - if (directory) - { - opt = EXECUTION_SUCCESS; - printf ("%s\n", directory); - /* This is dumb but posix-mandated. */ - if (posixly_correct && pflag) - opt = setpwd (directory); - if (directory != the_current_working_directory) - free (directory); - return (sh_chkwrite (opt)); - } - else - return (EXECUTION_FAILURE); -} - -/* Do the work of changing to the directory NEWDIR. Handle symbolic - link following, etc. This function *must* return with - the_current_working_directory either set to NULL (in which case - getcwd() will eventually be called), or set to a string corresponding - to the working directory. Return 1 on success, 0 on failure. */ - -static int -change_to_directory (newdir, nolinks) - char *newdir; - int nolinks; -{ - char *t, *tdir; - int err, canon_failed, r, ndlen, dlen; - - tdir = (char *)NULL; - - if (the_current_working_directory == 0) - { - t = get_working_directory ("chdir"); - FREE (t); - } - - t = make_absolute (newdir, the_current_working_directory); - - /* TDIR is either the canonicalized absolute pathname of NEWDIR - (nolinks == 0) or the absolute physical pathname of NEWDIR - (nolinks != 0). */ - tdir = nolinks ? sh_physpath (t, 0) - : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - - ndlen = strlen (newdir); - dlen = strlen (t); - - /* Use the canonicalized version of NEWDIR, or, if canonicalization - failed, use the non-canonical form. */ - canon_failed = 0; - if (tdir && *tdir) - free (t); - else - { - FREE (tdir); - tdir = t; - canon_failed = 1; - } - - /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath - returns NULL (because it checks the path, it will return NULL if the - resolved path doesn't exist), fail immediately. */ - if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX)) - { -#if defined ENAMETOOLONG - if (errno != ENOENT && errno != ENAMETOOLONG) -#else - if (errno != ENOENT) -#endif - errno = ENOTDIR; - free (tdir); - return (0); - } - - /* If the chdir succeeds, update the_current_working_directory. */ - if (chdir (nolinks ? newdir : tdir) == 0) - { - /* If canonicalization failed, but the chdir succeeded, reset the - shell's idea of the_current_working_directory. */ - if (canon_failed) - { - t = resetpwd ("cd"); - if (t == 0) - set_working_directory (tdir); - else - free (t); - } - else - set_working_directory (tdir); - - free (tdir); - return (1); - } - - /* We failed to change to the appropriate directory name. If we tried - what the user passed (nolinks != 0), punt now. */ - if (nolinks) - { - free (tdir); - return (0); - } - - err = errno; - - /* We're not in physical mode (nolinks == 0), but we failed to change to - the canonicalized directory name (TDIR). Try what the user passed - verbatim. If we succeed, reinitialize the_current_working_directory. */ - if (chdir (newdir) == 0) - { - t = resetpwd ("cd"); - if (t == 0) - set_working_directory (tdir); - else - free (t); - - r = 1; - } - else - { - errno = err; - r = 0; - } - - free (tdir); - return r; -} diff --git a/builtins/fc.def~ b/builtins/fc.def~ deleted file mode 100644 index 557d02629..000000000 --- a/builtins/fc.def~ +++ /dev/null @@ -1,683 +0,0 @@ -This file is fc.def, from which is created fc.c. -It implements the builtin "fc" in Bash. - -Copyright (C) 1987-2011 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 . - -$PRODUCES fc.c - -$BUILTIN fc -$FUNCTION fc_builtin -$DEPENDS_ON HISTORY -$SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command] -Display or execute commands from the history list. - -fc is used to list or edit and re-execute commands from the history list. -FIRST and LAST can be numbers specifying the range, or FIRST can be a -string, which means the most recent command beginning with that -string. - -Options: - -e ENAME select which editor to use. Default is FCEDIT, then EDITOR, - then vi - -l list lines instead of editing - -n omit line numbers when listing - -r reverse the order of the lines (newest listed first) - -With the `fc -s [pat=rep ...] [command]' format, COMMAND is -re-executed after the substitution OLD=NEW is performed. - -A useful alias to use with this is r='fc -s', so that typing `r cc' -runs the last command beginning with `cc' and typing `r' re-executes -the last command. - -Exit Status: -Returns success or status of executed command; non-zero if an error occurs. -$END - -#include - -#if defined (HISTORY) -#ifndef _MINIX -# include -#endif -#include "../bashtypes.h" -#include "posixstat.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include "../bashansi.h" -#include "../bashintl.h" -#include - -#include "../shell.h" -#include "../builtins.h" -#include "../flags.h" -#include "../bashhist.h" -#include "maxpath.h" -#include -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int current_command_line_count; -extern int literal_history; -extern int posixly_correct; -extern int subshell_environment, interactive_shell; - -extern int unlink __P((const char *)); - -extern FILE *sh_mktmpfp __P((char *, int, char **)); - -/* **************************************************************** */ -/* */ -/* The K*rn shell style fc command (Fix Command) */ -/* */ -/* **************************************************************** */ - -/* fc builtin command (fix command) for Bash for those who - like K*rn-style history better than csh-style. - - fc [-e ename] [-nlr] [first] [last] - - FIRST and LAST can be numbers specifying the range, or FIRST can be - a string, which means the most recent command beginning with that - string. - - -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, - then the editor which corresponds to the current readline editing - mode, then vi. - - -l means list lines instead of editing. - -n means no line numbers listed. - -r means reverse the order of the lines (making it newest listed first). - - fc -e - [pat=rep ...] [command] - fc -s [pat=rep ...] [command] - - Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's. -*/ - -/* Data structure describing a list of global replacements to perform. */ -typedef struct repl { - struct repl *next; - char *pat; - char *rep; -} REPL; - -/* Accessors for HIST_ENTRY lists that are called HLIST. */ -#define histline(i) (hlist[(i)]->line) -#define histdata(i) (hlist[(i)]->data) - -#define FREE_RLIST() \ - do { \ - for (rl = rlist; rl; ) { \ - REPL *r; \ - r = rl->next; \ - if (rl->pat) \ - free (rl->pat); \ - if (rl->rep) \ - free (rl->rep); \ - free (rl); \ - rl = r; \ - } \ - } while (0) - -static char *fc_dosubs __P((char *, REPL *)); -static char *fc_gethist __P((char *, HIST_ENTRY **)); -static int fc_gethnum __P((char *, HIST_ENTRY **)); -static int fc_number __P((WORD_LIST *)); -static void fc_replhist __P((char *)); -#ifdef INCLUDE_UNUSED -static char *fc_readline __P((FILE *)); -static void fc_addhist __P((char *)); -#endif - -/* String to execute on a file that we want to edit. */ -#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}" -#if defined (STRICT_POSIX) -# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}" -#else -# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}" -#endif - -int -fc_builtin (list) - WORD_LIST *list; -{ - register int i; - register char *sep; - int numbering, reverse, listing, execute; - int histbeg, histend, last_hist, retval, opt, rh; - FILE *stream; - REPL *rlist, *rl; - char *ename, *command, *newcom, *fcedit; - HIST_ENTRY **hlist; - char *fn; - - numbering = 1; - reverse = listing = execute = 0; - ename = (char *)NULL; - - /* Parse out the options and set which of the two forms we're in. */ - reset_internal_getopt (); - lcurrent = list; /* XXX */ - while (fc_number (loptend = lcurrent) == 0 && - (opt = internal_getopt (list, ":e:lnrs")) != -1) - { - switch (opt) - { - case 'n': - numbering = 0; - break; - - case 'l': - listing = 1; - break; - - case 'r': - reverse = 1; - break; - - case 's': - execute = 1; - break; - - case 'e': - ename = list_optarg; - break; - - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (ename && (*ename == '-') && (ename[1] == '\0')) - execute = 1; - - /* The "execute" form of the command (re-run, with possible string - substitutions). */ - if (execute) - { - rlist = (REPL *)NULL; - while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL)) - { - *sep++ = '\0'; - rl = (REPL *)xmalloc (sizeof (REPL)); - rl->next = (REPL *)NULL; - rl->pat = savestring (list->word->word); - rl->rep = savestring (sep); - - if (rlist == NULL) - rlist = rl; - else - { - rl->next = rlist; - rlist = rl; - } - list = list->next; - } - - /* If we have a list of substitutions to do, then reverse it - to get the replacements in the proper order. */ - - rlist = REVERSE_LIST (rlist, REPL *); - - hlist = history_list (); - - /* If we still have something in list, it is a command spec. - Otherwise, we use the most recent command in time. */ - command = fc_gethist (list ? list->word->word : (char *)NULL, hlist); - - if (command == NULL) - { - builtin_error (_("no command found")); - if (rlist) - FREE_RLIST (); - - return (EXECUTION_FAILURE); - } - - if (rlist) - { - newcom = fc_dosubs (command, rlist); - free (command); - FREE_RLIST (); - command = newcom; - } - - fprintf (stderr, "%s\n", command); - fc_replhist (command); /* replace `fc -s' with command */ - /* Posix says that the re-executed commands should be entered into the - history. */ - return (parse_and_execute (command, "fc", SEVAL_NOHIST)); - } - - /* This is the second form of the command (the list-or-edit-and-rerun - form). */ - hlist = history_list (); - if (hlist == 0) - return (EXECUTION_SUCCESS); - for (i = 0; hlist[i]; i++); - - /* With the Bash implementation of history, the current command line - ("fc blah..." and so on) is already part of the history list by - the time we get to this point. This just skips over that command - and makes the last command that this deals with be the last command - the user entered before the fc. We need to check whether the - line was actually added (HISTIGNORE may have caused it to not be), - so we check hist_last_line_added. */ - - /* Even though command substitution through parse_and_execute turns off - remember_on_history, command substitution in a shell when set -o history - has been enabled (interactive or not) should use it in the last_hist - calculation as if it were on. */ - rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); - last_hist = i - rh - hist_last_line_added; - - /* XXX */ - if (i == last_hist && hlist[last_hist] == 0) - while (last_hist >= 0 && hlist[last_hist] == 0) - last_hist--; - if (last_hist < 0) - { - sh_erange ((char *)NULL, _("history specification")); - return (EXECUTION_FAILURE); - } - - if (list) - { - histbeg = fc_gethnum (list->word->word, hlist); - list = list->next; - - if (list) - histend = fc_gethnum (list->word->word, hlist); - else - histend = listing ? last_hist : histbeg; - } - else - { - /* The default for listing is the last 16 history items. */ - if (listing) - { - histend = last_hist; - histbeg = histend - 16 + 1; /* +1 because loop below uses >= */ - if (histbeg < 0) - histbeg = 0; - } - else - /* For editing, it is the last history command. */ - histbeg = histend = last_hist; - } - - /* "When not listing, the fc command that caused the editing shall not be - entered into the history list." */ - if (listing == 0 && hist_last_line_added) - { - bash_delete_last_history (); - /* If we're editing a single command -- the last command in the - history -- and we just removed the dummy command added by - edit_and_execute_command (), we need to check whether or not we - just removed the last command in the history and need to back - the pointer up. remember_on_history is off because we're running - in parse_and_execute(). */ - if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0) - last_hist = histbeg = --histend; - } - - /* We print error messages for line specifications out of range. */ - if ((histbeg < 0) || (histend < 0)) - { - sh_erange ((char *)NULL, _("history specification")); - return (EXECUTION_FAILURE); - } - - if (histend < histbeg) - { - i = histend; - histend = histbeg; - histbeg = i; - - reverse = 1; - } - - if (listing) - stream = stdout; - else - { - numbering = 0; - stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn); - if (stream == 0) - { - builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno)); - FREE (fn); - return (EXECUTION_FAILURE); - } - } - - for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++) - { - QUIT; - if (numbering) - fprintf (stream, "%d", i + history_base); - if (listing) - { - if (posixly_correct) - fputs ("\t", stream); - else - fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); - } - fprintf (stream, "%s\n", histline (i)); - } - - if (listing) - return (sh_chkwrite (EXECUTION_SUCCESS)); - - fflush (stream); - if (ferror (stream)) - { - sh_wrerror (); - fclose (stream); - return (EXECUTION_FAILURE); - } - fclose (stream); - - /* Now edit the file of commands. */ - if (ename) - { - command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2); - sprintf (command, "%s %s", ename, fn); - } - else - { - fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND; - command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn)); - sprintf (command, "%s %s", fcedit, fn); - } - retval = parse_and_execute (command, "fc", SEVAL_NOHIST); - if (retval != EXECUTION_SUCCESS) - { - unlink (fn); - free (fn); - return (EXECUTION_FAILURE); - } - - /* Make sure parse_and_execute doesn't turn this off, even though a - call to parse_and_execute farther up the function call stack (e.g., - if this is called by vi_edit_and_execute_command) may have already - called bash_history_disable. */ - remember_on_history = 1; - - /* Turn on the `v' flag while fc_execute_file runs so the commands - will be echoed as they are read by the parser. */ - begin_unwind_frame ("fc builtin"); - add_unwind_protect ((Function *)xfree, fn); - add_unwind_protect (unlink, fn); - unwind_protect_int (echo_input_at_read); - echo_input_at_read = 1; - - retval = fc_execute_file (fn); - - run_unwind_frame ("fc builtin"); - - return (retval); -} - -/* Return 1 if LIST->word->word is a legal number for fc's use. */ -static int -fc_number (list) - WORD_LIST *list; -{ - char *s; - - if (list == 0) - return 0; - s = list->word->word; - if (*s == '-') - s++; - return (legal_number (s, (intmax_t *)NULL)); -} - -/* Return an absolute index into HLIST which corresponds to COMMAND. If - COMMAND is a number, then it was specified in relative terms. If it - is a string, then it is the start of a command line present in HLIST. */ -static int -fc_gethnum (command, hlist) - char *command; - HIST_ENTRY **hlist; -{ - int sign, n, clen, rh; - register int i, j, last_hist; - register char *s; - - sign = 1; - /* Count history elements. */ - for (i = 0; hlist[i]; i++); - - /* With the Bash implementation of history, the current command line - ("fc blah..." and so on) is already part of the history list by - the time we get to this point. This just skips over that command - and makes the last command that this deals with be the last command - the user entered before the fc. We need to check whether the - line was actually added (HISTIGNORE may have caused it to not be), - so we check hist_last_line_added. This needs to agree with the - calculation of last_hist in fc_builtin above. */ - /* Even though command substitution through parse_and_execute turns off - remember_on_history, command substitution in a shell when set -o history - has been enabled (interactive or not) should use it in the last_hist - calculation as if it were on. */ - rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); - last_hist = i - rh - hist_last_line_added; - - if (i == last_hist && hlist[last_hist] == 0) - while (last_hist >= 0 && hlist[last_hist] == 0) - last_hist--; - if (last_hist < 0) - return (-1); - - i = last_hist; - - /* No specification defaults to most recent command. */ - if (command == NULL) - return (i); - - /* Otherwise, there is a specification. It can be a number relative to - the current position, or an absolute history number. */ - s = command; - - /* Handle possible leading minus sign. */ - if (s && (*s == '-')) - { - sign = -1; - s++; - } - - if (s && DIGIT(*s)) - { - n = atoi (s); - n *= sign; - - /* If the value is negative or zero, then it is an offset from - the current history item. */ - if (n < 0) - { - n += i + 1; - return (n < 0 ? 0 : n); - } - else if (n == 0) - return (i); - else - { - n -= history_base; - return (i < n ? i : n); - } - } - - clen = strlen (command); - for (j = i; j >= 0; j--) - { - if (STREQN (command, histline (j), clen)) - return (j); - } - return (-1); -} - -/* Locate the most recent history line which begins with - COMMAND in HLIST, and return a malloc()'ed copy of it. */ -static char * -fc_gethist (command, hlist) - char *command; - HIST_ENTRY **hlist; -{ - int i; - - if (hlist == 0) - return ((char *)NULL); - - i = fc_gethnum (command, hlist); - - if (i >= 0) - return (savestring (histline (i))); - else - return ((char *)NULL); -} - -#ifdef INCLUDE_UNUSED -/* Read the edited history lines from STREAM and return them - one at a time. This can read unlimited length lines. The - caller should free the storage. */ -static char * -fc_readline (stream) - FILE *stream; -{ - register int c; - int line_len = 0, lindex = 0; - char *line = (char *)NULL; - - while ((c = getc (stream)) != EOF) - { - if ((lindex + 2) >= line_len) - line = (char *)xrealloc (line, (line_len += 128)); - - if (c == '\n') - { - line[lindex++] = '\n'; - line[lindex++] = '\0'; - return (line); - } - else - line[lindex++] = c; - } - - if (!lindex) - { - if (line) - free (line); - - return ((char *)NULL); - } - - if (lindex + 2 >= line_len) - line = (char *)xrealloc (line, lindex + 3); - - line[lindex++] = '\n'; /* Finish with newline if none in file */ - line[lindex++] = '\0'; - return (line); -} -#endif - -/* Perform the SUBS on COMMAND. - SUBS is a list of substitutions, and COMMAND is a simple string. - Return a pointer to a malloc'ed string which contains the substituted - command. */ -static char * -fc_dosubs (command, subs) - char *command; - REPL *subs; -{ - register char *new, *t; - register REPL *r; - - for (new = savestring (command), r = subs; r; r = r->next) - { - t = strsub (new, r->pat, r->rep, 1); - free (new); - new = t; - } - return (new); -} - -/* Use `command' to replace the last entry in the history list, which, - by this time, is `fc blah...'. The intent is that the new command - become the history entry, and that `fc' should never appear in the - history list. This way you can do `r' to your heart's content. */ -static void -fc_replhist (command) - char *command; -{ - int n; - - if (command == 0 || *command == '\0') - return; - - n = strlen (command); - if (command[n - 1] == '\n') - command[n - 1] = '\0'; - - if (command && *command) - { - bash_delete_last_history (); - maybe_add_history (command); /* Obeys HISTCONTROL setting. */ - } -} - -#ifdef INCLUDE_UNUSED -/* Add LINE to the history, after removing a single trailing newline. */ -static void -fc_addhist (line) - char *line; -{ - register int n; - - if (line == 0 || *line == 0) - return; - - n = strlen (line); - - if (line[n - 1] == '\n') - line[n - 1] = '\0'; - - if (line && *line) - maybe_add_history (line); /* Obeys HISTCONTROL setting. */ -} -#endif - -#endif /* HISTORY */ diff --git a/builtins/pushd.def~ b/builtins/pushd.def~ deleted file mode 100644 index 05b752927..000000000 --- a/builtins/pushd.def~ +++ /dev/null @@ -1,778 +0,0 @@ -This file is pushd.def, from which is created pushd.c. It implements the -builtins "pushd", "popd", and "dirs" in Bash. - -Copyright (C) 1987-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES pushd.c - -$BUILTIN pushd -$FUNCTION pushd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC pushd [-n] [+N | -N | dir] -Add directories to stack. - -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories. - -Options: - -n Suppresses the normal change of directory when adding - directories to the stack, so only the stack is manipulated. - -Arguments: - +N Rotates the stack so that the Nth directory (counting - from the left of the list shown by `dirs', starting with - zero) is at the top. - - -N Rotates the stack so that the Nth directory (counting - from the right of the list shown by `dirs', starting with - zero) is at the top. - - dir Adds DIR to the directory stack at the top, making it the - new current working directory. - -The `dirs' builtin displays the directory stack. - -Exit Status: -Returns success unless an invalid argument is supplied or the directory -change fails. -$END - -$BUILTIN popd -$FUNCTION popd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC popd [-n] [+N | -N] -Remove directories from stack. - -Removes entries from the directory stack. With no arguments, removes -the top directory from the stack, and changes to the new top directory. - -Options: - -n Suppresses the normal change of directory when removing - directories from the stack, so only the stack is manipulated. - -Arguments: - +N Removes the Nth entry counting from the left of the list - shown by `dirs', starting with zero. For example: `popd +0' - removes the first directory, `popd +1' the second. - - -N Removes the Nth entry counting from the right of the list - shown by `dirs', starting with zero. For example: `popd -0' - removes the last directory, `popd -1' the next to last. - -The `dirs' builtin displays the directory stack. - -Exit Status: -Returns success unless an invalid argument is supplied or the directory -change fails. -$END - -$BUILTIN dirs -$FUNCTION dirs_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC dirs [-clpv] [+N] [-N] -Display directory stack. - -Display the list of currently remembered directories. Directories -find their way onto the list with the `pushd' command; you can get -back up through the list with the `popd' command. - -Options: - -c clear the directory stack by deleting all of the elements - -l do not print tilde-prefixed versions of directories relative - to your home directory - -p print the directory stack with one entry per line - -v print the directory stack with one entry per line prefixed - with its position in the stack - -Arguments: - +N Displays the Nth entry counting from the left of the list shown by - dirs when invoked without options, starting with zero. - - -N Displays the Nth entry counting from the right of the list shown by - dirs when invoked without options, starting with zero. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -#include - -#if defined (PUSHD_AND_POPD) -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include - -#include - -#include "../shell.h" -#include "maxpath.h" -#include "common.h" -#include "builtext.h" - -#ifdef LOADABLE_BUILTIN -# include "builtins.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The list of remembered directories. */ -static char **pushd_directory_list = (char **)NULL; - -/* Number of existing slots in this list. */ -static int directory_list_size; - -/* Offset to the end of the list. */ -static int directory_list_offset; - -static void pushd_error __P((int, char *)); -static void clear_directory_stack __P((void)); -static int cd_to_string __P((char *)); -static int change_to_temp __P((char *)); -static void add_dirstack_element __P((char *)); -static int get_dirstack_index __P((intmax_t, int, int *)); - -#define NOCD 0x01 -#define ROTATE 0x02 -#define LONGFORM 0x04 -#define CLEARSTAK 0x08 - -int -pushd_builtin (list) - WORD_LIST *list; -{ - WORD_LIST *orig_list; - char *temp, *current_directory, *top; - int j, flags, skipopt; - intmax_t num; - char direction; - - orig_list = list; - if (list && list->word && ISOPTION (list->word->word, '-')) - { - list = list->next; - skipopt = 1; - } - else - skipopt = 0; - - /* If there is no argument list then switch current and - top of list. */ - if (list == 0) - { - if (directory_list_offset == 0) - { - builtin_error (_("no other directory")); - return (EXECUTION_FAILURE); - } - - current_directory = get_working_directory ("pushd"); - if (current_directory == 0) - return (EXECUTION_FAILURE); - - j = directory_list_offset - 1; - temp = pushd_directory_list[j]; - pushd_directory_list[j] = current_directory; - j = change_to_temp (temp); - free (temp); - return j; - } - - for (flags = 0; skipopt == 0 && list; list = list->next) - { - if (ISOPTION (list->word->word, 'n')) - { - flags |= NOCD; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (list->word->word[0] == '-' && list->word->word[1] == '\0') - /* Let `pushd -' work like it used to. */ - break; - else if (((direction = list->word->word[0]) == '+') || direction == '-') - { - if (legal_number (list->word->word + 1, &num) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - - if (direction == '-') - num = directory_list_offset - num; - - if (num > directory_list_offset || num < 0) - { - pushd_error (directory_list_offset, list->word->word); - return (EXECUTION_FAILURE); - } - flags |= ROTATE; - } - else if (*list->word->word == '-') - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - else - break; - } - - if (flags & ROTATE) - { - /* Rotate the stack num times. Remember, the current - directory acts like it is part of the stack. */ - temp = get_working_directory ("pushd"); - - if (num == 0) - { - j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; - free (temp); - return j; - } - - do - { - top = pushd_directory_list[directory_list_offset - 1]; - - for (j = directory_list_offset - 2; j > -1; j--) - pushd_directory_list[j + 1] = pushd_directory_list[j]; - - pushd_directory_list[j + 1] = temp; - - temp = top; - num--; - } - while (num); - - j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; - free (temp); - return j; - } - - if (list == 0) - return (EXECUTION_SUCCESS); - - /* Change to the directory in list->word->word. Save the current - directory on the top of the stack. */ - current_directory = get_working_directory ("pushd"); - if (current_directory == 0) - return (EXECUTION_FAILURE); - - j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS; - if (j == EXECUTION_SUCCESS) - { - add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory); - dirs_builtin ((WORD_LIST *)NULL); - if (flags & NOCD) - free (current_directory); - return (EXECUTION_SUCCESS); - } - else - { - free (current_directory); - return (EXECUTION_FAILURE); - } -} - -/* Pop the directory stack, and then change to the new top of the stack. - If LIST is non-null it should consist of a word +N or -N, which says - what element to delete from the stack. The default is the top one. */ -int -popd_builtin (list) - WORD_LIST *list; -{ - register int i; - intmax_t which; - int flags; - char direction; - char *which_word; - - which_word = (char *)NULL; - for (flags = 0, which = 0, direction = '+'; list; list = list->next) - { - if (ISOPTION (list->word->word, 'n')) - { - flags |= NOCD; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (((direction = list->word->word[0]) == '+') || direction == '-') - { - if (legal_number (list->word->word + 1, &which) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - which_word = list->word->word; - } - else if (*list->word->word == '-') - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - else - break; - } - - if (which > directory_list_offset || (directory_list_offset == 0 && which == 0)) - { - pushd_error (directory_list_offset, which_word ? which_word : ""); - return (EXECUTION_FAILURE); - } - - /* Handle case of no specification, or top of stack specification. */ - if ((direction == '+' && which == 0) || - (direction == '-' && which == directory_list_offset)) - { - i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1]) - : EXECUTION_SUCCESS; - if (i != EXECUTION_SUCCESS) - return (i); - free (pushd_directory_list[--directory_list_offset]); - } - else - { - /* Since an offset other than the top directory was specified, - remove that directory from the list and shift the remainder - of the list into place. */ - i = (direction == '+') ? directory_list_offset - which : which; - free (pushd_directory_list[i]); - directory_list_offset--; - - /* Shift the remainder of the list into place. */ - for (; i < directory_list_offset; i++) - pushd_directory_list[i] = pushd_directory_list[i + 1]; - } - - dirs_builtin ((WORD_LIST *)NULL); - return (EXECUTION_SUCCESS); -} - -/* Print the current list of directories on the directory stack. */ -int -dirs_builtin (list) - WORD_LIST *list; -{ - int flags, desired_index, index_flag, vflag; - intmax_t i; - char *temp, *w; - - for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next) - { - if (ISOPTION (list->word->word, 'l')) - { - flags |= LONGFORM; - } - else if (ISOPTION (list->word->word, 'c')) - { - flags |= CLEARSTAK; - } - else if (ISOPTION (list->word->word, 'v')) - { - vflag |= 2; - } - else if (ISOPTION (list->word->word, 'p')) - { - vflag |= 1; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (*list->word->word == '+' || *list->word->word == '-') - { - int sign; - if (legal_number (w = list->word->word + 1, &i) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - sign = (*list->word->word == '+') ? 1 : -1; - desired_index = get_dirstack_index (i, sign, &index_flag); - } - else - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - - if (flags & CLEARSTAK) - { - clear_directory_stack (); - return (EXECUTION_SUCCESS); - } - - if (index_flag && (desired_index < 0 || desired_index > directory_list_offset)) - { - pushd_error (directory_list_offset, w); - return (EXECUTION_FAILURE); - } - -#define DIRSTACK_FORMAT(temp) \ - (flags & LONGFORM) ? temp : polite_directory_format (temp) - - /* The first directory printed is always the current working directory. */ - if (index_flag == 0 || (index_flag == 1 && desired_index == 0)) - { - temp = get_working_directory ("dirs"); - if (temp == 0) - temp = savestring (_("")); - if (vflag & 2) - printf ("%2d %s", 0, DIRSTACK_FORMAT (temp)); - else - printf ("%s", DIRSTACK_FORMAT (temp)); - free (temp); - if (index_flag) - { - putchar ('\n'); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - } - -#define DIRSTACK_ENTRY(i) \ - (flags & LONGFORM) ? pushd_directory_list[i] \ - : polite_directory_format (pushd_directory_list[i]) - - /* Now print the requested directory stack entries. */ - if (index_flag) - { - if (vflag & 2) - printf ("%2d %s", directory_list_offset - desired_index, - DIRSTACK_ENTRY (desired_index)); - else - printf ("%s", DIRSTACK_ENTRY (desired_index)); - } - else - for (i = directory_list_offset - 1; i >= 0; i--) - if (vflag >= 2) - printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i)); - else - printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i)); - - putchar ('\n'); - - return (sh_chkwrite (EXECUTION_SUCCESS)); -} - -static void -pushd_error (offset, arg) - int offset; - char *arg; -{ - if (offset == 0) - builtin_error (_("directory stack empty")); - else - sh_erange (arg, _("directory stack index")); -} - -static void -clear_directory_stack () -{ - register int i; - - for (i = 0; i < directory_list_offset; i++) - free (pushd_directory_list[i]); - directory_list_offset = 0; -} - -/* Switch to the directory in NAME. This uses the cd_builtin to do the work, - so if the result is EXECUTION_FAILURE then an error message has already - been printed. */ -static int -cd_to_string (name) - char *name; -{ - WORD_LIST *tlist; - WORD_LIST *dir; - int result; - - dir = make_word_list (make_word (name), NULL); - tlist = make_word_list (make_word ("--"), dir); - result = cd_builtin (tlist); - dispose_words (tlist); - return (result); -} - -static int -change_to_temp (temp) - char *temp; -{ - int tt; - - tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE; - - if (tt == EXECUTION_SUCCESS) - dirs_builtin ((WORD_LIST *)NULL); - - return (tt); -} - -static void -add_dirstack_element (dir) - char *dir; -{ - if (directory_list_offset == directory_list_size) - pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10); - pushd_directory_list[directory_list_offset++] = dir; -} - -static int -get_dirstack_index (ind, sign, indexp) - intmax_t ind; - int sign, *indexp; -{ - if (indexp) - *indexp = sign > 0 ? 1 : 2; - - /* dirs +0 prints the current working directory. */ - /* dirs -0 prints last element in directory stack */ - if (ind == 0 && sign > 0) - return 0; - else if (ind == directory_list_offset) - { - if (indexp) - *indexp = sign > 0 ? 2 : 1; - return 0; - } - else if (ind >= 0 && ind <= directory_list_offset) - return (sign > 0 ? directory_list_offset - ind : ind); - else - return -1; -} - -/* Used by the tilde expansion code. */ -char * -get_dirstack_from_string (string) - char *string; -{ - int ind, sign, index_flag; - intmax_t i; - - sign = 1; - if (*string == '-' || *string == '+') - { - sign = (*string == '-') ? -1 : 1; - string++; - } - if (legal_number (string, &i) == 0) - return ((char *)NULL); - - index_flag = 0; - ind = get_dirstack_index (i, sign, &index_flag); - if (index_flag && (ind < 0 || ind > directory_list_offset)) - return ((char *)NULL); - if (index_flag == 0 || (index_flag == 1 && ind == 0)) - return (get_string_value ("PWD")); - else - return (pushd_directory_list[ind]); -} - -#ifdef INCLUDE_UNUSED -char * -get_dirstack_element (ind, sign) - intmax_t ind; - int sign; -{ - int i; - - i = get_dirstack_index (ind, sign, (int *)NULL); - return (i < 0 || i > directory_list_offset) ? (char *)NULL - : pushd_directory_list[i]; -} -#endif - -void -set_dirstack_element (ind, sign, value) - intmax_t ind; - int sign; - char *value; -{ - int i; - - i = get_dirstack_index (ind, sign, (int *)NULL); - if (ind == 0 || i < 0 || i > directory_list_offset) - return; - free (pushd_directory_list[i]); - pushd_directory_list[i] = savestring (value); -} - -WORD_LIST * -get_directory_stack (flags) - int flags; -{ - register int i; - WORD_LIST *ret; - char *d, *t; - - for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++) - { - d = (flags&1) ? polite_directory_format (pushd_directory_list[i]) - : pushd_directory_list[i]; - ret = make_word_list (make_word (d), ret); - } - /* Now the current directory. */ - d = get_working_directory ("dirstack"); - i = 0; /* sentinel to decide whether or not to free d */ - if (d == 0) - d = "."; - else - { - t = polite_directory_format (d); - /* polite_directory_format sometimes returns its argument unchanged. - If it does not, we can free d right away. If it does, we need to - mark d to be deleted later. */ - if (t != d) - { - free (d); - d = t; - } - else /* t == d, so d is what we want */ - i = 1; - } - ret = make_word_list (make_word (d), ret); - if (i) - free (d); - return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */ -} - -#ifdef LOADABLE_BUILTIN -char * const dirs_doc[] = { -N_("Display the list of currently remembered directories. Directories\n\ - find their way onto the list with the `pushd' command; you can get\n\ - back up through the list with the `popd' command.\n\ - \n\ - Options:\n\ - -c clear the directory stack by deleting all of the elements\n\ - -l do not print tilde-prefixed versions of directories relative\n\ - to your home directory\n\ - -p print the directory stack with one entry per line\n\ - -v print the directory stack with one entry per line prefixed\n\ - with its position in the stack\n\ - \n\ - Arguments:\n\ - +N Displays the Nth entry counting from the left of the list shown by\n\ - dirs when invoked without options, starting with zero.\n\ - \n\ - -N Displays the Nth entry counting from the right of the list shown by\n\ - dirs when invoked without options, starting with zero."), - (char *)NULL -}; - -char * const pushd_doc[] = { -N_("Adds a directory to the top of the directory stack, or rotates\n\ - the stack, making the new top of the stack the current working\n\ - directory. With no arguments, exchanges the top two directories.\n\ - \n\ - Options:\n\ - -n Suppresses the normal change of directory when adding\n\ - directories to the stack, so only the stack is manipulated.\n\ - \n\ - Arguments:\n\ - +N Rotates the stack so that the Nth directory (counting\n\ - from the left of the list shown by `dirs', starting with\n\ - zero) is at the top.\n\ - \n\ - -N Rotates the stack so that the Nth directory (counting\n\ - from the right of the list shown by `dirs', starting with\n\ - zero) is at the top.\n\ - \n\ - dir Adds DIR to the directory stack at the top, making it the\n\ - new current working directory.\n\ - \n\ - The `dirs' builtin displays the directory stack."), - (char *)NULL -}; - -char * const popd_doc[] = { -N_("Removes entries from the directory stack. With no arguments, removes\n\ - the top directory from the stack, and changes to the new top directory.\n\ - \n\ - Options:\n\ - -n Suppresses the normal change of directory when removing\n\ - directories from the stack, so only the stack is manipulated.\n\ - \n\ - Arguments:\n\ - +N Removes the Nth entry counting from the left of the list\n\ - shown by `dirs', starting with zero. For example: `popd +0'\n\ - removes the first directory, `popd +1' the second.\n\ - \n\ - -N Removes the Nth entry counting from the right of the list\n\ - shown by `dirs', starting with zero. For example: `popd -0'\n\ - removes the last directory, `popd -1' the next to last.\n\ - \n\ - The `dirs' builtin displays the directory stack."), - (char *)NULL -}; - -struct builtin pushd_struct = { - "pushd", - pushd_builtin, - BUILTIN_ENABLED, - pushd_doc, - "pushd [+N | -N] [-n] [dir]", - 0 -}; - -struct builtin popd_struct = { - "popd", - popd_builtin, - BUILTIN_ENABLED, - popd_doc, - "popd [+N | -N] [-n]", - 0 -}; - -struct builtin dirs_struct = { - "dirs", - dirs_builtin, - BUILTIN_ENABLED, - dirs_doc, - "dirs [-clpv] [+N] [-N]", - 0 -}; -#endif /* LOADABLE_BUILTIN */ - -#endif /* PUSHD_AND_POPD */ diff --git a/builtins/ulimit.def~ b/builtins/ulimit.def~ deleted file mode 100644 index ffdbdd480..000000000 --- a/builtins/ulimit.def~ +++ /dev/null @@ -1,779 +0,0 @@ -This file is ulimit.def, from which is created ulimit.c. -It implements the builtin "ulimit" in Bash. - -Copyright (C) 1987-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 . - -$PRODUCES ulimit.c - -$BUILTIN ulimit -$FUNCTION ulimit_builtin -$DEPENDS_ON !_MINIX -$SHORT_DOC ulimit [-SHabcdefilmnpqrstuvxT] [limit] -Modify shell resource limits. - -Provides control over the resources available to the shell and processes -it creates, on systems that allow such control. - -Options: - -S use the `soft' resource limit - -H use the `hard' resource limit - -a all current limits are reported - -b the socket buffer size - -c the maximum size of core files created - -d the maximum size of a process's data segment - -e the maximum scheduling priority (`nice') - -f the maximum size of files written by the shell and its children - -i the maximum number of pending signals - -l the maximum size a process may lock into memory - -m the maximum resident set size - -n the maximum number of open file descriptors - -p the pipe buffer size - -q the maximum number of bytes in POSIX message queues - -r the maximum real-time scheduling priority - -s the maximum stack size - -t the maximum amount of cpu time in seconds - -u the maximum number of user processes - -v the size of virtual memory - -x the maximum number of file locks - -T the maximum number of threads - -Not all options are available on all platforms. - -If LIMIT is given, it is the new value of the specified resource; the -special LIMIT values `soft', `hard', and `unlimited' stand for the -current soft limit, the current hard limit, and no limit, respectively. -Otherwise, the current value of the specified resource is printed. If -no option is given, then -f is assumed. - -Values are in 1024-byte increments, except for -t, which is in seconds, --p, which is in increments of 512 bytes, and -u, which is an unscaled -number of processes. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -#if !defined (_MINIX) - -#include - -#include "../bashtypes.h" -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" -#include "pipesize.h" - -#if !defined (errno) -extern int errno; -#endif - -/* For some reason, HPUX chose to make these definitions visible only if - _KERNEL is defined, so we define _KERNEL before including - and #undef it afterward. */ -#if defined (HAVE_RESOURCE) -# include -# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) -# define _KERNEL -# endif -# include -# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) -# undef _KERNEL -# endif -#elif defined (HAVE_SYS_TIMES_H) -# include -#endif - -#if defined (HAVE_LIMITS_H) -# include -#endif - -/* Check for the most basic symbols. If they aren't present, this - system's isn't very useful to us. */ -#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT) -# undef HAVE_RESOURCE -#endif - -#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H) -# include -#endif - -#if !defined (RLIMTYPE) -# define RLIMTYPE long -# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10) -# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") -#endif - -/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */ -#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) -# define RLIMIT_NOFILE RLIMIT_OFILE -#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */ - -/* Some systems have these, some do not. */ -#ifdef RLIMIT_FSIZE -# define RLIMIT_FILESIZE RLIMIT_FSIZE -#else -# define RLIMIT_FILESIZE 256 -#endif - -#define RLIMIT_PIPESIZE 257 - -#ifdef RLIMIT_NOFILE -# define RLIMIT_OPENFILES RLIMIT_NOFILE -#else -# define RLIMIT_OPENFILES 258 -#endif - -#ifdef RLIMIT_VMEM -# define RLIMIT_VIRTMEM RLIMIT_VMEM -# define RLIMIT_VMBLKSZ 1024 -#else -# ifdef RLIMIT_AS -# define RLIMIT_VIRTMEM RLIMIT_AS -# define RLIMIT_VMBLKSZ 1024 -# else -# define RLIMIT_VIRTMEM 259 -# define RLIMIT_VMBLKSZ 1 -# endif -#endif - -#ifdef RLIMIT_NPROC -# define RLIMIT_MAXUPROC RLIMIT_NPROC -#else -# define RLIMIT_MAXUPROC 260 -#endif - -#if !defined (RLIM_INFINITY) -# define RLIM_INFINITY 0x7fffffff -#endif - -#if !defined (RLIM_SAVED_CUR) -# define RLIM_SAVED_CUR RLIM_INFINITY -#endif - -#if !defined (RLIM_SAVED_MAX) -# define RLIM_SAVED_MAX RLIM_INFINITY -#endif - -#define LIMIT_HARD 0x01 -#define LIMIT_SOFT 0x02 - -/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes - otherwise. */ -#define POSIXBLK -2 - -#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x)) - -extern int posixly_correct; - -static int _findlim __P((int)); - -static int ulimit_internal __P((int, char *, int, int)); - -static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *)); -static int set_limit __P((int, RLIMTYPE, int)); - -static void printone __P((int, RLIMTYPE, int)); -static void print_all_limits __P((int)); - -static int set_all_limits __P((int, RLIMTYPE)); - -static int filesize __P((RLIMTYPE *)); -static int pipesize __P((RLIMTYPE *)); -static int getmaxuprc __P((RLIMTYPE *)); -static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *)); - -typedef struct { - int option; /* The ulimit option for this limit. */ - int parameter; /* Parameter to pass to get_limit (). */ - int block_factor; /* Blocking factor for specific limit. */ - const char * const description; /* Descriptive string to output. */ - const char * const units; /* scale */ -} RESOURCE_LIMITS; - -static RESOURCE_LIMITS limits[] = { -#ifdef RLIMIT_PTHREAD - { 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL }, -#endif -#ifdef RLIMIT_SBSIZE - { 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" }, -#endif -#ifdef RLIMIT_CORE - { 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" }, -#endif -#ifdef RLIMIT_DATA - { 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" }, -#endif -#ifdef RLIMIT_NICE - { 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL }, -#endif - { 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" }, -#ifdef RLIMIT_SIGPENDING - { 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL }, -#endif -#ifdef RLIMIT_MEMLOCK - { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" }, -#endif -#ifdef RLIMIT_RSS - { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" }, -#endif /* RLIMIT_RSS */ - { 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL}, - { 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" }, -#ifdef RLIMIT_MSGQUEUE - { 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" }, -#endif -#ifdef RLIMIT_RTPRIO - { 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL }, -#endif -#ifdef RLIMIT_STACK - { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" }, -#endif -#ifdef RLIMIT_CPU - { 't', RLIMIT_CPU, 1, "cpu time", "seconds" }, -#endif /* RLIMIT_CPU */ - { 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL }, -#if defined (HAVE_RESOURCE) - { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" }, -#endif -#ifdef RLIMIT_SWAP - { 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" }, -#endif -#ifdef RLIMIT_LOCKS - { 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL }, -#endif - { -1, -1, -1, (char *)NULL, (char *)NULL } -}; -#define NCMDS (sizeof(limits) / sizeof(limits[0])) - -typedef struct _cmd { - int cmd; - char *arg; -} ULCMD; - -static ULCMD *cmdlist; -static int ncmd; -static int cmdlistsz; - -#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT) -long -ulimit (cmd, newlim) - int cmd; - long newlim; -{ - errno = EINVAL; - return -1; -} -#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */ - -static int -_findlim (opt) - int opt; -{ - register int i; - - for (i = 0; limits[i].option > 0; i++) - if (limits[i].option == opt) - return i; - return -1; -} - -static char optstring[4 + 2 * NCMDS]; - -/* Report or set limits associated with certain per-process resources. - See the help documentation in builtins.c for a full description. */ -int -ulimit_builtin (list) - register WORD_LIST *list; -{ - register char *s; - int c, limind, mode, opt, all_limits; - - mode = 0; - - all_limits = 0; - - /* Idea stolen from pdksh -- build option string the first time called. */ - if (optstring[0] == 0) - { - s = optstring; - *s++ = 'a'; *s++ = 'S'; *s++ = 'H'; - for (c = 0; limits[c].option > 0; c++) - { - *s++ = limits[c].option; - *s++ = ';'; - } - *s = '\0'; - } - - /* Initialize the command list. */ - if (cmdlistsz == 0) - cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD)); - ncmd = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, optstring)) != -1) - { - switch (opt) - { - case 'a': - all_limits++; - break; - - /* -S and -H are modifiers, not real options. */ - case 'S': - mode |= LIMIT_SOFT; - break; - - case 'H': - mode |= LIMIT_HARD; - break; - - case '?': - builtin_usage (); - return (EX_USAGE); - - default: - if (ncmd >= cmdlistsz) - cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD)); - cmdlist[ncmd].cmd = opt; - cmdlist[ncmd++].arg = list_optarg; - break; - } - } - list = loptend; - - if (all_limits) - { -#ifdef NOTYET - if (list) /* setting */ - { - if (STREQ (list->word->word, "unlimited") == 0) - { - builtin_error (_("%s: invalid limit argument"), list->word->word); - return (EXECUTION_FAILURE); - } - return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY)); - } -#endif - print_all_limits (mode == 0 ? LIMIT_SOFT : mode); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - /* default is `ulimit -f' */ - if (ncmd == 0) - { - cmdlist[ncmd].cmd = 'f'; - /* `ulimit something' is same as `ulimit -f something' */ - cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL; - if (list) - list = list->next; - } - - /* verify each command in the list. */ - for (c = 0; c < ncmd; c++) - { - limind = _findlim (cmdlist[c].cmd); - if (limind == -1) - { - builtin_error (_("`%c': bad command"), cmdlist[c].cmd); - return (EX_USAGE); - } - } - - for (c = 0; c < ncmd; c++) - if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE) - return (EXECUTION_FAILURE); - - return (EXECUTION_SUCCESS); -} - -static int -ulimit_internal (cmd, cmdarg, mode, multiple) - int cmd; - char *cmdarg; - int mode, multiple; -{ - int opt, limind, setting; - int block_factor; - RLIMTYPE soft_limit, hard_limit, real_limit, limit; - - setting = cmdarg != 0; - limind = _findlim (cmd); - if (mode == 0) - mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT; - opt = get_limit (limind, &soft_limit, &hard_limit); - if (opt < 0) - { - builtin_error (_("%s: cannot get limit: %s"), limits[limind].description, - strerror (errno)); - return (EXECUTION_FAILURE); - } - - if (setting == 0) /* print the value of the specified limit */ - { - printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple); - return (EXECUTION_SUCCESS); - } - - /* Setting the limit. */ - if (STREQ (cmdarg, "hard")) - real_limit = hard_limit; - else if (STREQ (cmdarg, "soft")) - real_limit = soft_limit; - else if (STREQ (cmdarg, "unlimited")) - real_limit = RLIM_INFINITY; - else if (all_digits (cmdarg)) - { - limit = string_to_rlimtype (cmdarg); - block_factor = BLOCKSIZE(limits[limind].block_factor); - real_limit = limit * block_factor; - - if ((real_limit / block_factor) != limit) - { - sh_erange (cmdarg, _("limit")); - return (EXECUTION_FAILURE); - } - } - else - { - sh_invalidnum (cmdarg); - return (EXECUTION_FAILURE); - } - - if (set_limit (limind, real_limit, mode) < 0) - { - builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description, - strerror (errno)); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -} - -static int -get_limit (ind, softlim, hardlim) - int ind; - RLIMTYPE *softlim, *hardlim; -{ - RLIMTYPE value; -#if defined (HAVE_RESOURCE) - struct rlimit limit; -#endif - - if (limits[ind].parameter >= 256) - { - switch (limits[ind].parameter) - { - case RLIMIT_FILESIZE: - if (filesize (&value) < 0) - return -1; - break; - case RLIMIT_PIPESIZE: - if (pipesize (&value) < 0) - return -1; - break; - case RLIMIT_OPENFILES: - value = (RLIMTYPE)getdtablesize (); - break; - case RLIMIT_VIRTMEM: - return (getmaxvm (softlim, hardlim)); - case RLIMIT_MAXUPROC: - if (getmaxuprc (&value) < 0) - return -1; - break; - default: - errno = EINVAL; - return -1; - } - *softlim = *hardlim = value; - return (0); - } - else - { -#if defined (HAVE_RESOURCE) - if (getrlimit (limits[ind].parameter, &limit) < 0) - return -1; - *softlim = limit.rlim_cur; - *hardlim = limit.rlim_max; -# if defined (HPUX9) - if (limits[ind].parameter == RLIMIT_FILESIZE) - { - *softlim *= 512; - *hardlim *= 512; /* Ugh. */ - } - else -# endif /* HPUX9 */ - return 0; -#else - errno = EINVAL; - return -1; -#endif - } -} - -static int -set_limit (ind, newlim, mode) - int ind; - RLIMTYPE newlim; - int mode; -{ -#if defined (HAVE_RESOURCE) - struct rlimit limit; - RLIMTYPE val; -#endif - - if (limits[ind].parameter >= 256) - switch (limits[ind].parameter) - { - case RLIMIT_FILESIZE: -#if !defined (HAVE_RESOURCE) - return (ulimit (2, newlim / 512L)); -#else - errno = EINVAL; - return -1; -#endif - - case RLIMIT_OPENFILES: -#if defined (HAVE_SETDTABLESIZE) -# if defined (__CYGWIN__) - /* Grrr... Cygwin declares setdtablesize as void. */ - setdtablesize (newlim); - return 0; -# else - return (setdtablesize (newlim)); -# endif -#endif - case RLIMIT_PIPESIZE: - case RLIMIT_VIRTMEM: - case RLIMIT_MAXUPROC: - default: - errno = EINVAL; - return -1; - } - else - { -#if defined (HAVE_RESOURCE) - if (getrlimit (limits[ind].parameter, &limit) < 0) - return -1; -# if defined (HPUX9) - if (limits[ind].parameter == RLIMIT_FILESIZE) - newlim /= 512; /* Ugh. */ -# endif /* HPUX9 */ - val = (current_user.euid != 0 && newlim == RLIM_INFINITY && - (mode & LIMIT_HARD) == 0 && /* XXX -- test */ - (limit.rlim_cur <= limit.rlim_max)) - ? limit.rlim_max : newlim; - if (mode & LIMIT_SOFT) - limit.rlim_cur = val; - if (mode & LIMIT_HARD) - limit.rlim_max = val; - - return (setrlimit (limits[ind].parameter, &limit)); -#else - errno = EINVAL; - return -1; -#endif - } -} - -static int -getmaxvm (softlim, hardlim) - RLIMTYPE *softlim, *hardlim; -{ -#if defined (HAVE_RESOURCE) - struct rlimit datalim, stacklim; - - if (getrlimit (RLIMIT_DATA, &datalim) < 0) - return -1; - - if (getrlimit (RLIMIT_STACK, &stacklim) < 0) - return -1; - - /* Protect against overflow. */ - *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L); - *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L); - return 0; -#else - errno = EINVAL; - return -1; -#endif /* HAVE_RESOURCE */ -} - -static int -filesize(valuep) - RLIMTYPE *valuep; -{ -#if !defined (HAVE_RESOURCE) - long result; - if ((result = ulimit (1, 0L)) < 0) - return -1; - else - *valuep = (RLIMTYPE) result * 512; - return 0; -#else - errno = EINVAL; - return -1; -#endif -} - -static int -pipesize (valuep) - RLIMTYPE *valuep; -{ -#if defined (PIPE_BUF) - /* This is defined on Posix systems. */ - *valuep = (RLIMTYPE) PIPE_BUF; - return 0; -#else -# if defined (_POSIX_PIPE_BUF) - *valuep = (RLIMTYPE) _POSIX_PIPE_BUF; - return 0; -# else -# if defined (PIPESIZE) - /* This is defined by running a program from the Makefile. */ - *valuep = (RLIMTYPE) PIPESIZE; - return 0; -# else - errno = EINVAL; - return -1; -# endif /* PIPESIZE */ -# endif /* _POSIX_PIPE_BUF */ -#endif /* PIPE_BUF */ -} - -static int -getmaxuprc (valuep) - RLIMTYPE *valuep; -{ - long maxchild; - - maxchild = getmaxchild (); - if (maxchild < 0) - { - errno = EINVAL; - return -1; - } - else - { - *valuep = (RLIMTYPE) maxchild; - return 0; - } -} - -static void -print_all_limits (mode) - int mode; -{ - register int i; - RLIMTYPE softlim, hardlim; - - if (mode == 0) - mode |= LIMIT_SOFT; - - for (i = 0; limits[i].option > 0; i++) - { - if (get_limit (i, &softlim, &hardlim) == 0) - printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1); - else if (errno != EINVAL) - builtin_error ("%s: cannot get limit: %s", limits[i].description, - strerror (errno)); - } -} - -static void -printone (limind, curlim, pdesc) - int limind; - RLIMTYPE curlim; - int pdesc; -{ - char unitstr[64]; - int factor; - - factor = BLOCKSIZE(limits[limind].block_factor); - if (pdesc) - { - if (limits[limind].units) - sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option); - else - sprintf (unitstr, "(-%c) ", limits[limind].option); - - printf ("%-20s %16s", limits[limind].description, unitstr); - } - if (curlim == RLIM_INFINITY) - puts ("unlimited"); - else if (curlim == RLIM_SAVED_MAX) - puts ("hard"); - else if (curlim == RLIM_SAVED_CUR) - puts ("soft"); - else - print_rlimtype ((curlim / factor), 1); -} - -/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which - causes all limits to be set as high as possible depending on mode (like - csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits - were set successfully, and 1 if at least one limit could not be set. - - To raise all soft limits to their corresponding hard limits, use - ulimit -S -a unlimited - To attempt to raise all hard limits to infinity (superuser-only), use - ulimit -H -a unlimited - To attempt to raise all soft and hard limits to infinity, use - ulimit -a unlimited -*/ - -static int -set_all_limits (mode, newlim) - int mode; - RLIMTYPE newlim; -{ - register int i; - int retval = 0; - - if (newlim != RLIM_INFINITY) - { - errno = EINVAL; - return -1; - } - - if (mode == 0) - mode = LIMIT_SOFT|LIMIT_HARD; - - for (retval = i = 0; limits[i].option > 0; i++) - if (set_limit (i, newlim, mode) < 0) - { - builtin_error (_("%s: cannot modify limit: %s"), limits[i].description, - strerror (errno)); - retval = 1; - } - return retval; -} - -#endif /* !_MINIX */ diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old deleted file mode 100644 index 640390fbf..000000000 --- a/cross-build/cygwin32.cache.old +++ /dev/null @@ -1,42 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests for CYGWIN32 so they don't need to be done when cross-compiling. - -# AC_FUNC_GETPGRP should also define GETPGRP_VOID -ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} -# AC_FUNC_SETVBUF_REVERSED should not define anything else -ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} -# on CYGWIN32, system calls do not restart -ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} -bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} - -# these may be necessary, but they are currently commented out -#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} -ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} -ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} -ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} -ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} - -bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} -bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} -bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} -bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} -bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} -bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} -bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} -bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} -bash_cv_printf_declared=${bash_cv_printf_declared='yes'} -bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} -bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} -bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} -bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} -bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} -bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} -bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} -bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} - -bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} -bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} - -ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} - -# end of cross-build/cygwin32.cache diff --git a/ddd1~ b/ddd1~ deleted file mode 100644 index b7319b7fb..000000000 --- a/ddd1~ +++ /dev/null @@ -1,979 +0,0 @@ -*** ../bash-4.2-patched/execute_cmd.c 2012-05-02 12:02:27.000000000 -0400 ---- execute_cmd.c 2012-07-28 18:14:33.000000000 -0400 -*************** -*** 1,5 **** - /* execute_cmd.c -- Execute a COMMAND structure. */ - -! /* Copyright (C) 1987-2010 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. ---- 1,5 ---- - /* execute_cmd.c -- Execute a COMMAND structure. */ - -! /* Copyright (C) 1987-2012 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. -*************** -*** 119,122 **** ---- 119,124 ---- - #endif - -+ extern int job_control; /* XXX */ -+ - extern int close __P((int)); - -*************** -*** 196,200 **** - static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -! static int execute_intern_function __P((WORD_DESC *, COMMAND *)); - - /* Set to 1 if fd 0 was the subject of redirection to a subshell. Global ---- 198,202 ---- - static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -! static int execute_intern_function __P((WORD_DESC *, FUNCTION_DEF *)); - - /* Set to 1 if fd 0 was the subject of redirection to a subshell. Global -*************** -*** 273,277 **** - static int showing_function_line; - -! static int line_number_for_err_trap; - - /* A sort of function nesting level counter */ ---- 275,281 ---- - static int showing_function_line; - -! /* $LINENO ($BASH_LINENO) for use by an ERR trap. Global so parse_and_execute -! can save and restore it. */ -! int line_number_for_err_trap; - - /* A sort of function nesting level counter */ -*************** -*** 531,534 **** ---- 535,542 ---- - volatile int last_pid; - volatile int save_line_number; -+ #if defined (PROCESS_SUBSTITUTION) -+ volatile int ofifo, nfifo, osize, saved_fifo; -+ volatile char *ofifo_list; -+ #endif - - #if 0 -*************** -*** 593,597 **** - - #if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) -! unlink_fifo_list (); - #endif - /* If we are part of a pipeline, and not the end of the pipeline, ---- 601,606 ---- - - #if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) -! if (variable_context == 0) /* wait until shell function completes */ -! unlink_fifo_list (); - #endif - /* If we are part of a pipeline, and not the end of the pipeline, -*************** -*** 670,673 **** ---- 679,693 ---- - stdin_redir = stdin_redirects (command->redirects); - -+ #if defined (PROCESS_SUBSTITUTION) -+ if (variable_context != 0) -+ { -+ ofifo = num_fifos (); -+ ofifo_list = copy_fifo_list (&osize); -+ saved_fifo = 1; -+ } -+ else -+ saved_fifo = 0; -+ #endif -+ - /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input - redirection.) */ -*************** -*** 677,680 **** ---- 697,704 ---- - redirection_undo_list = (REDIRECT *)NULL; - dispose_exec_redirects (); -+ #if defined (PROCESS_SUBSTITUTION) -+ if (saved_fifo) -+ free (ofifo_list); -+ #endif - return (last_command_exit_value = EXECUTION_FAILURE); - } -*************** -*** 752,758 **** - - /* XXX - this is something to watch out for if there are problems -! when the shell is compiled without job control. */ -! if (already_making_children && pipe_out == NO_PIPE && -! last_made_pid != last_pid) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); ---- 776,784 ---- - - /* XXX - this is something to watch out for if there are problems -! when the shell is compiled without job control. Don't worry about -! whether or not last_made_pid == last_pid; already_making_children -! tells us whether or not there are unwaited-for children to wait -! for and reap. */ -! if (already_making_children && pipe_out == NO_PIPE) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); -*************** -*** 952,956 **** - case cm_function_def: - exec_result = execute_intern_function (command->value.Function_def->name, -! command->value.Function_def->command); - break; - ---- 978,982 ---- - case cm_function_def: - exec_result = execute_intern_function (command->value.Function_def->name, -! command->value.Function_def); - break; - -*************** -*** 971,974 **** ---- 997,1010 ---- - discard_unwind_frame ("loop_redirections"); - -+ #if defined (PROCESS_SUBSTITUTION) -+ if (saved_fifo) -+ { -+ nfifo = num_fifos (); -+ if (nfifo > ofifo) -+ close_new_fifos (ofifo_list, osize); -+ free (ofifo_list); -+ } -+ #endif -+ - /* Invert the return value if we have to */ - if (invert) -*************** -*** 1001,1004 **** ---- 1037,1041 ---- - #endif - currently_executing_command = (COMMAND *)NULL; -+ - return (last_command_exit_value); - } -*************** -*** 1223,1227 **** - #endif - -! posix_time = (command->flags & CMD_TIME_POSIX); - - nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); ---- 1260,1264 ---- - #endif - -! posix_time = command && (command->flags & CMD_TIME_POSIX); - - nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); -*************** -*** 1505,1509 **** - return_code = return_catch_value; - else -! return_code = execute_command_internal (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); - - /* If we are asked to, invert the return value. */ ---- 1542,1546 ---- - return_code = return_catch_value; - else -! return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); - - /* If we are asked to, invert the return value. */ -*************** -*** 1549,1556 **** - static void cpl_reap __P((void)); - static void cpl_flush __P((void)); - static struct cpelement *cpl_search __P((pid_t)); -! static struct cpelement *cpl_searchbyname __P((char *)); - static void cpl_prune __P((void)); - - Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 }; - ---- 1586,1597 ---- - static void cpl_reap __P((void)); - static void cpl_flush __P((void)); -+ static void cpl_closeall __P((void)); - static struct cpelement *cpl_search __P((pid_t)); -! static struct cpelement *cpl_searchbyname __P((const char *)); - static void cpl_prune __P((void)); - -+ static void coproc_free __P((struct coproc *)); -+ -+ /* Will go away when there is fully-implemented support for multiple coprocs. */ - Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 }; - -*************** -*** 1639,1668 **** - cpl_reap () - { -! struct cpelement *prev, *p; - -! for (prev = p = coproc_list.head; p; prev = p, p = p->next) -! if (p->coproc->c_flags & COPROC_DEAD) -! { -! prev->next = p->next; /* remove from list */ -! -! /* Housekeeping in the border cases. */ -! if (p == coproc_list.head) -! coproc_list.head = coproc_list.head->next; -! else if (p == coproc_list.tail) -! coproc_list.tail = prev; -! -! coproc_list.ncoproc--; -! if (coproc_list.ncoproc == 0) -! coproc_list.head = coproc_list.tail = 0; -! else if (coproc_list.ncoproc == 1) -! coproc_list.tail = coproc_list.head; /* just to make sure */ - - #if defined (DEBUG) -! itrace("cpl_reap: deleting %d", p->coproc->c_pid); - #endif - -! coproc_dispose (p->coproc); -! cpe_dispose (p); -! } - } - ---- 1680,1722 ---- - cpl_reap () - { -! struct cpelement *p, *next, *nh, *nt; - -! /* Build a new list by removing dead coprocs and fix up the coproc_list -! pointers when done. */ -! nh = nt = next = (struct cpelement *)0; -! for (p = coproc_list.head; p; p = next) -! { -! next = p->next; -! if (p->coproc->c_flags & COPROC_DEAD) -! { -! coproc_list.ncoproc--; /* keep running count, fix up pointers later */ - - #if defined (DEBUG) -! itrace("cpl_reap: deleting %d", p->coproc->c_pid); - #endif - -! coproc_dispose (p->coproc); -! cpe_dispose (p); -! } -! else if (nh == 0) -! nh = nt = p; -! else -! { -! nt->next = p; -! nt = nt->next; -! } -! } -! -! if (coproc_list.ncoproc == 0) -! coproc_list.head = coproc_list.tail = 0; -! else -! { -! if (nt) -! nt->next = 0; -! coproc_list.head = nh; -! coproc_list.tail = nt; -! if (coproc_list.ncoproc == 1) -! coproc_list.tail = coproc_list.head; /* just to make sure */ -! } - } - -*************** -*** 1686,1689 **** ---- 1740,1762 ---- - } - -+ static void -+ cpl_closeall () -+ { -+ struct cpelement *cpe; -+ -+ for (cpe = coproc_list.head; cpe; cpe = cpe->next) -+ coproc_close (cpe->coproc); -+ } -+ -+ static void -+ cpl_fdchk (fd) -+ int fd; -+ { -+ struct cpelement *cpe; -+ -+ for (cpe = coproc_list.head; cpe; cpe = cpe->next) -+ coproc_checkfd (cpe->coproc, fd); -+ } -+ - /* Search for PID in the list of coprocs; return the cpelement struct if - found. If not found, return NULL. */ -*************** -*** 1692,1700 **** - pid_t pid; - { -! struct cpelement *cp; - -! for (cp = coproc_list.head ; cp; cp = cp->next) -! if (cp->coproc->c_pid == pid) -! return cp; - return (struct cpelement *)NULL; - } ---- 1765,1773 ---- - pid_t pid; - { -! struct cpelement *cpe; - -! for (cpe = coproc_list.head ; cpe; cpe = cpe->next) -! if (cpe->coproc->c_pid == pid) -! return cpe; - return (struct cpelement *)NULL; - } -*************** -*** 1704,1708 **** - static struct cpelement * - cpl_searchbyname (name) -! char *name; - { - struct cpelement *cp; ---- 1777,1781 ---- - static struct cpelement * - cpl_searchbyname (name) -! const char *name; - { - struct cpelement *cp; -*************** -*** 1739,1743 **** ---- 1812,1823 ---- - pid_t pid; - { -+ #if MULTIPLE_COPROCS -+ struct cpelement *p; -+ -+ p = cpl_search (pid); -+ return (p ? p->coproc : 0); -+ #else - return (pid == sh_coproc.c_pid ? &sh_coproc : 0); -+ #endif - } - -*************** -*** 1746,1750 **** ---- 1826,1837 ---- - const char *name; - { -+ #if MULTIPLE_COPROCS -+ struct cpelement *p; -+ -+ p = cpl_searchbyname (name); -+ return (p ? p->coproc : 0); -+ #else - return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); -+ #endif - } - -*************** -*** 1767,1771 **** - struct coproc *cp; - -! cp = &sh_coproc; /* XXX */ - coproc_init (cp); - ---- 1854,1862 ---- - struct coproc *cp; - -! #if MULTIPLE_COPROCS -! cp = (struct coproc *)xmalloc (sizeof (struct coproc)); -! #else -! cp = &sh_coproc; -! #endif - coproc_init (cp); - -*************** -*** 1773,1779 **** ---- 1864,1881 ---- - cp->c_pid = pid; - -+ #if MULTIPLE_COPROCS -+ cpl_add (cp); -+ #endif -+ - return (cp); - } - -+ static void -+ coproc_free (cp) -+ struct coproc *cp; -+ { -+ free (cp); -+ } -+ - void - coproc_dispose (cp) -*************** -*** 1786,1797 **** - FREE (cp->c_name); - coproc_close (cp); - coproc_init (cp); - } - -! /* Placeholder for now. */ - void - coproc_flush () - { - coproc_dispose (&sh_coproc); - } - ---- 1888,1907 ---- - FREE (cp->c_name); - coproc_close (cp); -+ #if MULTIPLE_COPROCS -+ coproc_free (cp); -+ #else - coproc_init (cp); -+ #endif - } - -! /* Placeholder for now. Will require changes for multiple coprocs */ - void - coproc_flush () - { -+ #if MULTIPLE_COPROCS -+ cpl_flush (); -+ #else - coproc_dispose (&sh_coproc); -+ #endif - } - -*************** -*** 1816,1820 **** - coproc_closeall () - { -! coproc_close (&sh_coproc); - } - ---- 1926,1934 ---- - coproc_closeall () - { -! #if MULTIPLE_COPROCS -! cpl_closeall (); -! #else -! coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */ -! #endif - } - -*************** -*** 1822,1830 **** - coproc_reap () - { - struct coproc *cp; - -! cp = &sh_coproc; - if (cp && (cp->c_flags & COPROC_DEAD)) - coproc_dispose (cp); - } - ---- 1936,1948 ---- - coproc_reap () - { -+ #if MULTIPLE_COPROCS -+ cpl_reap (); -+ #else - struct coproc *cp; - -! cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */ - if (cp && (cp->c_flags & COPROC_DEAD)) - coproc_dispose (cp); -+ #endif - } - -*************** -*** 1873,1877 **** ---- 1991,1999 ---- - int fd; - { -+ #if MULTIPLE_COPROCS -+ cpl_fdchk (fd); -+ #else - coproc_checkfd (&sh_coproc, fd); -+ #endif - } - -*************** -*** 1908,1923 **** - struct coproc *cp; - - cp = getcoprocbypid (pid); -- #if 0 -- if (cp) -- itrace("coproc_pidchk: pid %d has died", pid); - #endif - if (cp) - { - cp->c_status = status; - cp->c_flags |= COPROC_DEAD; - cp->c_flags &= ~COPROC_RUNNING; -! #if 0 - coproc_dispose (cp); - #endif - } ---- 2030,2053 ---- - struct coproc *cp; - -+ #if MULTIPLE_COPROCS -+ struct cpelement *cpe; -+ -+ cpe = cpl_delete (pid); -+ cp = cpe ? cpe->coproc : 0; -+ #else - cp = getcoprocbypid (pid); - #endif - if (cp) - { -+ #if 0 -+ itrace("coproc_pidchk: pid %d has died", pid); -+ #endif - cp->c_status = status; - cp->c_flags |= COPROC_DEAD; - cp->c_flags &= ~COPROC_RUNNING; -! #if MULTIPLE_COPROCS - coproc_dispose (cp); -+ #else -+ coproc_unsetvars (cp); - #endif - } -*************** -*** 2015,2029 **** - char *tcmd; - -! /* XXX -- will require changes to handle multiple coprocs */ - if (sh_coproc.c_pid != NO_PID) -! { -! #if 0 -! internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name); -! return (last_command_exit_value = EXECUTION_FAILURE); -! #else -! internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name); -! #endif -! } - coproc_init (&sh_coproc); - - command_string_index = 0; ---- 2145,2154 ---- - char *tcmd; - -! /* XXX -- can be removed after changes to handle multiple coprocs */ -! #if !MULTIPLE_COPROCS - if (sh_coproc.c_pid != NO_PID) -! internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name); - coproc_init (&sh_coproc); -+ #endif - - command_string_index = 0; -*************** -*** 2197,2202 **** - cmd->flags |= CMD_IGNORE_RETURN; - -- #if defined (JOB_CONTROL) - lastpipe_flag = 0; - begin_unwind_frame ("lastpipe-exec"); - lstdin = -1; ---- 2322,2327 ---- - cmd->flags |= CMD_IGNORE_RETURN; - - lastpipe_flag = 0; -+ - begin_unwind_frame ("lastpipe-exec"); - lstdin = -1; -*************** -*** 2222,2233 **** - if (prev >= 0) - add_unwind_protect (close, prev); -- #endif - - exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); - -- #if defined (JOB_CONTROL) - if (lstdin > 0) - restore_stdin (lstdin); -- #endif - - if (prev >= 0) ---- 2347,2355 ---- -*************** -*** 2252,2258 **** - } - -- #if defined (JOB_CONTROL) - discard_unwind_frame ("lastpipe-exec"); -- #endif - - return (exec_result); ---- 2374,2378 ---- -*************** -*** 2471,2479 **** - /* Save this command unless it's a trap command and we're not running - a debug trap. */ -- #if 0 -- if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -- #else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -- #endif - { - FREE (the_printed_command_except_trap); ---- 2591,2595 ---- -*************** -*** 2490,2494 **** - - this_command_name = (char *)NULL; -! v = bind_variable (identifier, list->word->word, 0); - if (readonly_p (v) || noassign_p (v)) - { ---- 2606,2617 ---- - - this_command_name = (char *)NULL; -! /* XXX - special ksh93 for command index variable handling */ -! v = find_variable_last_nameref (identifier); -! if (v && nameref_p (v)) -! { -! v = bind_variable_value (v, list->word->word, 0); -! } -! else -! v = bind_variable (identifier, list->word->word, 0); - if (readonly_p (v) || noassign_p (v)) - { -*************** -*** 2749,2752 **** ---- 2872,2877 ---- - for (i = ind, l = list; l && --i; l = l->next) - ; -+ if (l == 0) /* don't think this can happen */ -+ return (0); - fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); - return (displen (l->word->word)); -*************** -*** 2889,2893 **** - for (l = list; l && --reply; l = l->next) - ; -! return (l->word->word); - } - } ---- 3014,3018 ---- - for (l = list; l && --reply; l = l->next) - ; -! return (l->word->word); /* XXX - can't be null? */ - } - } -*************** -*** 3330,3333 **** ---- 3455,3459 ---- - static char * const nullstr = ""; - -+ /* XXX - can COND ever be NULL when this is called? */ - static int - execute_cond_node (cond) -*************** -*** 3379,3384 **** - { - rmatch = 0; -! patmatch = ((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && -! (cond->op->word[0] == '!' || cond->op->word[0] == '=') || - (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); - #if defined (COND_REGEXP) ---- 3505,3510 ---- - { - rmatch = 0; -! patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && -! (cond->op->word[0] == '!' || cond->op->word[0] == '=')) || - (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); - #if defined (COND_REGEXP) -*************** -*** 3581,3585 **** - WORD_LIST *words; - { -! WORD_LIST *w; - struct builtin *b; - int assoc, global; ---- 3707,3711 ---- - WORD_LIST *words; - { -! WORD_LIST *w, *wcmd; - struct builtin *b; - int assoc, global; -*************** -*** 3591,3594 **** ---- 3717,3721 ---- - assoc = global = 0; - -+ wcmd = words; - for (w = words; w; w = w->next) - if (w->word->flags & W_ASSIGNMENT) -*************** -*** 3596,3604 **** - if (b == 0) - { -! b = builtin_address_internal (words->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) -! words->word->flags |= W_ASSNBLTIN; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); ---- 3723,3738 ---- - if (b == 0) - { -! /* Posix (post-2008) says that `command' doesn't change whether -! or not the builtin it shadows is a `declaration command', even -! though it removes other special builtin properties. In Posix -! mode, we skip over one or more instances of `command' and -! deal with the next word as the assignment builtin. */ -! while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) -! wcmd = wcmd->next; -! b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) -! wcmd->word->flags |= W_ASSNBLTIN; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); -*************** -*** 3620,3632 **** - if (b == 0) - { -! b = builtin_address_internal (words->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) -! words->word->flags |= W_ASSNBLTIN; - } -! if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) - assoc = 1; -! if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) - global = 1; - } ---- 3754,3768 ---- - if (b == 0) - { -! while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) -! wcmd = wcmd->next; -! b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) -! wcmd->word->flags |= W_ASSNBLTIN; - } -! if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) - assoc = 1; -! if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) - global = 1; - } -*************** -*** 3640,3645 **** - { - char *temp; -! temp = search_for_command (pathname); -! return (temp ? file_isdir (temp) : file_isdir (pathname)); - } - ---- 3776,3785 ---- - { - char *temp; -! int ret; -! -! temp = search_for_command (pathname, 0); -! ret = (temp ? file_isdir (temp) : file_isdir (pathname)); -! free (temp); -! return ret; - } - -*************** -*** 3665,3668 **** ---- 3805,3810 ---- - command_line = (char *)0; - -+ QUIT; -+ - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell && sourcelevel == 0) -*************** -*** 3981,3985 **** - - if (command_line == 0) -! command_line = savestring (the_printed_command_except_trap); - - #if defined (PROCESS_SUBSTITUTION) ---- 4123,4127 ---- - - if (command_line == 0) -! command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); - - #if defined (PROCESS_SUBSTITUTION) -*************** -*** 4042,4050 **** - char *error_trap; - -- #if 0 -- /* XXX -- added 12/11 */ -- terminate_immediately++; -- #endif -- - error_trap = 0; - old_e_flag = exit_immediately_on_error; ---- 4184,4187 ---- -*************** -*** 4128,4136 **** - } - -- #if 0 -- /* XXX -- added 12/11 */ -- terminate_immediately--; -- #endif -- - return (result); - } ---- 4265,4268 ---- -*************** -*** 4160,4164 **** - if (funcnest_max > 0 && funcnest >= funcnest_max) - { -! internal_error ("%s: maximum function nesting level exceeded (%d)", var->name, funcnest); - funcnest = 0; /* XXX - should we reset it somewhere else? */ - jump_to_top_level (DISCARD); ---- 4292,4296 ---- - if (funcnest_max > 0 && funcnest >= funcnest_max) - { -! internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest); - funcnest = 0; /* XXX - should we reset it somewhere else? */ - jump_to_top_level (DISCARD); -*************** -*** 4252,4260 **** - shell_fn = find_function_def (this_shell_function->name); - sfile = shell_fn ? shell_fn->source_file : ""; -! array_push (funcname_a, this_shell_function->name); - -! array_push (bash_source_a, sfile); - t = itos (executing_line_number ()); -! array_push (bash_lineno_a, t); - free (t); - #endif ---- 4384,4392 ---- - shell_fn = find_function_def (this_shell_function->name); - sfile = shell_fn ? shell_fn->source_file : ""; -! array_push ((ARRAY *)funcname_a, this_shell_function->name); - -! array_push ((ARRAY *)bash_source_a, sfile); - t = itos (executing_line_number ()); -! array_push ((ARRAY *)bash_lineno_a, t); - free (t); - #endif -*************** -*** 4331,4336 **** - /* These two variables cannot be unset, and cannot be affected by the - function. */ -! array_pop (bash_source_a); -! array_pop (bash_lineno_a); - - /* FUNCNAME can be unset, and so can potentially be changed by the ---- 4463,4468 ---- - /* These two variables cannot be unset, and cannot be affected by the - function. */ -! array_pop ((ARRAY *)bash_source_a); -! array_pop ((ARRAY *)bash_lineno_a); - - /* FUNCNAME can be unset, and so can potentially be changed by the -*************** -*** 4666,4670 **** - #endif /* RESTRICTED_SHELL */ - -! command = search_for_command (pathname); - - if (command) ---- 4798,4802 ---- - #endif /* RESTRICTED_SHELL */ - -! command = search_for_command (pathname, 1); - - if (command) -*************** -*** 4765,4768 **** ---- 4897,4902 ---- - { - parent_return: -+ QUIT; -+ - /* Make sure that the pipes are closed in the parent. */ - close_pipes (pipe_in, pipe_out); -*************** -*** 4993,4996 **** ---- 5127,5131 ---- - #if defined (HAVE_HASH_BANG_EXEC) - READ_SAMPLE_BUF (command, sample, sample_len); -+ sample[sample_len - 1] = '\0'; - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - { -*************** -*** 5045,5049 **** - if (check_binary_file (sample, sample_len)) - { -! internal_error (_("%s: cannot execute binary file"), command); - return (EX_BINARY_FILE); - } ---- 5180,5184 ---- - if (check_binary_file (sample, sample_len)) - { -! internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i)); - return (EX_BINARY_FILE); - } -*************** -*** 5098,5104 **** - - static int -! execute_intern_function (name, function) - WORD_DESC *name; -! COMMAND *function; - { - SHELL_VAR *var; ---- 5233,5239 ---- - - static int -! execute_intern_function (name, funcdef) - WORD_DESC *name; -! FUNCTION_DEF *funcdef; - { - SHELL_VAR *var; -*************** -*** 5114,5117 **** ---- 5249,5260 ---- - } - -+ /* Posix interpretation 383 */ -+ if (posixly_correct && find_special_builtin (name->word)) -+ { -+ internal_error (_("`%s': is a special builtin"), name->word); -+ last_command_exit_value = EX_BADUSAGE; -+ jump_to_top_level (ERREXIT); -+ } -+ - var = find_function (name->word); - if (var && (readonly_p (var) || noassign_p (var))) -*************** -*** 5122,5126 **** - } - -! bind_function (name->word, function); - return (EXECUTION_SUCCESS); - } ---- 5265,5273 ---- - } - -! #if defined (DEBUGGER) -! bind_function_def (name->word, funcdef); -! #endif -! -! bind_function (name->word, funcdef->command); - return (EXECUTION_SUCCESS); - } diff --git a/doc/FAQ.orig b/doc/FAQ.orig deleted file mode 100644 index 1cff3c8ef..000000000 --- a/doc/FAQ.orig +++ /dev/null @@ -1,1745 +0,0 @@ -This is the Bash FAQ, version 3.24, for Bash version 2.05b. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet@po.cwru.edu. - -This document is available for anonymous FTP with the URL - -ftp://ftp.cwru.edu/pub/bash/FAQ - -The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html - ----------- -Contents: - -Section A: The Basics - -A1) What is it? -A2) What's the latest version? -A3) Where can I get it? -A4) On what machines will bash run? -A5) Will bash run on operating systems other than Unix? -A6) How can I build bash with gcc? -A7) How can I make bash my login shell? -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? -A9) What's the `POSIX 1003.2 standard'? -A10) What is the bash `posix mode'? - -Section B: The latest version - -B1) What's new in version 2.05b? -B2) Are there any user-visible incompatibilities between bash-2.05b and - bash-1.14.7? - -Section C: Differences from other Unix shells - -C1) How does bash differ from sh, the Bourne shell? -C2) How does bash differ from the Korn shell, version ksh88? -C3) Which new features in ksh-93 are not in bash, and which are? - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? -D2) Why doesn't bash treat brace expansions exactly like csh? -D3) Why doesn't bash have csh variable modifiers? -D4) How can I make my csh aliases work when I convert to bash? -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -Section E: Why does bash do certain things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? -E2) Why does bash sometimes say `Broken pipe'? -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -E4) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? -E5) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? -E6) Why doesn't a while or for loop get suspended when I type ^Z? -E7) What about empty for loops in Makefiles? -E8) Why does the arithmetic evaluation code complain about `08'? -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? -E10) Why does `cd //' leave $PWD as `//'? -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? -G5) How do I get the current directory into my prompt? -G6) How can I rename "*.foo" to "*.bar"? -G7) How can I translate a filename from uppercase to lowercase? -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? -H2) What kind of bash documentation is there? -H3) What's coming in future versions? -H4) What's on the bash `wish list'? -H5) When will the next release appear? - ----------- -Section A: The Basics - -A1) What is it? - -Bash is a Unix command interpreter (shell). It is an implementation of -the Posix 1003.2 shell standard, and resembles the Korn and System V -shells. - -Bash contains a number of enhancements over those shells, both -for interactive use and shell programming. Features geared -toward interactive use include command line editing, command -history, job control, aliases, and prompt expansion. Programming -features include additional variable expansions, shell -arithmetic, and a number of variables and options to control -shell behavior. - -Bash was originally written by Brian Fox of the Free Software -Foundation. The current developer and maintainer is Chet Ramey -of Case Western Reserve University. - -A2) What's the latest version? - -The latest version is 2.05b, first made available on Wednesday, 17 -July, 2002. - -A3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, ftp.gnu.org, and its mirrors. The -latest version is also available for FTP from ftp.cwru.edu. -The following URLs tell how to get version 2.05b: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz - -A4) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `configure' and then `make'. The build process -will attempt to discover the version of UNIX you have and tailor -itself accordingly, using a script created by GNU autoconf. - -More information appears in the file `INSTALL' in the distribution. - -The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) -explains how to obtain binary versions of bash for most of the major -commercial Unix systems. - -A5) Will bash run on operating systems other than Unix? - -Configuration specifics for Unix-like systems such as QNX and -LynxOS are included in the distribution. Bash-2.05 and later -versions should compile and run on Minix 2.0 (patches were -contributed), but I don't believe anyone has built bash-2.x on -earlier Minix versions yet. - -Bash has been ported to versions of Windows implementing the Win32 -programming interface. This includes Windows 95 and Windows NT. -The port was done by Cygnus Solutions as part of their CYGWIN -project. For more information about the project, look at the URLs - -http://www.cygwin.com/ -http://sourceware.cygnus.com/cygwin - -Cygnus originally ported bash-1.14.7, and that port was part of their -early GNU-Win32 (the original name) releases. Cygnus has also done a -port of bash-2.05 to the CYGWIN environment, and it is available as -part of their current release. - -Bash-2.05b should require no local Cygnus changes to build and run under -CYGWIN. - -The Cygnus port works only on Intel machines. There is a port of bash -(I don't know which version) to the alpha/NT environment available from - -ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz - -DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part -of the DJGPP project. For more information on the project, see - -http://www.delorie.com/djgpp/ - -I have been told that the original DJGPP port was done by Daisuke Aoyama. - -Mark Elbrecht has sent me notice that bash-2.04 -is available for DJGPP V2. The files are available as: - -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source - -Mark has begun to work with bash-2.05, but I don't know the status. - -Ports of bash-1.12 and bash-2.0 are available for OS/2 from - -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip - -I haven't looked at either, but the second appears to be a binary-only -distribution. Beware. - -I have received word that Bash (I'm not sure which version, but I -believe that it's at least bash-2.02.1) is the standard shell on -BeOS. - -A6) How can I build bash with gcc? - -Bash configures to use gcc by default if it is available. Read the -file INSTALL in the distribution for more information. - -A7) How can I make bash my login shell? - -Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s' or `passwd -e'. If one of these works for -you, that's all you need. Note that many systems require the full -pathname to a shell to appear in /etc/shells before you can make it -your login shell. For this, you may need the assistance of your -friendly local system administrator. - -If you cannot do this, you can still use bash as your login shell, but -you need to perform some tricks. The basic idea is to add a command -to your login shell's startup file to replace your login shell with -bash. - -For example, if your login shell is csh or tcsh, and you have installed -bash in /usr/gnu/bin/bash, add the following line to ~/.login: - - if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login - -(the `--login' tells bash that it is a login shell). - -It's not a good idea to put this command into ~/.cshrc, because every -csh you run without the `-f' option, even ones started to run csh scripts, -reads that file. If you must put the command in ~/.cshrc, use something -like - - if ( $?prompt ) exec /usr/gnu/bin/bash --login - -to ensure that bash is exec'd only when the csh is interactive. - -If your login shell is sh or ksh, you have to do two things. - -First, create an empty file in your home directory named `.bash_profile'. -The existence of this file will prevent the exec'd bash from trying to -read ~/.profile, and re-execing itself over and over again. ~/.bash_profile -is the first file bash tries to read initialization commands from when -it is invoked as a login shell. - -Next, add a line similar to the above to ~/.profile: - - [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ - exec /usr/gnu/bin/bash --login - -This will cause login shells to replace themselves with bash running as -a login shell. Once you have this working, you can copy your initialization -code from ~/.profile to ~/.bash_profile. - -I have received word that the recipe supplied above is insufficient for -machines running CDE. CDE has a maze of twisty little startup files, all -slightly different. - -If you cannot change your login shell in the password file to bash, you -will have to (apparently) live with CDE using the shell in the password -file to run its startup scripts. If you have changed your shell to bash, -there is code in the CDE startup files (on Solaris, at least) that attempts -to do the right thing. It is, however, often broken, and may require that -you use the $BASH_ENV trick described below. - -`dtterm' claims to use $SHELL as the default program to start, so if you -can change $SHELL in the CDE startup files, you should be able to use bash -in your terminal windows. - -Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program -to read your login shell's startup files. You may be able to use bash for -the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as -well, but I have not tried this. - -You can use the above `exec' recipe to start bash when not logging in with -CDE by testing the value of the DT variable: - - if [ -n "$DT" ]; then - [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login - fi - -If CDE starts its shells non-interactively during login, the login shell -startup files (~/.profile, ~/.bash_profile) will not be sourced at login. -To get around this problem, append a line similar to the following to your -~/.dtprofile: - - BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV - -and add the following line to the beginning of ~/.bash_profile: - - unset BASH_ENV - -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? - -You must add the full pathname to bash to the file /etc/shells. As -noted in the answer to the previous question, many systems require -this before you can make bash your login shell. - -Most versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -A9) What's the `POSIX 1003.2 standard'? - -POSIX is a name originally coined by Richard Stallman for a -family of open system standards based on UNIX. There are a -number of aspects of UNIX under consideration for -standardization, from the basic system services at the system -call and C library level to applications and tools to system -administration and management. Each area of standardization is -assigned to a working group in the 1003 series. - -The POSIX Shell and Utilities standard has been developed by IEEE -Working Group 1003.2 (POSIX.2). It concentrates on the command -interpreter interface and utility programs commonly executed from -the command line or by other programs. An initial version of the -standard has been approved and published by the IEEE, and work is -currently underway to update it. - -Bash is concerned with the aspects of the shell's behavior -defined by POSIX.2. The shell command language has of course -been standardized, including the basic flow control and program -execution constructs, I/O redirection and pipelining, argument -handling, variable expansion, and quoting. - -The `special' builtins, which must be implemented as part of the -shell to provide the desired functionality, are specified as -being part of the shell; examples of these are `eval' and -`export'. Other utilities appear in the sections of POSIX.2 not -devoted to the shell which are commonly (and in some cases must -be) implemented as builtin commands, such as `read' and `test'. -POSIX.2 also specifies aspects of the shell's interactive -behavior as part of the UPE, including job control and command -line editing. Only vi-style line editing commands have been -standardized; emacs editing commands were left out due to -objections. - -The Open Group has made an older version of its Single Unix -Specification (version 2), which is very similar to POSIX.2, -available on the web at - -http://www.opengroup.org/onlinepubs/007908799/ - -The Single Unix Specification, version 3, is available on the web at - -http://www.opengroup.org/onlinepubs/007904975/ - -A10) What is the bash `posix mode'? - -Although bash is an implementation of the POSIX.2 shell -specification, there are areas where the bash default behavior -differs from that spec. The bash `posix mode' changes the bash -behavior in these areas so that it obeys the spec more closely. - -Posix mode is entered by starting bash with the --posix or -'-o posix' option or executing `set -o posix' after bash is running. - -The specific aspects of bash which change when posix mode is -active are listed in the file POSIX in the bash distribution. -They are also listed in a section in the Bash Reference Manual -(from which that file is generated). - -Section B: The latest version - -B1) What's new in version 2.05b? - -The raison d'etre for bash-2.05b is to make a second intermediate -release containing the first of the new features to be available -in bash-3.0 and get feedback on those features before proceeding. -The major new feature is multibyte character support in both Bash -and Readline. - -Bash-2.05b contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-2.05b -distribution): - -o support for multibyte characters has been added to both bash and readline - -o the DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops - -o the shell now performs arithmetic in the largest integer size the machine - supports (intmax_t) - -o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) - and inserts the result into the expanded prompt - -o there is a new `here-string' redirection operator: <<< word - -o when displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -o `read' has a new `-u fd' option to read from a specified file descriptor - -o the bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better - -o the expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires - - -A short feature history dating from Bash-2.0: - -Bash-2.05a introduced the following new features: - -o The `printf' builtin has undergone major work - -o There is a new read-only `shopt' option: login_shell, which is set by - login shells and unset otherwise - -o New `\A' prompt string escape sequence; expanding to time in 24-hour - HH:MM format - -o New `-A group/-g' option to complete and compgen; goes group name - completion - -o New [+-]O invocation option to set and unset `shopt' options at startup - -o ksh-like `ERR' trap - -o `for' loops now allow empty word lists after the `in' reserved word - -o new `hard' and `soft' arguments for the `ulimit' builtin - -o Readline can be configured to place the user at the same point on the line - when retrieving commands from the history list - -o Readline can be configured to skip `hidden' files (filenames with a leading - `.' on Unix) when performing completion - -Bash-2.05 introduced the following new features: - -o This version has once again reverted to using locales and strcoll(3) when - processing pattern matching bracket expressions, as POSIX requires. -o Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. -o The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. -o `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces -o A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. -o When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -Bash-2.04 introduced the following new features: - -o Programmable word completion with the new `complete' and `compgen' builtins; - examples are provided in examples/complete/complete-examples -o `history' has a new `-d' option to delete a history entry -o `bind' has a new `-x' option to bind key sequences to shell commands -o The prompt expansion code has new `\j' and `\l' escape sequences -o The `no_empty_cmd_completion' shell option, if enabled, inhibits - command completion when TAB is typed on an empty line -o `help' has a new `-s' option to print a usage synopsis -o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) -o New ksh93-style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done -o `read' has new options: `-t', `-n', `-d', `-s' -o The redirection code handles several filenames specially: /dev/fd/N, - /dev/stdin, /dev/stdout, /dev/stderr -o The redirection code now recognizes /dev/tcp/HOST/PORT and - /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, - to the specified port on the specified host -o The ${!prefix*} expansion has been implemented -o A new FUNCNAME variable, which expands to the name of a currently-executing - function -o The GROUPS variable is no longer readonly -o A new shopt `xpg_echo' variable, to control the behavior of echo with - respect to backslash-escape sequences at runtime -o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned - -The version of Readline released with Bash-2.04, Readline-4.1, had several -new features as well: - -o Parentheses matching is always compiled into readline, and controllable - with the new `blink-matching-paren' variable -o The history-search-forward and history-search-backward functions now leave - point at the end of the line when the search string is empty, like - reverse-search-history, and forward-search-history -o A new function for applications: rl_on_new_line_with_prompt() -o New variables for applications: rl_already_prompted, and rl_gnu_readline_p - - -Bash-2.03 had very few new features, in keeping with the convention -that odd-numbered releases provide mainly bug fixes. A number of new -features were added to Readline, mostly at the request of the Cygnus -folks. - -A new shopt option, `restricted_shell', so that startup files can test - whether or not the shell was started in restricted mode -Filename generation is now performed on the words between ( and ) in - compound array assignments (this is really a bug fix) -OLDPWD is now auto-exported, as POSIX.2 requires -ENV and BASH_ENV are read-only variables in a restricted shell -Bash may now be linked against an already-installed Readline library, - as long as the Readline library is version 4 or newer -All shells begun with the `--login' option will source the login shell - startup files, even if the shell is not interactive - -There were lots of changes to the version of the Readline library released -along with Bash-2.03. For a complete list of the changes, read the file -CHANGES in the Bash-2.03 distribution. - -Bash-2.02 contained the following new features: - -a new version of malloc (based on the old GNU malloc code in previous - bash versions) that is more page-oriented, more conservative - with memory usage, does not `orphan' large blocks when they - are freed, is usable on 64-bit machines, and has allocation - checking turned on unconditionally -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -the ksh [[...]] extended conditional command -the ksh egrep-style extended pattern matching operators -a new `printf' builtin -the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- - prompt string special char translation and variable expansion - auto-export of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. - export -n/-f/-p/name=value, pwd -L/-P, - read -e/-p/-a/-t/-n/-d/-s/-u, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -m/-p/-u, - type -a/-p/-t/-f/-P, suspend -f, kill -n, - test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion with $((...)) and `let' builtin - the `[[...]]' extended conditional command - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing with programmable completion - command history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, compgen, complete, builtin, - declare/typeset, dirs, enable, fc, help, - history, logout, popd, pushd, disown, shopt, - printf - exported functions - filename generation when using output redirection (command >a*) - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - variable assignments preceding commands affect only that command, - even for builtins and functions - posix mode - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - -Things sh has that bash does not: - uses variable SHACCT to do shell accounting - includes `stop' builtin (bash can use alias stop='kill -s STOP') - `newgrp' builtin - turns on job control if called as `jsh' - $TIMEOUT (like bash $TMOUT) - `^' is a synonym for `|' - new SVR4.2 sh builtins: mldmode, priv - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS, using POSIX.2 - field splitting rules; sh splits all words on IFS - sh does not allow MAILCHECK to be unset (?) - sh does not allow traps on SIGALRM or SIGCHLD - bash allows multiple option arguments when invoked (e.g. -x -v); - sh allows only a single option argument (`sh -x -v' attempts - to open a file named `-v', and, on SunOS 4.1.4, dumps core. - On Solaris 2.4 and earlier versions, sh goes into an infinite - loop.) - sh exits a script if any builtin fails; bash exits only if one of - the POSIX.2 `special' builtins fails - -C2) How does bash differ from the Korn shell, version ksh88? - -Things bash has or uses that ksh88 does not: - long invocation options - [-+]O invocation option - -l invocation option - `!' reserved word - arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done - arithmetic in largest machine-supported size (intmax_t) - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - the ${!param} indirect parameter expansion operator - the ${!param*} prefix expansion operator - the ${param:offset[:length]} parameter substring operator - the ${param/pat[/string]} parameter pattern substitution operator - variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, - TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, - HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, - IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, - PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, - GROUPS, FUNCNAME, histchars, auto_resume - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- - more extensive and extensible editing and programmable completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, - jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, - read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, - set -o braceexpand/-o histexpand/-o interactive-comments/ - -o notify/-o physical/-o posix/-o hashall/-o onecmd/ - -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, - typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, - disown, printf, complete, compgen - `!' csh-style history expansion - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - `**' arithmetic operator to do exponentiation - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr - arrays of unlimited size - TMOUT is default timeout for `read' and `select' - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (|&, >&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence - using environment to pass attributes of exported variables - arithmetic evaluation done on arguments to some builtins - reads .profile from $PWD when invoked as login shell - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - bash has brace expansion by default (ksh88 compile-time option) - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - bash waits for all commands in pipeline to exit before returning status - emacs-mode editing has some slightly different key bindings - -C3) Which new features in ksh-93 are not in bash, and which are? - -New things in ksh-93 not in bash-2.05b: - associative arrays - floating point arithmetic and variables - math library functions - ${!name[sub]} name of subscript for associative array - `.' is allowed in variable names to create a hierarchical namespace - more extensive compound assignment syntax - discipline functions - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - KEYBD trap - variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, - .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT - backreferences in pattern matching (\N) - `&' operator in pattern lists for matching - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - exit statuses between 0 and 255 - set -o pipefail - `+=' variable assignment operator - FPATH and PATH mixing - getopts -a - -I invocation option - DEBUG trap now executed before each simple command, instead of after - printf %H, %P, %T, %Z modifiers, output base for %d - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - -New things in ksh-93 present in bash-2.05b: - [n]<&word- and [n]>&word- redirections (combination dup and close) - for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command - ?:, ++, --, `expr1 , expr2' arithmetic operators - expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, - ${!param*} - compound array assignment - the `!' reserved word - loadable builtins -- but ksh uses `builtin' while bash uses `enable' - `command', `builtin', `disown' builtins - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - set -o notify/-C - changes to kill builtin - read -A (bash uses read -a) - read -t/-d - trap -p - exec -c/-a - `.' restores the positional parameters when it completes - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion - ENV processed only for interactive shells - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? - -On many systems, `which' is actually a csh script that assumes -you're running csh. In tcsh, `which' and its cousin `where' -are builtins. On other Unix systems, `which' is a perl script -that uses the PATH environment variable. - -The csh script version reads the csh startup files from your -home directory and uses those to determine which `command' will -be invoked. Since bash doesn't use any of those startup files, -there's a good chance that your bash environment differs from -your csh environment. The bash `type' builtin does everything -`which' does, and will report correct results for the running -shell. If you're really wedded to the name `which', try adding -the following function definition to your .bashrc: - - which() - { - builtin type "$@" - } - -If you're moving from tcsh and would like to bring `where' along -as well, use this function: - - where() - { - builtin type -a "$@" - } - -D2) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least one unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -D3) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more cryptic, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -D4) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/misc/aliasconv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `aliasconv.sh', saving the -results into `bash_aliases': - - alias | bash aliasconv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of some csh specific -variables to the bash equivalents. The script converts $cwd to -$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt -to $PS1. You may also have to add quotes to avoid unwanted -expansion. - -For example, the csh alias: - - alias cd 'cd \!*; echo $cwd' - -is converted to the bash function: - - cd () { command cd "$@"; echo $PWD ; } - -The only thing that needs to be done is to quote $PWD: - - cd () { command cd "$@"; echo "$PWD" ; } - -Merge the edited file into your ~/.bashrc. - -There is an additional, more ambitious, script in -examples/misc/cshtobash that attempts to convert your entire csh -environment to its bash equivalent. This script can be run as -simply `cshtobash' to convert your normal interactive -environment, or as `cshtobash ~/.login' to convert your login -environment. - -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? - -Use - command 2>&1 | command2 - -The key is to remember that piping is performed before redirection, so -file descriptor 1 points to the pipe when it is duplicated onto file -descriptor 2. - -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -There are features in ksh-88 and ksh-93 that do not have direct bash -equivalents. Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -coprocesses named pipe pairs (one for read, one for write) -typeset +f declare -F -cd, print, whence function substitutes in examples/functions/kshenv -autoloaded functions examples/functions/autoload is the same as typeset -fu -read var?prompt read -p prompt var - -ksh-93 feature Bash equivalent --------------- --------------- -sleep, getconf Bash has loadable versions in examples/loadables -${.sh.version} $BASH_VERSION -print -f printf -hist alias hist=fc -$HISTEDIT $FCEDIT - -Section E: How can I get bash to do certain things, and why does bash do - things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? - -The specific example used here is [ ! x -o x ], which is false. - -Bash's builtin `test' implements the Posix.2 spec, which can be -summarized as follows (the wording is due to David Korn): - -Here is the set of rules for processing test arguments. - - 0 Args: False - 1 Arg: True iff argument is not null. - 2 Args: If first arg is !, True iff second argument is null. - If first argument is unary, then true if unary test is true - Otherwise error. - 3 Args: If second argument is a binary operator, do binary test of $1 $3 - If first argument is !, negate two argument test of $2 $3 - If first argument is `(' and third argument is `)', do the - one-argument test of the second argument. - Otherwise error. - 4 Args: If first argument is !, negate three argument test of $2 $3 $4. - Otherwise unspecified - 5 or more Args: unspecified. (Historical shells would use their - current algorithm). - -The operators -a and -o are considered binary operators for the purpose -of the 3 Arg case. - -As you can see, the test becomes (not (x or x)), which is false. - -E2) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appears in a pipeline, and one of the -reading commands finishes before the writer has finished, the -writer receives a SIGPIPE signal. Many other shells special-case -SIGPIPE as an exit status in the pipeline and do not report it. -For example, in: - - ps -aux | head - -`head' can finish before `ps' writes all of its output, and ps -will try to write on a pipe without a reader. In that case, bash -will print `Broken pipe' to stderr when ps is killed by a -SIGPIPE. - -You can build a version of bash that will not report SIGPIPE errors -by uncommenting the definition of DONT_REPORT_SIGPIPE in the file -config-top.h. - -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Readline, the line editing library that bash uses, does not know -that the terminal escape sequences do not take up space on the -screen. The redisplay code assumes, unless told otherwise, that -each character in the prompt is a `printable' character that -takes up one character position on the screen. - -You can use the bash prompt expansion facility (see the PROMPTING -section in the manual page) to tell readline that sequences of -characters in the prompt strings take up no screen space. - -Use the \[ escape to begin a sequence of non-printing characters, -and the \] escape to signal the end of such a sequence. - -E4) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? - -This has to do with the parent-child relationship between Unix -processes. It affects all commands run in pipelines, not just -simple calls to `read'. For example, piping a command's output -into a `while' loop that repeatedly calls `read' will result in -the same behavior. - -Each element of a pipeline runs in a separate process, a child of -the shell running the pipeline. A subprocess cannot affect its -parent's environment. When the `read' command sets the variable -to the input, that variable is set only in the subshell, not the -parent shell. When the subshell exits, the value of the variable -is lost. - -Many pipelines that end with `read variable' can be converted -into command substitutions, which will capture the output of -a specified command. The output can then be assigned to a -variable: - - grep ^gnu /usr/lib/news/active | wc -l | read ngroup - -can be converted into - - ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) - -This does not, unfortunately, work to split the text among -multiple variables, as read does when given multiple variable -arguments. If you need to do this, you can either use the -command substitution above to read the output into a variable -and chop up the variable using the bash pattern removal -expansion operators or use some variant of the following -approach. - -Say /usr/local/bin/ipaddr is the following shell script: - -#! /bin/sh -host `hostname` | awk '/address/ {print $NF}' - -Instead of using - - /usr/local/bin/ipaddr | read A B C D - -to break the local machine's IP address into separate octets, use - - OIFS="$IFS" - IFS=. - set -- $(/usr/local/bin/ipaddr) - IFS="$OIFS" - A="$1" B="$2" C="$3" D="$4" - -Beware, however, that this will change the shell's positional -parameters. If you need them, you should save them before doing -this. - -This is the general approach -- in most cases you will not need to -set $IFS to a different value. - -Some other user-supplied alternatives include: - -read A B C D << HERE - $(IFS=.; echo $(/usr/local/bin/ipaddr)) -HERE - -and, where process substitution is available, - -read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) - -E5) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? - -This is the behavior of echo on most Unix System V machines. - -The bash builtin `echo' is modeled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default; -it requires the use of the -e option to enable the -interpretation. The System V echo provides no way to disable the -special characters; the bash echo has a -E option to disable -them. - -There is a configuration option that will make bash behave like -the System V echo and interpret things like `\t' by default. Run -configure with the --enable-xpg-echo-default option to turn this -on. Be aware that this will cause some of the tests run when you -type `make tests' to fail. - -There is a shell option, `xpg_echo', settable with `shopt', that will -change the behavior of echo at runtime. Enabling this option turns -on expansion of backslash-escape sequences. - -E6) Why doesn't a while or for loop get suspended when I type ^Z? - -This is a consequence of how job control works on Unix. The only -thing that can be suspended is the process group. This is a single -command or pipeline of commands that the shell forks and executes. - -When you run a while or for loop, the only thing that the shell forks -and executes are any commands in the while loop test and commands in -the loop bodies. These, therefore, are the only things that can be -suspended when you type ^Z. - -If you want to be able to stop the entire loop, you need to put it -within parentheses, which will force the loop into a subshell that -may be stopped (and subsequently restarted) as a single unit. - -E7) What about empty for loops in Makefiles? - -It's fairly common to see constructs like this in automatically-generated -Makefiles: - -SUBDIRS = @SUBDIRS@ - - ... - -subdirs-clean: - for d in ${SUBDIRS}; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -When SUBDIRS is empty, this results in a command like this being passed to -bash: - - for d in ; do - ( cd $d && ${MAKE} ${MFLAGS} clean ) - done - -In versions of bash before bash-2.05a, this was a syntax error. If the -reserved word `in' was present, a word must follow it before the semicolon -or newline. The language in the manual page referring to the list of words -being empty referred to the list after it is expanded. These versions of -bash required that there be at least one word following the `in' when the -construct was parsed. - -The idiomatic Makefile solution is something like: - -SUBDIRS = @SUBDIRS@ - -subdirs-clean: - subdirs=$SUBDIRS ; for d in $$subdirs; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -The latest drafts of the updated POSIX standard have changed this: the -word list is no longer required. Bash versions 2.05a and later accept -the new syntax. - -E8) Why does the arithmetic evaluation code complain about `08'? - -The bash arithmetic evaluation code (used for `let', $(()), (()), and in -other places), interprets a leading `0' in numeric constants as denoting -an octal number, and a leading `0x' as denoting hexadecimal. This is -in accordance with the POSIX.2 spec, section 2.9.2.1, which states that -arithmetic constants should be handled as signed long integers as defined -by the ANSI/ISO C standard. - -The POSIX.2 interpretation committee has confirmed this: - -http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html - -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? - -Bash-2.03, Bash-2.05 and later versions honor the current locale setting -when processing ranges within pattern matching bracket expressions ([A-Z]). -This is what POSIX.2 and SUSv3/XPG6 specify. - -The behavior of the matcher in bash-2.05 and later versions depends on the -current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will -result in the traditional behavior ([A-Z] matches all uppercase ASCII -characters). Many other locales, including the en_US locale (the default -on many US versions of Linux) collate the upper and lower case letters like -this: - - AaBb...Zz - -which means that [A-Z] matches every letter except `z'. Others collate like - - aAbBcC...zZ - -which means that [A-Z] matches every letter except `a'. - -The portable way to specify upper case letters is [:upper:] instead of -A-Z; lower case may be specified as [:lower:] instead of a-z. - -Look at the manual pages for setlocale(3), strcoll(3), and, if it is -present, locale(1). If you have locale(1), you can use it to find -your current locale information even if you do not have any of the -LC_ variables set. - -My advice is to put - - export LC_COLLATE=C - -into /etc/profile and inspect any shell scripts run from cron for -constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - -from removing every file in the current directory except those beginning -with `z' and still allow individual users to change the collation order. -Users may put the above command into their own profiles as well, of course. - -E10) Why does `cd //' leave $PWD as `//'? - -POSIX.2, in its description of `cd', says that *three* or more leading -slashes may be replaced with a single slash when canonicalizing the -current working directory. - -This is, I presume, for historical compatibility. Certain versions of -Unix, and early network file systems, used paths of the form -//hostname/path to access `path' on server `hostname'. - -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -This is another issue that deals with job control. - -The kernel maintains a notion of a current terminal process group. Members -of this process group (processes whose process group ID is equal to the -current terminal process group ID) receive terminal-generated signals like -SIGWINCH. (For more details, see the JOB CONTROL section of the bash -man page.) - -If a terminal is resized, the kernel sends SIGWINCH to each member of -the terminal's current process group (the `foreground' process group). - -When bash is running with job control enabled, each pipeline (which may be -a single command) is run in its own process group, different from bash's -process group. This foreground process group receives the SIGWINCH; bash -does not. Bash has no way of knowing that the terminal has been resized. - -There is a `checkwinsize' option, settable with the `shopt' builtin, that -will cause bash to check the window size and adjust its idea of the -terminal's dimensions each time a process stops or exits and returns control -of the terminal to bash. Enable it with `shopt -s checkwinsize'. - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? - -The problem is `cmdtool' and bash fighting over the input. When -scrolling is enabled in a cmdtool window, cmdtool puts the tty in -`raw mode' to permit command-line editing using the mouse for -applications that cannot do it themselves. As a result, bash and -cmdtool each try to read keyboard input immediately, with neither -getting enough of it to be useful. - -This mode also causes cmdtool to not implement many of the -terminal functions and control sequences appearing in the -`sun-cmd' termcap entry. For a more complete explanation, see -that file examples/suncmd.termcap in the bash distribution. - -`xterm' is a better choice, and gets along with bash much more -smoothly. - -If you must use cmdtool, you can use the termcap description in -examples/suncmd.termcap. Set the TERMCAP variable to the terminal -description contained in that file, i.e. - -TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' - -Then export TERMCAP and start a new cmdtool window from that shell. -The bash command-line editing should behave better in the new -cmdtool. If this works, you can put the assignment to TERMCAP -in your bashrc file. - -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? - -This is the consequence of building bash on SunOS 5 and linking -with the libraries in /usr/ucblib, but using the definitions -and structures from files in /usr/include. - -The actual conflict is between the dirent structure in -/usr/include/dirent.h and the struct returned by the version of -`readdir' in libucb.a (a 4.3-BSD style `struct direct'). - -Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH -when configuring and building bash. This will ensure that you -use /usr/ccs/bin/cc or acc instead of /usr/ucb/cc and that you -link with libc before libucb. - -If you have installed the Sun C compiler, you may also need to -put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before -/usr/ucb. - -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? - -This is a famous and long-standing bug in the SunOS YP (sorry, NIS) -client library, which is part of libc. - -The YP library code keeps static state -- a pointer into the data -returned from the server. When YP initializes itself (setpwent), -it looks at this pointer and calls free on it if it's non-null. -So far, so good. - -If one of the YP functions is interrupted during getpwent (the -exact function is interpretwithsave()), and returns NULL, the -pointer is freed without being reset to NULL, and the function -returns. The next time getpwent is called, it sees that this -pointer is non-null, calls free, and the bash free() blows up -because it's being asked to free freed memory. - -The traditional Unix mallocs allow memory to be freed multiple -times; that's probably why this has never been fixed. You can -run configure with the `--without-gnu-malloc' option to use -the C library malloc and avoid the problem. - -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? - -The `@' character is the default `line kill' character in most -versions of System V, including SVR4.2. You can change this -character to whatever you want using `stty'. For example, to -change the line kill character to control-u, type - - stty kill ^U - -where the `^' and `U' can be two separate characters. - -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? - -The actual command in question is something like - - < file ( command ) - -According to the grammar given in the POSIX.2 standard, this construct -is, in fact, a syntax error. Redirections may only precede `simple -commands'. A subshell construct such as the above is one of the shell's -`compound commands'. A redirection may only follow a compound command. - -This affects the mechanical transformation of commands that use `cat' -to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on -comp.unix.shell). While most commands of the form - - cat file | command - -can be converted to `< file command', shell control structures such as -loops and subshells require `command < file'. - -The file CWRU/sh-redir-hack in the bash-2.05a distribution is an -(unofficial) patch to parse.y that will modify the grammar to -support this construct. It will not apply with `patch'; you must -modify parse.y by hand. Note that if you apply this, you must -recompile with -DREDIRECTION_HACK. This introduces a large -number of reduce/reduce conflicts into the shell grammar. - -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? - -The short answer is that Red Hat screwed up. - -The long answer is that they shipped an /etc/inputrc that only works -for emacs mode editing, and then screwed all the vi users by setting -INPUTRC to /etc/inputrc in /etc/profile. - -The short fix is to do one of the following: remove or rename -/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, -but make sure you export it if you do), remove the assignment to -INPUTRC from /etc/profile, add - - set keymap emacs - -to the beginning of /etc/inputrc, or bracket the key bindings in -/etc/inputrc with these lines - - $if mode=emacs - [...] - $endif - -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -HP/UX's support for long double is imperfect at best. - -GCC will support it without problems, but the HP C library functions -like strtold(3) and printf(3) don't actually work with long doubles. -HP implemented a `long_double' type as a 4-element array of 32-bit -ints, and that is what the library functions use. The ANSI C -`long double' type is a 128-bit floating point scalar. - -The easiest fix, until HP fixes things up, is to edit the generated -config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, -the compilation should complete successfully. - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? - -This is a process requiring several steps. - -First, you must ensure that the `physical' data path is a full eight -bits. For xterms, for example, the `vt100' resources `eightBitInput' -and `eightBitOutput' should be set to `true'. - -Once you have set up an eight-bit path, you must tell the kernel and -tty driver to leave the eighth bit of characters alone when processing -keyboard input. Use `stty' to do this: - - stty cs8 -istrip -parenb - -For old BSD-style systems, you can use - - stty pass8 - -You may also need - - stty even odd - -Finally, you need to tell readline that you will be inputting and -displaying eight-bit characters. You use readline variables to do -this. These variables can be set in your .inputrc or using the bash -`bind' builtin. Here's an example using `bind': - - bash$ bind 'set convert-meta off' - bash$ bind 'set meta-flag on' - bash$ bind 'set output-meta on' - -The `set' commands between the single quotes may also be placed -in ~/.inputrc. - -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is why the `command' and `builtin' builtins exist. The -`command' builtin executes the command supplied as its first -argument, skipping over any function defined with that name. The -`builtin' builtin executes the builtin command given as its first -argument directly. - -For example, to write a function to replace `cd' that writes the -hostname and current directory to an xterm title bar, use -something like the following: - - cd() - { - builtin cd "$@" && xtitle "$HOST: $PWD" - } - -This could also be written using `command' instead of `builtin'; -the version above is marginally more efficient. - -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Versions of Bash newer than Bash-2.0 support this directly. You can use - - ${!var} - -For example, the following sequence of commands will echo `z': - - var1=var2 - var2=z - echo ${!var1} - -For sh compatibility, use the `eval' builtin. The important -thing to remember is that `eval' expands the arguments you give -it again, so you need to quote the parts of the arguments that -you want `eval' to act on. - -For example, this expression prints the value of the last positional -parameter: - - eval echo \"\$\{$#\}\" - -The expansion of the quoted portions of this expression will be -deferred until `eval' runs, while the `$#' will be expanded -before `eval' is executed. In versions of bash later than bash-2.0, - - echo ${!#} - -does the same thing. - -This is not the same thing as ksh93 `nameref' variables, though the syntax -is similar. I may add namerefs in a future bash version. - -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? - -The bash command timing code looks for a variable `TIMEFORMAT' and -uses its value as a format string to decide how to display the -timing statistics. - -The value of TIMEFORMAT is a string with `%' escapes expanded in a -fashion similar in spirit to printf(3). The manual page explains -the meanings of the escape sequences in the format string. - -If TIMEFORMAT is not set, bash acts as if the following assignment had -been performed: - - TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' - -The POSIX.2 default time format (used by `time -p command') is - - TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' - -The BSD /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' - -The System V /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' - -The ksh format can be emulated with: - - TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' - -G5) How do I get the current directory into my prompt? - -Bash provides a number of backslash-escape sequences which are expanded -when the prompt string (PS1 or PS2) is displayed. The full list is in -the manual page. - -The \w expansion gives the full pathname of the current directory, with -a tilde (`~') substituted for the current value of $HOME. The \W -expansion gives the basename of the current directory. To put the full -pathname of the current directory into the path without any tilde -subsitution, use $PWD. Here are some examples: - - PS1='\w$ ' # current directory with tilde - PS1='\W$ ' # basename of current directory - PS1='$PWD$ ' # full pathname of current directory - -The single quotes are important in the final example to prevent $PWD from -being expanded when the assignment to PS1 is performed. - -G6) How can I rename "*.foo" to "*.bar"? - -Use the pattern removal functionality described in D3. The following `for' -loop will do the trick: - - for f in *.foo; do - mv $f ${f%foo}bar - done - -G7) How can I translate a filename from uppercase to lowercase? - -The script examples/functions/lowercase, originally written by John DuBois, -will do the trick. The converse is left as an exercise. - -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -You must have set the `extglob' shell option using `shopt -s extglob' to use -this: - - echo .!(.|) * - -A solution that works without extended globbing is given in the Unix Shell -FAQ, posted periodically to comp.unix.shell. - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? - -Use the `bashbug' script to report bugs. It is built and -installed at the same time as bash. It provides a standard -template for reporting a problem and automatically includes -information about your configuration and build environment. - -`bashbug' sends its reports to bug-bash@gnu.org, which -is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. - -Bug fixes, answers to questions, and announcements of new releases -are all posted to gnu.bash.bug. Discussions concerning bash features -and problems also take place there. - -To reach the bash maintainers directly, send mail to -bash-maintainers@gnu.org. - -H2) What kind of bash documentation is there? - -First, look in the doc directory in the bash distribution. It should -contain at least the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -bashref.texi a reference manual in GNU tex`info format -bashref.info an info version of the reference manual -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript, HTML, and ASCII files created from the above source are -available in the documentation distribution. - -There is additional documentation available for anonymous FTP from host -ftp.cwru.edu in the `pub/bash' directory. - -Cameron Newham and Bill Rosenblatt have written a book on bash, published -by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn -Shell book. The title is ``Learning the Bash Shell'', and the ISBN number -is 1-56592-147-X. Look for it in fine bookstores near you. This book -covers bash-1.14, but has an appendix describing some of the new features -in bash-2.0. - -A second edition of this book is available, published in January, 1998. -The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores -or on the web. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers -bash-2.0 and is available from most online bookstores (see -http://www.network-theory.co.uk/bash/manual/ for details). The publisher -will donate $1 to the Free Software Foundation for each copy sold. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -a better bash debugger (a minimally-tested version is included with bash-2.05b) -associative arrays -co-processes, but with a new-style syntax that looks like function declaration - -H4) What's on the bash `wish list' for future versions? - -These are features that may or may not appear in a future version of bash. - -breaking some of the shell functionality into embeddable libraries -a module system like zsh's, using dynamic loading like builtins -better internationalization using GNU `gettext' -date-stamped command history -a bash programmer's guide with a chapter on creating loadable builtins -a better loadable interface to perl with access to the shell builtins and - variables (contributions gratefully accepted) -ksh93-like `nameref' variables -ksh93-like `+=' variable assignment operator -ksh93-like `xx.yy' variables (including some of the .sh.* variables) and - associated disipline functions -Some of the new ksh93 pattern matching operators, like backreferencing - -H5) When will the next release appear? - -The next version will appear sometime in 2002. Never make predictions. - - -This document is Copyright 1995-2003 by Chester Ramey. - -Permission is hereby granted, without written agreement and -without license or royalty fees, to use, copy, and distribute -this document for any purpose, provided that the above copyright -notice appears in all copies of this document and that the -contents of this document remain unaltered. diff --git a/doc/bash.1~ b/doc/bash.1~ deleted file mode 100644 index 8af3319ff..000000000 --- a/doc/bash.1~ +++ /dev/null @@ -1,10187 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Case Western Reserve University -.\" chet@po.cwru.edu -.\" -.\" Last Change: Thu Jul 5 11:10:13 EDT 2012 -.\" -.\" bash_builtins, strip all but Built-Ins section -.if \n(zZ=1 .ig zZ -.if \n(zY=1 .ig zY -.TH BASH 1 "2012 July 5" "GNU Bash 4.2" -.\" -.\" There's some problem with having a `@' -.\" in a tagged paragraph with the BSD man macros. -.\" It has to do with `@' appearing in the }1 macro. -.\" This is a problem on 4.3 BSD and Ultrix, but Sun -.\" appears to have fixed it. -.\" If you're seeing the characters -.\" `@u-3p' appearing before the lines reading -.\" `possible-hostname-completions -.\" and `complete-hostname' down in READLINE, -.\" then uncomment this redefinition. -.\" -.de }1 -.ds ]X \&\\*(]B\\ -.nr )E 0 -.if !"\\$1"" .nr )I \\$1n -.}f -.ll \\n(LLu -.in \\n()Ru+\\n(INu+\\n()Iu -.ti \\n(INu -.ie !\\n()Iu+\\n()Ru-\w\\*(]Xu-3p \{\\*(]X -.br\} -.el \\*(]X\h|\\n()Iu+\\n()Ru\c -.}f -.. -.\" -.\" File Name macro. This used to be `.PN', for Path Name, -.\" but Sun doesn't seem to like that very much. -.\" -.de FN -\fI\|\\$1\|\fP -.. -.SH NAME -bash \- GNU Bourne-Again SHell -.SH SYNOPSIS -.B bash -[options] -[command_string | file] -.SH COPYRIGHT -.if n Bash is Copyright (C) 1989-2012 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989-2012 by the Free Software Foundation, Inc. -.SH DESCRIPTION -.B Bash -is an \fBsh\fR-compatible command language interpreter that -executes commands read from the standard input or from a file. -.B Bash -also incorporates useful features from the \fIKorn\fP and \fIC\fP -shells (\fBksh\fP and \fBcsh\fP). -.PP -.B Bash -is intended to be a conformant implementation of the -Shell and Utilities portion of the IEEE POSIX specification -(IEEE Standard 1003.1). -.B Bash -can be configured to be POSIX-conformant by default. -.SH OPTIONS -All of the single-character shell options documented in the -description of the \fBset\fR builtin command can be used as options -when the shell is invoked. -In addition, \fBbash\fR -interprets the following options when it is invoked: -.PP -.PD 0 -.TP 10 -.B \-c -If the -.B \-c -option is present, then commands are read from the first non-option argument -.IR command_string . -If there are arguments after the -.IR command_string , -they are assigned to the positional parameters, starting with -.BR $0 . -.TP -.B \-i -If the -.B \-i -option is present, the shell is -.IR interactive . -.TP -.B \-l -Make -.B bash -act as if it had been invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-r -If the -.B \-r -option is present, the shell becomes -.I restricted -(see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-s -If the -.B \-s -option is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. -.TP -.B \-D -A list of all double-quoted strings preceded by \fB$\fP -is printed on the standard output. -These are the strings that -are subject to language translation when the current locale -is not \fBC\fP or \fBPOSIX\fP. -This implies the \fB\-n\fP option; no commands will be executed. -.TP -.B [\-+]O [\fIshopt_option\fP] -\fIshopt_option\fP is one of the shell options accepted by the -\fBshopt\fP builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -If \fIshopt_option\fP is present, \fB\-O\fP sets the value of that option; -\fB+O\fP unsets it. -If \fIshopt_option\fP is not supplied, the names and values of the shell -options accepted by \fBshopt\fP are printed on the standard output. -If the invocation option is \fB+O\fP, the output is displayed in a format -that may be reused as input. -.TP -.B \-\- -A -.B \-\- -signals the end of options and disables further option processing. -Any arguments after the -.B \-\- -are treated as filenames and arguments. An argument of -.B \- -is equivalent to \fB\-\-\fP. -.PD -.PP -.B Bash -also interprets a number of multi-character options. -These options must appear on the command line before the -single-character options to be recognized. -.PP -.PD 0 -.TP -.B \-\-debugger -Arrange for the debugger profile to be executed before the shell -starts. -Turns on extended debugging mode (see the description of the -.B extdebug -option to the -.B shopt -builtin below). -.TP -.B \-\-dump\-po\-strings -Equivalent to \fB\-D\fP, but the output is in the GNU \fIgettext\fP -\fBpo\fP (portable object) file format. -.TP -.B \-\-dump\-strings -Equivalent to \fB\-D\fP. -.TP -.B \-\-help -Display a usage message on standard output and exit successfully. -.TP -\fB\-\-init\-file\fP \fIfile\fP -.PD 0 -.TP -\fB\-\-rcfile\fP \fIfile\fP -.PD -Execute commands from -.I file -instead of the standard personal initialization file -.I ~/.bashrc -if the shell is interactive (see -.SM -.B INVOCATION -below). -.TP -.B \-\-login -Equivalent to \fB\-l\fP. -.TP -.B \-\-noediting -Do not use the GNU -.B readline -library to read command lines when the shell is interactive. -.TP -.B \-\-noprofile -Do not read either the system-wide startup file -.FN /etc/profile -or any of the personal initialization files -.IR ~/.bash_profile , -.IR ~/.bash_login , -or -.IR ~/.profile . -By default, -.B bash -reads these files when it is invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-\-norc -Do not read and execute the personal initialization file -.I ~/.bashrc -if the shell is interactive. -This option is on by default if the shell is invoked as -.BR sh . -.TP -.B \-\-posix -Change the behavior of \fBbash\fP where the default operation differs -from the POSIX standard to match the standard (\fIposix mode\fP). -.TP -.B \-\-restricted -The shell becomes restricted (see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-\-verbose -Equivalent to \fB\-v\fP. -.TP -.B \-\-version -Show version information for this instance of -.B bash -on the standard output and exit successfully. -.PD -.SH ARGUMENTS -If arguments remain after option processing, and neither the -.B \-c -nor the -.B \-s -option has been supplied, the first argument is assumed to -be the name of a file containing shell commands. -If -.B bash -is invoked in this fashion, -.B $0 -is set to the name of the file, and the positional parameters -are set to the remaining arguments. -.B Bash -reads and executes commands from this file, then exits. -\fBBash\fP's exit status is the exit status of the last command -executed in the script. -If no commands are executed, the exit status is 0. -An attempt is first made to open the file in the current directory, and, -if no file is found, then the shell searches the directories in -.SM -.B PATH -for the script. -.SH INVOCATION -A \fIlogin shell\fP is one whose first character of argument zero is a -.BR \- , -or one started with the -.B \-\-login -option. -.PP -An \fIinteractive\fP shell is one started without non-option arguments -and without the -.B \-c -option -whose standard input and error are -both connected to terminals (as determined by -.IR isatty (3)), -or one started with the -.B \-i -option. -.SM -.B PS1 -is set and -.B $\- -includes -.B i -if -.B bash -is interactive, -allowing a shell script or a startup file to test this state. -.PP -The following paragraphs describe how -.B bash -executes its startup files. -If any of the files exist but cannot be read, -.B bash -reports an error. -Tildes are expanded in filenames as described below under -.B "Tilde Expansion" -in the -.SM -.B EXPANSION -section. -.PP -When -.B bash -is invoked as an interactive login shell, or as a non-interactive shell -with the \fB\-\-login\fP option, it first reads and -executes commands from the file \fI/etc/profile\fP, if that -file exists. -After reading that file, it looks for \fI~/.bash_profile\fP, -\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads -and executes commands from the first one that exists and is readable. -The -.B \-\-noprofile -option may be used when the shell is started to inhibit this behavior. -.PP -When a login shell exits, -.B bash -reads and executes commands from the file \fI~/.bash_logout\fP, if it -exists. -.PP -When an interactive shell that is not a login shell is started, -.B bash -reads and executes commands from \fI~/.bashrc\fP, if that file exists. -This may be inhibited by using the -.B \-\-norc -option. -The \fB\-\-rcfile\fP \fIfile\fP option will force -.B bash -to read and execute commands from \fIfile\fP instead of \fI~/.bashrc\fP. -.PP -When -.B bash -is started non-interactively, to run a shell script, for example, it -looks for the variable -.SM -.B BASH_ENV -in the environment, expands its value if it appears there, and uses the -expanded value as the name of a file to read and execute. -.B Bash -behaves as if the following command were executed: -.sp .5 -.RS -.if t \f(CWif [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\fP -.if n if [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi -.RE -.sp .5 -but the value of the -.SM -.B PATH -variable is not used to search for the filename. -.PP -If -.B bash -is invoked with the name -.BR sh , -it tries to mimic the startup behavior of historical versions of -.B sh -as closely as possible, -while conforming to the POSIX standard as well. -When invoked as an interactive login shell, or a non-interactive -shell with the \fB\-\-login\fP option, it first attempts to -read and execute commands from -.I /etc/profile -and -.IR ~/.profile , -in that order. -The -.B \-\-noprofile -option may be used to inhibit this behavior. -When invoked as an interactive shell with the name -.BR sh , -.B bash -looks for the variable -.SM -.BR ENV , -expands its value if it is defined, and uses the -expanded value as the name of a file to read and execute. -Since a shell invoked as -.B sh -does not attempt to read and execute commands from any other startup -files, the -.B \-\-rcfile -option has no effect. -A non-interactive shell invoked with the name -.B sh -does not attempt to read any other startup files. -When invoked as -.BR sh , -.B bash -enters -.I posix -mode after the startup files are read. -.PP -When -.B bash -is started in -.I posix -mode, as with the -.B \-\-posix -command line option, it follows the POSIX standard for startup files. -In this mode, interactive shells expand the -.SM -.B ENV -variable and commands are read and executed from the file -whose name is the expanded value. -No other startup files are read. -.PP -.B Bash -attempts to determine when it is being run with its standard input -connected to a network connection, as when executed by the remote shell -daemon, usually \fIrshd\fP, or the secure shell daemon \fIsshd\fP. -If -.B bash -determines it is being run in this fashion, it reads and executes -commands from \fI~/.bashrc\fP, if that file exists and is readable. -It will not do this if invoked as \fBsh\fP. -The -.B \-\-norc -option may be used to inhibit this behavior, and the -.B \-\-rcfile -option may be used to force another file to be read, but -\fIrshd\fP does not generally invoke the shell with those options -or allow them to be specified. -.PP -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, no startup -files are read, shell functions are not inherited from the environment, the -.SM -.BR SHELLOPTS , -.SM -.BR BASHOPTS , -.SM -.BR CDPATH , -and -.SM -.B GLOBIGNORE -variables, if they appear in the environment, are ignored, -and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. -.SH DEFINITIONS -.PP -The following definitions are used throughout the rest of this -document. -.PD 0 -.TP -.B blank -A space or tab. -.TP -.B word -A sequence of characters considered as a single unit by the shell. -Also known as a -.BR token . -.TP -.B name -A -.I word -consisting only of alphanumeric characters and underscores, and -beginning with an alphabetic character or an underscore. Also -referred to as an -.BR identifier . -.TP -.B metacharacter -A character that, when unquoted, separates words. One of the following: -.br -.RS -.PP -.if t \fB| & ; ( ) < > space tab\fP -.if n \fB| & ; ( ) < > space tab\fP -.RE -.PP -.TP -.B control operator -A \fItoken\fP that performs a control function. It is one of the following -symbols: -.RS -.PP -.if t \fB|| & && ; ;; ( ) | |& \fP -.if n \fB|| & && ; ;; ( ) | |& \fP -.RE -.PD -.SH "RESERVED WORDS" -\fIReserved words\fP are words that have a special meaning to the shell. -The following words are recognized as reserved when unquoted and either -the first word of a simple command (see -.SM -.B SHELL GRAMMAR -below) or the third word of a -.B case -or -.B for -command: -.if t .RS -.PP -.B -.if n ! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t ! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t .RE -.SH "SHELL GRAMMAR" -.SS Simple Commands -.PP -A \fIsimple command\fP is a sequence of optional variable assignments -followed by \fBblank\fP-separated words and redirections, and -terminated by a \fIcontrol operator\fP. The first word -specifies the command to be executed, and is passed as argument zero. -The remaining words are passed as arguments to the invoked command. -.PP -The return value of a \fIsimple command\fP is its exit status, or -128+\fIn\^\fP if the command is terminated by signal -.IR n . -.SS Pipelines -.PP -A \fIpipeline\fP is a sequence of one or more commands separated by -one of the control operators -.B | -or \fB|&\fP. -The format for a pipeline is: -.RS -.PP -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ] -.RE -.PP -The standard output of -.I command -is connected via a pipe to the standard input of -.IR command2 . -This connection is performed before any redirections specified by the -command (see -.SM -.B REDIRECTION -below). -If \fB|&\fP is used, \fIcommand\fP's standard output and standard error -are connected to -\fIcommand2\fP's standard input through the pipe; -it is shorthand for \fB2>&1 |\fP. -This implicit redirection of the standard error is -performed after any redirections specified by the command. -.PP -The return status of a pipeline is the exit status of the last -command, unless the \fBpipefail\fP option is enabled. -If \fBpipefail\fP is enabled, the pipeline's return status is the -value of the last (rightmost) command to exit with a non-zero status, -or zero if all commands exit successfully. -If the reserved word -.B ! -precedes a pipeline, the exit status of that pipeline is the logical -negation of the exit status as described above. -The shell waits for all commands in the pipeline to -terminate before returning a value. -.PP -If the -.B time -reserved word precedes a pipeline, the elapsed as well as user and -system time consumed by its execution are reported when the pipeline -terminates. -The \fB\-p\fP option changes the output format to that specified by POSIX. -When the shell is in \fIposix mode\fP, it does not recognize -\fBtime\fP as a reserved word if the next token begins with a `-'. -The -.SM -.B TIMEFORMAT -variable may be set to a format string that specifies how the timing -information should be displayed; see the description of -.SM -.B TIMEFORMAT -under -.B "Shell Variables" -below. -.PP -When the shell is in \fIposix mode\fP, \fBtime\fP -may be followed by a newline. In this case, the shell displays the -total user and system time consumed by the shell and its children. -The -.SM -.B TIMEFORMAT -variable may be used to specify the format of -the time information. -.PP -Each command in a pipeline is executed as a separate process (i.e., in a -subshell). -.SS Lists -.PP -A \fIlist\fP is a sequence of one or more pipelines separated by one -of the operators -.BR ; , -.BR & , -.BR && , -or -.BR || , -and optionally terminated by one of -.BR ; , -.BR & , -or -.BR . -.PP -Of these list operators, -.B && -and -.B || -have equal precedence, followed by -.B ; -and -.BR & , -which have equal precedence. -.PP -A sequence of one or more newlines may appear in a \fIlist\fP instead -of a semicolon to delimit commands. -.PP -If a command is terminated by the control operator -.BR & , -the shell executes the command in the \fIbackground\fP -in a subshell. The shell does not wait for the command to -finish, and the return status is 0. Commands separated by a -.B ; -are executed sequentially; the shell waits for each -command to terminate in turn. The return status is the -exit status of the last command executed. -.PP -AND and OR lists are sequences of one of more pipelines separated by the -\fB&&\fP and \fB||\fP control operators, respectively. -AND and OR lists are executed with left associativity. -An AND list has the form -.RS -.PP -\fIcommand1\fP \fB&&\fP \fIcommand2\fP -.RE -.PP -.I command2 -is executed if, and only if, -.I command1 -returns an exit status of zero. -.PP -An OR list has the form -.RS -.PP -\fIcommand1\fP \fB||\fP \fIcommand2\fP -.PP -.RE -.PP -.I command2 -is executed if and only if -.I command1 -returns a non-zero exit status. -The return status of -AND and OR lists is the exit status of the last command -executed in the list. -.SS Compound Commands -.PP -A \fIcompound command\fP is one of the following. -In most cases a \fIlist\fP in a command's description may be separated from -the rest of the command by one or more newlines, and may be followed by a -newline in place of a semicolon. -.TP -(\fIlist\fP) -\fIlist\fP is executed in a subshell environment (see -.SM -\fBCOMMAND EXECUTION ENVIRONMENT\fP -below). -Variable assignments and builtin -commands that affect the shell's environment do not remain in effect -after the command completes. The return status is the exit status of -\fIlist\fP. -.TP -{ \fIlist\fP; } -\fIlist\fP is simply executed in the current shell environment. -\fIlist\fP must be terminated with a newline or semicolon. -This is known as a \fIgroup command\fP. -The return status is the exit status of -\fIlist\fP. -Note that unlike the metacharacters \fB(\fP and \fB)\fP, \fB{\fP and -\fB}\fP are \fIreserved words\fP and must occur where a reserved -word is permitted to be recognized. Since they do not cause a word -break, they must be separated from \fIlist\fP by whitespace or another -shell metacharacter. -.TP -((\fIexpression\fP)) -The \fIexpression\fP is evaluated according to the rules described -below under -.SM -.BR "ARITHMETIC EVALUATION" . -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -\fBlet "\fIexpression\fP"\fR. -.TP -\fB[[\fP \fIexpression\fP \fB]]\fP -Return a status of 0 or 1 depending on the evaluation of -the conditional expression \fIexpression\fP. -Expressions are composed of the primaries described below under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -Word splitting and pathname expansion are not performed on the words -between the \fB[[\fP and \fB]]\fP; tilde expansion, -parameter and variable expansion, -arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as \fB\-f\fP must be unquoted to be recognized -as primaries. -.if t .sp 0.5 -.if n .sp 1 -When used with \fB[[\fP, the \fB<\fP and \fB>\fP operators sort -lexicographically using the current locale. -.if t .sp 0.5 -.if n .sp 1 -When the \fB==\fP and \fB!=\fP operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below under \fBPattern Matching\fP. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (\fB==\fP) or does not match -(\fB!=\fP) the pattern, and 1 otherwise. -Any part of the pattern may be quoted to force the quoted portion -to be matched as a string. -.if t .sp 0.5 -.if n .sp 1 -An additional binary operator, \fB=~\fP, is available, with the same -precedence as \fB==\fP and \fB!=\fP. -When it is used, the string to the right of the operator is considered -an extended regular expression and matched accordingly (as in \fIregex\fP(3)). -The return value is 0 if the string matches -the pattern, and 1 otherwise. -If the regular expression is syntactically incorrect, the conditional -expression's return value is 2. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -Any part of the pattern may be quoted to force the quoted portion -to be matched as a string. -Bracket expressions in regular expressions must be treated carefully, -since normal quoting characters lose their meanings between brackets. -If the pattern is stored in a shell variable, quoting the variable -expansion forces the entire pattern to be matched as a string. -Substrings matched by parenthesized subexpressions within the regular -expression are saved in the array variable -.SM -.BR BASH_REMATCH . -The element of -.SM -.B BASH_REMATCH -with index 0 is the portion of the string -matching the entire regular expression. -The element of -.SM -.B BASH_REMATCH -with index \fIn\fP is the portion of the -string matching the \fIn\fPth parenthesized subexpression. -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence: -.if t .sp 0.5 -.if n .sp 1 -.RS -.PD 0 -.TP -.B ( \fIexpression\fP ) -Returns the value of \fIexpression\fP. -This may be used to override the normal precedence of operators. -.TP -.B ! \fIexpression\fP -True if -.I expression -is false. -.TP -\fIexpression1\fP \fB&&\fP \fIexpression2\fP -True if both -.I expression1 -and -.I expression2 -are true. -.TP -\fIexpression1\fP \fB||\fP \fIexpression2\fP -True if either -.I expression1 -or -.I expression2 -is true. -.PD -.LP -The \fB&&\fP and \fB||\fP -operators do not evaluate \fIexpression2\fP if the value of -\fIexpression1\fP is sufficient to determine the return value of -the entire conditional expression. -.RE -.TP -\fBfor\fP \fIname\fP [ [ \fBin\fP [ \fIword ...\fP ] ] ; ] \fBdo\fP \fIlist\fP ; \fBdone\fP -The list of words following \fBin\fP is expanded, generating a list -of items. -The variable \fIname\fP is set to each element of this list -in turn, and \fIlist\fP is executed each time. -If the \fBin\fP \fIword\fP is omitted, the \fBfor\fP command executes -\fIlist\fP once for each positional parameter that is set (see -.SM -.B PARAMETERS -below). -The return status is the exit status of the last command that executes. -If the expansion of the items following \fBin\fP results in an empty -list, no commands are executed, and the return status is 0. -.TP -\fBfor\fP (( \fIexpr1\fP ; \fIexpr2\fP ; \fIexpr3\fP )) ; \fBdo\fP \fIlist\fP ; \fBdone\fP -First, the arithmetic expression \fIexpr1\fP is evaluated according -to the rules described below under -.SM -.BR "ARITHMETIC EVALUATION" . -The arithmetic expression \fIexpr2\fP is then evaluated repeatedly -until it evaluates to zero. -Each time \fIexpr2\fP evaluates to a non-zero value, \fIlist\fP is -executed and the arithmetic expression \fIexpr3\fP is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in \fIlist\fP -that is executed, or false if any of the expressions is invalid. -.TP -\fBselect\fP \fIname\fP [ \fBin\fP \fIword\fP ] ; \fBdo\fP \fIlist\fP ; \fBdone\fP -The list of words following \fBin\fP is expanded, generating a list -of items. The set of expanded words is printed on the standard -error, each preceded by a number. If the \fBin\fP -\fIword\fP is omitted, the positional parameters are printed (see -.SM -.B PARAMETERS -below). The -.SM -.B PS3 -prompt is then displayed and a line read from the standard input. -If the line consists of a number corresponding to one of -the displayed words, then the value of -.I name -is set to that word. If the line is empty, the words and prompt -are displayed again. If EOF is read, the command completes. Any -other value read causes -.I name -to be set to null. The line read is saved in the variable -.SM -.BR REPLY . -The -.I list -is executed after each selection until a -.B break -command is executed. -The exit status of -.B select -is the exit status of the last command executed in -.IR list , -or zero if no commands were executed. -.TP -\fBcase\fP \fIword\fP \fBin\fP [ [(] \fIpattern\fP [ \fB|\fP \fIpattern\fP ] \ -... ) \fIlist\fP ;; ] ... \fBesac\fP -A \fBcase\fP command first expands \fIword\fP, and tries to match -it against each \fIpattern\fP in turn, using the same matching rules -as for pathname expansion (see -.B Pathname Expansion -below). -The \fIword\fP is expanded using tilde -expansion, parameter and variable expansion, arithmetic substitution, -command substitution, process substitution and quote removal. -Each \fIpattern\fP examined is expanded using tilde -expansion, parameter and variable expansion, arithmetic substitution, -command substitution, and process substitution. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -When a match is found, the corresponding \fIlist\fP is executed. -If the \fB;;\fP operator is used, no subsequent matches are attempted after -the first pattern match. -Using \fB;&\fP in place of \fB;;\fP causes execution to continue with -the \fIlist\fP associated with the next set of patterns. -Using \fB;;&\fP in place of \fB;;\fP causes the shell to test the next -pattern list in the statement, if any, and execute any associated \fIlist\fP -on a successful match. -The exit status is zero if no -pattern matches. Otherwise, it is the exit status of the -last command executed in \fIlist\fP. -.TP -\fBif\fP \fIlist\fP; \fBthen\fP \fIlist;\fP \ -[ \fBelif\fP \fIlist\fP; \fBthen\fP \fIlist\fP; ] ... \ -[ \fBelse\fP \fIlist\fP; ] \fBfi\fP -The -.B if -.I list -is executed. If its exit status is zero, the -\fBthen\fP \fIlist\fP is executed. Otherwise, each \fBelif\fP -\fIlist\fP is executed in turn, and if its exit status is zero, -the corresponding \fBthen\fP \fIlist\fP is executed and the -command completes. Otherwise, the \fBelse\fP \fIlist\fP is -executed, if present. The exit status is the exit status of the -last command executed, or zero if no condition tested true. -.TP -\fBwhile\fP \fIlist-1\fP; \fBdo\fP \fIlist-2\fP; \fBdone\fP -.PD 0 -.TP -\fBuntil\fP \fIlist-1\fP; \fBdo\fP \fIlist-2\fP; \fBdone\fP -.PD -The \fBwhile\fP command continuously executes the list -\fIlist-2\fP as long as the last command in the list \fIlist-1\fP returns -an exit status of zero. The \fBuntil\fP command is identical -to the \fBwhile\fP command, except that the test is negated; -.I list-2 -is executed as long as the last command in -.I list-1 -returns a non-zero exit status. -The exit status of the \fBwhile\fP and \fBuntil\fP commands -is the exit status -of the last command executed in \fIlist-2\fP, or zero if -none was executed. -.SS Coprocesses -.PP -A \fIcoprocess\fP is a shell command preceded by the \fBcoproc\fP reserved -word. -A coprocess is executed asynchronously in a subshell, as if the command -had been terminated with the \fB&\fP control operator, with a two-way pipe -established between the executing shell and the coprocess. -.PP -The format for a coprocess is: -.RS -.PP -\fBcoproc\fP [\fINAME\fP] \fIcommand\fP [\fIredirections\fP] -.RE -.PP -This creates a coprocess named \fINAME\fP. -If \fINAME\fP is not supplied, the default name is \fBCOPROC\fP. -\fINAME\fP must not be supplied if \fIcommand\fP is a \fIsimple -command\fP (see above); otherwise, it is interpreted as the first word -of the simple command. -When the coprocess is executed, the shell creates an array variable (see -.B Arrays -below) named \fINAME\fP in the context of the executing shell. -The standard output of -.I command -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to \fINAME\fP[0]. -The standard input of -.I command -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to \fINAME\fP[1]. -This pipe is established before any redirections specified by the -command (see -.SM -.B REDIRECTION -below). -The file descriptors can be utilized as arguments to shell commands -and redirections using standard word expansions. -The file descriptors are not available in subshells. -The process ID of the shell spawned to execute the coprocess is -available as the value of the variable \fINAME\fP_PID. -The \fBwait\fP -builtin command may be used to wait for the coprocess to terminate. -.PP -The return status of a coprocess is the exit status of \fIcommand\fP. -.SS Shell Function Definitions -.PP -A shell function is an object that is called like a simple command and -executes a compound command with a new set of positional parameters. -Shell functions are declared as follows: -.TP -\fIname\fP () \fIcompound\-command\fP [\fIredirection\fP] -.PD 0 -.TP -\fBfunction\fP \fIname\fP [()] \fIcompound\-command\fP [\fIredirection\fP] -.PD -This defines a function named \fIname\fP. -The reserved word \fBfunction\fP is optional. -If the \fBfunction\fP reserved word is supplied, the parentheses are optional. -The \fIbody\fP of the function is the compound command -.I compound\-command -(see \fBCompound Commands\fP above). -That command is usually a \fIlist\fP of commands between { and }, but -may be any command listed under \fBCompound Commands\fP above. -\fIcompound\-command\fP is executed whenever \fIname\fP is specified as the -name of a simple command. -When in \fIposix mode\fP, \fIname\fP may not be the name of one of the -POSIX \fIspecial builtins\fP. -Any redirections (see -.SM -.B REDIRECTION -below) specified when a function is defined are performed -when the function is executed. -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -last command executed in the body. (See -.SM -.B FUNCTIONS -below.) -.SH COMMENTS -In a non-interactive shell, or an interactive shell in which the -.B interactive_comments -option to the -.B shopt -builtin is enabled (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), a word beginning with -.B # -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the -.B interactive_comments -option enabled does not allow comments. The -.B interactive_comments -option is on by default in interactive shells. -.SH QUOTING -\fIQuoting\fP is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -disable special treatment for special characters, to prevent -reserved words from being recognized as such, and to prevent -parameter expansion. -.PP -Each of the \fImetacharacters\fP listed above under -.SM -.B DEFINITIONS -has special meaning to the shell and must be quoted if it is to -represent itself. -.PP -When the command history expansion facilities are being used -(see -.SM -.B HISTORY EXPANSION -below), the -\fIhistory expansion\fP character, usually \fB!\fP, must be quoted -to prevent history expansion. -.PP -There are three quoting mechanisms: the -.IR "escape character" , -single quotes, and double quotes. -.PP -A non-quoted backslash (\fB\e\fP) is the -.IR "escape character" . -It preserves the literal value of the next character that follows, -with the exception of . If a \fB\e\fP pair -appears, and the backslash is not itself quoted, the \fB\e\fP -is treated as a line continuation (that is, it is removed from the -input stream and effectively ignored). -.PP -Enclosing characters in single quotes preserves the literal value -of each character within the quotes. A single quote may not occur -between single quotes, even when preceded by a backslash. -.PP -Enclosing characters in double quotes preserves the literal value -of all characters within the quotes, with the exception of -.BR $ , -.BR \` , -.BR \e , -and, when history expansion is enabled, -.BR ! . -The characters -.B $ -and -.B \` -retain their special meaning within double quotes. The backslash -retains its special meaning only when followed by one of the following -characters: -.BR $ , -.BR \` , -\^\fB"\fP\^, -.BR \e , -or -.BR . -A double quote may be quoted within double quotes by preceding it with -a backslash. -If enabled, history expansion will be performed unless an -.B ! -appearing in double quotes is escaped using a backslash. -The backslash preceding the -.B ! -is not removed. -.PP -The special parameters -.B * -and -.B @ -have special meaning when in double -quotes (see -.SM -.B PARAMETERS -below). -.PP -Words of the form \fB$\fP\(aq\fIstring\fP\(aq are treated specially. The -word expands to \fIstring\fP, with backslash-escaped characters replaced -as specified by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ee -.TP -.B \eE -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e\(aq -single quote -.TP -.B \e\(dq -double quote -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.TP -.B \eu\fIHHHH\fP -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -\fIHHHH\fP (one to four hex digits) -.TP -.B \eU\fIHHHHHHHH\fP -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -\fIHHHHHHHH\fP (one to eight hex digits) -.TP -.B \ec\fIx\fP -a control-\fIx\fP character -.PD -.RE -.LP -The expanded result is single-quoted, as if the dollar sign had -not been present. -.PP -A double-quoted string preceded by a dollar sign (\fB$\fP\(dq\fIstring\fP\(dq) -will cause the string to be translated according to the current locale. -If the current locale is \fBC\fP or \fBPOSIX\fP, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. -.SH PARAMETERS -A -.I parameter -is an entity that stores values. -It can be a -.IR name , -a number, or one of the special characters listed below under -.BR "Special Parameters" . -A -.I variable -is a parameter denoted by a -.IR name . -A variable has a \fIvalue\fP and zero or more \fIattributes\fP. -Attributes are assigned using the -.B declare -builtin command (see -.B declare -below in -.SM -.BR "SHELL BUILTIN COMMANDS" ). -.PP -A parameter is set if it has been assigned a value. The null string is -a valid value. Once a variable is set, it may be unset only by using -the -.B unset -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.PP -A -.I variable -may be assigned to by a statement of the form -.RS -.PP -\fIname\fP=[\fIvalue\fP] -.RE -.PP -If -.I value -is not given, the variable is assigned the null string. All -.I values -undergo tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote -removal (see -.SM -.B EXPANSION -below). If the variable has its -.B integer -attribute set, then -.I value -is evaluated as an arithmetic expression even if the $((...)) expansion is -not used (see -.B "Arithmetic Expansion" -below). -Word splitting is not performed, with the exception -of \fB"$@"\fP as explained below under -.BR "Special Parameters" . -Pathname expansion is not performed. -Assignment statements may also appear as arguments to the -.BR alias , -.BR declare , -.BR typeset , -.BR export , -.BR readonly , -and -.B local -builtin commands. -When in \fIposix mode\fP, these builtins may appear in a command after -one or more instances of the \fBcommand\fP builtin and retain these -assignment statement properties. -.PP -In the context where an assignment statement is assigning a value -to a shell variable or array index, the += operator can be used to -append to or add to the variable's previous value. -When += is applied to a variable for which the \fIinteger\fP attribute has been -set, \fIvalue\fP is evaluated as an arithmetic expression and added to the -variable's current value, which is also evaluated. -When += is applied to an array variable using compound assignment (see -.B Arrays -below), the -variable's value is not unset (as it is when using =), and new values are -appended to the array beginning at one greater than the array's maximum index -(for indexed arrays) or added as additional key\-value pairs in an -associative array. -When applied to a string-valued variable, \fIvalue\fP is expanded and -appended to the variable's value. -.PP -A variable can be assigned the \fInameref\fP attribute using the -\fB\-n\fP option to the \fBdeclare\fP or \fBlocal\fP builtin commands -(see the descriptions of \fBdeclare\fP and \fBlocal\fP below) -to create a \fInameref\fP, or a reference to another variable. -This allows variables to be manipulated indirectly. -Whenever the nameref variable is referenced or assigned to, the operation -is actually performed on the variable specified by the nameref variable's -value. -A nameref is commonly used within shell functions to refer to a variable -whose name is passed as an argument to the function. -For instance, if a variable name is passed to a shell function as its first -argument, running -.sp .5 -.RS -.if t \f(CWdeclare -n ref=$1\fP -.if n declare -n ref=$1 -.RE -.sp .5 -inside the function creates a nameref variable \fBref\fP whose value is -the variable name passed as the first argument. -References and assignments to \fBref\fP are treated as references and -assignments to the variable whose name was passed as \fB$1\fP. -If the control variable in a \fBfor\fP loop has the nameref attribute, -the list of words can be a list of shell variables, and a name reference -will be established for each word in the list, in turn, when the loop is -executed. -Array variables cannot be given the \fB\-n\fP attribute. -However, nameref variables can reference array variables and subscripted -array variables. -Namerefs can be unset using the \fB\-n\fP option to the \fBunset\fP builtin. -Otherwise, if \fBunset\fP is executed with the name of a nameref variable -as an argument, the variable referenced by the nameref variable will be unset. -.SS Positional Parameters -.PP -A -.I positional parameter -is a parameter denoted by one or more -digits, other than the single digit 0. Positional parameters are -assigned from the shell's arguments when it is invoked, -and may be reassigned using the -.B set -builtin command. Positional parameters may not be assigned to -with assignment statements. The positional parameters are -temporarily replaced when a shell function is executed (see -.SM -.B FUNCTIONS -below). -.PP -When a positional parameter consisting of more than a single -digit is expanded, it must be enclosed in braces (see -.SM -.B EXPANSION -below). -.SS Special Parameters -.PP -The shell treats several parameters specially. These parameters may -only be referenced; assignment to them is not allowed. -.PD 0 -.TP -.B * -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, it expands to a single word -with the value of each parameter separated by the first character -of the -.SM -.B IFS -special variable. That is, "\fB$*\fP" is equivalent -to "\fB$1\fP\fIc\fP\fB$2\fP\fIc\fP\fB...\fP", where -.I c -is the first character of the value of the -.SM -.B IFS -variable. If -.SM -.B IFS -is unset, the parameters are separated by spaces. -If -.SM -.B IFS -is null, the parameters are joined without intervening separators. -.TP -.B @ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, "\fB$@\fP" is equivalent to -"\fB$1\fP" "\fB$2\fP" ... -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, "\fB$@\fP" and -.B $@ -expand to nothing (i.e., they are removed). -.TP -.B # -Expands to the number of positional parameters in decimal. -.TP -.B ? -Expands to the exit status of the most recently executed foreground -pipeline. -.TP -.B \- -Expands to the current option flags as specified upon invocation, -by the -.B set -builtin command, or those set by the shell itself -(such as the -.B \-i -option). -.TP -.B $ -Expands to the process ID of the shell. In a () subshell, it -expands to the process ID of the current shell, not the -subshell. -.TP -.B ! -Expands to the process ID of the most recently executed background -(asynchronous) command. -.TP -.B 0 -Expands to the name of the shell or shell script. This is set at -shell initialization. If -.B bash -is invoked with a file of commands, -.B $0 -is set to the name of that file. If -.B bash -is started with the -.B \-c -option, then -.B $0 -is set to the first argument after the string to be -executed, if one is present. Otherwise, it is set -to the filename used to invoke -.BR bash , -as given by argument zero. -.TP -.B _ -At shell startup, set to the absolute pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -When checking mail, this parameter holds the name of the mail file -currently being checked. -.PD -.SS Shell Variables -.PP -The following variables are set by the shell: -.PP -.PD 0 -.TP -.B BASH -Expands to the full filename used to invoke this instance of -.BR bash . -.TP -.B BASHOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the -.B \-s -option to the -.B shopt -builtin command (see -.SM -.B "SHELL BUILTIN COMMANDS" -below). The options appearing in -.SM -.B BASHOPTS -are those reported as -.I on -by \fBshopt\fP. -If this variable is in the environment when -.B bash -starts up, each shell option in the list will be enabled before -reading any startup files. -This variable is read-only. -.TP -.B BASHPID -Expands to the process ID of the current \fBbash\fP process. -This differs from \fB$$\fP under certain circumstances, such as subshells -that do not require \fBbash\fP to be re-initialized. -.TP -.B BASH_ALIASES -An associative array variable whose members correspond to the internal -list of aliases as maintained by the \fBalias\fP builtin. -Elements added to this array appear in the alias list; unsetting array -elements cause aliases to be removed from the alias list. -.TP -.B BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current \fBbash\fP execution call stack. -The number of -parameters to the current subroutine (shell function or script executed -with \fB.\fP or \fBsource\fP) is at the top of the stack. -When a subroutine is executed, the number of parameters passed is pushed onto -.SM -.BR BASH_ARGC . -The shell sets -.SM -.B BASH_ARGC -only when in extended debugging mode (see the description of the -.B extdebug -option to the -.B shopt -builtin below) -.TP -.B BASH_ARGV -An array variable containing all of the parameters in the current \fBbash\fP -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto -.SM -.BR BASH_ARGV . -The shell sets -.SM -.B BASH_ARGV -only when in extended debugging mode -(see the description of the -.B extdebug -option to the -.B shopt -builtin below) -.TP -.B BASH_CMDS -An associative array variable whose members correspond to the internal -hash table of commands as maintained by the \fBhash\fP builtin. -Elements added to this array appear in the hash table; unsetting array -elements cause commands to be removed from the hash table. -.TP -.B BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. -.TP -.B BASH_EXECUTION_STRING -The command argument to the \fB\-c\fP invocation option. -.TP -.B BASH_LINENO -An array variable whose members are the line numbers in source files -where each corresponding member of -.SM -.B FUNCNAME -was invoked. -\fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -file (\fB${BASH_SOURCE[\fP\fI$i+1\fP\fB]}\fP) where -\fB${FUNCNAME[\fP\fI$i\fP\fB]}\fP was called -(or \fB${BASH_LINENO[\fP\fI$i-1\fP\fB]}\fP if referenced within another -shell function). -Use -.SM -.B LINENO -to obtain the current line number. -.TP -.B BASH_REMATCH -An array variable whose members are assigned by the \fB=~\fP binary -operator to the \fB[[\fP conditional command. -The element with index 0 is the portion of the string -matching the entire regular expression. -The element with index \fIn\fP is the portion of the -string matching the \fIn\fPth parenthesized subexpression. -This variable is read-only. -.TP -.B BASH_SOURCE -An array variable whose members are the source filenames -where the corresponding shell function names in the -.SM -.B FUNCNAME -array variable are defined. -The shell function -\fB${FUNCNAME[\fP\fI$i\fP\fB]}\fP is defined in the file -\fB${BASH_SOURCE[\fP\fI$i\fP\fB]}\fP and called from -\fB${BASH_SOURCE[\fP\fI$i+1\fP\fB]}\fP. -.TP -.B BASH_SUBSHELL -Incremented by one within each subshell or subshell environment when -the shell begins executing in that environment. -The initial value is 0. -.TP -.B BASH_VERSINFO -A readonly array variable whose members hold version information for -this instance of -.BR bash . -The values assigned to the array members are as follows: -.sp .5 -.RS -.TP 24 -.B BASH_VERSINFO[\fR0\fP] -The major version number (the \fIrelease\fP). -.TP -.B BASH_VERSINFO[\fR1\fP] -The minor version number (the \fIversion\fP). -.TP -.B BASH_VERSINFO[\fR2\fP] -The patch level. -.TP -.B BASH_VERSINFO[\fR3\fP] -The build version. -.TP -.B BASH_VERSINFO[\fR4\fP] -The release status (e.g., \fIbeta1\fP). -.TP -.B BASH_VERSINFO[\fR5\fP] -The value of -.SM -.BR MACHTYPE . -.RE -.TP -.B BASH_VERSION -Expands to a string describing the version of this instance of -.BR bash . -.TP -.B COMP_CWORD -An index into \fB${COMP_WORDS}\fP of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_KEY -The key (or final key of a key sequence) used to invoke the current -completion function. -.TP -.B COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to \fB${#COMP_LINE}\fP. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_TYPE -Set to an integer value corresponding to the type of completion attempted -that caused a completion function to be called: -\fITAB\fP, for normal completion, -\fI?\fP, for listing completions after successive tabs, -\fI!\fP, for listing alternatives on partial word completion, -\fI@\fP, to list completions if the word is not unmodified, -or -\fI%\fP, for menu completion. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COMP_WORDBREAKS -The set of characters that the \fBreadline\fP library treats as word -separators when performing word completion. -If -.SM -.B COMP_WORDBREAKS -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B COMP_WORDS -An array variable (see \fBArrays\fP below) consisting of the individual -words in the current command line. -The line is split into words as \fBreadline\fP would split it, using -.SM -.B COMP_WORDBREAKS -as described above. -This variable is available only in shell functions invoked by the -programmable completion facilities (see \fBProgrammable Completion\fP -below). -.TP -.B COPROC -An array variable (see \fBArrays\fP below) created to hold the file descriptors -for output from and input to an unnamed coprocess (see \fBCoprocesses\fP -above). -.TP -.B DIRSTACK -An array variable (see -.B Arrays -below) containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -.B dirs -builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the -.B pushd -and -.B popd -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If -.SM -.B DIRSTACK -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B EUID -Expands to the effective user ID of the current user, initialized at -shell startup. This variable is readonly. -.TP -.B FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element (the one with the highest index) is -.if t \f(CW"main"\fP. -.if n "main". -This variable exists only when a shell function is executing. -Assignments to -.SM -.B FUNCNAME -have no effect and return an error status. -If -.SM -.B FUNCNAME -is unset, it loses its special properties, even if it is -subsequently reset. -.if t .sp 0.5 -.if n .sp 1 -This variable can be used with \fBBASH_LINENO\fP and \fBBASH_SOURCE\fP. -Each element of \fBFUNCNAME\fP has corresponding elements in -\fBBASH_LINENO\fP and \fBBASH_SOURCE\fP to describe the call stack. -For instance, \fB${FUNCNAME[\fP\fI$i\fP\fB]}\fP was called from the file -\fB${BASH_SOURCE[\fP\fI$i+1\fP\fB]}\fP at line number -\fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP. -The \fBcaller\fP builtin displays the current call stack using this -information. -.TP -.B GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to -.SM -.B GROUPS -have no effect and return an error status. -If -.SM -.B GROUPS -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B HISTCMD -The history number, or index in the history list, of the current -command. -If -.SM -.B HISTCMD -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B HOSTNAME -Automatically set to the name of the current host. -.TP -.B HOSTTYPE -Automatically set to a string that uniquely -describes the type of machine on which -.B bash -is executing. -The default is system-dependent. -.TP -.B LINENO -Each time this parameter is referenced, the shell substitutes -a decimal number representing the current sequential line number -(starting with 1) within a script or function. When not in a -script or function, the value substituted is not guaranteed to -be meaningful. -If -.SM -.B LINENO -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B MACHTYPE -Automatically set to a string that fully describes the system -type on which -.B bash -is executing, in the standard GNU \fIcpu-company-system\fP format. -The default is system-dependent. -.TP -.B MAPFILE -An array variable (see \fBArrays\fP below) created to hold the text -read by the \fBmapfile\fP builtin when no variable name is supplied. -.TP -.B OLDPWD -The previous working directory as set by the -.B cd -command. -.TP -.B OPTARG -The value of the last option argument processed by the -.B getopts -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.TP -.B OPTIND -The index of the next argument to be processed by the -.B getopts -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.TP -.B OSTYPE -Automatically set to a string that -describes the operating system on which -.B bash -is executing. -The default is system-dependent. -.TP -.B PIPESTATUS -An array variable (see -.B Arrays -below) containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). -.TP -.B PPID -The process ID of the shell's parent. This variable is readonly. -.TP -.B PWD -The current working directory as set by the -.B cd -command. -.TP -.B RANDOM -Each time this parameter is referenced, a random integer between -0 and 32767 is -generated. The sequence of random numbers may be initialized by assigning -a value to -.SM -.BR RANDOM . -If -.SM -.B RANDOM -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B READLINE_LINE -The contents of the -.B readline -line buffer, for use with -.if t \f(CWbind -x\fP -.if n "bind -x" -(see -.SM -.B "SHELL BUILTIN COMMANDS" -below). -.TP -.B READLINE_POINT -The position of the insertion point in the -.B readline -line buffer, for use with -.if t \f(CWbind -x\fP -.if n "bind -x" -(see -.SM -.B "SHELL BUILTIN COMMANDS" -below). -.TP -.B REPLY -Set to the line of input read by the -.B read -builtin command when no arguments are supplied. -.TP -.B SECONDS -Each time this parameter is -referenced, the number of seconds since shell invocation is returned. If a -value is assigned to -.SM -.BR SECONDS , -the value returned upon subsequent -references is -the number of seconds since the assignment plus the value assigned. -If -.SM -.B SECONDS -is unset, it loses its special properties, even if it is -subsequently reset. -.TP -.B SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the -.B \-o -option to the -.B set -builtin command (see -.SM -.B "SHELL BUILTIN COMMANDS" -below). The options appearing in -.SM -.B SHELLOPTS -are those reported as -.I on -by \fBset \-o\fP. -If this variable is in the environment when -.B bash -starts up, each shell option in the list will be enabled before -reading any startup files. -This variable is read-only. -.TP -.B SHLVL -Incremented by one each time an instance of -.B bash -is started. -.TP -.B UID -Expands to the user ID of the current user, initialized at shell startup. -This variable is readonly. -.PD -.PP -The following variables are used by the shell. In some cases, -.B bash -assigns a default value to a variable; these cases are noted -below. -.PP -.PD 0 -.TP -.B BASH_ENV -If this parameter is set when \fBbash\fP is executing a shell script, -its value is interpreted as a filename containing commands to -initialize the shell, as in -.IR ~/.bashrc . -The value of -.SM -.B BASH_ENV -is subjected to parameter expansion, command substitution, and arithmetic -expansion before being interpreted as a filename. -.SM -.B PATH -is not used to search for the resultant filename. -.TP -.B BASH_XTRACEFD -If set to an integer corresponding to a valid file descriptor, \fBbash\fP -will write the trace output generated when -.if t \f(CWset -x\fP -.if n \fIset -x\fP -is enabled to that file descriptor. -The file descriptor is closed when -.SM -.B BASH_XTRACEFD -is unset or assigned a new value. -Unsetting -.SM -.B BASH_XTRACEFD -or assigning it the empty string causes the -trace output to be sent to the standard error. -Note that setting -.SM -.B BASH_XTRACEFD -to 2 (the standard error file -descriptor) and then unsetting it will result in the standard error -being closed. -.TP -.B CDPATH -The search path for the -.B cd -command. -This is a colon-separated list of directories in which the shell looks -for destination directories specified by the -.B cd -command. -A sample value is -.if t \f(CW".:~:/usr"\fP. -.if n ".:~:/usr". -.TP -.B COLUMNS -Used by the \fBselect\fP compound command to determine the terminal width -when printing selection lists. Automatically set in an interactive shell -upon receipt of a -.SM -.BR SIGWINCH . -.TP -.B COMPREPLY -An array variable from which \fBbash\fP reads the possible completions -generated by a shell function invoked by the programmable completion -facility (see \fBProgrammable Completion\fP below). -Each array element contains one possible completion. -.TP -.B EMACS -If \fBbash\fP finds this variable in the environment when the shell starts -with value -.if t \f(CWt\fP, -.if n "t", -it assumes that the shell is running in an Emacs shell buffer and disables -line editing. -.TP -.B ENV -Similar to -.SM -.BR BASH_ENV ; -used when the shell is invoked in POSIX mode. -.TP -.B FCEDIT -The default editor for the -.B fc -builtin command. -.TP -.B FIGNORE -A colon-separated list of suffixes to ignore when performing -filename completion (see -.SM -.B READLINE -below). -A filename whose suffix matches one of the entries in -.SM -.B FIGNORE -is excluded from the list of matched filenames. -A sample value is -.if t \f(CW".o:~"\fP. -.if n ".o:~". -.TP -.B FUNCNEST -If set to a numeric value greater than 0, defines a maximum function -nesting level. Function invocations that exceed this nesting level -will cause the current command to abort. -.TP -.B GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by pathname expansion. -If a filename matched by a pathname expansion pattern also matches one -of the patterns in -.SM -.BR GLOBIGNORE , -it is removed from the list of matches. -.TP -.B HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes -.IR ignorespace , -lines which begin with a -.B space -character are not saved in the history list. -A value of -.I ignoredups -causes lines matching the previous history entry to not be saved. -A value of -.I ignoreboth -is shorthand for \fIignorespace\fP and \fIignoredups\fP. -A value of -.IR erasedups -causes all previous lines matching the current line to be removed from -the history list before that line is saved. -Any value not in the above list is ignored. -If -.SM -.B HISTCONTROL -is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of -.SM -.BR HISTIGNORE . -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.SM -.BR HISTCONTROL . -.TP -.B HISTFILE -The name of the file in which command history is saved (see -.SM -.B HISTORY -below). The default value is \fI~/.bash_history\fP. If unset, the -command history is not saved when a shell exits. -.TP -.B HISTFILESIZE -The maximum number of lines contained in the history file. When this -variable is assigned a value, the history file is truncated, if -necessary, -to contain no more than that number of lines by removing the oldest entries. -The history file is also truncated to this size after -writing it when a shell exits. -If the value is 0, the history file is truncated to zero size. -Non-numeric values and numeric values less than zero inhibit truncation. -The shell sets the default value to the value of \fBHISTSIZE\fP -after reading any startup files. -.TP -.B HISTIGNORE -A colon-separated list of patterns used to decide which command lines -should be saved on the history list. Each pattern is anchored at the -beginning of the line and must match the complete line (no implicit -`\fB*\fP' is appended). Each pattern is tested against the line -after the checks specified by -.SM -.B HISTCONTROL -are applied. -In addition to the normal shell pattern matching characters, `\fB&\fP' -matches the previous history line. `\fB&\fP' may be escaped using a -backslash; the backslash is removed before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -.SM -.BR HISTIGNORE . -.TP -.B HISTSIZE -The number of commands to remember in the command history (see -.SM -.B HISTORY -below). -If the value is 0, commands are not saved in the history list. -Numeric values less than zero result in every command being saved -on the history list (there is no limit). -The shell sets the default value to 500 after reading any startup files. -.TP -.B HISTTIMEFORMAT -If this variable is set and not null, its value is used as a format string -for \fIstrftime\fP(3) to print the time stamp associated with each history -entry displayed by the \fBhistory\fP builtin. -If this variable is set, time stamps are written to the history file so -they may be preserved across shell sessions. -This uses the history comment character to distinguish timestamps from -other history lines. -.TP -.B HOME -The home directory of the current user; the default argument for the -\fBcd\fP builtin command. -The value of this variable is also used when performing tilde expansion. -.TP -.B HOSTFILE -Contains the name of a file in the same format as -.FN /etc/hosts -that should be read when the shell needs to complete a -hostname. -The list of possible hostname completions may be changed while the -shell is running; -the next time hostname completion is attempted after the -value is changed, -.B bash -adds the contents of the new file to the existing list. -If -.SM -.B HOSTFILE -is set, but has no value, or does not name a readable file, -\fBbash\fP attempts to read -.FN /etc/hosts -to obtain the list of possible hostname completions. -When -.SM -.B HOSTFILE -is unset, the hostname list is cleared. -.TP -.B IFS -The -.I Internal Field Separator -that is used -for word splitting after expansion and to -split lines into words with the -.B read -builtin command. The default value is -``''. -.TP -.B IGNOREEOF -Controls the -action of an interactive shell on receipt of an -.SM -.B EOF -character as the sole input. If set, the value is the number of -consecutive -.SM -.B EOF -characters which must be -typed as the first characters on an input line before -.B bash -exits. If the variable exists but does not have a numeric value, or -has no value, the default value is 10. If it does not exist, -.SM -.B EOF -signifies the end of input to the shell. -.TP -.B INPUTRC -The filename for the -.B readline -startup file, overriding the default of -.FN ~/.inputrc -(see -.SM -.B READLINE -below). -.TP -.B LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with \fBLC_\fP. -.TP -.B LC_ALL -This variable overrides the value of -.SM -.B LANG -and any other -\fBLC_\fP variable specifying a locale category. -.TP -.B LC_COLLATE -This variable determines the collation order used when sorting the -results of pathname expansion, and determines the behavior of range -expressions, equivalence classes, and collating sequences within -pathname expansion and pattern matching. -.TP -.B LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within pathname expansion and pattern -matching. -.TP -.B LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a \fB$\fP. -.TP -.B LC_NUMERIC -This variable determines the locale category used for number formatting. -.TP -.B LINES -Used by the \fBselect\fP compound command to determine the column length -for printing selection lists. Automatically set by an interactive shell -upon receipt of a -.SM -.BR SIGWINCH . -.TP -.B MAIL -If this parameter is set to a file or directory name and the -.SM -.B MAILPATH -variable is not set, -.B bash -informs the user of the arrival of mail in the specified file or -Maildir-format directory. -.TP -.B MAILCHECK -Specifies how -often (in seconds) -.B bash -checks for mail. The default is 60 seconds. When it is time to check -for mail, the shell does so before displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. -.TP -.B MAILPATH -A colon-separated list of filenames to be checked for mail. -The message to be printed when mail arrives in a particular file -may be specified by separating the filename from the message with a `?'. -When used in the text of the message, \fB$_\fP expands to the name of -the current mailfile. -Example: -.RS -.PP -\fBMAILPATH\fP=\(aq/var/mail/bfox?"You have mail":~/shell\-mail?"$_ has mail!"\(aq -.PP -.B Bash -supplies a default value for this variable, but the location of the user -mail files that it uses is system dependent (e.g., /var/mail/\fB$USER\fP). -.RE -.TP -.B OPTERR -If set to the value 1, -.B bash -displays error messages generated by the -.B getopts -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SM -.B OPTERR -is initialized to 1 each time the shell is invoked or a shell -script is executed. -.TP -.B PATH -The search path for commands. It -is a colon-separated list of directories in which -the shell looks for commands (see -.SM -.B COMMAND EXECUTION -below). -A zero-length (null) directory name in the value of -.SM -.B PATH -indicates the current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. -The default path is system-dependent, -and is set by the administrator who installs -.BR bash . -A common value is -.if t \f(CW/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin\fP. -.if n ``/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin''. -.TP -.B POSIXLY_CORRECT -If this variable is in the environment when \fBbash\fP starts, the shell -enters \fIposix mode\fP before reading the startup files, as if the -.B \-\-posix -invocation option had been supplied. If it is set while the shell is -running, \fBbash\fP enables \fIposix mode\fP, as if the command -.if t \f(CWset -o posix\fP -.if n \fIset -o posix\fP -had been executed. -.TP -.B PROMPT_COMMAND -If set, the value is executed as a command prior to issuing each primary -prompt. -.TP -.B PROMPT_DIRTRIM -If set to a number greater than zero, the value is used as the number of -trailing directory components to retain when expanding the \fB\ew\fP and -\fB\eW\fP prompt string escapes (see -.SM -.B PROMPTING -below). Characters removed are replaced with an ellipsis. -.TP -.B PS1 -The value of this parameter is expanded (see -.SM -.B PROMPTING -below) and used as the primary prompt string. The default value is -``\fB\es\-\ev\e$ \fP''. -.TP -.B PS2 -The value of this parameter is expanded as with -.SM -.B PS1 -and used as the secondary prompt string. The default is -``\fB> \fP''. -.TP -.B PS3 -The value of this parameter is used as the prompt for the -.B select -command (see -.SM -.B SHELL GRAMMAR -above). -.TP -.B PS4 -The value of this parameter is expanded as with -.SM -.B PS1 -and the value is printed before each command -.B bash -displays during an execution trace. The first character of -.SM -.B PS4 -is replicated multiple times, as necessary, to indicate multiple -levels of indirection. The default is ``\fB+ \fP''. -.TP -.B SHELL -The full pathname to the shell is kept in this environment variable. -If it is not set when the shell starts, -.B bash -assigns to it the full pathname of the current user's login shell. -.TP -.B TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the -.B time -reserved word should be displayed. -The \fB%\fP character introduces an escape sequence that is -expanded to a time value or other information. -The escape sequences and their meanings are as follows; the -braces denote optional portions. -.sp .5 -.RS -.PD 0 -.TP 10 -.B %% -A literal \fB%\fP. -.TP -.B %[\fIp\fP][l]R -The elapsed time in seconds. -.TP -.B %[\fIp\fP][l]U -The number of CPU seconds spent in user mode. -.TP -.B %[\fIp\fP][l]S -The number of CPU seconds spent in system mode. -.TP -.B %P -The CPU percentage, computed as (%U + %S) / %R. -.PD -.RE -.IP -The optional \fIp\fP is a digit specifying the \fIprecision\fP, -the number of fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; -values of \fIp\fP greater than 3 are changed to 3. -If \fIp\fP is not specified, the value 3 is used. -.IP -The optional \fBl\fP specifies a longer format, including -minutes, of the form \fIMM\fPm\fISS\fP.\fIFF\fPs. -The value of \fIp\fP determines whether or not the fraction is -included. -.IP -If this variable is not set, \fBbash\fP acts as if it had the -value \fB$\(aq\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS\(aq\fP. -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. -.PD 0 -.TP -.B TMOUT -If set to a value greater than zero, -.SM -.B TMOUT -is treated as the -default timeout for the \fBread\fP builtin. -The \fBselect\fP command terminates if input does not arrive -after -.SM -.B TMOUT -seconds when input is coming from a terminal. -In an interactive shell, the value is interpreted as the -number of seconds to wait for a line of input after issuing the -primary prompt. -.B Bash -terminates after waiting for that number of seconds if a complete -line of input does not arrive. -.TP -.B TMPDIR -If set, \fBbash\fP uses its value as the name of a directory in which -\fBbash\fP creates temporary files for the shell's use. -.TP -.B auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable is set, single word simple -commands without redirections are treated as candidates for resumption -of an existing stopped job. There is no ambiguity allowed; if there is -more than one job beginning with the string typed, the job most recently -accessed is selected. The -.I name -of a stopped job, in this context, is the command line used to -start it. -If set to the value -.IR exact , -the string supplied must match the name of a stopped job exactly; -if set to -.IR substring , -the string supplied needs to match a substring of the name of a -stopped job. The -.I substring -value provides functionality analogous to the -.B %? -job identifier (see -.SM -.B JOB CONTROL -below). If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the \fB%\fP\fIstring\fP job identifier. -.TP -.B histchars -The two or three characters which control history expansion -and tokenization (see -.SM -.B HISTORY EXPANSION -below). The first character is the \fIhistory expansion\fP character, -the character which signals the start of a history -expansion, normally `\fB!\fP'. -The second character is the \fIquick substitution\fP -character, which is used as shorthand for re-running the previous -command entered, substituting one string for another in the command. -The default is `\fB^\fP'. -The optional third character is the character -which indicates that the remainder of the line is a comment when found -as the first character of a word, normally `\fB#\fP'. The history -comment character causes history substitution to be skipped for the -remaining words on the line. It does not necessarily cause the shell -parser to treat the rest of the line as a comment. -.PD -.SS Arrays -.B Bash -provides one-dimensional indexed and associative array variables. -Any variable may be used as an indexed array; the -.B declare -builtin will explicitly declare an array. -There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. -Indexed arrays are referenced using integers (including arithmetic -expressions) and are zero-based; associative arrays are referenced -using arbitrary strings. -Unless otherwise noted, indexed array indices must be non-negative integers. -.PP -An indexed array is created automatically if any variable is assigned to -using the syntax \fIname\fP[\fIsubscript\fP]=\fIvalue\fP. The -.I subscript -is treated as an arithmetic expression that must evaluate to a number. -To explicitly declare an indexed array, use -.B declare \-a \fIname\fP -(see -.SM -.B SHELL BUILTIN COMMANDS -below). -.B declare \-a \fIname\fP[\fIsubscript\fP] -is also accepted; the \fIsubscript\fP is ignored. -.PP -Associative arrays are created using -.BR "declare \-A \fIname\fP" . -.PP -Attributes may be -specified for an array variable using the -.B declare -and -.B readonly -builtins. Each attribute applies to all members of an array. -.PP -Arrays are assigned to using compound assignments of the form -\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each -\fIvalue\fP is of the form [\fIsubscript\fP]=\fIstring\fP. -Indexed array assignments do not require anything but \fIstring\fP. -When assigning to indexed arrays, if the optional brackets and subscript -are supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. -.PP -When assigning to an associative array, the subscript is required. -.PP -This syntax is also accepted by the -.B declare -builtin. Individual array elements may be assigned to using the -\fIname\fP[\fIsubscript\fP]=\fIvalue\fP syntax introduced above. -.PP -Any element of an array may be referenced using -${\fIname\fP[\fIsubscript\fP]}. The braces are required to avoid -conflicts with pathname expansion. If -\fIsubscript\fP is \fB@\fP or \fB*\fP, the word expands to -all members of \fIname\fP. These subscripts differ only when the -word appears within double quotes. If the word is double-quoted, -${\fIname\fP[*]} expands to a single -word with the value of each array member separated by the first -character of the -.SM -.B IFS -special variable, and ${\fIname\fP[@]} expands each element of -\fIname\fP to a separate word. When there are no array members, -${\fIname\fP[@]} expands to nothing. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the expansion -of the special parameters \fB*\fP and \fB@\fP (see -.B Special Parameters -above). ${#\fIname\fP[\fIsubscript\fP]} expands to the length of -${\fIname\fP[\fIsubscript\fP]}. If \fIsubscript\fP is \fB*\fP or -\fB@\fP, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing the array with a subscript of 0. -If the -.I subscript -used to reference an element of an indexed array -evaluates to a number less than zero, it is used as -an offset from one greater than the array's maximum index (so a subcript -of -1 refers to the last element of the array). -.PP -An array variable is considered set if a subscript has been assigned a -value. The null string is a valid value. -.PP -The -.B unset -builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] -destroys the array element at index \fIsubscript\fP. -Care must be taken to avoid unwanted side effects caused by pathname -expansion. -\fBunset\fP \fIname\fP, where \fIname\fP is an array, or -\fBunset\fP \fIname\fP[\fIsubscript\fP], where -\fIsubscript\fP is \fB*\fP or \fB@\fP, removes the entire array. -.PP -The -.BR declare , -.BR local , -and -.B readonly -builtins each accept a -.B \-a -option to specify an indexed array and a -.B \-A -option to specify an associative array. -If both options are supplied, -.B \-A -takes precedence. -The -.B read -builtin accepts a -.B \-a -option to assign a list of words read from the standard input -to an array. The -.B set -and -.B declare -builtins display array values in a way that allows them to be -reused as assignments. -.SH EXPANSION -Expansion is performed on the command line after it has been split into -words. There are seven kinds of expansion performed: -.IR "brace expansion" , -.IR "tilde expansion" , -.IR "parameter and variable expansion" , -.IR "command substitution" , -.IR "arithmetic expansion" , -.IR "word splitting" , -and -.IR "pathname expansion" . -.PP -The order of expansions is: brace expansion, tilde expansion, -parameter, variable and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and pathname -expansion. -.PP -On systems that can support it, there is an additional expansion -available: \fIprocess substitution\fP. -.PP -Only brace expansion, word splitting, and pathname expansion -can change the number of words of the expansion; other expansions -expand a single word to a single word. -The only exceptions to this are the expansions of -"\fB$@\fP" and "\fB${\fP\fIname\fP\fB[@]}\fP" -as explained above (see -.SM -.BR PARAMETERS ). -.SS Brace Expansion -.PP -.I "Brace expansion" -is a mechanism by which arbitrary strings -may be generated. This mechanism is similar to -\fIpathname expansion\fP, but the filenames generated -need not exist. Patterns to be brace expanded take -the form of an optional -.IR preamble , -followed by either a series of comma-separated strings or -a sequence expression between a pair of braces, followed by -an optional -.IR postscript . -The preamble is prefixed to each string contained -within the braces, and the postscript is then appended -to each resulting string, expanding left to right. -.PP -Brace expansions may be nested. The results of each expanded -string are not sorted; left to right order is preserved. -For example, a\fB{\fPd,c,b\fB}\fPe expands into `ade ace abe'. -.PP -A sequence expression takes the form -\fB{\fP\fIx\fP\fB..\fP\fIy\fP\fB[..\fP\fIincr\fP\fB]}\fP, -where \fIx\fP and \fIy\fP are either integers or single characters, -and \fIincr\fP, an optional increment, is an integer. -When integers are supplied, the expression expands to each number between -\fIx\fP and \fIy\fP, inclusive. -Supplied integers may be prefixed with \fI0\fP to force each term to have the -same width. When either \fIx\fP or \fPy\fP begins with a zero, the shell -attempts to force all generated terms to contain the same number of digits, -zero-padding where necessary. -When characters are supplied, the expression expands to each character -lexicographically between \fIx\fP and \fIy\fP, inclusive. Note that -both \fIx\fP and \fIy\fP must be of the same type. -When the increment is supplied, it is used as the difference between -each term. The default increment is 1 or -1 as appropriate. -.PP -Brace expansion is performed before any other expansions, -and any characters special to other expansions are preserved -in the result. It is strictly textual. -.B Bash -does not apply any syntactic interpretation to the context of the -expansion or the text between the braces. -.PP -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. -A \fB{\fP or \fB,\fP may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string \fB${\fP -is not considered eligible for brace expansion. -.PP -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -.RS -.PP -mkdir /usr/local/src/bash/{old,new,dist,bugs} -.RE -or -.RS -chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} -.RE -.PP -Brace expansion introduces a slight incompatibility with -historical versions of -.BR sh . -.B sh -does not treat opening or closing braces specially when they -appear as part of a word, and preserves them in the output. -.B Bash -removes braces from words as a consequence of brace -expansion. For example, a word entered to -.B sh -as \fIfile{1,2}\fP -appears identically in the output. The same word is -output as -.I file1 file2 -after expansion by -.BR bash . -If strict compatibility with -.B sh -is desired, start -.B bash -with the -.B +B -option or disable brace expansion with the -.B +B -option to the -.B set -command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS Tilde Expansion -.PP -If a word begins with an unquoted tilde character (`\fB~\fP'), all of -the characters preceding the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a \fItilde-prefix\fP. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible \fIlogin name\fP. -If this login name is the null string, the tilde is replaced with the -value of the shell parameter -.SM -.BR HOME . -If -.SM -.B HOME -is unset, the home directory of the user executing the shell is -substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. -.PP -If the tilde-prefix is a `~+', the value of the shell variable -.SM -.B PWD -replaces the tilde-prefix. -If the tilde-prefix is a `~\-', the value of the shell variable -.SM -.BR OLDPWD , -if it is set, is substituted. -If the characters following the tilde in the tilde-prefix consist -of a number \fIN\fP, optionally prefixed -by a `+' or a `\-', the tilde-prefix is replaced with the corresponding -element from the directory stack, as it would be displayed by the -.B dirs -builtin invoked with the tilde-prefix as an argument. -If the characters following the tilde in the tilde-prefix consist of a -number without a leading `+' or `\-', `+' is assumed. -.PP -If the login name is invalid, or the tilde expansion fails, the word -is unchanged. -.PP -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a -.B : -or the first -.BR = . -In these cases, tilde expansion is also performed. -Consequently, one may use filenames with tildes in assignments to -.SM -.BR PATH , -.SM -.BR MAILPATH , -and -.SM -.BR CDPATH , -and the shell assigns the expanded value. -.SS Parameter Expansion -.PP -The `\fB$\fP' character introduces parameter expansion, -command substitution, or arithmetic expansion. The parameter name -or symbol to be expanded may be enclosed in braces, which -are optional but serve to protect the variable to be expanded from -characters immediately following it which could be -interpreted as part of the name. -.PP -When braces are used, the matching ending brace is the first `\fB}\fP' -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or parameter -expansion. -.PP -.PD 0 -.TP -${\fIparameter\fP} -The value of \fIparameter\fP is substituted. The braces are required -when -.I parameter -is a positional parameter with more than one digit, -or when -.I parameter -is followed by a character which is not to be -interpreted as part of its name. -The \fIparameter\fP is a shell parameter as described above -\fBPARAMETERS\fP) or an array reference (\fBArrays\fP). -.PD -.PP -If the first character of \fIparameter\fP is an exclamation point (\fB!\fP), -it introduces a level of variable indirection. -\fBBash\fP uses the value of the variable formed from the rest of -\fIparameter\fP as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of \fIparameter\fP itself. -This is known as \fIindirect expansion\fP. -The exceptions to this are the expansions of ${\fB!\fP\fIprefix\fP\fB*\fP} and -${\fB!\fP\fIname\fP[\fI@\fP]} described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. -.PP -In each of the cases below, \fIword\fP is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. -.PP -When not performing substring expansion, using the forms documented below -(e.g., \fB:-\fP), -\fBbash\fP tests for a parameter that is unset or null. Omitting the colon -results in a test only for a parameter that is unset. -.PP -.PD 0 -.TP -${\fIparameter\fP\fB:\-\fP\fIword\fP} -\fBUse Default Values\fP. If -.I parameter -is unset or null, the expansion of -.I word -is substituted. Otherwise, the value of -.I parameter -is substituted. -.TP -${\fIparameter\fP\fB:=\fP\fIword\fP} -\fBAssign Default Values\fP. -If -.I parameter -is unset or null, the expansion of -.I word -is assigned to -.IR parameter . -The value of -.I parameter -is then substituted. Positional parameters and special parameters may -not be assigned to in this way. -.TP -${\fIparameter\fP\fB:?\fP\fIword\fP} -\fBDisplay Error if Null or Unset\fP. -If -.I parameter -is null or unset, the expansion of \fIword\fP (or a message to that effect -if -.I word -is not present) is written to the standard error and the shell, if it -is not interactive, exits. Otherwise, the value of \fIparameter\fP is -substituted. -.TP -${\fIparameter\fP\fB:+\fP\fIword\fP} -\fBUse Alternate Value\fP. -If -.I parameter -is null or unset, nothing is substituted, otherwise the expansion of -.I word -is substituted. -.TP -${\fIparameter\fP\fB:\fP\fIoffset\fP} -.PD 0 -.TP -${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP} -.PD -\fBSubstring Expansion\fP. -Expands to up to \fIlength\fP characters of the value of \fIparameter\fP -starting at the character specified by \fIoffset\fP. -If \fIparameter\fP is \fB@\fP, an indexed array subscripted by -\fB@\fP or \fB*\fP, or an associative array name, the results differ as -described below. -If \fIlength\fP is omitted, expands to the substring of the value of -\fIparameter\fP starting at the character specified by \fIoffset\fP -and extending to the end of the value. -\fIlength\fP and \fIoffset\fP are arithmetic expressions (see -.SM -.B -ARITHMETIC EVALUATION -below). -.sp 1 -If \fIoffset\fP evaluates to a number less than zero, the value -is used as an offset in characters -from the end of the value of \fIparameter\fP. -If \fIlength\fP evaluates to a number less than zero, -it is interpreted as an offset in characters -from the end of the value of \fIparameter\fP rather than -a number of characters, and the expansion is the characters between -\fIoffset\fP and that result. -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the \fB:-\fP expansion. -.sp 1 -If \fIparameter\fP is \fB@\fP, the result is \fIlength\fP positional -parameters beginning at \fIoffset\fP. -A negative \fIoffset\fP is taken relative to one greater than the greatest -positional parameter, so an offset of -1 evaluates to the last positional -parameter. -It is an expansion error if \fIlength\fP evaluates to a number less than -zero. -.sp 1 -If \fIparameter\fP is an indexed array name subscripted by @ or *, -the result is the \fIlength\fP -members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}. -A negative \fIoffset\fP is taken relative to one greater than the maximum -index of the specified array. -It is an expansion error if \fIlength\fP evaluates to a number less than -zero. -.sp 1 -Substring expansion applied to an associative array produces undefined -results. -.sp 1 -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If \fIoffset\fP is 0, and the positional parameters are used, \fB$0\fP is -prefixed to the list. -.TP -${\fB!\fP\fIprefix\fP\fB*\fP} -.PD 0 -.TP -${\fB!\fP\fIprefix\fP\fB@\fP} -.PD -\fBNames matching prefix\fP. -Expands to the names of variables whose names begin with \fIprefix\fP, -separated by the first character of the -.SM -.B IFS -special variable. -When \fI@\fP is used and the expansion appears within double quotes, each -variable name expands to a separate word. -.TP -${\fB!\fP\fIname\fP[\fI@\fP]} -.PD 0 -.TP -${\fB!\fP\fIname\fP[\fI*\fP]} -.PD -\fBList of array keys\fP. -If \fIname\fP is an array variable, expands to the list of array indices -(keys) assigned in \fIname\fP. -If \fIname\fP is not an array, expands to 0 if \fIname\fP is set and null -otherwise. -When \fI@\fP is used and the expansion appears within double quotes, each -key expands to a separate word. -.TP -${\fB#\fP\fIparameter\fP} -\fBParameter length\fP. -The length in characters of the value of \fIparameter\fP is substituted. -If -.I parameter -is -.B * -or -.BR @ , -the value substituted is the number of positional parameters. -If -.I parameter -is an array name subscripted by -.B * -or -.BR @ , -the value substituted is the number of elements in the array. -.TP -${\fIparameter\fP\fB#\fP\fIword\fP} -.PD 0 -.TP -${\fIparameter\fP\fB##\fP\fIword\fP} -.PD -\fBRemove matching prefix pattern\fP. -The -.I word -is expanded to produce a pattern just as in pathname -expansion. If the pattern matches the beginning of -the value of -.IR parameter , -then the result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB#\fP'' case) or the -longest matching pattern (the ``\fB##\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB%\fP\fIword\fP} -.PD 0 -.TP -${\fIparameter\fP\fB%%\fP\fIword\fP} -.PD -\fBRemove matching suffix pattern\fP. -The \fIword\fP is expanded to produce a pattern just as in -pathname expansion. -If the pattern matches a trailing portion of the expanded value of -.IR parameter , -then the result of the expansion is the expanded value of -.I parameter -with the shortest matching pattern (the ``\fB%\fP'' case) or the -longest matching pattern (the ``\fB%%\fP'' case) deleted. -If -.I parameter -is -.B @ -or -.BR * , -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB/\fP\fIpattern\fP\fB/\fP\fIstring\fP} -\fBPattern substitution\fP. -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -\fIParameter\fP is expanded and the longest match of \fIpattern\fP -against its value is replaced with \fIstring\fP. -If \fIpattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are -replaced with \fIstring\fP. Normally only the first match is replaced. -If \fIpattern\fP begins with \fB#\fP, it must match at the beginning -of the expanded value of \fIparameter\fP. -If \fIpattern\fP begins with \fB%\fP, it must match at the end -of the expanded value of \fIparameter\fP. -If \fIstring\fP is null, matches of \fIpattern\fP are deleted -and the \fB/\fP following \fIpattern\fP may be omitted. -If -.I parameter -is -.B @ -or -.BR * , -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.TP -${\fIparameter\fP\fB^\fP\fIpattern\fP} -.PD 0 -.TP -${\fIparameter\fP\fB^^\fP\fIpattern\fP} -.TP -${\fIparameter\fP\fB,\fP\fIpattern\fP} -.TP -${\fIparameter\fP\fB,,\fP\fIpattern\fP} -.PD -\fBCase modification\fP. -This expansion modifies the case of alphabetic characters in \fIparameter\fP. -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -Each character in the expanded value of \fIparameter\fP is tested against -\fIpattern\fP, and, if it matches the pattern, its case is converted. -The pattern should not attempt to match more than one character. -The \fB^\fP operator converts lowercase letters matching \fIpattern\fP -to uppercase; the \fB,\fP operator converts matching uppercase letters -to lowercase. -The \fB^^\fP and \fB,,\fP expansions convert each matched character in the -expanded value; the \fB^\fP and \fB,\fP expansions match and convert only -the first character in the expanded value. -If \fIpattern\fP is omitted, it is treated like a \fB?\fP, which matches -every character. -If -.I parameter -is -.B @ -or -.BR * , -the case modification operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If -.I parameter -is an array variable subscripted with -.B @ -or -.BR * , -the case modification operation is applied to each member of the -array in turn, and the expansion is the resultant list. -.SS Command Substitution -.PP -\fICommand substitution\fP allows the output of a command to replace -the command name. There are two forms: -.RS -.PP -\fB$(\fP\fIcommand\fP\|\fB)\fP -.RE -or -.RS -\fB\`\fP\fIcommand\fP\fB\`\fP -.RE -.PP -.B Bash -performs the expansion by executing \fIcommand\fP and -replacing the command substitution with the standard output of the -command, with any trailing newlines deleted. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution \fB$(cat \fIfile\fP)\fR can be replaced by -the equivalent but faster \fB$(< \fIfile\fP)\fR. -.PP -When the old-style backquote form of substitution is used, -backslash retains its literal meaning except when followed by -.BR $ , -.BR \` , -or -.BR \e . -The first backquote not preceded by a backslash terminates the -command substitution. -When using the $(\^\fIcommand\fP\|) form, all characters between the -parentheses make up the command; none are treated specially. -.PP -Command substitutions may be nested. To nest when using the backquoted form, -escape the inner backquotes with backslashes. -.PP -If the substitution appears within double quotes, word splitting and -pathname expansion are not performed on the results. -.SS Arithmetic Expansion -.PP -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. The format for arithmetic expansion is: -.RS -.PP -\fB$((\fP\fIexpression\fP\fB))\fP -.RE -.PP -The -.I expression -is treated as if it were within double quotes, but a double quote -inside the parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, string -expansion, command substitution, and quote removal. -Arithmetic expansions may be nested. -.PP -The evaluation is performed according to the rules listed below under -.SM -.BR "ARITHMETIC EVALUATION" . -If -.I expression -is invalid, -.B bash -prints a message indicating failure and no substitution occurs. -.SS Process Substitution -.PP -\fIProcess substitution\fP is supported on systems that support named -pipes (\fIFIFOs\fP) or the \fB/dev/fd\fP method of naming open files. -It takes the form of -\fB<(\fP\fIlist\^\fP\fB)\fP -or -\fB>(\fP\fIlist\^\fP\fB)\fP. -The process \fIlist\fP is run with its input or output connected to a -\fIFIFO\fP or some file in \fB/dev/fd\fP. The name of this file is -passed as an argument to the current command as the result of the -expansion. If the \fB>(\fP\fIlist\^\fP\fB)\fP form is used, writing to -the file will provide input for \fIlist\fP. If the -\fB<(\fP\fIlist\^\fP\fB)\fP form is used, the file passed as an -argument should be read to obtain the output of \fIlist\fP. -.PP -When available, process substitution is performed -simultaneously with parameter and variable expansion, -command substitution, -and arithmetic expansion. -.SS Word Splitting -.PP -The shell scans the results of -parameter expansion, -command substitution, -and -arithmetic expansion -that did not occur within double quotes for -.IR "word splitting" . -.PP -The shell treats each character of -.SM -.B IFS -as a delimiter, and splits the results of the other -expansions into words on these characters. If -.SM -.B IFS -is unset, or its -value is exactly -.BR , -the default, then -sequences of -.BR , -.BR , -and -.B -at the beginning and end of the results of the previous -expansions are ignored, and -any sequence of -.SM -.B IFS -characters not at the beginning or end serves to delimit words. -If -.SM -.B IFS -has a value other than the default, then sequences of -the whitespace characters -.B space -and -.B tab -are ignored at the beginning and end of the -word, as long as the whitespace character is in the -value of -.SM -.BR IFS -(an -.SM -.B IFS -whitespace character). -Any character in -.SM -.B IFS -that is not -.SM -.B IFS -whitespace, along with any adjacent -.SM -.B IFS -whitespace characters, delimits a field. -A sequence of -.SM -.B IFS -whitespace characters is also treated as a delimiter. -If the value of -.SM -.B IFS -is null, no word splitting occurs. -.PP -Explicit null arguments (\^\f3"\^"\fP or \^\f3\(aq\^\(aq\fP\^) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. -.PP -Note that if no expansion occurs, no splitting -is performed. -.SS Pathname Expansion -.PP -After word splitting, -unless the -.B \-f -option has been set, -.B bash -scans each word for the characters -.BR * , -.BR ? , -and -.BR [ . -If one of these characters appears, then the word is -regarded as a -.IR pattern , -and replaced with an alphabetically sorted list of -filenames matching the pattern -(see -.SM -.B "Pattern Matching" -below). -If no matching filenames are found, -and the shell option -.B nullglob -is not enabled, the word is left unchanged. -If the -.B nullglob -option is set, and no matches are found, -the word is removed. -If the -.B failglob -shell option is set, and no matches are found, an error message -is printed and the command is not executed. -If the shell option -.B nocaseglob -is enabled, the match is performed without regard to the case -of alphabetic characters. -When a pattern is used for pathname expansion, -the character -.B ``.'' -at the start of a name or immediately following a slash -must be matched explicitly, unless the shell option -.B dotglob -is set. -When matching a pathname, the slash character must always be -matched explicitly. -In other cases, the -.B ``.'' -character is not treated specially. -See the description of -.B shopt -below under -.SM -.B SHELL BUILTIN COMMANDS -for a description of the -.BR nocaseglob , -.BR nullglob , -.BR failglob , -and -.B dotglob -shell options. -.PP -The -.SM -.B GLOBIGNORE -shell variable may be used to restrict the set of filenames matching a -.IR pattern . -If -.SM -.B GLOBIGNORE -is set, each matching filename that also matches one of the patterns in -.SM -.B GLOBIGNORE -is removed from the list of matches. -The filenames -.B ``.'' -and -.B ``..'' -are always ignored when -.SM -.B GLOBIGNORE -is set and not null. However, setting -.SM -.B GLOBIGNORE -to a non-null value has the effect of enabling the -.B dotglob -shell option, so all other filenames beginning with a -.B ``.'' -will match. -To get the old behavior of ignoring filenames beginning with a -.BR ``.'' , -make -.B ``.*'' -one of the patterns in -.SM -.BR GLOBIGNORE . -The -.B dotglob -option is disabled when -.SM -.B GLOBIGNORE -is unset. -.PP -\fBPattern Matching\fP -.PP -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. The NUL character may not -occur in a pattern. A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if -they are to be matched literally. -.PP -The special pattern characters have the following meanings: -.PP -.PD 0 -.RS -.TP -.B * -Matches any string, including the null string. -When the \fBglobstar\fP shell option is enabled, and \fB*\fP is used in -a pathname expansion context, two adjacent \fB*\fPs used as a single -pattern will match all files and zero or more directories and -subdirectories. -If followed by a \fB/\fP, two adjacent \fB*\fPs will match only directories -and subdirectories. -.TP -.B ? -Matches any single character. -.TP -.B [...] -Matches any one of the enclosed characters. A pair of characters -separated by a hyphen denotes a -\fIrange expression\fP; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -.B [ -is a -.B ! -or a -.B ^ -then any character not enclosed is matched. -The sorting order of characters in range expressions is determined by -the current locale and the values of the -.SM -.B LC_COLLATE -or -.SM -.B LC_ALL -shell variables, if set. -To obtain the traditional interpretation of range expressions, where -.B [a\-d] -is equivalent to -.BR [abcd] , -set value of the -.B LC_ALL -shell variable to -.BR C , -or enable the -.B globasciiranges -shell option. -A -.B \- -may be matched by including it as the first or last character -in the set. -A -.B ] -may be matched by including it as the first character -in the set. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -\fIcharacter classes\fP can be specified using the syntax -\fB[:\fP\fIclass\fP\fB:]\fP, where \fIclass\fP is one of the -following classes defined in the POSIX standard: -.PP -.RS -.B -.if n alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.if t alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit -.br -A character class matches any character belonging to that class. -The \fBword\fP character class matches letters, digits, and the character _. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -an \fIequivalence class\fP can be specified using the syntax -\fB[=\fP\fIc\fP\fB=]\fP, which matches all characters with the -same collation weight (as defined by the current locale) as -the character \fIc\fP. -.br -.if t .sp 0.5 -.if n .sp 1 -Within -.B [ -and -.BR ] , -the syntax \fB[.\fP\fIsymbol\fP\fB.]\fP matches the collating symbol -\fIsymbol\fP. -.RE -.RE -.PD -.PP -If the \fBextglob\fP shell option is enabled using the \fBshopt\fP -builtin, several extended pattern matching operators are recognized. -In the following description, a \fIpattern-list\fP is a list of one -or more patterns separated by a \fB|\fP. -Composite patterns may be formed using one or more of the following -sub-patterns: -.sp 1 -.PD 0 -.RS -.TP -\fB?(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or one occurrence of the given patterns -.TP -\fB*(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches zero or more occurrences of the given patterns -.TP -\fB+(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches one or more occurrences of the given patterns -.TP -\fB@(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches one of the given patterns -.TP -\fB!(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches anything except one of the given patterns -.RE -.PD -.SS Quote Removal -.PP -After the preceding expansions, all unquoted occurrences of the -characters -.BR \e , -.BR \(aq , -and \^\f3"\fP\^ that did not result from one of the above -expansions are removed. -.SH REDIRECTION -Before a command is executed, its input and output -may be -.I redirected -using a special notation interpreted by the shell. -Redirection allows commands' file handles to be -duplicated, opened, closed, -made to refer to different files, -and can change the files the command reads from and writes to. -Redirection may also be used to modify file handles in the -current shell execution environment. -The following redirection -operators may precede or appear anywhere within a -.I simple command -or may follow a -.IR command . -Redirections are processed in the order they appear, from -left to right. -.PP -Each redirection that may be preceded by a file descriptor number -may instead be preceded by a word of the form {\fIvarname\fP}. -In this case, for each redirection operator except ->&- and <&-, the shell will allocate a file descriptor greater -than or equal to 10 and assign it to \fIvarname\fP. -If >&- or <&- is preceded -by {\fIvarname\fP}, the value of \fIvarname\fP defines the file -descriptor to close. -.PP -In the following descriptions, if the file descriptor number is -omitted, and the first character of the redirection operator is -.BR < , -the redirection refers to the standard input (file descriptor -0). If the first character of the redirection operator is -.BR > , -the redirection refers to the standard output (file descriptor -1). -.PP -The word following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, quote removal, -pathname expansion, and word splitting. -If it expands to more than one word, -.B bash -reports an error. -.PP -Note that the order of redirections is significant. For example, -the command -.RS -.PP -ls \fB>\fP dirlist 2\fB>&\fP1 -.RE -.PP -directs both standard output and standard error to the file -.IR dirlist , -while the command -.RS -.PP -ls 2\fB>&\fP1 \fB>\fP dirlist -.RE -.PP -directs only the standard output to file -.IR dirlist , -because the standard error was duplicated from the standard output -before the standard output was redirected to -.IR dirlist . -.PP -\fBBash\fP handles several filenames specially when they are used in -redirections, as described in the following table: -.RS -.PP -.PD 0 -.TP -.B /dev/fd/\fIfd\fP -If \fIfd\fP is a valid integer, file descriptor \fIfd\fP is duplicated. -.TP -.B /dev/stdin -File descriptor 0 is duplicated. -.TP -.B /dev/stdout -File descriptor 1 is duplicated. -.TP -.B /dev/stderr -File descriptor 2 is duplicated. -.TP -.B /dev/tcp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -the corresponding TCP socket. -.TP -.B /dev/udp/\fIhost\fP/\fIport\fP -If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP -is an integer port number or service name, \fBbash\fP attempts to open -the corresponding UDP socket. -.PD -.RE -.PP -A failure to open or create a file causes the redirection to fail. -.PP -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. -.SS Redirecting Input -.PP -Redirection of input causes the file whose name results from -the expansion of -.I word -to be opened for reading on file descriptor -.IR n , -or the standard input (file descriptor 0) if -.I n -is not specified. -.PP -The general format for redirecting input is: -.RS -.PP -[\fIn\fP]\fB<\fP\fIword\fP -.RE -.SS Redirecting Output -.PP -Redirection of output causes the file whose name results from -the expansion of -.I word -to be opened for writing on file descriptor -.IR n , -or the standard output (file descriptor 1) if -.I n -is not specified. If the file does not exist it is created; -if it does exist it is truncated to zero size. -.PP -The general format for redirecting output is: -.RS -.PP -[\fIn\fP]\fB>\fP\fIword\fP -.RE -.PP -If the redirection operator is -.BR > , -and the -.B noclobber -option to the -.B set -builtin has been enabled, the redirection will fail if the file -whose name results from the expansion of \fIword\fP exists and is -a regular file. -If the redirection operator is -.BR >| , -or the redirection operator is -.B > -and the -.B noclobber -option to the -.B set -builtin command is not enabled, the redirection is attempted even -if the file named by \fIword\fP exists. -.SS Appending Redirected Output -.PP -Redirection of output in this fashion -causes the file whose name results from -the expansion of -.I word -to be opened for appending on file descriptor -.IR n , -or the standard output (file descriptor 1) if -.I n -is not specified. If the file does not exist it is created. -.PP -The general format for appending output is: -.RS -.PP -[\fIn\fP]\fB>>\fP\fIword\fP -.RE -.PP -.SS Redirecting Standard Output and Standard Error -.PP -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be redirected to the file whose name is the -expansion of -.IR word . -.PP -There are two formats for redirecting standard output and -standard error: -.RS -.PP -\fB&>\fP\fIword\fP -.RE -and -.RS -\fB>&\fP\fIword\fP -.RE -.PP -Of the two forms, the first is preferred. -This is semantically equivalent to -.RS -.PP -\fB>\fP\fIword\fP 2\fB>&\fP1 -.RE -.PP -When using the second form, \fIword\fP may not expand to a number or -\fB\-\fP. If it does, other redirection operators apply -(see \fBDuplicating File Descriptors\fP below) for compatibility -reasons. -.SS Appending Standard Output and Standard Error -.PP -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be appended to the file whose name is the -expansion of -.IR word . -.PP -The format for appending standard output and standard error is: -.RS -.PP -\fB&>>\fP\fIword\fP -.RE -.PP -This is semantically equivalent to -.RS -.PP -\fB>>\fP\fIword\fP 2\fB>&\fP1 -.RE -.PP -(see \fBDuplicating File Descriptors\fP below). -.SS Here Documents -.PP -This type of redirection instructs the shell to read input from the -current source until a line containing only -.I delimiter -(with no trailing blanks) -is seen. All of -the lines read up to that point are then used as the standard -input for a command. -.PP -The format of here-documents is: -.RS -.PP -.nf -\fB<<\fP[\fB\-\fP]\fIword\fP - \fIhere-document\fP -\fIdelimiter\fP -.fi -.RE -.PP -No parameter and variable expansion, command substitution, -arithmetic expansion, or pathname expansion is performed on -.IR word . -If any characters in -.I word -are quoted, the -.I delimiter -is the result of quote removal on -.IR word , -and the lines in the here-document are not expanded. -If \fIword\fP is unquoted, -all lines of the here-document are subjected to -parameter expansion, command substitution, and arithmetic expansion, -the character sequence -.B \e -is ignored, and -.B \e -must be used to quote the characters -.BR \e , -.BR $ , -and -.BR \` . -.PP -If the redirection operator is -.BR <<\- , -then all leading tab characters are stripped from input lines and the -line containing -.IR delimiter . -This allows -here-documents within shell scripts to be indented in a -natural fashion. -.SS "Here Strings" -A variant of here documents, the format is: -.RS -.PP -.nf -\fB<<<\fP\fIword\fP -.fi -.RE -.PP -The \fIword\fP undergoes -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote removal. -Pathname expansion and word splitting are not performed. -The result is supplied as a single string to the command on its -standard input. -.SS "Duplicating File Descriptors" -.PP -The redirection operator -.RS -.PP -[\fIn\fP]\fB<&\fP\fIword\fP -.RE -.PP -is used to duplicate input file descriptors. -If -.I word -expands to one or more digits, the file descriptor denoted by -.I n -is made to be a copy of that file descriptor. -If the digits in -.I word -do not specify a file descriptor open for input, a redirection error occurs. -If -.I word -evaluates to -.BR \- , -file descriptor -.I n -is closed. If -.I n -is not specified, the standard input (file descriptor 0) is used. -.PP -The operator -.RS -.PP -[\fIn\fP]\fB>&\fP\fIword\fP -.RE -.PP -is used similarly to duplicate output file descriptors. If -.I n -is not specified, the standard output (file descriptor 1) is used. -If the digits in -.I word -do not specify a file descriptor open for output, a redirection error occurs. -If -.I word -evaluates to -.BR \- , -file descriptor -.I n -is closed. -As a special case, if \fIn\fP is omitted, and \fIword\fP does not -expand to one or more digits or \fB\-\fP, the standard output and standard -error are redirected as described previously. -.SS "Moving File Descriptors" -.PP -The redirection operator -.RS -.PP -[\fIn\fP]\fB<&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard input (file descriptor 0) if \fIn\fP is not specified. -\fIdigit\fP is closed after being duplicated to \fIn\fP. -.PP -Similarly, the redirection operator -.RS -.PP -[\fIn\fP]\fB>&\fP\fIdigit\fP\fB\-\fP -.RE -.PP -moves the file descriptor \fIdigit\fP to file descriptor -.IR n , -or the standard output (file descriptor 1) if \fIn\fP is not specified. -.SS "Opening File Descriptors for Reading and Writing" -.PP -The redirection operator -.RS -.PP -[\fIn\fP]\fB<>\fP\fIword\fP -.RE -.PP -causes the file whose name is the expansion of -.I word -to be opened for both reading and writing on file descriptor -.IR n , -or on file descriptor 0 if -.I n -is not specified. If the file does not exist, it is created. -.SH ALIASES -\fIAliases\fP allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of aliases that may be set and unset with the -.B alias -and -.B unalias -builtin commands (see -.SM -.B SHELL BUILTIN COMMANDS -below). -The first word of each simple command, if unquoted, -is checked to see if it has an -alias. If so, that word is replaced by the text of the alias. -The characters \fB/\fP, \fB$\fP, \fB\`\fP, and \fB=\fP and -any of the shell \fImetacharacters\fP or quoting characters -listed above may not appear in an alias name. -The replacement text may contain any valid shell input, -including shell metacharacters. -The first word of the replacement text is tested -for aliases, but a word that is identical to an alias being expanded -is not expanded a second time. -This means that one may alias -.B ls -to -.BR "ls \-F" , -for instance, and -.B bash -does not try to recursively expand the replacement text. -If the last character of the alias value is a -.IR blank , -then the next command -word following the alias is also checked for alias expansion. -.PP -Aliases are created and listed with the -.B alias -command, and removed with the -.B unalias -command. -.PP -There is no mechanism for using arguments in the replacement text. -If arguments are needed, a shell function should be used (see -.SM -.B FUNCTIONS -below). -.PP -Aliases are not expanded when the shell is not interactive, unless -the -.B expand_aliases -shell option is set using -.B shopt -(see the description of -.B shopt -under -.SM -\fBSHELL BUILTIN COMMANDS\fP -below). -.PP -The rules concerning the definition and use of aliases are -somewhat confusing. -.B Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -The commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when a function definition is read, -not when the function is executed, because a function definition -is itself a compound command. As a consequence, aliases -defined in a function are not available until after that -function is executed. To be safe, always put -alias definitions on a separate line, and do not use -.B alias -in compound commands. -.PP -For almost every purpose, aliases are superseded by -shell functions. -.SH FUNCTIONS -A shell function, defined as described above under -.SM -.BR "SHELL GRAMMAR" , -stores a series of commands for later execution. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -Functions are executed in the context of the -current shell; no new process is created to interpret -them (contrast this with the execution of a shell script). -When a function is executed, the arguments to the -function become the positional parameters -during its execution. -The special parameter -.B # -is updated to reflect the change. Special parameter \fB0\fP -is unchanged. -The first element of the -.SM -.B FUNCNAME -variable is set to the name of the function while the function -is executing. -.PP -All other aspects of the shell execution -environment are identical between a function and its caller -with these exceptions: the -.SM -.B DEBUG -and -.B RETURN -traps (see the description of the -.B trap -builtin under -.SM -.B SHELL BUILTIN COMMANDS -below) are not inherited unless the function has been given the -\fBtrace\fP attribute (see the description of the -.SM -.B declare -builtin below) or the -\fB\-o functrace\fP shell option has been enabled with -the \fBset\fP builtin -(in which case all functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps), -and the -.SM -.B ERR -trap is not inherited unless the \fB\-o errtrace\fP shell option has -been enabled. -.PP -Variables local to the function may be declared with the -.B local -builtin command. Ordinarily, variables and their values -are shared between the function and its caller. -.PP -The \fBFUNCNEST\fP variable, if set to a numeric value greater -than 0, defines a maximum function nesting level. Function -invocations that exceed the limit cause the entire command to -abort. -.PP -If the builtin command -.B return -is executed in a function, the function completes and -execution resumes with the next command after the function -call. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter -.B # -are restored to the values they had prior to the function's -execution. -.PP -Function names and definitions may be listed with the -.B \-f -option to the -.B declare -or -.B typeset -builtin commands. The -.B \-F -option to -.B declare -or -.B typeset -will list the function names only -(and optionally the source file and line number, if the \fBextdebug\fP -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -.B \-f -option to the -.B export -builtin. -A function definition may be deleted using the \fB\-f\fP option to -the -.B unset -builtin. -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. -.PP -Functions may be recursive. -The \fBFUNCNEST\fP variable may be used to limit the depth of the -function call stack and restrict the number of function invocations. -By default, no limit is imposed on the number of recursive calls. -.SH "ARITHMETIC EVALUATION" -The shell allows arithmetic expressions to be evaluated, under -certain circumstances (see the \fBlet\fP and \fBdeclare\fP builtin -commands and \fBArithmetic Expansion\fP). -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -The following list of operators is grouped into levels of -equal-precedence operators. -The levels are listed in order of decreasing precedence. -.PP -.PD 0 -.TP -.B \fIid\fP++ \fIid\fP\-\- -variable post-increment and post-decrement -.TP -.B ++\fIid\fP \-\-\fIid\fP -variable pre-increment and pre-decrement -.TP -.B \- + -unary minus and plus -.TP -.B ! ~ -logical and bitwise negation -.TP -.B ** -exponentiation -.TP -.B * / % -multiplication, division, remainder -.TP -.B + \- -addition, subtraction -.TP -.B << >> -left and right bitwise shifts -.TP -.B <= >= < > -comparison -.TP -.B == != -equality and inequality -.TP -.B & -bitwise AND -.TP -.B ^ -bitwise exclusive OR -.TP -.B | -bitwise OR -.TP -.B && -logical AND -.TP -.B || -logical OR -.TP -.B \fIexpr\fP?\fIexpr\fP:\fIexpr\fP -conditional operator -.TP -.B = *= /= %= += \-= <<= >>= &= ^= |= -assignment -.TP -.B \fIexpr1\fP , \fIexpr2\fP -comma -.PD -.PP -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -\fIinteger\fP attribute using \fBdeclare -i\fP is assigned a value. -A null value evaluates to 0. -A shell variable need not have its \fIinteger\fP attribute -turned on to be used in an expression. -.PP -Constants with a leading 0 are interpreted as octal numbers. -A leading 0x or 0X denotes hexadecimal. -Otherwise, numbers take the form [\fIbase#\fP]n, where the optional \fIbase\fP -is a decimal number between 2 and 64 representing the arithmetic -base, and \fIn\fP is a number in that base. -If \fIbase#\fP is omitted, then base 10 is used. -When specifying \fIn\fP, -the digits greater< than 9 are represented by the lowercase letters, -the uppercase letters, @, and _, in that order. -If \fIbase\fP is less than or equal to 36, lowercase and uppercase -letters may be used interchangeably to represent numbers between 10 -and 35. -.PP -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. -.SH "CONDITIONAL EXPRESSIONS" -Conditional expressions are used by the \fB[[\fP compound command and -the \fBtest\fP and \fB[\fP builtin commands to test file attributes -and perform string and arithmetic comparisons. -Expressions are formed from the following unary or binary primaries. -If any \fIfile\fP argument to one of the primaries is of the form -\fI/dev/fd/n\fP, then file descriptor \fIn\fP is checked. -If the \fIfile\fP argument to one of the primaries is one of -\fI/dev/stdin\fP, \fI/dev/stdout\fP, or \fI/dev/stderr\fP, file -descriptor 0, 1, or 2, respectively, is checked. -.PP -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. -.if t .sp 0.5 -.if n .sp 1 -When used with \fB[[\fP, the \fB<\fP and \fB>\fP operators sort -lexicographically using the current locale. -The \fBtest\fP command sorts using ASCII ordering. -.sp 1 -.PD 0 -.TP -.B \-a \fIfile\fP -True if \fIfile\fP exists. -.TP -.B \-b \fIfile\fP -True if \fIfile\fP exists and is a block special file. -.TP -.B \-c \fIfile\fP -True if \fIfile\fP exists and is a character special file. -.TP -.B \-d \fIfile\fP -True if \fIfile\fP exists and is a directory. -.TP -.B \-e \fIfile\fP -True if \fIfile\fP exists. -.TP -.B \-f \fIfile\fP -True if \fIfile\fP exists and is a regular file. -.TP -.B \-g \fIfile\fP -True if \fIfile\fP exists and is set-group-id. -.TP -.B \-h \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-k \fIfile\fP -True if \fIfile\fP exists and its ``sticky'' bit is set. -.TP -.B \-p \fIfile\fP -True if \fIfile\fP exists and is a named pipe (FIFO). -.TP -.B \-r \fIfile\fP -True if \fIfile\fP exists and is readable. -.TP -.B \-s \fIfile\fP -True if \fIfile\fP exists and has a size greater than zero. -.TP -.B \-t \fIfd\fP -True if file descriptor -.I fd -is open and refers to a terminal. -.TP -.B \-u \fIfile\fP -True if \fIfile\fP exists and its set-user-id bit is set. -.TP -.B \-w \fIfile\fP -True if \fIfile\fP exists and is writable. -.TP -.B \-x \fIfile\fP -True if \fIfile\fP exists and is executable. -.TP -.B \-G \fIfile\fP -True if \fIfile\fP exists and is owned by the effective group id. -.TP -.B \-L \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-N \fIfile\fP -True if \fIfile\fP exists and has been modified since it was last read. -.TP -.B \-O \fIfile\fP -True if \fIfile\fP exists and is owned by the effective user id. -.TP -.B \-S \fIfile\fP -True if \fIfile\fP exists and is a socket. -.TP -\fIfile1\fP \fB\-ef\fP \fIfile2\fP -True if \fIfile1\fP and \fIfile2\fP refer to the same device and -inode numbers. -.TP -\fIfile1\fP \-\fBnt\fP \fIfile2\fP -True if \fIfile1\fP is newer (according to modification date) than \fIfile2\fP, -or if \fIfile1\fP exists and \fPfile2\fP does not. -.TP -\fIfile1\fP \-\fBot\fP \fIfile2\fP -True if \fIfile1\fP is older than \fIfile2\fP, or if \fIfile2\fP exists -and \fIfile1\fP does not. -.TP -.B \-o \fIoptname\fP -True if the shell option -.I optname -is enabled. -See the list of options under the description of the -.B \-o -option to the -.B set -builtin below. -.TP -.B \-v \fIvarname\fP -True if the shell variable -.I varname -is set (has been assigned a value). -.TP -.B \-z \fIstring\fP -True if the length of \fIstring\fP is zero. -.TP -\fIstring\fP -.PD 0 -.TP -.B \-n \fIstring\fP -.PD -True if the length of -.I string -is non-zero. -.TP -\fIstring1\fP \fB==\fP \fIstring2\fP -.PD 0 -.TP -\fIstring1\fP \fB=\fP \fIstring2\fP -.PD -True if the strings are equal. \fB=\fP should be used -with the \fBtest\fP command for POSIX conformance. -.TP -\fIstring1\fP \fB!=\fP \fIstring2\fP -True if the strings are not equal. -.TP -\fIstring1\fP \fB<\fP \fIstring2\fP -True if \fIstring1\fP sorts before \fIstring2\fP lexicographically. -.TP -\fIstring1\fP \fB>\fP \fIstring2\fP -True if \fIstring1\fP sorts after \fIstring2\fP lexicographically. -.TP -.I \fIarg1\fP \fBOP\fP \fIarg2\fP -.SM -.B OP -is one of -.BR \-eq , -.BR \-ne , -.BR \-lt , -.BR \-le , -.BR \-gt , -or -.BR \-ge . -These arithmetic binary operators return true if \fIarg1\fP -is equal to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to \fIarg2\fP, respectively. -.I Arg1 -and -.I arg2 -may be positive or negative integers. -.PD -.SH "SIMPLE COMMAND EXPANSION" -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. -.IP 1. -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. -.IP 2. -The words that are not variable assignments or redirections are -expanded. If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. -.IP 3. -Redirections are performed as described above under -.SM -.BR REDIRECTION . -.IP 4. -The text after the \fB=\fP in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -.PP -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. -.PP -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. -.PP -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. -.SH "COMMAND EXECUTION" -After a command has been split into words, if it results in a -simple command and an optional list of arguments, the following -actions are taken. -.PP -If the command name contains no slashes, the shell attempts to -locate it. If there exists a shell function by that name, that -function is invoked as described above in -.SM -.BR FUNCTIONS . -If the name does not match a function, the shell searches for -it in the list of shell builtins. If a match is found, that -builtin is invoked. -.PP -If the name is neither a shell function nor a builtin, -and contains no slashes, -.B bash -searches each element of the -.SM -.B PATH -for a directory containing an executable file by that name. -.B Bash -uses a hash table to remember the full pathnames of executable -files (see -.B hash -under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -A full search of the directories in -.SM -.B PATH -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell searches for a defined shell -function named \fBcommand_not_found_handle\fP. -If that function exists, it is invoked with the original command and -the original command's arguments as its arguments, and the function's -exit status becomes the exit status of the shell. -If that function is not defined, the shell prints an error -message and returns an exit status of 127. -.PP -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in a -separate execution environment. -Argument 0 is set to the name given, and the remaining arguments -to the command are set to the arguments given, if any. -.PP -If this execution fails because the file is not in executable -format, and the file is not a directory, it is assumed to be -a \fIshell script\fP, a file -containing shell commands. A subshell is spawned to execute -it. This subshell reinitializes itself, so -that the effect is as if a new shell had been invoked -to handle the script, with the exception that the locations of -commands remembered by the parent (see -.B hash -below under -.SM -\fBSHELL BUILTIN COMMANDS\fP) -are retained by the child. -.PP -If the program is a file beginning with -.BR #! , -the remainder of the first line specifies an interpreter -for the program. The shell executes the -specified interpreter on operating systems that do not -handle this executable format themselves. The arguments to the -interpreter consist of a single optional argument following the -interpreter name on the first line of the program, followed -by the name of the program, followed by the command -arguments, if any. -.SH COMMAND EXECUTION ENVIRONMENT -The shell has an \fIexecution environment\fP, which consists of the -following: -.IP \(bu -open files inherited by the shell at invocation, as modified by -redirections supplied to the \fBexec\fP builtin -.IP \(bu -the current working directory as set by \fBcd\fP, \fBpushd\fP, or -\fBpopd\fP, or inherited by the shell at invocation -.IP \(bu -the file creation mode mask as set by \fBumask\fP or inherited from -the shell's parent -.IP \(bu -current traps set by \fBtrap\fP -.IP \(bu -shell parameters that are set by variable assignment or with \fBset\fP -or inherited from the shell's parent in the environment -.IP \(bu -shell functions defined during execution or inherited from the shell's -parent in the environment -.IP \(bu -options enabled at invocation (either by default or with command-line -arguments) or by \fBset\fP -.IP \(bu -options enabled by \fBshopt\fP -.IP \(bu -shell aliases defined with \fBalias\fP -.IP \(bu -various process IDs, including those of background jobs, the value -of \fB$$\fP, and the value of -.SM -.B PPID -.PP -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. -.if n .sp 1 -.IP \(bu -the shell's open files, plus any modifications and additions specified -by redirections to the command -.IP \(bu -the current working directory -.IP \(bu -the file creation mode mask -.IP \(bu -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment -.IP \(bu -traps caught by the shell are reset to the values inherited from the -shell's parent, and traps ignored by the shell are ignored -.PP -A command invoked in this separate environment cannot affect the -shell's execution environment. -.PP -Command substitution, commands grouped with parentheses, -and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed in a -subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. -.PP -Subshells spawned to execute command substitutions inherit the value of -the \fB\-e\fP option from the parent shell. When not in \fIposix\fP mode, -\fBbash\fP clears the \fB\-e\fP option in such subshells. -.PP -If a command is followed by a \fB&\fP and job control is not active, the -default standard input for the command is the empty file \fI/dev/null\fP. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. -.SH ENVIRONMENT -When a program is invoked it is given an array of strings -called the -.IR environment . -This is a list of -\fIname\fP\-\fIvalue\fP pairs, of the form -.IR "name\fR=\fPvalue" . -.PP -The shell provides several ways to manipulate the environment. -On invocation, the shell scans its own environment and -creates a parameter for each name found, automatically marking -it for -.I export -to child processes. Executed commands inherit the environment. -The -.B export -and -.B declare \-x -commands allow parameters and functions to be added to and -deleted from the environment. If the value of a parameter -in the environment is modified, the new value becomes part -of the environment, replacing the old. The environment -inherited by any executed command consists of the shell's -initial environment, whose values may be modified in the shell, -less any pairs removed by the -.B unset -command, plus any additions via the -.B export -and -.B declare \-x -commands. -.PP -The environment for any -.I simple command -or function may be augmented temporarily by prefixing it with -parameter assignments, as described above in -.SM -.BR PARAMETERS . -These assignment statements affect only the environment seen -by that command. -.PP -If the -.B \-k -option is set (see the -.B set -builtin command below), then -.I all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. -.PP -When -.B bash -invokes an external command, the variable -.B _ -is set to the full filename of the command and passed to that -command in its environment. -.SH "EXIT STATUS" -.PP -The exit status of an executed command is the value returned by the -\fIwaitpid\fP system call or equivalent function. Exit statuses -fall between 0 and 255, though, as explained below, the shell may -use values above 125 specially. Exit statuses from shell builtins and -compound commands are also limited to this range. Under certain -circumstances, the shell will use special values to indicate specific -failure modes. -.PP -For the shell's purposes, a command which exits with a -zero exit status has succeeded. An exit status of zero -indicates success. A non-zero exit status indicates failure. -When a command terminates on a fatal signal \fIN\fP, \fBbash\fP uses -the value of 128+\fIN\fP as the exit status. -.PP -If a command is not found, the child process created to -execute it returns a status of 127. If a command is found -but is not executable, the return status is 126. -.PP -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. -.PP -Shell builtin commands return a status of 0 (\fItrue\fP) if -successful, and non-zero (\fIfalse\fP) if an error occurs -while they execute. -All builtins return an exit status of 2 to indicate incorrect usage. -.PP -\fBBash\fP itself returns the exit status of the last command -executed, unless a syntax error occurs, in which case it exits -with a non-zero value. See also the \fBexit\fP builtin -command below. -.SH SIGNALS -When \fBbash\fP is interactive, in the absence of any traps, it ignores -.SM -.B SIGTERM -(so that \fBkill 0\fP does not kill an interactive shell), -and -.SM -.B SIGINT -is caught and handled (so that the \fBwait\fP builtin is interruptible). -In all cases, \fBbash\fP ignores -.SM -.BR SIGQUIT . -If job control is in effect, -.B bash -ignores -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . -.PP -Non-builtin commands run by \fBbash\fP have signal handlers -set to the values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore -.SM -.B SIGINT -and -.SM -.B SIGQUIT -in addition to these inherited handlers. -Commands run as a result of command substitution ignore the -keyboard-generated job control signals -.SM -.BR SIGTTIN , -.SM -.BR SIGTTOU , -and -.SM -.BR SIGTSTP . -.PP -The shell exits by default upon receipt of a -.SM -.BR SIGHUP . -Before exiting, an interactive shell resends the -.SM -.B SIGHUP -to all jobs, running or stopped. -Stopped jobs are sent -.SM -.B SIGCONT -to ensure that they receive the -.SM -.BR SIGHUP . -To prevent the shell from -sending the signal to a particular job, it should be removed from the -jobs table with the -.B disown -builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below) or marked -to not receive -.SM -.B SIGHUP -using -.BR "disown \-h" . -.PP -If the -.B huponexit -shell option has been set with -.BR shopt , -.B bash -sends a -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.PP -If \fBbash\fP is waiting for a command to complete and receives a signal -for which a trap has been set, the trap will not be executed until -the command completes. -When \fBbash\fP is waiting for an asynchronous command via the \fBwait\fP -builtin, the reception of a signal for which a trap has been set will -cause the \fBwait\fP builtin to return immediately with an exit status -greater than 128, immediately after which the trap is executed. -.SH "JOB CONTROL" -.I Job control -refers to the ability to selectively stop (\fIsuspend\fP) -the execution of processes and continue (\fIresume\fP) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the operating system kernel's terminal driver and -.BR bash . -.PP -The shell associates a -.I job -with each pipeline. It keeps a table of currently executing -jobs, which may be listed with the -.B jobs -command. When -.B bash -starts a job asynchronously (in the -.IR background ), -it prints a line that looks like: -.RS -.PP -[1] 25647 -.RE -.PP -indicating that this job is job number 1 and that the process ID -of the last process in the pipeline associated with this job is 25647. -All of the processes in a single pipeline are members of the same job. -.B Bash -uses the -.I job -abstraction as the basis for job control. -.PP -To facilitate the implementation of the user interface to job -control, the operating system maintains the notion of a \fIcurrent terminal -process group ID\fP. Members of this process group (processes whose -process group ID is equal to the current terminal process group ID) -receive keyboard-generated signals such as -.SM -.BR SIGINT . -These processes are said to be in the -.IR foreground . -.I Background -processes are those whose process group ID differs from the terminal's; -such processes are immune to keyboard-generated signals. -Only foreground processes are allowed to read from or, if the -user so specifies with \f(CWstty tostop\fP, write to the -terminal. -Background processes which attempt to read from (write to when -\f(CWstty tostop\fP is in effect) the -terminal are sent a -.SM -.B SIGTTIN (SIGTTOU) -signal by the kernel's terminal driver, -which, unless caught, suspends the process. -.PP -If the operating system on which -.B bash -is running supports -job control, -.B bash -contains facilities to use it. -Typing the -.I suspend -character (typically -.BR ^Z , -Control-Z) while a process is running -causes that process to be stopped and returns control to -.BR bash . -Typing the -.I "delayed suspend" -character (typically -.BR ^Y , -Control-Y) causes the process to be stopped when it -attempts to read input from the terminal, and control to -be returned to -.BR bash . -The user may then manipulate the state of this job, using the -.B bg -command to continue it in the background, the -.B fg -command to continue it in the foreground, or -the -.B kill -command to kill it. A \fB^Z\fP takes effect immediately, -and has the additional side effect of causing pending output -and typeahead to be discarded. -.PP -There are a number of ways to refer to a job in the shell. -The character -.B % -introduces a job specification (\fIjobspec\fP). Job number -.I n -may be referred to as -.BR %n . -A job may also be referred to using a prefix of the name used to -start it, or using a substring that appears in its command line. -For example, -.B %ce -refers to a stopped -.B ce -job. If a prefix matches more than one job, -.B bash -reports an error. Using -.BR %?ce , -on the other hand, refers to any job containing the string -.B ce -in its command line. If the substring matches more than one job, -.B bash -reports an error. The symbols -.B %% -and -.B %+ -refer to the shell's notion of the -.IR "current job" , -which is the last job stopped while it was in -the foreground or started in the background. -The -.I "previous job" -may be referenced using -.BR %\- . -If there is only a single job, \fB%+\fP and \fB%\-\fP can both be used -to refer to that job. -In output pertaining to jobs (e.g., the output of the -.B jobs -command), the current job is always flagged with a -.BR + , -and the previous job with a -.BR \- . -A single % (with no accompanying job specification) also refers to the -current job. -.PP -Simply naming a job can be used to bring it into the -foreground: -.B %1 -is a synonym for -\fB``fg %1''\fP, -bringing job 1 from the background into the foreground. -Similarly, -.B ``%1 &'' -resumes job 1 in the background, equivalent to -\fB``bg %1''\fP. -.PP -The shell learns immediately whenever a job changes state. -Normally, -.B bash -waits until it is about to print a prompt before reporting -changes in a job's status so as to not interrupt -any other output. If the -.B \-b -option to the -.B set -builtin command -is enabled, -.B bash -reports such changes immediately. -Any trap on -.SM -.B SIGCHLD -is executed for each child that exits. -.PP -If an attempt to exit -.B bash -is made while jobs are stopped (or, if the \fBcheckjobs\fP shell option has -been enabled using the \fBshopt\fP builtin, running), the shell prints a -warning message, and, if the \fBcheckjobs\fP option is enabled, lists the -jobs and their statuses. -The -.B jobs -command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -the shell does not print another warning, and any stopped -jobs are terminated. -.SH PROMPTING -When executing interactively, -.B bash -displays the primary prompt -.SM -.B PS1 -when it is ready to read a command, and the secondary prompt -.SM -.B PS2 -when it needs more input to complete a command. -.B Bash -allows these prompt strings to be customized by inserting a number of -backslash-escaped special characters that are decoded as follows: -.RS -.PD 0 -.TP -.B \ea -an ASCII bell character (07) -.TP -.B \ed -the date in "Weekday Month Date" format (e.g., "Tue May 26") -.TP -.B \eD{\fIformat\fP} -the \fIformat\fP is passed to \fIstrftime\fP(3) and the result is inserted -into the prompt string; an empty \fIformat\fP results in a locale-specific -time representation. The braces are required -.TP -.B \ee -an ASCII escape character (033) -.TP -.B \eh -the hostname up to the first `.' -.TP -.B \eH -the hostname -.TP -.B \ej -the number of jobs currently managed by the shell -.TP -.B \el -the basename of the shell's terminal device name -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \es -the name of the shell, the basename of -.B $0 -(the portion following the final slash) -.TP -.B \et -the current time in 24-hour HH:MM:SS format -.TP -.B \eT -the current time in 12-hour HH:MM:SS format -.TP -.B \e@ -the current time in 12-hour am/pm format -.TP -.B \eA -the current time in 24-hour HH:MM format -.TP -.B \eu -the username of the current user -.TP -.B \ev -the version of \fBbash\fP (e.g., 2.00) -.TP -.B \eV -the release of \fBbash\fP, version + patch level (e.g., 2.00.0) -.TP -.B \ew -the current working directory, with -.SM -.B $HOME -abbreviated with a tilde -(uses the value of the -.SM -.B PROMPT_DIRTRIM -variable) -.TP -.B \eW -the basename of the current working directory, with -.SM -.B $HOME -abbreviated with a tilde -.TP -.B \e! -the history number of this command -.TP -.B \e# -the command number of this command -.TP -.B \e$ -if the effective UID is 0, a -.BR # , -otherwise a -.B $ -.TP -.B \e\fInnn\fP -the character corresponding to the octal number \fInnn\fP -.TP -.B \e\e -a backslash -.TP -.B \e[ -begin a sequence of non-printing characters, which could be used to -embed a terminal control sequence into the prompt -.TP -.B \e] -end a sequence of non-printing characters -.PD -.RE -.PP -The command number and the history number are usually different: -the history number of a command is its position in the history -list, which may include commands restored from the history file -(see -.SM -.B HISTORY -below), while the command number is the position in the sequence -of commands executed during the current shell session. -After the string is decoded, it is expanded via -parameter expansion, command substitution, arithmetic -expansion, and quote removal, subject to the value of the -.B promptvars -shell option (see the description of the -.B shopt -command under -.SM -.B "SHELL BUILTIN COMMANDS" -below). -.SH READLINE -This is the library that handles reading input when using an interactive -shell, unless the -.B \-\-noediting -option is given at shell invocation. -Line editing is also used when using the \fB\-e\fP option to the -\fBread\fP builtin. -By default, the line editing commands are similar to those of Emacs. -A vi-style line editing interface is also available. -Line editing can be enabled at any time using the -.B \-o emacs -or -.B \-o vi -options to the -.B set -builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -To turn off line editing after the shell is running, use the -.B +o emacs -or -.B +o vi -options to the -.B set -builtin. -.SS "Readline Notation" -.PP -In this section, the Emacs-style notation is used to denote -keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n -means Control\-N. Similarly, -.I meta -keys are denoted by M\-\fIkey\fR, so M\-x means Meta\-X. (On keyboards -without a -.I meta -key, M\-\fIx\fP means ESC \fIx\fP, i.e., press the Escape key -then the -.I x -key. This makes ESC the \fImeta prefix\fP. -The combination M\-C\-\fIx\fP means ESC\-Control\-\fIx\fP, -or press the Escape key -then hold the Control key while pressing the -.I x -key.) -.PP -Readline commands may be given numeric -.IR arguments , -which normally act as a repeat count. -Sometimes, however, it is the sign of the argument that is significant. -Passing a negative argument to a command that acts in the forward -direction (e.g., \fBkill\-line\fP) causes that command to act in a -backward direction. -Commands whose behavior with arguments deviates from this are noted -below. -.PP -When a command is described as \fIkilling\fP text, the text -deleted is saved for possible future retrieval -(\fIyanking\fP). The killed text is saved in a -\fIkill ring\fP. Consecutive kills cause the text to be -accumulated into one unit, which can be yanked all at once. -Commands which do not kill text separate the chunks of text -on the kill ring. -.SS "Readline Initialization" -.PP -Readline is customized by putting commands in an initialization -file (the \fIinputrc\fP file). -The name of this file is taken from the value of the -.SM -.B INPUTRC -variable. If that variable is unset, the default is -.IR ~/.inputrc . -When a program which uses the readline library starts up, the -initialization file is read, and the key bindings and variables -are set. -There are only a few basic constructs allowed in the -readline initialization file. -Blank lines are ignored. -Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional constructs. -Other lines denote key bindings and variable settings. -.PP -The default key-bindings may be changed with an -.I inputrc -file. -Other programs that use this library may add their own commands -and bindings. -.PP -For example, placing -.RS -.PP -M\-Control\-u: universal\-argument -.RE -or -.RS -C\-Meta\-u: universal\-argument -.RE -into the -.I inputrc -would make M\-C\-u execute the readline command -.IR universal\-argument . -.PP -The following symbolic character names are recognized: -.IR RUBOUT , -.IR DEL , -.IR ESC , -.IR LFD , -.IR NEWLINE , -.IR RET , -.IR RETURN , -.IR SPC , -.IR SPACE , -and -.IR TAB . -.PP -In addition to command names, readline allows keys to be bound -to a string that is inserted when the key is pressed (a \fImacro\fP). -.SS "Readline Key Bindings" -.PP -The syntax for controlling key bindings in the -.I inputrc -file is simple. All that is required is the name of the -command or the text of a macro and a key sequence to which -it should be bound. The name may be specified in one of two ways: -as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP -prefixes, or as a key sequence. -.PP -When using the form \fBkeyname\fP:\^\fIfunction\-name\fP or \fImacro\fP, -.I keyname -is the name of a key spelled out in English. For example: -.sp -.RS -Control-u: universal\-argument -.br -Meta-Rubout: backward-kill-word -.br -Control-o: "> output" -.RE -.LP -In the above example, -.I C\-u -is bound to the function -.BR universal\-argument , -.I M\-DEL -is bound to the function -.BR backward\-kill\-word , -and -.I C\-o -is bound to run the macro -expressed on the right hand side (that is, to insert the text -.if t \f(CW> output\fP -.if n ``> output'' -into the line). -.PP -In the second form, \fB"keyseq"\fP:\^\fIfunction\-name\fP or \fImacro\fP, -.B keyseq -differs from -.B keyname -above in that strings denoting -an entire key sequence may be specified by placing the sequence -within double quotes. Some GNU Emacs style key escapes can be -used, as in the following example, but the symbolic character names -are not recognized. -.sp -.RS -"\eC\-u": universal\-argument -.br -"\eC\-x\eC\-r": re\-read\-init\-file -.br -"\ee[11~": "Function Key 1" -.RE -.PP -In this example, -.I C\-u -is again bound to the function -.BR universal\-argument . -.I "C\-x C\-r" -is bound to the function -.BR re\-read\-init\-file , -and -.I "ESC [ 1 1 ~" -is bound to insert the text -.if t \f(CWFunction Key 1\fP. -.if n ``Function Key 1''. -.PP -The full set of GNU Emacs style escape sequences is -.RS -.PD 0 -.TP -.B \eC\- -control prefix -.TP -.B \eM\- -meta prefix -.TP -.B \ee -an escape character -.TP -.B \e\e -backslash -.TP -.B \e" -literal " -.TP -.B \e\(aq -literal \(aq -.RE -.PD -.PP -In addition to the GNU Emacs style escape sequences, a second -set of backslash escapes is available: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ed -delete -.TP -.B \ef -form feed -.TP -.B \en -newline -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(one to three digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.RE -.PD -.PP -When entering the text of a macro, single or double quotes must -be used to indicate a macro definition. -Unquoted text is assumed to be a function name. -In the macro body, the backslash escapes described above are expanded. -Backslash will quote any other character in the macro text, -including " and \(aq. -.PP -.B Bash -allows the current readline key bindings to be displayed or modified -with the -.B bind -builtin command. The editing mode may be switched during interactive -use by using the -.B \-o -option to the -.B set -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). -.SS "Readline Variables" -.PP -Readline has variables that can be used to further customize its -behavior. A variable may be set in the -.I inputrc -file with a statement of the form -.RS -.PP -\fBset\fP \fIvariable\-name\fP \fIvalue\fP -.RE -.PP -Except where noted, readline variables can take the values -.B On -or -.B Off -(without regard to case). -Unrecognized variable names are ignored. -When a variable value is read, empty or null values, "on" (case-insensitive), -and "1" are equivalent to \fBOn\fP. All other values are equivalent to -\fBOff\fP. -The variables and their default values are: -.PP -.PD 0 -.TP -.B bell\-style (audible) -Controls what happens when readline wants to ring the terminal bell. -If set to \fBnone\fP, readline never rings the bell. If set to -\fBvisible\fP, readline uses a visible bell if one is available. -If set to \fBaudible\fP, readline attempts to ring the terminal's bell. -.TP -.B bind\-tty\-special\-chars (On) -If set to \fBOn\fP, readline attempts to bind the control characters -treated specially by the kernel's terminal driver to their readline -equivalents. -.TP -.B colored\-stats (Off) -If set to \fBOn\fP, readline displays possible completions using different -colors to indicate their file type. -The color definitions are taken from the value of the \fBLS_COLORS\fP -environment variable. -.TP -.B comment\-begin (``#'') -The string that is inserted when the readline -.B insert\-comment -command is executed. -This command is bound to -.B M\-# -in emacs mode and to -.B # -in vi command mode. -.TP -.B completion\-ignore\-case (Off) -If set to \fBOn\fP, readline performs filename matching and completion -in a case\-insensitive fashion. -.TP -.B completion\-prefix\-display\-length (0) -The length in characters of the common prefix of a list of possible -completions that is displayed without modification. When set to a -value greater than zero, common prefixes longer than this value are -replaced with an ellipsis when displaying possible completions. -.TP -.B completion\-query\-items (100) -This determines when the user is queried about viewing -the number of possible completions -generated by the \fBpossible\-completions\fP command. -It may be set to any integer value greater than or equal to -zero. If the number of possible completions is greater than -or equal to the value of this variable, the user is asked whether -or not he wishes to view them; otherwise they are simply listed -on the terminal. -.TP -.B convert\-meta (On) -If set to \fBOn\fP, readline will convert characters with the -eighth bit set to an ASCII key sequence -by stripping the eighth bit and prefixing an -escape character (in effect, using escape as the \fImeta prefix\fP). -.TP -.B disable\-completion (Off) -If set to \fBOn\fP, readline will inhibit word completion. Completion -characters will be inserted into the line as if they had been -mapped to \fBself-insert\fP. -.TP -.B editing\-mode (emacs) -Controls whether readline begins with a set of key bindings similar -to \fIEmacs\fP or \fIvi\fP. -.B editing\-mode -can be set to either -.B emacs -or -.BR vi . -.TP -.B echo\-control\-characters (On) -When set to \fBOn\fP, on operating systems that indicate they support it, -readline echoes a character corresponding to a signal generated from the -keyboard. -.TP -.B enable\-keypad (Off) -When set to \fBOn\fP, readline will try to enable the application -keypad when it is called. Some systems need this to enable the -arrow keys. -.TP -.B enable\-meta\-key (On) -When set to \fBOn\fP, readline will try to enable any meta modifier -key the terminal claims to support when it is called. On many terminals, -the meta key is used to send eight-bit characters. -.TP -.B expand\-tilde (Off) -If set to \fBOn\fP, tilde expansion is performed when readline -attempts word completion. -.TP -.B history\-preserve\-point (Off) -If set to \fBOn\fP, the history code attempts to place point at the -same location on each history line retrieved with \fBprevious-history\fP -or \fBnext-history\fP. -.TP -.B history\-size (0) -Set the maximum number of history entries saved in the history list. If -set to zero, the number of entries in the history list is not limited. -.TP -.B horizontal\-scroll\-mode (Off) -When set to \fBOn\fP, makes readline use a single line for display, -scrolling the input horizontally on a single screen line when it -becomes longer than the screen width rather than wrapping to a new line. -.TP -.B input\-meta (Off) -If set to \fBOn\fP, readline will enable eight-bit input (that is, -it will not strip the high bit from the characters it reads), -regardless of what the terminal claims it can support. The name -.B meta\-flag -is a synonym for this variable. -.TP -.B isearch\-terminators (``C\-[C\-J'') -The string of characters that should terminate an incremental -search without subsequently executing the character as a command. -If this variable has not been given a value, the characters -\fIESC\fP and \fIC\-J\fP will terminate an incremental search. -.TP -.B keymap (emacs) -Set the current readline keymap. The set of valid keymap names is -\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, -vi\-command\fP, and -.IR vi\-insert . -\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is -equivalent to \fIemacs\-standard\fP. The default value is -.IR emacs ; -the value of -.B editing\-mode -also affects the default keymap. -.TP -.B keyseq\-timeout (500) -Specifies the duration \fIreadline\fP will wait for a character when reading an -ambiguous key sequence (one that can form a complete key sequence using -the input read so far, or can take additional input to complete a longer -key sequence). -If no input is received within the timeout, \fIreadline\fP will use the shorter -but complete key sequence. -The value is specified in milliseconds, so a value of 1000 means that -\fIreadline\fP will wait one second for additional input. -If this variable is set to a value less than or equal to zero, or to a -non-numeric value, \fIreadline\fP will wait until another key is pressed to -decide which key sequence to complete. -.TP -.B mark\-directories (On) -If set to \fBOn\fP, completed directory names have a slash -appended. -.TP -.B mark\-modified\-lines (Off) -If set to \fBOn\fP, history lines that have been modified are displayed -with a preceding asterisk (\fB*\fP). -.TP -.B mark\-symlinked\-directories (Off) -If set to \fBOn\fP, completed names which are symbolic links to directories -have a slash appended (subject to the value of -\fBmark\-directories\fP). -.TP -.B match\-hidden\-files (On) -This variable, when set to \fBOn\fP, causes readline to match files whose -names begin with a `.' (hidden files) when performing filename -completion. -If set to \fBOff\fP, the leading `.' must be -supplied by the user in the filename to be completed. -.TP -.B menu\-complete\-display\-prefix (Off) -If set to \fBOn\fP, menu completion displays the common prefix of the -list of possible completions (which may be empty) before cycling through -the list. -.TP -.B output\-meta (Off) -If set to \fBOn\fP, readline will display characters with the -eighth bit set directly rather than as a meta-prefixed escape -sequence. -.TP -.B page\-completions (On) -If set to \fBOn\fP, readline uses an internal \fImore\fP-like pager -to display a screenful of possible completions at a time. -.TP -.B print\-completions\-horizontally (Off) -If set to \fBOn\fP, readline will display completions with matches -sorted horizontally in alphabetical order, rather than down the screen. -.TP -.B revert\-all\-at\-newline (Off) -If set to \fBOn\fP, readline will undo all changes to history lines -before returning when \fBaccept\-line\fP is executed. By default, -history lines may be modified and retain individual undo lists across -calls to \fBreadline\fP. -.TP -.B show\-all\-if\-ambiguous (Off) -This alters the default behavior of the completion functions. If -set to -.BR On , -words which have more than one possible completion cause the -matches to be listed immediately instead of ringing the bell. -.TP -.B show\-all\-if\-unmodified (Off) -This alters the default behavior of the completion functions in -a fashion similar to \fBshow\-all\-if\-ambiguous\fP. -If set to -.BR On , -words which have more than one possible completion without any -possible partial completion (the possible completions don't share -a common prefix) cause the matches to be listed immediately instead -of ringing the bell. -.TP -.B skip\-completed\-text (Off) -If set to \fBOn\fP, this alters the default completion behavior when -inserting a single match into the line. It's only active when -performing completion in the middle of a word. If enabled, readline -does not insert characters from the completion that match characters -after point in the word being completed, so portions of the word -following the cursor are not duplicated. -.TP -.B visible\-stats (Off) -If set to \fBOn\fP, a character denoting a file's type as reported -by \fIstat\fP(2) is appended to the filename when listing possible -completions. -.PD -.SS "Readline Conditional Constructs" -.PP -Readline implements a facility similar in spirit to the conditional -compilation features of the C preprocessor which allows key -bindings and variable settings to be performed as the result -of tests. There are four parser directives used. -.IP \fB$if\fP -The -.B $if -construct allows bindings to be made based on the -editing mode, the terminal being used, or the application using -readline. The text of the test extends to the end of the line; -no characters are required to isolate it. -.RS -.IP \fBmode\fP -The \fBmode=\fP form of the \fB$if\fP directive is used to test -whether readline is in emacs or vi mode. -This may be used in conjunction -with the \fBset keymap\fP command, for instance, to set bindings in -the \fIemacs\-standard\fP and \fIemacs\-ctlx\fP keymaps only if -readline is starting out in emacs mode. -.IP \fBterm\fP -The \fBterm=\fP form may be used to include terminal-specific -key bindings, perhaps to bind the key sequences output by the -terminal's function keys. The word on the right side of the -.B = -is tested against the both full name of the terminal and the portion -of the terminal name before the first \fB\-\fP. This allows -.I sun -to match both -.I sun -and -.IR sun\-cmd , -for instance. -.IP \fBapplication\fP -The \fBapplication\fP construct is used to include -application-specific settings. Each program using the readline -library sets the \fIapplication name\fP, and an initialization -file can test for a particular value. -This could be used to bind key sequences to functions useful for -a specific program. For instance, the following command adds a -key sequence that quotes the current or previous word in \fBbash\fP: -.sp 1 -.RS -.nf -\fB$if\fP Bash -# Quote the current or previous word -"\eC\-xq": "\eeb\e"\eef\e"" -\fB$endif\fP -.fi -.RE -.RE -.IP \fB$endif\fP -This command, as seen in the previous example, terminates an -\fB$if\fP command. -.IP \fB$else\fP -Commands in this branch of the \fB$if\fP directive are executed if -the test fails. -.IP \fB$include\fP -This directive takes a single filename as an argument and reads commands -and bindings from that file. For example, the following directive -would read \fI/etc/inputrc\fP: -.sp 1 -.RS -.nf -\fB$include\fP \^ \fI/etc/inputrc\fP -.fi -.RE -.SS Searching -.PP -Readline provides commands for searching through the command history -(see -.SM -.B HISTORY -below) for lines containing a specified string. -There are two search modes: -.I incremental -and -.IR non-incremental . -.PP -Incremental searches begin before the user has finished typing the -search string. -As each character of the search string is typed, readline displays -the next entry from the history matching the string typed so far. -An incremental search requires only as many characters as needed to -find the desired history entry. -The characters present in the value of the \fBisearch-terminators\fP -variable are used to terminate an incremental search. -If that variable has not been assigned a value the Escape and -Control-J characters will terminate an incremental search. -Control-G will abort an incremental search and restore the original -line. -When the search is terminated, the history entry containing the -search string becomes the current line. -.PP -To find other matching entries in the history list, type Control-S or -Control-R as appropriate. -This will search backward or forward in the history for the next -entry matching the search string typed so far. -Any other key sequence bound to a readline command will terminate -the search and execute that command. -For instance, a \fInewline\fP will terminate the search and accept -the line, thereby executing the command from the history list. -.PP -Readline remembers the last incremental search string. If two -Control-Rs are typed without any intervening characters defining a -new search string, any remembered search string is used. -.PP -Non-incremental searches read the entire search string before starting -to search for matching history lines. The search string may be -typed by the user or be part of the contents of the current line. -.SS "Readline Command Names" -.PP -The following is a list of the names of the commands and the default -key sequences to which they are bound. -Command names without an accompanying key sequence are unbound by default. -In the following descriptions, \fIpoint\fP refers to the current cursor -position, and \fImark\fP refers to a cursor position saved by the -\fBset\-mark\fP command. -The text between the point and mark is referred to as the \fIregion\fP. -.SS Commands for Moving -.PP -.PD 0 -.TP -.B beginning\-of\-line (C\-a) -Move to the start of the current line. -.TP -.B end\-of\-line (C\-e) -Move to the end of the line. -.TP -.B forward\-char (C\-f) -Move forward a character. -.TP -.B backward\-char (C\-b) -Move back a character. -.TP -.B forward\-word (M\-f) -Move forward to the end of the next word. Words are composed of -alphanumeric characters (letters and digits). -.TP -.B backward\-word (M\-b) -Move back to the start of the current or previous word. -Words are composed of alphanumeric characters (letters and digits). -.TP -.B shell\-forward\-word -Move forward to the end of the next word. -Words are delimited by non-quoted shell metacharacters. -.TP -.B shell\-backward\-word -Move back to the start of the current or previous word. -Words are delimited by non-quoted shell metacharacters. -.TP -.B clear\-screen (C\-l) -Clear the screen leaving the current line at the top of the screen. -With an argument, refresh the current line without clearing the -screen. -.TP -.B redraw\-current\-line -Refresh the current line. -.PD -.SS Commands for Manipulating the History -.PP -.PD 0 -.TP -.B accept\-line (Newline, Return) -Accept the line regardless of where the cursor is. If this line is -non-empty, add it to the history list according to the state of the -.SM -.B HISTCONTROL -variable. If the line is a modified history -line, then restore the history line to its original state. -.TP -.B previous\-history (C\-p) -Fetch the previous command from the history list, moving back in -the list. -.TP -.B next\-history (C\-n) -Fetch the next command from the history list, moving forward in the -list. -.TP -.B beginning\-of\-history (M\-<) -Move to the first line in the history. -.TP -.B end\-of\-history (M\->) -Move to the end of the input history, i.e., the line currently being -entered. -.TP -.B reverse\-search\-history (C\-r) -Search backward starting at the current line and moving `up' through -the history as necessary. This is an incremental search. -.TP -.B forward\-search\-history (C\-s) -Search forward starting at the current line and moving `down' through -the history as necessary. This is an incremental search. -.TP -.B non\-incremental\-reverse\-search\-history (M\-p) -Search backward through the history starting at the current line -using a non-incremental search for a string supplied by the user. -.TP -.B non\-incremental\-forward\-search\-history (M\-n) -Search forward through the history using a non-incremental search for -a string supplied by the user. -.TP -.B history\-search\-forward -Search forward through the history for the string of characters -between the start of the current line and the point. -This is a non-incremental search. -.TP -.B history\-search\-backward -Search backward through the history for the string of characters -between the start of the current line and the point. -This is a non-incremental search. -.TP -.B yank\-nth\-arg (M\-C\-y) -Insert the first argument to the previous command (usually -the second word on the previous line) at point. -With an argument -.IR n , -insert the \fIn\fPth word from the previous command (the words -in the previous command begin with word 0). A negative argument -inserts the \fIn\fPth word from the end of the previous command. -Once the argument \fIn\fP is computed, the argument is extracted -as if the "!\fIn\fP" history expansion had been specified. -.TP -.B -yank\-last\-arg (M\-.\^, M\-_\^) -Insert the last argument to the previous command (the last word of -the previous history entry). -With a numeric argument, behave exactly like \fByank\-nth\-arg\fP. -Successive calls to \fByank\-last\-arg\fP move back through the history -list, inserting the last word (or the word specified by the argument to -the first call) of each line in turn. -Any numeric argument supplied to these successive calls determines -the direction to move through the history. A negative argument switches -the direction through the history (back or forward). -The history expansion facilities are used to extract the last argument, -as if the "!$" history expansion had been specified. -.TP -.B shell\-expand\-line (M\-C\-e) -Expand the line as the shell does. This -performs alias and history expansion as well as all of the shell -word expansions. See -.SM -.B HISTORY EXPANSION -below for a description of history expansion. -.TP -.B history\-expand\-line (M\-^) -Perform history expansion on the current line. -See -.SM -.B HISTORY EXPANSION -below for a description of history expansion. -.TP -.B magic\-space -Perform history expansion on the current line and insert a space. -See -.SM -.B HISTORY EXPANSION -below for a description of history expansion. -.TP -.B alias\-expand\-line -Perform alias expansion on the current line. -See -.SM -.B ALIASES -above for a description of alias expansion. -.TP -.B history\-and\-alias\-expand\-line -Perform history and alias expansion on the current line. -.TP -.B insert\-last\-argument (M\-.\^, M\-_\^) -A synonym for \fByank\-last\-arg\fP. -.TP -.B operate\-and\-get\-next (C\-o) -Accept the current line for execution and fetch the next line -relative to the current line from the history for editing. Any -argument is ignored. -.TP -.B edit\-and\-execute\-command (C\-xC\-e) -Invoke an editor on the current command line, and execute the result as shell -commands. -\fBBash\fP attempts to invoke -.SM -.BR $VISUAL , -.SM -.BR $EDITOR , -and \fIemacs\fP as the editor, in that order. -.PD -.SS Commands for Changing Text -.PP -.PD 0 -.TP -.B delete\-char (C\-d) -Delete the character at point. If point is at the -beginning of the line, there are no characters in the line, and -the last character typed was not bound to \fBdelete\-char\fP, -then return -.SM -.BR EOF . -.TP -.B backward\-delete\-char (Rubout) -Delete the character behind the cursor. When given a numeric argument, -save the deleted text on the kill ring. -.TP -.B forward\-backward\-delete\-char -Delete the character under the cursor, unless the cursor is at the -end of the line, in which case the character behind the cursor is -deleted. -.TP -.B quoted\-insert (C\-q, C\-v) -Add the next character typed to the line verbatim. This is -how to insert characters like \fBC\-q\fP, for example. -.TP -.B tab\-insert (C\-v TAB) -Insert a tab character. -.TP -.B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...) -Insert the character typed. -.TP -.B transpose\-chars (C\-t) -Drag the character before point forward over the character at point, -moving point forward as well. -If point is at the end of the line, then this transposes -the two characters before point. -Negative arguments have no effect. -.TP -.B transpose\-words (M\-t) -Drag the word before point past the word after point, -moving point over that word as well. -If point is at the end of the line, this transposes -the last two words on the line. -.TP -.B upcase\-word (M\-u) -Uppercase the current (or following) word. With a negative argument, -uppercase the previous word, but do not move point. -.TP -.B downcase\-word (M\-l) -Lowercase the current (or following) word. With a negative argument, -lowercase the previous word, but do not move point. -.TP -.B capitalize\-word (M\-c) -Capitalize the current (or following) word. With a negative argument, -capitalize the previous word, but do not move point. -.TP -.B overwrite\-mode -Toggle overwrite mode. With an explicit positive numeric argument, -switches to overwrite mode. With an explicit non-positive numeric -argument, switches to insert mode. This command affects only -\fBemacs\fP mode; \fBvi\fP mode does overwrite differently. -Each call to \fIreadline()\fP starts in insert mode. -In overwrite mode, characters bound to \fBself\-insert\fP replace -the text at point rather than pushing the text to the right. -Characters bound to \fBbackward\-delete\-char\fP replace the character -before point with a space. By default, this command is unbound. -.PD -.SS Killing and Yanking -.PP -.PD 0 -.TP -.B kill\-line (C\-k) -Kill the text from point to the end of the line. -.TP -.B backward\-kill\-line (C\-x Rubout) -Kill backward to the beginning of the line. -.TP -.B unix\-line\-discard (C\-u) -Kill backward from point to the beginning of the line. -The killed text is saved on the kill-ring. -.\" There is no real difference between this and backward-kill-line -.TP -.B kill\-whole\-line -Kill all characters on the current line, no matter where point is. -.TP -.B kill\-word (M\-d) -Kill from point to the end of the current word, or if between -words, to the end of the next word. -Word boundaries are the same as those used by \fBforward\-word\fP. -.TP -.B backward\-kill\-word (M\-Rubout) -Kill the word behind point. -Word boundaries are the same as those used by \fBbackward\-word\fP. -.TP -.B shell\-kill\-word (M\-d) -Kill from point to the end of the current word, or if between -words, to the end of the next word. -Word boundaries are the same as those used by \fBshell\-forward\-word\fP. -.TP -.B shell\-backward\-kill\-word (M\-Rubout) -Kill the word behind point. -Word boundaries are the same as those used by \fBshell\-backward\-word\fP. -.TP -.B unix\-word\-rubout (C\-w) -Kill the word behind point, using white space as a word boundary. -The killed text is saved on the kill-ring. -.TP -.B unix\-filename\-rubout -Kill the word behind point, using white space and the slash character -as the word boundaries. -The killed text is saved on the kill-ring. -.TP -.B delete\-horizontal\-space (M\-\e) -Delete all spaces and tabs around point. -.TP -.B kill\-region -Kill the text in the current region. -.TP -.B copy\-region\-as\-kill -Copy the text in the region to the kill buffer. -.TP -.B copy\-backward\-word -Copy the word before point to the kill buffer. -The word boundaries are the same as \fBbackward\-word\fP. -.TP -.B copy\-forward\-word -Copy the word following point to the kill buffer. -The word boundaries are the same as \fBforward\-word\fP. -.TP -.B yank (C\-y) -Yank the top of the kill ring into the buffer at point. -.TP -.B yank\-pop (M\-y) -Rotate the kill ring, and yank the new top. Only works following -.B yank -or -.BR yank\-pop . -.PD -.SS Numeric Arguments -.PP -.PD 0 -.TP -.B digit\-argument (M\-0, M\-1, ..., M\-\-) -Add this digit to the argument already accumulating, or start a new -argument. M\-\- starts a negative argument. -.TP -.B universal\-argument -This is another way to specify an argument. -If this command is followed by one or more digits, optionally with a -leading minus sign, those digits define the argument. -If the command is followed by digits, executing -.B universal\-argument -again ends the numeric argument, but is otherwise ignored. -As a special case, if this command is immediately followed by a -character that is neither a digit or minus sign, the argument count -for the next command is multiplied by four. -The argument count is initially one, so executing this function the -first time makes the argument count four, a second time makes the -argument count sixteen, and so on. -.PD -.SS Completing -.PP -.PD 0 -.TP -.B complete (TAB) -Attempt to perform completion on the text before point. -.B Bash -attempts completion treating the text as a variable (if the -text begins with \fB$\fP), username (if the text begins with -\fB~\fP), hostname (if the text begins with \fB@\fP), or -command (including aliases and functions) in turn. If none -of these produces a match, filename completion is attempted. -.TP -.B possible\-completions (M\-?) -List the possible completions of the text before point. -.TP -.B insert\-completions (M\-*) -Insert all completions of the text before point -that would have been generated by -\fBpossible\-completions\fP. -.TP -.B menu\-complete -Similar to \fBcomplete\fP, but replaces the word to be completed -with a single match from the list of possible completions. -Repeated execution of \fBmenu\-complete\fP steps through the list -of possible completions, inserting each match in turn. -At the end of the list of completions, the bell is rung -(subject to the setting of \fBbell\-style\fP) -and the original text is restored. -An argument of \fIn\fP moves \fIn\fP positions forward in the list -of matches; a negative argument may be used to move backward -through the list. -This command is intended to be bound to \fBTAB\fP, but is unbound -by default. -.TP -.B menu\-complete\-backward -Identical to \fBmenu\-complete\fP, but moves backward through the list -of possible completions, as if \fBmenu\-complete\fP had been given a -negative argument. This command is unbound by default. -.TP -.B delete\-char\-or\-list -Deletes the character under the cursor if not at the beginning or -end of the line (like \fBdelete\-char\fP). -If at the end of the line, behaves identically to -\fBpossible\-completions\fP. -This command is unbound by default. -.TP -.B complete\-filename (M\-/) -Attempt filename completion on the text before point. -.TP -.B possible\-filename\-completions (C\-x /) -List the possible completions of the text before point, -treating it as a filename. -.TP -.B complete\-username (M\-~) -Attempt completion on the text before point, treating -it as a username. -.TP -.B possible\-username\-completions (C\-x ~) -List the possible completions of the text before point, -treating it as a username. -.TP -.B complete\-variable (M\-$) -Attempt completion on the text before point, treating -it as a shell variable. -.TP -.B possible\-variable\-completions (C\-x $) -List the possible completions of the text before point, -treating it as a shell variable. -.TP -.B complete\-hostname (M\-@) -Attempt completion on the text before point, treating -it as a hostname. -.TP -.B possible\-hostname\-completions (C\-x @) -List the possible completions of the text before point, -treating it as a hostname. -.TP -.B complete\-command (M\-!) -Attempt completion on the text before point, treating -it as a command name. Command completion attempts to -match the text against aliases, reserved words, shell -functions, shell builtins, and finally executable filenames, -in that order. -.TP -.B possible\-command\-completions (C\-x !) -List the possible completions of the text before point, -treating it as a command name. -.TP -.B dynamic\-complete\-history (M\-TAB) -Attempt completion on the text before point, comparing -the text against lines from the history list for possible -completion matches. -.TP -.B dabbrev\-expand -Attempt menu completion on the text before point, comparing -the text against lines from the history list for possible -completion matches. -.TP -.B complete\-into\-braces (M\-{) -Perform filename completion and insert the list of possible completions -enclosed within braces so the list is available to the shell (see -.B Brace Expansion -above). -.PD -.SS Keyboard Macros -.PP -.PD 0 -.TP -.B start\-kbd\-macro (C\-x (\^) -Begin saving the characters typed into the current keyboard macro. -.TP -.B end\-kbd\-macro (C\-x )\^) -Stop saving the characters typed into the current keyboard macro -and store the definition. -.TP -.B call\-last\-kbd\-macro (C\-x e) -Re-execute the last keyboard macro defined, by making the characters -in the macro appear as if typed at the keyboard. -.B print\-last\-kbd\-macro () -Print the last keyboard macro defined in a format suitable for the -\fIinputrc\fP file. -.PD -.SS Miscellaneous -.PP -.PD 0 -.TP -.B re\-read\-init\-file (C\-x C\-r) -Read in the contents of the \fIinputrc\fP file, and incorporate -any bindings or variable assignments found there. -.TP -.B abort (C\-g) -Abort the current editing command and -ring the terminal's bell (subject to the setting of -.BR bell\-style ). -.TP -.B do\-uppercase\-version (M\-a, M\-b, M\-\fIx\fP, ...) -If the metafied character \fIx\fP is lowercase, run the command -that is bound to the corresponding uppercase character. -.TP -.B prefix\-meta (ESC) -Metafy the next character typed. -.SM -.B ESC -.B f -is equivalent to -.BR Meta\-f . -.TP -.B undo (C\-_, C\-x C\-u) -Incremental undo, separately remembered for each line. -.TP -.B revert\-line (M\-r) -Undo all changes made to this line. This is like executing the -.B undo -command enough times to return the line to its initial state. -.TP -.B tilde\-expand (M\-&) -Perform tilde expansion on the current word. -.TP -.B set\-mark (C\-@, M\-) -Set the mark to the point. If a -numeric argument is supplied, the mark is set to that position. -.TP -.B exchange\-point\-and\-mark (C\-x C\-x) -Swap the point with the mark. The current cursor position is set to -the saved position, and the old cursor position is saved as the mark. -.TP -.B character\-search (C\-]) -A character is read and point is moved to the next occurrence of that -character. A negative count searches for previous occurrences. -.TP -.B character\-search\-backward (M\-C\-]) -A character is read and point is moved to the previous occurrence of that -character. A negative count searches for subsequent occurrences. -.TP -.B skip\-csi\-sequence -Read enough characters to consume a multi-key sequence such as those -defined for keys like Home and End. Such sequences begin with a -Control Sequence Indicator (CSI), usually ESC\-[. If this sequence is -bound to "\e[", keys producing such sequences will have no effect -unless explicitly bound to a readline command, instead of inserting -stray characters into the editing buffer. This is unbound by default, -but usually bound to ESC\-[. -.TP -.B insert\-comment (M\-#) -Without a numeric argument, the value of the readline -.B comment\-begin -variable is inserted at the beginning of the current line. -If a numeric argument is supplied, this command acts as a toggle: if -the characters at the beginning of the line do not match the value -of \fBcomment\-begin\fP, the value is inserted, otherwise -the characters in \fBcomment\-begin\fP are deleted from the beginning of -the line. -In either case, the line is accepted as if a newline had been typed. -The default value of -\fBcomment\-begin\fP causes this command to make the current line -a shell comment. -If a numeric argument causes the comment character to be removed, the line -will be executed by the shell. -.TP -.B glob\-complete\-word (M\-g) -The word before point is treated as a pattern for pathname expansion, -with an asterisk implicitly appended. This pattern is used to -generate a list of matching filenames for possible completions. -.TP -.B glob\-expand\-word (C\-x *) -The word before point is treated as a pattern for pathname expansion, -and the list of matching filenames is inserted, replacing the word. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B glob\-list\-expansions (C\-x g) -The list of expansions that would have been generated by -.B glob\-expand\-word -is displayed, and the line is redrawn. -If a numeric argument is supplied, an asterisk is appended before -pathname expansion. -.TP -.B dump\-functions -Print all of the functions and their key bindings to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-variables -Print all of the settable readline variables and their values to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-macros -Print all of the readline key sequences bound to macros and the -strings they output. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B display\-shell\-version (C\-x C\-v) -Display version information about the current instance of -.BR bash . -.PD -.SS Programmable Completion -.PP -When word completion is attempted for an argument to a command for -which a completion specification (a \fIcompspec\fP) has been defined -using the \fBcomplete\fP builtin (see -.SM -.B "SHELL BUILTIN COMMANDS" -below), the programmable completion facilities are invoked. -.PP -First, the command name is identified. -If the command word is the empty string (completion attempted at the -beginning of an empty line), any compspec defined with -the \fB\-E\fP option to \fBcomplete\fP is used. -If a compspec has been defined for that command, the -compspec is used to generate the list of possible completions for the word. -If the command word is a full pathname, a compspec for the full -pathname is searched for first. -If no compspec is found for the full pathname, an attempt is made to -find a compspec for the portion following the final slash. -If those searches do not result in a compspec, any compspec defined with -the \fB\-D\fP option to \fBcomplete\fP is used as the default. -.PP -Once a compspec has been found, it is used to generate the list of -matching words. -If a compspec is not found, the default \fBbash\fP completion as -described above under \fBCompleting\fP is performed. -.PP -First, the actions specified by the compspec are used. -Only matches which are prefixed by the word being completed are -returned. -When the -.B \-f -or -.B \-d -option is used for filename or directory name completion, the shell -variable -.SM -.B FIGNORE -is used to filter the matches. -.PP -Any completions specified by a pathname expansion pattern to the -\fB\-G\fP option are generated next. -The words generated by the pattern need not match the word -being completed. -The -.SM -.B GLOBIGNORE -shell variable is not used to filter the matches, but the -.SM -.B FIGNORE -variable is used. -.PP -Next, the string specified as the argument to the \fB\-W\fP option -is considered. -The string is first split using the characters in the -.SM -.B IFS -special variable as delimiters. -Shell quoting is honored. -Each word is then expanded using -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, and arithmetic expansion, -as described above under -.SM -.BR EXPANSION . -The results are split using the rules described above under -\fBWord Splitting\fP. -The results of the expansion are prefix-matched against the word being -completed, and the matching words become the possible completions. -.PP -After these matches have been generated, any shell function or command -specified with the \fB\-F\fP and \fB\-C\fP options is invoked. -When the command or function is invoked, the -.SM -.BR COMP_LINE , -.SM -.BR COMP_POINT , -.SM -.BR COMP_KEY , -and -.SM -.B COMP_TYPE -variables are assigned values as described above under -\fBShell Variables\fP. -If a shell function is being invoked, the -.SM -.B COMP_WORDS -and -.SM -.B COMP_CWORD -variables are also set. -When the function or command is invoked, -the first argument (\fB$1\fP) is the name of the command whose arguments are -being completed, -the second argument (\fB$2\fP) is the word being completed, -and the third argument (\fB$3\fP) is the word preceding the word being -completed on the current command line. -No filtering of the generated completions against the word being completed -is performed; the function or command has complete freedom in generating -the matches. -.PP -Any function specified with \fB\-F\fP is invoked first. -The function may use any of the shell facilities, including the -\fBcompgen\fP builtin described below, to generate the matches. -It must put the possible completions in the -.SM -.B COMPREPLY -array variable, one per array element. -.PP -Next, any command specified with the \fB\-C\fP option is invoked -in an environment equivalent to command substitution. -It should print a list of completions, one per line, to the -standard output. -Backslash may be used to escape a newline, if necessary. -.PP -After all of the possible completions are generated, any filter -specified with the \fB\-X\fP option is applied to the list. -The filter is a pattern as used for pathname expansion; a \fB&\fP -in the pattern is replaced with the text of the word being completed. -A literal \fB&\fP may be escaped with a backslash; the backslash -is removed before attempting a match. -Any completion that matches the pattern will be removed from the list. -A leading \fB!\fP negates the pattern; in this case any completion -not matching the pattern will be removed. -.PP -Finally, any prefix and suffix specified with the \fB\-P\fP and \fB\-S\fP -options are added to each member of the completion list, and the result is -returned to the readline completion code as the list of possible -completions. -.PP -If the previously-applied actions do not generate any matches, and the -\fB\-o dirnames\fP option was supplied to \fBcomplete\fP when the -compspec was defined, directory name completion is attempted. -.PP -If the \fB\-o plusdirs\fP option was supplied to \fBcomplete\fP when the -compspec was defined, directory name completion is attempted and any -matches are added to the results of the other actions. -.PP -By default, if a compspec is found, whatever it generates is returned -to the completion code as the full set of possible completions. -The default \fBbash\fP completions are not attempted, and the readline -default of filename completion is disabled. -If the \fB\-o bashdefault\fP option was supplied to \fBcomplete\fP when -the compspec was defined, the \fBbash\fP default completions are attempted -if the compspec generates no matches. -If the \fB\-o default\fP option was supplied to \fBcomplete\fP when the -compspec was defined, readline's default completion will be performed -if the compspec (and, if attempted, the default \fBbash\fP completions) -generate no matches. -.PP -When a compspec indicates that directory name completion is desired, -the programmable completion functions force readline to append a slash -to completed names which are symbolic links to directories, subject to -the value of the \fBmark\-directories\fP readline variable, regardless -of the setting of the \fBmark-symlinked\-directories\fP readline variable. -.PP -There is some support for dynamically modifying completions. This is -most useful when used in combination with a default completion specified -with \fBcomplete -D\fP. -It's possible for shell functions executed as completion -handlers to indicate that completion should be retried by returning an -exit status of 124. If a shell function returns 124, and changes -the compspec associated with the command on which completion is being -attempted (supplied as the first argument when the function is executed), -programmable completion restarts from the beginning, with an -attempt to find a new compspec for that command. This allows a set of -completions to be built dynamically as completion is attempted, rather than -being loaded all at once. -.PP -For instance, assuming that there is a library of compspecs, each kept in a -file corresponding to the name of the command, the following default -completion function would load completions dynamically: -.PP -\f(CW_completion_loader() -.br -{ -.br - . "/etc/bash_completion.d/$1.sh" >/dev/null 2>&1 && return 124 -.br -} -.br -complete -D -F _completion_loader -.br -\fP -.SH HISTORY -When the -.B \-o history -option to the -.B set -builtin is enabled, the shell provides access to the -\fIcommand history\fP, -the list of commands previously typed. -The value of the -.SM -.B HISTSIZE -variable is used as the -number of commands to save in a history list. -The text of the last -.SM -.B HISTSIZE -commands (default 500) is saved. The shell -stores each command in the history list prior to parameter and -variable expansion (see -.SM -.B EXPANSION -above) but after history expansion is performed, subject to the -values of the shell variables -.SM -.B HISTIGNORE -and -.SM -.BR HISTCONTROL . -.PP -On startup, the history is initialized from the file named by -the variable -.SM -.B HISTFILE -(default \fI~/.bash_history\fP). -The file named by the value of -.SM -.B HISTFILE -is truncated, if necessary, to contain no more than -the number of lines specified by the value of -.SM -.BR HISTFILESIZE . -If \fBHISTFILESIZE\fP is unset, or set to null, a non-numeric value, -or a numeric value less than zero, the history file is not truncated. -When the history file is read, -lines beginning with the history comment character followed immediately -by a digit are interpreted as timestamps for the preceding history line. -These timestamps are optionally displayed depending on the value of the -.SM -.B HISTTIMEFORMAT -variable. -When a shell with history enabled exits, the last -.SM -.B $HISTSIZE -lines are copied from the history list to -.SM -.BR $HISTFILE . -If the -.B histappend -shell option is enabled -(see the description of -.B shopt -under -.SM -.B "SHELL BUILTIN COMMANDS" -below), the lines are appended to the history file, -otherwise the history file is overwritten. -If -.SM -.B HISTFILE -is unset, or if the history file is unwritable, the history is -not saved. -If the -.SM -.B HISTTIMEFORMAT -variable is set, time stamps are written to the history file, marked -with the history comment character, so -they may be preserved across shell sessions. -This uses the history comment character to distinguish timestamps from -other history lines. -After saving the history, the history file is truncated -to contain no more than -.SM -.B HISTFILESIZE -lines. If -.SM -.B HISTFILESIZE -is unset, or set to null, a non-numeric value, -or a numeric value less than zero, the history file is not truncated. -.PP -The builtin command -.B fc -(see -.SM -.B SHELL BUILTIN COMMANDS -below) may be used to list or edit and re-execute a portion of -the history list. -The -.B history -builtin may be used to display or modify the history list and -manipulate the history file. -When using command-line editing, search commands -are available in each editing mode that provide access to the -history list. -.PP -The shell allows control over which commands are saved on the history -list. The -.SM -.B HISTCONTROL -and -.SM -.B HISTIGNORE -variables may be set to cause the shell to save only a subset of the -commands entered. -The -.B cmdhist -shell option, if enabled, causes the shell to attempt to save each -line of a multi-line command in the same history entry, adding -semicolons where necessary to preserve syntactic correctness. -The -.B lithist -shell option causes the shell to save the command with embedded newlines -instead of semicolons. See the description of the -.B shopt -builtin below under -.SM -.B "SHELL BUILTIN COMMANDS" -for information on setting and unsetting shell options. -.SH "HISTORY EXPANSION" -.PP -The shell supports a history expansion feature that -is similar to the history expansion in -.BR csh. -This section describes what syntax features are available. This -feature is enabled by default for interactive shells, and can be -disabled using the -.B +H -option to the -.B set -builtin command (see -.SM -.B SHELL BUILTIN COMMANDS -below). Non-interactive shells do not perform history expansion -by default. -.PP -History expansions introduce words from the history list into -the input stream, making it easy to repeat commands, insert the -arguments to a previous command into the current input line, or -fix errors in previous commands quickly. -.PP -History expansion is performed immediately after a complete line -is read, before the shell breaks it into words. -It takes place in two parts. -The first is to determine which line from the history list -to use during substitution. -The second is to select portions of that line for inclusion into -the current one. -The line selected from the history is the \fIevent\fP, -and the portions of that line that are acted upon are \fIwords\fP. -Various \fImodifiers\fP are available to manipulate the selected words. -The line is broken into words in the same fashion as when reading input, -so that several \fImetacharacter\fP-separated words surrounded by -quotes are considered one word. -History expansions are introduced by the appearance of the -history expansion character, which is \^\fB!\fP\^ by default. -Only backslash (\^\fB\e\fP\^) and single quotes can quote -the history expansion character. -.PP -Several characters inhibit history expansion if found immediately -following the history expansion character, even if it is unquoted: -space, tab, newline, carriage return, and \fB=\fP. -If the \fBextglob\fP shell option is enabled, \fB(\fP will also -inhibit expansion. -.PP -Several shell options settable with the -.B shopt -builtin may be used to tailor the behavior of history expansion. -If the -.B histverify -shell option is enabled (see the description of the -.B shopt -builtin below), and -.B readline -is being used, history substitutions are not immediately passed to -the shell parser. -Instead, the expanded line is reloaded into the -.B readline -editing buffer for further modification. -If -.B readline -is being used, and the -.B histreedit -shell option is enabled, a failed history substitution will be reloaded -into the -.B readline -editing buffer for correction. -The -.B \-p -option to the -.B history -builtin command may be used to see what a history expansion will -do before using it. -The -.B \-s -option to the -.B history -builtin may be used to add commands to the end of the history list -without actually executing them, so that they are available for -subsequent recall. -.PP -The shell allows control of the various characters used by the -history expansion mechanism (see the description of -.B histchars -above under -.BR "Shell Variables" ). -The shell uses -the history comment character to mark history timestamps when -writing the history file. -.SS Event Designators -.PP -An event designator is a reference to a command line entry in the -history list. -Unless the reference is absolute, events are relative to the current -position in the history list. -.PP -.PD 0 -.TP -.B ! -Start a history substitution, except when followed by a -.BR blank , -newline, carriage return, = -or ( (when the \fBextglob\fP shell option is enabled using -the \fBshopt\fP builtin). -.TP -.B !\fIn\fR -Refer to command line -.IR n . -.TP -.B !\-\fIn\fR -Refer to the current command minus -.IR n . -.TP -.B !! -Refer to the previous command. This is a synonym for `!\-1'. -.TP -.B !\fIstring\fR -Refer to the most recent command preceding the current position in the -history list starting with -.IR string . -.TP -.B !?\fIstring\fR\fB[?]\fR -Refer to the most recent command preceding the current position in the -history list containing -.IR string . -The trailing \fB?\fP may be omitted if -.I string -is followed immediately by a newline. -.TP -.B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u -Quick substitution. Repeat the previous command, replacing -.I string1 -with -.IR string2 . -Equivalent to -``!!:s/\fIstring1\fP/\fIstring2\fP/'' -(see \fBModifiers\fP below). -.TP -.B !# -The entire command line typed so far. -.PD -.SS Word Designators -.PP -Word designators are used to select desired words from the event. -A -.B : -separates the event specification from the word designator. -It may be omitted if the word designator begins with a -.BR ^ , -.BR $ , -.BR * , -.BR \- , -or -.BR % . -Words are numbered from the beginning of the line, -with the first word being denoted by 0 (zero). -Words are inserted into the current line separated by single spaces. -.PP -.PD 0 -.TP -.B 0 (zero) -The zeroth word. For the shell, this is the command -word. -.TP -.I n -The \fIn\fRth word. -.TP -.B ^ -The first argument. That is, word 1. -.TP -.B $ -The last argument. -.TP -.B % -The word matched by the most recent `?\fIstring\fR?' search. -.TP -.I x\fB\-\fPy -A range of words; `\-\fIy\fR' abbreviates `0\-\fIy\fR'. -.TP -.B * -All of the words but the zeroth. This is a synonym -for `\fI1\-$\fP'. It is not an error to use -.B * -if there is just one -word in the event; the empty string is returned in that case. -.TP -.B x* -Abbreviates \fIx\-$\fP. -.TP -.B x\- -Abbreviates \fIx\-$\fP like \fBx*\fP, but omits the last word. -.PD -.PP -If a word designator is supplied without an event specification, the -previous command is used as the event. -.SS Modifiers -.PP -After the optional word designator, there may appear a sequence of -one or more of the following modifiers, each preceded by a `:'. -.PP -.PD 0 -.PP -.TP -.B h -Remove a trailing filename component, leaving only the head. -.TP -.B t -Remove all leading filename components, leaving the tail. -.TP -.B r -Remove a trailing suffix of the form \fI.xxx\fP, leaving the -basename. -.TP -.B e -Remove all but the trailing suffix. -.TP -.B p -Print the new command but do not execute it. -.TP -.B q -Quote the substituted words, escaping further substitutions. -.TP -.B x -Quote the substituted words as with -.BR q , -but break into words at -.B blanks -and newlines. -.TP -.B s/\fIold\fP/\fInew\fP/ -Substitute -.I new -for the first occurrence of -.I old -in the event line. Any delimiter can be used in place of /. The -final delimiter is optional if it is the last character of the -event line. The delimiter may be quoted in -.I old -and -.I new -with a single backslash. If & appears in -.IR new , -it is replaced by -.IR old . -A single backslash will quote the &. If -.I old -is null, it is set to the last -.I old -substituted, or, if no previous history substitutions took place, -the last -.I string -in a -.B !?\fIstring\fR\fB[?]\fR -search. -.TP -.B & -Repeat the previous substitution. -.TP -.B g -Cause changes to be applied over the entire event line. This is -used in conjunction with `\fB:s\fP' (e.g., `\fB:gs/\fIold\fP/\fInew\fP/\fR') -or `\fB:&\fP'. If used with -`\fB:s\fP', any delimiter can be used -in place of /, and the final delimiter is optional -if it is the last character of the event line. -An \fBa\fP may be used as a synonym for \fBg\fP. -.TP -.B G -Apply the following `\fBs\fP' modifier once to each word in the event line. -.PD -.SH "SHELL BUILTIN COMMANDS" -.\" start of bash_builtins -.zZ -.PP -Unless otherwise noted, each builtin command documented in this -section as accepting options preceded by -.B \- -accepts -.B \-\- -to signify the end of the options. -The \fB:\fP, \fBtrue\fP, \fBfalse\fP, and \fBtest\fP builtins -do not accept options and do not treat \fB\-\-\fP specially. -The \fBexit\fP, \fBlogout\fP, \fBbreak\fP, \fBcontinue\fP, \fBlet\fP, -and \fBshift\fP builtins accept and process arguments beginning with -\fB\-\fP without requiring \fB\-\-\fP. -Other builtins that accept arguments but are not specified as accepting -options interpret arguments beginning with \fB\-\fP as invalid options and -require \fB\-\-\fP to prevent this interpretation. -.sp .5 -.PD 0 -.TP -\fB:\fP [\fIarguments\fP] -.PD -No effect; the command does nothing beyond expanding -.I arguments -and performing any specified -redirections. A zero exit code is returned. -.TP -\fB .\| \fP \fIfilename\fP [\fIarguments\fP] -.PD 0 -.TP -\fBsource\fP \fIfilename\fP [\fIarguments\fP] -.PD -Read and execute commands from -.I filename -in the current -shell environment and return the exit status of the last command -executed from -.IR filename . -If -.I filename -does not contain a slash, filenames in -.SM -.B PATH -are used to find the directory containing -.IR filename . -The file searched for in -.SM -.B PATH -need not be executable. -When \fBbash\fP is not in \fIposix mode\fP, the current directory is -searched if no file is found in -.SM -.BR PATH . -If the -.B sourcepath -option to the -.B shopt -builtin command is turned off, the -.SM -.B PATH -is not searched. -If any \fIarguments\fP are supplied, they become the positional -parameters when \fIfilename\fP is executed. Otherwise the positional -parameters are unchanged. -The return status is the status of the last command exited within -the script (0 if no commands are executed), and false if -.I filename -is not found or cannot be read. -.TP -\fBalias\fP [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -\fBAlias\fP with no arguments or with the -.B \-p -option prints the list of aliases in the form -\fBalias\fP \fIname\fP=\fIvalue\fP on standard output. -When arguments are supplied, an alias is defined for -each \fIname\fP whose \fIvalue\fP is given. -A trailing space in \fIvalue\fP causes the next word to be -checked for alias substitution when the alias is expanded. -For each \fIname\fP in the argument list for which no \fIvalue\fP -is supplied, the name and value of the alias is printed. -\fBAlias\fP returns true unless a \fIname\fP is given for which -no alias has been defined. -.TP -\fBbg\fP [\fIjobspec\fP ...] -Resume each suspended job \fIjobspec\fP in the background, as if it -had been started with -.BR & . -If -.I jobspec -is not present, the shell's notion of the \fIcurrent job\fP is used. -.B bg -.I jobspec -returns 0 unless run when job control is disabled or, when run with -job control enabled, any specified \fIjobspec\fP was not found -or was started without job control. -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSVX\fP] -.PD 0 -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-q\fP \fIfunction\fP] [\fB\-u\fP \fIfunction\fP] [\fB\-r\fP \fIkeyseq\fP] -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-f\fP \fIfilename\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fB\-x\fP \fIkeyseq\fP:\fIshell\-command\fP -.TP -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\fP:\fIfunction\-name\fP -.TP -\fBbind\fP \fIreadline\-command\fP -.PD -Display current -.B readline -key and function bindings, bind a key sequence to a -.B readline -function or macro, or set a -.B readline -variable. -Each non-option argument is a command as it would appear in -.IR .inputrc , -but each binding or command must be passed as a separate argument; -e.g., '"\eC\-x\eC\-r": re\-read\-init\-file'. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-m \fIkeymap\fP -Use -.I keymap -as the keymap to be affected by the subsequent bindings. -Acceptable -.I keymap -names are -\fIemacs, emacs\-standard, emacs\-meta, emacs\-ctlx, vi, -vi\-move, vi\-command\fP, and -.IR vi\-insert . -\fIvi\fP is equivalent to \fIvi\-command\fP; \fIemacs\fP is -equivalent to \fIemacs\-standard\fP. -.TP -.B \-l -List the names of all \fBreadline\fP functions. -.TP -.B \-p -Display \fBreadline\fP function names and bindings in such a way -that they can be re-read. -.TP -.B \-P -List current \fBreadline\fP function names and bindings. -.TP -.B \-s -Display \fBreadline\fP key sequences bound to macros and the strings -they output in such a way that they can be re-read. -.TP -.B \-S -Display \fBreadline\fP key sequences bound to macros and the strings -they output. -.TP -.B \-v -Display \fBreadline\fP variable names and values in such a way that they -can be re-read. -.TP -.B \-V -List current \fBreadline\fP variable names and values. -.TP -.B \-f \fIfilename\fP -Read key bindings from \fIfilename\fP. -.TP -.B \-q \fIfunction\fP -Query about which keys invoke the named \fIfunction\fP. -.TP -.B \-u \fIfunction\fP -Unbind all keys bound to the named \fIfunction\fP. -.TP -.B \-r \fIkeyseq\fP -Remove any current binding for \fIkeyseq\fP. -.TP -.B \-x \fIkeyseq\fP:\fIshell\-command\fP -Cause \fIshell\-command\fP to be executed whenever \fIkeyseq\fP is -entered. -When \fIshell\-command\fP is executed, the shell sets the -.SM -.B READLINE_LINE -variable to the contents of the \fBreadline\fP line buffer and the -.SM -.B READLINE_POINT -variable to the current location of the insertion point. -If the executed command changes the value of -.SM -.B READLINE_LINE -or -.SM -.BR READLINE_POINT , -those new values will be reflected in the editing state. -.TP -.B \-X -List all key sequences bound to shell commands and the associated commands -in a format that can be reused as input. -.PD -.PP -The return value is 0 unless an unrecognized option is given or an -error occurred. -.RE -.TP -\fBbreak\fP [\fIn\fP] -Exit from within a -.BR for , -.BR while , -.BR until , -or -.B select -loop. If \fIn\fP is specified, break \fIn\fP levels. -.I n -must be \(>= 1. If -.I n -is greater than the number of enclosing loops, all enclosing loops -are exited. -The return value is 0 unless \fIn\fP is not greater than or equal to 1. -.TP -\fBbuiltin\fP \fIshell\-builtin\fP [\fIarguments\fP] -Execute the specified shell builtin, passing it -.IR arguments , -and return its exit status. -This is useful when defining a -function whose name is the same as a shell builtin, -retaining the functionality of the builtin within the function. -The \fBcd\fP builtin is commonly redefined this way. -The return status is false if -.I shell\-builtin -is not a shell builtin command. -.TP -\fBcaller\fP [\fIexpr\fP] -Returns the context of any active subroutine call (a shell function or -a script executed with the \fB.\fP or \fBsource\fP builtins). -Without \fIexpr\fP, \fBcaller\fP displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as \fIexpr\fP, \fBcaller\fP -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. -The return value is 0 unless the shell is not executing a subroutine -call or \fIexpr\fP does not correspond to a valid position in the -call stack. -.TP -\fBcd\fP [\fB\-L\fP|[\fB\-P\fP [\fB\-e\fP]]] [\fIdir\fP] -Change the current directory to \fIdir\fP. -if \fIdir\fP is not supplied, the value of the -.SM -.B HOME -shell variable is the default. -Any additional arguments following \fIdir\fP are ignored. -The variable -.SM -.B CDPATH -defines the search path for the directory containing -.IR dir : -each directory name in -.SM -.B CDPATH -is searched for \fIdir\fP. -Alternative directory names in -.SM -.B CDPATH -are separated by a colon (:). A null directory name in -.SM -.B CDPATH -is the same as the current directory, i.e., ``\fB.\fP''. If -.I dir -begins with a slash (/), -then -.SM -.B CDPATH -is not used. The -.B \-P -option causes \fBcd\fP to use the physical directory structure -by resolving symbolic links while traversing \fIdir\fP and -before processing instances of \fI..\fP in \fIdir\fP (see also the -.B \-P -option to the -.B set -builtin command); the -.B \-L -option forces symbolic links to be followed by resolving the link -after processing instances of \fI..\fP in \fIdir\fP. -If \fI..\fP appears in \fIdir\fP, it is processed by removing the -immediately previous pathname component from \fIdir\fP, back to a slash -or the beginning of \fIdir\fP. -If the -.B \-e -option is supplied with -.BR \-P , -and the current working directory cannot be successfully determined -after a successful directory change, \fBcd\fP will return an unsuccessful -status. -An argument of -.B \- -is converted to -.SM -.B $OLDPWD -before the directory change is attempted. -If a non-empty directory name from -.SM -.B CDPATH -is used, or if -\fB\-\fP is the first argument, and the directory change is -successful, the absolute pathname of the new working directory is -written to the standard output. -The return value is true if the directory was successfully changed; -false otherwise. -.TP -\fBcommand\fP [\fB\-pVv\fP] \fIcommand\fP [\fIarg\fP ...] -Run -.I command -with -.I args -suppressing the normal shell function lookup. Only builtin -commands or commands found in the -.SM -.B PATH -are executed. If the -.B \-p -option is given, the search for -.I command -is performed using a default value for -.SM -.B PATH -that is guaranteed to find all of the standard utilities. -If either the -.B \-V -or -.B \-v -option is supplied, a description of -.I command -is printed. The -.B \-v -option causes a single word indicating the command or filename -used to invoke -.I command -to be displayed; the -.B \-V -option produces a more verbose description. -If the -.B \-V -or -.B \-v -option is supplied, the exit status is 0 if -.I command -was found, and 1 if not. If neither option is supplied and -an error occurred or -.I command -cannot be found, the exit status is 127. Otherwise, the exit status of the -.B command -builtin is the exit status of -.IR command . -.TP -\fBcompgen\fP [\fIoption\fP] [\fIword\fP] -Generate possible completion matches for \fIword\fP according to -the \fIoption\fPs, which may be any option accepted by the -.B complete -builtin with the exception of \fB\-p\fP and \fB\-r\fP, and write -the matches to the standard output. -When using the \fB\-F\fP or \fB\-C\fP options, the various shell variables -set by the programmable completion facilities, while available, will not -have useful values. -.sp 1 -The matches will be generated in the same way as if the programmable -completion code had generated them directly from a completion specification -with the same flags. -If \fIword\fP is specified, only those completions matching \fIword\fP -will be displayed. -.sp 1 -The return value is true unless an invalid option is supplied, or no -matches were generated. -.TP -\fBcomplete\fP [\fB\-abcdefgjksuv\fP] [\fB\-o\fP \fIcomp-option\fP] [\fB\-DE\fP] [\fB\-A\fP \fIaction\fP] [\fB\-G\fP \fIglobpat\fP] [\fB\-W\fP \fIwordlist\fP] [\fB\-F\fP \fIfunction\fP] [\fB\-C\fP \fIcommand\fP] -.br -[\fB\-X\fP \fIfilterpat\fP] [\fB\-P\fP \fIprefix\fP] [\fB\-S\fP \fIsuffix\fP] \fIname\fP [\fIname ...\fP] -.PD 0 -.TP -\fBcomplete\fP \fB\-pr\fP [\fB\-DE\fP] [\fIname\fP ...] -.PD -Specify how arguments to each \fIname\fP should be completed. -If the \fB\-p\fP option is supplied, or if no options are supplied, -existing completion specifications are printed in a way that allows -them to be reused as input. -The \fB\-r\fP option removes a completion specification for -each \fIname\fP, or, if no \fIname\fPs are supplied, all -completion specifications. -The \fB\-D\fP option indicates that the remaining options and actions should -apply to the ``default'' command completion; that is, completion attempted -on a command for which no completion has previously been defined. -The \fB\-E\fP option indicates that the remaining options and actions should -apply to ``empty'' command completion; that is, completion attempted on a -blank line. -.sp 1 -The process of applying these completion specifications when word completion -is attempted is described above under \fBProgrammable Completion\fP. -.sp 1 -Other options, if specified, have the following meanings. -The arguments to the \fB\-G\fP, \fB\-W\fP, and \fB\-X\fP options -(and, if necessary, the \fB\-P\fP and \fB\-S\fP options) -should be quoted to protect them from expansion before the -.B complete -builtin is invoked. -.RS -.PD 0 -.TP 8 -\fB\-o\fP \fIcomp-option\fP -The \fIcomp-option\fP controls several aspects of the compspec's behavior -beyond the simple generation of completions. -\fIcomp-option\fP may be one of: -.RS -.TP 8 -.B bashdefault -Perform the rest of the default \fBbash\fP completions if the compspec -generates no matches. -.TP 8 -.B default -Use readline's default filename completion if the compspec generates -no matches. -.TP 8 -.B dirnames -Perform directory name completion if the compspec generates no matches. -.TP 8 -.B filenames -Tell readline that the compspec generates filenames, so it can perform any -filename\-specific processing (like adding a slash to directory names, -quoting special characters, or suppressing trailing spaces). -Intended to be used with shell functions. -.TP 8 -.B noquote -Tell readline not to quote the completed words if they are filenames -(quoting filenames is the default). -.TP 8 -.B nospace -Tell readline not to append a space (the default) to words completed at -the end of the line. -.TP 8 -.B plusdirs -After any matches defined by the compspec are generated, -directory name completion is attempted and any -matches are added to the results of the other actions. -.RE -.TP 8 -\fB\-A\fP \fIaction\fP -The \fIaction\fP may be one of the following to generate a list of possible -completions: -.RS -.TP 8 -.B alias -Alias names. May also be specified as \fB\-a\fP. -.TP 8 -.B arrayvar -Array variable names. -.TP 8 -.B binding -\fBReadline\fP key binding names. -.TP 8 -.B builtin -Names of shell builtin commands. May also be specified as \fB\-b\fP. -.TP 8 -.B command -Command names. May also be specified as \fB\-c\fP. -.TP 8 -.B directory -Directory names. May also be specified as \fB\-d\fP. -.TP 8 -.B disabled -Names of disabled shell builtins. -.TP 8 -.B enabled -Names of enabled shell builtins. -.TP 8 -.B export -Names of exported shell variables. May also be specified as \fB\-e\fP. -.TP 8 -.B file -File names. May also be specified as \fB\-f\fP. -.TP 8 -.B function -Names of shell functions. -.TP 8 -.B group -Group names. May also be specified as \fB\-g\fP. -.TP 8 -.B helptopic -Help topics as accepted by the \fBhelp\fP builtin. -.TP 8 -.B hostname -Hostnames, as taken from the file specified by the -.SM -.B HOSTFILE -shell variable. -.TP 8 -.B job -Job names, if job control is active. May also be specified as \fB\-j\fP. -.TP 8 -.B keyword -Shell reserved words. May also be specified as \fB\-k\fP. -.TP 8 -.B running -Names of running jobs, if job control is active. -.TP 8 -.B service -Service names. May also be specified as \fB\-s\fP. -.TP 8 -.B setopt -Valid arguments for the \fB\-o\fP option to the \fBset\fP builtin. -.TP 8 -.B shopt -Shell option names as accepted by the \fBshopt\fP builtin. -.TP 8 -.B signal -Signal names. -.TP 8 -.B stopped -Names of stopped jobs, if job control is active. -.TP 8 -.B user -User names. May also be specified as \fB\-u\fP. -.TP 8 -.B variable -Names of all shell variables. May also be specified as \fB\-v\fP. -.RE -.TP 8 -\fB\-C\fP \fIcommand\fP -\fIcommand\fP is executed in a subshell environment, and its output is -used as the possible completions. -.TP 8 -\fB\-F\fP \fIfunction\fP -The shell function \fIfunction\fP is executed in the current shell -environment. -When the function is executed, -the first argument (\fB$1\fP) is the name of the command whose arguments are -being completed, -the second argument (\fB$2\fP) is the word being completed, -and the third argument (\fB$3\fP) is the word preceding the word being -completed on the current command line. -When it finishes, the possible completions are retrieved from the value -of the -.SM -.B COMPREPLY -array variable. -.TP 8 -\fB\-G\fP \fIglobpat\fP -The pathname expansion pattern \fIglobpat\fP is expanded to generate -the possible completions. -.TP 8 -\fB\-P\fP \fIprefix\fP -\fIprefix\fP is added at the beginning of each possible completion -after all other options have been applied. -.TP 8 -\fB\-S\fP \fIsuffix\fP -\fIsuffix\fP is appended to each possible completion -after all other options have been applied. -.TP 8 -\fB\-W\fP \fIwordlist\fP -The \fIwordlist\fP is split using the characters in the -.SM -.B IFS -special variable as delimiters, and each resultant word is expanded. -The possible completions are the members of the resultant list which -match the word being completed. -.TP 8 -\fB\-X\fP \fIfilterpat\fP -\fIfilterpat\fP is a pattern as used for pathname expansion. -It is applied to the list of possible completions generated by the -preceding options and arguments, and each completion matching -\fIfilterpat\fP is removed from the list. -A leading \fB!\fP in \fIfilterpat\fP negates the pattern; in this -case, any completion not matching \fIfilterpat\fP is removed. -.PD -.PP -The return value is true unless an invalid option is supplied, an option -other than \fB\-p\fP or \fB\-r\fP is supplied without a \fIname\fP -argument, an attempt is made to remove a completion specification for -a \fIname\fP for which no specification exists, or -an error occurs adding a completion specification. -.RE -.TP -\fBcompopt\fP [\fB\-o\fP \fIoption\fP] [\fB\-DE\fP] [\fB+o\fP \fIoption\fP] [\fIname\fP] -Modify completion options for each \fIname\fP according to the -\fIoption\fPs, or for the -currently-executing completion if no \fIname\fPs are supplied. -If no \fIoption\fPs are given, display the completion options for each -\fIname\fP or the current completion. -The possible values of \fIoption\fP are those valid for the \fBcomplete\fP -builtin described above. -The \fB\-D\fP option indicates that the remaining options should -apply to the ``default'' command completion; that is, completion attempted -on a command for which no completion has previously been defined. -The \fB\-E\fP option indicates that the remaining options should -apply to ``empty'' command completion; that is, completion attempted on a -blank line. -.sp 1 -The return value is true unless an invalid option is supplied, an attempt -is made to modify the options for a \fIname\fP for which no completion -specification exists, or an output error occurs. -.TP -\fBcontinue\fP [\fIn\fP] -Resume the next iteration of the enclosing -.BR for , -.BR while , -.BR until , -or -.B select -loop. -If -.I n -is specified, resume at the \fIn\fPth enclosing loop. -.I n -must be \(>= 1. If -.I n -is greater than the number of enclosing loops, the last enclosing loop -(the ``top-level'' loop) is resumed. -The return value is 0 unless \fIn\fP is not greater than or equal to 1. -.TP -\fBdeclare\fP [\fB\-aAfFgilnrtux\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD 0 -.TP -\fBtypeset\fP [\fB\-aAfFgilnrtux\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD -Declare variables and/or give them attributes. -If no \fIname\fPs are given then display the values of variables. -The -.B \-p -option will display the attributes and values of each -.IR name . -When -.B \-p -is used with \fIname\fP arguments, additional options are ignored. -When -.B \-p -is supplied without \fIname\fP arguments, it will display the attributes -and values of all variables having the attributes specified by the -additional options. -If no other options are supplied with \fB\-p\fP, \fBdeclare\fP will display -the attributes and values of all shell variables. The \fB\-f\fP option -will restrict the display to shell functions. -The -.B \-F -option inhibits the display of function definitions; only the -function name and attributes are printed. -If the \fBextdebug\fP shell option is enabled using \fBshopt\fP, -the source file name and line number where the function is defined -are displayed as well. The -.B \-F -option implies -.BR \-f . -The -.B \-g -option forces variables to be created or modified at the global scope, -even when \fBdeclare\fP is executed in a shell function. -It is ignored in all other cases. -The following options can -be used to restrict output to variables with the specified attribute or -to give variables attributes: -.RS -.PD 0 -.TP -.B \-a -Each \fIname\fP is an indexed array variable (see -.B Arrays -above). -.TP -.B \-A -Each \fIname\fP is an associative array variable (see -.B Arrays -above). -.TP -.B \-f -Use function names only. -.TP -.B \-i -The variable is treated as an integer; arithmetic evaluation (see -.SM -.B "ARITHMETIC EVALUATION" -above) is performed when the variable is assigned a value. -.TP -.B \-l -When the variable is assigned a value, all upper-case characters are -converted to lower-case. -The upper-case attribute is disabled. -.TP -.B \-n -Give each \fIname\fP the \fInameref\fP attribute, making -it a name reference to another variable. -That other variable is defined by the value of \fIname\fP. -All references and assignments to \fIname\fP, except for changing the -\fB\-n\fP attribute itself, are performed on the variable referenced by -\fIname\fP's value. -The \fB\-n\fP attribute cannot be applied to array variables. -.TP -.B \-r -Make \fIname\fPs readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. -.TP -.B \-t -Give each \fIname\fP the \fItrace\fP attribute. -Traced functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps from -the calling shell. -The trace attribute has no special meaning for variables. -.TP -.B \-u -When the variable is assigned a value, all lower-case characters are -converted to upper-case. -The lower-case attribute is disabled. -.TP -.B \-x -Mark \fIname\fPs for export to subsequent commands via the environment. -.PD -.PP -Using `+' instead of `\-' -turns off the attribute instead, -with the exceptions that \fB+a\fP -may not be used to destroy an array variable and \fB+r\fP will not -remove the readonly attribute. -When used in a function, -.B declare -and -.B typeset -make each -\fIname\fP local, as with the -.B local -command, -unless the \fB\-g\fP option is supplied. -If a variable name is followed by =\fIvalue\fP, the value of -the variable is set to \fIvalue\fP. -The return value is 0 unless an invalid option is encountered, -an attempt is made to define a function using -.if n ``\-f foo=bar'', -.if t \f(CW\-f foo=bar\fP, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (see -.B Arrays -above), one of the \fInames\fP is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with \fB\-f\fP. -.RE -.TP -.B dirs [\fB\-clpv\fP] [+\fIn\fP] [\-\fIn\fP] -Without options, displays the list of currently remembered directories. -The default display is on a single line with directory names separated -by spaces. -Directories are added to the list with the -.B pushd -command; the -.B popd -command removes entries from the list. -.RS -.PD 0 -.TP -.B \-c -Clears the directory stack by deleting all of the entries. -.TP -.B \-l -Produces a listing using full pathnames; -the default listing format uses a tilde to denote the home directory. -.TP -.B \-p -Print the directory stack with one entry per line. -.TP -.B \-v -Print the directory stack with one entry per line, -prefixing each entry with its index in the stack. -.TP -\fB+\fP\fIn\fP -Displays the \fIn\fPth entry counting from the left of the list -shown by -.B dirs -when invoked without options, starting with zero. -.TP -\fB\-\fP\fIn\fP -Displays the \fIn\fPth entry counting from the right of the list -shown by -.B dirs -when invoked without options, starting with zero. -.PD -.PP -The return value is 0 unless an -invalid option is supplied or \fIn\fP indexes beyond the end -of the directory stack. -.RE -.TP -\fBdisown\fP [\fB\-ar\fP] [\fB\-h\fP] [\fIjobspec\fP ...] -Without options, remove each -.I jobspec -from the table of active jobs. -If -.I jobspec -is not present, and neither \fB\-a\fP nor \fB\-r\fP is supplied, -the shell's notion of the \fIcurrent job\fP is used. -If the \fB\-h\fP option is given, each -.I jobspec -is not removed from the table, but is marked so that -.SM -.B SIGHUP -is not sent to the job if the shell receives a -.SM -.BR SIGHUP . -If no -.I jobspec -is present, and neither the -.B \-a -nor the -.B \-r -option is supplied, the \fIcurrent job\fP is used. -If no -.I jobspec -is supplied, the -.B \-a -option means to remove or mark all jobs; the -.B \-r -option without a -.I jobspec -argument restricts operation to running jobs. -The return value is 0 unless a -.I jobspec -does not specify a valid job. -.TP -\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...] -Output the \fIarg\fPs, separated by spaces, followed by a newline. -The return status is 0 unless a write error occurs. -If \fB\-n\fP is specified, the trailing newline is -suppressed. If the \fB\-e\fP option is given, interpretation of -the following backslash-escaped characters is enabled. The -.B \-E -option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The \fBxpg_echo\fP shell option may be used to -dynamically determine whether or not \fBecho\fP expands these -escape characters by default. -.B echo -does not interpret \fB\-\-\fP to mean the end of options. -.B echo -interprets the following escape sequences: -.RS -.PD 0 -.TP -.B \ea -alert (bell) -.TP -.B \eb -backspace -.TP -.B \ec -suppress further output -.TP -.B \ee -.TP -.B \eE -an escape character -.TP -.B \ef -form feed -.TP -.B \en -new line -.TP -.B \er -carriage return -.TP -.B \et -horizontal tab -.TP -.B \ev -vertical tab -.TP -.B \e\e -backslash -.TP -.B \e0\fInnn\fP -the eight-bit character whose value is the octal value \fInnn\fP -(zero to three octal digits) -.TP -.B \ex\fIHH\fP -the eight-bit character whose value is the hexadecimal value \fIHH\fP -(one or two hex digits) -.TP -.B \eu\fIHHHH\fP -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -\fIHHHH\fP (one to four hex digits) -.TP -.B \eU\fIHHHHHHHH\fP -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -\fIHHHHHHHH\fP (one to eight hex digits) -.PD -.RE -.TP -\fBenable\fP [\fB\-a\fP] [\fB\-dnps\fP] [\fB\-f\fP \fIfilename\fP] [\fIname\fP ...] -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -If \fB\-n\fP is used, each \fIname\fP -is disabled; otherwise, -\fInames\fP are enabled. For example, to use the -.B test -binary found via the -.SM -.B PATH -instead of the shell builtin version, run -.if t \f(CWenable -n test\fP. -.if n ``enable -n test''. -The -.B \-f -option means to load the new builtin command -.I name -from shared object -.IR filename , -on systems that support dynamic loading. The -.B \-d -option will delete a builtin previously loaded with -.BR \-f . -If no \fIname\fP arguments are given, or if the -.B \-p -option is supplied, a list of shell builtins is printed. -With no other option arguments, the list consists of all enabled -shell builtins. -If \fB\-n\fP is supplied, only disabled builtins are printed. -If \fB\-a\fP is supplied, the list printed includes all builtins, with an -indication of whether or not each is enabled. -If \fB\-s\fP is supplied, the output is restricted to the POSIX -\fIspecial\fP builtins. -The return value is 0 unless a -.I name -is not a shell builtin or there is an error loading a new builtin -from a shared object. -.TP -\fBeval\fP [\fIarg\fP ...] -The \fIarg\fPs are read and concatenated together into a single -command. This command is then read and executed by the shell, and -its exit status is returned as the value of -.BR eval . -If there are no -.IR args , -or only null arguments, -.B eval -returns 0. -.TP -\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP [\fIarguments\fP]] -If -.I command -is specified, it replaces the shell. -No new process is created. The -.I arguments -become the arguments to \fIcommand\fP. -If the -.B \-l -option is supplied, -the shell places a dash at the beginning of the zeroth argument passed to -.IR command . -This is what -.IR login (1) -does. The -.B \-c -option causes -.I command -to be executed with an empty environment. If -.B \-a -is supplied, the shell passes -.I name -as the zeroth argument to the executed command. -If -.I command -cannot be executed for some reason, a non-interactive shell exits, -unless the -.B execfail -shell option -is enabled. In that case, it returns failure. -An interactive shell returns failure if the file cannot be executed. -If -.I command -is not specified, any redirections take effect in the current shell, -and the return status is 0. If there is a redirection error, the -return status is 1. -.TP -\fBexit\fP [\fIn\fP] -Cause the shell to exit -with a status of \fIn\fP. If -.I n -is omitted, the exit status -is that of the last command executed. -A trap on -.SM -.B EXIT -is executed before the shell terminates. -.TP -\fBexport\fP [\fB\-fn\fP\^] [\fIname\fP[=\fIword\fP]] ... -.PD 0 -.TP -.B export \-p -.PD -The supplied -.I names -are marked for automatic export to the environment of -subsequently executed commands. If the -.B \-f -option is given, -the -.I names -refer to functions. -If no -.I names -are given, or if the -.B \-p -option is supplied, a list -of names of all exported variables is printed. -The -.B \-n -option causes the export property to be removed from each -\fIname\fP. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -.B export -returns an exit status of 0 unless an invalid option is -encountered, -one of the \fInames\fP is not a valid shell variable name, or -.B \-f -is supplied with a -.I name -that is not a function. -.TP -\fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-lnr\fP] [\fIfirst\fP] [\fIlast\fP] -.PD 0 -.TP -\fBfc\fP \fB\-s\fP [\fIpat\fP=\fIrep\fP] [\fIcmd\fP] -.PD -The first form selects a range of commands from -.I first -to -.I last -from the history list and displays or edits and re-executes them. -.I First -and -.I last -may be specified as a string (to locate the last command beginning -with that string) or as a number (an index into the history list, -where a negative number is used as an offset from the current -command number). If -.I last -is not specified it is set to -the current command for listing (so that -.if n ``fc \-l \-10'' -.if t \f(CWfc \-l \-10\fP -prints the last 10 commands) and to -.I first -otherwise. -If -.I first -is not specified it is set to the previous -command for editing and \-16 for listing. -.sp 1 -The -.B \-n -option suppresses -the command numbers when listing. The -.B \-r -option reverses the order of -the commands. If the -.B \-l -option is given, -the commands are listed on -standard output. Otherwise, the editor given by -.I ename -is invoked -on a file containing those commands. If -.I ename -is not given, the -value of the -.SM -.B FCEDIT -variable is used, and -the value of -.SM -.B EDITOR -if -.SM -.B FCEDIT -is not set. If neither variable is set, -.FN vi -is used. When editing is complete, the edited commands are -echoed and executed. -.sp 1 -In the second form, \fIcommand\fP is re-executed after each instance -of \fIpat\fP is replaced by \fIrep\fP. -\fICommand\fP is intepreted the same as \fIfirst\fP above. -A useful alias to use with this is -.if n ``r="fc -s"'', -.if t \f(CWr='fc \-s'\fP, -so that typing -.if n ``r cc'' -.if t \f(CWr cc\fP -runs the last command beginning with -.if n ``cc'' -.if t \f(CWcc\fP -and typing -.if n ``r'' -.if t \f(CWr\fP -re-executes the last command. -.sp 1 -If the first form is used, the return value is 0 unless an invalid -option is encountered or -.I first -or -.I last -specify history lines out of range. -If the -.B \-e -option is supplied, the return value is the value of the last -command executed or failure if an error occurs with the temporary -file of commands. If the second form is used, the return status -is that of the command re-executed, unless -.I cmd -does not specify a valid history line, in which case -.B fc -returns failure. -.TP -\fBfg\fP [\fIjobspec\fP] -Resume -.I jobspec -in the foreground, and make it the current job. -If -.I jobspec -is not present, the shell's notion of the \fIcurrent job\fP is used. -The return value is that of the command placed into the foreground, -or failure if run when job control is disabled or, when run with -job control enabled, if -.I jobspec -does not specify a valid job or -.I jobspec -specifies a job that was started without job control. -.TP -\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIargs\fP] -.B getopts -is used by shell procedures to parse positional parameters. -.I optstring -contains the option characters to be recognized; if a character -is followed by a colon, the option is expected to have an -argument, which should be separated from it by white space. -The colon and question mark characters may not be used as -option characters. -Each time it is invoked, -.B getopts -places the next option in the shell variable -.IR name , -initializing -.I name -if it does not exist, -and the index of the next argument to be processed into the -variable -.SM -.BR OPTIND . -.SM -.B OPTIND -is initialized to 1 each time the shell or a shell script -is invoked. When an option requires an argument, -.B getopts -places that argument into the variable -.SM -.BR OPTARG . -The shell does not reset -.SM -.B OPTIND -automatically; it must be manually reset between multiple -calls to -.B getopts -within the same shell invocation if a new set of parameters -is to be used. -.sp 1 -When the end of options is encountered, \fBgetopts\fP exits with a -return value greater than zero. -.SM -.B OPTIND -is set to the index of the first non-option argument, -and \fIname\fP is set to ?. -.sp 1 -.B getopts -normally parses the positional parameters, but if more arguments are -given in -.IR args , -.B getopts -parses those instead. -.sp 1 -.B getopts -can report errors in two ways. If the first character of -.I optstring -is a colon, -.I silent -error reporting is used. In normal operation, diagnostic messages -are printed when invalid options or missing option arguments are -encountered. -If the variable -.SM -.B OPTERR -is set to 0, no error messages will be displayed, even if the first -character of -.I optstring -is not a colon. -.sp 1 -If an invalid option is seen, -.B getopts -places ? into -.I name -and, if not silent, -prints an error message and unsets -.SM -.BR OPTARG . -If -.B getopts -is silent, -the option character found is placed in -.SM -.B OPTARG -and no diagnostic message is printed. -.sp 1 -If a required argument is not found, and -.B getopts -is not silent, -a question mark (\^\fB?\fP\^) is placed in -.IR name , -.SM -.B OPTARG -is unset, and a diagnostic message is printed. -If -.B getopts -is silent, then a colon (\^\fB:\fP\^) is placed in -.I name -and -.SM -.B OPTARG -is set to the option character found. -.sp 1 -.B getopts -returns true if an option, specified or unspecified, is found. -It returns false if the end of options is encountered or an -error occurs. -.TP -\fBhash\fP [\fB\-lr\fP] [\fB\-p\fP \fIfilename\fP] [\fB\-dt\fP] [\fIname\fP] -Each time \fBhash\fP is invoked, -the full pathname of the command -.I name -is determined by searching -the directories in -.B $PATH -and remembered. Any previously-remembered pathname is discarded. -If the -.B \-p -option is supplied, no path search is performed, and -.I filename -is used as the full filename of the command. -The -.B \-r -option causes the shell to forget all -remembered locations. -The -.B \-d -option causes the shell to forget the remembered location of each \fIname\fP. -If the -.B \-t -option is supplied, the full pathname to which each \fIname\fP corresponds -is printed. If multiple \fIname\fP arguments are supplied with \fB\-t\fP, -the \fIname\fP is printed before the hashed full pathname. -The -.B \-l -option causes output to be displayed in a format that may be reused as input. -If no arguments are given, or if only \fB\-l\fP is supplied, -information about remembered commands is printed. -The return status is true unless a -.I name -is not found or an invalid option is supplied. -.TP -\fBhelp\fP [\fB\-dms\fP] [\fIpattern\fP] -Display helpful information about builtin commands. If -.I pattern -is specified, -.B help -gives detailed help on all commands matching -.IR pattern ; -otherwise help for all the builtins and shell control structures -is printed. -.RS -.PD 0 -.TP -.B \-d -Display a short description of each \fIpattern\fP -.TP -.B \-m -Display the description of each \fIpattern\fP in a manpage-like format -.TP -.B \-s -Display only a short usage synopsis for each \fIpattern\fP -.PD -.PP -The return status is 0 unless no command matches -.IR pattern . -.RE -.TP -\fBhistory [\fIn\fP] -.PD 0 -.TP -\fBhistory\fP \fB\-c\fP -.TP -\fBhistory \-d\fP \fIoffset\fP -.TP -\fBhistory\fP \fB\-anrw\fP [\fIfilename\fP] -.TP -\fBhistory\fP \fB\-p\fP \fIarg\fP [\fIarg ...\fP] -.TP -\fBhistory\fP \fB\-s\fP \fIarg\fP [\fIarg ...\fP] -.PD -With no options, display the command -history list with line numbers. Lines listed -with a -.B * -have been modified. An argument of -.I n -lists only the last -.I n -lines. -If the shell variable -.SM -.B HISTTIMEFORMAT -is set and not null, -it is used as a format string for \fIstrftime\fP(3) to display -the time stamp associated with each displayed history entry. -No intervening blank is printed between the formatted time stamp -and the history line. -If \fIfilename\fP is supplied, it is used as the -name of the history file; if not, the value of -.SM -.B HISTFILE -is used. Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-c -Clear the history list by deleting all the entries. -.TP -\fB\-d\fP \fIoffset\fP -Delete the history entry at position \fIoffset\fP. -.TP -.B \-a -Append the ``new'' history lines (history lines entered since the -beginning of the current \fBbash\fP session) to the history file. -.TP -.B \-n -Read the history lines not already read from the history -file into the current history list. These are lines -appended to the history file since the beginning of the -current \fBbash\fP session. -.TP -.B \-r -Read the contents of the history file -and append them to the current history list. -.TP -.B \-w -Write the current history list to the history file, overwriting the -history file's contents. -.TP -.B \-p -Perform history substitution on the following \fIargs\fP and display -the result on the standard output. -Does not store the results in the history list. -Each \fIarg\fP must be quoted to disable normal history expansion. -.TP -.B \-s -Store the -.I args -in the history list as a single entry. The last command in the -history list is removed before the -.I args -are added. -.PD -.PP -If the -.SM -.B HISTTIMEFORMAT -variable is set, the time stamp information -associated with each history entry is written to the history file, -marked with the history comment character. -When the history file is read, lines beginning with the history -comment character followed immediately by a digit are interpreted -as timestamps for the previous history line. -The return value is 0 unless an invalid option is encountered, an -error occurs while reading or writing the history file, an invalid -\fIoffset\fP is supplied as an argument to \fB\-d\fP, or the -history expansion supplied as an argument to \fB\-p\fP fails. -.RE -.TP -\fBjobs\fP [\fB\-lnprs\fP] [ \fIjobspec\fP ... ] -.PD 0 -.TP -\fBjobs\fP \fB\-x\fP \fIcommand\fP [ \fIargs\fP ... ] -.PD -The first form lists the active jobs. The options have the following -meanings: -.RS -.PD 0 -.TP -.B \-l -List process IDs -in addition to the normal information. -.TP -.B \-n -Display information only about jobs that have changed status since -the user was last notified of their status. -.TP -.B \-p -List only the process ID of the job's process group -leader. -.TP -.B \-r -Display only running jobs. -.TP -.B \-s -Display only stopped jobs. -.PD -.PP -If -.I jobspec -is given, output is restricted to information about that job. -The return status is 0 unless an invalid option is encountered -or an invalid -.I jobspec -is supplied. -.PP -If the -.B \-x -option is supplied, -.B jobs -replaces any -.I jobspec -found in -.I command -or -.I args -with the corresponding process group ID, and executes -.I command -passing it -.IR args , -returning its exit status. -.RE -.TP -\fBkill\fP [\fB\-s\fP \fIsigspec\fP | \fB\-n\fP \fIsignum\fP | \fB\-\fP\fIsigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... -.PD 0 -.TP -\fBkill\fP \fB\-l\fP [\fIsigspec\fP | \fIexit_status\fP] -.PD -Send the signal named by -.I sigspec -or -.I signum -to the processes named by -.I pid -or -.IR jobspec . -.I sigspec -is either a case-insensitive signal name such as -.SM -.B SIGKILL -(with or without the -.SM -.B SIG -prefix) or a signal number; -.I signum -is a signal number. -If -.I sigspec -is not present, then -.SM -.B SIGTERM -is assumed. -An argument of -.B \-l -lists the signal names. -If any arguments are supplied when -.B \-l -is given, the names of the signals corresponding to the arguments are -listed, and the return status is 0. -The \fIexit_status\fP argument to -.B \-l -is a number specifying either a signal number or the exit status of -a process terminated by a signal. -.B kill -returns true if at least one signal was successfully sent, or false -if an error occurs or an invalid option is encountered. -.TP -\fBlet\fP \fIarg\fP [\fIarg\fP ...] -Each -.I arg -is an arithmetic expression to be evaluated (see -.SM -.B "ARITHMETIC EVALUATION" -above). -If the last -.I arg -evaluates to 0, -.B let -returns 1; 0 is returned otherwise. -.TP -\fBlocal\fP [\fIoption\fP] [\fIname\fP[=\fIvalue\fP] ...] -For each argument, a local variable named -.I name -is created, and assigned -.IR value . -The \fIoption\fP can be any of the options accepted by \fBdeclare\fP. -When -.B local -is used within a function, it causes the variable -.I name -to have a visible scope restricted to that function and its children. -With no operands, -.B local -writes a list of local variables to the standard output. It is -an error to use -.B local -when not within a function. The return status is 0 unless -.B local -is used outside a function, an invalid -.I name -is supplied, or -\fIname\fP is a readonly variable. -.TP -.B logout -Exit a login shell. -.TP -\fBmapfile\fP [\fB\-n\fP \fIcount\fP] [\fB\-O\fP \fIorigin\fP] [\fB\-s\fP \fIcount\fP] [\fB\-t\fP] [\fB\-u\fP \fIfd\fP] [\fB\-C\fP \fIcallback\fP] [\fB\-c\fP \fIquantum\fP] [\fIarray\fP] -.PD 0 -.TP -\fBreadarray\fP [\fB\-n\fP \fIcount\fP] [\fB\-O\fP \fIorigin\fP] [\fB\-s\fP \fIcount\fP] [\fB\-t\fP] [\fB\-u\fP \fIfd\fP] [\fB\-C\fP \fIcallback\fP] [\fB\-c\fP \fIquantum\fP] [\fIarray\fP] -.PD -Read lines from the standard input into the indexed array variable -.IR array , -or from file descriptor -.IR fd -if the -.B \-u -option is supplied. -The variable -.SM -.B MAPFILE -is the default \fIarray\fP. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-n -Copy at most -.I count -lines. If \fIcount\fP is 0, all lines are copied. -.TP -.B \-O -Begin assigning to -.I array -at index -.IR origin . -The default index is 0. -.TP -.B \-s -Discard the first \fIcount\fP lines read. -.TP -.B \-t -Remove a trailing newline from each line read. -.TP -.B \-u -Read lines from file descriptor \fIfd\fP instead of the standard input. -.TP -.B \-C -Evaluate -.I callback -each time \fIquantum\fP lines are read. The \fB\-c\fP option specifies -.IR quantum . -.TP -.B \-c -Specify the number of lines read between each call to -.IR callback . -.PD -.PP -If -.B \-C -is specified without -.BR \-c , -the default quantum is 5000. -When \fIcallback\fP is evaluated, it is supplied the index of the next -array element to be assigned and the line to be assigned to that element -as additional arguments. -\fIcallback\fP is evaluated after the line is read but before the -array element is assigned. -.PP -If not supplied with an explicit origin, \fBmapfile\fP will clear \fIarray\fP -before assigning to it. -.PP -\fBmapfile\fP returns successfully unless an invalid option or option -argument is supplied, \fIarray\fP is invalid or unassignable, or if -\fIarray\fP is not an indexed array. -.RE -.TP -\fBpopd\fP [\-\fBn\fP] [+\fIn\fP] [\-\fIn\fP] -Removes entries from the directory stack. With no arguments, -removes the top directory from the stack, and performs a -.B cd -to the new top directory. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -.TP -\fB+\fP\fIn\fP -Removes the \fIn\fPth entry counting from the left of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd +0'' -.if t \f(CWpopd +0\fP -removes the first directory, -.if n ``popd +1'' -.if t \f(CWpopd +1\fP -the second. -.TP -\fB\-\fP\fIn\fP -Removes the \fIn\fPth entry counting from the right of the list -shown by -.BR dirs , -starting with zero. For example: -.if n ``popd -0'' -.if t \f(CWpopd -0\fP -removes the last directory, -.if n ``popd -1'' -.if t \f(CWpopd -1\fP -the next to last. -.PD -.PP -If the -.B popd -command is successful, a -.B dirs -is performed as well, and the return status is 0. -.B popd -returns false if an invalid option is encountered, the directory stack -is empty, a non-existent directory stack entry is specified, or the -directory change fails. -.RE -.TP -\fBprintf\fP [\fB\-v\fP \fIvar\fP] \fIformat\fP [\fIarguments\fP] -Write the formatted \fIarguments\fP to the standard output under the -control of the \fIformat\fP. -The \fB\-v\fP option causes the output to be assigned to the variable -\fIvar\fP rather than being printed to the standard output. -.sp 1 -The \fIformat\fP is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -\fIargument\fP. -In addition to the standard \fIprintf\fP(1) format specifications, -\fBprintf\fP interprets the following extensions: -.RS -.PD 0 -.TP -.B %b -causes -\fBprintf\fP to expand backslash escape sequences in the corresponding -\fIargument\fP (except that \fB\ec\fP terminates output, backslashes in -\fB\e\(aq\fP, \fB\e"\fP, and \fB\e?\fP are not removed, and octal escapes -beginning with \fB\e0\fP may contain up to four digits). -.TP -.B %q -causes \fBprintf\fP to output the corresponding -\fIargument\fP in a format that can be reused as shell input. -.TP -.B %(\fIdatefmt\fP)T -causes \fBprintf\fP to output the date-time string resulting from using -\fIdatefmt\fP as a format string for \fIstrftime\fP(3). The corresponding -\fIargument\fP is an integer representing the number of seconds since the -epoch. Two special argument values may be used: -1 represents the current -time, and -2 represents the time the shell was invoked. -.PD -.PP -Arguments to non-string format specifiers are treated as C constants, -except that a leading plus or minus sign is allowed, and if the leading -character is a single or double quote, the value is the ASCII value of -the following character. -.PP -The \fIformat\fP is reused as necessary to consume all of the \fIarguments\fP. -If the \fIformat\fP requires more \fIarguments\fP than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. -The return value is zero on success, non-zero on failure. -.RE -.TP -\fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] -.PD 0 -.TP -\fBpushd\fP [\fB\-n\fP] [\fIdir\fP] -.PD -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories -and returns 0, unless the directory stack is empty. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -.TP -\fB+\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the left of the list shown by -.BR dirs , -starting with zero) -is at the top. -.TP -\fB\-\fP\fIn\fP -Rotates the stack so that the \fIn\fPth directory -(counting from the right of the list shown by -.BR dirs , -starting with zero) is at the top. -.TP -.I dir -Adds -.I dir -to the directory stack at the top, making it the -new current working directory as if it had been supplied as the argument -to the \fBcd\fP builtin. -.PD -.PP -If the -.B pushd -command is successful, a -.B dirs -is performed as well. -If the first form is used, -.B pushd -returns 0 unless the cd to -.I dir -fails. With the second form, -.B pushd -returns 0 unless the directory stack is empty, -a non-existent directory stack element is specified, -or the directory change to the specified new current directory -fails. -.RE -.TP -\fBpwd\fP [\fB\-LP\fP] -Print the absolute pathname of the current working directory. -The pathname printed contains no symbolic links if the -.B \-P -option is supplied or the -.B \-o physical -option to the -.B set -builtin command is enabled. -If the -.B \-L -option is used, the pathname printed may contain symbolic links. -The return status is 0 unless an error occurs while -reading the name of the current directory or an -invalid option is supplied. -.TP -\fBread\fP [\fB\-ers\fP] [\fB\-a\fP \fIaname\fP] [\fB\-d\fP \fIdelim\fP] [\fB\-i\fP \fItext\fP] [\fB\-n\fP \fInchars\fP] [\fB\-N\fP \fInchars\fP] [\fB\-p\fP \fIprompt\fP] [\fB\-t\fP \fItimeout\fP] [\fB\-u\fP \fIfd\fP] [\fIname\fP ...] -One line is read from the standard input, or from the file descriptor -\fIfd\fP supplied as an argument to the \fB\-u\fP option, and the first word -is assigned to the first -.IR name , -the second word to the second -.IR name , -and so on, with leftover words and their intervening separators assigned -to the last -.IR name . -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in -.SM -.B IFS -are used to split the line into words. -The backslash character (\fB\e\fP) may be used to remove any special -meaning for the next character read and for line continuation. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-a \fIaname\fP -The words are assigned to sequential indices -of the array variable -.IR aname , -starting at 0. -.I aname -is unset before any new values are assigned. -Other \fIname\fP arguments are ignored. -.TP -.B \-d \fIdelim\fP -The first character of \fIdelim\fP is used to terminate the input line, -rather than newline. -.TP -.B \-e -If the standard input -is coming from a terminal, -.B readline -(see -.SM -.B READLINE -above) is used to obtain the line. -Readline uses the current (or default, if line editing was not previously -active) editing settings. -.TP -.B \-i \fItext\fP -If -.B readline -is being used to read the line, \fItext\fP is placed into the editing -buffer before editing begins. -.TP -.B \-n \fInchars\fP -\fBread\fP returns after reading \fInchars\fP characters rather than -waiting for a complete line of input, but honor a delimiter if fewer -than \fInchars\fP characters are read before the delimiter. -.TP -.B \-N \fInchars\fP -\fBread\fP returns after reading exactly \fInchars\fP characters rather -than waiting for a complete line of input, unless EOF is encountered or -\fBread\fP times out. -Delimiter characters encountered in the input are -not treated specially and do not cause \fBread\fP to return until -\fInchars\fP characters are read. -.TP -.B \-p \fIprompt\fP -Display \fIprompt\fP on standard error, without a -trailing newline, before attempting to read any input. The prompt -is displayed only if input is coming from a terminal. -.TP -.B \-r -Backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. -.TP -.B \-s -Silent mode. If input is coming from a terminal, characters are -not echoed. -.TP -.B \-t \fItimeout\fP -Cause \fBread\fP to time out and return failure if a complete line of -input is not read within \fItimeout\fP seconds. -\fItimeout\fP may be a decimal number with a fractional portion following -the decimal point. -This option is only effective if \fBread\fP is reading input from a -terminal, pipe, or other special file; it has no effect when reading -from regular files. -If \fItimeout\fP is 0, \fBread\fP returns immediately, without trying to -read any data. The exit statis is 0 if input is available on -the specified file descriptor, non-zero otherwise. -The exit status is greater than 128 if the timeout is exceeded. -.TP -.B \-u \fIfd\fP -Read input from file descriptor \fIfd\fP. -.PD -.PP -If no -.I names -are supplied, the line read is assigned to the variable -.SM -.BR REPLY . -The return code is zero, unless end-of-file is encountered, \fBread\fP -times out (in which case the return code is greater than 128), -a variable assignment error (such as assigning to a readonly variable) occurs, -or an invalid file descriptor is supplied as the argument to \fB\-u\fP. -.RE -.TP -\fBreadonly\fP [\fB\-aAf\fP] [\fB\-p\fP] [\fIname\fP[=\fIword\fP] ...] -.PD -The given -\fInames\fP are marked readonly; the values of these -.I names -may not be changed by subsequent assignment. -If the -.B \-f -option is supplied, the functions corresponding to the -\fInames\fP are so -marked. -The -.B \-a -option restricts the variables to indexed arrays; the -.B \-A -option restricts the variables to associative arrays. -If both options are supplied, -.B \-A -takes precedence. -If no -.I name -arguments are given, or if the -.B \-p -option is supplied, a list of all readonly names is printed. -The other options may be used to restrict the output to a subset of -the set of readonly names. -The -.B \-p -option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =\fIword\fP, the value of -the variable is set to \fIword\fP. -The return status is 0 unless an invalid option is encountered, -one of the -.I names -is not a valid shell variable name, or -.B \-f -is supplied with a -.I name -that is not a function. -.TP -\fBreturn\fP [\fIn\fP] -Causes a function to stop executing and return the value specified by -.I n -to its caller. -If -.I n -is omitted, the return status is that of the last command -executed in the function body. If -.B return -is used outside a function, -but during execution of a script by the -.B . -(\fBsource\fP) command, it causes the shell to stop executing -that script and return either -.I n -or the exit status of the last command executed within the -script as the exit status of the script. -If \fIn\fP is supplied, the return value is its least significant -8 bits. -The return status is non-zero if -.B return -is supplied a non-numeric argument, or -is used outside a -function and not during execution of a script by \fB.\fP\^ or \fBsource\fP. -Any command associated with the \fBRETURN\fP trap is executed -before execution resumes after the function or script. -.TP -\fBset\fP [\fB\-\-abefhkmnptuvxBCEHPT\fP] [\fB\-o\fP \fIoption\-name\fP] [\fIarg\fP ...] -.PD 0 -.TP -\fBset\fP [\fB+abefhkmnptuvxBCEHPT\fP] [\fB+o\fP \fIoption\-name\fP] [\fIarg\fP ...] -.PD -Without options, the name and value of each shell variable are displayed -in a format that can be reused as input -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In \fIposix mode\fP, only shell variables are listed. -The output is sorted according to the current locale. -When options are specified, they set or unset shell attributes. -Any arguments remaining after option processing are treated -as values for the positional parameters and are assigned, in order, to -.BR $1 , -.BR $2 , -.B ... -.BR $\fIn\fP . -Options, if specified, have the following meanings: -.RS -.PD 0 -.TP 8 -.B \-a -Automatically mark variables and functions which are modified or -created for export to the environment of subsequent commands. -.TP 8 -.B \-b -Report the status of terminated background jobs -immediately, rather than before the next primary prompt. This is -effective only when job control is enabled. -.TP 8 -.B \-e -Exit immediately if a -\fIpipeline\fP (which may consist of a single \fIsimple command\fP), -a \fIlist\fP, -or a \fIcompound command\fP -(see -.SM -.B SHELL GRAMMAR -above), exits with a non-zero status. -The shell does not exit if the -command that fails is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test following the -.B if -or -.B elif -reserved words, part of any command executed in a -.B && -or -.B || -list except the command following the final \fB&&\fP or \fB||\fP, -any command in a pipeline but the last, -or if the command's return value is -being inverted with -.BR ! . -If a compound command other than a subshell -returns a non-zero status because a command failed -while \fB\-e\fP was being ignored, the shell does not exit. -A trap on \fBERR\fP, if set, is executed before the shell exits. -This option applies to the shell environment and each subshell environment -separately (see -.SM -.B "COMMAND EXECUTION ENVIRONMENT" -above), and may cause -subshells to exit before executing all the commands in the subshell. -.TP 8 -.B \-f -Disable pathname expansion. -.TP 8 -.B \-h -Remember the location of commands as they are looked up for execution. -This is enabled by default. -.TP 8 -.B \-k -All arguments in the form of assignment statements -are placed in the environment for a command, not just -those that precede the command name. -.TP 8 -.B \-m -Monitor mode. Job control is enabled. This option is on -by default for interactive shells on systems that support -it (see -.SM -.B JOB CONTROL -above). -All processes run in a separate process group. -When a background job completes, the shell prints a line -containing its exit status. -.TP 8 -.B \-n -Read commands but do not execute them. This may be used to -check a shell script for syntax errors. This is ignored by -interactive shells. -.TP 8 -.B \-o \fIoption\-name\fP -The \fIoption\-name\fP can be one of the following: -.RS -.TP 8 -.B allexport -Same as -.BR \-a . -.TP 8 -.B braceexpand -Same as -.BR \-B . -.TP 8 -.B emacs -Use an emacs-style command line editing interface. This is enabled -by default when the shell is interactive, unless the shell is started -with the -.B \-\-noediting -option. -This also affects the editing interface used for \fBread \-e\fP. -.TP 8 -.B errexit -Same as -.BR \-e . -.TP 8 -.B errtrace -Same as -.BR \-E . -.TP 8 -.B functrace -Same as -.BR \-T . -.TP 8 -.B hashall -Same as -.BR \-h . -.TP 8 -.B histexpand -Same as -.BR \-H . -.TP 8 -.B history -Enable command history, as described above under -.SM -.BR HISTORY . -This option is on by default in interactive shells. -.TP 8 -.B ignoreeof -The effect is as if the shell command -.if t \f(CWIGNOREEOF=10\fP -.if n ``IGNOREEOF=10'' -had been executed -(see -.B Shell Variables -above). -.TP 8 -.B keyword -Same as -.BR \-k . -.TP 8 -.B monitor -Same as -.BR \-m . -.TP 8 -.B noclobber -Same as -.BR \-C . -.TP 8 -.B noexec -Same as -.BR \-n . -.TP 8 -.B noglob -Same as -.BR \-f . -.TP 8 -.B nolog -Currently ignored. -.TP 8 -.B notify -Same as -.BR \-b . -.TP 8 -.B nounset -Same as -.BR \-u . -.TP 8 -.B onecmd -Same as -.BR \-t . -.TP 8 -.B physical -Same as -.BR \-P . -.TP 8 -.B pipefail -If set, the return value of a pipeline is the value of the last -(rightmost) command to exit with a non-zero status, or zero if all -commands in the pipeline exit successfully. -This option is disabled by default. -.TP 8 -.B posix -Change the behavior of -.B bash -where the default operation differs -from the POSIX standard to match the standard (\fIposix mode\fP). -.TP 8 -.B privileged -Same as -.BR \-p . -.TP 8 -.B verbose -Same as -.BR \-v . -.TP 8 -.B vi -Use a vi-style command line editing interface. -This also affects the editing interface used for \fBread \-e\fP. -.TP 8 -.B xtrace -Same as -.BR \-x . -.sp .5 -.PP -If -.B \-o -is supplied with no \fIoption\-name\fP, the values of the current options are -printed. -If -.B +o -is supplied with no \fIoption\-name\fP, a series of -.B set -commands to recreate the current option settings is displayed on -the standard output. -.RE -.TP 8 -.B \-p -Turn on -.I privileged -mode. In this mode, the -.SM -.B $ENV -and -.SM -.B $BASH_ENV -files are not processed, shell functions are not inherited from the -environment, and the -.SM -.BR SHELLOPTS , -.SM -.BR BASHOPTS , -.SM -.BR CDPATH , -and -.SM -.B GLOBIGNORE -variables, if they appear in the environment, are ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at startup, the effective user id is -not reset. -Turning this option off causes the effective user -and group ids to be set to the real user and group ids. -.TP 8 -.B \-t -Exit after reading and executing one command. -.TP 8 -.B \-u -Treat unset variables and parameters other than the special -parameters "@" and "*" as an error when performing -parameter expansion. If expansion is attempted on an -unset variable or parameter, the shell prints an error message, and, -if not interactive, exits with a non-zero status. -.TP 8 -.B \-v -Print shell input lines as they are read. -.TP 8 -.B \-x -After expanding each \fIsimple command\fP, -\fBfor\fP command, \fBcase\fP command, \fBselect\fP command, or -arithmetic \fBfor\fP command, display the expanded value of -.SM -.BR PS4 , -followed by the command and its expanded arguments -or associated word list. -.TP 8 -.B \-B -The shell performs brace expansion (see -.B Brace Expansion -above). This is on by default. -.TP 8 -.B \-C -If set, -.B bash -does not overwrite an existing file with the -.BR > , -.BR >& , -and -.B <> -redirection operators. This may be overridden when -creating output files by using the redirection operator -.B >| -instead of -.BR > . -.TP 8 -.B \-E -If set, any trap on \fBERR\fP is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The \fBERR\fP trap is normally not inherited in such cases. -.TP 8 -.B \-H -Enable -.B ! -style history substitution. This option is on by -default when the shell is interactive. -.TP 8 -.B \-P -If set, the shell does not resolve symbolic links when executing -commands such as -.B cd -that change the current working directory. It uses the -physical directory structure instead. By default, -.B bash -follows the logical chain of directories when performing commands -which change the current directory. -.TP 8 -.B \-T -If set, any traps on \fBDEBUG\fP and \fBRETURN\fP are inherited by shell -functions, command substitutions, and commands executed in a -subshell environment. -The \fBDEBUG\fP and \fBRETURN\fP traps are normally not inherited -in such cases. -.TP 8 -.B \-\- -If no arguments follow this option, then the positional parameters are -unset. Otherwise, the positional parameters are set to the -\fIarg\fPs, even if some of them begin with a -.BR \- . -.TP 8 -.B \- -Signal the end of options, cause all remaining \fIarg\fPs to be -assigned to the positional parameters. The -.B \-x -and -.B \-v -options are turned off. -If there are no \fIarg\fPs, -the positional parameters remain unchanged. -.PD -.PP -The options are off by default unless otherwise noted. -Using + rather than \- causes these options to be turned off. -The options can also be specified as arguments to an invocation of -the shell. -The current set of options may be found in -.BR $\- . -The return status is always true unless an invalid option is encountered. -.RE -.TP -\fBshift\fP [\fIn\fP] -The positional parameters from \fIn\fP+1 ... are renamed to -.B $1 -.B .... -Parameters represented by the numbers \fB$#\fP -down to \fB$#\fP\-\fIn\fP+1 are unset. -.I n -must be a non-negative number less than or equal to \fB$#\fP. -If -.I n -is 0, no parameters are changed. -If -.I n -is not given, it is assumed to be 1. -If -.I n -is greater than \fB$#\fP, the positional parameters are not changed. -The return status is greater than zero if -.I n -is greater than -.B $# -or less than zero; otherwise 0. -.TP -\fBshopt\fP [\fB\-pqsu\fP] [\fB\-o\fP] [\fIoptname\fP ...] -Toggle the values of variables controlling optional shell behavior. -With no options, or with the -.B \-p -option, a list of all settable options is displayed, with -an indication of whether or not each is set. -The \fB\-p\fP option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: -.RS -.PD 0 -.TP -.B \-s -Enable (set) each \fIoptname\fP. -.TP -.B \-u -Disable (unset) each \fIoptname\fP. -.TP -.B \-q -Suppresses normal output (quiet mode); the return status indicates -whether the \fIoptname\fP is set or unset. -If multiple \fIoptname\fP arguments are given with -.BR \-q , -the return status is zero if all \fIoptnames\fP are enabled; non-zero -otherwise. -.TP -.B \-o -Restricts the values of \fIoptname\fP to be those defined for the -.B \-o -option to the -.B set -builtin. -.PD -.PP -If either -.B \-s -or -.B \-u -is used with no \fIoptname\fP arguments, -.B shopt -shows only those options which are set or unset, respectively. -Unless otherwise noted, the \fBshopt\fP options are disabled (unset) -by default. -.PP -The return status when listing options is zero if all \fIoptnames\fP -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an \fIoptname\fP is not a valid shell -option. -.PP -The list of \fBshopt\fP options is: -.if t .sp .5v -.if n .sp 1v -.PD 0 -.TP 8 -.B autocd -If set, a command name that is the name of a directory is executed as if -it were the argument to the \fBcd\fP command. -This option is only used by interactive shells. -.TP 8 -.B cdable_vars -If set, an argument to the -.B cd -builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. -.TP 8 -.B cdspell -If set, minor errors in the spelling of a directory component in a -.B cd -command will be corrected. -The errors checked for are transposed characters, -a missing character, and one character too many. -If a correction is found, the corrected filename is printed, -and the command proceeds. -This option is only used by interactive shells. -.TP 8 -.B checkhash -If set, \fBbash\fP checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. -.TP 8 -.B checkjobs -If set, \fBbash\fP lists the status of any stopped and running jobs before -exiting an interactive shell. If any jobs are running, this causes -the exit to be deferred until a second exit is attempted without an -intervening command (see -.SM -.B "JOB CONTROL" -above). The shell always -postpones exiting if any jobs are stopped. -.TP 8 -.B checkwinsize -If set, \fBbash\fP checks the window size after each command -and, if necessary, updates the values of -.SM -.B LINES -and -.SM -.BR COLUMNS . -.TP 8 -.B cmdhist -If set, -.B bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. -.TP 8 -.B compat31 -If set, -.B bash -changes its behavior to that of version 3.1 with respect to quoted -arguments to the \fB[[\fP conditional command's \fB=~\fP operator -and locale-specific string comparison when using the \fB[[\fP -conditional command's \fB<\fP and \fB>\fP operators. -Bash versions prior to bash-4.1 use ASCII collation and -.IR strcmp (3); -bash-4.1 and later use the current locale's collation sequence and -.IR strcoll (3). -.TP 8 -.B compat32 -If set, -.B bash -changes its behavior to that of version 3.2 with respect to -locale-specific string comparison when using the \fB[[\fP -conditional command's \fB<\fP and \fB>\fP operators (see previous item). -.TP 8 -.B compat40 -If set, -.B bash -changes its behavior to that of version 4.0 with respect to locale-specific -string comparison when using the \fB[[\fP -conditional command's \fB<\fP and \fB>\fP operators (see description of -\fBcompat31\fP) -and the effect of interrupting a command list. -Bash versions 4.0 and later interrupt the list as if the shell received the -interrupt; previous versions continue with the next command in the list. -.TP 8 -.B compat41 -If set, -.BR bash , -when in posix mode, treats a single quote in a double-quoted -parameter expansion as a special character. The single quotes must match -(an even number) and the characters between the single quotes are considered -quoted. This is the behavior of posix mode through version 4.1. -The default bash behavior remains as in previous versions. -.TP 8 -.B complete_fullquote -If set, -.B bash -quotes all shell metacharacters in filenames and directory names when -performing completion. -If not set, -.B bash -removes metacharacters such as the dollar sign from the set of -characters that will be quoted in completed filenames -when these metacharacters appear in shell variable references in words to be -completed. -This means that dollar signs in variable names that expand to directories -will not be quoted; -however, any dollar signs appearing in filenames will not be quoted, either. -This is active only when bash is using backslashes to quote completed -filenames. -This variable is set by default, which is the default bash behavior in -versions through 4.2. -.TP 8 -.B direxpand -If set, -.B bash -replaces directory names with the results of word expansion when performing -filename completion. This changes the contents of the readline editing -buffer. -If not set, -.B bash -attempts to preserve what the user typed. -.TP 8 -.B dirspell -If set, -.B bash -attempts spelling correction on directory names during word completion -if the directory name initially supplied does not exist. -.TP 8 -.B dotglob -If set, -.B bash -includes filenames beginning with a `.' in the results of pathname -expansion. -.TP 8 -.B execfail -If set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the -.B exec -builtin command. An interactive shell does not exit if -.B exec -fails. -.TP 8 -.B expand_aliases -If set, aliases are expanded as described above under -.SM -.BR ALIASES . -This option is enabled by default for interactive shells. -.TP 8 -.B extdebug -If set, behavior intended for use by debuggers is enabled: -.RS -.TP -.B 1. -The \fB\-F\fP option to the \fBdeclare\fP builtin displays the source -file name and line number corresponding to each function name supplied -as an argument. -.TP -.B 2. -If the command run by the \fBDEBUG\fP trap returns a non-zero value, the -next command is skipped and not executed. -.TP -.B 3. -If the command run by the \fBDEBUG\fP trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the \fB.\fP or \fBsource\fP builtins), a call to -\fBreturn\fP is simulated. -.TP -.B 4. -.SM -.B BASH_ARGC -and -.SM -.B BASH_ARGV -are updated as described in their descriptions above. -.TP -.B 5. -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the -\fBDEBUG\fP and \fBRETURN\fP traps. -.TP -.B 6. -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the -\fBERR\fP trap. -.RE -.TP 8 -.B extglob -If set, the extended pattern matching features described above under -\fBPathname Expansion\fP are enabled. -.TP 8 -.B extquote -If set, \fB$\fP\(aq\fIstring\fP\(aq and \fB$\fP"\fIstring\fP" quoting is -performed within \fB${\fP\fIparameter\fP\fB}\fP expansions -enclosed in double quotes. This option is enabled by default. -.TP 8 -.B failglob -If set, patterns which fail to match filenames during pathname expansion -result in an expansion error. -.TP 8 -.B force_fignore -If set, the suffixes specified by the -.SM -.B FIGNORE -shell variable -cause words to be ignored when performing word completion even if -the ignored words are the only possible completions. -See -.SM -\fBSHELL VARIABLES\fP -above for a description of -.SM -.BR FIGNORE . -This option is enabled by default. -.TP 8 -.B globasciiranges -If set, range expressions used in pattern matching (see -.SM -.B Pattern Matching -above) behave as if in the traditional C locale when performing -comparisons. That is, the current locale's collating sequence -is not taken into account, so -.B b -will not collate between -.B A -and -.BR B , -and upper-case and lower-case ASCII characters will collate together. -.TP 8 -.B globstar -If set, the pattern \fB**\fP used in a pathname expansion context will -match all files and zero or more directories and subdirectories. -If the pattern is followed by a \fB/\fP, only directories and -subdirectories match. -.TP 8 -.B gnu_errfmt -If set, shell error messages are written in the standard GNU error -message format. -.TP 8 -.B histappend -If set, the history list is appended to the file named by the value -of the -.SM -.B HISTFILE -variable when the shell exits, rather than overwriting the file. -.TP 8 -.B histreedit -If set, and -.B readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. -.TP 8 -.B histverify -If set, and -.B readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the \fBreadline\fP editing buffer, allowing further modification. -.TP 8 -.B hostcomplete -If set, and -.B readline -is being used, \fBbash\fP will attempt to perform hostname completion when a -word containing a \fB@\fP is being completed (see -.B Completing -under -.SM -.B READLINE -above). -This is enabled by default. -.TP 8 -.B huponexit -If set, \fBbash\fP will send -.SM -.B SIGHUP -to all jobs when an interactive login shell exits. -.TP 8 -.B interactive_comments -If set, allow a word beginning with -.B # -to cause that word and all remaining characters on that -line to be ignored in an interactive shell (see -.SM -.B COMMENTS -above). This option is enabled by default. -.TP 8 -.B lastpipe -If set, and job control is not active, the shell runs the last command of -a pipeline not executed in the background in the current shell environment. -.TP 8 -.B lithist -If set, and the -.B cmdhist -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. -.TP 8 -.B login_shell -The shell sets this option if it is started as a login shell (see -.SM -.B "INVOCATION" -above). -The value may not be changed. -.TP 8 -.B mailwarn -If set, and a file that \fBbash\fP is checking for mail has been -accessed since the last time it was checked, the message ``The mail in -\fImailfile\fP has been read'' is displayed. -.TP 8 -.B no_empty_cmd_completion -If set, and -.B readline -is being used, -.B bash -will not attempt to search the -.SM -.B PATH -for possible completions when -completion is attempted on an empty line. -.TP 8 -.B nocaseglob -If set, -.B bash -matches filenames in a case\-insensitive fashion when performing pathname -expansion (see -.B Pathname Expansion -above). -.TP 8 -.B nocasematch -If set, -.B bash -matches patterns in a case\-insensitive fashion when performing matching -while executing \fBcase\fP or \fB[[\fP conditional commands. -.TP 8 -.B nullglob -If set, -.B bash -allows patterns which match no -files (see -.B Pathname Expansion -above) -to expand to a null string, rather than themselves. -.TP 8 -.B progcomp -If set, the programmable completion facilities (see -\fBProgrammable Completion\fP above) are enabled. -This option is enabled by default. -.TP 8 -.B promptvars -If set, prompt strings undergo -parameter expansion, command substitution, arithmetic -expansion, and quote removal after being expanded as described in -.SM -.B PROMPTING -above. This option is enabled by default. -.TP 8 -.B restricted_shell -The shell sets this option if it is started in restricted mode (see -.SM -.B "RESTRICTED SHELL" -below). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. -.TP 8 -.B shift_verbose -If set, the -.B shift -builtin prints an error message when the shift count exceeds the -number of positional parameters. -.TP 8 -.B sourcepath -If set, the -\fBsource\fP (\fB.\fP) builtin uses the value of -.SM -.B PATH -to find the directory containing the file supplied as an argument. -This option is enabled by default. -.TP 8 -.B xpg_echo -If set, the \fBecho\fP builtin expands backslash-escape sequences -by default. -.RE -.PD -.TP -\fBsuspend\fP [\fB\-f\fP] -Suspend the execution of this shell until it receives a -.SM -.B SIGCONT -signal. A login shell cannot be suspended; the -.B \-f -option can be used to override this and force the suspension. -The return status is 0 unless the shell is a login shell and -.B \-f -is not supplied, or if job control is not enabled. -.TP -\fBtest\fP \fIexpr\fP -.PD 0 -.TP -\fB[\fP \fIexpr\fP \fB]\fP -Return a status of 0 (true) or 1 (false) depending on -the evaluation of the conditional expression -.IR expr . -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described above under -.SM -.BR "CONDITIONAL EXPRESSIONS" . -\fBtest\fP does not accept any options, nor does it accept and ignore -an argument of \fB\-\-\fP as signifying the end of options. -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence. -The evaluation depends on the number of arguments; see below. -Operator precedence is used when there are five or more arguments. -.RS -.PD 0 -.TP -.B ! \fIexpr\fP -True if -.I expr -is false. -.TP -.B ( \fIexpr\fP ) -Returns the value of \fIexpr\fP. -This may be used to override the normal precedence of operators. -.TP -\fIexpr1\fP \-\fBa\fP \fIexpr2\fP -True if both -.I expr1 -and -.I expr2 -are true. -.TP -\fIexpr1\fP \-\fBo\fP \fIexpr2\fP -True if either -.I expr1 -or -.I expr2 -is true. -.PD -.PP -\fBtest\fP and \fB[\fP evaluate conditional -expressions using a set of rules based on the number of arguments. -.if t .sp 0.5 -.if n .sp 1 -.PD 0 -.TP -0 arguments -The expression is false. -.TP -1 argument -The expression is true if and only if the argument is not null. -.TP -2 arguments -If the first argument is \fB!\fP, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the expression is true if the unary test is true. -If the first argument is not a valid unary conditional operator, the expression -is false. -.TP -3 arguments -The following conditions are applied in the order listed. -If the second argument is one of the binary conditional operators listed above -under -.SM -.BR "CONDITIONAL EXPRESSIONS" , -the result of the expression is the result of the binary test using -the first and third arguments as operands. -The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -when there are three arguments. -If the first argument is \fB!\fP, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly \fB(\fP and the third argument is -exactly \fB)\fP, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -.TP -4 arguments -If the first argument is \fB!\fP, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. -.TP -5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -.if t .sp 0.5 -.if n .sp 1 -.LP -When used with \fBtest\fP or \fB[\fP, the \fB<\fP and \fB>\fP operators -sort lexicographically using ASCII ordering. -.RE -.PD -.TP -.B times -Print the accumulated user and system times for the shell and -for processes run from the shell. The return status is 0. -.TP -\fBtrap\fP [\fB\-lp\fP] [[\fIarg\fP] \fIsigspec\fP ...] -The command -.I arg -is to be read and executed when the shell receives -signal(s) -.IR sigspec . -If -.I arg -is absent (and there is a single \fIsigspec\fP) or -.BR \- , -each specified signal is -reset to its original disposition (the value it had -upon entrance to the shell). -If -.I arg -is the null string the signal specified by each -.I sigspec -is ignored by the shell and by the commands it invokes. -If -.I arg -is not present and -.B \-p -has been supplied, then the trap commands associated with each -.I sigspec -are displayed. -If no arguments are supplied or if only -.B \-p -is given, -.B trap -prints the list of commands associated with each signal. -The -.B \-l -option causes the shell to print a list of signal names and -their corresponding numbers. -Each -.I sigspec -is either -a signal name defined in <\fIsignal.h\fP>, or a signal number. -Signal names are case insensitive and the -.SM -.B SIG -prefix is optional. -.if t .sp 0.5 -.if n .sp 1 -If a -.I sigspec -is -.SM -.B EXIT -(0) the command -.I arg -is executed on exit from the shell. -If a -.I sigspec -is -.SM -.BR DEBUG , -the command -.I arg -is executed before every \fIsimple command\fP, \fIfor\fP command, -\fIcase\fP command, \fIselect\fP command, every arithmetic \fIfor\fP -command, and before the first command executes in a shell function (see -.SM -.B SHELL GRAMMAR -above). -Refer to the description of the \fBextdebug\fP option to the -\fBshopt\fP builtin for details of its effect on the \fBDEBUG\fP trap. -If a -.I sigspec -is -.SM -.BR RETURN , -the command -.I arg -is executed each time a shell function or a script executed with -the \fB.\fP or \fBsource\fP builtins finishes executing. -.if t .sp 0.5 -.if n .sp 1 -If a -.I sigspec -is -.SM -.BR ERR , -the command -.I arg -is executed whenever a simple command has a non\-zero exit status, -subject to the following conditions. -The -.SM -.B ERR -trap is not executed if the failed -command is part of the command list immediately following a -.B while -or -.B until -keyword, -part of the test in an -.I if -statement, part of a command executed in a -.B && -or -.B || -list, or if the command's return value is -being inverted via -.BR ! . -These are the same conditions obeyed by the \fBerrexit\fP option. -.if t .sp 0.5 -.if n .sp 1 -Signals ignored upon entry to the shell cannot be trapped or reset. -Trapped signals that are not being ignored are reset to their original -values in a subshell or subshell environment when one is created. -The return status is false if any -.I sigspec -is invalid; otherwise -.B trap -returns true. -.TP -\fBtype\fP [\fB\-aftpP\fP] \fIname\fP [\fIname\fP ...] -With no options, -indicate how each -.I name -would be interpreted if used as a command name. -If the -.B \-t -option is used, -.B type -prints a string which is one of -.IR alias , -.IR keyword , -.IR function , -.IR builtin , -or -.I file -if -.I name -is an alias, shell reserved word, function, builtin, or disk file, -respectively. -If the -.I name -is not found, then nothing is printed, and an exit status of false -is returned. -If the -.B \-p -option is used, -.B type -either returns the name of the disk file -that would be executed if -.I name -were specified as a command name, -or nothing if -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -The -.B \-P -option forces a -.SM -.B PATH -search for each \fIname\fP, even if -.if t \f(CWtype -t name\fP -.if n ``type -t name'' -would not return -.IR file . -If a command is hashed, -.B \-p -and -.B \-P -print the hashed value, which is not necessarily the file that appears -first in -.SM -.BR PATH . -If the -.B \-a -option is used, -.B type -prints all of the places that contain -an executable named -.IR name . -This includes aliases and functions, -if and only if the -.B \-p -option is not also used. -The table of hashed commands is not consulted -when using -.BR \-a . -The -.B \-f -option suppresses shell function lookup, as with the \fBcommand\fP builtin. -.B type -returns true if all of the arguments are found, false if -any are not found. -.TP -\fBulimit\fP [\fB\-HSTabcdefilmnpqrstuvx\fP [\fIlimit\fP]] -Provides control over the resources available to the shell and to -processes started by it, on systems that allow such control. -The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is -set for the given resource. -A hard limit cannot be increased by a non-root user once it is set; -a soft limit may be increased up to the value of the hard limit. -If neither \fB\-H\fP nor \fB\-S\fP is specified, both the soft and hard -limits are set. -The value of -.I limit -can be a number in the unit specified for the resource -or one of the special values -.BR hard , -.BR soft , -or -.BR unlimited , -which stand for the current hard limit, the current soft limit, and -no limit, respectively. -If -.I limit -is omitted, the current value of the soft limit of the resource is -printed, unless the \fB\-H\fP option is given. When more than one -resource is specified, the limit name and unit are printed before the value. -Other options are interpreted as follows: -.RS -.PD 0 -.TP -.B \-a -All current limits are reported -.TP -.B \-b -The maximum socket buffer size -.TP -.B \-c -The maximum size of core files created -.TP -.B \-d -The maximum size of a process's data segment -.TP -.B \-e -The maximum scheduling priority ("nice") -.TP -.B \-f -The maximum size of files written by the shell and its children -.TP -.B \-i -The maximum number of pending signals -.TP -.B \-l -The maximum size that may be locked into memory -.TP -.B \-m -The maximum resident set size (many systems do not honor this limit) -.TP -.B \-n -The maximum number of open file descriptors (most systems do not -allow this value to be set) -.TP -.B \-p -The pipe size in 512-byte blocks (this may not be set) -.TP -.B \-q -The maximum number of bytes in POSIX message queues -.TP -.B \-r -The maximum real-time scheduling priority -.TP -.B \-s -The maximum stack size -.TP -.B \-t -The maximum amount of cpu time in seconds -.TP -.B \-u -The maximum number of processes available to a single user -.TP -.B \-v -The maximum amount of virtual memory available to the shell and, on -some systems, to its children -.TP -.B \-x -The maximum number of file locks -.TP -.B \-T -The maximum number of threads -.PD -.PP -If -.I limit -is given, and the -.B \-a -option is not used, -\fIlimit\fP is the new value of the specified resource. -If no option is given, then -.B \-f -is assumed. Values are in 1024-byte increments, except for -.BR \-t , -which is in seconds; -.BR \-p , -which is in units of 512-byte blocks; -and -.BR \-T , -.BR \-b , -.BR \-n , -and -.BR \-u , -which are unscaled values. -The return status is 0 unless an invalid option or argument is supplied, -or an error occurs while setting a new limit. -.RE -.TP -\fBumask\fP [\fB\-p\fP] [\fB\-S\fP] [\fImode\fP] -The user file-creation mask is set to -.IR mode . -If -.I mode -begins with a digit, it -is interpreted as an octal number; otherwise -it is interpreted as a symbolic mode mask similar -to that accepted by -.IR chmod (1). -If -.I mode -is omitted, the current value of the mask is printed. -The -.B \-S -option causes the mask to be printed in symbolic form; the -default output is an octal number. -If the -.B \-p -option is supplied, and -.I mode -is omitted, the output is in a form that may be reused as input. -The return status is 0 if the mode was successfully changed or if -no \fImode\fP argument was supplied, and false otherwise. -.TP -\fBunalias\fP [\-\fBa\fP] [\fIname\fP ...] -Remove each \fIname\fP from the list of defined aliases. If -.B \-a -is supplied, all alias definitions are removed. The return -value is true unless a supplied -.I name -is not a defined alias. -.TP -\fBunset\fP [\-\fBfv\fP] [\-\fBn\fP] [\fIname\fP ...] -For each -.IR name , -remove the corresponding variable or function. -If the -.B \-v -option is given, each -.I name -refers to a shell variable, and that variable is removed. -Read-only variables may not be unset. -If -.B \-f -is specified, each -.I name -refers to a shell function, and the function definition -is removed. -If the -.B \-n -option is supplied, and \fIname\fP is a variable with the \fInameref\fP -attribute, \fIname\fP will be unset rather than the variable it -references. -\fB\-n\fP has no effect if the \fB\-f\fP option is supplied. -If no options are supplied, each \fIname\fP refers to a variable; if -there is no variable by that name, any function with that name is -unset. -Each unset variable or function is removed from the environment -passed to subsequent commands. -If any of -.SM -.BR COMP_WORDBREAKS , -.SM -.BR RANDOM , -.SM -.BR SECONDS , -.SM -.BR LINENO , -.SM -.BR HISTCMD , -.SM -.BR FUNCNAME , -.SM -.BR GROUPS , -or -.SM -.B DIRSTACK -are unset, they lose their special properties, even if they are -subsequently reset. The exit status is true unless a -.I name -is readonly. -.TP -\fBwait\fP [\fIn ...\fP] -Wait for each specified process and return its termination status. -Each -.I n -may be a process -ID or a job specification; if a job spec is given, all processes -in that job's pipeline are waited for. If -.I n -is not given, all currently active child processes -are waited for, and the return status is zero. If -.I n -specifies a non-existent process or job, the return status is -127. Otherwise, the return status is the exit status of the last -process or job waited for. -.\" bash_builtins -.if \n(zZ=1 .ig zZ -.SH "RESTRICTED SHELL" -.\" rbash.1 -.zY -.PP -If -.B bash -is started with the name -.BR rbash , -or the -.B \-r -option is supplied at invocation, -the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -It behaves identically to -.B bash -with the exception that the following are disallowed or not performed: -.IP \(bu -changing directories with \fBcd\fP -.IP \(bu -setting or unsetting the values of -.SM -.BR SHELL , -.SM -.BR PATH , -.SM -.BR ENV , -or -.SM -.B BASH_ENV -.IP \(bu -specifying command names containing -.B / -.IP \(bu -specifying a filename containing a -.B / -as an argument to the -.B . -builtin command -.IP \(bu -specifying a filename containing a slash as an argument to the -.B \-p -option to the -.B hash -builtin command -.IP \(bu -importing function definitions from the shell environment at startup -.IP \(bu -parsing the value of -.SM -.B SHELLOPTS -from the shell environment at startup -.IP \(bu -redirecting output using the >, >|, <>, >&, &>, and >> redirection operators -.IP \(bu -using the -.B exec -builtin command to replace the shell with another command -.IP \(bu -adding or deleting builtin commands with the -.B \-f -and -.B \-d -options to the -.B enable -builtin command -.IP \(bu -using the \fBenable\fP builtin command to enable disabled shell builtins -.IP \(bu -specifying the -.B \-p -option to the -.B command -builtin command -.IP \(bu -turning off restricted mode with -\fBset +r\fP or \fBset +o restricted\fP. -.PP -These restrictions are enforced after any startup files are read. -.PP -.ie \n(zY=1 When a command that is found to be a shell script is executed, -.el \{ When a command that is found to be a shell script is executed -(see -.SM -.B "COMMAND EXECUTION" -above), -\} -.B rbash -turns off any restrictions in the shell spawned to execute the -script. -.\" end of rbash.1 -.if \n(zY=1 .ig zY -.SH "SEE ALSO" -.PD 0 -.TP -\fIBash Reference Manual\fP, Brian Fox and Chet Ramey -.TP -\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey -.TP -\fIThe Gnu History Library\fP, Brian Fox and Chet Ramey -.TP -\fIPortable Operating System Interface (POSIX) Part 2: Shell and Utilities\fP, IEEE -.TP -\fIsh\fP(1), \fIksh\fP(1), \fIcsh\fP(1) -.TP -\fIemacs\fP(1), \fIvi\fP(1) -.TP -\fIreadline\fP(3) -.PD -.SH FILES -.PD 0 -.TP -.FN /bin/bash -The \fBbash\fP executable -.TP -.FN /etc/profile -The systemwide initialization file, executed for login shells -.TP -.FN ~/.bash_profile -The personal initialization file, executed for login shells -.TP -.FN ~/.bashrc -The individual per-interactive-shell startup file -.TP -.FN ~/.bash_logout -The individual login shell cleanup file, executed when a login shell exits -.TP -.FN ~/.inputrc -Individual \fIreadline\fP initialization file -.PD -.SH AUTHORS -Brian Fox, Free Software Foundation -.br -bfox@gnu.org -.PP -Chet Ramey, Case Western Reserve University -.br -chet.ramey@case.edu -.SH BUG REPORTS -If you find a bug in -.B bash, -you should report it. But first, you should -make sure that it really is a bug, and that it appears in the latest -version of -.BR bash . -The latest version is always available from -\fIftp://ftp.gnu.org/pub/gnu/bash/\fP. -.PP -Once you have determined that a bug actually exists, use the -.I bashbug -command to submit a bug report. -If you have a fix, you are encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to \fIbug-bash@gnu.org\fP or posted to the Usenet -newsgroup -.BR gnu.bash.bug . -.PP -ALL bug reports should include: -.PP -.PD 0 -.TP 20 -The version number of \fBbash\fR -.TP -The hardware and operating system -.TP -The compiler used to compile -.TP -A description of the bug behaviour -.TP -A short script or `recipe' which exercises the bug -.PD -.PP -.I bashbug -inserts the first three items automatically into the template -it provides for filing a bug report. -.PP -Comments and bug reports concerning -this manual page should be directed to -.IR chet.ramey@case.edu . -.SH BUGS -.PP -It's too big and too slow. -.PP -There are some subtle differences between -.B bash -and traditional versions of -.BR sh , -mostly because of the -.SM -.B POSIX -specification. -.PP -Aliases are confusing in some uses. -.PP -Shell builtin commands and functions are not stoppable/restartable. -.PP -Compound commands and command sequences of the form `a ; b ; c' -are not handled gracefully when process suspension is attempted. -When a process is stopped, the shell immediately executes the next -command in the sequence. -It suffices to place the sequence of commands between -parentheses to force it into a subshell, which may be stopped as -a unit. -.PP -Array variables may not (yet) be exported. -.PP -There may be only one active coprocess at a time. -.zZ -.zY diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ deleted file mode 100644 index 5eee0936e..000000000 --- a/doc/bashref.texi~ +++ /dev/null @@ -1,8585 +0,0 @@ -\input texinfo.tex @c -*- texinfo -*- -@c %**start of header -@setfilename bashref.info -@settitle Bash Reference Manual -@c %**end of header - -@setchapternewpage odd - -@include version.texi - -@copying -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}). - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Copyright @copyright{} 1988--2012 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -A copy of the license is included in the section entitled -``GNU Free Documentation License''. - -@end quotation -@end copying - -@defcodeindex bt -@defcodeindex rw -@set BashFeatures - -@dircategory Basics -@direntry -* Bash: (bash). The GNU Bourne-Again SHell. -@end direntry - -@finalout - -@titlepage -@title Bash Reference Manual -@subtitle Reference Documentation for Bash -@subtitle Edition @value{EDITION}, for @code{Bash} Version @value{VERSION}. -@subtitle @value{UPDATED-MONTH} -@author Chet Ramey, Case Western Reserve University -@author Brian Fox, Free Software Foundation - -@page -@vskip 0pt plus 1filll -@insertcopying - -@sp 1 -Published by the Free Software Foundation @* -59 Temple Place, Suite 330, @* -Boston, MA 02111-1307 @* -USA @* - -@end titlepage - -@contents - -@ifnottex -@node Top, Introduction, (dir), (dir) -@top Bash Features - -This text is a brief description of the features that are present in -the Bash shell (version @value{VERSION}, @value{UPDATED}). - -This is Edition @value{EDITION}, last updated @value{UPDATED}, -of @cite{The GNU Bash Reference Manual}, -for @code{Bash}, Version @value{VERSION}. - -Bash contains features that appear in other popular shells, and some -features that only appear in Bash. Some of the shells that Bash has -borrowed concepts from are the Bourne Shell (@file{sh}), the Korn Shell -(@file{ksh}), and the C-shell (@file{csh} and its successor, -@file{tcsh}). The following menu breaks the features up into -categories, noting which features were inspired by other shells and -which are specific to Bash. - -This manual is meant as a brief introduction to features found in -Bash. The Bash manual page should be used as the definitive -reference on shell behavior. - -@menu -* Introduction:: An introduction to the shell. -* Definitions:: Some definitions used in the rest of this - manual. -* Basic Shell Features:: The shell "building blocks". -* Shell Builtin Commands:: Commands that are a part of the shell. -* Shell Variables:: Variables used or set by Bash. -* Bash Features:: Features found only in Bash. -* Job Control:: What job control is and how Bash allows you - to use it. -* Command Line Editing:: Chapter describing the command line - editing features. -* Using History Interactively:: Command History Expansion -* Installing Bash:: How to build and install Bash on your system. -* Reporting Bugs:: How to report bugs in Bash. -* Major Differences From The Bourne Shell:: A terse list of the differences - between Bash and historical - versions of /bin/sh. -* GNU Free Documentation License:: Copying and sharing this documentation. -* Indexes:: Various indexes for this manual. -@end menu -@end ifnottex - -@node Introduction -@chapter Introduction -@menu -* What is Bash?:: A short description of Bash. -* What is a shell?:: A brief introduction to shells. -@end menu - -@node What is Bash? -@section What is Bash? - -Bash is the shell, or command language interpreter, -for the @sc{gnu} operating system. -The name is an acronym for the @samp{Bourne-Again SHell}, -a pun on Stephen Bourne, the author of the direct ancestor of -the current Unix shell @code{sh}, -which appeared in the Seventh Edition Bell Labs Research version -of Unix. - -Bash is largely compatible with @code{sh} and incorporates useful -features from the Korn shell @code{ksh} and the C shell @code{csh}. -It is intended to be a conformant implementation of the @sc{ieee} -@sc{posix} Shell and Tools portion of the @sc{ieee} @sc{posix} -specification (@sc{ieee} Standard 1003.1). -It offers functional improvements over @code{sh} for both interactive and -programming use. - -While the @sc{gnu} operating system provides other shells, including -a version of @code{csh}, Bash is the default shell. -Like other @sc{gnu} software, Bash is quite portable. It currently runs -on nearly every version of Unix and a few other operating systems @minus{} -independently-supported ports exist for @sc{ms-dos}, @sc{os/2}, -and Windows platforms. - -@node What is a shell? -@section What is a shell? - -At its base, a shell is simply a macro processor that executes -commands. The term macro processor means functionality where text -and symbols are expanded to create larger expressions. - -A Unix shell is both a command interpreter and a programming -language. As a command interpreter, the shell provides the user -interface to the rich set of @sc{gnu} utilities. The programming -language features allow these utilities to be combined. -Files containing commands can be created, and become -commands themselves. These new commands have the same status as -system commands in directories such as @file{/bin}, allowing users -or groups to establish custom environments to automate their common -tasks. - -Shells may be used interactively or non-interactively. In -interactive mode, they accept input typed from the keyboard. -When executing non-interactively, shells execute commands read -from a file. - -A shell allows execution of @sc{gnu} commands, both synchronously and -asynchronously. -The shell waits for synchronous commands to complete before accepting -more input; asynchronous commands continue to execute in parallel -with the shell while it reads and executes additional commands. -The @dfn{redirection} constructs permit -fine-grained control of the input and output of those commands. -Moreover, the shell allows control over the contents of commands' -environments. - -Shells also provide a small set of built-in -commands (@dfn{builtins}) implementing functionality impossible -or inconvenient to obtain via separate utilities. -For example, @code{cd}, @code{break}, @code{continue}, and -@code{exec} cannot be implemented outside of the shell because -they directly manipulate the shell itself. -The @code{history}, @code{getopts}, @code{kill}, or @code{pwd} -builtins, among others, could be implemented in separate utilities, -but they are more convenient to use as builtin commands. -All of the shell builtins are described in -subsequent sections. - -While executing commands is essential, most of the power (and -complexity) of shells is due to their embedded programming -languages. Like any high-level language, the shell provides -variables, flow control constructs, quoting, and functions. - -Shells offer features geared specifically for -interactive use rather than to augment the programming language. -These interactive features include job control, command line -editing, command history and aliases. Each of these features is -described in this manual. - -@node Definitions -@chapter Definitions -These definitions are used throughout the remainder of this manual. - -@table @code - -@item POSIX -@cindex POSIX -A family of open system standards based on Unix. Bash -is primarily concerned with the Shell and Utilities portion of the -@sc{posix} 1003.1 standard. - -@item blank -A space or tab character. - -@item builtin -@cindex builtin -A command that is implemented internally by the shell itself, rather -than by an executable program somewhere in the file system. - -@item control operator -@cindex control operator -A @code{token} that performs a control function. It is a @code{newline} -or one of the following: -@samp{||}, @samp{&&}, @samp{&}, @samp{;}, @samp{;;}, -@samp{|}, @samp{|&}, @samp{(}, or @samp{)}. - -@item exit status -@cindex exit status -The value returned by a command to its caller. The value is restricted -to eight bits, so the maximum value is 255. - -@item field -@cindex field -A unit of text that is the result of one of the shell expansions. After -expansion, when executing a command, the resulting fields are used as -the command name and arguments. - -@item filename -@cindex filename -A string of characters used to identify a file. - -@item job -@cindex job -A set of processes comprising a pipeline, and any processes descended -from it, that are all in the same process group. - -@item job control -@cindex job control -A mechanism by which users can selectively stop (suspend) and restart -(resume) execution of processes. - -@item metacharacter -@cindex metacharacter -A character that, when unquoted, separates words. A metacharacter is -a @code{blank} or one of the following characters: -@samp{|}, @samp{&}, @samp{;}, @samp{(}, @samp{)}, @samp{<}, or -@samp{>}. - -@item name -@cindex name -@cindex identifier -A @code{word} consisting solely of letters, numbers, and underscores, -and beginning with a letter or underscore. @code{Name}s are used as -shell variable and function names. -Also referred to as an @code{identifier}. - -@item operator -@cindex operator, shell -A @code{control operator} or a @code{redirection operator}. -@xref{Redirections}, for a list of redirection operators. -Operators contain at least one unquoted @code{metacharacter}. - -@item process group -@cindex process group -A collection of related processes each having the same process -group @sc{id}. - -@item process group ID -@cindex process group ID -A unique identifier that represents a @code{process group} -during its lifetime. - -@item reserved word -@cindex reserved word -A @code{word} that has a special meaning to the shell. Most reserved -words introduce shell flow control constructs, such as @code{for} and -@code{while}. - -@item return status -@cindex return status -A synonym for @code{exit status}. - -@item signal -@cindex signal -A mechanism by which a process may be notified by the kernel -of an event occurring in the system. - -@item special builtin -@cindex special builtin -A shell builtin command that has been classified as special by the -@sc{posix} standard. - -@item token -@cindex token -A sequence of characters considered a single unit by the shell. -It is either a @code{word} or an @code{operator}. - -@item word -@cindex word -A sequence of characters treated as a unit by the shell. -Words may not include unquoted @code{metacharacters}. -@end table - -@node Basic Shell Features -@chapter Basic Shell Features -@cindex Bourne shell - -Bash is an acronym for @samp{Bourne-Again SHell}. -The Bourne shell is -the traditional Unix shell originally written by Stephen Bourne. -All of the Bourne shell builtin commands are available in Bash, -The rules for evaluation and quoting are taken from the @sc{posix} -specification for the `standard' Unix shell. - -This chapter briefly summarizes the shell's `building blocks': -commands, control structures, shell functions, shell @i{parameters}, -shell expansions, -@i{redirections}, which are a way to direct input and output from -and to named files, and how the shell executes commands. - -@menu -* Shell Syntax:: What your input means to the shell. -* Shell Commands:: The types of commands you can use. -* Shell Functions:: Grouping commands by name. -* Shell Parameters:: How the shell stores values. -* Shell Expansions:: How Bash expands parameters and the various - expansions available. -* Redirections:: A way to control where input and output go. -* Executing Commands:: What happens when you run a command. -* Shell Scripts:: Executing files of shell commands. -@end menu - -@node Shell Syntax -@section Shell Syntax -@menu -* Shell Operation:: The basic operation of the shell. -* Quoting:: How to remove the special meaning from characters. -* Comments:: How to specify comments. -@end menu - -When the shell reads input, it proceeds through a -sequence of operations. If the input indicates the beginning of a -comment, the shell ignores the comment symbol (@samp{#}), and the rest -of that line. - -Otherwise, roughly speaking, the shell reads its input and -divides the input into words and operators, employing the quoting rules -to select which meanings to assign various words and characters. - -The shell then parses these tokens into commands and other constructs, -removes the special meaning of certain words or characters, expands -others, redirects input and output as needed, executes the specified -command, waits for the command's exit status, and makes that exit status -available for further inspection or processing. - -@node Shell Operation -@subsection Shell Operation - -The following is a brief description of the shell's operation when it -reads and executes a command. Basically, the shell does the -following: - -@enumerate -@item -Reads its input from a file (@pxref{Shell Scripts}), from a string -supplied as an argument to the @option{-c} invocation option -(@pxref{Invoking Bash}), or from the user's terminal. - -@item -Breaks the input into words and operators, obeying the quoting rules -described in @ref{Quoting}. These tokens are separated by -@code{metacharacters}. Alias expansion is performed by this step -(@pxref{Aliases}). - -@item -Parses the tokens into simple and compound commands -(@pxref{Shell Commands}). - -@item -Performs the various shell expansions (@pxref{Shell Expansions}), breaking -the expanded tokens into lists of filenames (@pxref{Filename Expansion}) -and commands and arguments. - -@item -Performs any necessary redirections (@pxref{Redirections}) and removes -the redirection operators and their operands from the argument list. - -@item -Executes the command (@pxref{Executing Commands}). - -@item -Optionally waits for the command to complete and collects its exit -status (@pxref{Exit Status}). - -@end enumerate - -@node Quoting -@subsection Quoting -@cindex quoting -@menu -* Escape Character:: How to remove the special meaning from a single - character. -* Single Quotes:: How to inhibit all interpretation of a sequence - of characters. -* Double Quotes:: How to suppress most of the interpretation of a - sequence of characters. -* ANSI-C Quoting:: How to expand ANSI-C sequences in quoted strings. -* Locale Translation:: How to translate strings into different languages. -@end menu - -Quoting is used to remove the special meaning of certain -characters or words to the shell. Quoting can be used to -disable special treatment for special characters, to prevent -reserved words from being recognized as such, and to prevent -parameter expansion. - -Each of the shell metacharacters (@pxref{Definitions}) -has special meaning to the shell and must be quoted if it is to -represent itself. -When the command history expansion facilities are being used -(@pxref{History Interaction}), the -@var{history expansion} character, usually @samp{!}, must be quoted -to prevent history expansion. @xref{Bash History Facilities}, for -more details concerning history expansion. - -There are three quoting mechanisms: the -@var{escape character}, single quotes, and double quotes. - -@node Escape Character -@subsubsection Escape Character -A non-quoted backslash @samp{\} is the Bash escape character. -It preserves the literal value of the next character that follows, -with the exception of @code{newline}. If a @code{\newline} pair -appears, and the backslash itself is not quoted, the @code{\newline} -is treated as a line continuation (that is, it is removed from -the input stream and effectively ignored). - -@node Single Quotes -@subsubsection Single Quotes - -Enclosing characters in single quotes (@samp{'}) preserves the literal value -of each character within the quotes. A single quote may not occur -between single quotes, even when preceded by a backslash. - -@node Double Quotes -@subsubsection Double Quotes - -Enclosing characters in double quotes (@samp{"}) preserves the literal value -of all characters within the quotes, with the exception of -@samp{$}, @samp{`}, @samp{\}, -and, when history expansion is enabled, @samp{!}. -The characters @samp{$} and @samp{`} -retain their special meaning within double quotes (@pxref{Shell Expansions}). -The backslash retains its special meaning only when followed by one of -the following characters: -@samp{$}, @samp{`}, @samp{"}, @samp{\}, or @code{newline}. -Within double quotes, backslashes that are followed by one of these -characters are removed. Backslashes preceding characters without a -special meaning are left unmodified. -A double quote may be quoted within double quotes by preceding it with -a backslash. -If enabled, history expansion will be performed unless an @samp{!} -appearing in double quotes is escaped using a backslash. -The backslash preceding the @samp{!} is not removed. - -The special parameters @samp{*} and @samp{@@} have special meaning -when in double quotes (@pxref{Shell Parameter Expansion}). - -@node ANSI-C Quoting -@subsubsection ANSI-C Quoting -@cindex quoting, ANSI - -Words of the form @code{$'@var{string}'} are treated specially. The -word expands to @var{string}, with backslash-escaped characters replaced -as specified by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: - -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \e -@itemx \E -an escape character (not ANSI C) -@item \f -form feed -@item \n -newline -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \' -single quote -@item \" -double quote -@item \@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(one to three digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@item \u@var{HHHH} -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -@var{HHHH} (one to four hex digits) -@item \U@var{HHHHHHHH} -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -@var{HHHHHHHH} (one to eight hex digits) -@item \c@var{x} -a control-@var{x} character -@end table - -@noindent -The expanded result is single-quoted, as if the dollar sign had not -been present. - -@node Locale Translation -@subsubsection Locale-Specific Translation -@cindex localization -@cindex internationalization -@cindex native languages -@cindex translation, native languages - -A double-quoted string preceded by a dollar sign (@samp{$}) will cause -the string to be translated according to the current locale. -If the current locale is @code{C} or @code{POSIX}, the dollar sign -is ignored. -If the string is translated and replaced, the replacement is -double-quoted. - -@vindex LC_MESSAGES -@vindex TEXTDOMAIN -@vindex TEXTDOMAINDIR -Some systems use the message catalog selected by the @env{LC_MESSAGES} -shell variable. Others create the name of the message catalog from the -value of the @env{TEXTDOMAIN} shell variable, possibly adding a -suffix of @samp{.mo}. If you use the @env{TEXTDOMAIN} variable, you -may need to set the @env{TEXTDOMAINDIR} variable to the location of -the message catalog files. Still others use both variables in this -fashion: -@env{TEXTDOMAINDIR}/@env{LC_MESSAGES}/LC_MESSAGES/@env{TEXTDOMAIN}.mo. - -@node Comments -@subsection Comments -@cindex comments, shell - -In a non-interactive shell, or an interactive shell in which the -@code{interactive_comments} option to the @code{shopt} -builtin is enabled (@pxref{The Shopt Builtin}), -a word beginning with @samp{#} -causes that word and all remaining characters on that line to -be ignored. An interactive shell without the @code{interactive_comments} -option enabled does not allow comments. The @code{interactive_comments} -option is on by default in interactive shells. -@xref{Interactive Shells}, for a description of what makes -a shell interactive. - -@node Shell Commands -@section Shell Commands -@cindex commands, shell - -A simple shell command such as @code{echo a b c} consists of the command -itself followed by arguments, separated by spaces. - -More complex shell commands are composed of simple commands arranged together -in a variety of ways: in a pipeline in which the output of one command -becomes the input of a second, in a loop or conditional construct, or in -some other grouping. - -@menu -* Simple Commands:: The most common type of command. -* Pipelines:: Connecting the input and output of several - commands. -* Lists:: How to execute commands sequentially. -* Compound Commands:: Shell commands for control flow. -* Coprocesses:: Two-way communication between commands. -* GNU Parallel:: Running commands in parallel. -@end menu - -@node Simple Commands -@subsection Simple Commands -@cindex commands, simple - -A simple command is the kind of command encountered most often. -It's just a sequence of words separated by @code{blank}s, terminated -by one of the shell's control operators (@pxref{Definitions}). The -first word generally specifies a command to be executed, with the -rest of the words being that command's arguments. - -The return status (@pxref{Exit Status}) of a simple command is -its exit status as provided -by the @sc{posix} 1003.1 @code{waitpid} function, or 128+@var{n} if -the command was terminated by signal @var{n}. - -@node Pipelines -@subsection Pipelines -@cindex pipeline -@cindex commands, pipelines - -A @code{pipeline} is a sequence of simple commands separated by one of -the control operators @samp{|} or @samp{|&}. - -@rwindex time -@rwindex ! -@cindex command timing -The format for a pipeline is -@example -[time [-p]] [!] @var{command1} [ | or |& @var{command2} ] @dots{} -@end example - -@noindent -The output of each command in the pipeline is connected via a pipe -to the input of the next command. -That is, each command reads the previous command's output. This -connection is performed before any redirections specified by the -command. - -If @samp{|&} is used, @var{command1}'s standard output and standard error -are connected to -@var{command2}'s standard input through the pipe; -it is shorthand for @code{2>&1 |}. -This implicit redirection of the standard error is -performed after any redirections specified by the command. - -The reserved word @code{time} causes timing statistics -to be printed for the pipeline once it finishes. -The statistics currently consist of elapsed (wall-clock) time and -user and system time consumed by the command's execution. -The @option{-p} option changes the output format to that specified -by @sc{posix}. -When the shell is in @sc{posix} mode (@pxref{Bash POSIX Mode}), -it does not recognize @code{time} as a reserved word if the next -token begins with a @samp{-}. -The @env{TIMEFORMAT} variable may be set to a format string that -specifies how the timing information should be displayed. -@xref{Bash Variables}, for a description of the available formats. -The use of @code{time} as a reserved word permits the timing of -shell builtins, shell functions, and pipelines. An external -@code{time} command cannot time these easily. - -When the shell is in @sc{posix} mode (@pxref{Bash POSIX Mode}), @code{time} -may be followed by a newline. In this case, the shell displays the -total user and system time consumed by the shell and its children. -The @env{TIMEFORMAT} variable may be used to specify the format of -the time information. - -If the pipeline is not executed asynchronously (@pxref{Lists}), the -shell waits for all commands in the pipeline to complete. - -Each command in a pipeline is executed in its own subshell -(@pxref{Command Execution Environment}). The exit -status of a pipeline is the exit status of the last command in the -pipeline, unless the @code{pipefail} option is enabled -(@pxref{The Set Builtin}). -If @code{pipefail} is enabled, the pipeline's return status is the -value of the last (rightmost) command to exit with a non-zero status, -or zero if all commands exit successfully. -If the reserved word @samp{!} precedes the pipeline, the -exit status is the logical negation of the exit status as described -above. -The shell waits for all commands in the pipeline to terminate before -returning a value. - -@node Lists -@subsection Lists of Commands -@cindex commands, lists - -A @code{list} is a sequence of one or more pipelines separated by one -of the operators @samp{;}, @samp{&}, @samp{&&}, or @samp{||}, -and optionally terminated by one of @samp{;}, @samp{&}, or a -@code{newline}. - -Of these list operators, @samp{&&} and @samp{||} -have equal precedence, followed by @samp{;} and @samp{&}, -which have equal precedence. - -A sequence of one or more newlines may appear in a @code{list} -to delimit commands, equivalent to a semicolon. - -If a command is terminated by the control operator @samp{&}, -the shell executes the command asynchronously in a subshell. -This is known as executing the command in the @var{background}. -The shell does not wait for the command to finish, and the return -status is 0 (true). -When job control is not active (@pxref{Job Control}), -the standard input for asynchronous commands, in the absence of any -explicit redirections, is redirected from @code{/dev/null}. - -Commands separated by a @samp{;} are executed sequentially; the shell -waits for each command to terminate in turn. The return status is the -exit status of the last command executed. - -@sc{and} and @sc{or} lists are sequences of one or more pipelines -separated by the control operators @samp{&&} and @samp{||}, -respectively. @sc{and} and @sc{or} lists are executed with left -associativity. - -An @sc{and} list has the form -@example -@var{command1} && @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns an exit status of zero. - -An @sc{or} list has the form -@example -@var{command1} || @var{command2} -@end example - -@noindent -@var{command2} is executed if, and only if, @var{command1} -returns a non-zero exit status. - -The return status of -@sc{and} and @sc{or} lists is the exit status of the last command -executed in the list. - -@node Compound Commands -@subsection Compound Commands -@cindex commands, compound - -@menu -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Command Grouping:: Ways to group commands. -@end menu - -Compound commands are the shell programming constructs. -Each construct begins with a reserved word or control operator and is -terminated by a corresponding reserved word or operator. -Any redirections (@pxref{Redirections}) associated with a compound command -apply to all commands within that compound command unless explicitly overridden. - -In most cases a list of commands in a compound command's description may be -separated from the rest of the command by one or more newlines, and may be -followed by a newline in place of a semicolon. - -Bash provides looping constructs, conditional commands, and mechanisms -to group commands and execute them as a unit. - -@node Looping Constructs -@subsubsection Looping Constructs -@cindex commands, looping - -Bash supports the following looping constructs. - -Note that wherever a @samp{;} appears in the description of a -command's syntax, it may be replaced with one or more newlines. - -@table @code -@item until -@rwindex until -@rwindex do -@rwindex done -The syntax of the @code{until} command is: - -@example -until @var{test-commands}; do @var{consequent-commands}; done -@end example - -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status which is not zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item while -@rwindex while -The syntax of the @code{while} command is: - -@example -while @var{test-commands}; do @var{consequent-commands}; done -@end example - -Execute @var{consequent-commands} as long as -@var{test-commands} has an exit status of zero. -The return status is the exit status of the last command executed -in @var{consequent-commands}, or zero if none was executed. - -@item for -@rwindex for -The syntax of the @code{for} command is: - -@example -for @var{name} [ [in [@var{words} @dots{}] ] ; ] do @var{commands}; done -@end example - -Expand @var{words}, and execute @var{commands} once for each member -in the resultant list, with @var{name} bound to the current member. -If @samp{in @var{words}} is not present, the @code{for} command -executes the @var{commands} once for each positional parameter that is -set, as if @samp{in "$@@"} had been specified -(@pxref{Special Parameters}). -The return status is the exit status of the last command that executes. -If there are no items in the expansion of @var{words}, no commands are -executed, and the return status is zero. - -An alternate form of the @code{for} command is also supported: - -@example -for (( @var{expr1} ; @var{expr2} ; @var{expr3} )) ; do @var{commands} ; done -@end example - -First, the arithmetic expression @var{expr1} is evaluated according -to the rules described below (@pxref{Shell Arithmetic}). -The arithmetic expression @var{expr2} is then evaluated repeatedly -until it evaluates to zero. -Each time @var{expr2} evaluates to a non-zero value, @var{commands} are -executed and the arithmetic expression @var{expr3} is evaluated. -If any expression is omitted, it behaves as if it evaluates to 1. -The return value is the exit status of the last command in @var{commands} -that is executed, or false if any of the expressions is invalid. -@end table - -The @code{break} and @code{continue} builtins (@pxref{Bourne Shell Builtins}) -may be used to control loop execution. - -@node Conditional Constructs -@subsubsection Conditional Constructs -@cindex commands, conditional - -@table @code -@item if -@rwindex if -@rwindex then -@rwindex else -@rwindex elif -@rwindex fi -The syntax of the @code{if} command is: - -@example -if @var{test-commands}; then - @var{consequent-commands}; -[elif @var{more-test-commands}; then - @var{more-consequents};] -[else @var{alternate-consequents};] -fi -@end example - -The @var{test-commands} list is executed, and if its return status is zero, -the @var{consequent-commands} list is executed. -If @var{test-commands} returns a non-zero status, each @code{elif} list -is executed in turn, and if its exit status is zero, -the corresponding @var{more-consequents} is executed and the -command completes. -If @samp{else @var{alternate-consequents}} is present, and -the final command in the final @code{if} or @code{elif} clause -has a non-zero exit status, then @var{alternate-consequents} is executed. -The return status is the exit status of the last command executed, or -zero if no condition tested true. - -@item case -@rwindex case -@rwindex in -@rwindex esac -The syntax of the @code{case} command is: - -@example -case @var{word} in [ [(] @var{pattern} [| @var{pattern}]@dots{}) @var{command-list} ;;]@dots{} esac -@end example - -@code{case} will selectively execute the @var{command-list} corresponding to -the first @var{pattern} that matches @var{word}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -The @samp{|} is used to separate multiple patterns, and the @samp{)} -operator terminates a pattern list. -A list of patterns and an associated command-list is known -as a @var{clause}. - -Each clause must be terminated with @samp{;;}, @samp{;&}, or @samp{;;&}. -The @var{word} undergoes tilde expansion, parameter expansion, command -substitution, arithmetic expansion, and quote removal before matching is -attempted. Each @var{pattern} undergoes tilde expansion, parameter -expansion, command substitution, and arithmetic expansion. - -There may be an arbitrary number of @code{case} clauses, each terminated -by a @samp{;;}, @samp{;&}, or @samp{;;&}. -The first pattern that matches determines the -command-list that is executed. -It's a common idiom to use @samp{*} as the final pattern to define the -default case, since that pattern will always match. - -Here is an example using @code{case} in a script that could be used to -describe one interesting feature of an animal: - -@example -echo -n "Enter the name of an animal: " -read ANIMAL -echo -n "The $ANIMAL has " -case $ANIMAL in - horse | dog | cat) echo -n "four";; - man | kangaroo ) echo -n "two";; - *) echo -n "an unknown number of";; -esac -echo " legs." -@end example - -@noindent - -If the @samp{;;} operator is used, no subsequent matches are attempted after -the first pattern match. -Using @samp{;&} in place of @samp{;;} causes execution to continue with -the @var{command-list} associated with the next clause, if any. -Using @samp{;;&} in place of @samp{;;} causes the shell to test the patterns -in the next clause, if any, and execute any associated @var{command-list} -on a successful match. - -The return status is zero if no @var{pattern} is matched. Otherwise, the -return status is the exit status of the @var{command-list} executed. - -@item select -@rwindex select - -The @code{select} construct allows the easy generation of menus. -It has almost the same syntax as the @code{for} command: - -@example -select @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example - -The list of words following @code{in} is expanded, generating a list -of items. The set of expanded words is printed on the standard -error output stream, each preceded by a number. If the -@samp{in @var{words}} is omitted, the positional parameters are printed, -as if @samp{in "$@@"} had been specified. -The @env{PS3} prompt is then displayed and a line is read from the -standard input. -If the line consists of a number corresponding to one of the displayed -words, then the value of @var{name} is set to that word. -If the line is empty, the words and prompt are displayed again. -If @code{EOF} is read, the @code{select} command completes. -Any other value read causes @var{name} to be set to null. -The line read is saved in the variable @env{REPLY}. - -The @var{commands} are executed after each selection until a -@code{break} command is executed, at which -point the @code{select} command completes. - -Here is an example that allows the user to pick a filename from the -current directory, and displays the name and index of the file -selected. - -@example -select fname in *; -do - echo you picked $fname \($REPLY\) - break; -done -@end example - -@item ((@dots{})) -@example -(( @var{expression} )) -@end example - -The arithmetic @var{expression} is evaluated according to the rules -described below (@pxref{Shell Arithmetic}). -If the value of the expression is non-zero, the return status is 0; -otherwise the return status is 1. This is exactly equivalent to -@example -let "@var{expression}" -@end example -@noindent -@xref{Bash Builtins}, for a full description of the @code{let} builtin. - -@item [[@dots{}]] -@rwindex [[ -@rwindex ]] -@example -[[ @var{expression} ]] -@end example - -Return a status of 0 or 1 depending on the evaluation of -the conditional expression @var{expression}. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. -Word splitting and filename expansion are not performed on the words -between the @samp{[[} and @samp{]]}; tilde expansion, parameter and -variable expansion, arithmetic expansion, command substitution, process -substitution, and quote removal are performed. -Conditional operators such as @samp{-f} must be unquoted to be recognized -as primaries. - -When used with @samp{[[}, the @samp{<} and @samp{>} operators sort -lexicographically using the current locale. - -When the @samp{==} and @samp{!=} operators are used, the string to the -right of the operator is considered a pattern and matched according -to the rules described below in @ref{Pattern Matching}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (@samp{==}) or does not -match (@samp{!=})the pattern, and 1 otherwise. -Any part of the pattern may be quoted to force the quoted portion -to be matched as a string. - -An additional binary operator, @samp{=~}, is available, with the same -precedence as @samp{==} and @samp{!=}. -When it is used, the string to the right of the operator is considered -an extended regular expression and matched accordingly (as in @i{regex}3)). -The return value is 0 if the string matches -the pattern, and 1 otherwise. -If the regular expression is syntactically incorrect, the conditional -expression's return value is 2. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -Any part of the pattern may be quoted to force the quoted portion -to be matched as a string. -Bracket expressions in regular expressions must be treated carefully, -since normal quoting characters lose their meanings between brackets. -If the pattern is stored in a shell variable, quoting the variable -expansion forces the entire pattern to be matched as a string. -Substrings matched by parenthesized subexpressions within the regular -expression are saved in the array variable @code{BASH_REMATCH}. -The element of @code{BASH_REMATCH} with index 0 is the portion of the string -matching the entire regular expression. -The element of @code{BASH_REMATCH} with index @var{n} is the portion of the -string matching the @var{n}th parenthesized subexpression. - -For example, the following will match a line -(stored in the shell variable @var{line}) -if there is a sequence of characters in the value consisting of -any number, including zero, of -space characters, zero or one instances of @samp{a}, then a @samp{b}: -@example -[[ $line =~ [[:space:]]*(a)?b ]] -@end example - -@noindent -That means values like @samp{aab} and @samp{ aaaaaab} will match, as -will a line containing a @samp{b} anywhere in its value. - -Storing the regular expression in a shell variable is often a useful -way to avoid problems with quoting characters that are special to the -shell. -It is sometimes difficult to specify a regular expression literally -without using quotes, or to keep track of the quoting used by regular -expressions while paying attention to the shell's quote removal. -Using a shell variable to store the pattern decreases these problems. -For example, the following is equivalent to the above: -@example -pattern='[[:space:]]*(a)?b' -[[ $line =~ $pattern ]] -@end example - -@noindent -If you want to match a character that's special to the regular expression -grammar, it has to be quoted to remove its special meaning. -This means that in the pattern @samp{xxx.txt}, the @samp{.} matches any -character in the string (its usual regular expression meaning), but in the -pattern @samp{"xxx.txt"} it can only match a literal @samp{.}. -Shell programmers should take special care with backslashes, since backslashes -are used both by the shell and regular expressions to remove the special -meaning from the following character. -The following two sets of commands are @emph{not} equivalent: -@example -pattern='\.' - -[[ . =~ $pattern ]] -[[ . =~ \. ]] - -[[ . =~ "$pattern" ]] -[[ . =~ '\.' ]] -@end example - -@noindent -The first two matches will succeed, but the second two will not, because -in the second two the backslash will be part of the pattern to be matched. -In the first two examples, the backslash removes the special meaning from -@samp{.}, so the literal @samp{.} matches. -If the string in the first examples were anything other than @samp{.}, say -@samp{a}, the pattern would not match, because the quoted @samp{.} in the -pattern loses its special meaning of matching any single character. - -Expressions may be combined using the following operators, listed -in decreasing order of precedence: - -@table @code -@item ( @var{expression} ) -Returns the value of @var{expression}. -This may be used to override the normal precedence of operators. - -@item ! @var{expression} -True if @var{expression} is false. - -@item @var{expression1} && @var{expression2} -True if both @var{expression1} and @var{expression2} are true. - -@item @var{expression1} || @var{expression2} -True if either @var{expression1} or @var{expression2} is true. -@end table - -@noindent -The @code{&&} and @code{||} operators do not evaluate @var{expression2} if the -value of @var{expression1} is sufficient to determine the return -value of the entire conditional expression. -@end table - -@node Command Grouping -@subsubsection Grouping Commands -@cindex commands, grouping - -Bash provides two ways to group a list of commands to be executed -as a unit. When commands are grouped, redirections may be applied -to the entire command list. For example, the output of all the -commands in the list may be redirected to a single stream. - -@table @code -@item () -@example -( @var{list} ) -@end example - -Placing a list of commands between parentheses causes a subshell -environment to be created (@pxref{Command Execution Environment}), and each -of the commands in @var{list} to be executed in that subshell. Since the -@var{list} is executed in a subshell, variable assignments do not remain in -effect after the subshell completes. - -@item @{@} -@rwindex @{ -@rwindex @} -@example -@{ @var{list}; @} -@end example - -Placing a list of commands between curly braces causes the list to -be executed in the current shell context. No subshell is created. -The semicolon (or newline) following @var{list} is required. -@end table - -In addition to the creation of a subshell, there is a subtle difference -between these two constructs due to historical reasons. The braces -are @code{reserved words}, so they must be separated from the @var{list} -by @code{blank}s or other shell metacharacters. -The parentheses are @code{operators}, and are -recognized as separate tokens by the shell even if they are not separated -from the @var{list} by whitespace. - -The exit status of both of these constructs is the exit status of -@var{list}. - -@node Coprocesses -@subsection Coprocesses -@cindex coprocess - -A @code{coprocess} is a shell command preceded by the @code{coproc} -reserved word. -A coprocess is executed asynchronously in a subshell, as if the command -had been terminated with the @samp{&} control operator, with a two-way pipe -established between the executing shell and the coprocess. - -The format for a coprocess is: -@example -coproc [@var{NAME}] @var{command} [@var{redirections}] -@end example - -@noindent -This creates a coprocess named @var{NAME}. -If @var{NAME} is not supplied, the default name is @var{COPROC}. -@var{NAME} must not be supplied if @var{command} is a simple -command (@pxref{Simple Commands}); otherwise, it is interpreted as -the first word of the simple command. - -When the coprocess is executed, the shell creates an array variable -(@pxref{Arrays}) -named @env{NAME} in the context of the executing shell. -The standard output of @var{command} -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to @env{NAME}[0]. -The standard input of @var{command} -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to @env{NAME}[1]. -This pipe is established before any redirections specified by the -command (@pxref{Redirections}). -The file descriptors can be utilized as arguments to shell commands -and redirections using standard word expansions. -The file descriptors are not available in subshells. - -The process ID of the shell spawned to execute the coprocess is -available as the value of the variable @env{NAME}_PID. -The @code{wait} -builtin command may be used to wait for the coprocess to terminate. - -The return status of a coprocess is the exit status of @var{command}. - -@node GNU Parallel -@subsection GNU Parallel - -GNU Parallel, as its name suggests, can be used to build and run commands -in parallel. You may run the same command with different arguments, whether -they are filenames, usernames, hostnames, or lines read from files. - -For a complete description, refer to the GNU Parallel documentation. A few -examples should provide a brief introduction to its use. - -For example, it is easy to prefix each line in a text file with a specified -string: -@example -cat file | parallel -k echo prefix_string -@end example -@noindent -The @option{-k} option is required to preserve the lines' order. - -Similarly, you can append a specified string to each line in a text file: -@example -cat file | parallel -k echo @{@} append_string -@end example - -You can use Parallel to move files from the current directory when the -number of files is too large to process with one @code{mv} invocation: -@example -ls | parallel mv @{@} destdir -@end example - -As you can see, the @{@} is replaced with each line read from standard input. -This will run as many @code{mv} commands as there are files in the current -directory. You can emulate a parallel @code{xargs} by adding the @option{-X} -option: -@example -ls | parallel -X mv @{@} destdir -@end example - -GNU Parallel can replace certain common idioms that operate on lines read -from a file (in this case, filenames): -@example - for x in $(cat list); do - do-something1 $x config-$x - do-something2 < $x - done | process-output -@end example - -@noindent -with a more compact syntax reminiscent of lambdas: -@example -cat list | parallel "do-something1 @{@} config-@{@} ; do-something2 < @{@}" | process-output -@end example - -Parallel provides a built-in mechanism to remove filename extensions, which -lends itself to batch file transformations or renaming: -@example -ls *.gz | parallel -j+0 "zcat @{@} | bzip2 >@{.@}.bz2 && rm @{@}" -@end example -@noindent -This will recompress all files in the current directory with names ending -in .gz using bzip2, running one job per CPU (-j+0) in parallel. - -If a command generates output, you may want to preserve the input order in -the output. For instance, the following command -@example -@{ echo foss.org.my ; echo debian.org; echo freenetproject.org; @} | parallel traceroute -@end example -@noindent -will display as output the traceroute invocation that finishes first. Using -the @option{-k} option, as we saw above -@example -@{ echo foss.org.my ; echo debian.org; echo freenetproject.org; @} | parallel -k traceroute -@end example -@noindent -will ensure that the output of @code{traceroute foss.org.my} is displayed first. - -@node Shell Functions -@section Shell Functions -@cindex shell function -@cindex functions, shell - -Shell functions are a way to group commands for later execution -using a single name for the group. They are executed just like -a "regular" command. -When the name of a shell function is used as a simple command name, -the list of commands associated with that function name is executed. -Shell functions are executed in the current -shell context; no new process is created to interpret them. - -Functions are declared using this syntax: -@rwindex function -@example -@var{name} () @var{compound-command} [ @var{redirections} ] -@end example - -or - -@example -function @var{name} [()] @var{compound-command} [ @var{redirections} ] -@end example - -This defines a shell function named @var{name}. The reserved -word @code{function} is optional. -If the @code{function} reserved -word is supplied, the parentheses are optional. -The @var{body} of the function is the compound command -@var{compound-command} (@pxref{Compound Commands}). -That command is usually a @var{list} enclosed between @{ and @}, but -may be any compound command listed above. -@var{compound-command} is executed whenever @var{name} is specified as the -name of a command. -When the shell is in @sc{posix} mode (@pxref{Bash POSIX Mode}), -@var{name} may not be the same as one of the special builtins -(@pxref{Special Builtins}). -Any redirections (@pxref{Redirections}) associated with the shell function -are performed when the function is executed. - -A function definition may be deleted using the @option{-f} option to the -@code{unset} builtin (@pxref{Bourne Shell Builtins}). - -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -last command executed in the body. - -Note that for historical reasons, in the most common usage the curly braces -that surround the body of the function must be separated from the body by -@code{blank}s or newlines. -This is because the braces are reserved words and are only recognized -as such when they are separated from the command list -by whitespace or another shell metacharacter. -Also, when using the braces, the @var{list} must be terminated by a semicolon, -a @samp{&}, or a newline. - -When a function is executed, the arguments to the -function become the positional parameters -during its execution (@pxref{Positional Parameters}). -The special parameter @samp{#} that expands to the number of -positional parameters is updated to reflect the change. -Special parameter @code{0} is unchanged. -The first element of the @env{FUNCNAME} variable is set to the -name of the function while the function is executing. - -All other aspects of the shell execution -environment are identical between a function and its caller -with these exceptions: -the @env{DEBUG} and @env{RETURN} traps -are not inherited unless the function has been given the -@code{trace} attribute using the @code{declare} builtin or -the @code{-o functrace} option has been enabled with -the @code{set} builtin, -(in which case all functions inherit the @env{DEBUG} and @env{RETURN} traps), -and the @env{ERR} trap is not inherited unless the @code{-o errtrace} -shell option has been enabled. -@xref{Bourne Shell Builtins}, for the description of the -@code{trap} builtin. - -The @env{FUNCNEST} variable, if set to a numeric value greater -than 0, defines a maximum function nesting level. Function -invocations that exceed the limit cause the entire command to -abort. - -If the builtin command @code{return} -is executed in a function, the function completes and -execution resumes with the next command after the function -call. -Any command associated with the @code{RETURN} trap is executed -before execution resumes. -When a function completes, the values of the -positional parameters and the special parameter @samp{#} -are restored to the values they had prior to the function's -execution. If a numeric argument is given to @code{return}, -that is the function's return status; otherwise the function's -return status is the exit status of the last command executed -before the @code{return}. - -Variables local to the function may be declared with the -@code{local} builtin. These variables are visible only to -the function and the commands it invokes. - -Function names and definitions may be listed with the -@option{-f} option to the @code{declare} (@code{typeset}) -builtin command (@pxref{Bash Builtins}). -The @option{-F} option to @code{declare} or @code{typeset} -will list the function names only -(and optionally the source file and line number, if the @code{extdebug} -shell option is enabled). -Functions may be exported so that subshells -automatically have them defined with the -@option{-f} option to the @code{export} builtin -(@pxref{Bourne Shell Builtins}). -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -Care should be taken in cases where this may cause a problem. - -Functions may be recursive. -The @code{FUNCNEST} variable may be used to limit the depth of the -function call stack and restrict the number of function invocations. -By default, no limit is placed on the number of recursive calls. - -@node Shell Parameters -@section Shell Parameters -@cindex parameters -@cindex variable, shell -@cindex shell variable - -@menu -* Positional Parameters:: The shell's command-line arguments. -* Special Parameters:: Parameters denoted by special characters. -@end menu - -A @var{parameter} is an entity that stores values. -It can be a @code{name}, a number, or one of the special characters -listed below. -A @var{variable} is a parameter denoted by a @code{name}. -A variable has a @var{value} and zero or more @var{attributes}. -Attributes are assigned using the @code{declare} builtin command -(see the description of the @code{declare} builtin in @ref{Bash Builtins}). - -A parameter is set if it has been assigned a value. The null string is -a valid value. Once a variable is set, it may be unset only by using -the @code{unset} builtin command. - -A variable may be assigned to by a statement of the form -@example -@var{name}=[@var{value}] -@end example -@noindent -If @var{value} -is not given, the variable is assigned the null string. All -@var{value}s undergo tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote -removal (detailed below). If the variable has its @code{integer} -attribute set, then @var{value} -is evaluated as an arithmetic expression even if the @code{$((@dots{}))} -expansion is not used (@pxref{Arithmetic Expansion}). -Word splitting is not performed, with the exception -of @code{"$@@"} as explained below. -Filename expansion is not performed. -Assignment statements may also appear as arguments to the -@code{alias}, -@code{declare}, @code{typeset}, @code{export}, @code{readonly}, -and @code{local} builtin commands. -When in @sc{posix} mode (@pxref{Bash POSIX Mode}), these builtins may appear -in a command after one or more instances of the @code{command} builtin -and retain these assignment statement properties. - -In the context where an assignment statement is assigning a value -to a shell variable or array index (@pxref{Arrays}), the @samp{+=} -operator can be used to -append to or add to the variable's previous value. -When @samp{+=} is applied to a variable for which the @var{integer} attribute -has been set, @var{value} is evaluated as an arithmetic expression and -added to the variable's current value, which is also evaluated. -When @samp{+=} is applied to an array variable using compound assignment -(@pxref{Arrays}), the -variable's value is not unset (as it is when using @samp{=}), and new -values are appended to the array beginning at one greater than the array's -maximum index (for indexed arrays), or added as additional key-value pairs -in an associative array. -When applied to a string-valued variable, @var{value} is expanded and -appended to the variable's value. - -A variable can be assigned the @var{nameref} attribute using the -@option{-n} option to the \fBdeclare\fP or \fBlocal\fP builtin commands -(@pxref{Bash Builtins}) -to create a @var{nameref}, or a reference to another variable. -This allows variables to be manipulated indirectly. -Whenever the nameref variable is referenced or assigned to, the operation -is actually performed on the variable specified by the nameref variable's -value. -A nameref is commonly used within shell functions to refer to a variable -whose name is passed as an argument to the function. -For instance, if a variable name is passed to a shell function as its first -argument, running -@example -declare -n ref=$1 -@end example -@noindent -inside the function creates a nameref variable @var{ref} whose value is -the variable name passed as the first argument. -References and assignments to @var{ref} are treated as references and -assignments to the variable whose name was passed as @code{$1}. - -If the control variable in a @code{for} loop has the nameref attribute, -the list of words can be a list of shell variables, and a name reference -will be established for each word in the list, in turn, when the loop is -executed. -Array variables cannot be given the @option{-n} attribute. -However, nameref variables can reference array variables and subscripted -array variables. -Namerefs can be unset using the @option{-n} option to the @code{unset} builtin -(@pxref{Bourne Shell Builtins}). -Otherwise, if @code{unset} is executed with the name of a nameref variable -as an argument, the variable referenced by the nameref variable will be unset. - -@node Positional Parameters -@subsection Positional Parameters -@cindex parameters, positional - -A @var{positional parameter} is a parameter denoted by one or more -digits, other than the single digit @code{0}. Positional parameters are -assigned from the shell's arguments when it is invoked, -and may be reassigned using the @code{set} builtin command. -Positional parameter @code{N} may be referenced as @code{$@{N@}}, or -as @code{$N} when @code{N} consists of a single digit. -Positional parameters may not be assigned to with assignment statements. -The @code{set} and @code{shift} builtins are used to set and -unset them (@pxref{Shell Builtin Commands}). -The positional parameters are -temporarily replaced when a shell function is executed -(@pxref{Shell Functions}). - -When a positional parameter consisting of more than a single -digit is expanded, it must be enclosed in braces. - -@node Special Parameters -@subsection Special Parameters -@cindex parameters, special - -The shell treats several parameters specially. These parameters may -only be referenced; assignment to them is not allowed. - -@vtable @code - -@item * -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, it expands to a single word -with the value of each parameter separated by the first character -of the @env{IFS} -special variable. That is, @code{"$*"} is equivalent -to @code{"$1@var{c}$2@var{c}@dots{}"}, where @var{c} -is the first character of the value of the @code{IFS} -variable. -If @env{IFS} is unset, the parameters are separated by spaces. -If @env{IFS} is null, the parameters are joined without intervening -separators. - - -@item @@ -Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands to a -separate word. That is, @code{"$@@"} is equivalent to -@code{"$1" "$2" @dots{}}. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, @code{"$@@"} and -@code{$@@} -expand to nothing (i.e., they are removed). - -@item # -Expands to the number of positional parameters in decimal. - -@item ? -Expands to the exit status of the most recently executed foreground -pipeline. - -@item - -(A hyphen.) Expands to the current option flags as specified upon -invocation, by the @code{set} -builtin command, or those set by the shell itself -(such as the @option{-i} option). - -@item $ -Expands to the process @sc{id} of the shell. In a @code{()} subshell, it -expands to the process @sc{id} of the invoking shell, not the subshell. - -@item ! -Expands to the process @sc{id} of the most recently executed background -(asynchronous) command. - -@item 0 -Expands to the name of the shell or shell script. This is set at -shell initialization. If Bash is invoked with a file of commands -(@pxref{Shell Scripts}), @code{$0} is set to the name of that file. -If Bash is started with the @option{-c} option (@pxref{Invoking Bash}), -then @code{$0} is set to the first argument after the string to be -executed, if one is present. Otherwise, it is set -to the filename used to invoke Bash, as given by argument zero. - -@item _ -(An underscore.) -At shell startup, set to the absolute pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -When checking mail, this parameter holds the name of the mail file. -@end vtable - -@node Shell Expansions -@section Shell Expansions -@cindex expansion - -Expansion is performed on the command line after it has been split into -@code{token}s. There are seven kinds of expansion performed: - -@itemize @bullet -@item brace expansion -@item tilde expansion -@item parameter and variable expansion -@item command substitution -@item arithmetic expansion -@item word splitting -@item filename expansion -@end itemize - -@menu -* Brace Expansion:: Expansion of expressions within braces. -* Tilde Expansion:: Expansion of the ~ character. -* Shell Parameter Expansion:: How Bash expands variables to their values. -* Command Substitution:: Using the output of a command as an argument. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Process Substitution:: A way to write and read to and from a - command. -* Word Splitting:: How the results of expansion are split into separate - arguments. -* Filename Expansion:: A shorthand for specifying filenames matching patterns. -* Quote Removal:: How and when quote characters are removed from - words. -@end menu - -The order of expansions is: brace expansion, tilde expansion, -parameter, variable, and arithmetic expansion and -command substitution -(done in a left-to-right fashion), word splitting, and filename -expansion. - -On systems that can support it, there is an additional expansion -available: @var{process substitution}. This is performed at the -same time as parameter, variable, and arithmetic expansion and -command substitution. - -Only brace expansion, word splitting, and filename expansion -can change the number of words of the expansion; other expansions -expand a single word to a single word. -The only exceptions to this are the expansions of -@code{"$@@"} (@pxref{Special Parameters}) and @code{"$@{@var{name}[@@]@}"} -(@pxref{Arrays}). - -After all expansions, @code{quote removal} (@pxref{Quote Removal}) -is performed. - -@node Brace Expansion -@subsection Brace Expansion -@cindex brace expansion -@cindex expansion, brace - -Brace expansion is a mechanism by which arbitrary strings may be generated. -This mechanism is similar to -@var{filename expansion} (@pxref{Filename Expansion}), -but the filenames generated need not exist. -Patterns to be brace expanded take the form of an optional @var{preamble}, -followed by either a series of comma-separated strings or a sequence expression -between a pair of braces, -followed by an optional @var{postscript}. -The preamble is prefixed to each string contained within the braces, and -the postscript is then appended to each resulting string, expanding left -to right. - -Brace expansions may be nested. -The results of each expanded string are not sorted; left to right order -is preserved. -For example, -@example -bash$ echo a@{d,c,b@}e -ade ace abe -@end example - -A sequence expression takes the form @code{@{@var{x}..@var{y}[..@var{incr}]@}}, -where @var{x} and @var{y} are either integers or single characters, -and @var{incr}, an optional increment, is an integer. -When integers are supplied, the expression expands to each number between -@var{x} and @var{y}, inclusive. -Supplied integers may be prefixed with @samp{0} to force each term to have the -same width. When either @var{x} or @var{y} begins with a zero, the shell -attempts to force all generated terms to contain the same number of digits, -zero-padding where necessary. -When characters are supplied, the expression expands to each character -lexicographically between @var{x} and @var{y}, inclusive. Note that -both @var{x} and @var{y} must be of the same type. -When the increment is supplied, it is used as the difference between -each term. The default increment is 1 or -1 as appropriate. - -Brace expansion is performed before any other expansions, -and any characters special to other expansions are preserved -in the result. It is strictly textual. Bash -does not apply any syntactic interpretation to the context of the -expansion or the text between the braces. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma or a valid -sequence expression. -Any incorrectly formed brace expansion is left unchanged. - -A @{ or @samp{,} may be quoted with a backslash to prevent its -being considered part of a brace expression. -To avoid conflicts with parameter expansion, the string @samp{$@{} -is not considered eligible for brace expansion. - -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -@example -mkdir /usr/local/src/bash/@{old,new,dist,bugs@} -@end example -or -@example -chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} -@end example - -@node Tilde Expansion -@subsection Tilde Expansion -@cindex tilde expansion -@cindex expansion, tilde - -If a word begins with an unquoted tilde character (@samp{~}), all of the -characters up to the first unquoted slash (or all characters, -if there is no unquoted slash) are considered a @var{tilde-prefix}. -If none of the characters in the tilde-prefix are quoted, the -characters in the tilde-prefix following the tilde are treated as a -possible @var{login name}. -If this login name is the null string, the tilde is replaced with the -value of the @env{HOME} shell variable. -If @env{HOME} is unset, the home directory of the user executing the -shell is substituted instead. -Otherwise, the tilde-prefix is replaced with the home directory -associated with the specified login name. - -If the tilde-prefix is @samp{~+}, the value of -the shell variable @env{PWD} replaces the tilde-prefix. -If the tilde-prefix is @samp{~-}, the value of the shell variable -@env{OLDPWD}, if it is set, is substituted. - -If the characters following the tilde in the tilde-prefix consist of a -number @var{N}, optionally prefixed by a @samp{+} or a @samp{-}, -the tilde-prefix is replaced with the -corresponding element from the directory stack, as it would be displayed -by the @code{dirs} builtin invoked with the characters following tilde -in the tilde-prefix as an argument (@pxref{The Directory Stack}). -If the tilde-prefix, sans the tilde, consists of a number without a -leading @samp{+} or @samp{-}, @samp{+} is assumed. - -If the login name is invalid, or the tilde expansion fails, the word is -left unchanged. - -Each variable assignment is checked for unquoted tilde-prefixes immediately -following a @samp{:} or the first @samp{=}. -In these cases, tilde expansion is also performed. -Consequently, one may use filenames with tildes in assignments to -@env{PATH}, @env{MAILPATH}, and @env{CDPATH}, -and the shell assigns the expanded value. - -The following table shows how Bash treats unquoted tilde-prefixes: - -@table @code -@item ~ -The value of @code{$HOME} -@item ~/foo -@file{$HOME/foo} - -@item ~fred/foo -The subdirectory @code{foo} of the home directory of the user -@code{fred} - -@item ~+/foo -@file{$PWD/foo} - -@item ~-/foo -@file{$@{OLDPWD-'~-'@}/foo} - -@item ~@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~+@var{N} -The string that would be displayed by @samp{dirs +@var{N}} - -@item ~-@var{N} -The string that would be displayed by @samp{dirs -@var{N}} -@end table - -@node Shell Parameter Expansion -@subsection Shell Parameter Expansion -@cindex parameter expansion -@cindex expansion, parameter - -The @samp{$} character introduces parameter expansion, -command substitution, or arithmetic expansion. The parameter name -or symbol to be expanded may be enclosed in braces, which -are optional but serve to protect the variable to be expanded from -characters immediately following it which could be -interpreted as part of the name. - -When braces are used, the matching ending brace is the first @samp{@}} -not escaped by a backslash or within a quoted string, and not within an -embedded arithmetic expansion, command substitution, or parameter -expansion. - -The basic form of parameter expansion is $@{@var{parameter}@}. -The value of @var{parameter} is substituted. -The @var{parameter} is a shell parameter as described above -(@pxref{Shell Parameters}) or an array reference (@pxref{Arrays}). -The braces are required when @var{parameter} -is a positional parameter with more than one digit, -or when @var{parameter} is followed by a character that is not to be -interpreted as part of its name. - -If the first character of @var{parameter} is an exclamation point (!), -it introduces a level of variable indirection. -Bash uses the value of the variable formed from the rest of -@var{parameter} as the name of the variable; this variable is then -expanded and that value is used in the rest of the substitution, rather -than the value of @var{parameter} itself. -This is known as @code{indirect expansion}. -The exceptions to this are the expansions of $@{!@var{prefix}*@} -and $@{!@var{name}[@@]@} -described below. -The exclamation point must immediately follow the left brace in order to -introduce indirection. - -In each of the cases below, @var{word} is subject to tilde expansion, -parameter expansion, command substitution, and arithmetic expansion. - -When not performing substring expansion, using the form described -below (e.g., @samp{:-}), Bash tests for a parameter that is unset or null. -Omitting the colon results in a test only for a parameter that is unset. -Put another way, if the colon is included, -the operator tests for both @var{parameter}'s existence and that its value -is not null; if the colon is omitted, the operator tests only for existence. - -@table @code - -@item $@{@var{parameter}:@minus{}@var{word}@} -If @var{parameter} is unset or null, the expansion of -@var{word} is substituted. Otherwise, the value of -@var{parameter} is substituted. - -@item $@{@var{parameter}:=@var{word}@} -If @var{parameter} -is unset or null, the expansion of @var{word} -is assigned to @var{parameter}. -The value of @var{parameter} is then substituted. -Positional parameters and special parameters may not be assigned to -in this way. - -@item $@{@var{parameter}:?@var{word}@} -If @var{parameter} -is null or unset, the expansion of @var{word} (or a message -to that effect if @var{word} -is not present) is written to the standard error and the shell, if it -is not interactive, exits. Otherwise, the value of @var{parameter} is -substituted. - -@item $@{@var{parameter}:+@var{word}@} -If @var{parameter} -is null or unset, nothing is substituted, otherwise the expansion of -@var{word} is substituted. - -@item $@{@var{parameter}:@var{offset}@} -@itemx $@{@var{parameter}:@var{offset}:@var{length}@} -This is referred to as Substring Expansion. -It expands to up to @var{length} characters of the value of @var{parameter} -starting at the character specified by @var{offset}. -If @var{parameter} is @samp{@@}, an indexed array subscripted by -@samp{@@} or @samp{*}, or an associative array name, the results differ as -described below. -If @var{length} is omitted, it expands to the substring of the value of -@var{parameter} starting at the character specified by @var{offset} -and extending to the end of the value. -@var{length} and @var{offset} are arithmetic expressions -(@pxref{Shell Arithmetic}). - -If @var{offset} evaluates to a number less than zero, the value -is used as an offset in characters -from the end of the value of @var{parameter}. -If @var{length} evaluates to a number less than zero, -it is interpreted as an offset in characters -from the end of the value of @var{parameter} rather than -a number of characters, and the expansion is the characters between -@var{offset} and that result. -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the @samp{:-} expansion. - -Here are some examples illustrating substring expansion on parameters and -subscripted arrays: - -@verbatim -$ string=01234567890abcdefgh -$ echo ${string:7} -7890abcdefgh -$ echo ${string:7:0} - -$ echo ${string:7:2} -78 -$ echo ${string:7:-2} -7890abcdef -$ echo ${string: -7} -bcdefgh -$ echo ${string: -7:0} - -$ echo ${string: -7:2} -bc -$ echo ${string: -7:-2} -bcdef -$ set -- 01234567890abcdefgh -$ echo ${1:7} -7890abcdefgh -$ echo ${1:7:0} - -$ echo ${1:7:2} -78 -$ echo ${1:7:-2} -7890abcdef -$ echo ${1: -7} -bcdefgh -$ echo ${1: -7:0} - -$ echo ${1: -7:2} -bc -$ echo ${1: -7:-2} -bcdef -$ array[0]=01234567890abcdefgh -$ echo ${array[0]:7} -7890abcdefgh -$ echo ${array[0]:7:0} - -$ echo ${array[0]:7:2} -78 -$ echo ${array[0]:7:-2} -7890abcdef -$ echo ${array[0]: -7} -bcdefgh -$ echo ${array[0]: -7:0} - -$ echo ${array[0]: -7:2} -bc -$ echo ${array[0]: -7:-2} -bcdef -@end verbatim - -If @var{parameter} is @samp{@@}, the result is @var{length} positional -parameters beginning at @var{offset}. -A negative @var{offset} is taken relative to one greater than the greatest -positional parameter, so an offset of -1 evaluates to the last positional -parameter. -It is an expansion error if @var{length} evaluates to a number less than zero. - -The following examples illustrate substring expansion using positional -parameters: - -@verbatim -$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h -$ echo ${@:7} -7 8 9 0 a b c d e f g h -$ echo ${@:7:0} - -$ echo ${@:7:2} -7 8 -$ echo ${@:7:-2} -bash: -2: substring expression < 0 -$ echo ${@: -7:2} -b c -$ echo ${@:0} -./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h -$ echo ${@:0:2} -./bash 1 -$ echo ${@: -7:0} - -@end verbatim - -If @var{parameter} is an indexed array name subscripted -by @samp{@@} or @samp{*}, the result is the @var{length} -members of the array beginning with @code{$@{@var{parameter}[@var{offset}]@}}. -A negative @var{offset} is taken relative to one greater than the maximum -index of the specified array. -It is an expansion error if @var{length} evaluates to a number less than zero. - -These examples show how you can use substring expansion with indexed -arrays: - -@verbatim -$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h) -$ echo ${array[@]:7} -7 8 9 0 a b c d e f g h -$ echo ${array[@]:7:2} -7 8 -$ echo ${array[@]: -7:2} -b c -$ echo ${array[@]: -7:-2} -bash: -2: substring expression < 0 -$ echo ${array[@]:0} -0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h -$ echo ${array[@]:0:2} -0 1 -$ echo ${array[@]: -7:0} - -@end verbatim - -Substring expansion applied to an associative array produces undefined -results. - -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If @var{offset} is 0, and the positional parameters are used, @code{$@@} is -prefixed to the list. - -@item $@{!@var{prefix}*@} -@itemx $@{!@var{prefix}@@@} -Expands to the names of variables whose names begin with @var{prefix}, -separated by the first character of the @env{IFS} special variable. -When @samp{@@} is used and the expansion appears within double quotes, each -variable name expands to a separate word. - -@item $@{!@var{name}[@@]@} -@itemx $@{!@var{name}[*]@} -If @var{name} is an array variable, expands to the list of array indices -(keys) assigned in @var{name}. -If @var{name} is not an array, expands to 0 if @var{name} is set and null -otherwise. -When @samp{@@} is used and the expansion appears within double quotes, each -key expands to a separate word. - -@item $@{#@var{parameter}@} -The length in characters of the expanded value of @var{parameter} is -substituted. -If @var{parameter} is @samp{*} or @samp{@@}, the value substituted -is the number of positional parameters. -If @var{parameter} is an array name subscripted by @samp{*} or @samp{@@}, -the value substituted is the number of elements in the array. - -@item $@{@var{parameter}#@var{word}@} -@itemx $@{@var{parameter}##@var{word}@} -The @var{word} -is expanded to produce a pattern just as in filename -expansion (@pxref{Filename Expansion}). If the pattern matches -the beginning of the expanded value of @var{parameter}, -then the result of the expansion is the expanded value of @var{parameter} -with the shortest matching pattern (the @samp{#} case) or the -longest matching pattern (the @samp{##} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} is an array variable subscripted with -@samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}%@var{word}@} -@itemx $@{@var{parameter}%%@var{word}@} -The @var{word} is expanded to produce a pattern just as in -filename expansion. -If the pattern matches a trailing portion of the expanded value of -@var{parameter}, then the result of the expansion is the value of -@var{parameter} with the shortest matching pattern (the @samp{%} case) -or the longest matching pattern (the @samp{%%} case) deleted. -If @var{parameter} is @samp{@@} or @samp{*}, -the pattern removal operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the pattern removal operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}/@var{pattern}/@var{string}@} - -The @var{pattern} is expanded to produce a pattern just as in -filename expansion. -@var{Parameter} is expanded and the longest match of @var{pattern} -against its value is replaced with @var{string}. -If @var{pattern} begins with @samp{/}, all matches of @var{pattern} are -replaced with @var{string}. Normally only the first match is replaced. -If @var{pattern} begins with @samp{#}, it must match at the beginning -of the expanded value of @var{parameter}. -If @var{pattern} begins with @samp{%}, it must match at the end -of the expanded value of @var{parameter}. -If @var{string} is null, matches of @var{pattern} are deleted -and the @code{/} following @var{pattern} may be omitted. -If @var{parameter} is @samp{@@} or @samp{*}, -the substitution operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the substitution operation is applied to each member of the -array in turn, and the expansion is the resultant list. - -@item $@{@var{parameter}^@var{pattern}@} -@itemx $@{@var{parameter}^^@var{pattern}@} -@itemx $@{@var{parameter},@var{pattern}@} -@itemx $@{@var{parameter},,@var{pattern}@} -This expansion modifies the case of alphabetic characters in @var{parameter}. -The @var{pattern} is expanded to produce a pattern just as in -filename expansion. -Each character in the expanded value of @var{parameter} is tested against -@var{pattern}, and, if it matches the pattern, its case is converted. -The pattern should not attempt to match more than one character. -The @samp{^} operator converts lowercase letters matching @var{pattern} -to uppercase; the @samp{,} operator converts matching uppercase letters -to lowercase. -The @samp{^^} and @samp{,,} expansions convert each matched character in the -expanded value; the @samp{^} and @samp{,} expansions match and convert only -the first character in the expanded value. -If @var{pattern} is omitted, it is treated like a @samp{?}, which matches -every character. -If @var{parameter} is @samp{@@} or @samp{*}, -the case modification operation is applied to each positional -parameter in turn, and the expansion is the resultant list. -If @var{parameter} -is an array variable subscripted with @samp{@@} or @samp{*}, -the case modification operation is applied to each member of the -array in turn, and the expansion is the resultant list. -@end table - -@node Command Substitution -@subsection Command Substitution -@cindex command substitution - -Command substitution allows the output of a command to replace -the command itself. -Command substitution occurs when a command is enclosed as follows: -@example -$(@var{command}) -@end example -@noindent -or -@example -`@var{command}` -@end example - -@noindent -Bash performs the expansion by executing @var{command} and -replacing the command substitution with the standard output of the -command, with any trailing newlines deleted. -Embedded newlines are not deleted, but they may be removed during -word splitting. -The command substitution @code{$(cat @var{file})} can be -replaced by the equivalent but faster @code{$(< @var{file})}. - -When the old-style backquote form of substitution is used, -backslash retains its literal meaning except when followed by -@samp{$}, @samp{`}, or @samp{\}. -The first backquote not preceded by a backslash terminates the -command substitution. -When using the @code{$(@var{command})} form, all characters between -the parentheses make up the command; none are treated specially. - -Command substitutions may be nested. To nest when using the backquoted -form, escape the inner backquotes with backslashes. - -If the substitution appears within double quotes, word splitting and -filename expansion are not performed on the results. - -@node Arithmetic Expansion -@subsection Arithmetic Expansion -@cindex expansion, arithmetic -@cindex arithmetic expansion - -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. The format for arithmetic expansion is: - -@example -$(( @var{expression} )) -@end example - -The expression is treated as if it were within double quotes, but -a double quote inside the parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, command -substitution, and quote removal. -Arithmetic expansions may be nested. - -The evaluation is performed according to the rules listed below -(@pxref{Shell Arithmetic}). -If the expression is invalid, Bash prints a message indicating -failure to the standard error and no substitution occurs. - -@node Process Substitution -@subsection Process Substitution -@cindex process substitution - -Process substitution is supported on systems that support named -pipes (@sc{fifo}s) or the @file{/dev/fd} method of naming open files. -It takes the form of -@example -<(@var{list}) -@end example -@noindent -or -@example ->(@var{list}) -@end example -@noindent -The process @var{list} is run with its input or output connected to a -@sc{fifo} or some file in @file{/dev/fd}. The name of this file is -passed as an argument to the current command as the result of the -expansion. If the @code{>(@var{list})} form is used, writing to -the file will provide input for @var{list}. If the -@code{<(@var{list})} form is used, the file passed as an -argument should be read to obtain the output of @var{list}. -Note that no space may appear between the @code{<} or @code{>} -and the left parenthesis, otherwise the construct would be interpreted -as a redirection. - -When available, process substitution is performed simultaneously with -parameter and variable expansion, command substitution, and arithmetic -expansion. - -@node Word Splitting -@subsection Word Splitting -@cindex word splitting - -The shell scans the results of parameter expansion, command substitution, -and arithmetic expansion that did not occur within double quotes for -word splitting. - -The shell treats each character of @env{$IFS} as a delimiter, and splits -the results of the other expansions into words on these characters. -If @env{IFS} is unset, or its value is exactly @code{}, -the default, then sequences of -@code{ }, @code{}, and @code{} -at the beginning and end of the results of the previous -expansions are ignored, and any sequence of @env{IFS} -characters not at the beginning or end serves to delimit words. -If @env{IFS} has a value other than the default, then sequences of -the whitespace characters @code{space} and @code{tab} -are ignored at the beginning and end of the -word, as long as the whitespace character is in the -value of @env{IFS} (an @env{IFS} whitespace character). -Any character in @env{IFS} that is not @env{IFS} -whitespace, along with any adjacent @env{IFS} -whitespace characters, delimits a field. A sequence of @env{IFS} -whitespace characters is also treated as a delimiter. -If the value of @env{IFS} is null, no word splitting occurs. - -Explicit null arguments (@code{""} or @code{''}) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -null argument results and is retained. - -Note that if no expansion occurs, no splitting -is performed. - -@node Filename Expansion -@subsection Filename Expansion -@menu -* Pattern Matching:: How the shell matches patterns. -@end menu -@cindex expansion, filename -@cindex expansion, pathname -@cindex filename expansion -@cindex pathname expansion - -After word splitting, unless the @option{-f} option has been set -(@pxref{The Set Builtin}), Bash scans each word for the characters -@samp{*}, @samp{?}, and @samp{[}. -If one of these characters appears, then the word is -regarded as a @var{pattern}, -and replaced with an alphabetically sorted list of -filenames matching the pattern (@pxref{Pattern Matching}). -If no matching filenames are found, -and the shell option @code{nullglob} is disabled, the word is left -unchanged. -If the @code{nullglob} option is set, and no matches are found, the word -is removed. -If the @code{failglob} shell option is set, and no matches are found, -an error message is printed and the command is not executed. -If the shell option @code{nocaseglob} is enabled, the match is performed -without regard to the case of alphabetic characters. - -When a pattern is used for filename expansion, the character @samp{.} -at the start of a filename or immediately following a slash -must be matched explicitly, unless the shell option @code{dotglob} is set. -When matching a filename, the slash character must always be -matched explicitly. -In other cases, the @samp{.} character is not treated specially. - -See the description of @code{shopt} in @ref{The Shopt Builtin}, -for a description of the @code{nocaseglob}, @code{nullglob}, -@code{failglob}, and @code{dotglob} options. - -The @env{GLOBIGNORE} -shell variable may be used to restrict the set of filenames matching a -pattern. If @env{GLOBIGNORE} -is set, each matching filename that also matches one of the patterns in -@env{GLOBIGNORE} is removed from the list of matches. The filenames -@file{.} and @file{..} -are always ignored when @env{GLOBIGNORE} -is set and not null. -However, setting @env{GLOBIGNORE} to a non-null value has the effect of -enabling the @code{dotglob} -shell option, so all other filenames beginning with a -@samp{.} will match. -To get the old behavior of ignoring filenames beginning with a -@samp{.}, make @samp{.*} one of the patterns in @env{GLOBIGNORE}. -The @code{dotglob} option is disabled when @env{GLOBIGNORE} -is unset. - -@node Pattern Matching -@subsubsection Pattern Matching -@cindex pattern matching -@cindex matching, pattern - -Any character that appears in a pattern, other than the special pattern -characters described below, matches itself. -The @sc{nul} character may not occur in a pattern. -A backslash escapes the following character; the -escaping backslash is discarded when matching. -The special pattern characters must be quoted if they are to be matched -literally. - -The special pattern characters have the following meanings: -@table @code -@item * -Matches any string, including the null string. -When the @code{globstar} shell option is enabled, and @samp{*} is used in -a filename expansion context, two adjacent @samp{*}s used as a single -pattern will match all files and zero or more directories and -subdirectories. -If followed by a @samp{/}, two adjacent @samp{*}s will match only -directories and subdirectories. -@item ? -Matches any single character. -@item [@dots{}] -Matches any one of the enclosed characters. A pair of characters -separated by a hyphen denotes a @var{range expression}; -any character that sorts between those two characters, inclusive, -using the current locale's collating sequence and character set, -is matched. If the first character following the -@samp{[} is a @samp{!} or a @samp{^} -then any character not enclosed is matched. A @samp{@minus{}} -may be matched by including it as the first or last character -in the set. A @samp{]} may be matched by including it as the first -character in the set. -The sorting order of characters in range expressions is determined by -the current locale and the values of the -@env{LC_COLLATE} and @env{LC_ALL} shell variables, if set. - -For example, in the default C locale, @samp{[a-dx-z]} is equivalent to -@samp{[abcdxyz]}. Many locales sort characters in dictionary order, and in -these locales @samp{[a-dx-z]} is typically not equivalent to @samp{[abcdxyz]}; -it might be equivalent to @samp{[aBbCcDdxXyYz]}, for example. To obtain -the traditional interpretation of ranges in bracket expressions, you can -force the use of the C locale by setting the @env{LC_COLLATE} or -@env{LC_ALL} environment variable to the value @samp{C}, or enable the -@code{globasciiranges} shell option. - -Within @samp{[} and @samp{]}, @var{character classes} can be specified -using the syntax -@code{[:}@var{class}@code{:]}, where @var{class} is one of the -following classes defined in the @sc{posix} standard: -@example -alnum alpha ascii blank cntrl digit graph lower -print punct space upper word xdigit -@end example -@noindent -A character class matches any character belonging to that class. -The @code{word} character class matches letters, digits, and the character -@samp{_}. - -Within @samp{[} and @samp{]}, an @var{equivalence class} can be -specified using the syntax @code{[=}@var{c}@code{=]}, which -matches all characters with the same collation weight (as defined -by the current locale) as the character @var{c}. - -Within @samp{[} and @samp{]}, the syntax @code{[.}@var{symbol}@code{.]} -matches the collating symbol @var{symbol}. -@end table - -If the @code{extglob} shell option is enabled using the @code{shopt} -builtin, several extended pattern matching operators are recognized. -In the following description, a @var{pattern-list} is a list of one -or more patterns separated by a @samp{|}. -Composite patterns may be formed using one or more of the following -sub-patterns: - -@table @code -@item ?(@var{pattern-list}) -Matches zero or one occurrence of the given patterns. - -@item *(@var{pattern-list}) -Matches zero or more occurrences of the given patterns. - -@item +(@var{pattern-list}) -Matches one or more occurrences of the given patterns. - -@item @@(@var{pattern-list}) -Matches one of the given patterns. - -@item !(@var{pattern-list}) -Matches anything except one of the given patterns. -@end table - -@node Quote Removal -@subsection Quote Removal - -After the preceding expansions, all unquoted occurrences of the -characters @samp{\}, @samp{'}, and @samp{"} that did not -result from one of the above expansions are removed. - -@node Redirections -@section Redirections -@cindex redirection - -Before a command is executed, its input and output -may be @var{redirected} -using a special notation interpreted by the shell. -Redirection allows commands' file handles to be -duplicated, opened, closed, -made to refer to different files, -and can change the files the command reads from and writes to. -Redirection may also be used to modify file handles in the -current shell execution environment. The following redirection -operators may precede or appear anywhere within a -simple command or may follow a command. -Redirections are processed in the order they appear, from -left to right. - -Each redirection that may be preceded by a file descriptor number -may instead be preceded by a word of the form @{@var{varname}@}. -In this case, for each redirection operator except ->&- and <&-, the shell will allocate a file descriptor greater -than 10 and assign it to @{@var{varname}@}. If >&- or <&- is preceded -by @{@var{varname}@}, the value of @var{varname} defines the file -descriptor to close. - -In the following descriptions, if the file descriptor number is -omitted, and the first character of the redirection operator is -@samp{<}, the redirection refers to the standard input (file -descriptor 0). If the first character of the redirection operator -is @samp{>}, the redirection refers to the standard output (file -descriptor 1). - -The word following the redirection operator in the following -descriptions, unless otherwise noted, is subjected to brace expansion, -tilde expansion, parameter expansion, command substitution, arithmetic -expansion, quote removal, filename expansion, and word splitting. -If it expands to more than one word, Bash reports an error. - -Note that the order of redirections is significant. For example, -the command -@example -ls > @var{dirlist} 2>&1 -@end example -@noindent -directs both standard output (file descriptor 1) and standard error -(file descriptor 2) to the file @var{dirlist}, while the command -@example -ls 2>&1 > @var{dirlist} -@end example -@noindent -directs only the standard output to file @var{dirlist}, -because the standard error was made a copy of the standard output -before the standard output was redirected to @var{dirlist}. - -Bash handles several filenames specially when they are used in -redirections, as described in the following table: - -@table @code -@item /dev/fd/@var{fd} -If @var{fd} is a valid integer, file descriptor @var{fd} is duplicated. - -@item /dev/stdin -File descriptor 0 is duplicated. - -@item /dev/stdout -File descriptor 1 is duplicated. - -@item /dev/stderr -File descriptor 2 is duplicated. - -@item /dev/tcp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open -the corresponding TCP socket. - -@item /dev/udp/@var{host}/@var{port} -If @var{host} is a valid hostname or Internet address, and @var{port} -is an integer port number or service name, Bash attempts to open -the corresponding UDP socket. -@end table - -A failure to open or create a file causes the redirection to fail. - -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. - -@subsection Redirecting Input -Redirection of input causes the file whose name results from -the expansion of @var{word} -to be opened for reading on file descriptor @code{n}, -or the standard input (file descriptor 0) if @code{n} -is not specified. - -The general format for redirecting input is: -@example -[@var{n}]<@var{word} -@end example - -@subsection Redirecting Output -Redirection of output causes the file whose name results from -the expansion of @var{word} -to be opened for writing on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created; -if it does exist it is truncated to zero size. - -The general format for redirecting output is: -@example -[@var{n}]>[|]@var{word} -@end example - -If the redirection operator is @samp{>}, and the @code{noclobber} -option to the @code{set} builtin has been enabled, the redirection -will fail if the file whose name results from the expansion of -@var{word} exists and is a regular file. -If the redirection operator is @samp{>|}, or the redirection operator is -@samp{>} and the @code{noclobber} option is not enabled, the redirection -is attempted even if the file named by @var{word} exists. - -@subsection Appending Redirected Output -Redirection of output in this fashion -causes the file whose name results from -the expansion of @var{word} -to be opened for appending on file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} -is not specified. If the file does not exist it is created. - -The general format for appending output is: -@example -[@var{n}]>>@var{word} -@end example - -@subsection Redirecting Standard Output and Standard Error -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be redirected to the file whose name is the -expansion of @var{word}. - -There are two formats for redirecting standard output and -standard error: -@example -&>@var{word} -@end example -@noindent -and -@example ->&@var{word} -@end example -@noindent -Of the two forms, the first is preferred. -This is semantically equivalent to -@example ->@var{word} 2>&1 -@end example -When using the second form, @var{word} may not expand to a number or -@samp{-}. If it does, other redirection operators apply -(see Duplicating File Descriptors below) for compatibility reasons. - -@subsection Appending Standard Output and Standard Error -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be appended to the file whose name is the -expansion of @var{word}. - -The format for appending standard output and standard error is: -@example -&>>@var{word} -@end example -@noindent -This is semantically equivalent to -@example ->>@var{word} 2>&1 -@end example -(see Duplicating File Descriptors below). - -@subsection Here Documents -This type of redirection instructs the shell to read input from the -current source until a line containing only @var{word} -(with no trailing blanks) is seen. All of -the lines read up to that point are then used as the standard -input for a command. - -The format of here-documents is: -@example -<<[@minus{}]@var{word} - @var{here-document} -@var{delimiter} -@end example - -No parameter and variable expansion, command substitution, -arithmetic expansion, or filename expansion is performed on -@var{word}. If any characters in @var{word} are quoted, the -@var{delimiter} is the result of quote removal on @var{word}, -and the lines in the here-document are not expanded. -If @var{word} is unquoted, -all lines of the here-document are subjected to -parameter expansion, command substitution, and arithmetic expansion, -the character sequence @code{\newline} is ignored, and @samp{\} -must be used to quote the characters -@samp{\}, @samp{$}, and @samp{`}. - -If the redirection operator is @samp{<<-}, -then all leading tab characters are stripped from input lines and the -line containing @var{delimiter}. -This allows here-documents within shell scripts to be indented in a -natural fashion. - -@subsection Here Strings -A variant of here documents, the format is: -@example -<<< @var{word} -@end example - -The @var{word} undergoes -brace expansion, tilde expansion, parameter and variable expansion, -command substitution, arithmetic expansion, and quote removal. -Pathname expansion and word splitting are not performed. -The result is supplied as a single string to the command on its -standard input. - -@subsection Duplicating File Descriptors -The redirection operator -@example -[@var{n}]<&@var{word} -@end example -@noindent -is used to duplicate input file descriptors. -If @var{word} -expands to one or more digits, the file descriptor denoted by @var{n} -is made to be a copy of that file descriptor. -If the digits in @var{word} do not specify a file descriptor open for -input, a redirection error occurs. -If @var{word} -evaluates to @samp{-}, file descriptor @var{n} is closed. -If @var{n} is not specified, the standard input (file descriptor 0) is used. - -The operator -@example -[@var{n}]>&@var{word} -@end example -@noindent -is used similarly to duplicate output file descriptors. If -@var{n} is not specified, the standard output (file descriptor 1) is used. -If the digits in @var{word} do not specify a file descriptor open for -output, a redirection error occurs. -If @var{word} -evaluates to @samp{-}, file descriptor @var{n} is closed. -As a special case, if @var{n} is omitted, and @var{word} does not -expand to one or more digits or @samp{-}, the standard output and standard -error are redirected as described previously. - -@subsection Moving File Descriptors -The redirection operator -@example -[@var{n}]<&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard input (file descriptor 0) if @var{n} is not specified. -@var{digit} is closed after being duplicated to @var{n}. - -Similarly, the redirection operator -@example -[@var{n}]>&@var{digit}- -@end example -@noindent -moves the file descriptor @var{digit} to file descriptor @var{n}, -or the standard output (file descriptor 1) if @var{n} is not specified. - -@subsection Opening File Descriptors for Reading and Writing -The redirection operator -@example -[@var{n}]<>@var{word} -@end example -@noindent -causes the file whose name is the expansion of @var{word} -to be opened for both reading and writing on file descriptor -@var{n}, or on file descriptor 0 if @var{n} -is not specified. If the file does not exist, it is created. - -@node Executing Commands -@section Executing Commands - -@menu -* Simple Command Expansion:: How Bash expands simple commands before - executing them. -* Command Search and Execution:: How Bash finds commands and runs them. -* Command Execution Environment:: The environment in which Bash - executes commands that are not - shell builtins. -* Environment:: The environment given to a command. -* Exit Status:: The status returned by commands and how Bash - interprets it. -* Signals:: What happens when Bash or a command it runs - receives a signal. -@end menu - -@node Simple Command Expansion -@subsection Simple Command Expansion -@cindex command expansion - -When a simple command is executed, the shell performs the following -expansions, assignments, and redirections, from left to right. - -@enumerate -@item -The words that the parser has marked as variable assignments (those -preceding the command name) and redirections are saved for later -processing. - -@item -The words that are not variable assignments or redirections are -expanded (@pxref{Shell Expansions}). -If any words remain after expansion, the first word -is taken to be the name of the command and the remaining words are -the arguments. - -@item -Redirections are performed as described above (@pxref{Redirections}). - -@item -The text after the @samp{=} in each variable assignment undergoes tilde -expansion, parameter expansion, command substitution, arithmetic expansion, -and quote removal before being assigned to the variable. -@end enumerate - -If no command name results, the variable assignments affect the current -shell environment. Otherwise, the variables are added to the environment -of the executed command and do not affect the current shell environment. -If any of the assignments attempts to assign a value to a readonly variable, -an error occurs, and the command exits with a non-zero status. - -If no command name results, redirections are performed, but do not -affect the current shell environment. A redirection error causes the -command to exit with a non-zero status. - -If there is a command name left after expansion, execution proceeds as -described below. Otherwise, the command exits. If one of the expansions -contained a command substitution, the exit status of the command is -the exit status of the last command substitution performed. If there -were no command substitutions, the command exits with a status of zero. - -@node Command Search and Execution -@subsection Command Search and Execution -@cindex command execution -@cindex command search - -After a command has been split into words, if it results in a -simple command and an optional list of arguments, the following -actions are taken. - -@enumerate -@item -If the command name contains no slashes, the shell attempts to -locate it. If there exists a shell function by that name, that -function is invoked as described in @ref{Shell Functions}. - -@item -If the name does not match a function, the shell searches for -it in the list of shell builtins. If a match is found, that -builtin is invoked. - -@item -If the name is neither a shell function nor a builtin, -and contains no slashes, Bash searches each element of -@env{$PATH} for a directory containing an executable file -by that name. Bash uses a hash table to remember the full -pathnames of executable files to avoid multiple @env{PATH} searches -(see the description of @code{hash} in @ref{Bourne Shell Builtins}). -A full search of the directories in @env{$PATH} -is performed only if the command is not found in the hash table. -If the search is unsuccessful, the shell searches for a defined shell -function named @code{command_not_found_handle}. -If that function exists, it is invoked with the original command and -the original command's arguments as its arguments, and the function's -exit status becomes the exit status of the shell. -If that function is not defined, the shell prints an error -message and returns an exit status of 127. - -@item -If the search is successful, or if the command name contains -one or more slashes, the shell executes the named program in -a separate execution environment. -Argument 0 is set to the name given, and the remaining arguments -to the command are set to the arguments supplied, if any. - -@item -If this execution fails because the file is not in executable -format, and the file is not a directory, it is assumed to be a -@var{shell script} and the shell executes it as described in -@ref{Shell Scripts}. - -@item -If the command was not begun asynchronously, the shell waits for -the command to complete and collects its exit status. - -@end enumerate - -@node Command Execution Environment -@subsection Command Execution Environment -@cindex execution environment - -The shell has an @var{execution environment}, which consists of the -following: - -@itemize @bullet -@item -open files inherited by the shell at invocation, as modified by -redirections supplied to the @code{exec} builtin - -@item -the current working directory as set by @code{cd}, @code{pushd}, or -@code{popd}, or inherited by the shell at invocation - -@item -the file creation mode mask as set by @code{umask} or inherited from -the shell's parent - -@item -current traps set by @code{trap} - -@item -shell parameters that are set by variable assignment or with @code{set} -or inherited from the shell's parent in the environment - -@item -shell functions defined during execution or inherited from the shell's -parent in the environment - -@item -options enabled at invocation (either by default or with command-line -arguments) or by @code{set} - -@item -options enabled by @code{shopt} (@pxref{The Shopt Builtin}) - -@item -shell aliases defined with @code{alias} (@pxref{Aliases}) - -@item -various process @sc{id}s, including those of background jobs -(@pxref{Lists}), the value of @code{$$}, and the value of -@env{$PPID} - -@end itemize - -When a simple command other than a builtin or shell function -is to be executed, it -is invoked in a separate execution environment that consists of -the following. Unless otherwise noted, the values are inherited -from the shell. - -@itemize @bullet -@item -the shell's open files, plus any modifications and additions specified -by redirections to the command - -@item -the current working directory - -@item -the file creation mode mask - -@item -shell variables and functions marked for export, along with variables -exported for the command, passed in the environment (@pxref{Environment}) - -@item -traps caught by the shell are reset to the values inherited from the -shell's parent, and traps ignored by the shell are ignored - -@end itemize - -A command invoked in this separate environment cannot affect the -shell's execution environment. - -Command substitution, commands grouped with parentheses, -and asynchronous commands are invoked in a -subshell environment that is a duplicate of the shell environment, -except that traps caught by the shell are reset to the values -that the shell inherited from its parent at invocation. Builtin -commands that are invoked as part of a pipeline are also executed -in a subshell environment. Changes made to the subshell environment -cannot affect the shell's execution environment. - -Subshells spawned to execute command substitutions inherit the value of -the @option{-e} option from the parent shell. When not in @sc{posix} mode, -Bash clears the @option{-e} option in such subshells. - -If a command is followed by a @samp{&} and job control is not active, the -default standard input for the command is the empty file @file{/dev/null}. -Otherwise, the invoked command inherits the file descriptors of the calling -shell as modified by redirections. - -@node Environment -@subsection Environment -@cindex environment - -When a program is invoked it is given an array of strings -called the @var{environment}. -This is a list of name-value pairs, of the form @code{name=value}. - -Bash provides several ways to manipulate the environment. -On invocation, the shell scans its own environment and -creates a parameter for each name found, automatically marking -it for @var{export} -to child processes. Executed commands inherit the environment. -The @code{export} and @samp{declare -x} -commands allow parameters and functions to be added to and -deleted from the environment. If the value of a parameter -in the environment is modified, the new value becomes part -of the environment, replacing the old. The environment -inherited by any executed command consists of the shell's -initial environment, whose values may be modified in the shell, -less any pairs removed by the @code{unset} and @samp{export -n} -commands, plus any additions via the @code{export} and -@samp{declare -x} commands. - -The environment for any simple command -or function may be augmented temporarily by prefixing it with -parameter assignments, as described in @ref{Shell Parameters}. -These assignment statements affect only the environment seen -by that command. - -If the @option{-k} option is set (@pxref{The Set Builtin}), then all -parameter assignments are placed in the environment for a command, -not just those that precede the command name. - -When Bash invokes an external command, the variable @samp{$_} -is set to the full pathname of the command and passed to that -command in its environment. - -@node Exit Status -@subsection Exit Status -@cindex exit status - -The exit status of an executed command is the value returned by the -@var{waitpid} system call or equivalent function. Exit statuses -fall between 0 and 255, though, as explained below, the shell may -use values above 125 specially. Exit statuses from shell builtins and -compound commands are also limited to this range. Under certain -circumstances, the shell will use special values to indicate specific -failure modes. - -For the shell's purposes, a command which exits with a -zero exit status has succeeded. -A non-zero exit status indicates failure. -This seemingly counter-intuitive scheme is used so there -is one well-defined way to indicate success and a variety of -ways to indicate various failure modes. -When a command terminates on a fatal signal whose number is @var{N}, -Bash uses the value 128+@var{N} as the exit status. - -If a command is not found, the child process created to -execute it returns a status of 127. If a command is found -but is not executable, the return status is 126. - -If a command fails because of an error during expansion or redirection, -the exit status is greater than zero. - -The exit status is used by the Bash conditional commands -(@pxref{Conditional Constructs}) and some of the list -constructs (@pxref{Lists}). - -All of the Bash builtins return an exit status of zero if they succeed -and a non-zero status on failure, so they may be used by the -conditional and list constructs. -All builtins return an exit status of 2 to indicate incorrect usage. - -@node Signals -@subsection Signals -@cindex signal handling - -When Bash is interactive, in the absence of any traps, it ignores -@code{SIGTERM} (so that @samp{kill 0} does not kill an interactive shell), -and @code{SIGINT} -is caught and handled (so that the @code{wait} builtin is interruptible). -When Bash receives a @code{SIGINT}, it breaks out of any executing loops. -In all cases, Bash ignores @code{SIGQUIT}. -If job control is in effect (@pxref{Job Control}), Bash -ignores @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -Non-builtin commands started by Bash have signal handlers set to the -values inherited by the shell from its parent. -When job control is not in effect, asynchronous commands -ignore @code{SIGINT} and @code{SIGQUIT} in addition to these inherited -handlers. -Commands run as a result of -command substitution ignore the keyboard-generated job control signals -@code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -The shell exits by default upon receipt of a @code{SIGHUP}. -Before exiting, an interactive shell resends the @code{SIGHUP} to -all jobs, running or stopped. -Stopped jobs are sent @code{SIGCONT} to ensure that they receive -the @code{SIGHUP}. -To prevent the shell from sending the @code{SIGHUP} signal to a -particular job, it should be removed -from the jobs table with the @code{disown} -builtin (@pxref{Job Control Builtins}) or marked -to not receive @code{SIGHUP} using @code{disown -h}. - -If the @code{huponexit} shell option has been set with @code{shopt} -(@pxref{The Shopt Builtin}), Bash sends a @code{SIGHUP} to all jobs when -an interactive login shell exits. - -If Bash is waiting for a command to complete and receives a signal -for which a trap has been set, the trap will not be executed until -the command completes. -When Bash is waiting for an asynchronous -command via the @code{wait} builtin, the reception of a signal for -which a trap has been set will cause the @code{wait} builtin to return -immediately with an exit status greater than 128, immediately after -which the trap is executed. - -@node Shell Scripts -@section Shell Scripts -@cindex shell script - -A shell script is a text file containing shell commands. When such -a file is used as the first non-option argument when invoking Bash, -and neither the @option{-c} nor @option{-s} option is supplied -(@pxref{Invoking Bash}), -Bash reads and executes commands from the file, then exits. This -mode of operation creates a non-interactive shell. The shell first -searches for the file in the current directory, and looks in the -directories in @env{$PATH} if not found there. - -When Bash runs -a shell script, it sets the special parameter @code{0} to the name -of the file, rather than the name of the shell, and the positional -parameters are set to the remaining arguments, if any are given. -If no additional arguments are supplied, the positional parameters -are unset. - -A shell script may be made executable by using the @code{chmod} command -to turn on the execute bit. When Bash finds such a file while -searching the @env{$PATH} for a command, it spawns a subshell to -execute it. In other words, executing -@example -filename @var{arguments} -@end example -@noindent -is equivalent to executing -@example -bash filename @var{arguments} -@end example - -@noindent -if @code{filename} is an executable shell script. -This subshell reinitializes itself, so that the effect is as if a -new shell had been invoked to interpret the script, with the -exception that the locations of commands remembered by the parent -(see the description of @code{hash} in @ref{Bourne Shell Builtins}) -are retained by the child. - -Most versions of Unix make this a part of the operating system's command -execution mechanism. If the first line of a script begins with -the two characters @samp{#!}, the remainder of the line specifies -an interpreter for the program. -Thus, you can specify Bash, @code{awk}, Perl, or some other -interpreter and write the rest of the script file in that language. - -The arguments to the interpreter -consist of a single optional argument following the interpreter -name on the first line of the script file, followed by the name of -the script file, followed by the rest of the arguments. Bash -will perform this action on operating systems that do not handle it -themselves. Note that some older versions of Unix limit the interpreter -name and argument to a maximum of 32 characters. - -Bash scripts often begin with @code{#! /bin/bash} (assuming that -Bash has been installed in @file{/bin}), since this ensures that -Bash will be used to interpret the script, even if it is executed -under another shell. - -@node Shell Builtin Commands -@chapter Shell Builtin Commands - -@menu -* Bourne Shell Builtins:: Builtin commands inherited from the Bourne - Shell. -* Bash Builtins:: Table of builtins specific to Bash. -* Modifying Shell Behavior:: Builtins to modify shell attributes and - optional behavior. -* Special Builtins:: Builtin commands classified specially by - POSIX. -@end menu - -Builtin commands are contained within the shell itself. -When the name of a builtin command is used as the first word of -a simple command (@pxref{Simple Commands}), the shell executes -the command directly, without invoking another program. -Builtin commands are necessary to implement functionality impossible -or inconvenient to obtain with separate utilities. - -This section briefly describes the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -Several builtin commands are described in other chapters: builtin -commands which provide the Bash interface to the job control -facilities (@pxref{Job Control Builtins}), the directory stack -(@pxref{Directory Stack Builtins}), the command history -(@pxref{Bash History Builtins}), and the programmable completion -facilities (@pxref{Programmable Completion Builtins}). - -Many of the builtins have been extended by @sc{posix} or Bash. - -Unless otherwise noted, each builtin command documented as accepting -options preceded by @samp{-} accepts @samp{--} -to signify the end of the options. -The @code{:}, @code{true}, @code{false}, and @code{test} -builtins do not accept options and do not treat @samp{--} specially. -The @code{exit}, @code{logout}, @code{break}, @code{continue}, @code{let}, -and @code{shift} builtins accept and process arguments beginning -with @samp{-} without requiring @samp{--}. -Other builtins that accept arguments but are not specified as accepting -options interpret arguments beginning with @samp{-} as invalid options and -require @samp{--} to prevent this interpretation. - -@node Bourne Shell Builtins -@section Bourne Shell Builtins - -The following shell builtin commands are inherited from the Bourne Shell. -These commands are implemented as specified by the @sc{posix} standard. - -@table @code -@item : @r{(a colon)} -@btindex : -@example -: [@var{arguments}] -@end example - -Do nothing beyond expanding @var{arguments} and performing redirections. -The return status is zero. - -@item . @r{(a period)} -@btindex . -@example -. @var{filename} [@var{arguments}] -@end example - -Read and execute commands from the @var{filename} argument in the -current shell context. If @var{filename} does not contain a slash, -the @env{PATH} variable is used to find @var{filename}. -When Bash is not in @sc{posix} mode, the current directory is searched -if @var{filename} is not found in @env{$PATH}. -If any @var{arguments} are supplied, they become the positional -parameters when @var{filename} is executed. Otherwise the positional -parameters are unchanged. -The return status is the exit status of the last command executed, or -zero if no commands are executed. If @var{filename} is not found, or -cannot be read, the return status is non-zero. -This builtin is equivalent to @code{source}. - -@item break -@btindex break -@example -break [@var{n}] -@end example - -Exit from a @code{for}, @code{while}, @code{until}, or @code{select} loop. -If @var{n} is supplied, the @var{n}th enclosing loop is exited. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item cd -@btindex cd -@example -cd [-L|[-P [-e]]] [@var{directory}] -@end example - -Change the current working directory to @var{directory}. -If @var{directory} is not supplied, the value of the @env{HOME} -shell variable is used. -Any additional arguments following @var{directory} are ignored. -If the shell variable -@env{CDPATH} exists, it is used as a search path: -each directory name in @env{CDPATH} is searched for -@var{directory}, with alternative directory names in @env{CDPATH} -separated by a colon (@samp{:}). -If @var{directory} begins with a slash, @env{CDPATH} is not used. - -The @option{-P} option means to not follow symbolic links: symbolic links -are resolved while @code{cd} is traversing @var{directory} and before -processing an instance of @samp{..} in @var{directory}. - -By default, or when the @option{-L} option is supplied, symbolic links -in @var{directory} are resolved after @code{cd} processes an instance -of @samp{..} in @var{directory}. - -If @samp{..} appears in @var{directory}, it is processed by removing the -immediately preceding pathname component, back to a slash or the beginning -of @var{directory}. - -If the @option{-e} option is supplied with @option{-P} -and the current working directory cannot be successfully determined -after a successful directory change, @code{cd} will return an unsuccessful -status. -If @var{directory} is @samp{-}, it is converted to @env{$OLDPWD} -before the directory change is attempted. - -If a non-empty directory name from @env{CDPATH} is used, or if -@samp{-} is the first argument, and the directory change is -successful, the absolute pathname of the new working directory is -written to the standard output. - -The return status is zero if the directory is successfully changed, -non-zero otherwise. - -@item continue -@btindex continue -@example -continue [@var{n}] -@end example - -Resume the next iteration of an enclosing @code{for}, @code{while}, -@code{until}, or @code{select} loop. -If @var{n} is supplied, the execution of the @var{n}th enclosing loop -is resumed. -@var{n} must be greater than or equal to 1. -The return status is zero unless @var{n} is not greater than or equal to 1. - -@item eval -@btindex eval -@example -eval [@var{arguments}] -@end example - -The arguments are concatenated together into a single command, which is -then read and executed, and its exit status returned as the exit status -of @code{eval}. -If there are no arguments or only empty arguments, the return status is -zero. - -@item exec -@btindex exec -@example -exec [-cl] [-a @var{name}] [@var{command} [@var{arguments}]] -@end example - -If @var{command} -is supplied, it replaces the shell without creating a new process. -If the @option{-l} option is supplied, the shell places a dash at the -beginning of the zeroth argument passed to @var{command}. -This is what the @code{login} program does. -The @option{-c} option causes @var{command} to be executed with an empty -environment. -If @option{-a} is supplied, the shell passes @var{name} as the zeroth -argument to @var{command}. -If @var{command} -cannot be executed for some reason, a non-interactive shell exits, -unless the @code{execfail} shell option -is enabled. In that case, it returns failure. -An interactive shell returns failure if the file cannot be executed. -If no @var{command} is specified, redirections may be used to affect -the current shell environment. If there are no redirection errors, the -return status is zero; otherwise the return status is non-zero. - -@item exit -@btindex exit -@example -exit [@var{n}] -@end example - -Exit the shell, returning a status of @var{n} to the shell's parent. -If @var{n} is omitted, the exit status is that of the last command executed. -Any trap on @code{EXIT} is executed before the shell terminates. - -@item export -@btindex export -@example -export [-fn] [-p] [@var{name}[=@var{value}]] -@end example - -Mark each @var{name} to be passed to child processes -in the environment. If the @option{-f} option is supplied, the @var{name}s -refer to shell functions; otherwise the names refer to shell variables. -The @option{-n} option means to no longer mark each @var{name} for export. -If no @var{names} are supplied, or if the @option{-p} option is given, a -list of names of all exported variables is displayed. -The @option{-p} option displays output in a form that may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. - -The return status is zero unless an invalid option is supplied, one of -the names is not a valid shell variable name, or @option{-f} is supplied -with a name that is not a shell function. - -@item getopts -@btindex getopts -@example -getopts @var{optstring} @var{name} [@var{args}] -@end example - -@code{getopts} is used by shell scripts to parse positional parameters. -@var{optstring} contains the option characters to be recognized; if a -character is followed by a colon, the option is expected to have an -argument, which should be separated from it by whitespace. -The colon (@samp{:}) and question mark (@samp{?}) may not be -used as option characters. -Each time it is invoked, @code{getopts} -places the next option in the shell variable @var{name}, initializing -@var{name} if it does not exist, -and the index of the next argument to be processed into the -variable @env{OPTIND}. -@env{OPTIND} is initialized to 1 each time the shell or a shell script -is invoked. -When an option requires an argument, -@code{getopts} places that argument into the variable @env{OPTARG}. -The shell does not reset @env{OPTIND} automatically; it must be manually -reset between multiple calls to @code{getopts} within the same shell -invocation if a new set of parameters is to be used. - -When the end of options is encountered, @code{getopts} exits with a -return value greater than zero. -@env{OPTIND} is set to the index of the first non-option argument, -and @var{name} is set to @samp{?}. - -@code{getopts} -normally parses the positional parameters, but if more arguments are -given in @var{args}, @code{getopts} parses those instead. - -@code{getopts} can report errors in two ways. If the first character of -@var{optstring} is a colon, @var{silent} -error reporting is used. In normal operation, diagnostic messages -are printed when invalid options or missing option arguments are -encountered. -If the variable @env{OPTERR} -is set to 0, no error messages will be displayed, even if the first -character of @code{optstring} is not a colon. - -If an invalid option is seen, -@code{getopts} places @samp{?} into @var{name} and, if not silent, -prints an error message and unsets @env{OPTARG}. -If @code{getopts} is silent, the option character found is placed in -@env{OPTARG} and no diagnostic message is printed. - -If a required argument is not found, and @code{getopts} -is not silent, a question mark (@samp{?}) is placed in @var{name}, -@code{OPTARG} is unset, and a diagnostic message is printed. -If @code{getopts} is silent, then a colon (@samp{:}) is placed in -@var{name} and @env{OPTARG} is set to the option character found. - -@item hash -@btindex hash -@example -hash [-r] [-p @var{filename}] [-dt] [@var{name}] -@end example - -Each time @code{hash} is invoked, it remembers the full pathnames of the -commands specified as @var{name} arguments, -so they need not be searched for on subsequent invocations. -The commands are found by searching through the directories listed in -@env{$PATH}. -Any previously-remembered pathname is discarded. -The @option{-p} option inhibits the path search, and @var{filename} is -used as the location of @var{name}. -The @option{-r} option causes the shell to forget all remembered locations. -The @option{-d} option causes the shell to forget the remembered location -of each @var{name}. -If the @option{-t} option is supplied, the full pathname to which each -@var{name} corresponds is printed. If multiple @var{name} arguments are -supplied with @option{-t} the @var{name} is printed before the hashed -full pathname. -The @option{-l} option causes output to be displayed in a format -that may be reused as input. -If no arguments are given, or if only @option{-l} is supplied, -information about remembered commands is printed. -The return status is zero unless a @var{name} is not found or an invalid -option is supplied. - -@item pwd -@btindex pwd -@example -pwd [-LP] -@end example - -Print the absolute pathname of the current working directory. -If the @option{-P} option is supplied, the pathname printed will not -contain symbolic links. -If the @option{-L} option is supplied, the pathname printed may contain -symbolic links. -The return status is zero unless an error is encountered while -determining the name of the current directory or an invalid option -is supplied. - -@item readonly -@btindex readonly -@example -readonly [-aAf] [-p] [@var{name}[=@var{value}]] @dots{} -@end example - -Mark each @var{name} as readonly. -The values of these names may not be changed by subsequent assignment. -If the @option{-f} option is supplied, each @var{name} refers to a shell -function. -The @option{-a} option means each @var{name} refers to an indexed -array variable; the @option{-A} option means each @var{name} refers -to an associative array variable. -If both options are supplied, @option{-A} takes precedence. -If no @var{name} arguments are given, or if the @option{-p} -option is supplied, a list of all readonly names is printed. -The other options may be used to restrict the output to a subset of -the set of readonly names. -The @option{-p} option causes output to be displayed in a format that -may be reused as input. -If a variable name is followed by =@var{value}, the value of -the variable is set to @var{value}. -The return status is zero unless an invalid option is supplied, one of -the @var{name} arguments is not a valid shell variable or function name, -or the @option{-f} option is supplied with a name that is not a shell function. - -@item return -@btindex return -@example -return [@var{n}] -@end example - -Cause a shell function to stop executing and return the value @var{n} -to its caller. -If @var{n} is not supplied, the return value is the exit status of the -last command executed in the function. -@code{return} may also be used to terminate execution of a script -being executed with the @code{.} (@code{source}) builtin, -returning either @var{n} or -the exit status of the last command executed within the script as the exit -status of the script. -If @var{n} is supplied, the return value is its least significant -8 bits. -Any command associated with the @code{RETURN} trap is executed -before execution resumes after the function or script. -The return status is non-zero if @code{return} is supplied a non-numeric -argument or is used outside a function -and not during the execution of a script by @code{.} or @code{source}. - -@item shift -@btindex shift -@example -shift [@var{n}] -@end example - -Shift the positional parameters to the left by @var{n}. -The positional parameters from @var{n}+1 @dots{} @code{$#} are -renamed to @code{$1} @dots{} @code{$#}-@var{n}. -Parameters represented by the numbers @code{$#} to @code{$#}-@var{n}+1 -are unset. -@var{n} must be a non-negative number less than or equal to @code{$#}. -If @var{n} is zero or greater than @code{$#}, the positional parameters -are not changed. -If @var{n} is not supplied, it is assumed to be 1. -The return status is zero unless @var{n} is greater than @code{$#} or -less than zero, non-zero otherwise. - -@item test[B -@itemx [ -@btindex test -@btindex [ -@example -test @var{expr} -@end example - -Evaluate a conditional expression @var{expr} and return a status of 0 -(true) or 1 (false). -Each operator and operand must be a separate argument. -Expressions are composed of the primaries described below in -@ref{Bash Conditional Expressions}. -@code{test} does not accept any options, nor does it accept and ignore -an argument of @option{--} as signifying the end of options. - -When the @code{[} form is used, the last argument to the command must -be a @code{]}. - -Expressions may be combined using the following operators, listed in -decreasing order of precedence. -The evaluation depends on the number of arguments; see below. -Operator precedence is used when there are five or more arguments. - -@table @code -@item ! @var{expr} -True if @var{expr} is false. - -@item ( @var{expr} ) -Returns the value of @var{expr}. -This may be used to override the normal precedence of operators. - -@item @var{expr1} -a @var{expr2} -True if both @var{expr1} and @var{expr2} are true. - -@item @var{expr1} -o @var{expr2} -True if either @var{expr1} or @var{expr2} is true. -@end table - -The @code{test} and @code{[} builtins evaluate conditional -expressions using a set of rules based on the number of arguments. - -@table @asis -@item 0 arguments -The expression is false. - -@item 1 argument -The expression is true if and only if the argument is not null. - -@item 2 arguments -If the first argument is @samp{!}, the expression is true if and -only if the second argument is null. -If the first argument is one of the unary conditional operators -(@pxref{Bash Conditional Expressions}), the expression -is true if the unary test is true. -If the first argument is not a valid unary operator, the expression is -false. - -@item 3 arguments -The following conditions are applied in the order listed. -If the second argument is one of the binary conditional -operators (@pxref{Bash Conditional Expressions}), the -result of the expression is the result of the binary test using the -first and third arguments as operands. -The @samp{-a} and @samp{-o} operators are considered binary operators -when there are three arguments. -If the first argument is @samp{!}, the value is the negation of -the two-argument test using the second and third arguments. -If the first argument is exactly @samp{(} and the third argument is -exactly @samp{)}, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. - -@item 4 arguments -If the first argument is @samp{!}, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence using the rules listed above. - -@item 5 or more arguments -The expression is parsed and evaluated according to precedence -using the rules listed above. -@end table - -When used with @code{test} or @samp{[}, the @samp{<} and @samp{>} -operators sort lexicographically using ASCII ordering. - -@item times -@btindex times -@example -times -@end example - -Print out the user and system times used by the shell and its children. -The return status is zero. - -@item trap -@btindex trap -@example -trap [-lp] [@var{arg}] [@var{sigspec} @dots{}] -@end example - -The commands in @var{arg} are to be read and executed when the -shell receives signal @var{sigspec}. If @var{arg} is absent (and -there is a single @var{sigspec}) or -equal to @samp{-}, each specified signal's disposition is reset -to the value it had when the shell was started. -If @var{arg} is the null string, then the signal specified by -each @var{sigspec} is ignored by the shell and commands it invokes. -If @var{arg} is not present and @option{-p} has been supplied, -the shell displays the trap commands associated with each @var{sigspec}. -If no arguments are supplied, or -only @option{-p} is given, @code{trap} prints the list of commands -associated with each signal number in a form that may be reused as -shell input. -The @option{-l} option causes the shell to print a list of signal names -and their corresponding numbers. -Each @var{sigspec} is either a signal name or a signal number. -Signal names are case insensitive and the @code{SIG} prefix is optional. - -If a @var{sigspec} -is @code{0} or @code{EXIT}, @var{arg} is executed when the shell exits. -If a @var{sigspec} is @code{DEBUG}, the command @var{arg} is executed -before every simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -Refer to the description of the @code{extdebug} option to the -@code{shopt} builtin (@pxref{The Shopt Builtin}) for details of its -effect on the @code{DEBUG} trap. -If a @var{sigspec} is @code{RETURN}, the command @var{arg} is executed -each time a shell function or a script executed with the @code{.} or -@code{source} builtins finishes executing. - -If a @var{sigspec} is @code{ERR}, the command @var{arg} -is executed whenever a simple command has a non-zero exit status, -subject to the following conditions. -The @code{ERR} trap is not executed if the failed command is part of the -command list immediately following an @code{until} or @code{while} keyword, -part of the test following the @code{if} or @code{elif} reserved words, -part of a command executed in a @code{&&} or @code{||} list, -or if the command's return -status is being inverted using @code{!}. -These are the same conditions obeyed by the @code{errexit} option. - -Signals ignored upon entry to the shell cannot be trapped or reset. -Trapped signals that are not being ignored are reset to their original -values in a subshell or subshell environment when one is created. - -The return status is zero unless a @var{sigspec} does not specify a -valid signal. - -@item umask -@btindex umask -@example -umask [-p] [-S] [@var{mode}] -@end example - -Set the shell process's file creation mask to @var{mode}. If -@var{mode} begins with a digit, it is interpreted as an octal number; -if not, it is interpreted as a symbolic mode mask similar -to that accepted by the @code{chmod} command. If @var{mode} is -omitted, the current value of the mask is printed. If the @option{-S} -option is supplied without a @var{mode} argument, the mask is printed -in a symbolic format. -If the @option{-p} option is supplied, and @var{mode} -is omitted, the output is in a form that may be reused as input. -The return status is zero if the mode is successfully changed or if -no @var{mode} argument is supplied, and non-zero otherwise. - -Note that when the mode is interpreted as an octal number, each number -of the umask is subtracted from @code{7}. Thus, a umask of @code{022} -results in permissions of @code{755}. - -@item unset -@btindex unset -@example -unset [-fnv] [@var{name}] -@end example - -Remove each variable or function @var{name}. -If the @option{-v} option is given, each -@var{name} refers to a shell variable and that variable is remvoved. -If the @option{-f} option is given, the @var{name}s refer to shell -functions, and the function definition is removed. -If the @option{-n} option is supplied, and @var{name} is a variable with -the @var{nameref} attribute, @var{name} will be unset rather than the -variable it references. -@option{-n} has no effect if the @option{-f} option is supplied. -If no options are supplied, each @var{name} refers to a variable; if -there is no variable by that name, any function with that name is -unset. -Readonly variables and functions may not be unset. -The return status is zero unless a @var{name} is readonly. -@end table - -@node Bash Builtins -@section Bash Builtin Commands - -This section describes builtin commands which are unique to -or have been extended in Bash. -Some of these commands are specified in the @sc{posix} standard. - -@table @code - -@item alias -@btindex alias -@example -alias [-p] [@var{name}[=@var{value}] @dots{}] -@end example - -Without arguments or with the @option{-p} option, @code{alias} prints -the list of aliases on the standard output in a form that allows -them to be reused as input. -If arguments are supplied, an alias is defined for each @var{name} -whose @var{value} is given. If no @var{value} is given, the name -and value of the alias is printed. -Aliases are described in @ref{Aliases}. - -@item bind -@btindex bind -@example -bind [-m @var{keymap}] [-lpsvPSVX] -bind [-m @var{keymap}] [-q @var{function}] [-u @var{function}] [-r @var{keyseq}] -bind [-m @var{keymap}] -f @var{filename} -bind [-m @var{keymap}] -x @var{keyseq:shell-command} -bind [-m @var{keymap}] @var{keyseq:function-name} -bind @var{readline-command} -@end example - -Display current Readline (@pxref{Command Line Editing}) -key and function bindings, -bind a key sequence to a Readline function or macro, -or set a Readline variable. -Each non-option argument is a command as it would appear in a -Readline initialization file (@pxref{Readline Init File}), -but each binding or command must be passed as a separate argument; e.g., -@samp{"\C-x\C-r":re-read-init-file}. - -Options, if supplied, have the following meanings: - -@table @code -@item -m @var{keymap} -Use @var{keymap} as the keymap to be affected by -the subsequent bindings. Acceptable @var{keymap} -names are -@code{emacs}, -@code{emacs-standard}, -@code{emacs-meta}, -@code{emacs-ctlx}, -@code{vi}, -@code{vi-move}, -@code{vi-command}, and -@code{vi-insert}. -@code{vi} is equivalent to @code{vi-command}; -@code{emacs} is equivalent to @code{emacs-standard}. - -@item -l -List the names of all Readline functions. - -@item -p -Display Readline function names and bindings in such a way that they -can be used as input or in a Readline initialization file. - -@item -P -List current Readline function names and bindings. - -@item -v -Display Readline variable names and values in such a way that they -can be used as input or in a Readline initialization file. - -@item -V -List current Readline variable names and values. - -@item -s -Display Readline key sequences bound to macros and the strings they output -in such a way that they can be used as input or in a Readline -initialization file. - -@item -S -Display Readline key sequences bound to macros and the strings they output. - -@item -f @var{filename} -Read key bindings from @var{filename}. - -@item -q @var{function} -Query about which keys invoke the named @var{function}. - -@item -u @var{function} -Unbind all keys bound to the named @var{function}. - -@item -r @var{keyseq} -Remove any current binding for @var{keyseq}. - -@item -x @var{keyseq:shell-command} -Cause @var{shell-command} to be executed whenever @var{keyseq} is -entered. -When @var{shell-command} is executed, the shell sets the -@code{READLINE_LINE} variable to the contents of the Readline line -buffer and the @code{READLINE_POINT} variable to the current location -of the insertion point. -If the executed command changes the value of @code{READLINE_LINE} or -@code{READLINE_POINT}, those new values will be reflected in the -editing state. - -@item -X -List all key sequences bound to shell commands and the associated commands -in a format that can be reused as input. -@end table - -@noindent -The return status is zero unless an invalid option is supplied or an -error occurs. - -@item builtin -@btindex builtin -@example -builtin [@var{shell-builtin} [@var{args}]] -@end example - -Run a shell builtin, passing it @var{args}, and return its exit status. -This is useful when defining a shell function with the same -name as a shell builtin, retaining the functionality of the builtin within -the function. -The return status is non-zero if @var{shell-builtin} is not a shell -builtin command. - -@item caller -@btindex caller -@example -caller [@var{expr}] -@end example - -Returns the context of any active subroutine call (a shell function or -a script executed with the @code{.} or @code{source} builtins). - -Without @var{expr}, @code{caller} displays the line number and source -filename of the current subroutine call. -If a non-negative integer is supplied as @var{expr}, @code{caller} -displays the line number, subroutine name, and source file corresponding -to that position in the current execution call stack. This extra -information may be used, for example, to print a stack trace. The -current frame is frame 0. - -The return value is 0 unless the shell is not executing a subroutine -call or @var{expr} does not correspond to a valid position in the -call stack. - -@item command -@btindex command -@example -command [-pVv] @var{command} [@var{arguments} @dots{}] -@end example - -Runs @var{command} with @var{arguments} ignoring any shell function -named @var{command}. -Only shell builtin commands or commands found by searching the -@env{PATH} are executed. -If there is a shell function named @code{ls}, running @samp{command ls} -within the function will execute the external command @code{ls} -instead of calling the function recursively. -The @option{-p} option means to use a default value for @env{PATH} -that is guaranteed to find all of the standard utilities. -The return status in this case is 127 if @var{command} cannot be -found or an error occurred, and the exit status of @var{command} -otherwise. - -If either the @option{-V} or @option{-v} option is supplied, a -description of @var{command} is printed. The @option{-v} option -causes a single word indicating the command or file name used to -invoke @var{command} to be displayed; the @option{-V} option produces -a more verbose description. In this case, the return status is -zero if @var{command} is found, and non-zero if not. - -@item declare -@btindex declare -@example -declare [-aAfFgilnrtux] [-p] [@var{name}[=@var{value}] @dots{}] -@end example - -Declare variables and give them attributes. If no @var{name}s -are given, then display the values of variables instead. - -The @option{-p} option will display the attributes and values of each -@var{name}. -When @option{-p} is used with @var{name} arguments, additional options -are ignored. - -When @option{-p} is supplied without @var{name} arguments, @code{declare} -will display the attributes and values of all variables having the -attributes specified by the additional options. -If no other options are supplied with @option{-p}, @code{declare} will -display the attributes and values of all shell variables. The @option{-f} -option will restrict the display to shell functions. - -The @option{-F} option inhibits the display of function definitions; -only the function name and attributes are printed. -If the @code{extdebug} shell option is enabled using @code{shopt} -(@pxref{The Shopt Builtin}), the source file name and line number where -the function is defined are displayed as well. -@option{-F} implies @option{-f}. - -The @option{-g} option forces variables to be created or modified at -the global scope, even when @code{declare} is executed in a shell function. -It is ignored in all other cases. - -The following options can be used to restrict output to variables with -the specified attributes or to give variables attributes: - -@table @code -@item -a -Each @var{name} is an indexed array variable (@pxref{Arrays}). - -@item -A -Each @var{name} is an associative array variable (@pxref{Arrays}). - -@item -f -Use function names only. - -@item -i -The variable is to be treated as -an integer; arithmetic evaluation (@pxref{Shell Arithmetic}) is -performed when the variable is assigned a value. - -@item -l -When the variable is assigned a value, all upper-case characters are -converted to lower-case. -The upper-case attribute is disabled. - -@item -n -Give each @var{name} the @var{nameref} attribute, making -it a name reference to another variable. -That other variable is defined by the value of @var{name}. -All references and assignments to @var{name}, except for changing the -@option{-n} attribute itself, are performed on the variable referenced by -@var{name}'s value. -The @option{-n} attribute cannot be applied to array variables. - -@item -r -Make @var{name}s readonly. These names cannot then be assigned values -by subsequent assignment statements or unset. - -@item -t -Give each @var{name} the @code{trace} attribute. -Traced functions inherit the @code{DEBUG} and @code{RETURN} traps from -the calling shell. -The trace attribute has no special meaning for variables. - -@item -u -When the variable is assigned a value, all lower-case characters are -converted to upper-case. -The lower-case attribute is disabled. - -@item -x -Mark each @var{name} for export to subsequent commands via -the environment. -@end table - -Using @samp{+} instead of @samp{-} turns off the attribute instead, -with the exceptions that @samp{+a} -may not be used to destroy an array variable and @samp{+r} will not -remove the readonly attribute. -When used in a function, @code{declare} makes each @var{name} local, -as with the @code{local} command, unless the @option{-g} option is used. -If a variable name is followed by =@var{value}, the value of the variable -is set to @var{value}. - -The return status is zero unless an invalid option is encountered, -an attempt is made to define a function using @samp{-f foo=bar}, -an attempt is made to assign a value to a readonly variable, -an attempt is made to assign a value to an array variable without -using the compound assignment syntax (@pxref{Arrays}), -one of the @var{names} is not a valid shell variable name, -an attempt is made to turn off readonly status for a readonly variable, -an attempt is made to turn off array status for an array variable, -or an attempt is made to display a non-existent function with @option{-f}. - -@item echo -@btindex echo -@example -echo [-neE] [@var{arg} @dots{}] -@end example - -Output the @var{arg}s, separated by spaces, terminated with a -newline. -The return status is 0 unless a write error occurs. -If @option{-n} is specified, the trailing newline is suppressed. -If the @option{-e} option is given, interpretation of the following -backslash-escaped characters is enabled. -The @option{-E} option disables the interpretation of these escape characters, -even on systems where they are interpreted by default. -The @code{xpg_echo} shell option may be used to -dynamically determine whether or not @code{echo} expands these -escape characters by default. -@code{echo} does not interpret @option{--} to mean the end of options. - -@code{echo} interprets the following escape sequences: -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \c -suppress further output -@item \e -@itemx \E -escape -@item \f -form feed -@item \n -new line -@item \r -carriage return -@item \t -horizontal tab -@item \v -vertical tab -@item \\ -backslash -@item \0@var{nnn} -the eight-bit character whose value is the octal value @var{nnn} -(zero to three octal digits) -@item \x@var{HH} -the eight-bit character whose value is the hexadecimal value @var{HH} -(one or two hex digits) -@item \u@var{HHHH} -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -@var{HHHH} (one to four hex digits) -@item \U@var{HHHHHHHH} -the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value -@var{HHHHHHHH} (one to eight hex digits) -@end table - -@item enable -@btindex enable -@example -enable [-a] [-dnps] [-f @var{filename}] [@var{name} @dots{}] -@end example - -Enable and disable builtin shell commands. -Disabling a builtin allows a disk command which has the same name -as a shell builtin to be executed without specifying a full pathname, -even though the shell normally searches for builtins before disk commands. -If @option{-n} is used, the @var{name}s become disabled. Otherwise -@var{name}s are enabled. For example, to use the @code{test} binary -found via @env{$PATH} instead of the shell builtin version, type -@samp{enable -n test}. - -If the @option{-p} option is supplied, or no @var{name} arguments appear, -a list of shell builtins is printed. With no other arguments, the list -consists of all enabled shell builtins. -The @option{-a} option means to list -each builtin with an indication of whether or not it is enabled. - -The @option{-f} option means to load the new builtin command @var{name} -from shared object @var{filename}, on systems that support dynamic loading. -The @option{-d} option will delete a builtin loaded with @option{-f}. - -If there are no options, a list of the shell builtins is displayed. -The @option{-s} option restricts @code{enable} to the @sc{posix} special -builtins. If @option{-s} is used with @option{-f}, the new builtin becomes -a special builtin (@pxref{Special Builtins}). - -The return status is zero unless a @var{name} is not a shell builtin -or there is an error loading a new builtin from a shared object. - -@item help -@btindex help -@example -help [-dms] [@var{pattern}] -@end example - -Display helpful information about builtin commands. -If @var{pattern} is specified, @code{help} gives detailed help -on all commands matching @var{pattern}, otherwise a list of -the builtins is printed. - -Options, if supplied, have the following meanings: - -@table @code -@item -d -Display a short description of each @var{pattern} -@item -m -Display the description of each @var{pattern} in a manpage-like format -@item -s -Display only a short usage synopsis for each @var{pattern} -@end table - -The return status is zero unless no command matches @var{pattern}. - -@item let -@btindex let -@example -let @var{expression} [@var{expression} @dots{}] -@end example - -The @code{let} builtin allows arithmetic to be performed on shell -variables. Each @var{expression} is evaluated according to the -rules given below in @ref{Shell Arithmetic}. If the -last @var{expression} evaluates to 0, @code{let} returns 1; -otherwise 0 is returned. - -@item local -@btindex local -@example -local [@var{option}] @var{name}[=@var{value}] @dots{} -@end example - -For each argument, a local variable named @var{name} is created, -and assigned @var{value}. -The @var{option} can be any of the options accepted by @code{declare}. -@code{local} can only be used within a function; it makes the variable -@var{name} have a visible scope restricted to that function and its -children. The return status is zero unless @code{local} is used outside -a function, an invalid @var{name} is supplied, or @var{name} is a -readonly variable. - -@item logout -@btindex logout -@example -logout [@var{n}] -@end example - -Exit a login shell, returning a status of @var{n} to the shell's -parent. - -@item mapfile -@btindex mapfile -@example -mapfile [-n @var{count}] [-O @var{origin}] [-s @var{count}] [-t] [-u @var{fd}] - [-C @var{callback}] [-c @var{quantum}] [@var{array}] -@end example - -Read lines from the standard input into the indexed array variable @var{array}, -or from file descriptor @var{fd} -if the @option{-u} option is supplied. -The variable @code{MAPFILE} is the default @var{array}. -Options, if supplied, have the following meanings: - -@table @code - -@item -n -Copy at most @var{count} lines. If @var{count} is 0, all lines are copied. -@item -O -Begin assigning to @var{array} at index @var{origin}. -The default index is 0. -@item -s -Discard the first @var{count} lines read. -@item -t -Remove a trailing newline from each line read. -@item -u -Read lines from file descriptor @var{fd} instead of the standard input. -@item -C -Evaluate @var{callback} each time @var{quantum}P lines are read. -The @option{-c} option specifies @var{quantum}. -@item -c -Specify the number of lines read between each call to @var{callback}. -@end table - -If @option{-C} is specified without @option{-c}, -the default quantum is 5000. -When @var{callback} is evaluated, it is supplied the index of the next -array element to be assigned and the line to be assigned to that element -as additional arguments. -@var{callback} is evaluated after the line is read but before the -array element is assigned. - -If not supplied with an explicit origin, @code{mapfile} will clear @var{array} -before assigning to it. - -@code{mapfile} returns successfully unless an invalid option or option -argument is supplied, @var{array} is invalid or unassignable, or @var{array} -is not an indexed array. - -@item printf -@btindex printf -@example -printf [-v @var{var}] @var{format} [@var{arguments}] -@end example - -Write the formatted @var{arguments} to the standard output under the -control of the @var{format}. -The @option{-v} option causes the output to be assigned to the variable -@var{var} rather than being printed to the standard output. - -The @var{format} is a character string which contains three types of objects: -plain characters, which are simply copied to standard output, character -escape sequences, which are converted and copied to the standard output, and -format specifications, each of which causes printing of the next successive -@var{argument}. -In addition to the standard @code{printf(1)} formats, @code{printf} -interprets the following extensions: - -@table @code -@item %b -Causes @code{printf} to expand backslash escape sequences in the -corresponding @var{argument}, -except that @samp{\c} terminates output, backslashes in -@samp{\'}, @samp{\"}, and @samp{\?} are not removed, and octal escapes -beginning with @samp{\0} may contain up to four digits. -@item %q -Causes @code{printf} to output the -corresponding @var{argument} in a format that can be reused as shell input. -@item %(@var{datefmt})T -Causes @code{printf} to output the date-time string resulting from using -@var{datefmt} as a format string for @code{strftime}(3). The corresponding -@var{argument} is an integer representing the number of seconds since the -epoch. Two special argument values may be used: -1 represents the current -time, and -2 represents the time the shell was invoked. -@end table - -@noindent -Arguments to non-string format specifiers are treated as C language constants, -except that a leading plus or minus sign is allowed, and if the leading -character is a single or double quote, the value is the ASCII value of -the following character. - -The @var{format} is reused as necessary to consume all of the @var{arguments}. -If the @var{format} requires more @var{arguments} than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. - -@item read -@btindex read -@example -read [-ers] [-a @var{aname}] [-d @var{delim}] [-i @var{text}] [-n @var{nchars}] - [-N @var{nchars}] [-p @var{prompt}] [-t @var{timeout}] [-u @var{fd}] [@var{name} @dots{}] -@end example - -One line is read from the standard input, or from the file descriptor -@var{fd} supplied as an argument to the @option{-u} option, and the first word -is assigned to the first @var{name}, the second word to the second @var{name}, -and so on, with leftover words and their intervening separators assigned -to the last @var{name}. -If there are fewer words read from the input stream than names, -the remaining names are assigned empty values. -The characters in the value of the @env{IFS} variable -are used to split the line into words. -The backslash character @samp{\} may be used to remove any special -meaning for the next character read and for line continuation. -If no names are supplied, the line read is assigned to the -variable @env{REPLY}. -The return code is zero, unless end-of-file is encountered, @code{read} -times out (in which case the return code is greater than 128), -a variable assignment error (such as assigning to a readonly variable) occurs, -or an invalid file descriptor is supplied as the argument to @option{-u}. - -Options, if supplied, have the following meanings: - -@table @code -@item -a @var{aname} -The words are assigned to sequential indices of the array variable -@var{aname}, starting at 0. -All elements are removed from @var{aname} before the assignment. -Other @var{name} arguments are ignored. - -@item -d @var{delim} -The first character of @var{delim} is used to terminate the input line, -rather than newline. - -@item -e -Readline (@pxref{Command Line Editing}) is used to obtain the line. -Readline uses the current (or default, if line editing was not previously -active) editing settings. - -@item -i @var{text} -If Readline is being used to read the line, @var{text} is placed into -the editing buffer before editing begins. - -@item -n @var{nchars} -@code{read} returns after reading @var{nchars} characters rather than -waiting for a complete line of input, but honor a delimiter if fewer -than @var{nchars} characters are read before the delimiter. - -@item -N @var{nchars} -@code{read} returns after reading exactly @var{nchars} characters rather -than waiting for a complete line of input, unless EOF is encountered or -@code{read} times out. -Delimiter characters encountered in the input are -not treated specially and do not cause @code{read} to return until -@var{nchars} characters are read. - -@item -p @var{prompt} -Display @var{prompt}, without a trailing newline, before attempting -to read any input. -The prompt is displayed only if input is coming from a terminal. - -@item -r -If this option is given, backslash does not act as an escape character. -The backslash is considered to be part of the line. -In particular, a backslash-newline pair may not be used as a line -continuation. - -@item -s -Silent mode. If input is coming from a terminal, characters are -not echoed. - -@item -t @var{timeout} -Cause @code{read} to time out and return failure if a complete line of -input is not read within @var{timeout} seconds. -@var{timeout} may be a decimal number with a fractional portion following -the decimal point. -This option is only effective if @code{read} is reading input from a -terminal, pipe, or other special file; it has no effect when reading -from regular files. -If @var{timeout} is 0, @code{read} returns immediately, without trying to -read and data. The exit status is 0 if input is available on -the specified file descriptor, non-zero otherwise. -The exit status is greater than 128 if the timeout is exceeded. - -@item -u @var{fd} -Read input from file descriptor @var{fd}. -@end table - -@item readarray -@btindex readarray -@example -readarray [-n @var{count}] [-O @var{origin}] [-s @var{count}] [-t] [-u @var{fd}] - [-C @var{callback}] [-c @var{quantum}] [@var{array}] -@end example - -Read lines from the standard input into the indexed array variable @var{array}, -or from file descriptor @var{fd} -if the @option{-u} option is supplied. - -A synonym for @code{mapfile}. - -@item source -@btindex source -@example -source @var{filename} -@end example - -A synonym for @code{.} (@pxref{Bourne Shell Builtins}). - -@item type -@btindex type -@example -type [-afptP] [@var{name} @dots{}] -@end example - -For each @var{name}, indicate how it would be interpreted if used as a -command name. - -If the @option{-t} option is used, @code{type} prints a single word -which is one of @samp{alias}, @samp{function}, @samp{builtin}, -@samp{file} or @samp{keyword}, -if @var{name} is an alias, shell function, shell builtin, -disk file, or shell reserved word, respectively. -If the @var{name} is not found, then nothing is printed, and -@code{type} returns a failure status. - -If the @option{-p} option is used, @code{type} either returns the name -of the disk file that would be executed, or nothing if @option{-t} -would not return @samp{file}. - -The @option{-P} option forces a path search for each @var{name}, even if -@option{-t} would not return @samp{file}. - -If a command is hashed, @option{-p} and @option{-P} print the hashed value, -which is not necessarily the file that appears first in @code{$PATH}. - -If the @option{-a} option is used, @code{type} returns all of the places -that contain an executable named @var{file}. -This includes aliases and functions, if and only if the @option{-p} option -is not also used. - -If the @option{-f} option is used, @code{type} does not attempt to find -shell functions, as with the @code{command} builtin. - -The return status is zero if all of the @var{names} are found, non-zero -if any are not found. - -@item typeset -@btindex typeset -@example -typeset [-afFgrxilnrtux] [-p] [@var{name}[=@var{value}] @dots{}] -@end example - -The @code{typeset} command is supplied for compatibility with the Korn -shell. -It is a synonym for the @code{declare} builtin command. - -@item ulimit -@btindex ulimit -@example -ulimit [-abcdefilmnpqrstuvxHST] [@var{limit}] -@end example - -@code{ulimit} provides control over the resources available to processes -started by the shell, on systems that allow such control. If an -option is given, it is interpreted as follows: - -@table @code -@item -S -Change and report the soft limit associated with a resource. - -@item -H -Change and report the hard limit associated with a resource. - -@item -a -All current limits are reported. - -@item -b -The maximum socket buffer size. - -@item -c -The maximum size of core files created. - -@item -d -The maximum size of a process's data segment. - -@item -e -The maximum scheduling priority ("nice"). - -@item -f -The maximum size of files written by the shell and its children. - -@item -i -The maximum number of pending signals. - -@item -l -The maximum size that may be locked into memory. - -@item -m -The maximum resident set size (many systems do not honor this limit). - -@item -n -The maximum number of open file descriptors (most systems do not -allow this value to be set). - -@item -p -The pipe buffer size. - -@item -q -The maximum number of bytes in POSIX message queues. - -@item -r -The maximum real-time scheduling priority. - -@item -s -The maximum stack size. - -@item -t -The maximum amount of cpu time in seconds. - -@item -u -The maximum number of processes available to a single user. - -@item -v -The maximum amount of virtual memory available to the shell, and, on -some systems, to its children. - -@item -x -The maximum number of file locks. - -@item -T -The maximum number of threads. -@end table - -If @var{limit} is given, and the @option{-a} option is not used, -@var{limit} is the new value of the specified resource. -The special @var{limit} values @code{hard}, @code{soft}, and -@code{unlimited} stand for the current hard limit, the current soft limit, -and no limit, respectively. -A hard limit cannot be increased by a non-root user once it is set; -a soft limit may be increased up to the value of the hard limit. -Otherwise, the current value of the soft limit for the specified resource -is printed, unless the @option{-H} option is supplied. -When setting new limits, if neither @option{-H} nor @option{-S} is supplied, -both the hard and soft limits are set. -If no option is given, then @option{-f} is assumed. Values are in 1024-byte -increments, except for @option{-t}, which is in seconds; @option{-p}, -which is in units of 512-byte blocks; and @option{-T}, @option{-b}, -@option{-n} and @option{-u}, which are unscaled values. - -The return status is zero unless an invalid option or argument is supplied, -or an error occurs while setting a new limit. - -@item unalias -@btindex unalias -@example -unalias [-a] [@var{name} @dots{} ] -@end example - -Remove each @var{name} from the list of aliases. If @option{-a} is -supplied, all aliases are removed. -Aliases are described in @ref{Aliases}. -@end table - -@node Modifying Shell Behavior -@section Modifying Shell Behavior - -@menu -* The Set Builtin:: Change the values of shell attributes and - positional parameters. -* The Shopt Builtin:: Modify shell optional behavior. -@end menu - -@node The Set Builtin -@subsection The Set Builtin - -This builtin is so complicated that it deserves its own section. @code{set} -allows you to change the values of shell options and set the positional -parameters, or to display the names and values of shell variables. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCEHPT] [-o @var{option-name}] [@var{argument} @dots{}] -set [+abefhkmnptuvxBCEHPT] [+o @var{option-name}] [@var{argument} @dots{}] -@end example - -If no options or arguments are supplied, @code{set} displays the names -and values of all shell variables and functions, sorted according to the -current locale, in a format that may be reused as input -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In @sc{posix} mode, only shell variables are listed. - -When options are supplied, they set or unset shell attributes. -Options, if specified, have the following meanings: - -@table @code -@item -a -Mark variables and function which are modified or created for export -to the environment of subsequent commands. - -@item -b -Cause the status of terminated background jobs to be reported -immediately, rather than before printing the next primary prompt. - -@item -e -Exit immediately if -a pipeline (@pxref{Pipelines}), which may consist of a single simple command -(@pxref{Simple Commands}), -a list (@pxref{Lists}), -or a compound command (@pxref{Compound Commands}) -returns a non-zero status. -The shell does not exit if the command that fails is part of the -command list immediately following a @code{while} or @code{until} keyword, -part of the test in an @code{if} statement, -part of any command executed in a @code{&&} or @code{||} list except -the command following the final @code{&&} or @code{||}, -any command in a pipeline but the last, -or if the command's return status is being inverted with @code{!}. -If a compound command other than a subshell -returns a non-zero status because a command failed -while @option{-e} was being ignored, the shell does not exit. -A trap on @code{ERR}, if set, is executed before the shell exits. - -This option applies to the shell environment and each subshell environment -separately (@pxref{Command Execution Environment}), and may cause -subshells to exit before executing all the commands in the subshell. - -@item -f -Disable filename expansion (globbing). - -@item -h -Locate and remember (hash) commands as they are looked up for execution. -This option is enabled by default. - -@item -k -All arguments in the form of assignment statements are placed -in the environment for a command, not just those that precede -the command name. - -@item -m -Job control is enabled (@pxref{Job Control}). -All processes run in a separate process group. -When a background job completes, the shell prints a line -containing its exit status. - -@item -n -Read commands but do not execute them; this may be used to check a -script for syntax errors. -This option is ignored by interactive shells. - -@item -o @var{option-name} - -Set the option corresponding to @var{option-name}: - -@table @code -@item allexport -Same as @code{-a}. - -@item braceexpand -Same as @code{-B}. - -@item emacs -Use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). -This also affects the editing interface used for @code{read -e}. - -@item errexit -Same as @code{-e}. - -@item errtrace -Same as @code{-E}. - -@item functrace -Same as @code{-T}. - -@item hashall -Same as @code{-h}. - -@item histexpand -Same as @code{-H}. - -@item history -Enable command history, as described in @ref{Bash History Facilities}. -This option is on by default in interactive shells. - -@item ignoreeof -An interactive shell will not exit upon reading EOF. - -@item keyword -Same as @code{-k}. - -@item monitor -Same as @code{-m}. - -@item noclobber -Same as @code{-C}. - -@item noexec -Same as @code{-n}. - -@item noglob -Same as @code{-f}. - -@item nolog -Currently ignored. - -@item notify -Same as @code{-b}. - -@item nounset -Same as @code{-u}. - -@item onecmd -Same as @code{-t}. - -@item physical -Same as @code{-P}. - -@item pipefail -If set, the return value of a pipeline is the value of the last -(rightmost) command to exit with a non-zero status, or zero if all -commands in the pipeline exit successfully. -This option is disabled by default. - -@item posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} standard to match the standard -(@pxref{Bash POSIX Mode}). -This is intended to make Bash behave as a strict superset of that -standard. - -@item privileged -Same as @code{-p}. - -@item verbose -Same as @code{-v}. - -@item vi -Use a @code{vi}-style line editing interface. -This also affects the editing interface used for @code{read -e}. - -@item xtrace -Same as @code{-x}. -@end table - -@item -p -Turn on privileged mode. -In this mode, the @env{$BASH_ENV} and @env{$ENV} files are not -processed, shell functions are not inherited from the environment, -and the @env{SHELLOPTS}, @env{BASHOPTS}, @env{CDPATH} and @env{GLOBIGNORE} -variables, if they appear in the environment, are ignored. -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the @option{-p} option is not supplied, these actions -are taken and the effective user id is set to the real user id. -If the @option{-p} option is supplied at startup, the effective user id is -not reset. -Turning this option off causes the effective user -and group ids to be set to the real user and group ids. - -@item -t -Exit after reading and executing one command. - -@item -u -Treat unset variables and parameters other than the special parameters -@samp{@@} or @samp{*} as an error when performing parameter expansion. -An error message will be written to the standard error, and a non-interactive -shell will exit. - -@item -v -Print shell input lines as they are read. - -@item -x -Print a trace of simple commands, @code{for} commands, @code{case} -commands, @code{select} commands, and arithmetic @code{for} commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -the command and its expanded arguments. - -@item -B -The shell will perform brace expansion (@pxref{Brace Expansion}). -This option is on by default. - -@item -C -Prevent output redirection using @samp{>}, @samp{>&}, and @samp{<>} -from overwriting existing files. - -@item -E -If set, any trap on @code{ERR} is inherited by shell functions, command -substitutions, and commands executed in a subshell environment. -The @code{ERR} trap is normally not inherited in such cases. - -@item -H -Enable @samp{!} style history substitution (@pxref{History Interaction}). -This option is on by default for interactive shells. - -@item -P -If set, do not resolve symbolic links when performing commands such as -@code{cd} which change the current directory. The physical directory -is used instead. By default, Bash follows -the logical chain of directories when performing commands -which change the current directory. - -For example, if @file{/usr/sys} is a symbolic link to @file{/usr/local/sys} -then: -@example -$ cd /usr/sys; echo $PWD -/usr/sys -$ cd ..; pwd -/usr -@end example - -@noindent -If @code{set -P} is on, then: -@example -$ cd /usr/sys; echo $PWD -/usr/local/sys -$ cd ..; pwd -/usr/local -@end example - -@item -T -If set, any trap on @code{DEBUG} and @code{RETURN} are inherited by -shell functions, command substitutions, and commands executed -in a subshell environment. -The @code{DEBUG} and @code{RETURN} traps are normally not inherited -in such cases. - -@item -- -If no arguments follow this option, then the positional parameters are -unset. Otherwise, the positional parameters are set to the -@var{arguments}, even if some of them begin with a @samp{-}. - -@item - -Signal the end of options, cause all remaining @var{arguments} -to be assigned to the positional parameters. The @option{-x} -and @option{-v} options are turned off. -If there are no arguments, the positional parameters remain unchanged. -@end table - -Using @samp{+} rather than @samp{-} causes these options to be -turned off. The options can also be used upon invocation of the -shell. The current set of options may be found in @code{$-}. - -The remaining N @var{arguments} are positional parameters and are -assigned, in order, to @code{$1}, @code{$2}, @dots{} @code{$N}. -The special parameter @code{#} is set to N. - -The return status is always zero unless an invalid option is supplied. -@end table - -@node The Shopt Builtin -@subsection The Shopt Builtin - -This builtin allows you to change additional shell optional behavior. - -@table @code - -@item shopt -@btindex shopt -@example -shopt [-pqsu] [-o] [@var{optname} @dots{}] -@end example - -Toggle the values of variables controlling optional shell behavior. -With no options, or with the @option{-p} option, a list of all settable -options is displayed, with an indication of whether or not each is set. -The @option{-p} option causes output to be displayed in a form that -may be reused as input. -Other options have the following meanings: - -@table @code -@item -s -Enable (set) each @var{optname}. - -@item -u -Disable (unset) each @var{optname}. - -@item -q -Suppresses normal output; the return status -indicates whether the @var{optname} is set or unset. -If multiple @var{optname} arguments are given with @option{-q}, -the return status is zero if all @var{optnames} are enabled; -non-zero otherwise. - -@item -o -Restricts the values of -@var{optname} to be those defined for the @option{-o} option to the -@code{set} builtin (@pxref{The Set Builtin}). -@end table - -If either @option{-s} or @option{-u} -is used with no @var{optname} arguments, @code{shopt} shows only -those options which are set or unset, respectively. - -Unless otherwise noted, the @code{shopt} options are disabled (off) -by default. - -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an @var{optname} is not a valid shell -option. - -The list of @code{shopt} options is: -@table @code - -@item autocd -If set, a command name that is the name of a directory is executed as if -it were the argument to the @code{cd} command. -This option is only used by interactive shells. - -@item cdable_vars -If this is set, an argument to the @code{cd} builtin command that -is not a directory is assumed to be the name of a variable whose -value is the directory to change to. - -@item cdspell -If set, minor errors in the spelling of a directory component in a -@code{cd} command will be corrected. -The errors checked for are transposed characters, -a missing character, and a character too many. -If a correction is found, the corrected path is printed, -and the command proceeds. -This option is only used by interactive shells. - -@item checkhash -If this is set, Bash checks that a command found in the hash -table exists before trying to execute it. If a hashed command no -longer exists, a normal path search is performed. - -@item checkjobs -If set, Bash lists the status of any stopped and running jobs before -exiting an interactive shell. If any jobs are running, this causes -the exit to be deferred until a second exit is attempted without an -intervening command (@pxref{Job Control}). -The shell always postpones exiting if any jobs are stopped. - -@item checkwinsize -If set, Bash checks the window size after each command - and, if necessary, updates the values of -@env{LINES} and @env{COLUMNS}. - -@item cmdhist -If set, Bash -attempts to save all lines of a multiple-line -command in the same history entry. This allows -easy re-editing of multi-line commands. - -@item compat31 -If set, Bash -changes its behavior to that of version 3.1 with respect to quoted -arguments to the conditional command's @samp{=~} operator -and with respect to locale-specific -string comparison when using the @samp{[[} -conditional command's @samp{<} and @samp{>} operators. -Bash versions prior to bash-4.1 use ASCII collation and strcmp(3); -bash-4.1 and later use the current locale's collation sequence and strcoll(3). - -@item compat32 -If set, Bash -changes its behavior to that of version 3.2 with respect to locale-specific -string comparison when using the @samp{[[} -conditional command's @samp{<} and @samp{>} operators (see previous item). - -@item compat40 -If set, Bash -changes its behavior to that of version 4.0 with respect to locale-specific -string comparison when using the @samp{[[} -conditional command's @samp{<} and @samp{>} operators (see description -of @code{compat31}) -and the effect of interrupting a command list. -Bash versions 4.0 and later interrupt the list as if the shell received the -interrupt; previous versions continue with the next command in the list. - -@item compat41 -If set, Bash, when in posix mode, treats a single quote in a double-quoted -parameter expansion as a special character. The single quotes must match -(an even number) and the characters between the single quotes are considered -quoted. This is the behavior of @sc{posix} mode through version 4.1. -The default Bash behavior remains as in previous versions. - -@item complete_fullquote -If set, Bash -quotes all shell metacharacters in filenames and directory names when -performing completion. -If not set, Bash -removes metacharacters such as the dollar sign from the set of -characters that will be quoted in completed filenames -when these metacharacters appear in shell variable references in words to be -completed. -This means that dollar signs in variable names that expand to directories -will not be quoted; -however, any dollar signs appearing in filenames will not be quoted, either. -This is active only when bash is using backslashes to quote completed -filenames. -This variable is set by default, which is the default Bash behavior in -versions through 4.2. - -@item direxpand -If set, Bash -replaces directory names with the results of word expansion when performing -filename completion. This changes the contents of the readline editing -buffer. -If not set, Bash attempts to preserve what the user typed. - -@item dirspell -If set, Bash -attempts spelling correction on directory names during word completion -if the directory name initially supplied does not exist. - -@item dotglob -If set, Bash includes filenames beginning with a `.' in -the results of filename expansion. - -@item execfail -If this is set, a non-interactive shell will not exit if -it cannot execute the file specified as an argument to the @code{exec} -builtin command. An interactive shell does not exit if @code{exec} -fails. - -@item expand_aliases -If set, aliases are expanded as described below under Aliases, -@ref{Aliases}. -This option is enabled by default for interactive shells. - -@item extdebug -If set, behavior intended for use by debuggers is enabled: - -@enumerate -@item -The @option{-F} option to the @code{declare} builtin (@pxref{Bash Builtins}) -displays the source file name and line number corresponding to each function -name supplied as an argument. - -@item -If the command run by the @code{DEBUG} trap returns a non-zero value, the -next command is skipped and not executed. - -@item -If the command run by the @code{DEBUG} trap returns a value of 2, and the -shell is executing in a subroutine (a shell function or a shell script -executed by the @code{.} or @code{source} builtins), a call to -@code{return} is simulated. - -@item -@code{BASH_ARGC} and @code{BASH_ARGV} are updated as described in their -descriptions (@pxref{Bash Variables}). - -@item -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{DEBUG} and @code{RETURN} traps. - -@item -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{ERR} trap. -@end enumerate - -@item extglob -If set, the extended pattern matching features described above -(@pxref{Pattern Matching}) are enabled. - -@item extquote -If set, @code{$'@var{string}'} and @code{$"@var{string}"} quoting is -performed within @code{$@{@var{parameter}@}} expansions -enclosed in double quotes. This option is enabled by default. - -@item failglob -If set, patterns which fail to match filenames during filename expansion -result in an expansion error. - -@item force_fignore -If set, the suffixes specified by the @env{FIGNORE} shell variable -cause words to be ignored when performing word completion even if -the ignored words are the only possible completions. -@xref{Bash Variables}, for a description of @env{FIGNORE}. -This option is enabled by default. - -@item globasciiranges -If set, range expressions used in pattern matching (@pxref{Pattern Matching}) -behave as if in the traditional C locale when performing -comparisons. That is, the current locale's collating sequence -is not taken into account, so -@samp{b} will not collate between @samp{A} and @samp{B}, -and upper-case and lower-case ASCII characters will collate together. - -@item globstar -If set, the pattern @samp{**} used in a filename expansion context will -match all files and zero or more directories and subdirectories. -If the pattern is followed by a @samp{/}, only directories and -subdirectories match. - -@item gnu_errfmt -If set, shell error messages are written in the standard @sc{gnu} error -message format. - -@item histappend -If set, the history list is appended to the file named by the value -of the @env{HISTFILE} -variable when the shell exits, rather than overwriting the file. - -@item histreedit -If set, and Readline -is being used, a user is given the opportunity to re-edit a -failed history substitution. - -@item histverify -If set, and Readline -is being used, the results of history substitution are not immediately -passed to the shell parser. Instead, the resulting line is loaded into -the Readline editing buffer, allowing further modification. - -@item hostcomplete -If set, and Readline is being used, Bash will attempt to perform -hostname completion when a word containing a @samp{@@} is being -completed (@pxref{Commands For Completion}). This option is enabled -by default. - -@item huponexit -If set, Bash will send @code{SIGHUP} to all jobs when an interactive -login shell exits (@pxref{Signals}). - -@item interactive_comments -Allow a word beginning with @samp{#} -to cause that word and all remaining characters on that -line to be ignored in an interactive shell. -This option is enabled by default. - -@item lastpipe -If set, and job control is not active, the shell runs the last command of -a pipeline not executed in the background in the current shell environment. - -@item lithist -If enabled, and the @code{cmdhist} -option is enabled, multi-line commands are saved to the history with -embedded newlines rather than using semicolon separators where possible. - -@item login_shell -The shell sets this option if it is started as a login shell -(@pxref{Invoking Bash}). -The value may not be changed. - -@item mailwarn -If set, and a file that Bash is checking for mail has been -accessed since the last time it was checked, the message -@code{"The mail in @var{mailfile} has been read"} is displayed. - -@item no_empty_cmd_completion -If set, and Readline is being used, Bash will not attempt to search -the @env{PATH} for possible completions when completion is attempted -on an empty line. - -@item nocaseglob -If set, Bash matches filenames in a case-insensitive fashion when -performing filename expansion. - -@item nocasematch -If set, Bash matches patterns in a case-insensitive fashion when -performing matching while executing @code{case} or @code{[[} -conditional commands. - -@item nullglob -If set, Bash allows filename patterns which match no -files to expand to a null string, rather than themselves. - -@item progcomp -If set, the programmable completion facilities -(@pxref{Programmable Completion}) are enabled. -This option is enabled by default. - -@item promptvars -If set, prompt strings undergo -parameter expansion, command substitution, arithmetic -expansion, and quote removal after being expanded -as described below (@pxref{Controlling the Prompt}). -This option is enabled by default. - -@item restricted_shell -The shell sets this option if it is started in restricted mode -(@pxref{The Restricted Shell}). -The value may not be changed. -This is not reset when the startup files are executed, allowing -the startup files to discover whether or not a shell is restricted. - -@item shift_verbose -If this is set, the @code{shift} -builtin prints an error message when the shift count exceeds the -number of positional parameters. - -@item sourcepath -If set, the @code{source} builtin uses the value of @env{PATH} -to find the directory containing the file supplied as an argument. -This option is enabled by default. - -@item xpg_echo -If set, the @code{echo} builtin expands backslash-escape sequences -by default. - -@end table - -@noindent -The return status when listing options is zero if all @var{optnames} -are enabled, non-zero otherwise. -When setting or unsetting options, the return status is zero unless an -@var{optname} is not a valid shell option. -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} standard has classified -several builtin commands as @emph{special}. -When Bash is executing in @sc{posix} mode, the special builtins -differ from other builtin commands in three respects: - -@enumerate -@item -Special builtins are found before shell functions during command lookup. - -@item -If a special builtin returns an error status, a non-interactive shell exits. - -@item -Assignment statements preceding the command stay in effect in the shell -environment after the command completes. -@end enumerate - -When Bash is not executing in @sc{posix} mode, these builtins behave no -differently than the rest of the Bash builtin commands. -The Bash @sc{posix} mode is described in @ref{Bash POSIX Mode}. - -These are the @sc{posix} special builtins: -@example -@w{break : . continue eval exec exit export readonly return set} -@w{shift trap unset} -@end example - -@node Shell Variables -@chapter Shell Variables - -@menu -* Bourne Shell Variables:: Variables which Bash uses in the same way - as the Bourne Shell. -* Bash Variables:: List of variables that exist in Bash. -@end menu - -This chapter describes the shell variables that Bash uses. -Bash automatically assigns default values to a number of variables. - -@node Bourne Shell Variables -@section Bourne Shell Variables - -Bash uses certain shell variables in the same way as the Bourne shell. -In some cases, Bash assigns a default value to the variable. - -@vtable @code - -@item CDPATH -A colon-separated list of directories used as a search path for -the @code{cd} builtin command. - -@item HOME -The current user's home directory; the default for the @code{cd} builtin -command. -The value of this variable is also used by tilde expansion -(@pxref{Tilde Expansion}). - -@item IFS -A list of characters that separate fields; used when the shell splits -words as part of expansion. - -@item MAIL -If this parameter is set to a filename or directory name -and the @env{MAILPATH} variable -is not set, Bash informs the user of the arrival of mail in -the specified file or Maildir-format directory. - -@item MAILPATH -A colon-separated list of filenames which the shell periodically checks -for new mail. -Each list entry can specify the message that is printed when new mail -arrives in the mail file by separating the filename from the message with -a @samp{?}. -When used in the text of the message, @code{$_} expands to the name of -the current mail file. - -@item OPTARG -The value of the last option argument processed by the @code{getopts} builtin. - -@item OPTIND -The index of the last option argument processed by the @code{getopts} builtin. - -@item PATH -A colon-separated list of directories in which the shell looks for -commands. -A zero-length (null) directory name in the value of @code{PATH} indicates the -current directory. -A null directory name may appear as two adjacent colons, or as an initial -or trailing colon. - - -@item PS1 -The primary prompt string. The default value is @samp{\s-\v\$ }. -@xref{Controlling the Prompt}, for the complete list of escape -sequences that are expanded before @env{PS1} is displayed. - -@item PS2 -The secondary prompt string. The default value is @samp{> }. - -@end vtable - -@node Bash Variables -@section Bash Variables - -These variables are set or used by Bash, but other shells -do not normally treat them specially. - -A few variables used by Bash are described in different chapters: -variables for controlling the job control facilities -(@pxref{Job Control Variables}). - -@vtable @code - -@item BASH -The full pathname used to execute the current instance of Bash. - -@item BASHOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the @option{-s} option to the -@code{shopt} builtin command (@pxref{The Shopt Builtin}). -The options appearing in @env{BASHOPTS} are those reported -as @samp{on} by @samp{shopt}. -If this variable is in the environment when Bash -starts up, each shell option in the list will be enabled before -reading any startup files. This variable is readonly. - -@item BASHPID -Expands to the process ID of the current Bash process. -This differs from @code{$$} under certain circumstances, such as subshells -that do not require Bash to be re-initialized. - -@item BASH_ALIASES -An associative array variable whose members correspond to the internal -list of aliases as maintained by the @code{alias} builtin. -(@pxref{Bourne Shell Builtins}). -Elements added to this array appear in the alias list; unsetting array -elements cause aliases to be removed from the alias list. - -@item BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current bash execution call stack. The number of -parameters to the current subroutine (shell function or script executed -with @code{.} or @code{source}) is at the top of the stack. When a -subroutine is executed, the number of parameters passed is pushed onto -@code{BASH_ARGC}. -The shell sets @code{BASH_ARGC} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@item BASH_ARGV -An array variable containing all of the parameters in the current bash -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto @code{BASH_ARGV}. -The shell sets @code{BASH_ARGV} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@item BASH_CMDS -An associative array variable whose members correspond to the internal -hash table of commands as maintained by the @code{hash} builtin -(@pxref{Bourne Shell Builtins}). -Elements added to this array appear in the hash table; unsetting array -elements cause commands to be removed from the hash table. - -@item BASH_COMMAND -The command currently being executed or about to be executed, unless the -shell is executing a command as the result of a trap, -in which case it is the command executing at the time of the trap. - -@item BASH_ENV -If this variable is set when Bash is invoked to execute a shell -script, its value is expanded and used as the name of a startup file -to read before executing the script. @xref{Bash Startup Files}. - -@item BASH_EXECUTION_STRING -The command argument to the @option{-c} invocation option. - -@item BASH_LINENO -An array variable whose members are the line numbers in source files -where each corresponding member of @var{FUNCNAME} was invoked. -@code{$@{BASH_LINENO[$i]@}} is the line number in the source file -(@code{$@{BASH_SOURCE[$i+1]@}}) where -@code{$@{FUNCNAME[$i]@}} was called (or @code{$@{BASH_LINENO[$i-1]@}} if -referenced within another shell function). -Use @code{LINENO} to obtain the current line number. - -@item BASH_REMATCH -An array variable whose members are assigned by the @samp{=~} binary -operator to the @code{[[} conditional command -(@pxref{Conditional Constructs}). -The element with index 0 is the portion of the string -matching the entire regular expression. -The element with index @var{n} is the portion of the -string matching the @var{n}th parenthesized subexpression. -This variable is read-only. - -@item BASH_SOURCE -An array variable whose members are the source filenames where the -corresponding shell function names in the @code{FUNCNAME} array -variable are defined. -The shell function @code{$@{FUNCNAME[$i]@}} is defined in the file -@code{$@{BASH_SOURCE[$i]@}} and called from @code{$@{BASH_SOURCE[$i+1]@}} - -@item BASH_SUBSHELL -Incremented by one within each subshell or subshell environment when -the shell begins executing in that environment. -The initial value is 0. - -@item BASH_VERSINFO -A readonly array variable (@pxref{Arrays}) -whose members hold version information for this instance of Bash. -The values assigned to the array members are as follows: - -@table @code - -@item BASH_VERSINFO[0] -The major version number (the @var{release}). - -@item BASH_VERSINFO[1] -The minor version number (the @var{version}). - -@item BASH_VERSINFO[2] -The patch level. - -@item BASH_VERSINFO[3] -The build version. - -@item BASH_VERSINFO[4] -The release status (e.g., @var{beta1}). - -@item BASH_VERSINFO[5] -The value of @env{MACHTYPE}. -@end table - -@item BASH_VERSION -The version number of the current instance of Bash. - -@item BASH_XTRACEFD -If set to an integer corresponding to a valid file descriptor, Bash -will write the trace output generated when @samp{set -x} -is enabled to that file descriptor. -This allows tracing output to be separated from diagnostic and error -messages. -The file descriptor is closed when @code{BASH_XTRACEFD} is unset or assigned -a new value. -Unsetting @code{BASH_XTRACEFD} or assigning it the empty string causes the -trace output to be sent to the standard error. -Note that setting @code{BASH_XTRACEFD} to 2 (the standard error file -descriptor) and then unsetting it will result in the standard error -being closed. - -@item COLUMNS -Used by the @code{select} command to determine the terminal width -when printing selection lists. Automatically set by an interactive shell -upon receipt of a -@code{SIGWINCH}. - -@item COMP_CWORD -An index into @env{$@{COMP_WORDS@}} of the word containing the current -cursor position. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_LINE -The current command line. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_POINT -The index of the current cursor position relative to the beginning of -the current command. -If the current cursor position is at the end of the current command, -the value of this variable is equal to @code{$@{#COMP_LINE@}}. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_TYPE -Set to an integer value corresponding to the type of completion attempted -that caused a completion function to be called: -@var{TAB}, for normal completion, -@samp{?}, for listing completions after successive tabs, -@samp{!}, for listing alternatives on partial word completion, -@samp{@@}, to list completions if the word is not unmodified, -or -@samp{%}, for menu completion. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_KEY -The key (or final key of a key sequence) used to invoke the current -completion function. - -@item COMP_WORDBREAKS -The set of characters that the Readline library treats as word -separators when performing word completion. -If @code{COMP_WORDBREAKS} is unset, it loses its special properties, -even if it is subsequently reset. - -@item COMP_WORDS -An array variable consisting of the individual -words in the current command line. -The line is split into words as Readline would split it, using -@code{COMP_WORDBREAKS} as described above. -This variable is available only in shell functions invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMPREPLY -An array variable from which Bash reads the possible completions -generated by a shell function invoked by the programmable completion -facility (@pxref{Programmable Completion}). -Each array element contains one possible completion. - -@item COPROC -An array variable created to hold the file descriptors -for output from and input to an unnamed coprocess (@pxref{Coprocesses}). - -@item DIRSTACK -An array variable containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -@code{dirs} builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the @code{pushd} and @code{popd} -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If @env{DIRSTACK} is unset, it loses its special properties, even if -it is subsequently reset. - -@item EMACS -If Bash finds this variable in the environment when the shell -starts with value @samp{t}, it assumes that the shell is running in an -Emacs shell buffer and disables line editing. - -@item ENV -Similar to @code{BASH_ENV}; used when the shell is invoked in -@sc{posix} Mode (@pxref{Bash POSIX Mode}). - -@item EUID -The numeric effective user id of the current user. This variable -is readonly. - -@item FCEDIT -The editor used as a default by the @option{-e} option to the @code{fc} -builtin command. - -@item FIGNORE -A colon-separated list of suffixes to ignore when performing -filename completion. -A filename whose suffix matches one of the entries in -@env{FIGNORE} -is excluded from the list of matched filenames. A sample -value is @samp{.o:~} - -@item FUNCNAME -An array variable containing the names of all shell functions -currently in the execution call stack. -The element with index 0 is the name of any currently-executing -shell function. -The bottom-most element (the one with the highest index) -is @code{"main"}. -This variable exists only when a shell function is executing. -Assignments to @env{FUNCNAME} have no effect and return an error status. -If @env{FUNCNAME} is unset, it loses its special properties, even if -it is subsequently reset. - -This variable can be used with @code{BASH_LINENO} and @code{BASH_SOURCE}. -Each element of @code{FUNCNAME} has corresponding elements in -@code{BASH_LINENO} and @code{BASH_SOURCE} to describe the call stack. -For instance, @code{$@{FUNCNAME[$i]@}} was called from the file -@code{$@{BASH_SOURCE[$i+1]@}} at line number @code{$@{BASH_LINENO[$i]@}}. -The @code{caller} builtin displays the current call stack using this -information. - -@item FUNCNEST -If set to a numeric value greater than 0, defines a maximum function -nesting level. Function invocations that exceed this nesting level -will cause the current command to abort. - -@item GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by filename expansion. -If a filename matched by a filename expansion pattern also matches one -of the patterns in @env{GLOBIGNORE}, it is removed from the list -of matches. - -@item GROUPS -An array variable containing the list of groups of which the current -user is a member. -Assignments to @env{GROUPS} have no effect and return an error status. -If @env{GROUPS} is unset, it loses its special properties, even if it is -subsequently reset. - -@item histchars -Up to three characters which control history expansion, quick -substitution, and tokenization (@pxref{History Interaction}). -The first character is the -@var{history expansion} character, that is, the character which signifies the -start of a history expansion, normally @samp{!}. The second character is the -character which signifies `quick substitution' when seen as the first -character on a line, normally @samp{^}. The optional third character is the -character which indicates that the remainder of the line is a comment when -found as the first character of a word, usually @samp{#}. The history -comment character causes history substitution to be skipped for the -remaining words on the line. It does not necessarily cause the shell -parser to treat the rest of the line as a comment. - -@item HISTCMD -The history number, or index in the history list, of the current -command. If @env{HISTCMD} is unset, it loses its special properties, -even if it is subsequently reset. - -@item HISTCONTROL -A colon-separated list of values controlling how commands are saved on -the history list. -If the list of values includes @samp{ignorespace}, lines which begin -with a space character are not saved in the history list. -A value of @samp{ignoredups} causes lines which match the previous -history entry to not be saved. -A value of @samp{ignoreboth} is shorthand for -@samp{ignorespace} and @samp{ignoredups}. -A value of @samp{erasedups} causes all previous lines matching the -current line to be removed from the history list before that line -is saved. -Any value not in the above list is ignored. -If @env{HISTCONTROL} is unset, or does not include a valid value, -all lines read by the shell parser are saved on the history list, -subject to the value of @env{HISTIGNORE}. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTCONTROL}. - -@item HISTFILE -The name of the file to which the command history is saved. The -default value is @file{~/.bash_history}. - -@item HISTFILESIZE -The maximum number of lines contained in the history file. -When this variable is assigned a value, the history file is truncated, -if necessary, to contain no more than that number of lines -by removing the oldest entries. -The history file is also truncated to this size after -writing it when a shell exits. -If the value is 0, the history file is truncated to zero size. -Non-numeric values and numeric values less than zero inhibit truncation. -The shell sets the default value to the value of @env{HISTSIZE} -after reading any startup files. - -@item HISTIGNORE -A colon-separated list of patterns used to decide which command -lines should be saved on the history list. Each pattern is -anchored at the beginning of the line and must match the complete -line (no implicit @samp{*} is appended). Each pattern is tested -against the line after the checks specified by @env{HISTCONTROL} -are applied. In addition to the normal shell pattern matching -characters, @samp{&} matches the previous history line. @samp{&} -may be escaped using a backslash; the backslash is removed -before attempting a match. -The second and subsequent lines of a multi-line compound command are -not tested, and are added to the history regardless of the value of -@env{HISTIGNORE}. - -@env{HISTIGNORE} subsumes the function of @env{HISTCONTROL}. A -pattern of @samp{&} is identical to @code{ignoredups}, and a -pattern of @samp{[ ]*} is identical to @code{ignorespace}. -Combining these two patterns, separating them with a colon, -provides the functionality of @code{ignoreboth}. - -@item HISTSIZE -The maximum number of commands to remember on the history list. -If the value is 0, commands are not saved in the history list. -Numeric values less than zero result in every command being saved -on the history list (there is no limit). -The shell sets the default value to 500 after reading any startup files. - -@item HISTTIMEFORMAT -If this variable is set and not null, its value is used as a format string -for @var{strftime} to print the time stamp associated with each history -entry displayed by the @code{history} builtin. -If this variable is set, time stamps are written to the history file so -they may be preserved across shell sessions. -This uses the history comment character to distinguish timestamps from -other history lines. - -@item HOSTFILE -Contains the name of a file in the same format as @file{/etc/hosts} that -should be read when the shell needs to complete a hostname. -The list of possible hostname completions may be changed while the shell -is running; -the next time hostname completion is attempted after the -value is changed, Bash adds the contents of the new file to the -existing list. -If @env{HOSTFILE} is set, but has no value, or does not name a readable file, -Bash attempts to read -@file{/etc/hosts} to obtain the list of possible hostname completions. -When @env{HOSTFILE} is unset, the hostname list is cleared. - -@item HOSTNAME -The name of the current host. - -@item HOSTTYPE -A string describing the machine Bash is running on. - -@item IGNOREEOF -Controls the action of the shell on receipt of an @code{EOF} character -as the sole input. If set, the value denotes the number -of consecutive @code{EOF} characters that can be read as the -first character on an input line -before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. -If the variable does not exist, then @code{EOF} signifies the end of -input to the shell. This is only in effect for interactive shells. - -@item INPUTRC -The name of the Readline initialization file, overriding the default -of @file{~/.inputrc}. - -@item LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with @code{LC_}. - -@item LC_ALL -This variable overrides the value of @env{LANG} and any other -@code{LC_} variable specifying a locale category. - -@item LC_COLLATE -This variable determines the collation order used when sorting the -results of filename expansion, and -determines the behavior of range expressions, equivalence classes, -and collating sequences within filename expansion and pattern matching -(@pxref{Filename Expansion}). - -@item LC_CTYPE -This variable determines the interpretation of characters and the -behavior of character classes within filename expansion and pattern -matching (@pxref{Filename Expansion}). - -@item LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a @samp{$} (@pxref{Locale Translation}). - -@item LC_NUMERIC -This variable determines the locale category used for number formatting. - -@item LINENO -The line number in the script or shell function currently executing. - -@item LINES -Used by the @code{select} command to determine the column length -for printing selection lists. Automatically set by an interactive shell -upon receipt of a -@code{SIGWINCH}. - -@item MACHTYPE -A string that fully describes the system type on which Bash -is executing, in the standard @sc{gnu} @var{cpu-company-system} format. - -@item MAILCHECK -How often (in seconds) that the shell should check for mail in the -files specified in the @env{MAILPATH} or @env{MAIL} variables. -The default is 60 seconds. When it is time to check -for mail, the shell does so before displaying the primary prompt. -If this variable is unset, or set to a value that is not a number -greater than or equal to zero, the shell disables mail checking. - -@item MAPFILE -An array variable created to hold the text read by the -@code{mapfile} builtin when no variable name is supplied. - -@item OLDPWD -The previous working directory as set by the @code{cd} builtin. - -@item OPTERR -If set to the value 1, Bash displays error messages -generated by the @code{getopts} builtin command. - -@item OSTYPE -A string describing the operating system Bash is running on. - -@item PIPESTATUS -An array variable (@pxref{Arrays}) -containing a list of exit status values from the processes -in the most-recently-executed foreground pipeline (which may -contain only a single command). - -@item POSIXLY_CORRECT -If this variable is in the environment when Bash starts, the shell -enters @sc{posix} mode (@pxref{Bash POSIX Mode}) before reading the -startup files, as if the @option{--posix} invocation option had been supplied. -If it is set while the shell is running, Bash enables @sc{posix} mode, -as if the command -@example -@code{set -o posix} -@end example -@noindent -had been executed. - -@item PPID -The process @sc{id} of the shell's parent process. This variable -is readonly. - -@item PROMPT_COMMAND -If set, the value is interpreted as a command to execute -before the printing of each primary prompt (@env{$PS1}). - -@item PROMPT_DIRTRIM -If set to a number greater than zero, the value is used as the number of -trailing directory components to retain when expanding the @code{\w} and -@code{\W} prompt string escapes (@pxref{Controlling the Prompt}). -Characters removed are replaced with an ellipsis. - -@item PS3 -The value of this variable is used as the prompt for the -@code{select} command. If this variable is not set, the -@code{select} command prompts with @samp{#? } - -@item PS4 -The value is the prompt printed before the command line is echoed -when the @option{-x} option is set (@pxref{The Set Builtin}). -The first character of @env{PS4} is replicated multiple times, as -necessary, to indicate multiple levels of indirection. -The default is @samp{+ }. - -@item PWD -The current working directory as set by the @code{cd} builtin. - -@item RANDOM -Each time this parameter is referenced, a random integer -between 0 and 32767 is generated. Assigning a value to this -variable seeds the random number generator. - -@item READLINE_LINE -The contents of the Readline line buffer, for use -with @samp{bind -x} (@pxref{Bash Builtins}). - -@item READLINE_POINT -The position of the insertion point in the Readline line buffer, for use -with @samp{bind -x} (@pxref{Bash Builtins}). - -@item REPLY -The default variable for the @code{read} builtin. - -@item SECONDS -This variable expands to the number of seconds since the -shell was started. Assignment to this variable resets -the count to the value assigned, and the expanded value -becomes the value assigned plus the number of seconds -since the assignment. - -@item SHELL -The full pathname to the shell is kept in this environment variable. -If it is not set when the shell starts, -Bash assigns to it the full pathname of the current user's login shell. - -@item SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the @option{-o} option to the -@code{set} builtin command (@pxref{The Set Builtin}). -The options appearing in @env{SHELLOPTS} are those reported -as @samp{on} by @samp{set -o}. -If this variable is in the environment when Bash -starts up, each shell option in the list will be enabled before -reading any startup files. This variable is readonly. - -@item SHLVL -Incremented by one each time a new instance of Bash is started. This is -intended to be a count of how deeply your Bash shells are nested. - -@item TIMEFORMAT -The value of this parameter is used as a format string specifying -how the timing information for pipelines prefixed with the @code{time} -reserved word should be displayed. -The @samp{%} character introduces an -escape sequence that is expanded to a time value or other -information. -The escape sequences and their meanings are as -follows; the braces denote optional portions. - -@table @code - -@item %% -A literal @samp{%}. - -@item %[@var{p}][l]R -The elapsed time in seconds. - -@item %[@var{p}][l]U -The number of CPU seconds spent in user mode. - -@item %[@var{p}][l]S -The number of CPU seconds spent in system mode. - -@item %P -The CPU percentage, computed as (%U + %S) / %R. -@end table - -The optional @var{p} is a digit specifying the precision, the number of -fractional digits after a decimal point. -A value of 0 causes no decimal point or fraction to be output. -At most three places after the decimal point may be specified; values -of @var{p} greater than 3 are changed to 3. -If @var{p} is not specified, the value 3 is used. - -The optional @code{l} specifies a longer format, including minutes, of -the form @var{MM}m@var{SS}.@var{FF}s. -The value of @var{p} determines whether or not the fraction is included. - -If this variable is not set, Bash acts as if it had the value -@example -@code{$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'} -@end example -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. - -@item TMOUT -If set to a value greater than zero, @code{TMOUT} is treated as the -default timeout for the @code{read} builtin (@pxref{Bash Builtins}). -The @code{select} command (@pxref{Conditional Constructs}) terminates -if input does not arrive after @code{TMOUT} seconds when input is coming -from a terminal. - -In an interactive shell, the value is interpreted as -the number of seconds to wait for a line of input after issuing -the primary prompt. -Bash -terminates after waiting for that number of seconds if a complete -line of input does not arrive. - -@item TMPDIR -If set, Bash uses its value as the name of a directory in which -Bash creates temporary files for the shell's use. - -@item UID -The numeric real user id of the current user. This variable is readonly. - -@end vtable - -@node Bash Features -@chapter Bash Features - -This chapter describes features unique to Bash. - -@menu -* Invoking Bash:: Command line options that you can give - to Bash. -* Bash Startup Files:: When and how Bash executes scripts. -* Interactive Shells:: What an interactive shell is. -* Bash Conditional Expressions:: Primitives used in composing expressions for - the @code{test} builtin. -* Shell Arithmetic:: Arithmetic on shell variables. -* Aliases:: Substituting one command for another. -* Arrays:: Array Variables. -* The Directory Stack:: History of visited directories. -* Controlling the Prompt:: Customizing the various prompt strings. -* The Restricted Shell:: A more controlled mode of shell execution. -* Bash POSIX Mode:: Making Bash behave more closely to what - the POSIX standard specifies. -@end menu - -@node Invoking Bash -@section Invoking Bash - -@example -bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] -c @var{string} [@var{argument} @dots{}] -bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}] -@end example - -All of the single-character options used with the @code{set} builtin -(@pxref{The Set Builtin}) can be used as options when the shell is invoked. -In addition, there are several multi-character -options that you can use. These options must appear on the command -line before the single-character options to be recognized. - -@table @code -@item --debugger -Arrange for the debugger profile to be executed before the shell -starts. Turns on extended debugging mode (see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@item --dump-po-strings -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard output -in the @sc{gnu} @code{gettext} PO (portable object) file format. -Equivalent to @option{-D} except for the output format. - -@item --dump-strings -Equivalent to @option{-D}. - -@item --help -Display a usage message on standard output and exit successfully. - -@item --init-file @var{filename} -@itemx --rcfile @var{filename} -Execute commands from @var{filename} (instead of @file{~/.bashrc}) -in an interactive shell. - -@item --login -Equivalent to @option{-l}. - -@item --noediting -Do not use the @sc{gnu} Readline library (@pxref{Command Line Editing}) -to read command lines when the shell is interactive. - -@item --noprofile -Don't load the system-wide startup file @file{/etc/profile} -or any of the personal initialization files -@file{~/.bash_profile}, @file{~/.bash_login}, or @file{~/.profile} -when Bash is invoked as a login shell. - -@item --norc -Don't read the @file{~/.bashrc} initialization file in an -interactive shell. This is on by default if the shell is -invoked as @code{sh}. - -@item --posix -Change the behavior of Bash where the default operation differs -from the @sc{posix} standard to match the standard. This -is intended to make Bash behave as a strict superset of that -standard. @xref{Bash POSIX Mode}, for a description of the Bash -@sc{posix} mode. - -@item --restricted -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item --verbose -Equivalent to @option{-v}. Print shell input lines as they're read. - -@item --version -Show version information for this instance of -Bash on the standard output and exit successfully. -@end table - -There are several single-character options that may be supplied at -invocation which are not available with the @code{set} builtin. - -@table @code -@item -c -Read and execute commands from the first non-option @var{argument} -after processing the options, then exit. -Any remaining arguments are assigned to the -positional parameters, starting with @code{$0}. - -@item -i -Force the shell to run interactively. Interactive shells are -described in @ref{Interactive Shells}. - -@item -l -Make this shell act as if it had been directly invoked by login. -When the shell is interactive, this is equivalent to starting a -login shell with @samp{exec -l bash}. -When the shell is not interactive, the login shell startup files will -be executed. -@samp{exec bash -l} or @samp{exec bash --login} -will replace the current shell with a Bash login shell. -@xref{Bash Startup Files}, for a description of the special behavior -of a login shell. - -@item -r -Make the shell a restricted shell (@pxref{The Restricted Shell}). - -@item -s -If this option is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. - -@item -D -A list of all double-quoted strings preceded by @samp{$} -is printed on the standard output. -These are the strings that -are subject to language translation when the current locale -is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). -This implies the @option{-n} option; no commands will be executed. - -@item [-+]O [@var{shopt_option}] -@var{shopt_option} is one of the shell options accepted by the -@code{shopt} builtin (@pxref{The Shopt Builtin}). -If @var{shopt_option} is present, @option{-O} sets the value of that option; -@option{+O} unsets it. -If @var{shopt_option} is not supplied, the names and values of the shell -options accepted by @code{shopt} are printed on the standard output. -If the invocation option is @option{+O}, the output is displayed in a format -that may be reused as input. - -@item -- -A @code{--} signals the end of options and disables further option -processing. -Any arguments after the @code{--} are treated as filenames and arguments. -@end table - -@cindex login shell -A @emph{login} shell is one whose first character of argument zero is -@samp{-}, or one invoked with the @option{--login} option. - -@cindex interactive shell -An @emph{interactive} shell is one started without non-option arguments, -unless @option{-s} is specified, -without specifying the @option{-c} option, and whose input and output are both -connected to terminals (as determined by @code{isatty(3)}), or one -started with the @option{-i} option. @xref{Interactive Shells}, for more -information. - -If arguments remain after option processing, and neither the -@option{-c} nor the @option{-s} -option has been supplied, the first argument is assumed to -be the name of a file containing shell commands (@pxref{Shell Scripts}). -When Bash is invoked in this fashion, @code{$0} -is set to the name of the file, and the positional parameters -are set to the remaining arguments. -Bash reads and executes commands from this file, then exits. -Bash's exit status is the exit status of the last command executed -in the script. If no commands are executed, the exit status is 0. - -@node Bash Startup Files -@section Bash Startup Files -@cindex startup files - -This section describes how Bash executes its startup files. -If any of the files exist but cannot be read, Bash reports an error. -Tildes are expanded in filenames as described above under -Tilde Expansion (@pxref{Tilde Expansion}). - -Interactive shells are described in @ref{Interactive Shells}. - -@subsubheading Invoked as an interactive login shell, or with @option{--login} - -When Bash is invoked as an interactive login shell, or as a -non-interactive shell with the @option{--login} option, it first reads and -executes commands from the file @file{/etc/profile}, if that file exists. -After reading that file, it looks for @file{~/.bash_profile}, -@file{~/.bash_login}, and @file{~/.profile}, in that order, and reads -and executes commands from the first one that exists and is readable. -The @option{--noprofile} option may be used when the shell is started to -inhibit this behavior. - -When a login shell exits, Bash reads and executes commands from -the file @file{~/.bash_logout}, if it exists. - -@subsubheading Invoked as an interactive non-login shell - -When an interactive shell that is not a login shell is started, Bash -reads and executes commands from @file{~/.bashrc}, if that file exists. -This may be inhibited by using the @option{--norc} option. -The @option{--rcfile @var{file}} option will force Bash to read and -execute commands from @var{file} instead of @file{~/.bashrc}. - -So, typically, your @file{~/.bash_profile} contains the line -@example -@code{if [ -f ~/.bashrc ]; then . ~/.bashrc; fi} -@end example -@noindent -after (or before) any login-specific initializations. - -@subsubheading Invoked non-interactively - -When Bash is started non-interactively, to run a shell script, -for example, it looks for the variable @env{BASH_ENV} in the environment, -expands its value if it appears there, and uses the expanded value as -the name of a file to read and execute. Bash behaves as if the -following command were executed: -@example -@code{if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi} -@end example -@noindent -but the value of the @env{PATH} variable is not used to search for the -filename. - -As noted above, if a non-interactive shell is invoked with the -@option{--login} option, Bash attempts to read and execute commands from the -login shell startup files. - -@subsubheading Invoked with name @code{sh} - -If Bash is invoked with the name @code{sh}, it tries to mimic the -startup behavior of historical versions of @code{sh} as closely as -possible, while conforming to the @sc{posix} standard as well. - -When invoked as an interactive login shell, or as a non-interactive -shell with the @option{--login} option, it first attempts to read -and execute commands from @file{/etc/profile} and @file{~/.profile}, in -that order. -The @option{--noprofile} option may be used to inhibit this behavior. -When invoked as an interactive shell with the name @code{sh}, Bash -looks for the variable @env{ENV}, expands its value if it is defined, -and uses the expanded value as the name of a file to read and execute. -Since a shell invoked as @code{sh} does not attempt to read and execute -commands from any other startup files, the @option{--rcfile} option has -no effect. -A non-interactive shell invoked with the name @code{sh} does not attempt -to read any other startup files. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after -the startup files are read. - -@subsubheading Invoked in @sc{posix} mode - -When Bash is started in @sc{posix} mode, as with the -@option{--posix} command line option, it follows the @sc{posix} standard -for startup files. -In this mode, interactive shells expand the @env{ENV} variable -and commands are read and executed from the file whose name is the -expanded value. -No other startup files are read. - -@subsubheading Invoked by remote shell daemon - -Bash attempts to determine when it is being run with its standard input -connected to a network connection, as when executed by the remote shell -daemon, usually @code{rshd}, or the secure shell daemon @code{sshd}. -If Bash determines it is being run in -this fashion, it reads and executes commands from @file{~/.bashrc}, if that -file exists and is readable. -It will not do this if invoked as @code{sh}. -The @option{--norc} option may be used to inhibit this behavior, and the -@option{--rcfile} option may be used to force another file to be read, but -@code{rshd} does not generally invoke the shell with those options or -allow them to be specified. - -@subsubheading Invoked with unequal effective and real @sc{uid/gid}s - -If Bash is started with the effective user (group) id not equal to the -real user (group) id, and the @option{-p} option is not supplied, no startup -files are read, shell functions are not inherited from the environment, -the @env{SHELLOPTS}, @env{BASHOPTS}, @env{CDPATH}, and @env{GLOBIGNORE} -variables, if they appear in the environment, are ignored, and the effective -user id is set to the real user id. -If the @option{-p} option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. - -@node Interactive Shells -@section Interactive Shells -@cindex interactive shell -@cindex shell, interactive - -@menu -* What is an Interactive Shell?:: What determines whether a shell is Interactive. -* Is this Shell Interactive?:: How to tell if a shell is interactive. -* Interactive Shell Behavior:: What changes in a interactive shell? -@end menu - -@node What is an Interactive Shell? -@subsection What is an Interactive Shell? - -An interactive shell -is one started without non-option arguments, unless @option{-s} is -specified, without specifying the @option{-c} option, and -whose input and error output are both -connected to terminals (as determined by @code{isatty(3)}), -or one started with the @option{-i} option. - -An interactive shell generally reads from and writes to a user's -terminal. - -The @option{-s} invocation option may be used to set the positional parameters -when an interactive shell is started. - -@node Is this Shell Interactive? -@subsection Is this Shell Interactive? - -To determine within a startup script whether or not Bash is -running interactively, -test the value of the @samp{-} special parameter. -It contains @code{i} when the shell is interactive. For example: - -@example -case "$-" in -*i*) echo This shell is interactive ;; -*) echo This shell is not interactive ;; -esac -@end example - -Alternatively, startup scripts may examine the variable -@env{PS1}; it is unset in non-interactive shells, and set in -interactive shells. Thus: - -@example -if [ -z "$PS1" ]; then - echo This shell is not interactive -else - echo This shell is interactive -fi -@end example - -@node Interactive Shell Behavior -@subsection Interactive Shell Behavior - -When the shell is running interactively, it changes its behavior in -several ways. - -@enumerate -@item -Startup files are read and executed as described in @ref{Bash Startup Files}. - -@item -Job Control (@pxref{Job Control}) is enabled by default. When job -control is in effect, Bash ignores the keyboard-generated job control -signals @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. - -@item -Bash expands and displays @env{PS1} before reading the first line -of a command, and expands and displays @env{PS2} before reading the -second and subsequent lines of a multi-line command. - -@item -Bash executes the value of the @env{PROMPT_COMMAND} variable as a command -before printing the primary prompt, @env{$PS1} -(@pxref{Bash Variables}). - -@item -Readline (@pxref{Command Line Editing}) is used to read commands from -the user's terminal. - -@item -Bash inspects the value of the @code{ignoreeof} option to @code{set -o} -instead of exiting immediately when it receives an @code{EOF} on its -standard input when reading a command (@pxref{The Set Builtin}). - -@item -Command history (@pxref{Bash History Facilities}) -and history expansion (@pxref{History Interaction}) -are enabled by default. -Bash will save the command history to the file named by @env{$HISTFILE} -when a shell with history enabled exits. - -@item -Alias expansion (@pxref{Aliases}) is performed by default. - -@item -In the absence of any traps, Bash ignores @code{SIGTERM} -(@pxref{Signals}). - -@item -In the absence of any traps, @code{SIGINT} is caught and handled -((@pxref{Signals}). -@code{SIGINT} will interrupt some shell builtins. - -@item -An interactive login shell sends a @code{SIGHUP} to all jobs on exit -if the @code{huponexit} shell option has been enabled (@pxref{Signals}). - -@item -The @option{-n} invocation option is ignored, and @samp{set -n} has -no effect (@pxref{The Set Builtin}). - -@item -Bash will check for mail periodically, depending on the values of the -@env{MAIL}, @env{MAILPATH}, and @env{MAILCHECK} shell variables -(@pxref{Bash Variables}). - -@item -Expansion errors due to references to unbound shell variables after -@samp{set -u} has been enabled will not cause the shell to exit -(@pxref{The Set Builtin}). - -@item -The shell will not exit on expansion errors caused by @var{var} being unset -or null in @code{$@{@var{var}:?@var{word}@}} expansions -(@pxref{Shell Parameter Expansion}). - -@item -Redirection errors encountered by shell builtins will not cause the -shell to exit. - -@item -When running in @sc{posix} mode, a special builtin returning an error -status will not cause the shell to exit (@pxref{Bash POSIX Mode}). - -@item -A failed @code{exec} will not cause the shell to exit -(@pxref{Bourne Shell Builtins}). - -@item -Parser syntax errors will not cause the shell to exit. - -@item -Simple spelling correction for directory arguments to the @code{cd} -builtin is enabled by default (see the description of the @code{cdspell} -option to the @code{shopt} builtin in @ref{The Shopt Builtin}). - -@item -The shell will check the value of the @env{TMOUT} variable and exit -if a command is not read within the specified number of seconds after -printing @env{$PS1} (@pxref{Bash Variables}). - -@end enumerate - -@node Bash Conditional Expressions -@section Bash Conditional Expressions -@cindex expressions, conditional - -Conditional expressions are used by the @code{[[} compound command -and the @code{test} and @code{[} builtin commands. - -Expressions may be unary or binary. -Unary expressions are often used to examine the status of a file. -There are string operators and numeric comparison operators as well. -If the @var{file} argument to one of the primaries is of the form -@file{/dev/fd/@var{N}}, then file descriptor @var{N} is checked. -If the @var{file} argument to one of the primaries is one of -@file{/dev/stdin}, @file{/dev/stdout}, or @file{/dev/stderr}, file -descriptor 0, 1, or 2, respectively, is checked. - -When used with @samp{[[}, the @samp{<} and @samp{>} operators sort -lexicographically using the current locale. -The @code{test} command uses ASCII ordering. - -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. - -@table @code -@item -a @var{file} -True if @var{file} exists. - -@item -b @var{file} -True if @var{file} exists and is a block special file. - -@item -c @var{file} -True if @var{file} exists and is a character special file. - -@item -d @var{file} -True if @var{file} exists and is a directory. - -@item -e @var{file} -True if @var{file} exists. - -@item -f @var{file} -True if @var{file} exists and is a regular file. - -@item -g @var{file} -True if @var{file} exists and its set-group-id bit is set. - -@item -h @var{file} -True if @var{file} exists and is a symbolic link. - -@item -k @var{file} -True if @var{file} exists and its "sticky" bit is set. - -@item -p @var{file} -True if @var{file} exists and is a named pipe (FIFO). - -@item -r @var{file} -True if @var{file} exists and is readable. - -@item -s @var{file} -True if @var{file} exists and has a size greater than zero. - -@item -t @var{fd} -True if file descriptor @var{fd} is open and refers to a terminal. - -@item -u @var{file} -True if @var{file} exists and its set-user-id bit is set. - -@item -w @var{file} -True if @var{file} exists and is writable. - -@item -x @var{file} -True if @var{file} exists and is executable. - -@item -G @var{file} -True if @var{file} exists and is owned by the effective group id. - -@item -L @var{file} -True if @var{file} exists and is a symbolic link. - -@item -N @var{file} -True if @var{file} exists and has been modified since it was last read. - -@item -O @var{file} -True if @var{file} exists and is owned by the effective user id. - -@item -S @var{file} -True if @var{file} exists and is a socket. - -@item @var{file1} -ef @var{file2} -True if @var{file1} and @var{file2} refer to the same device and -inode numbers. - -@item @var{file1} -nt @var{file2} -True if @var{file1} is newer (according to modification date) -than @var{file2}, or if @var{file1} exists and @var{file2} does not. - -@item @var{file1} -ot @var{file2} -True if @var{file1} is older than @var{file2}, -or if @var{file2} exists and @var{file1} does not. - -@item -o @var{optname} -True if the shell option @var{optname} is enabled. -The list of options appears in the description of the @option{-o} -option to the @code{set} builtin (@pxref{The Set Builtin}). - -@item -v @var{varname} -True if the shell variable @var{varname} is set (has been assigned a value). - -@item -z @var{string} -True if the length of @var{string} is zero. - -@item -n @var{string} -@itemx @var{string} -True if the length of @var{string} is non-zero. - -@item @var{string1} == @var{string2} -@itemx @var{string1} = @var{string2} -True if the strings are equal. -@samp{=} should be used with the @code{test} command for @sc{posix} conformance. - -@item @var{string1} != @var{string2} -True if the strings are not equal. - -@item @var{string1} < @var{string2} -True if @var{string1} sorts before @var{string2} lexicographically. - -@item @var{string1} > @var{string2} -True if @var{string1} sorts after @var{string2} lexicographically. - -@item @var{arg1} OP @var{arg2} -@code{OP} is one of -@samp{-eq}, @samp{-ne}, @samp{-lt}, @samp{-le}, @samp{-gt}, or @samp{-ge}. -These arithmetic binary operators return true if @var{arg1} -is equal to, not equal to, less than, less than or equal to, -greater than, or greater than or equal to @var{arg2}, -respectively. @var{Arg1} and @var{arg2} -may be positive or negative integers. -@end table - -@node Shell Arithmetic -@section Shell Arithmetic -@cindex arithmetic, shell -@cindex shell arithmetic -@cindex expressions, arithmetic -@cindex evaluation, arithmetic -@cindex arithmetic evaluation - -The shell allows arithmetic expressions to be evaluated, as one of -the shell expansions or by the @code{let} and the @option{-i} option -to the @code{declare} builtins. - -Evaluation is done in fixed-width integers with no check for overflow, -though division by 0 is trapped and flagged as an error. -The operators and their precedence, associativity, and values -are the same as in the C language. -The following list of operators is grouped into levels of -equal-precedence operators. -The levels are listed in order of decreasing precedence. - -@table @code - -@item @var{id}++ @var{id}-- -variable post-increment and post-decrement - -@item ++@var{id} --@var{id} -variable pre-increment and pre-decrement - -@item - + -unary minus and plus - -@item ! ~ -logical and bitwise negation - -@item ** -exponentiation - -@item * / % -multiplication, division, remainder - -@item + - -addition, subtraction - -@item << >> -left and right bitwise shifts - -@item <= >= < > -comparison - -@item == != -equality and inequality - -@item & -bitwise AND - -@item ^ -bitwise exclusive OR - -@item | -bitwise OR - -@item && -logical AND - -@item || -logical OR - -@item expr ? expr : expr -conditional operator - -@item = *= /= %= += -= <<= >>= &= ^= |= -assignment - -@item expr1 , expr2 -comma -@end table - -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -Within an expression, shell variables may also be referenced by name -without using the parameter expansion syntax. -A shell variable that is null or unset evaluates to 0 when referenced -by name without using the parameter expansion syntax. -The value of a variable is evaluated as an arithmetic expression -when it is referenced, or when a variable which has been given the -@var{integer} attribute using @samp{declare -i} is assigned a value. -A null value evaluates to 0. -A shell variable need not have its @var{integer} attribute turned on -to be used in an expression. - -Constants with a leading 0 are interpreted as octal numbers. -A leading @samp{0x} or @samp{0X} denotes hexadecimal. Otherwise, -numbers take the form [@var{base}@code{#}]@var{n}, where the optional @var{base} -is a decimal number between 2 and 64 representing the arithmetic -base, and @var{n} is a number in that base. -If @var{base}@code{#} is omitted, then base 10 is used. -When specifying @var{n}, -he digits greater than 9 are represented by the lowercase letters, -the uppercase letters, @samp{@@}, and @samp{_}, in that order. -If @var{base} is less than or equal to 36, lowercase and uppercase -letters may be used interchangeably to represent numbers between 10 -and 35. - -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. - -@node Aliases -@section Aliases -@cindex alias expansion - -@var{Aliases} allow a string to be substituted for a word when it is used -as the first word of a simple command. -The shell maintains a list of aliases that may be set and unset with -the @code{alias} and @code{unalias} builtin commands. - -The first word of each simple command, if unquoted, is checked to see -if it has an alias. -If so, that word is replaced by the text of the alias. -The characters @samp{/}, @samp{$}, @samp{`}, @samp{=} and any of the -shell metacharacters or quoting characters listed above may not appear -in an alias name. -The replacement text may contain any valid -shell input, including shell metacharacters. -The first word of the replacement text is tested for -aliases, but a word that is identical to an alias being expanded -is not expanded a second time. -This means that one may alias @code{ls} to @code{"ls -F"}, -for instance, and Bash does not try to recursively expand the -replacement text. -If the last character of the alias value is a -@var{blank}, then the next command word following the -alias is also checked for alias expansion. - -Aliases are created and listed with the @code{alias} -command, and removed with the @code{unalias} command. - -There is no mechanism for using arguments in the replacement text, -as in @code{csh}. -If arguments are needed, a shell function should be used -(@pxref{Shell Functions}). - -Aliases are not expanded when the shell is not interactive, -unless the @code{expand_aliases} shell option is set using -@code{shopt} (@pxref{The Shopt Builtin}). - -The rules concerning the definition and use of aliases are -somewhat confusing. Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -The commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when a function definition is read, -not when the function is executed, because a function definition -is itself a compound command. As a consequence, aliases -defined in a function are not available until after that -function is executed. To be safe, always put -alias definitions on a separate line, and do not use @code{alias} -in compound commands. - -For almost every purpose, shell functions are preferred over aliases. - -@node Arrays -@section Arrays -@cindex arrays - -Bash provides one-dimensional indexed and associative array variables. -Any variable may be used as an indexed array; -the @code{declare} builtin will explicitly declare an array. -There is no maximum -limit on the size of an array, nor any requirement that members -be indexed or assigned contiguously. -Indexed arrays are referenced using integers (including arithmetic -expressions (@pxref{Shell Arithmetic})) and are zero-based; -associative arrays use arbitrary strings. -Unless otherwise noted, indexed array indices must be non-negative integers. - -An indexed array is created automatically if any variable is assigned to -using the syntax -@example -@var{name}[@var{subscript}]=@var{value} -@end example - -@noindent -The @var{subscript} -is treated as an arithmetic expression that must evaluate to a number. -To explicitly declare an array, use -@example -declare -a @var{name} -@end example -@noindent -The syntax -@example -declare -a @var{name}[@var{subscript}] -@end example -@noindent -is also accepted; the @var{subscript} is ignored. - -@noindent -Associative arrays are created using -@example -declare -A @var{name}. -@end example - -Attributes may be -specified for an array variable using the @code{declare} and -@code{readonly} builtins. Each attribute applies to all members of -an array. - -Arrays are assigned to using compound assignments of the form -@example -@var{name}=(@var{value1} @var{value2} @dots{} ) -@end example -@noindent -where each -@var{value} is of the form @code{[@var{subscript}]=}@var{string}. -Indexed array assignments do not require anything but @var{string}. -When assigning to indexed arrays, if -the optional subscript is supplied, that index is assigned to; -otherwise the index of the element assigned is the last index assigned -to by the statement plus one. Indexing starts at zero. - -When assigning to an associative array, the subscript is required. - -This syntax is also accepted by the @code{declare} -builtin. Individual array elements may be assigned to using the -@code{@var{name}[@var{subscript}]=@var{value}} syntax introduced above. - -Any element of an array may be referenced using -@code{$@{@var{name}[@var{subscript}]@}}. -The braces are required to avoid -conflicts with the shell's filename expansion operators. If the -@var{subscript} is @samp{@@} or @samp{*}, the word expands to all members -of the array @var{name}. These subscripts differ only when the word -appears within double quotes. -If the word is double-quoted, -@code{$@{@var{name}[*]@}} expands to a single word with -the value of each array member separated by the first character of the -@env{IFS} variable, and @code{$@{@var{name}[@@]@}} expands each element of -@var{name} to a separate word. When there are no array members, -@code{$@{@var{name}[@@]@}} expands to nothing. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the -expansion of the special parameters @samp{@@} and @samp{*}. -@code{$@{#@var{name}[@var{subscript}]@}} expands to the length of -@code{$@{@var{name}[@var{subscript}]@}}. -If @var{subscript} is @samp{@@} or -@samp{*}, the expansion is the number of elements in the array. -Referencing an array variable without a subscript is equivalent to -referencing with a subscript of 0. -If the @var{subscript} -used to reference an element of an indexed array -evaluates to a number less than zero, it is used as -an offset from one greater than the array's maximum index (so a subcript -of -1 refers to the last element of the array). - -An array variable is considered set if a subscript has been assigned a -value. The null string is a valid value. - -The @code{unset} builtin is used to destroy arrays. -@code{unset @var{name}[@var{subscript}]} -destroys the array element at index @var{subscript}. -Care must be taken to avoid unwanted side effects caused by filename -expansion. -@code{unset @var{name}}, where @var{name} is an array, removes the -entire array. A subscript of @samp{*} or @samp{@@} also removes the -entire array. - -The @code{declare}, @code{local}, and @code{readonly} -builtins each accept a @option{-a} option to specify an indexed -array and a @option{-A} option to specify an associative array. -If both options are supplied, @option{-A} takes precedence. -The @code{read} builtin accepts a @option{-a} -option to assign a list of words read from the standard input -to an array, and can read values from the standard input into -individual array elements. The @code{set} and @code{declare} -builtins display array values in a way that allows them to be -reused as input. - -@node The Directory Stack -@section The Directory Stack -@cindex directory stack - -@menu -* Directory Stack Builtins:: Bash builtin commands to manipulate - the directory stack. -@end menu - -The directory stack is a list of recently-visited directories. The -@code{pushd} builtin adds directories to the stack as it changes -the current directory, and the @code{popd} builtin removes specified -directories from the stack and changes the current directory to -the directory removed. The @code{dirs} builtin displays the contents -of the directory stack. - -The contents of the directory stack are also visible -as the value of the @env{DIRSTACK} shell variable. - -@node Directory Stack Builtins -@subsection Directory Stack Builtins - -@table @code - -@item dirs -@btindex dirs -@example -dirs [-clpv] [+@var{N} | -@var{N}] -@end example - -Display the list of currently remembered directories. Directories -are added to the list with the @code{pushd} command; the -@code{popd} command removes directories from the list. - -@table @code -@item -c -Clears the directory stack by deleting all of the elements. -@item -l -Produces a listing using full pathnames; -the default listing format uses a tilde to denote the home directory. -@item -p -Causes @code{dirs} to print the directory stack with one entry per -line. -@item -v -Causes @code{dirs} to print the directory stack with one entry per -line, prefixing each entry with its index in the stack. -@item +@var{N} -Displays the @var{N}th directory (counting from the left of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{N} -Displays the @var{N}th directory (counting from the right of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@end table - -@item popd -@btindex popd -@example -popd [-n] [+@var{N} | -@var{N}] -@end example - -Remove the top entry from the directory stack, and @code{cd} -to the new top directory. -When no arguments are given, @code{popd} -removes the top directory from the stack and -performs a @code{cd} to the new top directory. The -elements are numbered from 0 starting at the first directory listed with -@code{dirs}; that is, @code{popd} is equivalent to @code{popd +0}. - -@table @code -@item -n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -@item +@var{N} -Removes the @var{N}th directory (counting from the left of the -list printed by @code{dirs}), starting with zero. -@item -@var{N} -Removes the @var{N}th directory (counting from the right of the -list printed by @code{dirs}), starting with zero. -@end table - -@btindex pushd -@item pushd -@example -pushd [-n] [@var{+N} | @var{-N} | @var{dir}] -@end example - -Save the current directory on the top of the directory stack -and then @code{cd} to @var{dir}. -With no arguments, @code{pushd} exchanges the top two directories. - -@table @code -@item -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@item +@var{N} -Brings the @var{N}th directory (counting from the left of the -list printed by @code{dirs}, starting with zero) to the top of -the list by rotating the stack. -@item -@var{N} -Brings the @var{N}th directory (counting from the right of the -list printed by @code{dirs}, starting with zero) to the top of -the list by rotating the stack. -@item @var{dir} -Makes the current working directory be the top of the stack, making -it the new current directory as if it had been supplied as an argument -to the @code{cd} builtin. -@end table -@end table - -@node Controlling the Prompt -@section Controlling the Prompt -@cindex prompting - -The value of the variable @env{PROMPT_COMMAND} is examined just before -Bash prints each primary prompt. If @env{PROMPT_COMMAND} is set and -has a non-null value, then the -value is executed just as if it had been typed on the command line. - -In addition, the following table describes the special characters which -can appear in the prompt variables @env{PS1} to @env{PS4}: - -@table @code -@item \a -A bell character. -@item \d -The date, in "Weekday Month Date" format (e.g., "Tue May 26"). -@item \D@{@var{format}@} -The @var{format} is passed to @code{strftime}(3) and the result is inserted -into the prompt string; an empty @var{format} results in a locale-specific -time representation. The braces are required. -@item \e -An escape character. -@item \h -The hostname, up to the first `.'. -@item \H -The hostname. -@item \j -The number of jobs currently managed by the shell. -@item \l -The basename of the shell's terminal device name. -@item \n -A newline. -@item \r -A carriage return. -@item \s -The name of the shell, the basename of @code{$0} (the portion -following the final slash). -@item \t -The time, in 24-hour HH:MM:SS format. -@item \T -The time, in 12-hour HH:MM:SS format. -@item \@@ -The time, in 12-hour am/pm format. -@item \A -The time, in 24-hour HH:MM format. -@item \u -The username of the current user. -@item \v -The version of Bash (e.g., 2.00) -@item \V -The release of Bash, version + patchlevel (e.g., 2.00.0) -@item \w -The current working directory, with @env{$HOME} abbreviated with a tilde -(uses the @env{$PROMPT_DIRTRIM} variable). -@item \W -The basename of @env{$PWD}, with @env{$HOME} abbreviated with a tilde. -@item \! -The history number of this command. -@item \# -The command number of this command. -@item \$ -If the effective uid is 0, @code{#}, otherwise @code{$}. -@item \@var{nnn} -The character whose ASCII code is the octal value @var{nnn}. -@item \\ -A backslash. -@item \[ -Begin a sequence of non-printing characters. This could be used to -embed a terminal control sequence into the prompt. -@item \] -End a sequence of non-printing characters. -@end table - -The command number and the history number are usually different: -the history number of a command is its position in the history -list, which may include commands restored from the history file -(@pxref{Bash History Facilities}), while the command number is -the position in the sequence of commands executed during the current -shell session. - -After the string is decoded, it is expanded via -parameter expansion, command substitution, arithmetic -expansion, and quote removal, subject to the value of the -@code{promptvars} shell option (@pxref{Bash Builtins}). - -@node The Restricted Shell -@section The Restricted Shell -@cindex restricted shell - -If Bash is started with the name @code{rbash}, or the -@option{--restricted} -or -@option{-r} -option is supplied at invocation, the shell becomes restricted. -A restricted shell is used to -set up an environment more controlled than the standard shell. -A restricted shell behaves identically to @code{bash} -with the exception that the following are disallowed or not performed: - -@itemize @bullet -@item -Changing directories with the @code{cd} builtin. -@item -Setting or unsetting the values of the @env{SHELL}, @env{PATH}, -@env{ENV}, or @env{BASH_ENV} variables. -@item -Specifying command names containing slashes. -@item -Specifying a filename containing a slash as an argument to the @code{.} -builtin command. -@item -Specifying a filename containing a slash as an argument to the @option{-p} -option to the @code{hash} builtin command. -@item -Importing function definitions from the shell environment at startup. -@item -Parsing the value of @env{SHELLOPTS} from the shell environment at startup. -@item -Redirecting output using the @samp{>}, @samp{>|}, @samp{<>}, @samp{>&}, -@samp{&>}, and @samp{>>} redirection operators. -@item -Using the @code{exec} builtin to replace the shell with another command. -@item -Adding or deleting builtin commands with the -@option{-f} and @option{-d} options to the @code{enable} builtin. -@item -Using the @code{enable} builtin command to enable disabled shell builtins. -@item -Specifying the @option{-p} option to the @code{command} builtin. -@item -Turning off restricted mode with @samp{set +r} or @samp{set +o restricted}. -@end itemize - -These restrictions are enforced after any startup files are read. - -When a command that is found to be a shell script is executed -(@pxref{Shell Scripts}), @code{rbash} turns off any restrictions in -the shell spawned to execute the script. - -@node Bash POSIX Mode -@section Bash POSIX Mode -@cindex POSIX Mode - -Starting Bash with the @option{--posix} command-line option or executing -@samp{set -o posix} while Bash is running will cause Bash to conform more -closely to the @sc{posix} standard by changing the behavior to -match that specified by @sc{posix} in areas where the Bash default differs. - -When invoked as @code{sh}, Bash enters @sc{posix} mode after reading the -startup files. - -The following list is what's changed when `@sc{posix} mode' is in effect: - -@enumerate -@item -When a command in the hash table no longer exists, Bash will re-search -@env{$PATH} to find the new location. This is also available with -@samp{shopt -s checkhash}. - -@item -The message printed by the job control code and builtins when a job -exits with a non-zero status is `Done(status)'. - -@item -The message printed by the job control code and builtins when a job -is stopped is `Stopped(@var{signame})', where @var{signame} is, for -example, @code{SIGTSTP}. - -@item -The @code{bg} builtin uses the required format to describe each job placed -in the background, which does not include an indication of whether the job -is the current or previous job. - -@item -Reserved words appearing in a context where reserved words are recognized -do not undergo alias expansion. - -@item -The @sc{posix} @env{PS1} and @env{PS2} expansions of @samp{!} to -the history number and @samp{!!} to @samp{!} are enabled, -and parameter expansion is performed on the values of @env{PS1} and -@env{PS2} regardless of the setting of the @code{promptvars} option. - -@item -The @sc{posix} startup files are executed (@env{$ENV}) rather than -the normal Bash files. - -@item -Tilde expansion is only performed on assignments preceding a command -name, rather than on all assignment statements on the line. - -@item -The @code{command} builtin does not prevent builtins that take assignment -statements as arguments from expanding them as assignment statements; -when not in POSIX mode, assignment builtins lose their assignment -statement expansion properties when preceded by @code{command}. - -@item -The default history file is @file{~/.sh_history} (this is the -default value of @env{$HISTFILE}). - -@item -The output of @samp{kill -l} prints all the signal names on a single line, -separated by spaces, without the @samp{SIG} prefix. - -@item -The @code{kill} builtin does not accept signal names with a @samp{SIG} -prefix. - -@item -Non-interactive shells exit if @var{filename} in @code{.} @var{filename} -is not found. - -@item -Non-interactive shells exit if a syntax error in an arithmetic expansion -results in an invalid expression. - -@item -Non-interactive shells exit if there is a syntax error in a script read -with the @code{.} or @code{source} builtins, or in a string processed by -the @code{eval} builtin. - -@item -Redirection operators do not perform filename expansion on the word -in the redirection unless the shell is interactive. - -@item -Redirection operators do not perform word splitting on the word in the -redirection. - -@item -Function names must be valid shell @code{name}s. That is, they may not -contain characters other than letters, digits, and underscores, and -may not start with a digit. Declaring a function with an invalid name -causes a fatal syntax error in non-interactive shells. - -@item -Function names may not be the same as one of the @sc{posix} special -builtins. - -@item -@sc{posix} special builtins are found before shell functions -during command lookup. - -@item -The @code{time} reserved word may be used by itself as a command. When -used in this way, it displays timing statistics for the shell and its -completed children. The @env{TIMEFORMAT} variable controls the format -of the timing information. - -@item -When parsing and expanding a $@{@dots{}@} expansion that appears within -double quotes, single quotes are no longer special and cannot be used to -quote a closing brace or other special character, unless the operator is -one of those defined to perform pattern removal. In this case, they do -not have to appear as matched pairs. - -@item -The parser does not recognize @code{time} as a reserved word if the next -token begins with a @samp{-}. - -@item -If a @sc{posix} special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the @sc{posix} standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@item -A non-interactive shell exits with an error status if a variable -assignment error occurs when no command name follows the assignment -statements. -A variable assignment error occurs, for example, when trying to assign -a value to a readonly variable. - -@item -A non-interactive shell exists with an error status if a variable -assignment error occurs in an assignment statement preceding a special -builtin, but not with any other simple command. - -@item -A non-interactive shell exits with an error status if the iteration -variable in a @code{for} statement or the selection variable in a -@code{select} statement is a readonly variable. - -@item -Process substitution is not available. - -@item -While variable indirection is available, it may not be applied to the -@samp{#} and @samp{?} special parameters. - -@item -Assignment statements preceding @sc{posix} special builtins -persist in the shell environment after the builtin completes. - -@item -Assignment statements preceding shell function calls persist in the -shell environment after the function returns, as if a @sc{posix} -special builtin command had been executed. - -@item -The @code{export} and @code{readonly} builtin commands display their -output in the format required by @sc{posix}. - -@item -The @code{trap} builtin displays signal names without the leading -@code{SIG}. - -@item -The @code{trap} builtin doesn't check the first argument for a possible -signal specification and revert the signal handling to the original -disposition if it is, unless that argument consists solely of digits and -is a valid signal number. If users want to reset the handler for a given -signal to the original disposition, they should use @samp{-} as the -first argument. - -@item -The @code{.} and @code{source} builtins do not search the current directory -for the filename argument if it is not found by searching @env{PATH}. - -@item -Subshells spawned to execute command substitutions inherit the value of -the @option{-e} option from the parent shell. When not in @sc{posix} mode, -Bash clears the @option{-e} option in such subshells. - -@item -Alias expansion is always enabled, even in non-interactive shells. - -@item -When the @code{alias} builtin displays alias definitions, it does not -display them with a leading @samp{alias } unless the @option{-p} option -is supplied. - -@item -When the @code{set} builtin is invoked without options, it does not display -shell function names and definitions. - -@item -When the @code{set} builtin is invoked without options, it displays -variable values without quotes, unless they contain shell metacharacters, -even if the result contains nonprinting characters. - -@item -When the @code{cd} builtin is invoked in @var{logical} mode, and the pathname -constructed from @code{$PWD} and the directory name supplied as an argument -does not refer to an existing directory, @code{cd} will fail instead of -falling back to @var{physical} mode. - -@item -The @code{pwd} builtin verifies that the value it prints is the same as the -current directory, even if it is not asked to check the file system with the -@option{-P} option. - -@item -When listing the history, the @code{fc} builtin does not include an -indication of whether or not a history entry has been modified. - -@item -The default editor used by @code{fc} is @code{ed}. - -@item -The @code{type} and @code{command} builtins will not report a non-executable -file as having been found, though the shell will attempt to execute such a -file if it is the only so-named file found in @code{$PATH}. - -@item -The @code{vi} editing mode will invoke the @code{vi} editor directly when -the @samp{v} command is run, instead of checking @code{$VISUAL} and -@code{$EDITOR}. - -@item -When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret -any arguments to @code{echo} as options. Each argument is displayed, after -escape characters are converted. - -@item -The @code{ulimit} builtin uses a block size of 512 bytes for the @option{-c} -and @option{-f} options. - -@item -The arrival of @code{SIGCHLD} when a trap is set on @code{SIGCHLD} does -not interrupt the @code{wait} builtin and cause it to return immediately. -The trap command is run once for each child that exits. - -@item -The @code{read} builtin may be interrupted by a signal for which a trap -has been set. -If Bash receives a trapped signal while executing @code{read}, the trap -handler executes and @code{read} returns an exit status greater than 128. - -@end enumerate - -There is other @sc{posix} behavior that Bash does not implement by -default even when in @sc{posix} mode. -Specifically: - -@enumerate - -@item -The @code{fc} builtin checks @code{$EDITOR} as a program to edit history -entries if @code{FCEDIT} is unset, rather than defaulting directly to -@code{ed}. @code{fc} uses @code{ed} if @code{EDITOR} is unset. - -@item -As noted above, Bash requires the @code{xpg_echo} option to be enabled for -the @code{echo} builtin to be fully conformant. - -@end enumerate - -Bash can be configured to be @sc{posix}-conformant by default, by specifying -the @option{--enable-strict-posix-default} to @code{configure} when building -(@pxref{Optional Features}). - -@node Job Control -@chapter Job Control - -This chapter discusses what job control is, how it works, and how -Bash allows you to access its facilities. - -@menu -* Job Control Basics:: How job control works. -* Job Control Builtins:: Bash builtin commands used to interact - with job control. -* Job Control Variables:: Variables Bash uses to customize job - control. -@end menu - -@node Job Control Basics -@section Job Control Basics -@cindex job control -@cindex foreground -@cindex background -@cindex suspending jobs - -Job control -refers to the ability to selectively stop (suspend) -the execution of processes and continue (resume) -their execution at a later point. A user typically employs -this facility via an interactive interface supplied jointly -by the operating system kernel's terminal driver and Bash. - -The shell associates a @var{job} with each pipeline. It keeps a -table of currently executing jobs, which may be listed with the -@code{jobs} command. When Bash starts a job -asynchronously, it prints a line that looks -like: -@example -[1] 25647 -@end example -@noindent -indicating that this job is job number 1 and that the process @sc{id} -of the last process in the pipeline associated with this job is -25647. All of the processes in a single pipeline are members of -the same job. Bash uses the @var{job} abstraction as the -basis for job control. - -To facilitate the implementation of the user interface to job -control, the operating system maintains the notion of a current terminal -process group @sc{id}. Members of this process group (processes whose -process group @sc{id} is equal to the current terminal process group -@sc{id}) receive keyboard-generated signals such as @code{SIGINT}. -These processes are said to be in the foreground. Background -processes are those whose process group @sc{id} differs from the -terminal's; such processes are immune to keyboard-generated -signals. Only foreground processes are allowed to read from or, if -the user so specifies with @code{stty tostop}, write to the terminal. -Background processes which attempt to -read from (write to when @code{stty tostop} is in effect) the -terminal are sent a @code{SIGTTIN} (@code{SIGTTOU}) -signal by the kernel's terminal driver, -which, unless caught, suspends the process. - -If the operating system on which Bash is running supports -job control, Bash contains facilities to use it. Typing the -@var{suspend} character (typically @samp{^Z}, Control-Z) while a -process is running causes that process to be stopped and returns -control to Bash. Typing the @var{delayed suspend} character -(typically @samp{^Y}, Control-Y) causes the process to be stopped -when it attempts to read input from the terminal, and control to -be returned to Bash. The user then manipulates the state of -this job, using the @code{bg} command to continue it in the -background, the @code{fg} command to continue it in the -foreground, or the @code{kill} command to kill it. A @samp{^Z} -takes effect immediately, and has the additional side effect of -causing pending output and typeahead to be discarded. - -There are a number of ways to refer to a job in the shell. The -character @samp{%} introduces a job specification (@var{jobspec}). - -Job number @code{n} may be referred to as @samp{%n}. -The symbols @samp{%%} and @samp{%+} refer to the shell's notion of the -current job, which is the last job stopped while it was in the foreground -or started in the background. -A single @samp{%} (with no accompanying job specification) also refers -to the current job. -The previous job may be referenced using @samp{%-}. -If there is only a single job, @samp{%+} and @samp{%-} can both be used -to refer to that job. -In output pertaining to jobs (e.g., the output of the @code{jobs} -command), the current job is always flagged with a @samp{+}, and the -previous job with a @samp{-}. - -A job may also be referred to -using a prefix of the name used to start it, or using a substring -that appears in its command line. For example, @samp{%ce} refers -to a stopped @code{ce} job. Using @samp{%?ce}, on the -other hand, refers to any job containing the string @samp{ce} in -its command line. If the prefix or substring matches more than one job, -Bash reports an error. - -Simply naming a job can be used to bring it into the foreground: -@samp{%1} is a synonym for @samp{fg %1}, bringing job 1 from the -background into the foreground. Similarly, @samp{%1 &} resumes -job 1 in the background, equivalent to @samp{bg %1} - -The shell learns immediately whenever a job changes state. -Normally, Bash waits until it is about to print a prompt -before reporting changes in a job's status so as to not interrupt -any other output. -If the @option{-b} option to the @code{set} builtin is enabled, -Bash reports such changes immediately (@pxref{The Set Builtin}). -Any trap on @code{SIGCHLD} is executed for each child process -that exits. - -If an attempt to exit Bash is made while jobs are stopped, (or running, if -the @code{checkjobs} option is enabled -- see @ref{The Shopt Builtin}), the -shell prints a warning message, and if the @code{checkjobs} option is -enabled, lists the jobs and their statuses. -The @code{jobs} command may then be used to inspect their status. -If a second attempt to exit is made without an intervening command, -Bash does not print another warning, and any stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@table @code - -@item bg -@btindex bg -@example -bg [@var{jobspec} @dots{}] -@end example - -Resume each suspended job @var{jobspec} in the background, as if it -had been started with @samp{&}. -If @var{jobspec} is not supplied, the current job is used. -The return status is zero unless it is run when job control is not -enabled, or, when run with job control enabled, any -@var{jobspec} was not found or specifies a job -that was started without job control. - -@item fg -@btindex fg -@example -fg [@var{jobspec}] -@end example - -Resume the job @var{jobspec} in the foreground and make it the current job. -If @var{jobspec} is not supplied, the current job is used. -The return status is that of the command placed into the foreground, -or non-zero if run when job control is disabled or, when run with -job control enabled, @var{jobspec} does not specify a valid job or -@var{jobspec} specifies a job that was started without job control. - -@item jobs -@btindex jobs -@example -jobs [-lnprs] [@var{jobspec}] -jobs -x @var{command} [@var{arguments}] -@end example - -The first form lists the active jobs. The options have the -following meanings: - -@table @code -@item -l -List process @sc{id}s in addition to the normal information. - -@item -n -Display information only about jobs that have changed status since -the user was last notified of their status. - -@item -p -List only the process @sc{id} of the job's process group leader. - -@item -r -Display only running jobs. - -@item -s -Display only stopped jobs. -@end table - -If @var{jobspec} is given, -output is restricted to information about that job. -If @var{jobspec} is not supplied, the status of all jobs is -listed. - -If the @option{-x} option is supplied, @code{jobs} replaces any -@var{jobspec} found in @var{command} or @var{arguments} with the -corresponding process group @sc{id}, and executes @var{command}, -passing it @var{argument}s, returning its exit status. - -@item kill -@btindex kill -@example -kill [-s @var{sigspec}] [-n @var{signum}] [-@var{sigspec}] @var{jobspec} or @var{pid} -kill -l [@var{exit_status}] -@end example - -Send a signal specified by @var{sigspec} or @var{signum} to the process -named by job specification @var{jobspec} or process @sc{id} @var{pid}. -@var{sigspec} is either a case-insensitive signal name such as -@code{SIGINT} (with or without the @code{SIG} prefix) -or a signal number; @var{signum} is a signal number. -If @var{sigspec} and @var{signum} are not present, @code{SIGTERM} is used. -The @option{-l} option lists the signal names. -If any arguments are supplied when @option{-l} is given, the names of the -signals corresponding to the arguments are listed, and the return status -is zero. -@var{exit_status} is a number specifying a signal number or the exit -status of a process terminated by a signal. -The return status is zero if at least one signal was successfully sent, -or non-zero if an error occurs or an invalid option is encountered. - -@item wait -@btindex wait -@example -wait [@var{jobspec} or @var{pid} @dots{}] -@end example - -Wait until the child process specified by each process @sc{id} @var{pid} -or job specification @var{jobspec} exits and return the exit status of the -last command waited for. -If a job spec is given, all processes in the job are waited for. -If no arguments are given, all currently active child processes are -waited for, and the return status is zero. -If neither @var{jobspec} nor @var{pid} specifies an active child process -of the shell, the return status is 127. - -@item disown -@btindex disown -@example -disown [-ar] [-h] [@var{jobspec} @dots{}] -@end example - -Without options, remove each @var{jobspec} from the table of -active jobs. -If the @option{-h} option is given, the job is not removed from the table, -but is marked so that @code{SIGHUP} is not sent to the job if the shell -receives a @code{SIGHUP}. -If @var{jobspec} is not present, and neither the @option{-a} nor @option{-r} -option is supplied, the current job is used. -If no @var{jobspec} is supplied, the @option{-a} option means to remove or -mark all jobs; the @option{-r} option without a @var{jobspec} -argument restricts operation to running jobs. - -@item suspend -@btindex suspend -@example -suspend [-f] -@end example - -Suspend the execution of this shell until it receives a -@code{SIGCONT} signal. -A login shell cannot be suspended; the @option{-f} -option can be used to override this and force the suspension. -@end table - -When job control is not active, the @code{kill} and @code{wait} -builtins do not accept @var{jobspec} arguments. They must be -supplied process @sc{id}s. - -@node Job Control Variables -@section Job Control Variables - -@vtable @code - -@item auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable exists then single word simple -commands without redirections are treated as candidates for resumption -of an existing job. There is no ambiguity allowed; if there is -more than one job beginning with the string typed, then -the most recently accessed job will be selected. -The name of a stopped job, in this context, is the command line -used to start it. If this variable is set to the value @samp{exact}, -the string supplied must match the name of a stopped job exactly; -if set to @samp{substring}, -the string supplied needs to match a substring of the name of a -stopped job. The @samp{substring} value provides functionality -analogous to the @samp{%?} job @sc{id} (@pxref{Job Control Basics}). -If set to any other value, the supplied string must -be a prefix of a stopped job's name; this provides functionality -analogous to the @samp{%} job @sc{id}. - -@end vtable - -@set readline-appendix -@set history-appendix -@cindex Readline, how to use -@include rluser.texi -@cindex History, how to use -@include hsuser.texi -@clear readline-appendix -@clear history-appendix - -@node Installing Bash -@chapter Installing Bash - -This chapter provides basic instructions for installing Bash on -the various supported platforms. The distribution supports the -@sc{gnu} operating systems, nearly every version of Unix, and several -non-Unix systems such as BeOS and Interix. -Other independent ports exist for -@sc{ms-dos}, @sc{os/2}, and Windows platforms. - -@menu -* Basic Installation:: Installation instructions. -* Compilers and Options:: How to set special options for various - systems. -* Compiling For Multiple Architectures:: How to compile Bash for more - than one kind of system from - the same source tree. -* Installation Names:: How to set the various paths used by the installation. -* Specifying the System Type:: How to configure Bash for a particular system. -* Sharing Defaults:: How to share default configuration values among GNU - programs. -* Operation Controls:: Options recognized by the configuration program. -* Optional Features:: How to enable and disable optional features when - building Bash. -@end menu - -@node Basic Installation -@section Basic Installation -@cindex installation -@cindex configuration -@cindex Bash installation -@cindex Bash configuration - -These are installation instructions for Bash. - -The simplest way to compile Bash is: - -@enumerate -@item -@code{cd} to the directory containing the source code and type -@samp{./configure} to configure Bash for your system. If you're -using @code{csh} on an old version of System V, you might need to -type @samp{sh ./configure} instead to prevent @code{csh} from trying -to execute @code{configure} itself. - -Running @code{configure} takes some time. -While running, it prints messages telling which features it is -checking for. - -@item -Type @samp{make} to compile Bash and build the @code{bashbug} bug -reporting script. - -@item -Optionally, type @samp{make tests} to run the Bash test suite. - -@item -Type @samp{make install} to install @code{bash} and @code{bashbug}. -This will also install the manual pages and Info file. - -@end enumerate - -The @code{configure} shell script attempts to guess correct -values for various system-dependent variables used during -compilation. It uses those values to create a @file{Makefile} in -each directory of the package (the top directory, the -@file{builtins}, @file{doc}, and @file{support} directories, -each directory under @file{lib}, and several others). It also creates a -@file{config.h} file containing system-dependent definitions. -Finally, it creates a shell script named @code{config.status} that you -can run in the future to recreate the current configuration, a -file @file{config.cache} that saves the results of its tests to -speed up reconfiguring, and a file @file{config.log} containing -compiler output (useful mainly for debugging @code{configure}). -If at some point -@file{config.cache} contains results you don't want to keep, you -may remove or edit it. - -To find out more about the options and arguments that the -@code{configure} script understands, type - -@example -bash-2.04$ ./configure --help -@end example - -@noindent -at the Bash prompt in your Bash source directory. - -If you need to do unusual things to compile Bash, please -try to figure out how @code{configure} could check whether or not -to do them, and mail diffs or instructions to -@email{bash-maintainers@@gnu.org} so they can be -considered for the next release. - -The file @file{configure.in} is used to create @code{configure} -by a program called Autoconf. You only need -@file{configure.in} if you want to change it or regenerate -@code{configure} using a newer version of Autoconf. If -you do this, make sure you are using Autoconf version 2.50 or -newer. - -You can remove the program binaries and object files from the -source code directory by typing @samp{make clean}. To also remove the -files that @code{configure} created (so you can compile Bash for -a different kind of computer), type @samp{make distclean}. - -@node Compilers and Options -@section Compilers and Options - -Some systems require unusual options for compilation or linking -that the @code{configure} script does not know about. You can -give @code{configure} initial values for variables by setting -them in the environment. Using a Bourne-compatible shell, you -can do that on the command line like this: - -@example -CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure -@end example - -On systems that have the @code{env} program, you can do it like this: - -@example -env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure -@end example - -The configuration process uses GCC to build Bash if it -is available. - -@node Compiling For Multiple Architectures -@section Compiling For Multiple Architectures - -You can compile Bash for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of @code{make} that -supports the @code{VPATH} variable, such as GNU @code{make}. -@code{cd} to the -directory where you want the object files and executables to go and run -the @code{configure} script from the source directory. You may need to -supply the @option{--srcdir=PATH} argument to tell @code{configure} where the -source files are. @code{configure} automatically checks for the -source code in the directory that @code{configure} is in and in `..'. - -If you have to use a @code{make} that does not supports the @code{VPATH} -variable, you can compile Bash for one architecture at a -time in the source code directory. After you have installed -Bash for one architecture, use @samp{make distclean} before -reconfiguring for another architecture. - -Alternatively, if your system supports symbolic links, you can use the -@file{support/mkclone} script to create a build tree which has -symbolic links back to each file in the source directory. Here's an -example that creates a build directory in the current directory from a -source directory @file{/usr/gnu/src/bash-2.0}: - -@example -bash /usr/gnu/src/bash-2.0/support/mkclone -s /usr/gnu/src/bash-2.0 . -@end example - -@noindent -The @code{mkclone} script requires Bash, so you must have already built -Bash for at least one architecture before you can create build -directories for other architectures. - -@node Installation Names -@section Installation Names - -By default, @samp{make install} will install into -@file{/usr/local/bin}, @file{/usr/local/man}, etc. You can -specify an installation prefix other than @file{/usr/local} by -giving @code{configure} the option @option{--prefix=@var{PATH}}, -or by specifying a value for the @code{DESTDIR} @samp{make} -variable when running @samp{make install}. - -You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. -If you give @code{configure} the option -@option{--exec-prefix=@var{PATH}}, @samp{make install} will use -@var{PATH} as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - -@node Specifying the System Type -@section Specifying the System Type - -There may be some features @code{configure} can not figure out -automatically, but need to determine by the type of host Bash -will run on. Usually @code{configure} can figure that -out, but if it prints a message saying it can not guess the host -type, give it the @option{--host=TYPE} option. @samp{TYPE} can -either be a short name for the system type, such as @samp{sun4}, -or a canonical name with three fields: @samp{CPU-COMPANY-SYSTEM} -(e.g., @samp{i386-unknown-freebsd4.2}). - -See the file @file{support/config.sub} for the possible -values of each field. - -@node Sharing Defaults -@section Sharing Defaults - -If you want to set default values for @code{configure} scripts to -share, you can create a site shell script called -@code{config.site} that gives default values for variables like -@code{CC}, @code{cache_file}, and @code{prefix}. @code{configure} -looks for @file{PREFIX/share/config.site} if it exists, then -@file{PREFIX/etc/config.site} if it exists. Or, you can set the -@code{CONFIG_SITE} environment variable to the location of the site -script. A warning: the Bash @code{configure} looks for a site script, -but not all @code{configure} scripts do. - -@node Operation Controls -@section Operation Controls - -@code{configure} recognizes the following options to control how it -operates. - -@table @code - -@item --cache-file=@var{file} -Use and save the results of the tests in -@var{file} instead of @file{./config.cache}. Set @var{file} to -@file{/dev/null} to disable caching, for debugging -@code{configure}. - -@item --help -Print a summary of the options to @code{configure}, and exit. - -@item --quiet -@itemx --silent -@itemx -q -Do not print messages saying which checks are being made. - -@item --srcdir=@var{dir} -Look for the Bash source code in directory @var{dir}. Usually -@code{configure} can determine that directory automatically. - -@item --version -Print the version of Autoconf used to generate the @code{configure} -script, and exit. -@end table - -@code{configure} also accepts some other, not widely used, boilerplate -options. @samp{configure --help} prints the complete list. - -@node Optional Features -@section Optional Features - -The Bash @code{configure} has a number of @option{--enable-@var{feature}} -options, where @var{feature} indicates an optional part of Bash. -There are also several @option{--with-@var{package}} options, -where @var{package} is something like @samp{bash-malloc} or @samp{purify}. -To turn off the default use of a package, use -@option{--without-@var{package}}. To configure Bash without a feature -that is enabled by default, use @option{--disable-@var{feature}}. - -Here is a complete list of the @option{--enable-} and -@option{--with-} options that the Bash @code{configure} recognizes. - -@table @code -@item --with-afs -Define if you are using the Andrew File System from Transarc. - -@item --with-bash-malloc -Use the Bash version of -@code{malloc} in the directory @file{lib/malloc}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -originally derived from the 4.2 @sc{bsd} @code{malloc}. This @code{malloc} -is very fast, but wastes some space on each allocation. -This option is enabled by default. -The @file{NOTES} file contains a list of systems for -which this should be turned off, and @code{configure} disables this -option automatically for a number of systems. - -@item --with-curses -Use the curses library instead of the termcap library. This should -be supplied if your system has an inadequate or incomplete termcap -database. - -@item --with-gnu-malloc -A synonym for @code{--with-bash-malloc}. - -@item --with-installed-readline[=@var{PREFIX}] -Define this to make Bash link with a locally-installed version of Readline -rather than the version in @file{lib/readline}. This works only with -Readline 5.0 and later versions. If @var{PREFIX} is @code{yes} or not -supplied, @code{configure} uses the values of the make variables -@code{includedir} and @code{libdir}, which are subdirectories of @code{prefix} -by default, to find the installed version of Readline if it is not in -the standard system include and library directories. -If @var{PREFIX} is @code{no}, Bash links with the version in -@file{lib/readline}. -If @var{PREFIX} is set to any other value, @code{configure} treats it as -a directory pathname and looks for -the installed version of Readline in subdirectories of that directory -(include files in @var{PREFIX}/@code{include} and the library in -@var{PREFIX}/@code{lib}). - -@item --with-purify -Define this to use the Purify memory allocation checker from Rational -Software. - -@item --enable-minimal-config -This produces a shell with minimal features, close to the historical -Bourne shell. -@end table - -There are several @option{--enable-} options that alter how Bash is -compiled and linked, rather than changing run-time features. - -@table @code -@item --enable-largefile -Enable support for @uref{http://www.sas.com/standards/large_file/x_open.20Mar96.html, -large files} if the operating system requires special compiler options -to build programs which can access large files. This is enabled by -default, if the operating system provides large file support. - -@item --enable-profiling -This builds a Bash binary that produces profiling information to be -processed by @code{gprof} each time it is executed. - -@item --enable-static-link -This causes Bash to be linked statically, if @code{gcc} is being used. -This could be used to build a version to use as root's shell. -@end table - -The @samp{minimal-config} option can be used to disable all of -the following options, but it is processed first, so individual -options may be enabled using @samp{enable-@var{feature}}. - -All of the following options except for @samp{disabled-builtins} and -@samp{xpg-echo-default} are -enabled by default, unless the operating system does not provide the -necessary support. - -@table @code -@item --enable-alias -Allow alias expansion and include the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item --enable-arith-for-command -Include support for the alternate form of the @code{for} command -that behaves like the C language @code{for} statement -(@pxref{Looping Constructs}). - -@item --enable-array-variables -Include support for one-dimensional array shell variables -(@pxref{Arrays}). - -@item --enable-bang-history -Include support for @code{csh}-like history substitution -(@pxref{History Interaction}). - -@item --enable-brace-expansion -Include @code{csh}-like brace expansion -( @code{b@{a,b@}c} @expansion{} @code{bac bbc} ). -See @ref{Brace Expansion}, for a complete description. - -@item --enable-casemod-attributes -Include support for case-modifying attributes in the @code{declare} builtin -and assignment statements. Variables with the @var{uppercase} attribute, -for example, will have their values converted to uppercase upon assignment. - -@item --enable-casemod-expansion -Include support for case-modifying word expansions. - -@item --enable-command-timing -Include support for recognizing @code{time} as a reserved word and for -displaying timing statistics for the pipeline following @code{time} -(@pxref{Pipelines}). -This allows pipelines as well as shell builtins and functions to be timed. - -@item --enable-cond-command -Include support for the @code{[[} conditional command. -(@pxref{Conditional Constructs}). - -@item --enable-cond-regexp -Include support for matching @sc{posix} regular expressions using the -@samp{=~} binary operator in the @code{[[} conditional command. -(@pxref{Conditional Constructs}). - -@item --enable-coprocesses -Include support for coprocesses and the @code{coproc} reserved word -(@pxref{Pipelines}). - -@item --enable-debugger -Include support for the bash debugger (distributed separately). - -@item --enable-directory-stack -Include support for a @code{csh}-like directory stack and the -@code{pushd}, @code{popd}, and @code{dirs} builtins -(@pxref{The Directory Stack}). - -@item --enable-disabled-builtins -Allow builtin commands to be invoked via @samp{builtin xxx} -even after @code{xxx} has been disabled using @samp{enable -n xxx}. -See @ref{Bash Builtins}, for details of the @code{builtin} and -@code{enable} builtin commands. - -@item --enable-dparen-arithmetic -Include support for the @code{((@dots{}))} command -(@pxref{Conditional Constructs}). - -@item --enable-extended-glob -Include support for the extended pattern matching features described -above under @ref{Pattern Matching}. - -@item --enable-extended-glob-default -Set the default value of the @var{extglob} shell option described -above under @ref{The Shopt Builtin} to be enabled. - -@item --enable-help-builtin -Include the @code{help} builtin, which displays help on shell builtins and -variables (@pxref{Bash Builtins}). - -@item --enable-history -Include command history and the @code{fc} and @code{history} -builtin commands (@pxref{Bash History Facilities}). - -@item --enable-job-control -This enables the job control features (@pxref{Job Control}), -if the operating system supports them. - -@item --enable-multibyte -This enables support for multibyte characters if the operating -system provides the necessary support. - -@item --enable-net-redirections -This enables the special handling of filenames of the form -@code{/dev/tcp/@var{host}/@var{port}} and -@code{/dev/udp/@var{host}/@var{port}} -when used in redirections (@pxref{Redirections}). - -@item --enable-process-substitution -This enables process substitution (@pxref{Process Substitution}) if -the operating system provides the necessary support. - -@item --enable-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@item --enable-prompt-string-decoding -Turn on the interpretation of a number of backslash-escaped characters -in the @env{$PS1}, @env{$PS2}, @env{$PS3}, and @env{$PS4} prompt -strings. See @ref{Controlling the Prompt}, for a complete list of prompt -string escape sequences. - -@item --enable-readline -Include support for command-line editing and history with the Bash -version of the Readline library (@pxref{Command Line Editing}). - -@item --enable-restricted -Include support for a @dfn{restricted shell}. If this is enabled, Bash, -when called as @code{rbash}, enters a restricted mode. See -@ref{The Restricted Shell}, for a description of restricted mode. - -@item --enable-select -Include the @code{select} compound command, which allows the generation of -simple menus (@pxref{Conditional Constructs}). - -@item --enable-separate-helpfiles -Use external files for the documentation displayed by the @code{help} builtin -instead of storing the text internally. - -@item --enable-single-help-strings -Store the text displayed by the @code{help} builtin as a single string for -each help topic. This aids in translating the text to different languages. -You may need to disable this if your compiler cannot handle very long string -literals. - -@item --enable-strict-posix-default -Make Bash @sc{posix}-conformant by default (@pxref{Bash POSIX Mode}). - -@item --enable-usg-echo-default -A synonym for @code{--enable-xpg-echo-default}. - -@item --enable-xpg-echo-default -Make the @code{echo} builtin expand backslash-escaped characters by default, -without requiring the @option{-e} option. -This sets the default value of the @code{xpg_echo} shell option to @code{on}, -which makes the Bash @code{echo} behave more like the version specified in -the Single Unix Specification, version 3. -@xref{Bash Builtins}, for a description of the escape sequences that -@code{echo} recognizes. -@end table - -The file @file{config-top.h} contains C Preprocessor -@samp{#define} statements for options which are not settable from -@code{configure}. -Some of these are not meant to be changed; beware of the consequences if -you do. -Read the comments associated with each definition for more -information about its effect. - -@node Reporting Bugs -@appendix Reporting Bugs - -Please report all bugs you find in Bash. -But first, you should -make sure that it really is a bug, and that it appears in the latest -version of Bash. -The latest version of Bash is always available for FTP from -@uref{ftp://ftp.gnu.org/pub/gnu/bash/}. - -Once you have determined that a bug actually exists, use the -@code{bashbug} command to submit a bug report. -If you have a fix, you are encouraged to mail that as well! -Suggestions and `philosophical' bug reports may be mailed -to @email{bug-bash@@gnu.org} or posted to the Usenet -newsgroup @code{gnu.bash.bug}. - -All bug reports should include: -@itemize @bullet -@item -The version number of Bash. -@item -The hardware and operating system. -@item -The compiler used to compile Bash. -@item -A description of the bug behaviour. -@item -A short script or `recipe' which exercises the bug and may be used -to reproduce it. -@end itemize - -@noindent -@code{bashbug} inserts the first three items automatically into -the template it provides for filing a bug report. - -Please send all reports concerning this manual to -@email{chet.ramey@@case.edu}. - -@node Major Differences From The Bourne Shell -@appendix Major Differences From The Bourne Shell - -Bash implements essentially the same grammar, parameter and -variable expansion, redirection, and quoting as the Bourne Shell. -Bash uses the @sc{posix} standard as the specification of -how these features are to be implemented. There are some -differences between the traditional Bourne shell and Bash; this -section quickly details the differences of significance. A -number of these differences are explained in greater depth in -previous sections. -This section uses the version of @code{sh} included in SVR4.2 (the -last version of the historical Bourne shell) as the baseline reference. - -@itemize @bullet - -@item -Bash is @sc{posix}-conformant, even where the @sc{posix} specification -differs from traditional @code{sh} behavior (@pxref{Bash POSIX Mode}). - -@item -Bash has multi-character invocation options (@pxref{Invoking Bash}). - -@item -Bash has command-line editing (@pxref{Command Line Editing}) and -the @code{bind} builtin. - -@item -Bash provides a programmable word completion mechanism -(@pxref{Programmable Completion}), and builtin commands -@code{complete}, @code{compgen}, and @code{compopt}, to -manipulate it. - -@item -Bash has command history (@pxref{Bash History Facilities}) and the -@code{history} and @code{fc} builtins to manipulate it. -The Bash history list maintains timestamp information and uses the -value of the @code{HISTTIMEFORMAT} variable to display it. - -@item -Bash implements @code{csh}-like history expansion -(@pxref{History Interaction}). - -@item -Bash has one-dimensional array variables (@pxref{Arrays}), and the -appropriate variable expansions and assignment syntax to use them. -Several of the Bash builtins take options to act on arrays. -Bash provides a number of built-in array variables. - -@item -The @code{$'@dots{}'} quoting syntax, which expands ANSI-C -backslash-escaped characters in the text between the single quotes, -is supported (@pxref{ANSI-C Quoting}). - -@item -Bash supports the @code{$"@dots{}"} quoting syntax to do -locale-specific translation of the characters between the double -quotes. The @option{-D}, @option{--dump-strings}, and @option{--dump-po-strings} -invocation options list the translatable strings found in a script -(@pxref{Locale Translation}). - -@item -Bash implements the @code{!} keyword to negate the return value of -a pipeline (@pxref{Pipelines}). -Very useful when an @code{if} statement needs to act only if a test fails. -The Bash @samp{-o pipefail} option to @code{set} will cause a pipeline to -return a failure status if any command fails. - -@item -Bash has the @code{time} reserved word and command timing (@pxref{Pipelines}). -The display of the timing statistics may be controlled with the -@env{TIMEFORMAT} variable. - -@item -Bash implements the @code{for (( @var{expr1} ; @var{expr2} ; @var{expr3} ))} -arithmetic for command, similar to the C language (@pxref{Looping Constructs}). - -@item -Bash includes the @code{select} compound command, which allows the -generation of simple menus (@pxref{Conditional Constructs}). - -@item -Bash includes the @code{[[} compound command, which makes conditional -testing part of the shell grammar (@pxref{Conditional Constructs}), including -optional regular expression matching. - -@item -Bash provides optional case-insensitive matching for the @code{case} and -@code{[[} constructs. - -@item -Bash includes brace expansion (@pxref{Brace Expansion}) and tilde -expansion (@pxref{Tilde Expansion}). - -@item -Bash implements command aliases and the @code{alias} and @code{unalias} -builtins (@pxref{Aliases}). - -@item -Bash provides shell arithmetic, the @code{((} compound command -(@pxref{Conditional Constructs}), -and arithmetic expansion (@pxref{Shell Arithmetic}). - -@item -Variables present in the shell's initial environment are automatically -exported to child processes. The Bourne shell does not normally do -this unless the variables are explicitly marked using the @code{export} -command. - -@item -Bash supports the @samp{+=} assignment operator, which appends to the value -of the variable named on the left hand side. - -@item -Bash includes the @sc{posix} pattern removal @samp{%}, @samp{#}, @samp{%%} -and @samp{##} expansions to remove leading or trailing substrings from -variable values (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{#xx@}}, which returns the length of @code{$@{xx@}}, -is supported (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{var:}@var{offset}@code{[:}@var{length}@code{]@}}, -which expands to the substring of @code{var}'s value of length -@var{length}, beginning at @var{offset}, is present -(@pxref{Shell Parameter Expansion}). - -@item -The expansion -@code{$@{var/[/]}@var{pattern}@code{[/}@var{replacement}@code{]@}}, -which matches @var{pattern} and replaces it with @var{replacement} in -the value of @code{var}, is available (@pxref{Shell Parameter Expansion}). - -@item -The expansion @code{$@{!@var{prefix}*@}} expansion, which expands to -the names of all shell variables whose names begin with @var{prefix}, -is available (@pxref{Shell Parameter Expansion}). - -@item -Bash has @var{indirect} variable expansion using @code{$@{!word@}} -(@pxref{Shell Parameter Expansion}). - -@item -Bash can expand positional parameters beyond @code{$9} using -@code{$@{@var{num}@}}. - -@item -The @sc{posix} @code{$()} form of command substitution -is implemented (@pxref{Command Substitution}), -and preferred to the Bourne shell's @code{``} (which -is also implemented for backwards compatibility). - -@item -Bash has process substitution (@pxref{Process Substitution}). - -@item -Bash automatically assigns variables that provide information about the -current user (@env{UID}, @env{EUID}, and @env{GROUPS}), the current host -(@env{HOSTTYPE}, @env{OSTYPE}, @env{MACHTYPE}, and @env{HOSTNAME}), -and the instance of Bash that is running (@env{BASH}, -@env{BASH_VERSION}, and @env{BASH_VERSINFO}). @xref{Bash Variables}, -for details. - -@item -The @env{IFS} variable is used to split only the results of expansion, -not all words (@pxref{Word Splitting}). -This closes a longstanding shell security hole. - -@item -Bash implements the full set of @sc{posix} filename expansion operators, -including @var{character classes}, @var{equivalence classes}, and -@var{collating symbols} (@pxref{Filename Expansion}). - -@item -Bash implements extended pattern matching features when the @code{extglob} -shell option is enabled (@pxref{Pattern Matching}). - -@item -It is possible to have a variable and a function with the same name; -@code{sh} does not separate the two name spaces. - -@item -Bash functions are permitted to have local variables using the -@code{local} builtin, and thus useful recursive functions may be written -(@pxref{Bash Builtins}). - -@item -Variable assignments preceding commands affect only that command, even -builtins and functions (@pxref{Environment}). -In @code{sh}, all variable assignments -preceding commands are global unless the command is executed from the -file system. - -@item -Bash performs filename expansion on filenames specified as operands -to input and output redirection operators (@pxref{Redirections}). - -@item -Bash contains the @samp{<>} redirection operator, allowing a file to be -opened for both reading and writing, and the @samp{&>} redirection -operator, for directing standard output and standard error to the same -file (@pxref{Redirections}). - -@item -Bash includes the @samp{<<<} redirection operator, allowing a string to -be used as the standard input to a command. - -@item -Bash implements the @samp{[n]<&@var{word}} and @samp{[n]>&@var{word}} -redirection operators, which move one file descriptor to another. - -@item -Bash treats a number of filenames specially when they are -used in redirection operators (@pxref{Redirections}). - -@item -Bash can open network connections to arbitrary machines and services -with the redirection operators (@pxref{Redirections}). - -@item -The @code{noclobber} option is available to avoid overwriting existing -files with output redirection (@pxref{The Set Builtin}). -The @samp{>|} redirection operator may be used to override @code{noclobber}. - -@item -The Bash @code{cd} and @code{pwd} builtins (@pxref{Bourne Shell Builtins}) -each take @option{-L} and @option{-P} options to switch between logical and -physical modes. - -@item -Bash allows a function to override a builtin with the same name, and provides -access to that builtin's functionality within the function via the -@code{builtin} and @code{command} builtins (@pxref{Bash Builtins}). - -@item -The @code{command} builtin allows selective disabling of functions -when command lookup is performed (@pxref{Bash Builtins}). - -@item -Individual builtins may be enabled or disabled using the @code{enable} -builtin (@pxref{Bash Builtins}). - -@item -The Bash @code{exec} builtin takes additional options that allow users -to control the contents of the environment passed to the executed -command, and what the zeroth argument to the command is to be -(@pxref{Bourne Shell Builtins}). - -@item -Shell functions may be exported to children via the environment -using @code{export -f} (@pxref{Shell Functions}). - -@item -The Bash @code{export}, @code{readonly}, and @code{declare} builtins can -take a @option{-f} option to act on shell functions, a @option{-p} option to -display variables with various attributes set in a format that can be -used as shell input, a @option{-n} option to remove various variable -attributes, and @samp{name=value} arguments to set variable attributes -and values simultaneously. - -@item -The Bash @code{hash} builtin allows a name to be associated with -an arbitrary filename, even when that filename cannot be found by -searching the @env{$PATH}, using @samp{hash -p} -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes a @code{help} builtin for quick reference to shell -facilities (@pxref{Bash Builtins}). - -@item -The @code{printf} builtin is available to display formatted output -(@pxref{Bash Builtins}). - -@item -The Bash @code{read} builtin (@pxref{Bash Builtins}) -will read a line ending in @samp{\} with -the @option{-r} option, and will use the @env{REPLY} variable as a -default if no non-option arguments are supplied. -The Bash @code{read} builtin -also accepts a prompt string with the @option{-p} option and will use -Readline to obtain the line when given the @option{-e} option. -The @code{read} builtin also has additional options to control input: -the @option{-s} option will turn off echoing of input characters as -they are read, the @option{-t} option will allow @code{read} to time out -if input does not arrive within a specified number of seconds, the -@option{-n} option will allow reading only a specified number of -characters rather than a full line, and the @option{-d} option will read -until a particular character rather than newline. - -@item -The @code{return} builtin may be used to abort execution of scripts -executed with the @code{.} or @code{source} builtins -(@pxref{Bourne Shell Builtins}). - -@item -Bash includes the @code{shopt} builtin, for finer control of shell -optional capabilities (@pxref{The Shopt Builtin}), and allows these options -to be set and unset at shell invocation (@pxref{Invoking Bash}). - -@item -Bash has much more optional behavior controllable with the @code{set} -builtin (@pxref{The Set Builtin}). - -@item -The @samp{-x} (@option{xtrace}) option displays commands other than -simple commands when performing an execution trace -(@pxref{The Set Builtin}). - -@item -The @code{test} builtin (@pxref{Bourne Shell Builtins}) -is slightly different, as it implements the @sc{posix} algorithm, -which specifies the behavior based on the number of arguments. - -@item -Bash includes the @code{caller} builtin, which displays the context of -any active subroutine call (a shell function or a script executed with -the @code{.} or @code{source} builtins). This supports the bash -debugger. - -@item -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{DEBUG} pseudo-signal specification, similar to @code{EXIT}. -Commands specified with a @code{DEBUG} trap are executed before every -simple command, @code{for} command, @code{case} command, -@code{select} command, every arithmetic @code{for} command, and before -the first command executes in a shell function. -The @code{DEBUG} trap is not inherited by shell functions unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. -The @code{extdebug} shell option has additional effects on the -@code{DEBUG} trap. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows an -@code{ERR} pseudo-signal specification, similar to @code{EXIT} and @code{DEBUG}. -Commands specified with an @code{ERR} trap are executed after a simple -command fails, with a few exceptions. -The @code{ERR} trap is not inherited by shell functions unless the -@code{-o errtrace} option to the @code{set} builtin is enabled. - -The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a -@code{RETURN} pseudo-signal specification, similar to -@code{EXIT} and @code{DEBUG}. -Commands specified with an @code{RETURN} trap are executed before -execution resumes after a shell function or a shell script executed with -@code{.} or @code{source} returns. -The @code{RETURN} trap is not inherited by shell functions unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. - -@item -The Bash @code{type} builtin is more extensive and gives more information -about the names it finds (@pxref{Bash Builtins}). - -@item -The Bash @code{umask} builtin permits a @option{-p} option to cause -the output to be displayed in the form of a @code{umask} command -that may be reused as input (@pxref{Bourne Shell Builtins}). - -@item -Bash implements a @code{csh}-like directory stack, and provides the -@code{pushd}, @code{popd}, and @code{dirs} builtins to manipulate it -(@pxref{The Directory Stack}). -Bash also makes the directory stack visible as the value of the -@env{DIRSTACK} shell variable. - -@item -Bash interprets special backslash-escaped characters in the prompt -strings when interactive (@pxref{Controlling the Prompt}). - -@item -The Bash restricted mode is more useful (@pxref{The Restricted Shell}); -the SVR4.2 shell restricted mode is too limited. - -@item -The @code{disown} builtin can remove a job from the internal shell -job table (@pxref{Job Control Builtins}) or suppress the sending -of @code{SIGHUP} to a job when the shell exits as the result of a -@code{SIGHUP}. - -@item -Bash includes a number of features to support a separate debugger for -shell scripts. - -@item -The SVR4.2 shell has two privilege-related builtins -(@code{mldmode} and @code{priv}) not present in Bash. - -@item -Bash does not have the @code{stop} or @code{newgrp} builtins. - -@item -Bash does not use the @env{SHACCT} variable or perform shell accounting. - -@item -The SVR4.2 @code{sh} uses a @env{TIMEOUT} variable like Bash uses -@env{TMOUT}. - -@end itemize - -@noindent -More features unique to Bash may be found in @ref{Bash Features}. - - -@appendixsec Implementation Differences From The SVR4.2 Shell - -Since Bash is a completely new implementation, it does not suffer from -many of the limitations of the SVR4.2 shell. For instance: - -@itemize @bullet - -@item -Bash does not fork a subshell when redirecting into or out of -a shell control structure such as an @code{if} or @code{while} -statement. - -@item -Bash does not allow unbalanced quotes. The SVR4.2 shell will silently -insert a needed closing quote at @code{EOF} under certain circumstances. -This can be the cause of some hard-to-find errors. - -@item -The SVR4.2 shell uses a baroque memory management scheme based on -trapping @code{SIGSEGV}. If the shell is started from a process with -@code{SIGSEGV} blocked (e.g., by using the @code{system()} C library -function call), it misbehaves badly. - -@item -In a questionable attempt at security, the SVR4.2 shell, -when invoked without the @option{-p} option, will alter its real -and effective @sc{uid} and @sc{gid} if they are less than some -magic threshold value, commonly 100. -This can lead to unexpected results. - -@item -The SVR4.2 shell does not allow users to trap @code{SIGSEGV}, -@code{SIGALRM}, or @code{SIGCHLD}. - -@item -The SVR4.2 shell does not allow the @env{IFS}, @env{MAILCHECK}, -@env{PATH}, @env{PS1}, or @env{PS2} variables to be unset. - -@item -The SVR4.2 shell treats @samp{^} as the undocumented equivalent of -@samp{|}. - -@item -Bash allows multiple option arguments when it is invoked (@code{-x -v}); -the SVR4.2 shell allows only one option argument (@code{-xv}). In -fact, some versions of the shell dump core if the second argument begins -with a @samp{-}. - -@item -The SVR4.2 shell exits a script if any builtin fails; Bash exits -a script only if one of the @sc{posix} special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} standard. - -@item -The SVR4.2 shell behaves differently when invoked as @code{jsh} -(it turns on job control). -@end itemize - -@node GNU Free Documentation License -@appendix GNU Free Documentation License - -@include fdl.texi - -@node Indexes -@appendix Indexes - -@menu -* Builtin Index:: Index of Bash builtin commands. -* Reserved Word Index:: Index of Bash reserved words. -* Variable Index:: Quick reference helps you find the - variable you want. -* Function Index:: Index of bindable Readline functions. -* Concept Index:: General index for concepts described in - this manual. -@end menu - -@node Builtin Index -@appendixsec Index of Shell Builtin Commands -@printindex bt - -@node Reserved Word Index -@appendixsec Index of Shell Reserved Words -@printindex rw - -@node Variable Index -@appendixsec Parameter and Variable Index -@printindex vr - -@node Function Index -@appendixsec Function Index -@printindex fn - -@node Concept Index -@appendixsec Concept Index -@printindex cp - -@bye diff --git a/doc/version.texi~ b/doc/version.texi~ deleted file mode 100644 index 34f4cfb9c..000000000 --- a/doc/version.texi~ +++ /dev/null @@ -1,19 +0,0 @@ -@ignore -Copyright (C) 1988-2012 Free Software Foundation, Inc. -@end ignore - -@set LASTCHANGE Thu Jul 5 19:37:34 EDT 2012 - -@set EDITION 4.2 -@set VERSION 4.2 -@set UPDATED 5 July 2012 -@set UPDATED-MONTH July 2012 - - - - - - - - - diff --git a/eval.c~ b/eval.c~ deleted file mode 100644 index aaa61dd72..000000000 --- a/eval.c~ +++ /dev/null @@ -1,283 +0,0 @@ -/* eval.c -- reading and evaluating commands. */ - -/* Copyright (C) 1996-2011 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 . -*/ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bashansi.h" -#include - -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "trap.h" - -#include "builtins/common.h" - -#include "input.h" -#include "execute_cmd.h" - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int EOF_reached; -extern int indirection_level; -extern int posixly_correct; -extern int subshell_environment, running_under_emacs; -extern int last_command_exit_value, stdin_redir; -extern int need_here_doc; -extern int current_command_number, current_command_line_count, line_number; -extern int expand_aliases; - -static void send_pwd_to_eterm __P((void)); -static sighandler alrm_catcher __P((int)); - -/* Read and execute commands until EOF is reached. This assumes that - the input source has already been initialized. */ -int -reader_loop () -{ - int our_indirection_level; - COMMAND * volatile current_command; - - USE_VAR(current_command); - - current_command = (COMMAND *)NULL; - - our_indirection_level = ++indirection_level; - - while (EOF_Reached == 0) - { - int code; - - code = setjmp (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - if (interactive_shell && signal_is_ignored (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) - { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - current_command = (COMMAND *)NULL; - if (exit_immediately_on_error) - variable_context = 0; /* not in a function */ - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - /* Make sure the exit status is reset to a non-zero value, but - leave existing non-zero values (e.g., > 128 on signal) - alone. */ - if (last_command_exit_value == 0) - last_command_exit_value = EXECUTION_FAILURE; - if (subshell_environment) - { - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - } - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - break; - - default: - command_error ("reader_loop", CMDERR_BADJUMP, code, 0); - } - } - - executing = 0; - if (temporary_env) - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif - - if (read_command () == 0) - { - if (interactive_shell == 0 && read_but_dont_execute) - { - last_command_exit_value = EXECUTION_SUCCESS; - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else if (current_command = global_command) - { - global_command = (COMMAND *)NULL; - current_command_number++; - - executing = 1; - stdin_redir = 0; - execute_command (current_command); - - exec_done: - QUIT; - - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - } - } - else - { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (interactive == 0) - EOF_Reached = EOF; - } - if (just_one_command) - EOF_Reached = EOF; - } - indirection_level--; - return (last_command_exit_value); -} - -static sighandler -alrm_catcher(i) - int i; -{ - printf (_("\007timed out waiting for input: auto-logout\n")); - fflush (stdout); - bash_logout (); /* run ~/.bash_logout if this is a login shell */ - jump_to_top_level (EXITPROG); - SIGRETURN (0); -} - -/* Send an escape sequence to emacs term mode to tell it the - current working directory. */ -static void -send_pwd_to_eterm () -{ - char *pwd, *f; - - f = 0; - pwd = get_string_value ("PWD"); - if (pwd == 0) - f = pwd = get_working_directory ("eterm"); - fprintf (stderr, "\032/%s\n", pwd); - free (f); -} - -/* Call the YACC-generated parser and return the status of the parse. - Input is read from the current input stream (bash_input). yyparse - leaves the parsed command in the global variable GLOBAL_COMMAND. - This is where PROMPT_COMMAND is executed. */ -int -parse_command () -{ - int r; - char *command_to_execute; - - need_here_doc = 0; - run_pending_traps (); - - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then the value of it is the command to execute. */ - if (interactive && bash_input.type != st_string) - { - command_to_execute = get_string_value ("PROMPT_COMMAND"); - if (command_to_execute) - execute_variable_command (command_to_execute, "PROMPT_COMMAND"); - - if (running_under_emacs == 2) - send_pwd_to_eterm (); /* Yuck */ - } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); -} - -/* Read and parse a command, returning the status of the parse. The command - is left in the globval variable GLOBAL_COMMAND for use by reader_loop. - This is where the shell timeout code is executed. */ -int -read_command () -{ - SHELL_VAR *tmout_var; - int tmout_len, result; - SigHandler *old_alrm; - - set_current_prompt_level (1); - global_command = (COMMAND *)NULL; - - /* Only do timeouts if interactive. */ - tmout_var = (SHELL_VAR *)NULL; - tmout_len = 0; - old_alrm = (SigHandler *)NULL; - - if (interactive) - { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && var_isset (tmout_var)) - { - tmout_len = atoi (value_cell (tmout_var)); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } - } - - QUIT; - - current_command_line_count = 0; - result = parse_command (); - - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - - return (result); -} diff --git a/examples/loadables/Makefile.in.save b/examples/loadables/Makefile.in.save deleted file mode 100644 index f6208f5cc..000000000 --- a/examples/loadables/Makefile.in.save +++ /dev/null @@ -1,238 +0,0 @@ -# -# Simple makefile for the sample loadable builtins -# -# Copyright (C) 1996 Free Software Foundation, Inc. - -# This program 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 2, or (at your option) -# any later version. - -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -@SET_MAKE@ -CC = @CC@ -RM = rm -f - -SHELL = @MAKE_SHELL@ - -host_os = @host_os@ -host_cpu = @host_cpu@ -host_vendor = @host_vendor@ - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -CPPFLAGS = @CPPFLAGS@ - -BASHINCDIR = ${topdir}/include - -LIBBUILD = ${BUILD_DIR}/lib - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_INC = @INTL_INC@ -LIBINTL_H = @LIBINTL_H@ - -CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) - -# -# These values are generated for configure by ${topdir}/support/shobj-conf. -# If your system is not supported by that script, but includes facilities for -# dynamic loading of shared objects, please update the script and send the -# changes to bash-maintainers@gnu.org. -# -SHOBJ_CC = @SHOBJ_CC@ -SHOBJ_CFLAGS = @SHOBJ_CFLAGS@ -SHOBJ_LD = @SHOBJ_LD@ -SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ -SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@ -SHOBJ_LIBS = @SHOBJ_LIBS@ -SHOBJ_STATUS = @SHOBJ_STATUS@ - -INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ - -I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \ - -I$(BUILD_DIR)/builtins $(INTL_INC) - -.c.o: - $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $< - - -ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ - tty pathchk tee head mkdir rmdir printenv id whoami \ - uname sync push ln unlink cut realpath getconf strftime -OTHERPROG = necho hello cat - -all: $(SHOBJ_STATUS) - -supported: $(ALLPROG) -others: $(OTHERPROG) - -unsupported: - @echo "Your system (${host_os}) is not supported by the" - @echo "${topdir}/support/shobj-conf script." - @echo "If your operating system provides facilities for dynamic" - @echo "loading of shared objects using the dlopen(3) interface," - @echo "please update the script and re-run configure. - @echo "Please send the changes you made to bash-maintainers@gnu.org" - @echo "for inclusion in future bash releases." - -everything: supported others - -print: print.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS) - -necho: necho.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS) - -getconf: getconf.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS) - -hello: hello.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS) - -truefalse: truefalse.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS) - -sleep: sleep.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS) - -finfo: finfo.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS) - -cat: cat.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS) - -logname: logname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS) - -basename: basename.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS) - -dirname: dirname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS) - -tty: tty.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS) - -pathchk: pathchk.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS) - -tee: tee.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS) - -mkdir: mkdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS) - -rmdir: rmdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS) - -head: head.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS) - -printenv: printenv.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS) - -id: id.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS) - -whoami: whoami.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS) - -uname: uname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS) - -sync: sync.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS) - -push: push.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS) - -ln: ln.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS) - -unlink: unlink.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS) - -cut: cut.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS) - -realpath: realpath.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) - -strftime: strftime.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS) - -# pushd is a special case. We use the same source that the builtin version -# uses, with special compilation options. -# -pushd.c: ${topdir}/builtins/pushd.def - $(RM) $@ - ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def - -pushd.o: pushd.c - $(RM) $@ - $(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $< - -pushd: pushd.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS) - -clean: - $(RM) $(ALLPROG) $(OTHERPROG) *.o - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -mostlyclean: clean - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -distclean maintainer-clean: clean - $(RM) Makefile pushd.c - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -print.o: print.c -truefalse.o: truefalse.c -sleep.o: sleep.c -finfo.o: finfo.c -logname.o: logname.c -basename.o: basename.c -dirname.o: dirname.c -tty.o: tty.c -pathchk.o: pathchk.c -tee.o: tee.c -head.o: head.c -rmdir.o: rmdir.c -necho.o: necho.c -getconf.o: getconf.c -hello.o: hello.c -cat.o: cat.c -printenv.o: printenv.c -id.o: id.c -whoami.o: whoami.c -uname.o: uname.c -sync.o: sync.c -push.o: push.c -mkdir.o: mkdir.c -realpath.o: realpath.c -strftime.o: strftime.c diff --git a/examples/scripts/adventure.sh.save1 b/examples/scripts/adventure.sh.save1 deleted file mode 100755 index 4e2239396..000000000 --- a/examples/scripts/adventure.sh.save1 +++ /dev/null @@ -1,549 +0,0 @@ -#!/bin/bash -# ash -- "Adventure shell" -# last edit: 86/04/21 D A Gwyn -# SCCS ID: @(#)ash.sh 1.4 - -OPATH=$PATH - -ask() -{ - echo -n "$@" '[y/n] ' - read ans - - case "$ans" in - y*|Y*) - return 0 - ;; - *) - return 1 - ;; - esac -} - -CAT=${PAGER:-more} - -ash_inst() -{ - cat <<- EOF - - Instructions for the Adventure shell - - Welcome to the Adventure shell! In this exploration of the UNIX file - system, I will act as your eyes and hands. As you move around, I will - describe whatever is visible and will carry out your commands. The - general form of a command is - Verb Object Extra_stuff. - Most commands pay no attention to the "Extra_stuff", and many do not - need an "Object". A typical command is - get all - which picks up all files in the current "room" (directory). You can - find out what you are carrying by typing the command - inventory - The command "help" results in a full description of all commands that I - understand. To quit the Adventure shell, type - quit - - There are UNIX monsters lurking in the background. These are also - known as "commands with arguments". - - Good luck! - EOF -} - -ash_help() -{ -echo "I understand the following commands (synonyms in parentheses):" -echo "" - -echo "change OBJECT to NEW_NAME changes the name of the object" -echo "clone OBJECT as NEW_NAME duplicates the object" -echo "drop OBJECTS leaves the objects in the room" -echo "enter (go) PASSAGE takes the labeled passage" -echo "examine OBJECTS describes the objects in detail" -echo "feed OBJECT to MONSTER stuffs the object into a UNIX monster" -echo "get (take) OBJECTS picks up the specified objects" -echo "gripe (bug) report a problem with the Adventure shell" -echo "help prints this summary" -echo "inventory (i) tells what you are carrying" -echo "kill (destroy) OBJECTS destroys the objects" -echo "look (l) describes the room, including hidden objects" -echo "open (read) OBJECT shows the contents of an object" -echo "quit (exit) leaves the Adventure shell" -echo "resurrect OBJECTS attempts to restore dead objects" -echo "steal OBJECT from MONSTER obtains the object from a UNIX monster" -echo "throw OBJECT at daemon feeds the object to the printer daemon" -echo "up takes the overhead passage" -echo "wake MONSTER awakens a UNIX monster" -echo "where (w) tells you where you are" -echo "xyzzy moves you to your home" -} - -MAINT=chet@ins.cwru.edu - -PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin:. -export PATH - -trap 'echo Ouch!' 2 3 -#trap '' 18 # disable Berkeley job control - -ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; } -ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; } -ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; } - -# enable history, bang history expansion, and emacs editing -set -o history -set -o histexpand -set -o emacs - -cd -LIM=.limbo # $HOME/$LIM contains "destroyed" objects -mkdir $LIM >&- 2>&- -KNAP=.knapsack # $HOME/$KNAP contains objects being "carried" -if [ ! -d $KNAP ] -then mkdir $KNAP >&- 2>&- - if [ $? = 0 ] - then echo 'You found a discarded empty knapsack.' - else echo 'You have no knapsack to carry things in.' - exit 1 - fi -else echo 'One moment while I peek in your old knapsack...' -fi - -kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\`` - -if ask 'Welcome to the Adventure shell! Do you need instructions?' -then - ash_inst - echo -n 'Type a newline to continue: ' - read -fi - -wiz=false -cha=false -prev=$LIM -while : -do room=`pwd` - if [ $room != $prev ] - then if [ $room = $HOME ] - then echo 'You are in your own home.' - else echo "You have entered $room." - fi - exs= - obs= - hexs= - hobs= - f=false - for i in `ls -a` - do case $i in - .|..) ;; - .*) if [ -f $i ] - then hobs="$hobs $i" - elif [ -d $i ] - then hexs="$hexs $i" - else f=true - fi - ;; - *) if [ -f $i ] - then obs="$obs $i" - elif [ -d $i ] - then exs="$exs $i" - else f=true - fi - ;; - esac - done - if [ "$obs" ] - then echo 'This room contains:' - ash_pr $obs - else echo 'The room looks empty.' - fi - if [ "$exs" ] - then echo 'There are exits labeled:' - ash_pr $exs - echo 'as well as a passage overhead.' - else echo 'There is a passage overhead.' - fi - if sh -c $f - then echo 'There are shadowy figures in the corner.' - fi - prev=$room - fi - - read -e -p '-advsh> ' verb obj x # prompt is '-advsh> ' - if [ $? != 0 ] - then verb=quit # EOF - fi - - case $verb in - change) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then set -- $x - case "$1" in - to) if [ "$2" ] - then if [ -f $2 ] - then echo "You must destroy $2 first." - set -- - fi - if [ "$2" ] - then if mv $obj $2 >&- 2>&- - then echo "The $obj shimmers and turns into $2." - obs=`ash_rm "$2 $obs" "$obj"` - else echo "There is a cloud of smoke but the $obj is unchanged." - fi - fi - else echo 'To what?' - fi - ;; - *) echo "Change $obj to what?" - ;; - esac - else if ash_lk "$kn" "$obj" - then echo 'You must drop it first.' - else echo "I see no $obj here." - fi - fi - else echo 'Change what?' - fi - ;; - clone) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then if [ ! -r $obj ] - then echo "The $obj does not wish to be cloned." - else set -- $x - case "$1" in - as) if [ "$2" ] - then if [ -f $2 ] - then echo "You must destroy $2 first." - else if cp $obj $2 >&- 2>&- - then echo "Poof! When the smoke clears, you see the new $2." - obs="$obs $2" - else echo 'You hear a dull thud but no clone appears.' - fi - fi - else echo 'As what?' - fi - ;; - *) echo "Clone $obj as what?" - ;; - esac - fi - else if ash_lk "$kn" "$obj" - then echo 'You must drop it first.' - else echo "I see no $obj here." - fi - fi - else echo 'Clone what?' - fi - ;; - drop) if [ "$obj" ] - then for it in $obj $x - do if ash_lk "$kn" "$it" - then if [ -w $it ] - then echo "You must destroy $it first." - else if mv $HOME/$KNAP/$it $it >&- 2>&- - then echo "$it: dropped." - kn=`ash_rm "$kn" "$it"` - obs=`echo $it $obs` - else echo "The $it is caught in your knapsack." - fi - fi - else echo "You're not carrying the $it!" - fi - done - else echo 'Drop what?' - fi - ;; - enter|go) if [ "$obj" ] - then if [ $obj != up ] - then if ash_lk "$exs $hexs" "$obj" - then if [ -x $obj ] - then if cd $obj - then echo 'You squeeze through the passage.' - else echo "You can't go that direction." - fi - else echo 'An invisible force blocks your way.' - fi - else echo 'I see no such passage.' - fi - else if cd .. - then echo 'You struggle upwards.' - else echo "You can't reach that high." - fi - fi - else echo 'Which passage?' - fi - ;; - examine) if [ "$obj" ] - then if [ $obj = all ] - then $obj=`echo $obs $exs` - x= - fi - for it in $obj $x - do if ash_lk "$obs $hobs $exs $hexs" "$it" - then echo "Upon close inspection of the $it, you see:" - ls -ld $it 2>&- - if [ $? != 0 ] - then echo "-- when you look directly at the $it, it vanishes." - fi - else if ash_lk "$kn" "$it" - then echo 'You must drop it first.' - else echo "I see no $it here." - fi - fi - done - else echo 'Examine what?' - fi - ;; - feed) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then set -- $x - case "$1" in - to) if [ "$2" ] - then shift - if PATH=$OPATH $* <$obj 2>&- - then echo "The $1 monster devours your $obj." - if rm -f $obj >&- 2>&- - then obs=`ash_rm "$obs" "$obj"` - else echo 'But he spits it back up.' - fi - else echo "The $1 monster holds his nose in disdain." - fi - else echo 'To what?' - fi - ;; - *) echo "Feed $obj to what?" - ;; - esac - else if ash_lk "$kn" "$obj" - then echo 'You must drop it first.' - else echo "I see no $obj here." - fi - fi - else echo 'Feed what?' - fi - ;; - get|take) if [ "$obj" ] - then if [ $obj = all ] - then obj="$obs" - x= - fi - for it in $obj $x - do if ash_lk "$obs $hobs" "$it" - then if ash_lk "$kn" "$it" - then echo 'You already have one.' - else if mv $it $HOME/$KNAP/$it >&- 2>&- - then echo "$it: taken." - kn="$it $kn" - obs=`ash_rm "$obs" "$it"` - else echo "The $it is too heavy." - fi - fi - else echo "I see no $it here." - fi - done - else echo 'Get what?' - fi - ;; - gripe|bug) echo 'Please describe the problem and your situation at the time it failed.\nEnd the bug report with a line containing just a Ctrl-D.' - cat | mail $MAINT -s 'ash bug' - echo 'Thank you!' - ;; - help) ash_help - ;; - inventory|i) if [ "$kn" ] - then echo 'Your knapsack contains:' - ash_pr $kn - else echo 'You are poverty-stricken.' - fi - ;; - kill|destroy) if [ "$obj" ] - then if [ $obj = all ] - then x= - if ask "Do you really want to attempt to $verb them all?" - then obj=`echo $obs` - else echo 'Chicken!' - obj= - fi - fi - for it in $obj $x - do if ash_lk "$obs $hobs" "$it" - then if mv $it $HOME/$LIM <&- >&- 2>&- - then if [ $verb = kill ] - then echo "The $it cannot defend himself; he dies." - else echo "You have destroyed the $it; it vanishes." - fi - obs=`ash_rm "$obs" "$it"` - else if [ $verb = kill ] - then echo "Your feeble blows are no match for the $it." - else echo "The $it is indestructible." - fi - fi - else if ash_lk "$kn" "$it" - then echo "You must drop the $it first." - found=false - else echo "I see no $it here." - fi - fi - done - else echo 'Kill what?' - fi - ;; - look|l) obs=`echo $obs $hobs` - hobs= - if [ "$obs" ] - then echo 'The room contains:' - ash_pr $obs - else echo 'The room is empty.' - fi - exs=`echo $exs $hexs` - hexs= - if [ "$exs" ] - then echo 'There are exits plainly labeled:' - ash_pr $exs - echo 'and a passage directly overhead.' - else echo 'The only exit is directly overhead.' - fi - ;; - magic) if [ "$obj" = mode ] - then if sh -c $cha - then echo 'You had your chance and you blew it.' - else if ask 'Are you a wizard?' - then echo -n 'Prove it! Say the magic word: ' - read obj - if [ "$obj" = armadillo ] - then echo 'Yes, master!!' - wiz=true - else echo "Homie says: I don't think so" - cha=true - fi - else echo "I didn't think so." - fi - fi - else echo 'Nice try.' - fi - ;; - open|read) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then if [ -r $obj ] - then if [ -s $obj ] - then echo "Opening the $obj reveals:" - $CAT < $obj - if [ $? != 0 ] - then echo '-- oops, you lost the contents!' - fi - else echo "There is nothing inside the $obj." - fi - else echo "You do not have the proper tools to open the $obj." - fi - else if ash_lk "$kn" "$obj" - then echo 'You must drop it first.' - found=false - else echo "I see no $obj here." - fi - fi - else echo 'Open what?' - fi - ;; - quit|exit) if ask 'Do you really want to quit now?' - then if [ "$kn" ] - then echo 'The contents of your knapsack will still be there next time.' - fi - rm -rf $HOME/$LIM - echo 'See you later!' - exit 0 - fi - ;; - resurrect) if [ "$obj" ] - then for it in $obj $x - do if ash_lk "$obs $hobs" "$it" - then echo "The $it is already alive and well." - else if mv $HOME/$LIM/$it $it <&- >&- 2>&- - then echo "The $it staggers to his feet." - obs=`echo $it $obs` - else echo "There are sparks but no $it appears." - fi - fi - done - else echo 'Resurrect what?' - fi - ;; - steal) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then echo 'There is already one here.' - else set -- $x - case "$1" in - from) if [ "$2" ] - then shift - if PATH=$OPATH $* >$obj 2>&- - then echo "The $1 monster drops the $obj." - obs=`echo $obj $obs` - else echo "The $1 monster runs away as you approach." - rm -f $obj >&- 2>&- - fi - else echo 'From what?' - fi - ;; - *) echo "Steal $obj from what?" - ;; - esac - fi - else echo 'Steal what?' - fi - ;; - throw) if [ "$obj" ] - then if ash_lk "$obs $hobs" "$obj" - then set -- $x - case "$1" in - at) case "$2" in - daemon) if sh -c "lpr -r $obj" - then echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket." - obs=`ash_rm "$obs" "$obj"` - else echo "The daemon is nowhere to be found." - fi - ;; - *) echo 'At what?' - ;; - esac - ;; - *) echo "Throw $obj at what?" - ;; - esac - else if ash_lk "$kn" "$obj" - then echo 'It is in your knapsack.' - found=false - else echo "I see no $obj here." - fi - fi - else echo 'Throw what?' - fi - ;; - u|up) if cd .. - then echo 'You pull yourself up a level.' - else echo "You can't reach that high." - fi - ;; - wake) if [ "$obj" ] - then echo "You awaken the $obj monster:" - PATH=$OPATH $obj $x - echo 'The monster slithers back into the darkness.' - else echo 'Wake what?' - fi - ;; - w|where) echo "You are in $room." - ;; - xyzzy) if cd - then echo 'A strange feeling comes over you.' - else echo 'Your spell fizzles out.' - fi - ;; - *) if [ "$verb" ] - then if sh -c $wiz - then PATH=$OPATH $verb $obj $x - else echo "I don't know how to \"$verb\"." - echo 'Type "help" for assistance.' - fi - else echo 'Say something!' - fi - ;; - esac -done diff --git a/execute_cmd.c~ b/execute_cmd.c~ deleted file mode 100644 index caf427fa4..000000000 --- a/execute_cmd.c~ +++ /dev/null @@ -1,5354 +0,0 @@ -/* execute_cmd.c -- Execute a COMMAND structure. */ - -/* Copyright (C) 1987-2012 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 . -*/ - -#include "config.h" - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include -#include "chartypes.h" -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixtime.h" - -#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) -# include -#endif - -#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES) -# include -#endif - -#include - -#if !defined (errno) -extern int errno; -#endif - -#define NEED_FPURGE_DECL - -#include "bashansi.h" -#include "bashintl.h" - -#include "memalloc.h" -#include "shell.h" -#include /* use <...> so we pick it up from the build directory */ -#include "flags.h" -#include "builtins.h" -#include "hashlib.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "redir.h" -#include "trap.h" -#include "pathexp.h" -#include "hashcmd.h" - -#if defined (COND_COMMAND) -# include "test.h" -#endif - -#include "builtins/common.h" -#include "builtins/builtext.h" /* list of builtins */ - -#include -#include - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -#if defined (ALIAS) -# include "alias.h" -#endif - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int dollar_dollar_pid; -extern int posixly_correct; -extern int expand_aliases; -extern int autocd; -extern int breaking, continuing, loop_level; -extern int parse_and_execute_level, running_trap, sourcelevel; -extern int command_string_index, line_number; -extern int dot_found_in_search; -extern int already_making_children; -extern int tempenv_assign_error; -extern char *the_printed_command, *shell_name; -extern pid_t last_command_subst_pid; -extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; -extern char **subshell_argv, **subshell_envp; -extern int subshell_argc; -extern time_t shell_start_time; -#if 0 -extern char *glob_argv_flags; -#endif - -extern int job_control; /* XXX */ - -extern int close __P((int)); - -/* Static functions defined and used in this file. */ -static void close_pipes __P((int, int)); -static void do_piping __P((int, int)); -static void bind_lastarg __P((char *)); -static int shell_control_structure __P((enum command_type)); -static void cleanup_redirects __P((REDIRECT *)); - -#if defined (JOB_CONTROL) -static int restore_signal_mask __P((sigset_t *)); -#endif - -static void async_redirect_stdin __P((void)); - -static int builtin_status __P((int)); - -static int execute_for_command __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -static int displen __P((const char *)); -static int print_index_and_element __P((int, int, WORD_LIST *)); -static void indent __P((int, int)); -static void print_select_list __P((WORD_LIST *, int, int, int)); -static char *select_query __P((WORD_LIST *, int, char *, int)); -static int execute_select_command __P((SELECT_COM *)); -#endif -#if defined (DPAREN_ARITHMETIC) -static int execute_arith_command __P((ARITH_COM *)); -#endif -#if defined (COND_COMMAND) -static int execute_cond_node __P((COND_COM *)); -static int execute_cond_command __P((COND_COM *)); -#endif -#if defined (COMMAND_TIMING) -static int mkfmt __P((char *, int, int, time_t, int)); -static void print_formatted_time __P((FILE *, char *, - time_t, int, time_t, int, - time_t, int, int)); -static int time_command __P((COMMAND *, int, int, int, struct fd_bitmap *)); -#endif -#if defined (ARITH_FOR_COMMAND) -static intmax_t eval_arith_for_expr __P((WORD_LIST *, int *)); -static int execute_arith_for_command __P((ARITH_FOR_COM *)); -#endif -static int execute_case_command __P((CASE_COM *)); -static int execute_while_command __P((WHILE_COM *)); -static int execute_until_command __P((WHILE_COM *)); -static int execute_while_or_until __P((WHILE_COM *, int)); -static int execute_if_command __P((IF_COM *)); -static int execute_null_command __P((REDIRECT *, int, int, int)); -static void fix_assignment_words __P((WORD_LIST *)); -static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *)); -static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int)); -static int execute_function __P((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int)); -static int execute_builtin_or_function __P((WORD_LIST *, sh_builtin_func_t *, - SHELL_VAR *, - REDIRECT *, struct fd_bitmap *, int)); -static void execute_subshell_builtin_or_function __P((WORD_LIST *, REDIRECT *, - sh_builtin_func_t *, - SHELL_VAR *, - int, int, int, - struct fd_bitmap *, - int)); -static int execute_disk_command __P((WORD_LIST *, REDIRECT *, char *, - int, int, int, struct fd_bitmap *, int)); - -static char *getinterp __P((char *, int, int *)); -static void initialize_subshell __P((void)); -static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *)); -#if defined (COPROCESS_SUPPORT) -static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *)); -#endif - -static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)); - -static int execute_intern_function __P((WORD_DESC *, FUNCTION_DEF *)); - -/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global - so that reader_loop can set it to zero before executing a command. */ -int stdin_redir; - -/* The name of the command that is currently being executed. - `test' needs this, for example. */ -char *this_command_name; - -/* The printed representation of the currently-executing command (same as - the_printed_command), except when a trap is being executed. Useful for - a debugger to know where exactly the program is currently executing. */ -char *the_printed_command_except_trap; - -/* For catching RETURN in a function. */ -int return_catch_flag; -int return_catch_value; -procenv_t return_catch; - -/* The value returned by the last synchronous command. */ -int last_command_exit_value; - -/* Whether or not the last command (corresponding to last_command_exit_value) - was terminated by a signal, and, if so, which one. */ -int last_command_exit_signal; - -/* The list of redirections to perform which will undo the redirections - that I made in the shell. */ -REDIRECT *redirection_undo_list = (REDIRECT *)NULL; - -/* The list of redirections to perform which will undo the internal - redirections performed by the `exec' builtin. These are redirections - that must be undone even when exec discards redirection_undo_list. */ -REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL; - -/* When greater than zero, value is the `level' of builtins we are - currently executing (e.g. `eval echo a' would have it set to 2). */ -int executing_builtin = 0; - -/* Non-zero if we are executing a command list (a;b;c, etc.) */ -int executing_list = 0; - -/* Non-zero if failing commands in a command substitution should not exit the - shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to - commands run in command substitutions by parse_and_execute. */ -int comsub_ignore_return = 0; - -/* Non-zero if we have just forked and are currently running in a subshell - environment. */ -int subshell_environment; - -/* Count of nested subshells, like SHLVL. Available via $BASH_SUBSHELL */ -int subshell_level = 0; - -/* Currently-executing shell function. */ -SHELL_VAR *this_shell_function; - -/* If non-zero, matches in case and [[ ... ]] are case-insensitive */ -int match_ignore_case = 0; - -int executing_command_builtin = 0; - -struct stat SB; /* used for debugging */ - -static int special_builtin_failed; - -static COMMAND *currently_executing_command; - -/* The line number that the currently executing function starts on. */ -static int function_line_number; - -/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line - number containing the function name. Used by executing_line_number to - report the correct line number. Kind of a hack. */ -static int showing_function_line; - -/* $LINENO ($BASH_LINENO) for use by an ERR trap. Global so parse_and_execute - can save and restore it. */ -int line_number_for_err_trap; - -/* A sort of function nesting level counter */ -int funcnest = 0; -int funcnest_max = 0; /* XXX - bash-4.2 */ - -int lastpipe_opt = 0; - -struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; - -#define FD_BITMAP_DEFAULT_SIZE 32 - -/* Functions to allocate and deallocate the structures used to pass - information from the shell to its children about file descriptors - to close. */ -struct fd_bitmap * -new_fd_bitmap (size) - int size; -{ - struct fd_bitmap *ret; - - ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap)); - - ret->size = size; - - if (size) - { - ret->bitmap = (char *)xmalloc (size); - memset (ret->bitmap, '\0', size); - } - else - ret->bitmap = (char *)NULL; - return (ret); -} - -void -dispose_fd_bitmap (fdbp) - struct fd_bitmap *fdbp; -{ - FREE (fdbp->bitmap); - free (fdbp); -} - -void -close_fd_bitmap (fdbp) - struct fd_bitmap *fdbp; -{ - register int i; - - if (fdbp) - { - for (i = 0; i < fdbp->size; i++) - if (fdbp->bitmap[i]) - { - close (i); - fdbp->bitmap[i] = 0; - } - } -} - -/* Return the line number of the currently executing command. */ -int -executing_line_number () -{ - if (executing && showing_function_line == 0 && - (variable_context == 0 || interactive_shell == 0) && - currently_executing_command) - { -#if defined (COND_COMMAND) - if (currently_executing_command->type == cm_cond) - return currently_executing_command->value.Cond->line; -#endif -#if defined (DPAREN_ARITHMETIC) - else if (currently_executing_command->type == cm_arith) - return currently_executing_command->value.Arith->line; -#endif -#if defined (ARITH_FOR_COMMAND) - else if (currently_executing_command->type == cm_arith_for) - return currently_executing_command->value.ArithFor->line; -#endif - - return line_number; - } - else - return line_number; -} - -/* Execute the command passed in COMMAND. COMMAND is exactly what - read_command () places into GLOBAL_COMMAND. See "command.h" for the - details of the command structure. - - EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible - return values. Executing a command with nothing in it returns - EXECUTION_SUCCESS. */ -int -execute_command (command) - COMMAND *command; -{ - struct fd_bitmap *bitmap; - int result; - - current_fds_to_close = (struct fd_bitmap *)NULL; - bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); - begin_unwind_frame ("execute-command"); - add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); - - /* Just do the command, but not asynchronously. */ - result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap); - - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("execute-command"); - -#if defined (PROCESS_SUBSTITUTION) - /* don't unlink fifos if we're in a shell function; wait until the function - returns. */ - if (variable_context == 0) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - QUIT; - return (result); -} - -/* Return 1 if TYPE is a shell control structure type. */ -static int -shell_control_structure (type) - enum command_type type; -{ - switch (type) - { -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: -#endif -#if defined (SELECT_COMMAND) - case cm_select: -#endif -#if defined (DPAREN_ARITHMETIC) - case cm_arith: -#endif -#if defined (COND_COMMAND) - case cm_cond: -#endif - case cm_case: - case cm_while: - case cm_until: - case cm_if: - case cm_for: - case cm_group: - case cm_function_def: - return (1); - - default: - return (0); - } -} - -/* A function to use to unwind_protect the redirection undo list - for loops. */ -static void -cleanup_redirects (list) - REDIRECT *list; -{ - do_redirections (list, RX_ACTIVE); - dispose_redirects (list); -} - -#if 0 -/* Function to unwind_protect the redirections for functions and builtins. */ -static void -cleanup_func_redirects (list) - REDIRECT *list; -{ - do_redirections (list, RX_ACTIVE); -} -#endif - -void -dispose_exec_redirects () -{ - if (exec_redirection_undo_list) - { - dispose_redirects (exec_redirection_undo_list); - exec_redirection_undo_list = (REDIRECT *)NULL; - } -} - -#if defined (JOB_CONTROL) -/* A function to restore the signal mask to its proper value when the shell - is interrupted or errors occur while creating a pipeline. */ -static int -restore_signal_mask (set) - sigset_t *set; -{ - return (sigprocmask (SIG_SETMASK, set, (sigset_t *)NULL)); -} -#endif /* JOB_CONTROL */ - -#ifdef DEBUG -/* A debugging function that can be called from gdb, for instance. */ -void -open_files () -{ - register int i; - int f, fd_table_size; - - fd_table_size = getdtablesize (); - - fprintf (stderr, "pid %ld open files:", (long)getpid ()); - for (i = 3; i < fd_table_size; i++) - { - if ((f = fcntl (i, F_GETFD, 0)) != -1) - fprintf (stderr, " %d (%s)", i, f ? "close" : "open"); - } - fprintf (stderr, "\n"); -} -#endif - -static void -async_redirect_stdin () -{ - int fd; - - fd = open ("/dev/null", O_RDONLY); - if (fd > 0) - { - dup2 (fd, 0); - close (fd); - } - else if (fd < 0) - internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno)); -} - -#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) - -/* Execute the command passed in COMMAND, perhaps doing it asynchrounously. - COMMAND is exactly what read_command () places into GLOBAL_COMMAND. - ASYNCHROUNOUS, if non-zero, says to do this command in the background. - PIPE_IN and PIPE_OUT are file descriptors saying where input comes - from and where it goes. They can have the value of NO_PIPE, which means - I/O is stdin/stdout. - FDS_TO_CLOSE is a list of file descriptors to close once the child has - been forked. This list often contains the unusable sides of pipes, etc. - - EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible - return values. Executing a command with nothing in it returns - EXECUTION_SUCCESS. */ -int -execute_command_internal (command, asynchronous, pipe_in, pipe_out, - fds_to_close) - COMMAND *command; - int asynchronous; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int exec_result, user_subshell, invert, ignore_return, was_error_trap; - REDIRECT *my_undo_list, *exec_undo_list; - volatile int last_pid; - volatile int save_line_number; -#if defined (PROCESS_SUBSTITUTION) - volatile int ofifo, nfifo, osize, saved_fifo; - volatile char *ofifo_list; -#endif - - if (breaking || continuing) - return (last_command_exit_value); - if (command == 0 || read_but_dont_execute) - return (EXECUTION_SUCCESS); - - QUIT; - run_pending_traps (); - -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = command; - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - - /* If we're inverting the return value and `set -e' has been executed, - we don't want a failing command to inadvertently cause the shell - to exit. */ - if (exit_immediately_on_error && invert) /* XXX */ - command->flags |= CMD_IGNORE_RETURN; /* XXX */ - - exec_result = EXECUTION_SUCCESS; - - /* If a command was being explicitly run in a subshell, or if it is - a shell control-structure, and it has a pipe, then we do the command - in a subshell. */ - if (command->type == cm_subshell && (command->flags & CMD_NO_FORK)) - return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); - -#if defined (COPROCESS_SUPPORT) - if (command->type == cm_coproc) - return (execute_coproc (command, pipe_in, pipe_out, fds_to_close)); -#endif - - user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); - - if (command->type == cm_subshell || - (command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) || - (shell_control_structure (command->type) && - (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous))) - { - pid_t paren_pid; - int s; - - /* Fork a subshell, turn off the subshell bit, turn off job - control and call execute_command () on the command again. */ - line_number_for_err_trap = line_number; - paren_pid = make_child (savestring (make_command_string (command)), - asynchronous); - if (paren_pid == 0) - { - /* We want to run the exit trap for forced {} subshells, and we - want to note this before execute_in_subshell modifies the - COMMAND struct. Need to keep in mind that execute_in_subshell - runs the exit trap for () subshells itself. */ - s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous; - last_command_exit_value = execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close); - if (s) - subshell_exit (last_command_exit_value); - else - exit (last_command_exit_value); - /* NOTREACHED */ - } - else - { - close_pipes (pipe_in, pipe_out); - -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - if (variable_context == 0) /* wait until shell function completes */ - unlink_fifo_list (); -#endif - /* If we are part of a pipeline, and not the end of the pipeline, - then we should simply return and let the last command in the - pipe be waited for. If we are not in a pipeline, or are the - last command in the pipeline, then we wait for the subshell - and return its exit status as usual. */ - if (pipe_out != NO_PIPE) - return (EXECUTION_SUCCESS); - - stop_pipeline (asynchronous, (COMMAND *)NULL); - - if (asynchronous == 0) - { - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - exec_result = wait_for (paren_pid); - - /* If we have to, invert the return value. */ - if (invert) - exec_result = ((exec_result == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS); - - last_command_exit_value = exec_result; - if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - return (last_command_exit_value); - } - else - { - DESCRIBE_PID (paren_pid); - - run_pending_traps (); - - return (EXECUTION_SUCCESS); - } - } - } - -#if defined (COMMAND_TIMING) - if (command->flags & CMD_TIME_PIPELINE) - { - if (asynchronous) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); - } - else - { - exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close); -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = (COMMAND *)NULL; - } - return (exec_result); - } -#endif /* COMMAND_TIMING */ - - if (shell_control_structure (command->type) && command->redirects) - stdin_redir = stdin_redirects (command->redirects); - -#if defined (PROCESS_SUBSTITUTION) - if (variable_context != 0) - { - ofifo = num_fifos (); - ofifo_list = copy_fifo_list (&osize); - saved_fifo = 1; - } - else - saved_fifo = 0; -#endif - - /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input - redirection.) */ - if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 0) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - dispose_exec_redirects (); -#if defined (PROCESS_SUBSTITUTION) - if (saved_fifo) - free (ofifo_list); -#endif - return (last_command_exit_value = EXECUTION_FAILURE); - } - - if (redirection_undo_list) - { - /* XXX - why copy here? */ - my_undo_list = (REDIRECT *)copy_redirects (redirection_undo_list); - dispose_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } - else - my_undo_list = (REDIRECT *)NULL; - - if (exec_redirection_undo_list) - { - /* XXX - why copy here? */ - exec_undo_list = (REDIRECT *)copy_redirects (exec_redirection_undo_list); - dispose_redirects (exec_redirection_undo_list); - exec_redirection_undo_list = (REDIRECT *)NULL; - } - else - exec_undo_list = (REDIRECT *)NULL; - - if (my_undo_list || exec_undo_list) - begin_unwind_frame ("loop_redirections"); - - if (my_undo_list) - add_unwind_protect ((Function *)cleanup_redirects, my_undo_list); - - if (exec_undo_list) - add_unwind_protect ((Function *)dispose_redirects, exec_undo_list); - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - QUIT; - - switch (command->type) - { - case cm_simple: - { - save_line_number = line_number; - /* We can't rely on variables retaining their values across a - call to execute_simple_command if a longjmp occurs as the - result of a `return' builtin. This is true for sure with gcc. */ -#if defined (RECYCLES_PIDS) - last_made_pid = NO_PID; -#endif - last_pid = last_made_pid; - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - - if (ignore_return && command->value.Simple) - command->value.Simple->flags |= CMD_IGNORE_RETURN; - if (command->flags & CMD_STDIN_REDIR) - command->value.Simple->flags |= CMD_STDIN_REDIR; - - line_number_for_err_trap = line_number = command->value.Simple->line; - exec_result = - execute_simple_command (command->value.Simple, pipe_in, pipe_out, - asynchronous, fds_to_close); - line_number = save_line_number; - - /* The temporary environment should be used for only the simple - command immediately following its definition. */ - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Reclaim memory allocated with alloca () on machines which - may be using the alloca emulation code. */ - (void) alloca (0); -#endif /* (ultrix && mips) || C_ALLOCA */ - - /* If we forked to do the command, then we must wait_for () - the child. */ - - /* XXX - this is something to watch out for if there are problems - when the shell is compiled without job control. Don't worry about - whether or not last_made_pid == last_pid; already_making_children - tells us whether or not there are unwaited-for children to wait - for and reap. */ - if (already_making_children && pipe_out == NO_PIPE) - { - stop_pipeline (asynchronous, (COMMAND *)NULL); - - if (asynchronous) - { - DESCRIBE_PID (last_made_pid); - } - else -#if !defined (JOB_CONTROL) - /* Do not wait for asynchronous processes started from - startup files. */ - if (last_made_pid != last_asynchronous_pid) -#endif - /* When executing a shell function that executes other - commands, this causes the last simple command in - the function to be waited for twice. This also causes - subshells forked to execute builtin commands (e.g., in - pipelines) to be waited for twice. */ - exec_result = wait_for (last_made_pid); - } - } - - /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles - only the failure of a simple command. */ - if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && - ((posixly_correct && interactive == 0 && special_builtin_failed) || - (exit_immediately_on_error && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS))) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; - - case cm_for: - if (ignore_return) - command->value.For->flags |= CMD_IGNORE_RETURN; - exec_result = execute_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - if (ignore_return) - command->value.ArithFor->flags |= CMD_IGNORE_RETURN; - exec_result = execute_arith_for_command (command->value.ArithFor); - break; -#endif - -#if defined (SELECT_COMMAND) - case cm_select: - if (ignore_return) - command->value.Select->flags |= CMD_IGNORE_RETURN; - exec_result = execute_select_command (command->value.Select); - break; -#endif - - case cm_case: - if (ignore_return) - command->value.Case->flags |= CMD_IGNORE_RETURN; - exec_result = execute_case_command (command->value.Case); - break; - - case cm_while: - if (ignore_return) - command->value.While->flags |= CMD_IGNORE_RETURN; - exec_result = execute_while_command (command->value.While); - break; - - case cm_until: - if (ignore_return) - command->value.While->flags |= CMD_IGNORE_RETURN; - exec_result = execute_until_command (command->value.While); - break; - - case cm_if: - if (ignore_return) - command->value.If->flags |= CMD_IGNORE_RETURN; - exec_result = execute_if_command (command->value.If); - break; - - case cm_group: - - /* This code can be executed from either of two paths: an explicit - '{}' command, or via a function call. If we are executed via a - function call, we have already taken care of the function being - executed in the background (down there in execute_simple_command ()), - and this command should *not* be marked as asynchronous. If we - are executing a regular '{}' group command, and asynchronous == 1, - we must want to execute the whole command in the background, so we - need a subshell, and we want the stuff executed in that subshell - (this group command) to be executed in the foreground of that - subshell (i.e. there will not be *another* subshell forked). - - What we do is to force a subshell if asynchronous, and then call - execute_command_internal again with asynchronous still set to 1, - but with the original group command, so the printed command will - look right. - - The code above that handles forking off subshells will note that - both subshell and async are on, and turn off async in the child - after forking the subshell (but leave async set in the parent, so - the normal call to describe_pid is made). This turning off - async is *crucial*; if it is not done, this will fall into an - infinite loop of executions through this spot in subshell after - subshell until the process limit is exhausted. */ - - if (asynchronous) - { - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = - execute_command_internal (command, 1, pipe_in, pipe_out, - fds_to_close); - } - else - { - if (ignore_return && command->value.Group->command) - command->value.Group->command->flags |= CMD_IGNORE_RETURN; - exec_result = - execute_command_internal (command->value.Group->command, - asynchronous, pipe_in, pipe_out, - fds_to_close); - } - break; - - case cm_connection: - exec_result = execute_connection (command, asynchronous, - pipe_in, pipe_out, fds_to_close); - break; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - if (ignore_return) - command->value.Arith->flags |= CMD_IGNORE_RETURN; - line_number_for_err_trap = save_line_number = line_number; - exec_result = execute_arith_command (command->value.Arith); - line_number = save_line_number; - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; -#endif - -#if defined (COND_COMMAND) - case cm_cond: - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - if (ignore_return) - command->value.Cond->flags |= CMD_IGNORE_RETURN; - - line_number_for_err_trap = save_line_number = line_number; - exec_result = execute_cond_command (command->value.Cond); - line_number = save_line_number; - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; -#endif - - case cm_function_def: - exec_result = execute_intern_function (command->value.Function_def->name, - command->value.Function_def); - break; - - default: - command_error ("execute_command", CMDERR_BADTYPE, command->type, 0); - } - - if (my_undo_list) - { - do_redirections (my_undo_list, RX_ACTIVE); - dispose_redirects (my_undo_list); - } - - if (exec_undo_list) - dispose_redirects (exec_undo_list); - - if (my_undo_list || exec_undo_list) - discard_unwind_frame ("loop_redirections"); - -#if defined (PROCESS_SUBSTITUTION) - if (saved_fifo) - { - nfifo = num_fifos (); - if (nfifo > ofifo) - close_new_fifos (ofifo_list, osize); - free (ofifo_list); - } -#endif - - /* Invert the return value if we have to */ - if (invert) - exec_result = (exec_result == EXECUTION_SUCCESS) - ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - -#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND) - /* This is where we set PIPESTATUS from the exit status of the appropriate - compound commands (the ones that look enough like simple commands to - cause confusion). We might be able to optimize by not doing this if - subshell_environment != 0. */ - switch (command->type) - { -# if defined (DPAREN_ARITHMETIC) - case cm_arith: -# endif -# if defined (COND_COMMAND) - case cm_cond: -# endif - set_pipestatus_from_exit (exec_result); - break; - } -#endif - - last_command_exit_value = exec_result; - run_pending_traps (); -#if 0 - if (running_trap == 0) -#endif - currently_executing_command = (COMMAND *)NULL; - - return (last_command_exit_value); -} - -#if defined (COMMAND_TIMING) - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -extern struct timeval *difftimeval __P((struct timeval *, struct timeval *, struct timeval *)); -extern struct timeval *addtimeval __P((struct timeval *, struct timeval *, struct timeval *)); -extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeval *)); -#endif - -#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S" -#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS" - -static const int precs[] = { 0, 100, 10, 1 }; - -/* Expand one `%'-prefixed escape sequence from a time format string. */ -static int -mkfmt (buf, prec, lng, sec, sec_fraction) - char *buf; - int prec, lng; - time_t sec; - int sec_fraction; -{ - time_t min; - char abuf[INT_STRLEN_BOUND(time_t) + 1]; - int ind, aind; - - ind = 0; - abuf[sizeof(abuf) - 1] = '\0'; - - /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ - if (lng) - { - min = sec / 60; - sec %= 60; - aind = sizeof(abuf) - 2; - do - abuf[aind--] = (min % 10) + '0'; - while (min /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - buf[ind++] = 'm'; - } - - /* Now add the seconds. */ - aind = sizeof (abuf) - 2; - do - abuf[aind--] = (sec % 10) + '0'; - while (sec /= 10); - aind++; - while (abuf[aind]) - buf[ind++] = abuf[aind++]; - - /* We want to add a decimal point and PREC places after it if PREC is - nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 - and 999. */ - if (prec != 0) - { - buf[ind++] = '.'; - for (aind = 1; aind <= prec; aind++) - { - buf[ind++] = (sec_fraction / precs[aind]) + '0'; - sec_fraction %= precs[aind]; - } - } - - if (lng) - buf[ind++] = 's'; - buf[ind] = '\0'; - - return (ind); -} - -/* Interpret the format string FORMAT, interpolating the following escape - sequences: - %[prec][l][RUS] - - where the optional `prec' is a precision, meaning the number of - characters after the decimal point, the optional `l' means to format - using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', - and the last character is one of - - R number of seconds of `real' time - U number of seconds of `user' time - S number of seconds of `system' time - - An occurrence of `%%' in the format string is translated to a `%'. The - result is printed to FP, a pointer to a FILE. The other variables are - the seconds and thousandths of a second of real, user, and system time, - resectively. */ -static void -print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) - FILE *fp; - char *format; - time_t rs; - int rsf; - time_t us; - int usf; - time_t ss; - int ssf, cpu; -{ - int prec, lng, len; - char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")]; - time_t sum; - int sum_frac; - int sindex, ssize; - - len = strlen (format); - ssize = (len + 64) - (len % 64); - str = (char *)xmalloc (ssize); - sindex = 0; - - for (s = format; *s; s++) - { - if (*s != '%' || s[1] == '\0') - { - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == '%') - { - s++; - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } - else if (s[1] == 'P') - { - s++; -#if 0 - /* clamp CPU usage at 100% */ - if (cpu > 10000) - cpu = 10000; -#endif - sum = cpu / 100; - sum_frac = (cpu % 100) * 10; - len = mkfmt (ts, 2, 0, sum, sum_frac); - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - else - { - prec = 3; /* default is three places past the decimal point. */ - lng = 0; /* default is to not use minutes or append `s' */ - s++; - if (DIGIT (*s)) /* `precision' */ - { - prec = *s++ - '0'; - if (prec > 3) prec = 3; - } - if (*s == 'l') /* `length extender' */ - { - lng = 1; - s++; - } - if (*s == 'R' || *s == 'E') - len = mkfmt (ts, prec, lng, rs, rsf); - else if (*s == 'U') - len = mkfmt (ts, prec, lng, us, usf); - else if (*s == 'S') - len = mkfmt (ts, prec, lng, ss, ssf); - else - { - internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s); - free (str); - return; - } - RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); - strcpy (str + sindex, ts); - sindex += len; - } - } - - str[sindex] = '\0'; - fprintf (fp, "%s\n", str); - fflush (fp); - - free (str); -} - -static int -time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rv, posix_time, old_flags, nullcmd; - time_t rs, us, ss; - int rsf, usf, ssf; - int cpu; - char *time_format; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) - struct timeval real, user, sys; - struct timeval before, after; -# if defined (HAVE_STRUCT_TIMEZONE) - struct timezone dtz; /* posix doesn't define this */ -# endif - struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */ -#else -# if defined (HAVE_TIMES) - clock_t tbefore, tafter, real, user, sys; - struct tms before, after; -# endif -#endif - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&before, &dtz); -# else - gettimeofday (&before, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfb); - getrusage (RUSAGE_CHILDREN, &kidsb); -#else -# if defined (HAVE_TIMES) - tbefore = times (&before); -# endif -#endif - - posix_time = command && (command->flags & CMD_TIME_POSIX); - - nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); - if (posixly_correct && nullcmd) - { -#if defined (HAVE_GETRUSAGE) - selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0; - selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0; - before.tv_sec = shell_start_time; - before.tv_usec = 0; -#else - before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0; - tbefore = shell_start_time; -#endif - } - - old_flags = command->flags; - command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); - rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); - command->flags = old_flags; - - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; - -#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) -# if defined (HAVE_STRUCT_TIMEZONE) - gettimeofday (&after, &dtz); -# else - gettimeofday (&after, (void *)NULL); -# endif /* !HAVE_STRUCT_TIMEZONE */ - getrusage (RUSAGE_SELF, &selfa); - getrusage (RUSAGE_CHILDREN, &kidsa); - - difftimeval (&real, &before, &after); - timeval_to_secs (&real, &rs, &rsf); - - addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), - difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); - timeval_to_secs (&user, &us, &usf); - - addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), - difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); - timeval_to_secs (&sys, &ss, &ssf); - - cpu = timeval_to_cpu (&real, &user, &sys); -#else -# if defined (HAVE_TIMES) - tafter = times (&after); - - real = tafter - tbefore; - clock_t_to_secs (real, &rs, &rsf); - - user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); - clock_t_to_secs (user, &us, &usf); - - sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); - clock_t_to_secs (sys, &ss, &ssf); - - cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real; - -# else - rs = us = ss = 0; - rsf = usf = ssf = cpu = 0; -# endif -#endif - - if (posix_time) - time_format = POSIX_TIMEFORMAT; - else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) - { - if (posixly_correct && nullcmd) - time_format = "user\t%2lU\nsys\t%2lS"; - else - time_format = BASH_TIMEFORMAT; - } - if (time_format && *time_format) - print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); - - return rv; -} -#endif /* COMMAND_TIMING */ - -/* Execute a command that's supposed to be in a subshell. This must be - called after make_child and we must be running in the child process. - The caller will return or exit() immediately with the value this returns. */ -static int -execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int user_subshell, return_code, function_value, should_redir_stdin, invert; - int ois, user_coproc; - int result; - volatile COMMAND *tcom; - - USE_VAR(user_subshell); - USE_VAR(user_coproc); - USE_VAR(invert); - USE_VAR(tcom); - USE_VAR(asynchronous); - - subshell_level++; - should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - stdin_redirects (command->redirects) == 0); - - invert = (command->flags & CMD_INVERT_RETURN) != 0; - user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); - user_coproc = command->type == cm_coproc; - - command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); - - /* If a command is asynchronous in a subshell (like ( foo ) & or - the special case of an asynchronous GROUP command where the - the subshell bit is turned on down in case cm_group: below), - turn off `asynchronous', so that two subshells aren't spawned. - XXX - asynchronous used to be set to 0 in this block, but that - means that setup_async_signals was never run. Now it's set to - 0 after subshell_environment is set appropriately and setup_async_signals - is run. - - This seems semantically correct to me. For example, - ( foo ) & seems to say ``do the command `foo' in a subshell - environment, but don't wait for that subshell to finish'', - and "{ foo ; bar ; } &" seems to me to be like functions or - builtins in the background, which executed in a subshell - environment. I just don't see the need to fork two subshells. */ - - /* Don't fork again, we are already in a subshell. A `doubly - async' shell is not interactive, however. */ - if (asynchronous) - { -#if defined (JOB_CONTROL) - /* If a construct like ( exec xxx yyy ) & is given while job - control is active, we want to prevent exec from putting the - subshell back into the original process group, carefully - undoing all the work we just did in make_child. */ - original_pgrp = -1; -#endif /* JOB_CONTROL */ - ois = interactive_shell; - interactive_shell = 0; - /* This test is to prevent alias expansion by interactive shells that - run `(command) &' but to allow scripts that have enabled alias - expansion with `shopt -s expand_alias' to continue to expand - aliases. */ - if (ois != interactive_shell) - expand_aliases = 0; - } - - /* Subshells are neither login nor interactive. */ - login_shell = interactive = 0; - - if (user_subshell) - subshell_environment = SUBSHELL_PAREN; - else - { - subshell_environment = 0; /* XXX */ - if (asynchronous) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (user_coproc) - subshell_environment |= SUBSHELL_COPROC; - } - - reset_terminating_signals (); /* in sig.c */ - /* Cancel traps, in trap.c. */ - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - reset_signal_handlers (); - subshell_environment |= SUBSHELL_RESETTRAP; - - /* Make sure restore_original_signals doesn't undo the work done by - make_child to ensure that asynchronous children are immune to SIGINT - and SIGQUIT. Turn off asynchronous to make sure more subshells are - not spawned. */ - if (asynchronous) - { - setup_async_signals (); - asynchronous = 0; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - -#if defined (JOB_CONTROL) - /* Delete all traces that there were any jobs running. This is - only for subshells. */ - without_job_control (); -#endif /* JOB_CONTROL */ - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - /* If this is a user subshell, set a flag if stdin was redirected. - This is used later to decide whether to redirect fd 0 to - /dev/null for async commands in the subshell. This adds more - sh compatibility, but I'm not sure it's the right thing to do. */ - if (user_subshell) - { - stdin_redir = stdin_redirects (command->redirects); - restore_default_signal (0); - } - - /* If this is an asynchronous command (command &), we want to - redirect the standard input from /dev/null in the absence of - any specific redirection involving stdin. */ - if (should_redir_stdin && stdin_redir == 0) - async_redirect_stdin (); - - /* Do redirections, then dispose of them before recursive call. */ - if (command->redirects) - { - if (do_redirections (command->redirects, RX_ACTIVE) != 0) - exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - - dispose_redirects (command->redirects); - command->redirects = (REDIRECT *)NULL; - } - - if (command->type == cm_subshell) - tcom = command->value.Subshell->command; - else if (user_coproc) - tcom = command->value.Coproc->command; - else - tcom = command; - - if (command->flags & CMD_TIME_PIPELINE) - tcom->flags |= CMD_TIME_PIPELINE; - if (command->flags & CMD_TIME_POSIX) - tcom->flags |= CMD_TIME_POSIX; - - /* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */ - if ((command->flags & CMD_IGNORE_RETURN) && tcom != command) - tcom->flags |= CMD_IGNORE_RETURN; - - /* If this is a simple command, tell execute_disk_command that it - might be able to get away without forking and simply exec. - This means things like ( sleep 10 ) will only cause one fork. - If we're timing the command or inverting its return value, however, - we cannot do this optimization. */ - if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) && - ((tcom->flags & CMD_TIME_PIPELINE) == 0) && - ((tcom->flags & CMD_INVERT_RETURN) == 0)) - { - tcom->flags |= CMD_NO_FORK; - if (tcom->type == cm_simple) - tcom->value.Simple->flags |= CMD_NO_FORK; - } - - invert = (tcom->flags & CMD_INVERT_RETURN) != 0; - tcom->flags &= ~CMD_INVERT_RETURN; - - result = setjmp (top_level); - - /* If we're inside a function while executing this subshell, we - need to handle a possible `return'. */ - function_value = 0; - if (return_catch_flag) - function_value = setjmp (return_catch); - - /* If we're going to exit the shell, we don't want to invert the return - status. */ - if (result == EXITPROG) - invert = 0, return_code = last_command_exit_value; - else if (result) - return_code = EXECUTION_FAILURE; - else if (function_value) - return_code = return_catch_value; - else - return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close); - - /* If we are asked to, invert the return value. */ - if (invert) - return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE - : EXECUTION_SUCCESS; - - /* If we were explicitly placed in a subshell with (), we need - to do the `shell cleanup' things, such as running traps[0]. */ - if (user_subshell && signal_is_trapped (0)) - { - last_command_exit_value = return_code; - return_code = run_exit_trap (); - } - - subshell_level--; - return (return_code); - /* NOTREACHED */ -} - -#if defined (COPROCESS_SUPPORT) -#define COPROC_MAX 16 - -typedef struct cpelement - { - struct cpelement *next; - struct coproc *coproc; - } -cpelement_t; - -typedef struct cplist - { - struct cpelement *head; - struct cpelement *tail; - int ncoproc; - } -cplist_t; - -static struct cpelement *cpe_alloc __P((struct coproc *)); -static void cpe_dispose __P((struct cpelement *)); -static struct cpelement *cpl_add __P((struct coproc *)); -static struct cpelement *cpl_delete __P((pid_t)); -static void cpl_reap __P((void)); -static void cpl_flush __P((void)); -static void cpl_closeall __P((void)); -static struct cpelement *cpl_search __P((pid_t)); -static struct cpelement *cpl_searchbyname __P((const char *)); -static void cpl_prune __P((void)); - -static void coproc_free __P((struct coproc *)); - -/* Will go away when there is fully-implemented support for multiple coprocs. */ -Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 }; - -cplist_t coproc_list = {0, 0, 0}; - -/* Functions to manage the list of coprocs */ - -static struct cpelement * -cpe_alloc (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement)); - cpe->coproc = cp; - cpe->next = (struct cpelement *)0; - return cpe; -} - -static void -cpe_dispose (cpe) - struct cpelement *cpe; -{ - free (cpe); -} - -static struct cpelement * -cpl_add (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = cpe_alloc (cp); - - if (coproc_list.head == 0) - { - coproc_list.head = coproc_list.tail = cpe; - coproc_list.ncoproc = 0; /* just to make sure */ - } - else - { - coproc_list.tail->next = cpe; - coproc_list.tail = cpe; - } - coproc_list.ncoproc++; - - return cpe; -} - -static struct cpelement * -cpl_delete (pid) - pid_t pid; -{ - struct cpelement *prev, *p; - - for (prev = p = coproc_list.head; p; prev = p, p = p->next) - if (p->coproc->c_pid == pid) - { - prev->next = p->next; /* remove from list */ - break; - } - - if (p == 0) - return 0; /* not found */ - -#if defined (DEBUG) - itrace("cpl_delete: deleting %d", pid); -#endif - - /* Housekeeping in the border cases. */ - if (p == coproc_list.head) - coproc_list.head = coproc_list.head->next; - else if (p == coproc_list.tail) - coproc_list.tail = prev; - - coproc_list.ncoproc--; - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - - return (p); -} - -static void -cpl_reap () -{ - struct cpelement *p, *next, *nh, *nt; - - /* Build a new list by removing dead coprocs and fix up the coproc_list - pointers when done. */ - nh = nt = next = (struct cpelement *)0; - for (p = coproc_list.head; p; p = next) - { - next = p->next; - if (p->coproc->c_flags & COPROC_DEAD) - { - coproc_list.ncoproc--; /* keep running count, fix up pointers later */ - -#if defined (DEBUG) - itrace("cpl_reap: deleting %d", p->coproc->c_pid); -#endif - - coproc_dispose (p->coproc); - cpe_dispose (p); - } - else if (nh == 0) - nh = nt = p; - else - { - nt->next = p; - nt = nt->next; - } - } - - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else - { - if (nt) - nt->next = 0; - coproc_list.head = nh; - coproc_list.tail = nt; - if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - } -} - -/* Clear out the list of saved statuses */ -static void -cpl_flush () -{ - struct cpelement *cpe, *p; - - for (cpe = coproc_list.head; cpe; ) - { - p = cpe; - cpe = cpe->next; - - coproc_dispose (p->coproc); - cpe_dispose (p); - } - - coproc_list.head = coproc_list.tail = 0; - coproc_list.ncoproc = 0; -} - -static void -cpl_closeall () -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head; cpe; cpe = cpe->next) - coproc_close (cpe->coproc); -} - -static void -cpl_fdchk (fd) - int fd; -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head; cpe; cpe = cpe->next) - coproc_checkfd (cpe->coproc, fd); -} - -/* Search for PID in the list of coprocs; return the cpelement struct if - found. If not found, return NULL. */ -static struct cpelement * -cpl_search (pid) - pid_t pid; -{ - struct cpelement *cpe; - - for (cpe = coproc_list.head ; cpe; cpe = cpe->next) - if (cpe->coproc->c_pid == pid) - return cpe; - return (struct cpelement *)NULL; -} - -/* Search for the coproc named NAME in the list of coprocs; return the - cpelement struct if found. If not found, return NULL. */ -static struct cpelement * -cpl_searchbyname (name) - const char *name; -{ - struct cpelement *cp; - - for (cp = coproc_list.head ; cp; cp = cp->next) - if (STREQ (cp->coproc->c_name, name)) - return cp; - return (struct cpelement *)NULL; -} - -#if 0 -static void -cpl_prune () -{ - struct cpelement *cp; - - while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX) - { - cp = coproc_list.head; - coproc_list.head = coproc_list.head->next; - coproc_dispose (cp->coproc); - cpe_dispose (cp); - coproc_list.ncoproc--; - } -} -#endif - -/* These currently use a single global "shell coproc" but are written in a - way to not preclude additional coprocs later (using the list management - package above). */ - -struct coproc * -getcoprocbypid (pid) - pid_t pid; -{ -#if MULTIPLE_COPROCS - struct cpelement *p; - - p = cpl_search (pid); - return (p ? p->coproc : 0); -#else - return (pid == sh_coproc.c_pid ? &sh_coproc : 0); -#endif -} - -struct coproc * -getcoprocbyname (name) - const char *name; -{ -#if MULTIPLE_COPROCS - struct cpelement *p; - - p = cpl_searchbyname (name); - return (p ? p->coproc : 0); -#else - return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); -#endif -} - -void -coproc_init (cp) - struct coproc *cp; -{ - cp->c_name = 0; - cp->c_pid = NO_PID; - cp->c_rfd = cp->c_wfd = -1; - cp->c_rsave = cp->c_wsave = -1; - cp->c_flags = cp->c_status = 0; -} - -struct coproc * -coproc_alloc (name, pid) - char *name; - pid_t pid; -{ - struct coproc *cp; - -#if MULTIPLE_COPROCS - cp = (struct coproc *)xmalloc (sizeof (struct coproc)); -#else - cp = &sh_coproc; -#endif - coproc_init (cp); - - cp->c_name = savestring (name); - cp->c_pid = pid; - -#if MULTIPLE_COPROCS - cpl_add (cp); -#endif - - return (cp); -} - -static void -coproc_free (cp) - struct coproc *cp; -{ - free (cp); -} - -void -coproc_dispose (cp) - struct coproc *cp; -{ - if (cp == 0) - return; - - coproc_unsetvars (cp); - FREE (cp->c_name); - coproc_close (cp); -#if MULTIPLE_COPROCS - coproc_free (cp); -#else - coproc_init (cp); -#endif -} - -/* Placeholder for now. Will require changes for multiple coprocs */ -void -coproc_flush () -{ -#if MULTIPLE_COPROCS - cpl_flush (); -#else - coproc_dispose (&sh_coproc); -#endif -} - -void -coproc_close (cp) - struct coproc *cp; -{ - if (cp->c_rfd >= 0) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } - if (cp->c_wfd >= 0) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } - cp->c_rsave = cp->c_wsave = -1; -} - -void -coproc_closeall () -{ -#if MULTIPLE_COPROCS - cpl_closeall (); -#else - coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */ -#endif -} - -void -coproc_reap () -{ -#if MULTIPLE_COPROCS - cpl_reap (); -#else - struct coproc *cp; - - cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */ - if (cp && (cp->c_flags & COPROC_DEAD)) - coproc_dispose (cp); -#endif -} - -void -coproc_rclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } -} - -void -coproc_wclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } -} - -void -coproc_checkfd (cp, fd) - struct coproc *cp; - int fd; -{ - int update; - - update = 0; - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - update = cp->c_rfd = -1; - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - update = cp->c_wfd = -1; - if (update) - coproc_setvars (cp); -} - -void -coproc_fdchk (fd) - int fd; -{ -#if MULTIPLE_COPROCS - cpl_fdchk (fd); -#else - coproc_checkfd (&sh_coproc, fd); -#endif -} - -void -coproc_fdclose (cp, fd) - struct coproc *cp; - int fd; -{ - coproc_rclose (cp, fd); - coproc_wclose (cp, fd); - coproc_setvars (cp); -} - -void -coproc_fdsave (cp) - struct coproc *cp; -{ - cp->c_rsave = cp->c_rfd; - cp->c_wsave = cp->c_wfd; -} - -void -coproc_fdrestore (cp) - struct coproc *cp; -{ - cp->c_rfd = cp->c_rsave; - cp->c_wfd = cp->c_wsave; -} - -void -coproc_pidchk (pid, status) - pid_t pid; -{ - struct coproc *cp; - -#if MULTIPLE_COPROCS - struct cpelement *cpe; - - cpe = cpl_delete (pid); - cp = cpe ? cpe->coproc : 0; -#else - cp = getcoprocbypid (pid); -#endif - if (cp) - { -#if 0 - itrace("coproc_pidchk: pid %d has died", pid); -#endif - cp->c_status = status; - cp->c_flags |= COPROC_DEAD; - cp->c_flags &= ~COPROC_RUNNING; -#if MULTIPLE_COPROCS - coproc_dispose (cp); -#else - coproc_unsetvars (cp); -#endif - } -} - -void -coproc_setvars (cp) - struct coproc *cp; -{ - SHELL_VAR *v; - char *namevar, *t; - int l; -#if defined (ARRAY_VARS) - arrayind_t ind; -#endif - - if (cp->c_name == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - -#if defined (ARRAY_VARS) - v = find_variable (cp->c_name); - if (v == 0) - v = make_new_array_variable (cp->c_name); - if (array_p (v) == 0) - v = convert_var_to_array (v); - - t = itos (cp->c_rfd); - ind = 0; - v = bind_array_variable (cp->c_name, ind, t, 0); - free (t); - - t = itos (cp->c_wfd); - ind = 1; - bind_array_variable (cp->c_name, ind, t, 0); - free (t); -#else - sprintf (namevar, "%s_READ", cp->c_name); - t = itos (cp->c_rfd); - bind_variable (namevar, t, 0); - free (t); - sprintf (namevar, "%s_WRITE", cp->c_name); - t = itos (cp->c_wfd); - bind_variable (namevar, t, 0); - free (t); -#endif - - sprintf (namevar, "%s_PID", cp->c_name); - t = itos (cp->c_pid); - bind_variable (namevar, t, 0); - free (t); - - free (namevar); -} - -void -coproc_unsetvars (cp) - struct coproc *cp; -{ - int l; - char *namevar; - - if (cp->c_name == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - - sprintf (namevar, "%s_PID", cp->c_name); - unbind_variable (namevar); - -#if defined (ARRAY_VARS) - unbind_variable (cp->c_name); -#else - sprintf (namevar, "%s_READ", cp->c_name); - unbind_variable (namevar); - sprintf (namevar, "%s_WRITE", cp->c_name); - unbind_variable (namevar); -#endif - - free (namevar); -} - -static int -execute_coproc (command, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rpipe[2], wpipe[2], estat; - pid_t coproc_pid; - Coproc *cp; - char *tcmd; - - /* XXX -- can be removed after changes to handle multiple coprocs */ -#if !MULTIPLE_COPROCS - if (sh_coproc.c_pid != NO_PID) - internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name); - coproc_init (&sh_coproc); -#endif - - command_string_index = 0; - tcmd = make_command_string (command); - - sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ - sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ - - coproc_pid = make_child (savestring (tcmd), 1); - if (coproc_pid == 0) - { - close (rpipe[0]); - close (wpipe[1]); - - estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close); - - fflush (stdout); - fflush (stderr); - - exit (estat); - } - - close (rpipe[1]); - close (wpipe[0]); - - cp = coproc_alloc (command->value.Coproc->name, coproc_pid); - cp->c_rfd = rpipe[0]; - cp->c_wfd = wpipe[1]; - - SET_CLOSE_ON_EXEC (cp->c_rfd); - SET_CLOSE_ON_EXEC (cp->c_wfd); - - coproc_setvars (cp); - -#if 0 - itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command); -#endif - - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - stop_pipeline (1, (COMMAND *)NULL); - DESCRIBE_PID (coproc_pid); - run_pending_traps (); - - return (EXECUTION_SUCCESS); -} -#endif - -static void -restore_stdin (s) - int s; -{ - dup2 (s, 0); - close (s); -} - -/* Catch-all cleanup function for lastpipe code for unwind-protects */ -static void -lastpipe_cleanup (s) - int s; -{ - unfreeze_jobs_list (); -} - -static int -execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; - int lstdin, lastpipe_flag, lastpipe_jid; - COMMAND *cmd; - struct fd_bitmap *fd_bitmap; - pid_t lastpid; - -#if defined (JOB_CONTROL) - sigset_t set, oset; - BLOCK_CHILD (set, oset); -#endif /* JOB_CONTROL */ - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - prev = pipe_in; - cmd = command; - - while (cmd && cmd->type == cm_connection && - cmd->value.Connection && cmd->value.Connection->connector == '|') - { - /* Make a pipeline between the two commands. */ - if (pipe (fildes) < 0) - { - sys_error (_("pipe error")); -#if defined (JOB_CONTROL) - terminate_current_pipeline (); - kill_current_pipeline (); - UNBLOCK_CHILD (oset); -#endif /* JOB_CONTROL */ - last_command_exit_value = EXECUTION_FAILURE; - /* The unwind-protects installed below will take care - of closing all of the open file descriptors. */ - throw_to_top_level (); - return (EXECUTION_FAILURE); /* XXX */ - } - - /* Here is a problem: with the new file close-on-exec - code, the read end of the pipe (fildes[0]) stays open - in the first process, so that process will never get a - SIGPIPE. There is no way to signal the first process - that it should close fildes[0] after forking, so it - remains open. No SIGPIPE is ever sent because there - is still a file descriptor open for reading connected - to the pipe. We take care of that here. This passes - around a bitmap of file descriptors that must be - closed after making a child process in execute_simple_command. */ - - /* We need fd_bitmap to be at least as big as fildes[0]. - If fildes[0] is less than fds_to_close->size, then - use fds_to_close->size. */ - new_bitmap_size = (fildes[0] < fds_to_close->size) - ? fds_to_close->size - : fildes[0] + 8; - - fd_bitmap = new_fd_bitmap (new_bitmap_size); - - /* Now copy the old information into the new bitmap. */ - xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); - - /* And mark the pipe file descriptors to be closed. */ - fd_bitmap->bitmap[fildes[0]] = 1; - - /* In case there are pipe or out-of-processes errors, we - want all these file descriptors to be closed when - unwind-protects are run, and the storage used for the - bitmaps freed up. */ - begin_unwind_frame ("pipe-file-descriptors"); - add_unwind_protect (dispose_fd_bitmap, fd_bitmap); - add_unwind_protect (close_fd_bitmap, fd_bitmap); - if (prev >= 0) - add_unwind_protect (close, prev); - dummyfd = fildes[1]; - add_unwind_protect (close, dummyfd); - -#if defined (JOB_CONTROL) - add_unwind_protect (restore_signal_mask, &oset); -#endif /* JOB_CONTROL */ - - if (ignore_return && cmd->value.Connection->first) - cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN; - execute_command_internal (cmd->value.Connection->first, asynchronous, - prev, fildes[1], fd_bitmap); - - if (prev >= 0) - close (prev); - - prev = fildes[0]; - close (fildes[1]); - - dispose_fd_bitmap (fd_bitmap); - discard_unwind_frame ("pipe-file-descriptors"); - - cmd = cmd->value.Connection->second; - } - - lastpid = last_made_pid; - - /* Now execute the rightmost command in the pipeline. */ - if (ignore_return && cmd) - cmd->flags |= CMD_IGNORE_RETURN; - - lastpipe_flag = 0; - - begin_unwind_frame ("lastpipe-exec"); - lstdin = -1; - /* If the `lastpipe' option is set with shopt, and job control is not - enabled, execute the last element of non-async pipelines in the - current shell environment. */ - if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0) - { - lstdin = move_to_high_fd (0, 1, -1); - if (lstdin > 0) - { - do_piping (prev, pipe_out); - prev = NO_PIPE; - add_unwind_protect (restore_stdin, lstdin); - lastpipe_flag = 1; - freeze_jobs_list (); - lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ - add_unwind_protect (lastpipe_cleanup, lastpipe_jid); - } - if (cmd) - cmd->flags |= CMD_LASTPIPE; - } - if (prev >= 0) - add_unwind_protect (close, prev); - - exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); - - if (lstdin > 0) - restore_stdin (lstdin); - - if (prev >= 0) - close (prev); - -#if defined (JOB_CONTROL) - UNBLOCK_CHILD (oset); -#endif - - QUIT; - - if (lastpipe_flag) - { -#if defined (JOB_CONTROL) - append_process (savestring (the_printed_command), dollar_dollar_pid, exec_result, lastpipe_jid); -#endif - lstdin = wait_for (lastpid); -#if defined (JOB_CONTROL) - exec_result = job_exit_status (lastpipe_jid); -#endif - unfreeze_jobs_list (); - } - - discard_unwind_frame ("lastpipe-exec"); - - return (exec_result); -} - -static int -execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int asynchronous, pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - COMMAND *tc, *second; - int ignore_return, exec_result, was_error_trap, invert; - volatile int save_line_number; - - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - switch (command->value.Connection->connector) - { - /* Do the first command asynchronously. */ - case '&': - tc = command->value.Connection->first; - if (tc == 0) - return (EXECUTION_SUCCESS); - - if (ignore_return) - tc->flags |= CMD_IGNORE_RETURN; - tc->flags |= CMD_AMPERSAND; - - /* If this shell was compiled without job control support, - if we are currently in a subshell via `( xxx )', or if job - control is not active then the standard input for an - asynchronous command is forced to /dev/null. */ -#if defined (JOB_CONTROL) - if ((subshell_environment || !job_control) && !stdin_redir) -#else - if (!stdin_redir) -#endif /* JOB_CONTROL */ - tc->flags |= CMD_STDIN_REDIR; - - exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); - QUIT; - - if (tc->flags & CMD_STDIN_REDIR) - tc->flags &= ~CMD_STDIN_REDIR; - - second = command->value.Connection->second; - if (second) - { - if (ignore_return) - second->flags |= CMD_IGNORE_RETURN; - - exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close); - } - - break; - - /* Just call execute command on both sides. */ - case ';': - if (ignore_return) - { - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - if (command->value.Connection->second) - command->value.Connection->second->flags |= CMD_IGNORE_RETURN; - } - executing_list++; - QUIT; - execute_command (command->value.Connection->first); - QUIT; - exec_result = execute_command_internal (command->value.Connection->second, - asynchronous, pipe_in, pipe_out, - fds_to_close); - executing_list--; - break; - - case '|': - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - line_number_for_err_trap = line_number; - exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); - - if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - save_line_number = line_number; - line_number = line_number_for_err_trap; - run_error_trap (); - line_number = save_line_number; - } - - if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - break; - - case AND_AND: - case OR_OR: - if (asynchronous) - { - /* If we have something like `a && b &' or `a || b &', run the - && or || stuff in a subshell. Force a subshell and just call - execute_command_internal again. Leave asynchronous on - so that we get a report from the parent shell about the - background job. */ - command->flags |= CMD_FORCE_SUBSHELL; - exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); - break; - } - - /* Execute the first command. If the result of that is successful - and the connector is AND_AND, or the result is not successful - and the connector is OR_OR, then execute the second command, - otherwise return. */ - - executing_list++; - if (command->value.Connection->first) - command->value.Connection->first->flags |= CMD_IGNORE_RETURN; - - exec_result = execute_command (command->value.Connection->first); - QUIT; - if (((command->value.Connection->connector == AND_AND) && - (exec_result == EXECUTION_SUCCESS)) || - ((command->value.Connection->connector == OR_OR) && - (exec_result != EXECUTION_SUCCESS))) - { - if (ignore_return && command->value.Connection->second) - command->value.Connection->second->flags |= CMD_IGNORE_RETURN; - - exec_result = execute_command (command->value.Connection->second); - } - executing_list--; - break; - - default: - command_error ("execute_connection", CMDERR_BADCONN, command->value.Connection->connector, 0); - jump_to_top_level (DISCARD); - exec_result = EXECUTION_FAILURE; - } - - return exec_result; -} - -#define REAP() \ - do \ - { \ - if (!interactive_shell) \ - reap_dead_jobs (); \ - } \ - while (0) - -/* Execute a FOR command. The syntax is: FOR word_desc IN word_list; - DO command; DONE */ -static int -execute_for_command (for_command) - FOR_COM *for_command; -{ - register WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier; - int retval, save_line_number; -#if 0 - SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */ -#endif - - save_line_number = line_number; - if (check_identifier (for_command->name, 1) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (ERREXIT); - } - return (EXECUTION_FAILURE); - } - - loop_level++; - identifier = for_command->name->word; - - list = releaser = expand_words_no_vars (for_command->map_list); - - begin_unwind_frame ("for"); - add_unwind_protect (dispose_words, releaser); - -#if 0 - if (lexical_scoping) - { - old_value = copy_variable (find_variable (identifier)); - if (old_value) - add_unwind_protect (dispose_variable, old_value); - } -#endif - - if (for_command->flags & CMD_IGNORE_RETURN) - for_command->action->flags |= CMD_IGNORE_RETURN; - - for (retval = EXECUTION_SUCCESS; list; list = list->next) - { - QUIT; - - line_number = for_command->line; - - /* Remember what this command looks like, for debugger. */ - command_string_index = 0; - print_for_command_head (for_command); - - if (echo_command_at_execute) - xtrace_print_for_command_head (for_command); - - /* Save this command unless it's a trap command and we're not running - a debug trap. */ - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - continue; -#endif - - this_command_name = (char *)NULL; - /* XXX - special ksh93 for command index variable handling */ - v = find_variable_last_nameref (identifier); - if (v && nameref_p (v)) - { - v = bind_variable_value (v, list->word->word, 0); - } - else - v = bind_variable (identifier, list->word->word, 0); - if (readonly_p (v) || noassign_p (v)) - { - line_number = save_line_number; - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("for"); - loop_level--; - return (EXECUTION_FAILURE); - } - } - retval = execute_command (for_command->action); - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - } - - loop_level--; - line_number = save_line_number; - -#if 0 - if (lexical_scoping) - { - if (!old_value) - unbind_variable (identifier); - else - { - SHELL_VAR *new_value; - - new_value = bind_variable (identifier, value_cell(old_value), 0); - new_value->attributes = old_value->attributes; - dispose_variable (old_value); - } - } -#endif - - dispose_words (releaser); - discard_unwind_frame ("for"); - return (retval); -} - -#if defined (ARITH_FOR_COMMAND) -/* Execute an arithmetic for command. The syntax is - - for (( init ; step ; test )) - do - body - done - - The execution should be exactly equivalent to - - eval \(\( init \)\) - while eval \(\( test \)\) ; do - body; - eval \(\( step \)\) - done -*/ -static intmax_t -eval_arith_for_expr (l, okp) - WORD_LIST *l; - int *okp; -{ - WORD_LIST *new; - intmax_t expresult; - int r; - - new = expand_words_no_vars (l); - if (new) - { - if (echo_command_at_execute) - xtrace_print_arith_cmd (new); - this_command_name = "(("; /* )) for expression error messages */ - - command_string_index = 0; - print_arith_command (new); - if (signal_in_progress (DEBUG_TRAP) == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - r = run_debug_trap (); - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ -#if defined (DEBUGGER) - if (debugging_mode == 0 || r == EXECUTION_SUCCESS) - expresult = evalexp (new->word->word, okp); - else - { - expresult = 0; - if (okp) - *okp = 1; - } -#else - expresult = evalexp (new->word->word, okp); -#endif - dispose_words (new); - } - else - { - expresult = 0; - if (okp) - *okp = 1; - } - return (expresult); -} - -static int -execute_arith_for_command (arith_for_command) - ARITH_FOR_COM *arith_for_command; -{ - intmax_t expresult; - int expok, body_status, arith_lineno, save_lineno; - - body_status = EXECUTION_SUCCESS; - loop_level++; - save_lineno = line_number; - - if (arith_for_command->flags & CMD_IGNORE_RETURN) - arith_for_command->action->flags |= CMD_IGNORE_RETURN; - - this_command_name = "(("; /* )) for expression error messages */ - - /* save the starting line number of the command so we can reset - line_number before executing each expression -- for $LINENO - and the DEBUG trap. */ - line_number = arith_lineno = arith_for_command->line; - if (variable_context && interactive_shell) - line_number -= function_line_number; - - /* Evaluate the initialization expression. */ - expresult = eval_arith_for_expr (arith_for_command->init, &expok); - if (expok == 0) - { - line_number = save_lineno; - return (EXECUTION_FAILURE); - } - - while (1) - { - /* Evaluate the test expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->test, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - REAP (); - if (expresult == 0) - break; - - /* Execute the body of the arithmetic for command. */ - QUIT; - body_status = execute_command (arith_for_command->action); - QUIT; - - /* Handle any `break' or `continue' commands executed by the body. */ - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - - /* Evaluate the step expression. */ - line_number = arith_lineno; - expresult = eval_arith_for_expr (arith_for_command->step, &expok); - line_number = save_lineno; - - if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } - } - - loop_level--; - line_number = save_lineno; - - return (body_status); -} -#endif - -#if defined (SELECT_COMMAND) -static int LINES, COLS, tabsize; - -#define RP_SPACE ") " -#define RP_SPACE_LEN 2 - -/* XXX - does not handle numbers > 1000000 at all. */ -#define NUMBER_LEN(s) \ -((s < 10) ? 1 \ - : ((s < 100) ? 2 \ - : ((s < 1000) ? 3 \ - : ((s < 10000) ? 4 \ - : ((s < 100000) ? 5 \ - : 6))))) - -static int -displen (s) - const char *s; -{ -#if defined (HANDLE_MULTIBYTE) - wchar_t *wcstr; - size_t wclen, slen; - - wcstr = 0; - slen = mbstowcs (wcstr, s, 0); - if (slen == -1) - slen = 0; - wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1)); - mbstowcs (wcstr, s, slen + 1); - wclen = wcswidth (wcstr, slen); - free (wcstr); - return ((int)wclen); -#else - return (STRLEN (s)); -#endif -} - -static int -print_index_and_element (len, ind, list) - int len, ind; - WORD_LIST *list; -{ - register WORD_LIST *l; - register int i; - - if (list == 0) - return (0); - for (i = ind, l = list; l && --i; l = l->next) - ; - if (l == 0) /* don't think this can happen */ - return (0); - fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word); - return (displen (l->word->word)); -} - -static void -indent (from, to) - int from, to; -{ - while (from < to) - { - if ((to / tabsize) > (from / tabsize)) - { - putc ('\t', stderr); - from += tabsize - from % tabsize; - } - else - { - putc (' ', stderr); - from++; - } - } -} - -static void -print_select_list (list, list_len, max_elem_len, indices_len) - WORD_LIST *list; - int list_len, max_elem_len, indices_len; -{ - int ind, row, elem_len, pos, cols, rows; - int first_column_indices_len, other_indices_len; - - if (list == 0) - { - putc ('\n', stderr); - return; - } - - cols = max_elem_len ? COLS / max_elem_len : 1; - if (cols == 0) - cols = 1; - rows = list_len ? list_len / cols + (list_len % cols != 0) : 1; - cols = list_len ? list_len / rows + (list_len % rows != 0) : 1; - - if (rows == 1) - { - rows = cols; - cols = 1; - } - - first_column_indices_len = NUMBER_LEN (rows); - other_indices_len = indices_len; - - for (row = 0; row < rows; row++) - { - ind = row; - pos = 0; - while (1) - { - indices_len = (pos == 0) ? first_column_indices_len : other_indices_len; - elem_len = print_index_and_element (indices_len, ind + 1, list); - elem_len += indices_len + RP_SPACE_LEN; - ind += rows; - if (ind >= list_len) - break; - indent (pos + elem_len, pos + max_elem_len); - pos += max_elem_len; - } - putc ('\n', stderr); - } -} - -/* Print the elements of LIST, one per line, preceded by an index from 1 to - LIST_LEN. Then display PROMPT and wait for the user to enter a number. - If the number is between 1 and LIST_LEN, return that selection. If EOF - is read, return a null string. If a blank line is entered, or an invalid - number is entered, the loop is executed again. */ -static char * -select_query (list, list_len, prompt, print_menu) - WORD_LIST *list; - int list_len; - char *prompt; - int print_menu; -{ - int max_elem_len, indices_len, len; - intmax_t reply; - WORD_LIST *l; - char *repl_string, *t; - -#if 0 - t = get_string_value ("LINES"); - LINES = (t && *t) ? atoi (t) : 24; -#endif - t = get_string_value ("COLUMNS"); - COLS = (t && *t) ? atoi (t) : 80; - -#if 0 - t = get_string_value ("TABSIZE"); - tabsize = (t && *t) ? atoi (t) : 8; - if (tabsize <= 0) - tabsize = 8; -#else - tabsize = 8; -#endif - - max_elem_len = 0; - for (l = list; l; l = l->next) - { - len = displen (l->word->word); - if (len > max_elem_len) - max_elem_len = len; - } - indices_len = NUMBER_LEN (list_len); - max_elem_len += indices_len + RP_SPACE_LEN + 2; - - while (1) - { - if (print_menu) - print_select_list (list, list_len, max_elem_len, indices_len); - fprintf (stderr, "%s", prompt); - fflush (stderr); - QUIT; - - if (read_builtin ((WORD_LIST *)NULL) != EXECUTION_SUCCESS) - { - putchar ('\n'); - return ((char *)NULL); - } - repl_string = get_string_value ("REPLY"); - if (*repl_string == 0) - { - print_menu = 1; - continue; - } - if (legal_number (repl_string, &reply) == 0) - return ""; - if (reply < 1 || reply > list_len) - return ""; - - for (l = list; l && --reply; l = l->next) - ; - return (l->word->word); /* XXX - can't be null? */ - } -} - -/* Execute a SELECT command. The syntax is: - SELECT word IN list DO command_list DONE - Only `break' or `return' in command_list will terminate - the command. */ -static int -execute_select_command (select_command) - SELECT_COM *select_command; -{ - WORD_LIST *releaser, *list; - SHELL_VAR *v; - char *identifier, *ps3_prompt, *selection; - int retval, list_len, show_menu, save_line_number; - - if (check_identifier (select_command->name, 1) == 0) - return (EXECUTION_FAILURE); - - save_line_number = line_number; - line_number = select_command->line; - - command_string_index = 0; - print_select_command_head (select_command); - - if (echo_command_at_execute) - xtrace_print_select_command_head (select_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - loop_level++; - identifier = select_command->name->word; - - /* command and arithmetic substitution, parameter and variable expansion, - word splitting, pathname expansion, and quote removal. */ - list = releaser = expand_words_no_vars (select_command->map_list); - list_len = list_length (list); - if (list == 0 || list_len == 0) - { - if (list) - dispose_words (list); - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } - - begin_unwind_frame ("select"); - add_unwind_protect (dispose_words, releaser); - - if (select_command->flags & CMD_IGNORE_RETURN) - select_command->action->flags |= CMD_IGNORE_RETURN; - - retval = EXECUTION_SUCCESS; - show_menu = 1; - - while (1) - { - line_number = select_command->line; - ps3_prompt = get_string_value ("PS3"); - if (ps3_prompt == 0) - ps3_prompt = "#? "; - - QUIT; - selection = select_query (list, list_len, ps3_prompt, show_menu); - QUIT; - if (selection == 0) - { - /* select_query returns EXECUTION_FAILURE if the read builtin - fails, so we want to return failure in this case. */ - retval = EXECUTION_FAILURE; - break; - } - - v = bind_variable (identifier, selection, 0); - if (readonly_p (v) || noassign_p (v)) - { - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - else - { - dispose_words (releaser); - discard_unwind_frame ("select"); - loop_level--; - line_number = save_line_number; - return (EXECUTION_FAILURE); - } - } - - retval = execute_command (select_command->action); - - REAP (); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - -#if defined (KSH_COMPATIBLE_SELECT) - show_menu = 0; - selection = get_string_value ("REPLY"); - if (selection && *selection == '\0') - show_menu = 1; -#endif - } - - loop_level--; - line_number = save_line_number; - - dispose_words (releaser); - discard_unwind_frame ("select"); - return (retval); -} -#endif /* SELECT_COMMAND */ - -/* Execute a CASE command. The syntax is: CASE word_desc IN pattern_list ESAC. - The pattern_list is a linked list of pattern clauses; each clause contains - some patterns to compare word_desc against, and an associated command to - execute. */ -static int -execute_case_command (case_command) - CASE_COM *case_command; -{ - register WORD_LIST *list; - WORD_LIST *wlist, *es; - PATTERN_LIST *clauses; - char *word, *pattern; - int retval, match, ignore_return, save_line_number; - - save_line_number = line_number; - line_number = case_command->line; - - command_string_index = 0; - print_case_command_head (case_command); - - if (echo_command_at_execute) - xtrace_print_case_command_head (case_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - retval = run_debug_trap(); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - wlist = expand_word_unsplit (case_command->word, 0); - word = wlist ? string_list (wlist) : savestring (""); - dispose_words (wlist); - - retval = EXECUTION_SUCCESS; - ignore_return = case_command->flags & CMD_IGNORE_RETURN; - - begin_unwind_frame ("case"); - add_unwind_protect ((Function *)xfree, word); - -#define EXIT_CASE() goto exit_case_command - - for (clauses = case_command->clauses; clauses; clauses = clauses->next) - { - QUIT; - for (list = clauses->patterns; list; list = list->next) - { - es = expand_word_leave_quoted (list->word, 0); - - if (es && es->word && es->word->word && *(es->word->word)) - pattern = quote_string_for_globbing (es->word->word, QGLOB_CVTNULL); - else - { - pattern = (char *)xmalloc (1); - pattern[0] = '\0'; - } - - /* Since the pattern does not undergo quote removal (as per - Posix.2, section 3.9.4.3), the strmatch () call must be able - to recognize backslashes as escape characters. */ - match = strmatch (pattern, word, FNMATCH_EXTFLAG|FNMATCH_IGNCASE) != FNM_NOMATCH; - free (pattern); - - dispose_words (es); - - if (match) - { - do - { - if (clauses->action && ignore_return) - clauses->action->flags |= CMD_IGNORE_RETURN; - retval = execute_command (clauses->action); - } - while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next)); - if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0) - EXIT_CASE (); - else - break; - } - - QUIT; - } - } - -exit_case_command: - free (word); - discard_unwind_frame ("case"); - line_number = save_line_number; - return (retval); -} - -#define CMD_WHILE 0 -#define CMD_UNTIL 1 - -/* The WHILE command. Syntax: WHILE test DO action; DONE. - Repeatedly execute action while executing test produces - EXECUTION_SUCCESS. */ -static int -execute_while_command (while_command) - WHILE_COM *while_command; -{ - return (execute_while_or_until (while_command, CMD_WHILE)); -} - -/* UNTIL is just like WHILE except that the test result is negated. */ -static int -execute_until_command (while_command) - WHILE_COM *while_command; -{ - return (execute_while_or_until (while_command, CMD_UNTIL)); -} - -/* The body for both while and until. The only difference between the - two is that the test value is treated differently. TYPE is - CMD_WHILE or CMD_UNTIL. The return value for both commands should - be EXECUTION_SUCCESS if no commands in the body are executed, and - the status of the last command executed in the body otherwise. */ -static int -execute_while_or_until (while_command, type) - WHILE_COM *while_command; - int type; -{ - int return_value, body_status; - - body_status = EXECUTION_SUCCESS; - loop_level++; - - while_command->test->flags |= CMD_IGNORE_RETURN; - if (while_command->flags & CMD_IGNORE_RETURN) - while_command->action->flags |= CMD_IGNORE_RETURN; - - while (1) - { - return_value = execute_command (while_command->test); - REAP (); - - /* Need to handle `break' in the test when we would break out of the - loop. The job control code will set `breaking' to loop_level - when a job in a loop is stopped with SIGTSTP. If the stopped job - is in the loop test, `breaking' will not be reset unless we do - this, and the shell will cease to execute commands. */ - if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - break; - } - if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS) - { - if (breaking) - breaking--; - break; - } - - QUIT; - body_status = execute_command (while_command->action); - QUIT; - - if (breaking) - { - breaking--; - break; - } - - if (continuing) - { - continuing--; - if (continuing) - break; - } - } - loop_level--; - - return (body_status); -} - -/* IF test THEN command [ELSE command]. - IF also allows ELIF in the place of ELSE IF, but - the parser makes *that* stupidity transparent. */ -static int -execute_if_command (if_command) - IF_COM *if_command; -{ - int return_value, save_line_number; - - save_line_number = line_number; - if_command->test->flags |= CMD_IGNORE_RETURN; - return_value = execute_command (if_command->test); - line_number = save_line_number; - - if (return_value == EXECUTION_SUCCESS) - { - QUIT; - - if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN)) - if_command->true_case->flags |= CMD_IGNORE_RETURN; - - return (execute_command (if_command->true_case)); - } - else - { - QUIT; - - if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN)) - if_command->false_case->flags |= CMD_IGNORE_RETURN; - - return (execute_command (if_command->false_case)); - } -} - -#if defined (DPAREN_ARITHMETIC) -static int -execute_arith_command (arith_command) - ARITH_COM *arith_command; -{ - int expok, save_line_number, retval; - intmax_t expresult; - WORD_LIST *new; - char *exp; - - expresult = 0; - - save_line_number = line_number; - this_command_name = "(("; /* )) */ - line_number = arith_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell) - line_number -= function_line_number; - - command_string_index = 0; - print_arith_command (arith_command->exp); - - if (signal_in_progress (DEBUG_TRAP) == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - /* Run the debug trap before each arithmetic command, but do it after we - update the line number information and before we expand the various - words in the expression. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - - new = expand_words_no_vars (arith_command->exp); - - /* If we're tracing, make a new word list with `((' at the front and `))' - at the back and print it. */ - if (echo_command_at_execute) - xtrace_print_arith_cmd (new); - - if (new) - { - exp = new->next ? string_list (new) : new->word->word; - expresult = evalexp (exp, &expok); - line_number = save_line_number; - if (exp != new->word->word) - free (exp); - dispose_words (new); - } - else - { - expresult = 0; - expok = 1; - } - - if (expok == 0) - return (EXECUTION_FAILURE); - - return (expresult == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif /* DPAREN_ARITHMETIC */ - -#if defined (COND_COMMAND) - -static char * const nullstr = ""; - -/* XXX - can COND ever be NULL when this is called? */ -static int -execute_cond_node (cond) - COND_COM *cond; -{ - int result, invert, patmatch, rmatch, mflags, ignore; - char *arg1, *arg2; - - invert = (cond->flags & CMD_INVERT_RETURN); - ignore = (cond->flags & CMD_IGNORE_RETURN); - if (ignore) - { - if (cond->left) - cond->left->flags |= CMD_IGNORE_RETURN; - if (cond->right) - cond->right->flags |= CMD_IGNORE_RETURN; - } - - if (cond->type == COND_EXPR) - result = execute_cond_node (cond->left); - else if (cond->type == COND_OR) - { - result = execute_cond_node (cond->left); - if (result != EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_AND) - { - result = execute_cond_node (cond->left); - if (result == EXECUTION_SUCCESS) - result = execute_cond_node (cond->right); - } - else if (cond->type == COND_UNARY) - { - if (ignore) - comsub_ignore_return++; - arg1 = cond_expand_word (cond->left->op, 0); - if (ignore) - comsub_ignore_return--; - if (arg1 == 0) - arg1 = nullstr; - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL); - result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; - if (arg1 != nullstr) - free (arg1); - } - else if (cond->type == COND_BINARY) - { - rmatch = 0; - patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && - (cond->op->word[0] == '!' || cond->op->word[0] == '=')) || - (cond->op->word[0] == '=' && cond->op->word[1] == '\0')); -#if defined (COND_REGEXP) - rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' && - cond->op->word[2] == '\0'); -#endif - - if (ignore) - comsub_ignore_return++; - arg1 = cond_expand_word (cond->left->op, 0); - if (ignore) - comsub_ignore_return--; - if (arg1 == 0) - arg1 = nullstr; - if (ignore) - comsub_ignore_return++; - arg2 = cond_expand_word (cond->right->op, - (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0)); - if (ignore) - comsub_ignore_return--; - if (arg2 == 0) - arg2 = nullstr; - - if (echo_command_at_execute) - xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2); - -#if defined (COND_REGEXP) - if (rmatch) - { - mflags = SHMAT_PWARN; -#if defined (ARRAY_VARS) - mflags |= SHMAT_SUBEXP; -#endif - - result = sh_regmatch (arg1, arg2, mflags); - } - else -#endif /* COND_REGEXP */ - { - int oe; - oe = extended_glob; - extended_glob = 1; - result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE) - ? EXECUTION_SUCCESS - : EXECUTION_FAILURE; - extended_glob = oe; - } - if (arg1 != nullstr) - free (arg1); - if (arg2 != nullstr) - free (arg2); - } - else - { - command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0); - jump_to_top_level (DISCARD); - result = EXECUTION_FAILURE; - } - - if (invert) - result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - - return result; -} - -static int -execute_cond_command (cond_command) - COND_COM *cond_command; -{ - int retval, save_line_number; - - retval = EXECUTION_SUCCESS; - save_line_number = line_number; - - this_command_name = "[["; - line_number = cond_command->line; - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell) - line_number -= function_line_number; - command_string_index = 0; - print_cond_command (cond_command); - - if (signal_in_progress (DEBUG_TRAP) == 0) - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); - } - - /* Run the debug trap before each conditional command, but do it after we - update the line number information. */ - retval = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && retval != EXECUTION_SUCCESS) - { - line_number = save_line_number; - return (EXECUTION_SUCCESS); - } -#endif - -#if 0 - debug_print_cond_command (cond_command); -#endif - - last_command_exit_value = retval = execute_cond_node (cond_command); - line_number = save_line_number; - return (retval); -} -#endif /* COND_COMMAND */ - -static void -bind_lastarg (arg) - char *arg; -{ - SHELL_VAR *var; - - if (arg == 0) - arg = ""; - var = bind_variable ("_", arg, 0); - VUNSETATTR (var, att_exported); -} - -/* Execute a null command. Fork a subshell if the command uses pipes or is - to be run asynchronously. This handles all the side effects that are - supposed to take place. */ -static int -execute_null_command (redirects, pipe_in, pipe_out, async) - REDIRECT *redirects; - int pipe_in, pipe_out, async; -{ - int r; - int forcefork; - REDIRECT *rd; - - for (forcefork = 0, rd = redirects; rd; rd = rd->next) - forcefork += rd->rflags & REDIR_VARASSIGN; - - if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) - { - /* We have a null command, but we really want a subshell to take - care of it. Just fork, do piping and redirections, and exit. */ - if (make_child ((char *)NULL, async) == 0) - { - /* Cancel traps, in trap.c. */ - restore_original_signals (); /* XXX */ - - do_piping (pipe_in, pipe_out); - -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - subshell_environment = 0; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - if (do_redirections (redirects, RX_ACTIVE) == 0) - exit (EXECUTION_SUCCESS); - else - exit (EXECUTION_FAILURE); - } - else - { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - return (EXECUTION_SUCCESS); - } - } - else - { - /* Even if there aren't any command names, pretend to do the - redirections that are specified. The user expects the side - effects to take place. If the redirections fail, then return - failure. Otherwise, if a command substitution took place while - expanding the command or a redirection, return the value of that - substitution. Otherwise, return EXECUTION_SUCCESS. */ - - r = do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE); - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - - if (r != 0) - return (EXECUTION_FAILURE); - else if (last_command_subst_pid != NO_PID) - return (last_command_exit_value); - else - return (EXECUTION_SUCCESS); - } -} - -/* This is a hack to suppress word splitting for assignment statements - given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */ -static void -fix_assignment_words (words) - WORD_LIST *words; -{ - WORD_LIST *w, *wcmd; - struct builtin *b; - int assoc, global; - - if (words == 0) - return; - - b = 0; - assoc = global = 0; - - wcmd = words; - for (w = words; w; w = w->next) - if (w->word->flags & W_ASSIGNMENT) - { - if (b == 0) - { - /* Posix (post-2008) says that `command' doesn't change whether - or not the builtin it shadows is a `declaration command', even - though it removes other special builtin properties. In Posix - mode, we skip over one or more instances of `command' and - deal with the next word as the assignment builtin. */ - while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) - wcmd = wcmd->next; - b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - wcmd->word->flags |= W_ASSNBLTIN; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); -#if defined (ARRAY_VARS) - if (assoc) - w->word->flags |= W_ASSIGNASSOC; - if (global) - w->word->flags |= W_ASSNGLOBAL; -#endif - } -#if defined (ARRAY_VARS) - /* Note that we saw an associative array option to a builtin that takes - assignment statements. This is a bit of a kludge. */ - else if (w->word->word[0] == '-' && (strchr (w->word->word+1, 'A') || strchr (w->word->word+1, 'g'))) -#else - else if (w->word->word[0] == '-' && strchr (w->word->word+1, 'g')) -#endif - { - if (b == 0) - { - while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command")) - wcmd = wcmd->next; - b = builtin_address_internal (wcmd->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - wcmd->word->flags |= W_ASSNBLTIN; - } - if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) - assoc = 1; - if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) - global = 1; - } -} - -/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting - to PATHNAME, is a directory. Used by the autocd code below. */ -static int -is_dirname (pathname) - char *pathname; -{ - char *temp; - int ret; - - temp = search_for_command (pathname, 0); - ret = (temp ? file_isdir (temp) : file_isdir (pathname)); - free (temp); - return ret; -} - -/* The meaty part of all the executions. We have to start hacking the - real execution of commands here. Fork a process, set things up, - execute the command. */ -static int -execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) - SIMPLE_COM *simple_command; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; -{ - WORD_LIST *words, *lastword; - char *command_line, *lastarg, *temp; - int first_word_quoted, result, builtin_is_special, already_forked, dofork; - pid_t old_last_async_pid; - sh_builtin_func_t *builtin; - SHELL_VAR *func; - volatile int old_builtin, old_command_builtin; - - result = EXECUTION_SUCCESS; - special_builtin_failed = builtin_is_special = 0; - command_line = (char *)0; - - QUIT; - - /* If we're in a function, update the line number information. */ - if (variable_context && interactive_shell && sourcelevel == 0) - line_number -= function_line_number; - - /* Remember what this command line looks like at invocation. */ - command_string_index = 0; - print_simple_command (simple_command); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0; - } - - /* Run the debug trap before each simple command, but do it after we - update the line number information. */ - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode && result != EXECUTION_SUCCESS) - return (EXECUTION_SUCCESS); -#endif - - first_word_quoted = - simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0; - - last_command_subst_pid = NO_PID; - old_last_async_pid = last_asynchronous_pid; - - already_forked = dofork = 0; - - /* If we're in a pipeline or run in the background, set DOFORK so we - make the child early, before word expansion. This keeps assignment - statements from affecting the parent shell's environment when they - should not. */ - dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async; - - /* Something like `%2 &' should restart job 2 in the background, not cause - the shell to fork here. */ - if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE && - simple_command->words && simple_command->words->word && - simple_command->words->word->word && - (simple_command->words->word->word[0] == '%')) - dofork = 0; - - if (dofork) - { - /* Do this now, because execute_disk_command will do it anyway in the - vast majority of cases. */ - maybe_make_export_env (); - - /* Don't let a DEBUG trap overwrite the command string to be saved with - the process/job associated with this child. */ - if (make_child (savestring (the_printed_command_except_trap), async) == 0) - { - already_forked = 1; - simple_command->flags |= CMD_NO_FORK; - - subshell_environment = SUBSHELL_FORK; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - - /* We need to do this before piping to handle some really - pathological cases where one of the pipe file descriptors - is < 2. */ - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - pipe_in = pipe_out = NO_PIPE; -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - last_asynchronous_pid = old_last_async_pid; - } - else - { - /* Don't let simple commands that aren't the last command in a - pipeline change $? for the rest of the pipeline (or at all). */ - if (pipe_out != NO_PIPE) - result = last_command_exit_value; - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - command_line = (char *)NULL; /* don't free this. */ - bind_lastarg ((char *)NULL); - return (result); - } - } - - /* If we are re-running this as the result of executing the `command' - builtin, do not expand the command words a second time. */ - if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0) - { - current_fds_to_close = fds_to_close; - fix_assignment_words (simple_command->words); - /* Pass the ignore return flag down to command substitutions */ - if (simple_command->flags & CMD_IGNORE_RETURN) /* XXX */ - comsub_ignore_return++; - words = expand_words (simple_command->words); - if (simple_command->flags & CMD_IGNORE_RETURN) - comsub_ignore_return--; - current_fds_to_close = (struct fd_bitmap *)NULL; - } - else - words = copy_word_list (simple_command->words); - - /* It is possible for WORDS not to have anything left in it. - Perhaps all the words consisted of `$foo', and there was - no variable `$foo'. */ - if (words == 0) - { - this_command_name = 0; - result = execute_null_command (simple_command->redirects, - pipe_in, pipe_out, - already_forked ? 0 : async); - if (already_forked) - exit (result); - else - { - bind_lastarg ((char *)NULL); - set_pipestatus_from_exit (result); - return (result); - } - } - - lastarg = (char *)NULL; - - begin_unwind_frame ("simple-command"); - - if (echo_command_at_execute) - xtrace_print_word_list (words, 1); - - builtin = (sh_builtin_func_t *)NULL; - func = (SHELL_VAR *)NULL; - if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0) - { - /* Posix.2 says special builtins are found before functions. We - don't set builtin_is_special anywhere other than here, because - this path is followed only when the `command' builtin is *not* - being used, and we don't want to exit the shell if a special - builtin executed with `command builtin' fails. `command' is not - a special builtin. */ - if (posixly_correct) - { - builtin = find_special_builtin (words->word->word); - if (builtin) - builtin_is_special = 1; - } - if (builtin == 0) - func = find_function (words->word->word); - } - - /* In POSIX mode, assignment errors in the temporary environment cause a - non-interactive shell to exit. */ - if (builtin_is_special && interactive_shell == 0 && tempenv_assign_error) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (ERREXIT); - } - - add_unwind_protect (dispose_words, words); - QUIT; - - /* Bind the last word in this command to "$_" after execution. */ - for (lastword = words; lastword->next; lastword = lastword->next) - ; - lastarg = lastword->word->word; - -#if defined (JOB_CONTROL) - /* Is this command a job control related thing? */ - if (words->word->word[0] == '%' && already_forked == 0) - { - this_command_name = async ? "bg" : "fg"; - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address (this_command_name); - result = (*this_shell_builtin) (words); - goto return_result; - } - - /* One other possiblilty. The user may want to resume an existing job. - If they do, find out whether this word is a candidate for a running - job. */ - if (job_control && already_forked == 0 && async == 0 && - !first_word_quoted && - !words->next && - words->word->word[0] && - !simple_command->redirects && - pipe_in == NO_PIPE && - pipe_out == NO_PIPE && - (temp = get_string_value ("auto_resume"))) - { - int job, jflags, started_status; - - jflags = JM_STOPPED|JM_FIRSTMATCH; - if (STREQ (temp, "exact")) - jflags |= JM_EXACT; - else if (STREQ (temp, "substring")) - jflags |= JM_SUBSTRING; - else - jflags |= JM_PREFIX; - job = get_job_by_name (words->word->word, jflags); - if (job != NO_JOB) - { - run_unwind_frame ("simple-command"); - this_command_name = "fg"; - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin_address ("fg"); - - started_status = start_job (job, 1); - return ((started_status < 0) ? EXECUTION_FAILURE : started_status); - } - } -#endif /* JOB_CONTROL */ - -run_builtin: - /* Remember the name of this command globally. */ - this_command_name = words->word->word; - - QUIT; - - /* This command could be a shell builtin or a user-defined function. - We have already found special builtins by this time, so we do not - set builtin_is_special. If this is a function or builtin, and we - have pipes, then fork a subshell in here. Otherwise, just execute - the command directly. */ - if (func == 0 && builtin == 0) - builtin = find_shell_builtin (this_command_name); - - last_shell_builtin = this_shell_builtin; - this_shell_builtin = builtin; - - if (builtin || func) - { - if (builtin) - { - old_builtin = executing_builtin; - old_command_builtin = executing_command_builtin; - unwind_protect_int (executing_builtin); /* modified in execute_builtin */ - unwind_protect_int (executing_command_builtin); /* ditto */ - } - if (already_forked) - { - /* reset_terminating_signals (); */ /* XXX */ - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - reset_signal_handlers (); - subshell_environment |= SUBSHELL_RESETTRAP; - - if (async) - { - if ((simple_command->flags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (simple_command->redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - subshell_level++; - execute_subshell_builtin_or_function - (words, simple_command->redirects, builtin, func, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); - subshell_level--; - } - else - { - result = execute_builtin_or_function - (words, builtin, func, simple_command->redirects, fds_to_close, - simple_command->flags); - if (builtin) - { - if (result > EX_SHERRBASE) - { - result = builtin_status (result); - if (builtin_is_special) - special_builtin_failed = 1; - } - /* In POSIX mode, if there are assignment statements preceding - a special builtin, they persist after the builtin - completes. */ - if (posixly_correct && builtin_is_special && temporary_env) - merge_temporary_env (); - } - else /* function */ - { - if (result == EX_USAGE) - result = EX_BADUSAGE; - else if (result > EX_SHERRBASE) - result = EXECUTION_FAILURE; - } - - set_pipestatus_from_exit (result); - - goto return_result; - } - } - - if (autocd && interactive && words->word && is_dirname (words->word->word)) - { - words = make_word_list (make_word ("cd"), words); - xtrace_print_word_list (words, 0); - goto run_builtin; - } - - if (command_line == 0) - command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); - -#if defined (PROCESS_SUBSTITUTION) - if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0) - simple_command->flags &= ~CMD_NO_FORK; -#endif - - result = execute_disk_command (words, simple_command->redirects, command_line, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); - - return_result: - bind_lastarg (lastarg); - FREE (command_line); - dispose_words (words); - if (builtin) - { - executing_builtin = old_builtin; - executing_command_builtin = old_command_builtin; - } - discard_unwind_frame ("simple-command"); - this_command_name = (char *)NULL; /* points to freed memory now */ - return (result); -} - -/* Translate the special builtin exit statuses. We don't really need a - function for this; it's a placeholder for future work. */ -static int -builtin_status (result) - int result; -{ - int r; - - switch (result) - { - case EX_USAGE: - r = EX_BADUSAGE; - break; - case EX_REDIRFAIL: - case EX_BADSYNTAX: - case EX_BADASSIGN: - case EX_EXPFAIL: - r = EXECUTION_FAILURE; - break; - default: - r = EXECUTION_SUCCESS; - break; - } - return (r); -} - -static int -execute_builtin (builtin, words, flags, subshell) - sh_builtin_func_t *builtin; - WORD_LIST *words; - int flags, subshell; -{ - int old_e_flag, result, eval_unwind; - int isbltinenv; - char *error_trap; - - error_trap = 0; - old_e_flag = exit_immediately_on_error; - /* The eval builtin calls parse_and_execute, which does not know about - the setting of flags, and always calls the execution functions with - flags that will exit the shell on an error if -e is set. If the - eval builtin is being called, and we're supposed to ignore the exit - value of the command, we turn the -e flag off ourselves and disable - the ERR trap, then restore them when the command completes. This is - also a problem (as below) for the command and source/. builtins. */ - if (subshell == 0 && (flags & CMD_IGNORE_RETURN) && - (builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin)) - { - begin_unwind_frame ("eval_builtin"); - unwind_protect_int (exit_immediately_on_error); - error_trap = TRAP_STRING (ERROR_TRAP); - if (error_trap) - { - error_trap = savestring (error_trap); - add_unwind_protect (xfree, error_trap); - add_unwind_protect (set_error_trap, error_trap); - restore_default_signal (ERROR_TRAP); - } - exit_immediately_on_error = 0; - eval_unwind = 1; - } - else - eval_unwind = 0; - - /* The temporary environment for a builtin is supposed to apply to - all commands executed by that builtin. Currently, this is a - problem only with the `unset', `source' and `eval' builtins. */ - - isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin); - - if (isbltinenv) - { - if (subshell == 0) - begin_unwind_frame ("builtin_env"); - - if (temporary_env) - { - push_scope (VC_BLTNENV, temporary_env); - if (subshell == 0) - add_unwind_protect (pop_scope, (flags & CMD_COMMAND_BUILTIN) ? 0 : "1"); - temporary_env = (HASH_TABLE *)NULL; - } - } - - /* `return' does a longjmp() back to a saved environment in execute_function. - If a variable assignment list preceded the command, and the shell is - running in POSIX mode, we need to merge that into the shell_variables - table, since `return' is a POSIX special builtin. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) - { - begin_unwind_frame ("return_temp_env"); - add_unwind_protect (merge_temporary_env, (char *)NULL); - } - - executing_builtin++; - executing_command_builtin |= builtin == command_builtin; - result = ((*builtin) (words->next)); - - /* This shouldn't happen, but in case `return' comes back instead of - longjmp'ing, we need to unwind. */ - if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env) - discard_unwind_frame ("return_temp_env"); - - if (subshell == 0 && isbltinenv) - run_unwind_frame ("builtin_env"); - - if (eval_unwind) - { - exit_immediately_on_error += old_e_flag; - if (error_trap) - { - set_error_trap (error_trap); - xfree (error_trap); - } - discard_unwind_frame ("eval_builtin"); - } - - return (result); -} - -static int -execute_function (var, words, flags, fds_to_close, async, subshell) - SHELL_VAR *var; - WORD_LIST *words; - int flags; - struct fd_bitmap *fds_to_close; - int async, subshell; -{ - int return_val, result; - COMMAND *tc, *fc, *save_current; - char *debug_trap, *error_trap, *return_trap; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a; - volatile ARRAY *bash_source_a; - volatile ARRAY *bash_lineno_a; -#endif - FUNCTION_DEF *shell_fn; - char *sfile, *t; - - USE_VAR(fc); - - if (funcnest_max > 0 && funcnest >= funcnest_max) - { - internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest); - funcnest = 0; /* XXX - should we reset it somewhere else? */ - jump_to_top_level (DISCARD); - } - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); -#endif - - tc = (COMMAND *)copy_command (function_cell (var)); - if (tc && (flags & CMD_IGNORE_RETURN)) - tc->flags |= CMD_IGNORE_RETURN; - - if (subshell == 0) - { - begin_unwind_frame ("function_calling"); - push_context (var->name, subshell, temporary_env); - add_unwind_protect (pop_context, (char *)NULL); - unwind_protect_int (line_number); - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - add_unwind_protect (dispose_command, (char *)tc); - unwind_protect_pointer (this_shell_function); - unwind_protect_int (loop_level); - unwind_protect_int (funcnest); - } - else - push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */ - - temporary_env = (HASH_TABLE *)NULL; - - this_shell_function = var; - make_funcname_visible (1); - - debug_trap = TRAP_STRING(DEBUG_TRAP); - error_trap = TRAP_STRING(ERROR_TRAP); - return_trap = TRAP_STRING(RETURN_TRAP); - - /* The order of the unwind protects for debug_trap, error_trap and - return_trap is important here! unwind-protect commands are run - in reverse order of registration. If this causes problems, take - out the xfree unwind-protect calls and live with the small memory leak. */ - - /* function_trace_mode != 0 means that all functions inherit the DEBUG trap. - if the function has the trace attribute set, it inherits the DEBUG trap */ - if (debug_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) - { - if (subshell == 0) - { - debug_trap = savestring (debug_trap); - add_unwind_protect (xfree, debug_trap); - add_unwind_protect (set_debug_trap, debug_trap); - } - restore_default_signal (DEBUG_TRAP); - } - - /* error_trace_mode != 0 means that functions inherit the ERR trap. */ - if (error_trap && error_trace_mode == 0) - { - if (subshell == 0) - { - error_trap = savestring (error_trap); - add_unwind_protect (xfree, error_trap); - add_unwind_protect (set_error_trap, error_trap); - } - restore_default_signal (ERROR_TRAP); - } - - /* Shell functions inherit the RETURN trap if function tracing is on - globally or on individually for this function. */ -#if 0 - if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) -#else - if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0))) -#endif - { - if (subshell == 0) - { - return_trap = savestring (return_trap); - add_unwind_protect (xfree, return_trap); - add_unwind_protect (set_return_trap, return_trap); - } - restore_default_signal (RETURN_TRAP); - } - - funcnest++; -#if defined (ARRAY_VARS) - /* This is quite similar to the code in shell.c and elsewhere. */ - shell_fn = find_function_def (this_shell_function->name); - sfile = shell_fn ? shell_fn->source_file : ""; - array_push ((ARRAY *)funcname_a, this_shell_function->name); - - array_push ((ARRAY *)bash_source_a, sfile); - t = itos (executing_line_number ()); - array_push ((ARRAY *)bash_lineno_a, t); - free (t); -#endif - - /* The temporary environment for a function is supposed to apply to - all commands executed within the function body. */ - - remember_args (words->next, 1); - - /* Update BASH_ARGV and BASH_ARGC */ - if (debugging_mode) - push_args (words->next); - - /* Number of the line on which the function body starts. */ - line_number = function_line_number = tc->line; - -#if defined (JOB_CONTROL) - if (subshell) - stop_pipeline (async, (COMMAND *)NULL); -#endif - - fc = tc; - - return_catch_flag++; - return_val = setjmp (return_catch); - - if (return_val) - { - result = return_catch_value; - /* Run the RETURN trap in the function's context. */ - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; - } - else - { - /* Run the debug trap here so we can trap at the start of a function's - execution rather than the execution of the body's first command. */ - showing_function_line = 1; - save_current = currently_executing_command; - result = run_debug_trap (); -#if defined (DEBUGGER) - /* In debugging mode, if the DEBUG trap returns a non-zero status, we - skip the command. */ - if (debugging_mode == 0 || result == EXECUTION_SUCCESS) - { - showing_function_line = 0; - currently_executing_command = save_current; - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - - /* Run the RETURN trap in the function's context */ - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; - } -#else - result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close); - - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; -#endif - showing_function_line = 0; - } - - /* Restore BASH_ARGC and BASH_ARGV */ - if (debugging_mode) - pop_args (); - - if (subshell == 0) - run_unwind_frame ("function_calling"); - -#if defined (ARRAY_VARS) - /* These two variables cannot be unset, and cannot be affected by the - function. */ - array_pop ((ARRAY *)bash_source_a); - array_pop ((ARRAY *)bash_lineno_a); - - /* FUNCNAME can be unset, and so can potentially be changed by the - function. */ - GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a); - if (nfv == funcname_v) - array_pop (funcname_a); -#endif - - if (variable_context == 0 || this_shell_function == 0) - { - make_funcname_visible (0); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - } - - return (result); -} - -/* A convenience routine for use by other parts of the shell to execute - a particular shell function. */ -int -execute_shell_function (var, words) - SHELL_VAR *var; - WORD_LIST *words; -{ - int ret; - struct fd_bitmap *bitmap; - - bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE); - begin_unwind_frame ("execute-shell-function"); - add_unwind_protect (dispose_fd_bitmap, (char *)bitmap); - - ret = execute_function (var, words, 0, bitmap, 0, 0); - - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("execute-shell-function"); - - return ret; -} - -/* Execute a shell builtin or function in a subshell environment. This - routine does not return; it only calls exit(). If BUILTIN is non-null, - it points to a function to call to execute a shell builtin; otherwise - VAR points at the body of a function to execute. WORDS is the arguments - to the command, REDIRECTS specifies redirections to perform before the - command is executed. */ -static void -execute_subshell_builtin_or_function (words, redirects, builtin, var, - pipe_in, pipe_out, async, fds_to_close, - flags) - WORD_LIST *words; - REDIRECT *redirects; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result, r, funcvalue; -#if defined (JOB_CONTROL) - int jobs_hack; - - jobs_hack = (builtin == jobs_builtin) && - ((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE); -#endif - - /* A subshell is neither a login shell nor interactive. */ - login_shell = interactive = 0; - - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - maybe_make_export_env (); /* XXX - is this needed? */ - -#if defined (JOB_CONTROL) - /* Eradicate all traces of job control after we fork the subshell, so - all jobs begun by this subshell are in the same process group as - the shell itself. */ - - /* Allow the output of `jobs' to be piped. */ - if (jobs_hack) - kill_current_pipeline (); - else - without_job_control (); - - set_sigchld_handler (); -#endif /* JOB_CONTROL */ - - set_sigint_handler (); - - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - - if (do_redirections (redirects, RX_ACTIVE) != 0) - exit (EXECUTION_FAILURE); - - if (builtin) - { - /* Give builtins a place to jump back to on failure, - so we don't go back up to main(). */ - result = setjmp (top_level); - - /* Give the return builtin a place to jump to when executed in a subshell - or pipeline */ - funcvalue = 0; - if (return_catch_flag && builtin == return_builtin) - funcvalue = setjmp (return_catch); - - if (result == EXITPROG) - exit (last_command_exit_value); - else if (result) - exit (EXECUTION_FAILURE); - else if (funcvalue) - exit (return_catch_value); - else - { - r = execute_builtin (builtin, words, flags, 1); - fflush (stdout); - if (r == EX_USAGE) - r = EX_BADUSAGE; - exit (r); - } - } - else - { - r = execute_function (var, words, flags, fds_to_close, async, 1); - fflush (stdout); - exit (r); - } -} - -/* Execute a builtin or function in the current shell context. If BUILTIN - is non-null, it is the builtin command to execute, otherwise VAR points - to the body of a function. WORDS are the command's arguments, REDIRECTS - are the redirections to perform. FDS_TO_CLOSE is the usual bitmap of - file descriptors to close. - - If BUILTIN is exec_builtin, the redirections specified in REDIRECTS are - not undone before this function returns. */ -static int -execute_builtin_or_function (words, builtin, var, redirects, - fds_to_close, flags) - WORD_LIST *words; - sh_builtin_func_t *builtin; - SHELL_VAR *var; - REDIRECT *redirects; - struct fd_bitmap *fds_to_close; - int flags; -{ - int result; - REDIRECT *saved_undo_list; -#if defined (PROCESS_SUBSTITUTION) - int ofifo, nfifo, osize; - char *ofifo_list; -#endif - - -#if defined (PROCESS_SUBSTITUTION) - ofifo = num_fifos (); - ofifo_list = copy_fifo_list (&osize); -#endif - - if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - dispose_exec_redirects (); -#if defined (PROCESS_SUBSTITUTION) - free (ofifo_list); -#endif - return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */ - } - - saved_undo_list = redirection_undo_list; - - /* Calling the "exec" builtin changes redirections forever. */ - if (builtin == exec_builtin) - { - dispose_redirects (saved_undo_list); - saved_undo_list = exec_redirection_undo_list; - exec_redirection_undo_list = (REDIRECT *)NULL; - } - else - dispose_exec_redirects (); - - if (saved_undo_list) - { - begin_unwind_frame ("saved redirects"); - add_unwind_protect (cleanup_redirects, (char *)saved_undo_list); - } - - redirection_undo_list = (REDIRECT *)NULL; - - if (builtin) - result = execute_builtin (builtin, words, flags, 0); - else - result = execute_function (var, words, flags, fds_to_close, 0, 0); - - /* We do this before undoing the effects of any redirections. */ - fflush (stdout); - fpurge (stdout); - if (ferror (stdout)) - clearerr (stdout); - - /* If we are executing the `command' builtin, but this_shell_builtin is - set to `exec_builtin', we know that we have something like - `command exec [redirection]', since otherwise `exec' would have - overwritten the shell and we wouldn't get here. In this case, we - want to behave as if the `command' builtin had not been specified - and preserve the redirections. */ - if (builtin == command_builtin && this_shell_builtin == exec_builtin) - { - int discard; - - discard = 0; - if (saved_undo_list) - { - dispose_redirects (saved_undo_list); - discard = 1; - } - redirection_undo_list = exec_redirection_undo_list; - saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL; - if (discard) - discard_unwind_frame ("saved redirects"); - } - - if (saved_undo_list) - { - redirection_undo_list = saved_undo_list; - discard_unwind_frame ("saved redirects"); - } - - if (redirection_undo_list) - { - cleanup_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } - -#if defined (PROCESS_SUBSTITUTION) - /* Close any FIFOs created by this builtin or function. */ - nfifo = num_fifos (); - if (nfifo > ofifo) - close_new_fifos (ofifo_list, osize); - free (ofifo_list); -#endif - - return (result); -} - -void -setup_async_signals () -{ -#if defined (__BEOS__) - set_signal_handler (SIGHUP, SIG_IGN); /* they want csh-like behavior */ -#endif - -#if defined (JOB_CONTROL) - if (job_control == 0) -#endif - { - set_signal_handler (SIGINT, SIG_IGN); - set_signal_ignored (SIGINT); - set_signal_handler (SIGQUIT, SIG_IGN); - set_signal_ignored (SIGQUIT); - } -} - -/* Execute a simple command that is hopefully defined in a disk file - somewhere. - - 1) fork () - 2) connect pipes - 3) look up the command - 4) do redirections - 5) execve () - 6) If the execve failed, see if the file has executable mode set. - If so, and it isn't a directory, then execute its contents as - a shell script. - - Note that the filename hashing stuff has to take place up here, - in the parent. This is probably why the Bourne style shells - don't handle it, since that would require them to go through - this gnarly hair, for no good reason. - - NOTE: callers expect this to fork or exit(). */ - -/* Name of a shell function to call when a command name is not found. */ -#ifndef NOTFOUND_HOOK -# define NOTFOUND_HOOK "command_not_found_handle" -#endif - -static int -execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, - async, fds_to_close, cmdflags) - WORD_LIST *words; - REDIRECT *redirects; - char *command_line; - int pipe_in, pipe_out, async; - struct fd_bitmap *fds_to_close; - int cmdflags; -{ - char *pathname, *command, **args; - int nofork, result; - pid_t pid; - SHELL_VAR *hookf; - WORD_LIST *wl; - - nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */ - pathname = words->word->word; - - result = EXECUTION_SUCCESS; -#if defined (RESTRICTED_SHELL) - command = (char *)NULL; - if (restricted && mbschr (pathname, '/')) - { - internal_error (_("%s: restricted: cannot specify `/' in command names"), - pathname); - result = last_command_exit_value = EXECUTION_FAILURE; - - /* If we're not going to fork below, we must already be in a child - process or a context in which it's safe to call exit(2). */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - exit (last_command_exit_value); - else - goto parent_return; - } -#endif /* RESTRICTED_SHELL */ - - command = search_for_command (pathname, 1); - - if (command) - { - maybe_make_export_env (); - put_command_name_into_env (command); - } - - /* We have to make the child before we check for the non-existence - of COMMAND, since we want the error messages to be redirected. */ - /* If we can get away without forking and there are no pipes to deal with, - don't bother to fork, just directly exec the command. */ - if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE) - pid = 0; - else - pid = make_child (savestring (command_line), async); - - if (pid == 0) - { - int old_interactive; - -#if 0 - /* This has been disabled for the time being. */ -#if !defined (ARG_MAX) || ARG_MAX >= 10240 - if (posixly_correct == 0) - put_gnu_argv_flags_into_env ((long)getpid (), glob_argv_flags); -#endif -#endif - - reset_terminating_signals (); /* XXX */ - /* Cancel traps, in trap.c. */ - restore_original_signals (); - - /* restore_original_signals may have undone the work done - by make_child to ensure that SIGINT and SIGQUIT are ignored - in asynchronous children. */ - if (async) - { - if ((cmdflags & CMD_STDIN_REDIR) && - pipe_in == NO_PIPE && - (stdin_redirects (redirects) == 0)) - async_redirect_stdin (); - setup_async_signals (); - } - - /* This functionality is now provided by close-on-exec of the - file descriptors manipulated by redirection and piping. - Some file descriptors still need to be closed in all children - because of the way bash does pipes; fds_to_close is a - bitmap of all such file descriptors. */ - if (fds_to_close) - close_fd_bitmap (fds_to_close); - - do_piping (pipe_in, pipe_out); - - old_interactive = interactive; - if (async) - interactive = 0; - - subshell_environment = SUBSHELL_FORK; - - if (redirects && (do_redirections (redirects, RX_ACTIVE) != 0)) - { -#if defined (PROCESS_SUBSTITUTION) - /* Try to remove named pipes that may have been created as the - result of redirections. */ - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - exit (EXECUTION_FAILURE); - } - - if (async) - interactive = old_interactive; - - if (command == 0) - { - hookf = find_function (NOTFOUND_HOOK); - if (hookf == 0) - { - /* Make sure filenames are displayed using printable characters */ - if (ansic_shouldquote (pathname)) - pathname = ansic_quote (pathname, 0, NULL); - internal_error (_("%s: command not found"), pathname); - exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ - } - - wl = make_word_list (make_word (NOTFOUND_HOOK), words); - exit (execute_shell_function (hookf, wl)); - } - - /* Execve expects the command name to be in args[0]. So we - leave it there, in the same format that the user used to - type it in. */ - args = strvec_from_word_list (words, 0, 0, (int *)NULL); - exit (shell_execve (command, args, export_env)); - } - else - { -parent_return: - QUIT; - - /* Make sure that the pipes are closed in the parent. */ - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - if (variable_context == 0) - unlink_fifo_list (); -#endif - FREE (command); - return (result); - } -} - -/* CPP defines to decide whether a particular index into the #! line - corresponds to a valid interpreter name or argument character, or - whitespace. The MSDOS define is to allow \r to be treated the same - as \n. */ - -#if !defined (MSDOS) -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#else /* MSDOS */ -# define STRINGCHAR(ind) \ - (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r') -# define WHITECHAR(ind) \ - (ind < sample_len && whitespace (sample[ind])) -#endif /* MSDOS */ - -static char * -getinterp (sample, sample_len, endp) - char *sample; - int sample_len, *endp; -{ - register int i; - char *execname; - int start; - - /* Find the name of the interpreter to exec. */ - for (i = 2; i < sample_len && whitespace (sample[i]); i++) - ; - - for (start = i; STRINGCHAR(i); i++) - ; - - execname = substring (sample, start, i); - - if (endp) - *endp = i; - return execname; -} - -#if !defined (HAVE_HASH_BANG_EXEC) -/* If the operating system on which we're running does not handle - the #! executable format, then help out. SAMPLE is the text read - from the file, SAMPLE_LEN characters. COMMAND is the name of - the script; it and ARGS, the arguments given by the user, will - become arguments to the specified interpreter. ENV is the environment - to pass to the interpreter. - - The word immediately following the #! is the interpreter to execute. - A single argument to the interpreter is allowed. */ - -static int -execute_shell_script (sample, sample_len, command, args, env) - char *sample; - int sample_len; - char *command; - char **args, **env; -{ - char *execname, *firstarg; - int i, start, size_increment, larry; - - /* Find the name of the interpreter to exec. */ - execname = getinterp (sample, sample_len, &i); - size_increment = 1; - - /* Now the argument, if any. */ - for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++) - ; - - /* If there is more text on the line, then it is an argument for the - interpreter. */ - - if (STRINGCHAR(i)) - { - for (start = i; STRINGCHAR(i); i++) - ; - firstarg = substring ((char *)sample, start, i); - size_increment = 2; - } - - larry = strvec_len (args) + size_increment; - args = strvec_resize (args, larry + 1); - - for (i = larry - 1; i; i--) - args[i] = args[i - size_increment]; - - args[0] = execname; - if (firstarg) - { - args[1] = firstarg; - args[2] = command; - } - else - args[1] = command; - - args[larry] = (char *)NULL; - - return (shell_execve (execname, args, env)); -} -#undef STRINGCHAR -#undef WHITECHAR - -#endif /* !HAVE_HASH_BANG_EXEC */ - -static void -initialize_subshell () -{ -#if defined (ALIAS) - /* Forget about any aliases that we knew of. We are in a subshell. */ - delete_all_aliases (); -#endif /* ALIAS */ - -#if defined (HISTORY) - /* Forget about the history lines we have read. This is a non-interactive - subshell. */ - history_lines_this_session = 0; -#endif - -#if defined (JOB_CONTROL) - /* Forget about the way job control was working. We are in a subshell. */ - without_job_control (); - set_sigchld_handler (); - init_job_stats (); -#endif /* JOB_CONTROL */ - - /* Reset the values of the shell flags and options. */ - reset_shell_flags (); - reset_shell_options (); - reset_shopt_options (); - - /* Zero out builtin_env, since this could be a shell script run from a - sourced file with a temporary environment supplied to the `source/.' - builtin. Such variables are not supposed to be exported (empirical - testing with sh and ksh). Just throw it away; don't worry about a - memory leak. */ - if (vc_isbltnenv (shell_variables)) - shell_variables = shell_variables->down; - - clear_unwind_protect_list (0); - /* XXX -- are there other things we should be resetting here? */ - parse_and_execute_level = 0; /* nothing left to restore it */ - - /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = funcnest = 0; - - executing_list = 0; /* XXX */ - - /* If we're not interactive, close the file descriptor from which we're - reading the current shell script. */ - if (interactive_shell == 0) - unset_bash_input (0); -} - -#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) -# define SETOSTYPE(x) __setostype(x) -#else -# define SETOSTYPE(x) -#endif - -#define READ_SAMPLE_BUF(file, buf, len) \ - do \ - { \ - fd = open(file, O_RDONLY); \ - if (fd >= 0) \ - { \ - len = read (fd, buf, 80); \ - close (fd); \ - } \ - else \ - len = -1; \ - } \ - while (0) - -/* Call execve (), handling interpreting shell scripts, and handling - exec failures. */ -int -shell_execve (command, args, env) - char *command; - char **args, **env; -{ - int larray, i, fd; - char sample[80]; - int sample_len; - - SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ - execve (command, args, env); - i = errno; /* error from execve() */ - CHECK_TERMSIG; - SETOSTYPE (1); - - /* If we get to this point, then start checking out the file. - Maybe it is something we can hack ourselves. */ - if (i != ENOEXEC) - { - if (file_isdir (command)) -#if defined (EISDIR) - internal_error (_("%s: %s"), command, strerror (EISDIR)); -#else - internal_error (_("%s: is a directory"), command); -#endif - else if (executable_file (command) == 0) - { - errno = i; - file_error (command); - } - /* errors not involving the path argument to execve. */ - else if (i == E2BIG || i == ENOMEM) - { - errno = i; - file_error (command); - } - else - { - /* The file has the execute bits set, but the kernel refuses to - run it for some reason. See why. */ -#if defined (HAVE_HASH_BANG_EXEC) - READ_SAMPLE_BUF (command, sample, sample_len); - sample[sample_len - 1] = '\0'; - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - { - char *interp; - int ilen; - - interp = getinterp (sample, sample_len, (int *)NULL); - ilen = strlen (interp); - errno = i; - if (interp[ilen - 1] == '\r') - { - interp = xrealloc (interp, ilen + 2); - interp[ilen - 1] = '^'; - interp[ilen] = 'M'; - interp[ilen + 1] = '\0'; - } - sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : ""); - FREE (interp); - return (EX_NOEXEC); - } -#endif - errno = i; - file_error (command); - } - return ((i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); /* XXX Posix.2 says that exit status is 126 */ - } - - /* This file is executable. - If it begins with #!, then help out people with losing operating - systems. Otherwise, check to see if it is a binary file by seeing - if the contents of the first line (or up to 80 characters) are in the - ASCII set. If it's a text file, execute the contents as shell commands, - otherwise return 126 (EX_BINARY_FILE). */ - READ_SAMPLE_BUF (command, sample, sample_len); - - if (sample_len == 0) - return (EXECUTION_SUCCESS); - - /* Is this supposed to be an executable script? - If so, the format of the line is "#! interpreter [argument]". - A single argument is allowed. The BSD kernel restricts - the length of the entire line to 32 characters (32 bytes - being the size of the BSD exec header), but we allow 80 - characters. */ - if (sample_len > 0) - { -#if !defined (HAVE_HASH_BANG_EXEC) - if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') - return (execute_shell_script (sample, sample_len, command, args, env)); - else -#endif - if (check_binary_file (sample, sample_len)) - { - internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i)); - return (EX_BINARY_FILE); - } - } - - /* We have committed to attempting to execute the contents of this file - as shell commands. */ - - initialize_subshell (); - - set_sigint_handler (); - - /* Insert the name of this shell into the argument list. */ - larray = strvec_len (args) + 1; - args = strvec_resize (args, larray + 1); - - for (i = larray - 1; i; i--) - args[i] = args[i - 1]; - - args[0] = shell_name; - args[1] = command; - args[larray] = (char *)NULL; - - if (args[0][0] == '-') - args[0]++; - -#if defined (RESTRICTED_SHELL) - if (restricted) - change_flag ('r', FLAG_OFF); -#endif - - if (subshell_argv) - { - /* Can't free subshell_argv[0]; that is shell_name. */ - for (i = 1; i < subshell_argc; i++) - free (subshell_argv[i]); - free (subshell_argv); - } - - dispose_command (currently_executing_command); /* XXX */ - currently_executing_command = (COMMAND *)NULL; - - subshell_argc = larray; - subshell_argv = args; - subshell_envp = env; - - unbind_args (); /* remove the positional parameters */ - - longjmp (subshell_top_level, 1); - /*NOTREACHED*/ -} - -static int -execute_intern_function (name, funcdef) - WORD_DESC *name; - FUNCTION_DEF *funcdef; -{ - SHELL_VAR *var; - - if (check_identifier (name, posixly_correct) == 0) - { - if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (ERREXIT); - } - return (EXECUTION_FAILURE); - } - - /* Posix interpretation 383 */ - if (posixly_correct && find_special_builtin (name->word)) - { - internal_error (_("`%s': is a special builtin"), name->word); - last_command_exit_value = EX_BADUSAGE; - jump_to_top_level (ERREXIT); - } - - var = find_function (name->word); - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - internal_error (_("%s: readonly function"), var->name); - return (EXECUTION_FAILURE); - } - -#if defined (DEBUGGER) - bind_function_def (name->word, funcdef); -#endif - - bind_function (name->word, funcdef->command); - return (EXECUTION_SUCCESS); -} - -#if defined (INCLUDE_UNUSED) -#if defined (PROCESS_SUBSTITUTION) -void -close_all_files () -{ - register int i, fd_table_size; - - fd_table_size = getdtablesize (); - if (fd_table_size > 256) /* clamp to a reasonable value */ - fd_table_size = 256; - - for (i = 3; i < fd_table_size; i++) - close (i); -} -#endif /* PROCESS_SUBSTITUTION */ -#endif - -static void -close_pipes (in, out) - int in, out; -{ - if (in >= 0) - close (in); - if (out >= 0) - close (out); -} - -static void -dup_error (oldd, newd) - int oldd, newd; -{ - sys_error (_("cannot duplicate fd %d to fd %d"), oldd, newd); -} - -/* Redirect input and output to be from and to the specified pipes. - NO_PIPE and REDIRECT_BOTH are handled correctly. */ -static void -do_piping (pipe_in, pipe_out) - int pipe_in, pipe_out; -{ - if (pipe_in != NO_PIPE) - { - if (dup2 (pipe_in, 0) < 0) - dup_error (pipe_in, 0); - if (pipe_in > 0) - close (pipe_in); -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode. */ - freopen (NULL, "r", stdin); -#endif /* __CYGWIN__ */ - } - if (pipe_out != NO_PIPE) - { - if (pipe_out != REDIRECT_BOTH) - { - if (dup2 (pipe_out, 1) < 0) - dup_error (pipe_out, 1); - if (pipe_out == 0 || pipe_out > 1) - close (pipe_out); - } - else - { - if (dup2 (1, 2) < 0) - dup_error (1, 2); - } -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode, and - make sure to preserve stdout line buffering. */ - freopen (NULL, "w", stdout); - sh_setlinebuf (stdout); -#endif /* __CYGWIN__ */ - } -} diff --git a/externs.h~ b/externs.h~ deleted file mode 100644 index 205dd8009..000000000 --- a/externs.h~ +++ /dev/null @@ -1,502 +0,0 @@ -/* externs.h -- extern function declarations which do not appear in their - own header file. */ - -/* Copyright (C) 1993-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 . -*/ - -/* Make sure that this is included *after* config.h! */ - -#if !defined (_EXTERNS_H_) -# define _EXTERNS_H_ - -#include "stdc.h" - -/* Functions from expr.c. */ -extern intmax_t evalexp __P((char *, int *)); - -/* Functions from print_cmd.c. */ -#define FUNC_MULTILINE 0x01 -#define FUNC_EXTERNAL 0x02 - -extern char *make_command_string __P((COMMAND *)); -extern char *named_function_string __P((char *, COMMAND *, int)); - -extern void print_command __P((COMMAND *)); -extern void print_simple_command __P((SIMPLE_COM *)); -extern void print_word_list __P((WORD_LIST *, char *)); - -/* debugger support */ -extern void print_for_command_head __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -extern void print_select_command_head __P((SELECT_COM *)); -#endif -extern void print_case_command_head __P((CASE_COM *)); -#if defined (DPAREN_ARITHMETIC) -extern void print_arith_command __P((WORD_LIST *)); -#endif -#if defined (COND_COMMAND) -extern void print_cond_command __P((COND_COM *)); -#endif - -/* set -x support */ -extern void xtrace_init __P((void)); -#ifdef NEED_XTRACE_SET_DECL -extern void xtrace_set __P((int, FILE *)); -#endif -extern void xtrace_fdchk __P((int)); -extern void xtrace_reset __P((void)); -extern char *indirection_level_string __P((void)); -extern void xtrace_print_assignment __P((char *, char *, int, int)); -extern void xtrace_print_word_list __P((WORD_LIST *, int)); -extern void xtrace_print_for_command_head __P((FOR_COM *)); -#if defined (SELECT_COMMAND) -extern void xtrace_print_select_command_head __P((SELECT_COM *)); -#endif -extern void xtrace_print_case_command_head __P((CASE_COM *)); -#if defined (DPAREN_ARITHMETIC) -extern void xtrace_print_arith_cmd __P((WORD_LIST *)); -#endif -#if defined (COND_COMMAND) -extern void xtrace_print_cond_term __P((int, int, WORD_DESC *, char *, char *)); -#endif - -/* Functions from shell.c. */ -extern void exit_shell __P((int)) __attribute__((__noreturn__)); -extern void sh_exit __P((int)) __attribute__((__noreturn__)); -extern void disable_priv_mode __P((void)); -extern void unbind_args __P((void)); - -#if defined (RESTRICTED_SHELL) -extern int shell_is_restricted __P((char *)); -extern int maybe_make_restricted __P((char *)); -#endif - -extern void unset_bash_input __P((int)); -extern void get_current_user_info __P((void)); - -/* Functions from eval.c. */ -extern int reader_loop __P((void)); -extern int parse_command __P((void)); -extern int read_command __P((void)); - -/* Functions from braces.c. */ -#if defined (BRACE_EXPANSION) -extern char **brace_expand __P((char *)); -#endif - -/* Miscellaneous functions from parse.y */ -extern int yyparse __P((void)); -extern int return_EOF __P((void)); -extern char *xparse_dolparen __P((char *, char *, int *, int)); -extern void reset_parser __P((void)); -extern WORD_LIST *parse_string_to_word_list __P((char *, int, const char *)); - -extern int parser_in_command_position __P((void)); - -extern void free_pushed_string_input __P((void)); - -extern char *decode_prompt_string __P((char *)); - -extern int get_current_prompt_level __P((void)); -extern void set_current_prompt_level __P((int)); - -#if defined (HISTORY) -extern char *history_delimiting_chars __P((const char *)); -#endif - -/* Declarations for functions defined in locale.c */ -extern void set_default_locale __P((void)); -extern void set_default_locale_vars __P((void)); -extern int set_locale_var __P((char *, char *)); -extern int set_lang __P((char *, char *)); -extern void set_default_lang __P((void)); -extern char *get_locale_var __P((char *)); -extern char *localetrans __P((char *, int, int *)); -extern char *mk_msgstr __P((char *, int *)); -extern char *localeexpand __P((char *, int, int, int, int *)); - -/* Declarations for functions defined in list.c. */ -extern void list_walk __P((GENERIC_LIST *, sh_glist_func_t *)); -extern void wlist_walk __P((WORD_LIST *, sh_icpfunc_t *)); -extern GENERIC_LIST *list_reverse (); -extern int list_length (); -extern GENERIC_LIST *list_append (); -extern GENERIC_LIST *list_remove (); - -/* Declarations for functions defined in stringlib.c */ -extern int find_string_in_alist __P((char *, STRING_INT_ALIST *, int)); -extern char *find_token_in_alist __P((int, STRING_INT_ALIST *, int)); -extern int find_index_in_alist __P((char *, STRING_INT_ALIST *, int)); - -extern char *substring __P((const char *, int, int)); -extern char *strsub __P((char *, char *, char *, int)); -extern char *strcreplace __P((char *, int, char *, int)); -extern void strip_leading __P((char *)); -extern void strip_trailing __P((char *, int, int)); -extern void xbcopy __P((char *, char *, int)); - -/* Functions from version.c. */ -extern char *shell_version_string __P((void)); -extern void show_shell_version __P((int)); - -/* Functions from the bash library, lib/sh/libsh.a. These should really - go into a separate include file. */ - -/* declarations for functions defined in lib/sh/casemod.c */ -extern char *sh_modcase __P((const char *, char *, int)); - -/* Defines for flags argument to sh_modcase. These need to agree with what's - in lib/sh/casemode.c */ -#define CASE_LOWER 0x0001 -#define CASE_UPPER 0x0002 -#define CASE_CAPITALIZE 0x0004 -#define CASE_UNCAP 0x0008 -#define CASE_TOGGLE 0x0010 -#define CASE_TOGGLEALL 0x0020 -#define CASE_UPFIRST 0x0040 -#define CASE_LOWFIRST 0x0080 - -#define CASE_USEWORDS 0x1000 - -/* declarations for functions defined in lib/sh/clktck.c */ -extern long get_clk_tck __P((void)); - -/* declarations for functions defined in lib/sh/clock.c */ -extern void clock_t_to_secs (); -extern void print_clock_t (); - -/* Declarations for functions defined in lib/sh/dprintf.c */ -#if !defined (HAVE_DPRINTF) -extern void dprintf __P((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3))); -#endif - -/* Declarations for functions defined in lib/sh/fmtulong.c */ -#define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */ -#define FL_ADDBASE 0x02 /* add base# prefix to converted value */ -#define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */ -#define FL_UNSIGNED 0x08 /* don't add any sign */ - -extern char *fmtulong __P((unsigned long int, int, char *, size_t, int)); - -/* Declarations for functions defined in lib/sh/fmtulong.c */ -#if defined (HAVE_LONG_LONG) -extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); -#endif - -/* Declarations for functions defined in lib/sh/fmtumax.c */ -extern char *fmtumax __P((uintmax_t, int, char *, size_t, int)); - -/* Declarations for functions defined in lib/sh/fnxform.c */ -extern char *fnx_fromfs __P((char *, size_t)); -extern char *fnx_tofs __P((char *, size_t)); - -/* Declarations for functions defined in lib/sh/fpurge.c */ - -#if defined NEED_FPURGE_DECL -#if !HAVE_DECL_FPURGE - -#if HAVE_FPURGE -# define fpurge _bash_fpurge -#endif -extern int fpurge __P((FILE *stream)); - -#endif /* HAVE_DECL_FPURGE */ -#endif /* NEED_FPURGE_DECL */ - -/* Declarations for functions defined in lib/sh/getcwd.c */ -#if !defined (HAVE_GETCWD) -extern char *getcwd __P((char *, size_t)); -#endif - -/* Declarations for functions defined in lib/sh/input_avail.c */ -extern int input_avail __P((int)); - -/* Declarations for functions defined in lib/sh/itos.c */ -extern char *inttostr __P((intmax_t, char *, size_t)); -extern char *itos __P((intmax_t)); -extern char *uinttostr __P((uintmax_t, char *, size_t)); -extern char *uitos __P((uintmax_t)); - -/* declarations for functions defined in lib/sh/makepath.c */ -#define MP_DOTILDE 0x01 -#define MP_DOCWD 0x02 -#define MP_RMDOT 0x04 -#define MP_IGNDOT 0x08 - -extern char *sh_makepath __P((const char *, const char *, int)); - -/* declarations for functions defined in lib/sh/mbscasecmp.c */ -#if !defined (HAVE_MBSCASECMP) -extern char *mbscasecmp __P((const char *, const char *)); -#endif - -/* declarations for functions defined in lib/sh/mbschr.c */ -#if !defined (HAVE_MBSCHR) -extern char *mbschr __P((const char *, int)); -#endif - -/* declarations for functions defined in lib/sh/mbscmp.c */ -#if !defined (HAVE_MBSCMP) -extern char *mbscmp __P((const char *, const char *)); -#endif - -/* declarations for functions defined in lib/sh/netconn.c */ -extern int isnetconn __P((int)); - -/* declarations for functions defined in lib/sh/netopen.c */ -extern int netopen __P((char *)); - -/* Declarations for functions defined in lib/sh/oslib.c */ - -#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) -extern int dup2 __P((int, int)); -#endif - -#if !defined (HAVE_GETDTABLESIZE) -extern int getdtablesize __P((void)); -#endif /* !HAVE_GETDTABLESIZE */ - -#if !defined (HAVE_GETHOSTNAME) -extern int gethostname __P((char *, int)); -#endif /* !HAVE_GETHOSTNAME */ - -extern int getmaxgroups __P((void)); -extern long getmaxchild __P((void)); - -/* declarations for functions defined in lib/sh/pathcanon.c */ -#define PATH_CHECKDOTDOT 0x0001 -#define PATH_CHECKEXISTS 0x0002 -#define PATH_HARDPATH 0x0004 -#define PATH_NOALLOC 0x0008 - -extern char *sh_canonpath __P((char *, int)); - -/* declarations for functions defined in lib/sh/pathphys.c */ -extern char *sh_physpath __P((char *, int)); -extern char *sh_realpath __P((const char *, char *)); - -/* declarations for functions defined in lib/sh/setlinebuf.c */ -#ifdef NEED_SH_SETLINEBUF_DECL -extern int sh_setlinebuf __P((FILE *)); -#endif - -/* declarations for functions defined in lib/sh/shaccess.c */ -extern int sh_eaccess __P((char *, int)); - -/* declarations for functions defined in lib/sh/shmatch.c */ -extern int sh_regmatch __P((const char *, const char *, int)); - -/* defines for flags argument to sh_regmatch. */ -#define SHMAT_SUBEXP 0x001 /* save subexpressions in SH_REMATCH */ -#define SHMAT_PWARN 0x002 /* print a warning message on invalid regexp */ - -/* declarations for functions defined in lib/sh/shmbchar.c */ -extern size_t mbstrlen __P((const char *)); -extern char *mbsmbchar __P((const char *)); -extern int sh_mbsnlen __P((const char *, size_t, int)); - -/* declarations for functions defined in lib/sh/shquote.c */ -extern char *sh_single_quote __P((const char *)); -extern char *sh_double_quote __P((const char *)); -extern char *sh_mkdoublequoted __P((const char *, int, int)); -extern char *sh_un_double_quote __P((char *)); -extern char *sh_backslash_quote __P((char *, const char *, int)); -extern char *sh_backslash_quote_for_double_quotes __P((char *)); -extern int sh_contains_shell_metas __P((char *)); - -/* declarations for functions defined in lib/sh/spell.c */ -extern int spname __P((char *, char *)); -extern char *dirspell __P((char *)); - -/* declarations for functions defined in lib/sh/strcasecmp.c */ -#if !defined (HAVE_STRCASECMP) -extern int strncasecmp __P((const char *, const char *, int)); -extern int strcasecmp __P((const char *, const char *)); -#endif /* HAVE_STRCASECMP */ - -/* declarations for functions defined in lib/sh/strcasestr.c */ -#if ! HAVE_STRCASESTR -extern char *strcasestr __P((const char *, const char *)); -#endif - -/* declarations for functions defined in lib/sh/strchrnul.c */ -#if ! HAVE_STRCHRNUL -extern char *strchrnul __P((const char *, int)); -#endif - -/* declarations for functions defined in lib/sh/strerror.c */ -#if !defined (HAVE_STRERROR) && !defined (strerror) -extern char *strerror __P((int)); -#endif - -/* declarations for functions defined in lib/sh/strftime.c */ -#if !defined (HAVE_STRFTIME) && defined (NEED_STRFTIME_DECL) -extern size_t strftime __P((char *, size_t, const char *, const struct tm *)); -#endif - -/* declarations for functions and structures defined in lib/sh/stringlist.c */ - -/* This is a general-purpose argv-style array struct. */ -typedef struct _list_of_strings { - char **list; - int list_size; - int list_len; -} STRINGLIST; - -typedef int sh_strlist_map_func_t __P((char *)); - -extern STRINGLIST *strlist_create __P((int)); -extern STRINGLIST *strlist_resize __P((STRINGLIST *, int)); -extern void strlist_flush __P((STRINGLIST *)); -extern void strlist_dispose __P((STRINGLIST *)); -extern int strlist_remove __P((STRINGLIST *, char *)); -extern STRINGLIST *strlist_copy __P((STRINGLIST *)); -extern STRINGLIST *strlist_merge __P((STRINGLIST *, STRINGLIST *)); -extern STRINGLIST *strlist_append __P((STRINGLIST *, STRINGLIST *)); -extern STRINGLIST *strlist_prefix_suffix __P((STRINGLIST *, char *, char *)); -extern void strlist_print __P((STRINGLIST *, char *)); -extern void strlist_walk __P((STRINGLIST *, sh_strlist_map_func_t *)); -extern void strlist_sort __P((STRINGLIST *)); - -/* declarations for functions defined in lib/sh/stringvec.c */ - -extern char **strvec_create __P((int)); -extern char **strvec_resize __P((char **, int)); -extern void strvec_flush __P((char **)); -extern void strvec_dispose __P((char **)); -extern int strvec_remove __P((char **, char *)); -extern int strvec_len __P((char **)); -extern int strvec_search __P((char **, char *)); -extern char **strvec_copy __P((char **)); -extern int strvec_strcmp __P((char **, char **)); -extern void strvec_sort __P((char **)); - -extern char **strvec_from_word_list __P((WORD_LIST *, int, int, int *)); -extern WORD_LIST *strvec_to_word_list __P((char **, int, int)); - -/* declarations for functions defined in lib/sh/strnlen.c */ -#if !defined (HAVE_STRNLEN) -extern size_t strnlen __P((const char *, size_t)); -#endif - -/* declarations for functions defined in lib/sh/strpbrk.c */ -#if !defined (HAVE_STRPBRK) -extern char *strpbrk __P((const char *, const char *)); -#endif - -/* declarations for functions defined in lib/sh/strtod.c */ -#if !defined (HAVE_STRTOD) -extern double strtod __P((const char *, char **)); -#endif - -/* declarations for functions defined in lib/sh/strtol.c */ -#if !HAVE_DECL_STRTOL -extern long strtol __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoll.c */ -#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOLL -extern long long strtoll __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoul.c */ -#if !HAVE_DECL_STRTOUL -extern unsigned long strtoul __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtoull.c */ -#if defined (HAVE_LONG_LONG) && !HAVE_DECL_STRTOULL -extern unsigned long long strtoull __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strimax.c */ -#if !HAVE_DECL_STRTOIMAX -extern intmax_t strtoimax __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strumax.c */ -#if !HAVE_DECL_STRTOUMAX -extern uintmax_t strtoumax __P((const char *, char **, int)); -#endif - -/* declarations for functions defined in lib/sh/strtrans.c */ -extern char *ansicstr __P((char *, int, int, int *, int *)); -extern char *ansic_quote __P((char *, int, int *)); -extern int ansic_shouldquote __P((const char *)); -extern char *ansiexpand __P((char *, int, int, int *)); - -/* declarations for functions defined in lib/sh/timeval.c. No prototypes - so we don't have to count on having a definition of struct timeval in - scope when this file is included. */ -extern void timeval_to_secs (); -extern void print_timeval (); - -/* declarations for functions defined in lib/sh/tmpfile.c */ -#define MT_USETMPDIR 0x0001 -#define MT_READWRITE 0x0002 -#define MT_USERANDOM 0x0004 - -extern char *sh_mktmpname __P((char *, int)); -extern int sh_mktmpfd __P((char *, int, char **)); -/* extern FILE *sh_mktmpfp __P((char *, int, char **)); */ - -/* declarations for functions defined in lib/sh/uconvert.c */ -extern int uconvert __P((char *, long *, long *)); - -/* declarations for functions defined in lib/sh/ufuncs.c */ -extern unsigned int falarm __P((unsigned int, unsigned int)); -extern unsigned int fsleep __P((unsigned int, unsigned int)); - -/* declarations for functions defined in lib/sh/unicode.c */ -extern int u32cconv __P((unsigned long, char *)); -extern void u32reset __P((void)); - -/* declarations for functions defined in lib/sh/winsize.c */ -extern void get_new_window_size __P((int, int *, int *)); - -/* declarations for functions defined in lib/sh/zcatfd.c */ -extern int zcatfd __P((int, int, char *)); - -/* declarations for functions defined in lib/sh/zgetline.c */ -extern ssize_t zgetline __P((int, char **, size_t *, int)); - -/* declarations for functions defined in lib/sh/zmapfd.c */ -extern int zmapfd __P((int, char **, char *)); - -/* declarations for functions defined in lib/sh/zread.c */ -extern ssize_t zread __P((int, char *, size_t)); -extern ssize_t zreadretry __P((int, char *, size_t)); -extern ssize_t zreadintr __P((int, char *, size_t)); -extern ssize_t zreadc __P((int, char *)); -extern ssize_t zreadcintr __P((int, char *)); -extern void zreset __P((void)); -extern void zsyncfd __P((int)); - -/* declarations for functions defined in lib/sh/zwrite.c */ -extern int zwrite __P((int, char *, size_t)); - -/* declarations for functions defined in lib/glob/gmisc.c */ -extern int match_pattern_char __P((char *, char *)); -extern int umatchlen __P((char *, size_t)); - -#if defined (HANDLE_MULTIBYTE) -extern int match_pattern_wchar __P((wchar_t *, wchar_t *)); -extern int wmatchlen __P((wchar_t *, size_t)); -#endif - -#endif /* _EXTERNS_H_ */ diff --git a/general.c~ b/general.c~ deleted file mode 100644 index aa5ce7e25..000000000 --- a/general.c~ +++ /dev/null @@ -1,1166 +0,0 @@ -/* general.c -- Stuff that is used by all files. */ - -/* Copyright (C) 1987-2011 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 . -*/ - -#include "config.h" - -#include "bashtypes.h" -#ifndef _MINIX -# include -#endif -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "filecntl.h" -#include "bashansi.h" -#include -#include "chartypes.h" -#include - -#include "bashintl.h" - -#include "shell.h" -#include "test.h" - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int expand_aliases; -extern int interactive_comments; -extern int check_hashed_filenames; -extern int source_uses_path; -extern int source_searches_cwd; - -static char *bash_special_tilde_expansions __P((char *)); -static int unquoted_tilde_word __P((const char *)); -static void initialize_group_array __P((void)); - -/* A standard error message to use when getcwd() returns NULL. */ -const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories"); - -/* Do whatever is necessary to initialize `Posix mode'. */ -void -posix_initialize (on) - int on; -{ - /* Things that should be turned on when posix mode is enabled. */ - if (on != 0) - { - interactive_comments = source_uses_path = expand_aliases = 1; - source_searches_cwd = 0; - } - - /* Things that should be turned on when posix mode is disabled. */ - if (on == 0) - { - source_searches_cwd = 1; - expand_aliases = interactive_shell; - } -} - -/* **************************************************************** */ -/* */ -/* Functions to convert to and from and display non-standard types */ -/* */ -/* **************************************************************** */ - -#if defined (RLIMTYPE) -RLIMTYPE -string_to_rlimtype (s) - char *s; -{ - RLIMTYPE ret; - int neg; - - ret = 0; - neg = 0; - while (s && *s && whitespace (*s)) - s++; - if (s && (*s == '-' || *s == '+')) - { - neg = *s == '-'; - s++; - } - for ( ; s && *s && DIGIT (*s); s++) - ret = (ret * 10) + TODIGIT (*s); - return (neg ? -ret : ret); -} - -void -print_rlimtype (n, addnl) - RLIMTYPE n; - int addnl; -{ - char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p; - - p = s + sizeof(s); - *--p = '\0'; - - if (n < 0) - { - do - *--p = '0' - n % 10; - while ((n /= 10) != 0); - - *--p = '-'; - } - else - { - do - *--p = '0' + n % 10; - while ((n /= 10) != 0); - } - - printf ("%s%s", p, addnl ? "\n" : ""); -} -#endif /* RLIMTYPE */ - -/* **************************************************************** */ -/* */ -/* Input Validation Functions */ -/* */ -/* **************************************************************** */ - -/* Return non-zero if all of the characters in STRING are digits. */ -int -all_digits (string) - char *string; -{ - register char *s; - - for (s = string; *s; s++) - if (DIGIT (*s) == 0) - return (0); - - return (1); -} - -/* Return non-zero if the characters pointed to by STRING constitute a - valid number. Stuff the converted number into RESULT if RESULT is - not null. */ -int -legal_number (string, result) - const char *string; - intmax_t *result; -{ - intmax_t value; - char *ep; - - if (result) - *result = 0; - - if (string == 0) - return 0; - - errno = 0; - value = strtoimax (string, &ep, 10); - if (errno || ep == string) - return 0; /* errno is set on overflow or underflow */ - - /* Skip any trailing whitespace, since strtoimax does not. */ - while (whitespace (*ep)) - ep++; - - /* If *string is not '\0' but *ep is '\0' on return, the entire string - is valid. */ - if (*string && *ep == '\0') - { - if (result) - *result = value; - /* The SunOS4 implementation of strtol() will happily ignore - overflow conditions, so this cannot do overflow correctly - on those systems. */ - return 1; - } - - return (0); -} - -/* Return 1 if this token is a legal shell `identifier'; that is, it consists - solely of letters, digits, and underscores, and does not begin with a - digit. */ -int -legal_identifier (name) - char *name; -{ - register char *s; - unsigned char c; - - if (!name || !(c = *name) || (legal_variable_starter (c) == 0)) - return (0); - - for (s = name + 1; (c = *s) != 0; s++) - { - if (legal_variable_char (c) == 0) - return (0); - } - return (1); -} - -/* Make sure that WORD is a valid shell identifier, i.e. - does not contain a dollar sign, nor is quoted in any way. Nor - does it consist of all digits. If CHECK_WORD is non-zero, - the word is checked to ensure that it consists of only letters, - digits, and underscores. */ -int -check_identifier (word, check_word) - WORD_DESC *word; - int check_word; -{ - if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word)) - { - internal_error (_("`%s': not a valid identifier"), word->word); - return (0); - } - else if (check_word && legal_identifier (word->word) == 0) - { - internal_error (_("`%s': not a valid identifier"), word->word); - return (0); - } - else - return (1); -} - -/* Return 1 if STRING comprises a valid alias name. The shell accepts - essentially all characters except those which must be quoted to the - parser (which disqualifies them from alias expansion anyway) and `/'. */ -int -legal_alias_name (string, flags) - char *string; - int flags; -{ - register char *s; - - for (s = string; *s; s++) - if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/')) - return 0; - return 1; -} - -/* Returns non-zero if STRING is an assignment statement. The returned value - is the index of the `=' sign. */ -int -assignment (string, flags) - const char *string; - int flags; -{ - register unsigned char c; - register int newi, indx; - - c = string[indx = 0]; - -#if defined (ARRAY_VARS) - if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */ -#else - if (legal_variable_starter (c) == 0) -#endif - return (0); - - while (c = string[indx]) - { - /* The following is safe. Note that '=' at the start of a word - is not an assignment statement. */ - if (c == '=') - return (indx); - -#if defined (ARRAY_VARS) - if (c == '[') - { - newi = skipsubscript (string, indx, 0); - if (string[newi++] != ']') - return (0); - if (string[newi] == '+' && string[newi+1] == '=') - return (newi + 1); - return ((string[newi] == '=') ? newi : 0); - } -#endif /* ARRAY_VARS */ - - /* Check for `+=' */ - if (c == '+' && string[indx+1] == '=') - return (indx + 1); - - /* Variable names in assignment statements may contain only letters, - digits, and `_'. */ - if (legal_variable_char (c) == 0) - return (0); - - indx++; - } - return (0); -} - -/* **************************************************************** */ -/* */ -/* Functions to manage files and file descriptors */ -/* */ -/* **************************************************************** */ - -/* A function to unset no-delay mode on a file descriptor. Used in shell.c - to unset it on the fd passed as stdin. Should be called on stdin if - readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */ - -#if !defined (O_NDELAY) -# if defined (FNDELAY) -# define O_NDELAY FNDELAY -# endif -#endif /* O_NDELAY */ - -/* Make sure no-delay mode is not set on file descriptor FD. */ -int -sh_unset_nodelay_mode (fd) - int fd; -{ - int flags, bflags; - - if ((flags = fcntl (fd, F_GETFL, 0)) < 0) - return -1; - - bflags = 0; - - /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present - and O_NDELAY is defined. */ -#ifdef O_NONBLOCK - bflags |= O_NONBLOCK; -#endif - -#ifdef O_NDELAY - bflags |= O_NDELAY; -#endif - - if (flags & bflags) - { - flags &= ~bflags; - return (fcntl (fd, F_SETFL, flags)); - } - - return 0; -} - -/* Return 1 if file descriptor FD is valid; 0 otherwise. */ -int -sh_validfd (fd) - int fd; -{ - return (fcntl (fd, F_GETFD, 0) >= 0); -} - -int -fd_ispipe (fd) - int fd; -{ - errno = 0; - if (lseek ((fd), 0L, SEEK_CUR) < 0) - return (errno == ESPIPE); - return 0; -} - -/* There is a bug in the NeXT 2.1 rlogind that causes opens - of /dev/tty to fail. */ - -#if defined (__BEOS__) -/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it - into a no-op. This should probably go away in the future. */ -# undef O_NONBLOCK -# define O_NONBLOCK 0 -#endif /* __BEOS__ */ - -void -check_dev_tty () -{ - int tty_fd; - char *tty; - - tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK); - - if (tty_fd < 0) - { - tty = (char *)ttyname (fileno (stdin)); - if (tty == 0) - return; - tty_fd = open (tty, O_RDWR|O_NONBLOCK); - } - if (tty_fd >= 0) - close (tty_fd); -} - -/* Return 1 if PATH1 and PATH2 are the same file. This is kind of - expensive. If non-NULL STP1 and STP2 point to stat structures - corresponding to PATH1 and PATH2, respectively. */ -int -same_file (path1, path2, stp1, stp2) - char *path1, *path2; - struct stat *stp1, *stp2; -{ - struct stat st1, st2; - - if (stp1 == NULL) - { - if (stat (path1, &st1) != 0) - return (0); - stp1 = &st1; - } - - if (stp2 == NULL) - { - if (stat (path2, &st2) != 0) - return (0); - stp2 = &st2; - } - - return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino)); -} - -/* Move FD to a number close to the maximum number of file descriptors - allowed in the shell process, to avoid the user stepping on it with - redirection and causing us extra work. If CHECK_NEW is non-zero, - we check whether or not the file descriptors are in use before - duplicating FD onto them. MAXFD says where to start checking the - file descriptors. If it's less than 20, we get the maximum value - available from getdtablesize(2). */ -int -move_to_high_fd (fd, check_new, maxfd) - int fd, check_new, maxfd; -{ - int script_fd, nfds, ignore; - - if (maxfd < 20) - { - nfds = getdtablesize (); - if (nfds <= 0) - nfds = 20; - if (nfds > HIGH_FD_MAX) - nfds = HIGH_FD_MAX; /* reasonable maximum */ - } - else - nfds = maxfd; - - for (nfds--; check_new && nfds > 3; nfds--) - if (fcntl (nfds, F_GETFD, &ignore) == -1) - break; - - if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1) - { - if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */ - close (fd); - return (script_fd); - } - - /* OK, we didn't find one less than our artificial maximum; return the - original file descriptor. */ - return (fd); -} - -/* Return non-zero if the characters from SAMPLE are not all valid - characters to be found in the first line of a shell script. We - check up to the first newline, or SAMPLE_LEN, whichever comes first. - All of the characters must be printable or whitespace. */ - -int -check_binary_file (sample, sample_len) - char *sample; - int sample_len; -{ - register int i; - unsigned char c; - - for (i = 0; i < sample_len; i++) - { - c = sample[i]; - if (c == '\n') - return (0); - if (c == '\0') - return (1); - } - - return (0); -} - -/* **************************************************************** */ -/* */ -/* Functions to manipulate pipes */ -/* */ -/* **************************************************************** */ - -int -sh_openpipe (pv) - int *pv; -{ - int r; - - if ((r = pipe (pv)) < 0) - return r; - - pv[0] = move_to_high_fd (pv[0], 1, 64); - pv[1] = move_to_high_fd (pv[1], 1, 64); - - return 0; -} - -int -sh_closepipe (pv) - int *pv; -{ - if (pv[0] >= 0) - close (pv[0]); - - if (pv[1] >= 0) - close (pv[1]); - - pv[0] = pv[1] = -1; - return 0; -} - -/* **************************************************************** */ -/* */ -/* Functions to inspect pathnames */ -/* */ -/* **************************************************************** */ - -int -file_exists (fn) - char *fn; -{ - struct stat sb; - - return (stat (fn, &sb) == 0); -} - -int -file_isdir (fn) - char *fn; -{ - struct stat sb; - - return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode)); -} - -int -file_iswdir (fn) - char *fn; -{ - return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0); -} - -/* Return 1 if STRING is "." or "..", optionally followed by a directory - separator */ -int -path_dot_or_dotdot (string) - const char *string; -{ - if (string == 0 || *string == '\0' || *string != '.') - return (0); - - /* string[0] == '.' */ - if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2]))) - return (1); - - return (0); -} - -/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd' - to decide whether or not to look up a directory name in $CDPATH. */ -int -absolute_pathname (string) - const char *string; -{ - if (string == 0 || *string == '\0') - return (0); - - if (ABSPATH(string)) - return (1); - - if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */ - return (1); - - if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */ - return (1); - - return (0); -} - -/* Return 1 if STRING is an absolute program name; it is absolute if it - contains any slashes. This is used to decide whether or not to look - up through $PATH. */ -int -absolute_program (string) - const char *string; -{ - return ((char *)mbschr (string, '/') != (char *)NULL); -} - -/* **************************************************************** */ -/* */ -/* Functions to manipulate pathnames */ -/* */ -/* **************************************************************** */ - -/* Turn STRING (a pathname) into an absolute pathname, assuming that - DOT_PATH contains the symbolic location of `.'. This always - returns a new string, even if STRING was an absolute pathname to - begin with. */ -char * -make_absolute (string, dot_path) - char *string, *dot_path; -{ - char *result; - - if (dot_path == 0 || ABSPATH(string)) -#ifdef __CYGWIN__ - { - char pathbuf[PATH_MAX + 1]; - - cygwin_conv_to_full_posix_path (string, pathbuf); - result = savestring (pathbuf); - } -#else - result = savestring (string); -#endif - else - result = sh_makepath (dot_path, string, 0); - - return (result); -} - -/* Return the `basename' of the pathname in STRING (the stuff after the - last '/'). If STRING is `/', just return it. */ -char * -base_pathname (string) - char *string; -{ - char *p; - -#if 0 - if (absolute_pathname (string) == 0) - return (string); -#endif - - if (string[0] == '/' && string[1] == 0) - return (string); - - p = (char *)strrchr (string, '/'); - return (p ? ++p : string); -} - -/* Return the full pathname of FILE. Easy. Filenames that begin - with a '/' are returned as themselves. Other filenames have - the current working directory prepended. A new string is - returned in either case. */ -char * -full_pathname (file) - char *file; -{ - char *ret; - - file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file); - - if (ABSPATH(file)) - return (file); - - ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT)); - free (file); - - return (ret); -} - -/* A slightly related function. Get the prettiest name of this - directory possible. */ -static char tdir[PATH_MAX]; - -/* Return a pretty pathname. If the first part of the pathname is - the same as $HOME, then replace that with `~'. */ -char * -polite_directory_format (name) - char *name; -{ - char *home; - int l; - - home = get_string_value ("HOME"); - l = home ? strlen (home) : 0; - if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/')) - { - strncpy (tdir + 1, name + l, sizeof(tdir) - 2); - tdir[0] = '~'; - tdir[sizeof(tdir) - 1] = '\0'; - return (tdir); - } - else - return (name); -} - -/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to - keep any tilde prefix and PROMPT_DIRTRIM trailing directory components - and replace the intervening characters with `...' */ -char * -trim_pathname (name, maxlen) - char *name; - int maxlen; -{ - int nlen, ndirs; - intmax_t nskip; - char *nbeg, *nend, *ntail, *v; - - if (name == 0 || (nlen = strlen (name)) == 0) - return name; - nend = name + nlen; - - v = get_string_value ("PROMPT_DIRTRIM"); - if (v == 0 || *v == 0) - return name; - if (legal_number (v, &nskip) == 0 || nskip <= 0) - return name; - - /* Skip over tilde prefix */ - nbeg = name; - if (name[0] == '~') - for (nbeg = name; *nbeg; nbeg++) - if (*nbeg == '/') - { - nbeg++; - break; - } - if (*nbeg == 0) - return name; - - for (ndirs = 0, ntail = nbeg; *ntail; ntail++) - if (*ntail == '/') - ndirs++; - if (ndirs < nskip) - return name; - - for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--) - { - if (*ntail == '/') - nskip--; - if (nskip == 0) - break; - } - if (ntail == nbeg) - return name; - - /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */ - nlen = ntail - nbeg; - if (nlen <= 3) - return name; - - *nbeg++ = '.'; - *nbeg++ = '.'; - *nbeg++ = '.'; - - nlen = nend - ntail; - memcpy (nbeg, ntail, nlen); - nbeg[nlen] = '\0'; - - return name; -} - -/* Given a string containing units of information separated by colons, - return the next one pointed to by (P_INDEX), or NULL if there are no more. - Advance (P_INDEX) to the character after the colon. */ -char * -extract_colon_unit (string, p_index) - char *string; - int *p_index; -{ - int i, start, len; - char *value; - - if (string == 0) - return (string); - - len = strlen (string); - if (*p_index >= len) - return ((char *)NULL); - - i = *p_index; - - /* Each call to this routine leaves the index pointing at a colon if - there is more to the path. If I is > 0, then increment past the - `:'. If I is 0, then the path has a leading colon. Trailing colons - are handled OK by the `else' part of the if statement; an empty - string is returned in that case. */ - if (i && string[i] == ':') - i++; - - for (start = i; string[i] && string[i] != ':'; i++) - ; - - *p_index = i; - - if (i == start) - { - if (string[i]) - (*p_index)++; - /* Return "" in the case of a trailing `:'. */ - value = (char *)xmalloc (1); - value[0] = '\0'; - } - else - value = substring (string, start, i); - - return (value); -} - -/* **************************************************************** */ -/* */ -/* Tilde Initialization and Expansion */ -/* */ -/* **************************************************************** */ - -#if defined (PUSHD_AND_POPD) -extern char *get_dirstack_from_string __P((char *)); -#endif - -static char **bash_tilde_prefixes; -static char **bash_tilde_prefixes2; -static char **bash_tilde_suffixes; -static char **bash_tilde_suffixes2; - -/* If tilde_expand hasn't been able to expand the text, perhaps it - is a special shell expansion. This function is installed as the - tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+. - If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the - directory stack. */ -static char * -bash_special_tilde_expansions (text) - char *text; -{ - char *result; - - result = (char *)NULL; - - if (text[0] == '+' && text[1] == '\0') - result = get_string_value ("PWD"); - else if (text[0] == '-' && text[1] == '\0') - result = get_string_value ("OLDPWD"); -#if defined (PUSHD_AND_POPD) - else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1]))) - result = get_dirstack_from_string (text); -#endif - - return (result ? savestring (result) : (char *)NULL); -} - -/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as - well as handling special tilde prefixes; `:~" and `=~' are indications - that we should do tilde expansion. */ -void -tilde_initialize () -{ - static int times_called = 0; - - /* Tell the tilde expander that we want a crack first. */ - tilde_expansion_preexpansion_hook = bash_special_tilde_expansions; - - /* Tell the tilde expander about special strings which start a tilde - expansion, and the special strings that end one. Only do this once. - tilde_initialize () is called from within bashline_reinitialize (). */ - if (times_called++ == 0) - { - bash_tilde_prefixes = strvec_create (3); - bash_tilde_prefixes[0] = "=~"; - bash_tilde_prefixes[1] = ":~"; - bash_tilde_prefixes[2] = (char *)NULL; - - bash_tilde_prefixes2 = strvec_create (2); - bash_tilde_prefixes2[0] = ":~"; - bash_tilde_prefixes2[1] = (char *)NULL; - - tilde_additional_prefixes = bash_tilde_prefixes; - - bash_tilde_suffixes = strvec_create (3); - bash_tilde_suffixes[0] = ":"; - bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */ - bash_tilde_suffixes[2] = (char *)NULL; - - tilde_additional_suffixes = bash_tilde_suffixes; - - bash_tilde_suffixes2 = strvec_create (2); - bash_tilde_suffixes2[0] = ":"; - bash_tilde_suffixes2[1] = (char *)NULL; - } -} - -/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character - at the beginning of the word, followed by all of the characters preceding - the first unquoted slash in the word, or all the characters in the word - if there is no slash...If none of the characters in the tilde-prefix are - quoted, the characters in the tilde-prefix following the tilde shell be - treated as a possible login name. */ - -#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':') - -static int -unquoted_tilde_word (s) - const char *s; -{ - const char *r; - - for (r = s; TILDE_END(*r) == 0; r++) - { - switch (*r) - { - case '\\': - case '\'': - case '"': - return 0; - } - } - return 1; -} - -/* Find the end of the tilde-prefix starting at S, and return the tilde - prefix in newly-allocated memory. Return the length of the string in - *LENP. FLAGS tells whether or not we're in an assignment context -- - if so, `:' delimits the end of the tilde prefix as well. */ -char * -bash_tilde_find_word (s, flags, lenp) - const char *s; - int flags, *lenp; -{ - const char *r; - char *ret; - int l; - - for (r = s; *r && *r != '/'; r++) - { - /* Short-circuit immediately if we see a quote character. Even though - POSIX says that `the first unquoted slash' (or `:') terminates the - tilde-prefix, in practice, any quoted portion of the tilde prefix - will cause it to not be expanded. */ - if (*r == '\\' || *r == '\'' || *r == '"') - { - ret = savestring (s); - if (lenp) - *lenp = 0; - return ret; - } - else if (flags && *r == ':') - break; - } - l = r - s; - ret = xmalloc (l + 1); - strncpy (ret, s, l); - ret[l] = '\0'; - if (lenp) - *lenp = l; - return ret; -} - -/* Tilde-expand S by running it through the tilde expansion library. - ASSIGN_P is 1 if this is a variable assignment, so the alternate - tilde prefixes should be enabled (`=~' and `:~', see above). If - ASSIGN_P is 2, we are expanding the rhs of an assignment statement, - so `=~' is not valid. */ -char * -bash_tilde_expand (s, assign_p) - const char *s; - int assign_p; -{ - int old_immed, old_term, r; - char *ret; - - old_immed = interrupt_immediately; - old_term = terminate_immediately; - interrupt_immediately = terminate_immediately = 1; - - tilde_additional_prefixes = assign_p == 0 ? (char **)0 - : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes); - if (assign_p == 2) - tilde_additional_suffixes = bash_tilde_suffixes2; - - r = (*s == '~') ? unquoted_tilde_word (s) : 1; - ret = r ? tilde_expand (s) : savestring (s); - interrupt_immediately = old_immed; - terminate_immediately = old_term; - return (ret); -} - -/* **************************************************************** */ -/* */ -/* Functions to manipulate and search the group list */ -/* */ -/* **************************************************************** */ - -static int ngroups, maxgroups; - -/* The set of groups that this user is a member of. */ -static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; - -#if !defined (NOGROUP) -# define NOGROUP (gid_t) -1 -#endif - -static void -initialize_group_array () -{ - register int i; - - if (maxgroups == 0) - maxgroups = getmaxgroups (); - - ngroups = 0; - group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T)); - -#if defined (HAVE_GETGROUPS) - ngroups = getgroups (maxgroups, group_array); -#endif - - /* If getgroups returns nothing, or the OS does not support getgroups(), - make sure the groups array includes at least the current gid. */ - if (ngroups == 0) - { - group_array[0] = current_user.gid; - ngroups = 1; - } - - /* If the primary group is not in the groups array, add it as group_array[0] - and shuffle everything else up 1, if there's room. */ - for (i = 0; i < ngroups; i++) - if (current_user.gid == (gid_t)group_array[i]) - break; - if (i == ngroups && ngroups < maxgroups) - { - for (i = ngroups; i > 0; i--) - group_array[i] = group_array[i - 1]; - group_array[0] = current_user.gid; - ngroups++; - } - - /* If the primary group is not group_array[0], swap group_array[0] and - whatever the current group is. The vast majority of systems should - not need this; a notable exception is Linux. */ - if (group_array[0] != current_user.gid) - { - for (i = 0; i < ngroups; i++) - if (group_array[i] == current_user.gid) - break; - if (i < ngroups) - { - group_array[i] = group_array[0]; - group_array[0] = current_user.gid; - } - } -} - -/* Return non-zero if GID is one that we have in our groups list. */ -int -#if defined (__STDC__) || defined ( _MINIX) -group_member (gid_t gid) -#else -group_member (gid) - gid_t gid; -#endif /* !__STDC__ && !_MINIX */ -{ -#if defined (HAVE_GETGROUPS) - register int i; -#endif - - /* Short-circuit if possible, maybe saving a call to getgroups(). */ - if (gid == current_user.gid || gid == current_user.egid) - return (1); - -#if defined (HAVE_GETGROUPS) - if (ngroups == 0) - initialize_group_array (); - - /* In case of error, the user loses. */ - if (ngroups <= 0) - return (0); - - /* Search through the list looking for GID. */ - for (i = 0; i < ngroups; i++) - if (gid == (gid_t)group_array[i]) - return (1); -#endif - - return (0); -} - -char ** -get_group_list (ngp) - int *ngp; -{ - static char **group_vector = (char **)NULL; - register int i; - - if (group_vector) - { - if (ngp) - *ngp = ngroups; - return group_vector; - } - - if (ngroups == 0) - initialize_group_array (); - - if (ngroups <= 0) - { - if (ngp) - *ngp = 0; - return (char **)NULL; - } - - group_vector = strvec_create (ngroups); - for (i = 0; i < ngroups; i++) - group_vector[i] = itos (group_array[i]); - - if (ngp) - *ngp = ngroups; - return group_vector; -} - -int * -get_group_array (ngp) - int *ngp; -{ - int i; - static int *group_iarray = (int *)NULL; - - if (group_iarray) - { - if (ngp) - *ngp = ngroups; - return (group_iarray); - } - - if (ngroups == 0) - initialize_group_array (); - - if (ngroups <= 0) - { - if (ngp) - *ngp = 0; - return (int *)NULL; - } - - group_iarray = (int *)xmalloc (ngroups * sizeof (int)); - for (i = 0; i < ngroups; i++) - group_iarray[i] = (int)group_array[i]; - - if (ngp) - *ngp = ngroups; - return group_iarray; -} diff --git a/jobs.c~ b/jobs.c~ deleted file mode 100644 index 55d0cb821..000000000 --- a/jobs.c~ +++ /dev/null @@ -1,4312 +0,0 @@ -/* jobs.c - functions that make children, remember them, and handle their termination. */ - -/* This file works with both POSIX and BSD systems. It implements job - control. */ - -/* Copyright (C) 1989-2012 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 . -*/ - -#include "config.h" - -#include "bashtypes.h" -#include "trap.h" -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixtime.h" - -#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) -# include -#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ - -#if defined (HAVE_SYS_FILE_H) -# include -#endif - -#include "filecntl.h" -#include -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -/* Need to include this up here for *_TTY_DRIVER definitions. */ -#include "shtty.h" - -/* Define this if your output is getting swallowed. It's a no-op on - machines with the termio or termios tty drivers. */ -/* #define DRAIN_OUTPUT */ - -/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ -#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) -# include -#endif /* hpux && !TERMIOS_TTY_DRIVER */ - -#include "bashansi.h" -#include "bashintl.h" -#include "shell.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "flags.h" - -#include "builtins/builtext.h" -#include "builtins/common.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#if !defined (HAVE_KILLPG) -extern int killpg __P((pid_t, int)); -#endif - -#define DEFAULT_CHILD_MAX 32 -#if !defined (DEBUG) -#define MAX_JOBS_IN_ARRAY 4096 /* production */ -#else -#define MAX_JOBS_IN_ARRAY 128 /* testing */ -#endif - -/* Flag values for second argument to delete_job */ -#define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */ -#define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */ - -/* Take care of system dependencies that must be handled when waiting for - children. The arguments to the WAITPID macro match those to the Posix.1 - waitpid() function. */ - -#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION) -# define WAITPID(pid, statusp, options) \ - wait3 ((union wait *)statusp, options, (struct rusage *)0) -#else -# if defined (_POSIX_VERSION) || defined (HAVE_WAITPID) -# define WAITPID(pid, statusp, options) \ - waitpid ((pid_t)pid, statusp, options) -# else -# if defined (HAVE_WAIT3) -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (struct rusage *)0) -# else -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (int *)0) -# endif /* HAVE_WAIT3 */ -# endif /* !_POSIX_VERSION && !HAVE_WAITPID*/ -#endif /* !(Ultrix && mips && _POSIX_VERSION) */ - -/* getpgrp () varies between systems. Even systems that claim to be - Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ -#if defined (GETPGRP_VOID) -# define getpgid(p) getpgrp () -#else -# define getpgid(p) getpgrp (p) -#endif /* !GETPGRP_VOID */ - -/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the - handler for SIGCHLD. */ -#if defined (MUST_REINSTALL_SIGHANDLERS) -# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler) -#else -# define REINSTALL_SIGCHLD_HANDLER -#endif /* !MUST_REINSTALL_SIGHANDLERS */ - -/* Some systems let waitpid(2) tell callers about stopped children. */ -#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN) -# undef WCONTINUED -# define WCONTINUED 0 -#endif -#if !defined (WIFCONTINUED) -# define WIFCONTINUED(s) (0) -#endif - -/* The number of additional slots to allocate when we run out. */ -#define JOB_SLOTS 8 - -typedef int sh_job_map_func_t __P((JOB *, int, int, int)); - -/* Variables used here but defined in other files. */ -extern int subshell_environment, line_number; -extern int posixly_correct, shell_level; -extern int last_command_exit_value, last_command_exit_signal; -extern int loop_level, breaking; -extern int executing_list; -extern int sourcelevel; -extern int running_trap; -extern sh_builtin_func_t *this_shell_builtin; -extern char *shell_name, *this_command_name; -extern sigset_t top_level_mask; -extern procenv_t wait_intr_buf; -extern int wait_signal_received; -extern WORD_LIST *subst_assign_varlist; - -static struct jobstats zerojs = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 }; -struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 }; - -struct bgpids bgpids = { 0, 0, 0 }; - -/* The array of known jobs. */ -JOB **jobs = (JOB **)NULL; - -#if 0 -/* The number of slots currently allocated to JOBS. */ -int job_slots = 0; -#endif - -/* The controlling tty for this shell. */ -int shell_tty = -1; - -/* The shell's process group. */ -pid_t shell_pgrp = NO_PID; - -/* The terminal's process group. */ -pid_t terminal_pgrp = NO_PID; - -/* The process group of the shell's parent. */ -pid_t original_pgrp = NO_PID; - -/* The process group of the pipeline currently being made. */ -pid_t pipeline_pgrp = (pid_t)0; - -#if defined (PGRP_PIPE) -/* Pipes which each shell uses to communicate with the process group leader - until all of the processes in a pipeline have been started. Then the - process leader is allowed to continue. */ -int pgrp_pipe[2] = { -1, -1 }; -#endif - -#if 0 -/* The job which is current; i.e. the one that `%+' stands for. */ -int current_job = NO_JOB; - -/* The previous job; i.e. the one that `%-' stands for. */ -int previous_job = NO_JOB; -#endif - -/* Last child made by the shell. */ -pid_t last_made_pid = NO_PID; - -/* Pid of the last asynchronous child. */ -pid_t last_asynchronous_pid = NO_PID; - -/* The pipeline currently being built. */ -PROCESS *the_pipeline = (PROCESS *)NULL; - -/* If this is non-zero, do job control. */ -int job_control = 1; - -/* Call this when you start making children. */ -int already_making_children = 0; - -/* If this is non-zero, $LINES and $COLUMNS are reset after every process - exits from get_tty_state(). */ -int check_window_size = CHECKWINSIZE_DEFAULT; - -/* Functions local to this file. */ - -static sighandler wait_sigint_handler __P((int)); -static sighandler sigchld_handler __P((int)); -static sighandler sigcont_sighandler __P((int)); -static sighandler sigstop_sighandler __P((int)); - -static int waitchld __P((pid_t, int)); - -static PROCESS *find_pipeline __P((pid_t, int, int *)); -static PROCESS *find_process __P((pid_t, int, int *)); - -static char *current_working_directory __P((void)); -static char *job_working_directory __P((void)); -static char *j_strsignal __P((int)); -static char *printable_job_status __P((int, PROCESS *, int)); - -static PROCESS *find_last_proc __P((int, int)); -static pid_t find_last_pid __P((int, int)); - -static int set_new_line_discipline __P((int)); -static int map_over_jobs __P((sh_job_map_func_t *, int, int)); -static int job_last_stopped __P((int)); -static int job_last_running __P((int)); -static int most_recent_job_in_state __P((int, JOB_STATE)); -static int find_job __P((pid_t, int, PROCESS **)); -static int print_job __P((JOB *, int, int, int)); -static int process_exit_status __P((WAIT)); -static int process_exit_signal __P((WAIT)); -static int set_job_status_and_cleanup __P((int)); - -static WAIT job_signal_status __P((int)); -static WAIT raw_job_exit_status __P((int)); - -static void notify_of_job_status __P((void)); -static void reset_job_indices __P((void)); -static void cleanup_dead_jobs __P((void)); -static int processes_in_job __P((int)); -static void realloc_jobs_list __P((void)); -static int compact_jobs_list __P((int)); -static int discard_pipeline __P((PROCESS *)); -static void add_process __P((char *, pid_t)); -static void print_pipeline __P((PROCESS *, int, int, FILE *)); -static void pretty_print_job __P((int, int, FILE *)); -static void set_current_job __P((int)); -static void reset_current __P((void)); -static void set_job_running __P((int)); -static void setjstatus __P((int)); -static int maybe_give_terminal_to __P((pid_t, pid_t, int)); -static void mark_all_jobs_as_dead __P((void)); -static void mark_dead_jobs_as_notified __P((int)); -static void restore_sigint_handler __P((void)); -#if defined (PGRP_PIPE) -static void pipe_read __P((int *)); -#endif - -static struct pidstat *bgp_alloc __P((pid_t, int)); -static struct pidstat *bgp_add __P((pid_t, int)); -static int bgp_delete __P((pid_t)); -static void bgp_clear __P((void)); -static int bgp_search __P((pid_t)); -static void bgp_prune __P((void)); - -#if defined (ARRAY_VARS) -static int *pstatuses; /* list of pipeline statuses */ -static int statsize; -#endif - -/* Used to synchronize between wait_for and other functions and the SIGCHLD - signal handler. */ -static int sigchld; -static int queue_sigchld; - -#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++ - -#define UNQUEUE_SIGCHLD(os) \ - do { \ - queue_sigchld--; \ - if (queue_sigchld == 0 && os != sigchld) \ - waitchld (-1, 0); \ - } while (0) - -static SigHandler *old_tstp, *old_ttou, *old_ttin; -static SigHandler *old_cont = (SigHandler *)SIG_DFL; - -/* A place to temporarily save the current pipeline. */ -static PROCESS *saved_pipeline; -static int saved_already_making_children; - -/* Set this to non-zero whenever you don't want the jobs list to change at - all: no jobs deleted and no status change notifications. This is used, - for example, when executing SIGCHLD traps, which may run arbitrary - commands. */ -static int jobs_list_frozen; - -static char retcode_name_buffer[64]; - -/* flags to detect pid wraparound */ -static pid_t first_pid = NO_PID; -static int pid_wrap = -1; - -#if !defined (_POSIX_VERSION) - -/* These are definitions to map POSIX 1003.1 functions onto existing BSD - library functions and system calls. */ -#define setpgid(pid, pgrp) setpgrp (pid, pgrp) -#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) - -pid_t -tcgetpgrp (fd) - int fd; -{ - pid_t pgrp; - - /* ioctl will handle setting errno correctly. */ - if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) - return (-1); - return (pgrp); -} - -#endif /* !_POSIX_VERSION */ - -/* Initialize the global job stats structure and other bookkeeping variables */ -void -init_job_stats () -{ - js = zerojs; - first_pid = NO_PID; - pid_wrap = -1; -} - -/* Return the working directory for the current process. Unlike - job_working_directory, this does not call malloc (), nor do any - of the functions it calls. This is so that it can safely be called - from a signal handler. */ -static char * -current_working_directory () -{ - char *dir; - static char d[PATH_MAX]; - - dir = get_string_value ("PWD"); - - if (dir == 0 && the_current_working_directory && no_symbolic_links) - dir = the_current_working_directory; - - if (dir == 0) - { - dir = getcwd (d, sizeof(d)); - if (dir) - dir = d; - } - - return (dir == 0) ? "" : dir; -} - -/* Return the working directory for the current process. */ -static char * -job_working_directory () -{ - char *dir; - - dir = get_string_value ("PWD"); - if (dir) - return (savestring (dir)); - - dir = get_working_directory ("job-working-directory"); - if (dir) - return (dir); - - return (savestring ("")); -} - -void -making_children () -{ - if (already_making_children) - return; - - already_making_children = 1; - start_pipeline (); -} - -void -stop_making_children () -{ - already_making_children = 0; -} - -void -cleanup_the_pipeline () -{ - PROCESS *disposer; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - disposer = the_pipeline; - the_pipeline = (PROCESS *)NULL; - UNBLOCK_CHILD (oset); - - if (disposer) - discard_pipeline (disposer); -} - -void -save_pipeline (clear) - int clear; -{ - saved_pipeline = the_pipeline; - if (clear) - the_pipeline = (PROCESS *)NULL; - saved_already_making_children = already_making_children; -} - -void -restore_pipeline (discard) - int discard; -{ - PROCESS *old_pipeline; - - old_pipeline = the_pipeline; - the_pipeline = saved_pipeline; - already_making_children = saved_already_making_children; - if (discard && old_pipeline) - discard_pipeline (old_pipeline); -} - -/* Start building a pipeline. */ -void -start_pipeline () -{ - if (the_pipeline) - { - cleanup_the_pipeline (); - pipeline_pgrp = 0; -#if defined (PGRP_PIPE) - sh_closepipe (pgrp_pipe); -#endif - } - -#if defined (PGRP_PIPE) - if (job_control) - { - if (pipe (pgrp_pipe) == -1) - sys_error (_("start_pipeline: pgrp pipe")); - } -#endif -} - -/* Stop building a pipeline. Install the process list in the job array. - This returns the index of the newly installed job. - DEFERRED is a command structure to be executed upon satisfactory - execution exit of this pipeline. */ -int -stop_pipeline (async, deferred) - int async; - COMMAND *deferred; -{ - register int i, j; - JOB *newjob; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - -#if defined (PGRP_PIPE) - /* The parent closes the process group synchronization pipe. */ - sh_closepipe (pgrp_pipe); -#endif - - cleanup_dead_jobs (); - - if (js.j_jobslots == 0) - { - js.j_jobslots = JOB_SLOTS; - jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *)); - - /* Now blank out these new entries. */ - for (i = 0; i < js.j_jobslots; i++) - jobs[i] = (JOB *)NULL; - - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - - /* Scan from the last slot backward, looking for the next free one. */ - /* XXX - revisit this interactive assumption */ - /* XXX - this way for now */ - if (interactive) - { - for (i = js.j_jobslots; i; i--) - if (jobs[i - 1]) - break; - } - else - { -#if 0 - /* This wraps around, but makes it inconvenient to extend the array */ - for (i = js.j_lastj+1; i != js.j_lastj; i++) - { - if (i >= js.j_jobslots) - i = 0; - if (jobs[i] == 0) - break; - } - if (i == js.j_lastj) - i = js.j_jobslots; -#else - /* This doesn't wrap around yet. */ - for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++) - if (jobs[i] == 0) - break; -#endif - } - - /* Do we need more room? */ - - /* First try compaction */ - if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY) - i = compact_jobs_list (0); - - /* If we can't compact, reallocate */ - if (i == js.j_jobslots) - { - js.j_jobslots += JOB_SLOTS; - jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *))); - - for (j = i; j < js.j_jobslots; j++) - jobs[j] = (JOB *)NULL; - } - - /* Add the current pipeline to the job list. */ - if (the_pipeline) - { - register PROCESS *p; - int any_running, any_stopped, n; - - newjob = (JOB *)xmalloc (sizeof (JOB)); - - for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next) - ; - p->next = (PROCESS *)NULL; - newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); - for (p = newjob->pipe; p->next; p = p->next) - ; - p->next = newjob->pipe; - - the_pipeline = (PROCESS *)NULL; - newjob->pgrp = pipeline_pgrp; - pipeline_pgrp = 0; - - newjob->flags = 0; - - /* Flag to see if in another pgrp. */ - if (job_control) - newjob->flags |= J_JOBCONTROL; - - /* Set the state of this pipeline. */ - p = newjob->pipe; - any_running = any_stopped = 0; - do - { - any_running |= PRUNNING (p); - any_stopped |= PSTOPPED (p); - p = p->next; - } - while (p != newjob->pipe); - - newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); - newjob->wd = job_working_directory (); - newjob->deferred = deferred; - - newjob->j_cleanup = (sh_vptrfunc_t *)NULL; - newjob->cleanarg = (PTR_T) NULL; - - jobs[i] = newjob; - if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) - setjstatus (i); - if (newjob->state == JDEAD) - { - js.c_reaped += n; /* wouldn't have been done since this was not part of a job */ - js.j_ndead++; - } - js.c_injobs += n; - - js.j_lastj = i; - js.j_njobs++; - } - else - newjob = (JOB *)NULL; - - if (newjob) - js.j_lastmade = newjob; - - if (async) - { - if (newjob) - { - newjob->flags &= ~J_FOREGROUND; - newjob->flags |= J_ASYNC; - js.j_lastasync = newjob; - } - reset_current (); - } - else - { - if (newjob) - { - newjob->flags |= J_FOREGROUND; - /* - * !!!!! NOTE !!!!! (chet@ins.cwru.edu) - * - * The currently-accepted job control wisdom says to set the - * terminal's process group n+1 times in an n-step pipeline: - * once in the parent and once in each child. This is where - * the parent gives it away. - * - * Don't give the terminal away if this shell is an asynchronous - * subshell. - * - */ - if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0) - maybe_give_terminal_to (shell_pgrp, newjob->pgrp, 0); - } - } - - stop_making_children (); - UNBLOCK_CHILD (oset); - return (newjob ? i : js.j_current); -} - -/* Functions to manage the list of exited background pids whose status has - been saved. */ - -static struct pidstat * -bgp_alloc (pid, status) - pid_t pid; - int status; -{ - struct pidstat *ps; - - ps = (struct pidstat *)xmalloc (sizeof (struct pidstat)); - ps->pid = pid; - ps->status = status; - ps->next = (struct pidstat *)0; - return ps; -} - -static struct pidstat * -bgp_add (pid, status) - pid_t pid; - int status; -{ - struct pidstat *ps; - - ps = bgp_alloc (pid, status); - - if (bgpids.list == 0) - { - bgpids.list = bgpids.end = ps; - bgpids.npid = 0; /* just to make sure */ - } - else - { - bgpids.end->next = ps; - bgpids.end = ps; - } - bgpids.npid++; - - if (bgpids.npid > js.c_childmax) - bgp_prune (); - - return ps; -} - -static int -bgp_delete (pid) - pid_t pid; -{ - struct pidstat *prev, *p; - - for (prev = p = bgpids.list; p; prev = p, p = p->next) - if (p->pid == pid) - { - prev->next = p->next; /* remove from list */ - break; - } - - if (p == 0) - return 0; /* not found */ - -#if defined (DEBUG) - itrace("bgp_delete: deleting %d", pid); -#endif - - /* Housekeeping in the border cases. */ - if (p == bgpids.list) - bgpids.list = bgpids.list->next; - else if (p == bgpids.end) - bgpids.end = prev; - - bgpids.npid--; - if (bgpids.npid == 0) - bgpids.list = bgpids.end = 0; - else if (bgpids.npid == 1) - bgpids.end = bgpids.list; /* just to make sure */ - - free (p); - return 1; -} - -/* Clear out the list of saved statuses */ -static void -bgp_clear () -{ - struct pidstat *ps, *p; - - for (ps = bgpids.list; ps; ) - { - p = ps; - ps = ps->next; - free (p); - } - bgpids.list = bgpids.end = 0; - bgpids.npid = 0; -} - -/* Search for PID in the list of saved background pids; return its status if - found. If not found, return -1. */ -static int -bgp_search (pid) - pid_t pid; -{ - struct pidstat *ps; - - for (ps = bgpids.list ; ps; ps = ps->next) - if (ps->pid == pid) - return ps->status; - return -1; -} - -static void -bgp_prune () -{ - struct pidstat *ps; - - while (bgpids.npid > js.c_childmax) - { - ps = bgpids.list; - bgpids.list = bgpids.list->next; - free (ps); - bgpids.npid--; - } -} - -/* Reset the values of js.j_lastj and js.j_firstj after one or both have - been deleted. The caller should check whether js.j_njobs is 0 before - calling this. This wraps around, but the rest of the code does not. At - this point, it should not matter. */ -static void -reset_job_indices () -{ - int old; - - if (jobs[js.j_firstj] == 0) - { - old = js.j_firstj++; - if (old >= js.j_jobslots) - old = js.j_jobslots - 1; - while (js.j_firstj != old) - { - if (js.j_firstj >= js.j_jobslots) - js.j_firstj = 0; - if (jobs[js.j_firstj] || js.j_firstj == old) /* needed if old == 0 */ - break; - js.j_firstj++; - } - if (js.j_firstj == old) - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - if (jobs[js.j_lastj] == 0) - { - old = js.j_lastj--; - if (old < 0) - old = 0; - while (js.j_lastj != old) - { - if (js.j_lastj < 0) - js.j_lastj = js.j_jobslots - 1; - if (jobs[js.j_lastj] || js.j_lastj == old) /* needed if old == js.j_jobslots */ - break; - js.j_lastj--; - } - if (js.j_lastj == old) - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } -} - -/* Delete all DEAD jobs that the user had received notification about. */ -static void -cleanup_dead_jobs () -{ - register int i; - int os; - - if (js.j_jobslots == 0 || jobs_list_frozen) - return; - - QUEUE_SIGCHLD(os); - - /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - - if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) - delete_job (i, 0); - } - -#if defined (COPROCESS_SUPPORT) - coproc_reap (); -#endif - - UNQUEUE_SIGCHLD(os); -} - -static int -processes_in_job (job) - int job; -{ - int nproc; - register PROCESS *p; - - nproc = 0; - p = jobs[job]->pipe; - do - { - p = p->next; - nproc++; - } - while (p != jobs[job]->pipe); - - return nproc; -} - -static void -delete_old_job (pid) - pid_t pid; -{ - PROCESS *p; - int job; - - job = find_job (pid, 0, &p); - if (job != NO_JOB) - { -#ifdef DEBUG - itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state); -#endif - if (JOBSTATE (job) == JDEAD) - delete_job (job, DEL_NOBGPID); - else - { - internal_warning (_("forked pid %d appears in running job %d"), pid, job); - if (p) - p->pid = 0; - } - } -} - -/* Reallocate and compress the jobs list. This returns with a jobs array - whose size is a multiple of JOB_SLOTS and can hold the current number of - jobs. Heuristics are used to minimize the number of new reallocs. */ -static void -realloc_jobs_list () -{ - sigset_t set, oset; - int nsize, i, j, ncur, nprev; - JOB **nlist; - - ncur = nprev = NO_JOB; - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; - i = js.j_njobs % JOB_SLOTS; - if (i == 0 || i > (JOB_SLOTS >> 1)) - nsize += JOB_SLOTS; - - BLOCK_CHILD (set, oset); - nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); - - js.c_reaped = js.j_ndead = 0; - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) - { - if (i == js.j_current) - ncur = j; - if (i == js.j_previous) - nprev = j; - nlist[j++] = jobs[i]; - if (jobs[i]->state == JDEAD) - { - js.j_ndead++; - js.c_reaped += processes_in_job (i); - } - } - -#if defined (DEBUG) - itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); - itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); - itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, j); - itrace ("realloc_jobs_list: js.j_ndead %d js.c_reaped %d", js.j_ndead, js.c_reaped); -#endif - - js.j_firstj = 0; - js.j_lastj = (j > 0) ? j - 1 : 0; - js.j_njobs = j; - js.j_jobslots = nsize; - - /* Zero out remaining slots in new jobs list */ - for ( ; j < nsize; j++) - nlist[j] = (JOB *)NULL; - - if (jobs != nlist) - { - free (jobs); - jobs = nlist; - } - - if (ncur != NO_JOB) - js.j_current = ncur; - if (nprev != NO_JOB) - js.j_previous = nprev; - - /* Need to reset these */ - if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj) - reset_current (); - -#ifdef DEBUG - itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous); -#endif - - UNBLOCK_CHILD (oset); -} - -/* Compact the jobs list by removing dead jobs. Assumed that we have filled - the jobs array to some predefined maximum. Called when the shell is not - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then - the list needs to be reallocated. The jobs array may be in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ -static int -compact_jobs_list (flags) - int flags; -{ - if (js.j_jobslots == 0 || jobs_list_frozen) - return js.j_jobslots; - - reap_dead_jobs (); - realloc_jobs_list (); - -#ifdef DEBUG - itrace("compact_jobs_list: returning %d", (js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); -#endif - - return ((js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); -} - -/* Delete the job at INDEX from the job list. Must be called - with SIGCHLD blocked. */ -void -delete_job (job_index, dflags) - int job_index, dflags; -{ - register JOB *temp; - PROCESS *proc; - int ndel; - - if (js.j_jobslots == 0 || jobs_list_frozen) - return; - - if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index)) - internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); - temp = jobs[job_index]; - if (temp == 0) - return; - - if ((dflags & DEL_NOBGPID) == 0) - { - proc = find_last_proc (job_index, 0); - /* Could do this just for J_ASYNC jobs, but we save all. */ - if (proc) - bgp_add (proc->pid, process_exit_status (proc->status)); - } - - jobs[job_index] = (JOB *)NULL; - if (temp == js.j_lastmade) - js.j_lastmade = 0; - else if (temp == js.j_lastasync) - js.j_lastasync = 0; - - free (temp->wd); - ndel = discard_pipeline (temp->pipe); - - js.c_injobs -= ndel; - if (temp->state == JDEAD) - { - js.c_reaped -= ndel; - js.j_ndead--; - if (js.c_reaped < 0) - { -#ifdef DEBUG - itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead); -#endif - js.c_reaped = 0; - } - } - - if (temp->deferred) - dispose_command (temp->deferred); - - free (temp); - - js.j_njobs--; - if (js.j_njobs == 0) - js.j_firstj = js.j_lastj = 0; - else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0) - reset_job_indices (); - - if (job_index == js.j_current || job_index == js.j_previous) - reset_current (); -} - -/* Must be called with SIGCHLD blocked. */ -void -nohup_job (job_index) - int job_index; -{ - register JOB *temp; - - if (js.j_jobslots == 0) - return; - - if (temp = jobs[job_index]) - temp->flags |= J_NOHUP; -} - -/* Get rid of the data structure associated with a process chain. */ -static int -discard_pipeline (chain) - register PROCESS *chain; -{ - register PROCESS *this, *next; - int n; - - this = chain; - n = 0; - do - { - next = this->next; - FREE (this->command); - free (this); - n++; - this = next; - } - while (this != chain); - - return n; -} - -/* Add this process to the chain being built in the_pipeline. - NAME is the command string that will be exec'ed later. - PID is the process id of the child. */ -static void -add_process (name, pid) - char *name; - pid_t pid; -{ - PROCESS *t, *p; - -#if defined (RECYCLES_PIDS) - int j; - p = find_process (pid, 0, &j); - if (p) - { -# ifdef DEBUG - if (j == NO_JOB) - internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command); -# endif - if (PALIVE (p)) - internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command); - p->running = PS_RECYCLED; /* mark as recycled */ - } -#endif - - t = (PROCESS *)xmalloc (sizeof (PROCESS)); - t->next = the_pipeline; - t->pid = pid; - WSTATUS (t->status) = 0; - t->running = PS_RUNNING; - t->command = name; - the_pipeline = t; - - if (t->next == 0) - t->next = t; - else - { - p = t->next; - while (p->next != t->next) - p = p->next; - p->next = t; - } -} - -/* Create a (dummy) PROCESS with NAME, PID, and STATUS, and make it the last - process in jobs[JID]->pipe. Used by the lastpipe code. */ -void -append_process (name, pid, status, jid) - char *name; - pid_t pid; - int status; - int jid; -{ - PROCESS *t, *p; - - t = (PROCESS *)xmalloc (sizeof (PROCESS)); - t->next = (PROCESS *)NULL; - t->pid = pid; - /* set process exit status using offset discovered by configure */ - t->status = (status & 0xff) << WEXITSTATUS_OFFSET; - t->running = PS_DONE; - t->command = name; - - js.c_reaped++; /* XXX */ - - for (p = jobs[jid]->pipe; p->next != jobs[jid]->pipe; p = p->next) - ; - p->next = t; - t->next = jobs[jid]->pipe; -} - -#if 0 -/* Take the last job and make it the first job. Must be called with - SIGCHLD blocked. */ -int -rotate_the_pipeline () -{ - PROCESS *p; - - if (the_pipeline->next == the_pipeline) - return; - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - the_pipeline = p; -} - -/* Reverse the order of the processes in the_pipeline. Must be called with - SIGCHLD blocked. */ -int -reverse_the_pipeline () -{ - PROCESS *p, *n; - - if (the_pipeline->next == the_pipeline) - return; - - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - p->next = (PROCESS *)NULL; - - n = REVERSE_LIST (the_pipeline, PROCESS *); - - the_pipeline = n; - for (p = the_pipeline; p->next; p = p->next) - ; - p->next = the_pipeline; -} -#endif - -/* Map FUNC over the list of jobs. If FUNC returns non-zero, - then it is time to stop mapping, and that is the return value - for map_over_jobs. FUNC is called with a JOB, arg1, arg2, - and INDEX. */ -static int -map_over_jobs (func, arg1, arg2) - sh_job_map_func_t *func; - int arg1, arg2; -{ - register int i; - int result; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return 0; - - BLOCK_CHILD (set, oset); - - /* XXX could use js.j_firstj here */ - for (i = result = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i]) - { - result = (*func)(jobs[i], arg1, arg2, i); - if (result) - break; - } - } - - UNBLOCK_CHILD (oset); - - return (result); -} - -/* Cause all the jobs in the current pipeline to exit. */ -void -terminate_current_pipeline () -{ - if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) - { - killpg (pipeline_pgrp, SIGTERM); - killpg (pipeline_pgrp, SIGCONT); - } -} - -/* Cause all stopped jobs to exit. */ -void -terminate_stopped_jobs () -{ - register int i; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && STOPPED (i)) - { - killpg (jobs[i]->pgrp, SIGTERM); - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -/* Cause all jobs, running or stopped, to receive a hangup signal. If - a job is marked J_NOHUP, don't send the SIGHUP. */ -void -hangup_all_jobs () -{ - register int i; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i]) - { - if (jobs[i]->flags & J_NOHUP) - continue; - killpg (jobs[i]->pgrp, SIGHUP); - if (STOPPED (i)) - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -void -kill_current_pipeline () -{ - stop_making_children (); - start_pipeline (); -} - -/* Return the pipeline that PID belongs to. Note that the pipeline - doesn't have to belong to a job. Must be called with SIGCHLD blocked. - If JOBP is non-null, return the index of the job containing PID. */ -static PROCESS * -find_pipeline (pid, alive_only, jobp) - pid_t pid; - int alive_only; - int *jobp; /* index into jobs list or NO_JOB */ -{ - int job; - PROCESS *p; - - /* See if this process is in the pipeline that we are building. */ - if (jobp) - *jobp = NO_JOB; - if (the_pipeline) - { - p = the_pipeline; - do - { - /* Return it if we found it. Don't ever return a recycled pid. */ - if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) - return (p); - - p = p->next; - } - while (p != the_pipeline); - } - - job = find_job (pid, alive_only, &p); - if (jobp) - *jobp = job; - return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe; -} - -/* Return the PROCESS * describing PID. If JOBP is non-null return the index - into the jobs array of the job containing PID. Must be called with - SIGCHLD blocked. */ -static PROCESS * -find_process (pid, alive_only, jobp) - pid_t pid; - int alive_only; - int *jobp; /* index into jobs list or NO_JOB */ -{ - PROCESS *p; - - p = find_pipeline (pid, alive_only, jobp); - while (p && p->pid != pid) - p = p->next; - return p; -} - -/* Return the job index that PID belongs to, or NO_JOB if it doesn't - belong to any job. Must be called with SIGCHLD blocked. */ -static int -find_job (pid, alive_only, procp) - pid_t pid; - int alive_only; - PROCESS **procp; -{ - register int i; - PROCESS *p; - - /* XXX could use js.j_firstj here, and should check js.j_lastj */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i]) - { - p = jobs[i]->pipe; - - do - { - if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) - { - if (procp) - *procp = p; - return (i); - } - - p = p->next; - } - while (p != jobs[i]->pipe); - } - } - - return (NO_JOB); -} - -/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as - required by find_job. */ -int -get_job_by_pid (pid, block) - pid_t pid; - int block; -{ - int job; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0, NULL); - - if (block) - UNBLOCK_CHILD (oset); - - return job; -} - -/* Print descriptive information about the job with leader pid PID. */ -void -describe_pid (pid) - pid_t pid; -{ - int job; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0, NULL); - - if (job != NO_JOB) - fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid); - else - programming_error (_("describe_pid: %ld: no such pid"), (long)pid); - - UNBLOCK_CHILD (oset); -} - -static char * -j_strsignal (s) - int s; -{ - char *x; - - x = strsignal (s); - if (x == 0) - { - x = retcode_name_buffer; - sprintf (x, _("Signal %d"), s); - } - return x; -} - -static char * -printable_job_status (j, p, format) - int j; - PROCESS *p; - int format; -{ - static char *temp; - int es; - - temp = _("Done"); - - if (STOPPED (j) && format == 0) - { - if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) - temp = _("Stopped"); - else - { - temp = retcode_name_buffer; - sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status))); - } - } - else if (RUNNING (j)) - temp = _("Running"); - else - { - if (WIFSTOPPED (p->status)) - temp = j_strsignal (WSTOPSIG (p->status)); - else if (WIFSIGNALED (p->status)) - temp = j_strsignal (WTERMSIG (p->status)); - else if (WIFEXITED (p->status)) - { - temp = retcode_name_buffer; - es = WEXITSTATUS (p->status); - if (es == 0) - strcpy (temp, _("Done")); - else if (posixly_correct) - sprintf (temp, _("Done(%d)"), es); - else - sprintf (temp, _("Exit %d"), es); - } - else - temp = _("Unknown status"); - } - - return temp; -} - -/* This is the way to print out information on a job if you - know the index. FORMAT is: - - JLIST_NORMAL) [1]+ Running emacs - JLIST_LONG ) [1]+ 2378 Running emacs - -1 ) [1]+ 2378 emacs - - JLIST_NORMAL) [1]+ Stopped ls | more - JLIST_LONG ) [1]+ 2369 Stopped ls - 2367 | more - JLIST_PID_ONLY) - Just list the pid of the process group leader (really - the process group). - JLIST_CHANGED_ONLY) - Use format JLIST_NORMAL, but list only jobs about which - the user has not been notified. */ - -/* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into - the JOBS array corresponding to this pipeline. FORMAT is as described - above. Must be called with SIGCHLD blocked. - - If you're printing a pipeline that's not in the jobs array, like the - current pipeline as it's being created, pass -1 for JOB_INDEX */ -static void -print_pipeline (p, job_index, format, stream) - PROCESS *p; - int job_index, format; - FILE *stream; -{ - PROCESS *first, *last, *show; - int es, name_padding; - char *temp; - - if (p == 0) - return; - - first = last = p; - while (last->next != first) - last = last->next; - - for (;;) - { - if (p != first) - fprintf (stream, format ? " " : " |"); - - if (format != JLIST_STANDARD) - fprintf (stream, "%5ld", (long)p->pid); - - fprintf (stream, " "); - - if (format > -1 && job_index >= 0) - { - show = format ? p : last; - temp = printable_job_status (job_index, show, format); - - if (p != first) - { - if (format) - { - if (show->running == first->running && - WSTATUS (show->status) == WSTATUS (first->status)) - temp = ""; - } - else - temp = (char *)NULL; - } - - if (temp) - { - fprintf (stream, "%s", temp); - - es = STRLEN (temp); - if (es == 0) - es = 2; /* strlen ("| ") */ - name_padding = LONGEST_SIGNAL_DESC - es; - - fprintf (stream, "%*s", name_padding, ""); - - if ((WIFSTOPPED (show->status) == 0) && - (WIFCONTINUED (show->status) == 0) && - WIFCORED (show->status)) - fprintf (stream, _("(core dumped) ")); - } - } - - if (p != first && format) - fprintf (stream, "| "); - - if (p->command) - fprintf (stream, "%s", p->command); - - if (p == last && job_index >= 0) - { - temp = current_working_directory (); - - if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) - fprintf (stream, " &"); - - if (strcmp (temp, jobs[job_index]->wd) != 0) - fprintf (stream, - _(" (wd: %s)"), polite_directory_format (jobs[job_index]->wd)); - } - - if (format || (p == last)) - { - /* We need to add a CR only if this is an interactive shell, and - we're reporting the status of a completed job asynchronously. - We can't really check whether this particular job is being - reported asynchronously, so just add the CR if the shell is - currently interactive and asynchronous notification is enabled. */ - if (asynchronous_notification && interactive) - fprintf (stream, "\r\n"); - else - fprintf (stream, "\n"); - } - - if (p == last) - break; - p = p->next; - } - fflush (stream); -} - -/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT. - Must be called with SIGCHLD blocked or queued with queue_sigchld */ -static void -pretty_print_job (job_index, format, stream) - int job_index, format; - FILE *stream; -{ - register PROCESS *p; - - /* Format only pid information about the process group leader? */ - if (format == JLIST_PID_ONLY) - { - fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); - return; - } - - if (format == JLIST_CHANGED_ONLY) - { - if (IS_NOTIFIED (job_index)) - return; - format = JLIST_STANDARD; - } - - if (format != JLIST_NONINTERACTIVE) - fprintf (stream, "[%d]%c ", job_index + 1, - (job_index == js.j_current) ? '+': - (job_index == js.j_previous) ? '-' : ' '); - - if (format == JLIST_NONINTERACTIVE) - format = JLIST_LONG; - - p = jobs[job_index]->pipe; - - print_pipeline (p, job_index, format, stream); - - /* We have printed information about this job. When the job's - status changes, waitchld () sets the notification flag to 0. */ - jobs[job_index]->flags |= J_NOTIFIED; -} - -static int -print_job (job, format, state, job_index) - JOB *job; - int format, state, job_index; -{ - if (state == -1 || (JOB_STATE)state == job->state) - pretty_print_job (job_index, format, stdout); - return (0); -} - -void -list_one_job (job, format, ignore, job_index) - JOB *job; - int format, ignore, job_index; -{ - pretty_print_job (job_index, format, stdout); -} - -void -list_stopped_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JSTOPPED); -} - -void -list_running_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JRUNNING); -} - -/* List jobs. If FORMAT is non-zero, then the long form of the information - is printed, else just a short version. */ -void -list_all_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, -1); -} - -/* Fork, handling errors. Returns the pid of the newly made child, or 0. - COMMAND is just for remembering the name of the command; we don't do - anything else with it. ASYNC_P says what to do with the tty. If - non-zero, then don't give it away. */ -pid_t -make_child (command, async_p) - char *command; - int async_p; -{ - int forksleep; - sigset_t set, oset; - pid_t pid; - - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGINT); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - - making_children (); - - forksleep = 1; - -#if defined (BUFFERED_INPUT) - /* If default_buffered_input is active, we are reading a script. If - the command is asynchronous, we have already duplicated /dev/null - as fd 0, but have not changed the buffered stream corresponding to - the old fd 0. We don't want to sync the stream in this case. */ - if (default_buffered_input != -1 && - (!async_p || default_buffered_input > 0)) - sync_buffered_stream (default_buffered_input); -#endif /* BUFFERED_INPUT */ - - /* Create the child, handle severe errors. Retry on EAGAIN. */ - while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) - { - /* bash-4.2 */ - /* If we can't create any children, try to reap some dead ones. */ - waitchld (-1, 0); - - sys_error ("fork: retry"); - if (sleep (forksleep) != 0) - break; - forksleep <<= 1; - } - - if (pid < 0) - { - sys_error ("fork"); - - /* Kill all of the processes in the current pipeline. */ - terminate_current_pipeline (); - - /* Discard the current pipeline, if any. */ - if (the_pipeline) - kill_current_pipeline (); - - last_command_exit_value = EX_NOEXEC; - throw_to_top_level (); /* Reset signals, etc. */ - } - - if (pid == 0) - { - /* In the child. Give this child the right process group, set the - signals to the default state for a new process. */ - pid_t mypid; - - mypid = getpid (); -#if defined (BUFFERED_INPUT) - /* Close default_buffered_input if it's > 0. We don't close it if it's - 0 because that's the file descriptor used when redirecting input, - and it's wrong to close the file in that case. */ - unset_bash_input (0); -#endif /* BUFFERED_INPUT */ - - /* Restore top-level signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); - - if (job_control) - { - /* All processes in this pipeline belong in the same - process group. */ - - if (pipeline_pgrp == 0) /* This is the first child. */ - pipeline_pgrp = mypid; - - /* Check for running command in backquotes. */ - if (pipeline_pgrp == shell_pgrp) - ignore_tty_job_signals (); - else - default_tty_job_signals (); - - /* Set the process group before trying to mess with the terminal's - process group. This is mandated by POSIX. */ - /* This is in accordance with the Posix 1003.1 standard, - section B.7.2.4, which says that trying to set the terminal - process group with tcsetpgrp() to an unused pgrp value (like - this would have for the first child) is an error. Section - B.4.3.3, p. 237 also covers this, in the context of job control - shells. */ - if (setpgid (mypid, pipeline_pgrp) < 0) - sys_error (_("child setpgid (%ld to %ld)"), (long)mypid, (long)pipeline_pgrp); - - /* By convention (and assumption above), if - pipeline_pgrp == shell_pgrp, we are making a child for - command substitution. - In this case, we don't want to give the terminal to the - shell's process group (we could be in the middle of a - pipeline, for example). */ - if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0)) - give_terminal_to (pipeline_pgrp, 0); - -#if defined (PGRP_PIPE) - if (pipeline_pgrp == mypid) - pipe_read (pgrp_pipe); -#endif - } - else /* Without job control... */ - { - if (pipeline_pgrp == 0) - pipeline_pgrp = shell_pgrp; - - /* If these signals are set to SIG_DFL, we encounter the curious - situation of an interactive ^Z to a running process *working* - and stopping the process, but being unable to do anything with - that process to change its state. On the other hand, if they - are set to SIG_IGN, jobs started from scripts do not stop when - the shell running the script gets a SIGTSTP and stops. */ - - default_tty_job_signals (); - } - -#if defined (PGRP_PIPE) - /* Release the process group pipe, since our call to setpgid () - is done. The last call to sh_closepipe is done in stop_pipeline. */ - sh_closepipe (pgrp_pipe); -#endif /* PGRP_PIPE */ - -#if 0 - /* Don't set last_asynchronous_pid in the child */ - if (async_p) - last_asynchronous_pid = mypid; /* XXX */ - else -#endif -#if defined (RECYCLES_PIDS) - if (last_asynchronous_pid == mypid) - /* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ - last_asynchronous_pid = 1; -#endif - } - else - { - /* In the parent. Remember the pid of the child just created - as the proper pgrp if this is the first child. */ - - if (first_pid == NO_PID) - first_pid = pid; - else if (pid_wrap == -1 && pid < first_pid) - pid_wrap = 0; - else if (pid_wrap == 0 && pid >= first_pid) - pid_wrap = 1; - - if (job_control) - { - if (pipeline_pgrp == 0) - { - pipeline_pgrp = pid; - /* Don't twiddle terminal pgrps in the parent! This is the bug, - not the good thing of twiddling them in the child! */ - /* give_terminal_to (pipeline_pgrp, 0); */ - } - /* This is done on the recommendation of the Rationale section of - the POSIX 1003.1 standard, where it discusses job control and - shells. It is done to avoid possible race conditions. (Ref. - 1003.1 Rationale, section B.4.3.3, page 236). */ - setpgid (pid, pipeline_pgrp); - } - else - { - if (pipeline_pgrp == 0) - pipeline_pgrp = shell_pgrp; - } - - /* Place all processes into the jobs array regardless of the - state of job_control. */ - add_process (command, pid); - - if (async_p) - last_asynchronous_pid = pid; -#if defined (RECYCLES_PIDS) - else if (last_asynchronous_pid == pid) - /* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ - last_asynchronous_pid = 1; -#endif - - /* Delete the saved status for any job containing this PID in case it's - been reused. */ - delete_old_job (pid); - - /* Perform the check for pid reuse unconditionally. Some systems reuse - PIDs before giving a process CHILD_MAX/_SC_CHILD_MAX unique ones. */ - bgp_delete (pid); /* new process, discard any saved status */ - - last_made_pid = pid; - - /* keep stats */ - js.c_totforked++; - js.c_living++; - - /* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case - SIGCHLD remains blocked until all commands in the pipeline have been - created. */ - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - return (pid); -} - -/* These two functions are called only in child processes. */ -void -ignore_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); -} - -void -default_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); -} - -/* When we end a job abnormally, or if we stop a job, we set the tty to the - state kept in here. When a job ends normally, we set the state in here - to the state of the tty. */ - -static TTYSTRUCT shell_tty_info; - -#if defined (NEW_TTY_DRIVER) -static struct tchars shell_tchars; -static struct ltchars shell_ltchars; -#endif /* NEW_TTY_DRIVER */ - -#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) -/* Since the BSD tty driver does not allow us to change the tty modes - while simultaneously waiting for output to drain and preserving - typeahead, we have to drain the output ourselves before calling - ioctl. We cheat by finding the length of the output queue, and - using select to wait for an appropriate length of time. This is - a hack, and should be labeled as such (it's a hastily-adapted - mutation of a `usleep' implementation). It's only reason for - existing is the flaw in the BSD tty driver. */ - -static int ttspeeds[] = -{ - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400 -}; - -static void -draino (fd, ospeed) - int fd, ospeed; -{ - register int delay = ttspeeds[ospeed]; - int n; - - if (!delay) - return; - - while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) - { - if (n > (delay / 100)) - { - struct timeval tv; - - n *= 10; /* 2 bits more for conservativeness. */ - tv.tv_sec = n / delay; - tv.tv_usec = ((n % delay) * 1000000) / delay; - select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); - } - else - break; - } -} -#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ - -/* Return the fd from which we are actually getting input. */ -#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) - -/* Fill the contents of shell_tty_info with the current tty info. */ -int -get_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) - ioctl (tty, TIOCGETP, &shell_tty_info); - ioctl (tty, TIOCGETC, &shell_tchars); - ioctl (tty, TIOCGLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCGETA, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcgetattr (tty, &shell_tty_info) < 0) - { -#if 0 - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d (%d)] tcgetattr", (long)getpid (), shell_level, tty); -#endif - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - if (check_window_size) - get_new_window_size (0, (int *)0, (int *)0); - } - return 0; -} - -/* Make the current tty use the state in shell_tty_info. */ -int -set_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) -# if defined (DRAIN_OUTPUT) - draino (tty, shell_tty_info.sg_ospeed); -# endif /* DRAIN_OUTPUT */ - ioctl (tty, TIOCSETN, &shell_tty_info); - ioctl (tty, TIOCSETC, &shell_tchars); - ioctl (tty, TIOCSLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCSETAW, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - { - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d (%d)] tcsetattr", (long)getpid (), shell_level, tty); - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - } - return 0; -} - -/* Given an index into the jobs array JOB, return the PROCESS struct of the last - process in that job's pipeline. This is the one whose exit status - counts. Must be called with SIGCHLD blocked or queued. */ -static PROCESS * -find_last_proc (job, block) - int job; - int block; -{ - register PROCESS *p; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - p = jobs[job]->pipe; - while (p && p->next != jobs[job]->pipe) - p = p->next; - - if (block) - UNBLOCK_CHILD (oset); - - return (p); -} - -static pid_t -find_last_pid (job, block) - int job; - int block; -{ - PROCESS *p; - - p = find_last_proc (job, block); - /* Possible race condition here. */ - return p->pid; -} - -/* Wait for a particular child of the shell to finish executing. - This low-level function prints an error message if PID is not - a child of this shell. It returns -1 if it fails, or whatever - wait_for returns otherwise. If the child is not found in the - jobs table, it returns 127. */ -int -wait_for_single_pid (pid) - pid_t pid; -{ - register PROCESS *child; - sigset_t set, oset; - int r, job; - - BLOCK_CHILD (set, oset); - child = find_pipeline (pid, 0, (int *)NULL); - UNBLOCK_CHILD (oset); - - if (child == 0) - { - r = bgp_search (pid); - if (r >= 0) - return r; - } - - if (child == 0) - { - internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); - return (127); - } - - r = wait_for (pid); - - /* POSIX.2: if we just waited for a job, we can remove it from the jobs - table. */ - BLOCK_CHILD (set, oset); - job = find_job (pid, 0, NULL); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - /* If running in posix mode, remove the job from the jobs table immediately */ - if (posixly_correct) - { - cleanup_dead_jobs (); - bgp_delete (pid); - } - - return r; -} - -/* Wait for all of the background processes started by this shell to finish. */ -void -wait_for_background_pids () -{ - register int i, r, waited_for; - sigset_t set, oset; - pid_t pid; - - for (waited_for = 0;;) - { - BLOCK_CHILD (set, oset); - - /* find first running job; if none running in foreground, break */ - /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) - break; - } - if (i == js.j_jobslots) - { - UNBLOCK_CHILD (oset); - break; - } - - /* now wait for the last pid in that job. */ - pid = find_last_pid (i, 0); - UNBLOCK_CHILD (oset); - QUIT; - errno = 0; /* XXX */ - r = wait_for_single_pid (pid); - if (r == -1) - { - /* If we're mistaken about job state, compensate. */ - if (errno == ECHILD) - mark_all_jobs_as_dead (); - } - else - waited_for++; - } - - /* POSIX.2 says the shell can discard the statuses of all completed jobs if - `wait' is called with no arguments. */ - mark_dead_jobs_as_notified (1); - cleanup_dead_jobs (); - bgp_clear (); -} - -/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ -#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids -static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; - -static int wait_sigint_received; -static int child_caught_sigint; -static int waiting_for_child; - -static void -restore_sigint_handler () -{ - if (old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - set_signal_handler (SIGINT, old_sigint_handler); - old_sigint_handler = INVALID_SIGNAL_HANDLER; - waiting_for_child = 0; - } -} - -/* Handle SIGINT while we are waiting for children in a script to exit. - The `wait' builtin should be interruptible, but all others should be - effectively ignored (i.e. not cause the shell to exit). */ -static sighandler -wait_sigint_handler (sig) - int sig; -{ - SigHandler *sigint_handler; - - if (interrupt_immediately || - (this_shell_builtin && this_shell_builtin == wait_builtin)) - { - last_command_exit_value = EXECUTION_FAILURE; - restore_sigint_handler (); - /* If we got a SIGINT while in `wait', and SIGINT is trapped, do - what POSIX.2 says (see builtins/wait.def for more info). */ - if (this_shell_builtin && this_shell_builtin == wait_builtin && - signal_is_trapped (SIGINT) && - ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler)) - { - interrupt_immediately = 0; - trap_handler (SIGINT); /* set pending_traps[SIGINT] */ - wait_signal_received = SIGINT; - longjmp (wait_intr_buf, 1); - } - - ADDINTERRUPT; - QUIT; - } - - /* XXX - should this be interrupt_state? If it is, the shell will act - as if it got the SIGINT interrupt. */ - if (waiting_for_child) - wait_sigint_received = 1; - else - { - last_command_exit_value = 128+SIGINT; - restore_sigint_handler (); - kill (getpid (), SIGINT); - } - - /* Otherwise effectively ignore the SIGINT and allow the running job to - be killed. */ - SIGRETURN (0); -} - -static int -process_exit_signal (status) - WAIT status; -{ - return (WIFSIGNALED (status) ? WTERMSIG (status) : 0); -} - -static int -process_exit_status (status) - WAIT status; -{ - if (WIFSIGNALED (status)) - return (128 + WTERMSIG (status)); - else if (WIFSTOPPED (status) == 0) - return (WEXITSTATUS (status)); - else - return (EXECUTION_SUCCESS); -} - -static WAIT -job_signal_status (job) - int job; -{ - register PROCESS *p; - WAIT s; - - p = jobs[job]->pipe; - do - { - s = p->status; - if (WIFSIGNALED(s) || WIFSTOPPED(s)) - break; - p = p->next; - } - while (p != jobs[job]->pipe); - - return s; -} - -/* Return the exit status of the last process in the pipeline for job JOB. - This is the exit status of the entire job. */ -static WAIT -raw_job_exit_status (job) - int job; -{ - register PROCESS *p; - int fail; - WAIT ret; - - if (pipefail_opt) - { - fail = 0; - p = jobs[job]->pipe; - do - { - if (WSTATUS (p->status) != EXECUTION_SUCCESS) - fail = WSTATUS(p->status); - p = p->next; - } - while (p != jobs[job]->pipe); - WSTATUS (ret) = fail; - return ret; - } - - for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) - ; - return (p->status); -} - -/* Return the exit status of job JOB. This is the exit status of the last - (rightmost) process in the job's pipeline, modified if the job was killed - by a signal or stopped. */ -int -job_exit_status (job) - int job; -{ - return (process_exit_status (raw_job_exit_status (job))); -} - -int -job_exit_signal (job) - int job; -{ - return (process_exit_signal (raw_job_exit_status (job))); -} - -#define FIND_CHILD(pid, child) \ - do \ - { \ - child = find_pipeline (pid, 0, (int *)NULL); \ - if (child == 0) \ - { \ - give_terminal_to (shell_pgrp, 0); \ - UNBLOCK_CHILD (oset); \ - internal_error (_("wait_for: No record of process %ld"), (long)pid); \ - restore_sigint_handler (); \ - return (termination_state = 127); \ - } \ - } \ - while (0) - -/* Wait for pid (one of our children) to terminate, then - return the termination state. Returns 127 if PID is not found in - the jobs table. Returns -1 if waitchld() returns -1, indicating - that there are no unwaited-for child processes. */ -int -wait_for (pid) - pid_t pid; -{ - int job, termination_state, r; - WAIT s; - register PROCESS *child; - sigset_t set, oset; - - /* In the case that this code is interrupted, and we longjmp () out of it, - we are relying on the code in throw_to_top_level () to restore the - top-level signal mask. */ - BLOCK_CHILD (set, oset); - - /* Ignore interrupts while waiting for a job run without job control - to finish. We don't want the shell to exit if an interrupt is - received, only if one of the jobs run is killed via SIGINT. If - job control is not set, the job will be run in the same pgrp as - the shell, and the shell will see any signals the job gets. In - fact, we want this set every time the waiting shell and the waited- - for process are in the same process group, including command - substitution. */ - - /* This is possibly a race condition -- should it go in stop_pipeline? */ - wait_sigint_received = child_caught_sigint = 0; - if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB)) - { - old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - waiting_for_child = 0; - if (old_sigint_handler == SIG_IGN) - set_signal_handler (SIGINT, old_sigint_handler); - } - - termination_state = last_command_exit_value; - - if (interactive && job_control == 0) - QUIT; - /* Check for terminating signals and exit the shell if we receive one */ - CHECK_TERMSIG; - - /* If we say wait_for (), then we have a record of this child somewhere. - If it and none of its peers are running, don't call waitchld(). */ - - job = NO_JOB; - do - { - FIND_CHILD (pid, child); - - /* If this child is part of a job, then we are really waiting for the - job to finish. Otherwise, we are waiting for the child to finish. - We check for JDEAD in case the job state has been set by waitchld - after receipt of a SIGCHLD. */ - if (job == NO_JOB) - job = find_job (pid, 0, NULL); - - /* waitchld() takes care of setting the state of the job. If the job - has already exited before this is called, sigchld_handler will have - called waitchld and the state will be set to JDEAD. */ - - if (PRUNNING(child) || (job != NO_JOB && RUNNING (job))) - { -#if defined (WAITPID_BROKEN) /* SCOv4 */ - sigset_t suspend_set; - sigemptyset (&suspend_set); - sigsuspend (&suspend_set); -#else /* !WAITPID_BROKEN */ -# if defined (MUST_UNBLOCK_CHLD) - struct sigaction act, oact; - sigset_t nullset, chldset; - - sigemptyset (&nullset); - sigemptyset (&chldset); - sigprocmask (SIG_SETMASK, &nullset, &chldset); - act.sa_handler = SIG_DFL; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - act.sa_flags = 0; - sigaction (SIGCHLD, &act, &oact); -# endif - queue_sigchld = 1; - waiting_for_child++; - r = waitchld (pid, 1); - waiting_for_child--; -# if defined (MUST_UNBLOCK_CHLD) - sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); - sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); -# endif - queue_sigchld = 0; - if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin) - { - termination_state = -1; - goto wait_for_return; - } - - /* If child is marked as running, but waitpid() returns -1/ECHILD, - there is something wrong. Somewhere, wait should have returned - that child's pid. Mark the child as not running and the job, - if it exists, as JDEAD. */ - if (r == -1 && errno == ECHILD) - { - child->running = PS_DONE; - WSTATUS (child->status) = 0; /* XXX -- can't find true status */ - js.c_living = 0; /* no living child processes */ - if (job != NO_JOB) - { - jobs[job]->state = JDEAD; - js.c_reaped++; - js.j_ndead++; - } - } -#endif /* WAITPID_BROKEN */ - } - - /* If the shell is interactive, and job control is disabled, see - if the foreground process has died due to SIGINT and jump out - of the wait loop if it has. waitchld has already restored the - old SIGINT signal handler. */ - if (interactive && job_control == 0) - QUIT; - /* Check for terminating signals and exit the shell if we receive one */ - CHECK_TERMSIG; - } - while (PRUNNING (child) || (job != NO_JOB && RUNNING (job))); - - /* Restore the original SIGINT signal handler before we return. */ - restore_sigint_handler (); - - /* The exit state of the command is either the termination state of the - child, or the termination state of the job. If a job, the status - of the last child in the pipeline is the significant one. If the command - or job was terminated by a signal, note that value also. */ - termination_state = (job != NO_JOB) ? job_exit_status (job) - : process_exit_status (child->status); - last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job) - : process_exit_signal (child->status); - - /* XXX */ - if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status)) - termination_state = 128 + WSTOPSIG (child->status); - - if (job == NO_JOB || IS_JOBCONTROL (job)) - { - /* XXX - under what circumstances is a job not present in the jobs - table (job == NO_JOB)? - 1. command substitution - - In the case of command substitution, at least, it's probably not - the right thing to give the terminal to the shell's process group, - even though there is code in subst.c:command_substitute to work - around it. - - Things that don't: - $PROMPT_COMMAND execution - process substitution - */ -#if 0 -if (job == NO_JOB) - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); -#endif - give_terminal_to (shell_pgrp, 0); - } - - /* If the command did not exit cleanly, or the job is just - being stopped, then reset the tty state back to what it - was before this command. Reset the tty state and notify - the user of the job termination only if the shell is - interactive. Clean up any dead jobs in either case. */ - if (job != NO_JOB) - { - if (interactive_shell && subshell_environment == 0) - { - /* This used to use `child->status'. That's wrong, however, for - pipelines. `child' is the first process in the pipeline. It's - likely that the process we want to check for abnormal termination - or stopping is the last process in the pipeline, especially if - it's long-lived and the first process is short-lived. Since we - know we have a job here, we can check all the processes in this - job's pipeline and see if one of them stopped or terminated due - to a signal. We might want to change this later to just check - the last process in the pipeline. If no process exits due to a - signal, S is left as the status of the last job in the pipeline. */ - s = job_signal_status (job); - - if (WIFSIGNALED (s) || WIFSTOPPED (s)) - { - set_tty_state (); - - /* If the current job was stopped or killed by a signal, and - the user has requested it, get a possibly new window size */ - if (check_window_size && (job == js.j_current || IS_FOREGROUND (job))) - get_new_window_size (0, (int *)0, (int *)0); - } - else - get_tty_state (); - - /* If job control is enabled, the job was started with job - control, the job was the foreground job, and it was killed - by SIGINT, then print a newline to compensate for the kernel - printing the ^C without a trailing newline. */ - if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && - WIFSIGNALED (s) && WTERMSIG (s) == SIGINT) - { - /* If SIGINT is not trapped and the shell is in a for, while, - or until loop, act as if the shell received SIGINT as - well, so the loop can be broken. This doesn't call the - SIGINT signal handler; maybe it should. */ - if (signal_is_trapped (SIGINT) == 0 && (loop_level || (shell_compatibility_level > 32 && executing_list))) - ADDINTERRUPT; - else - { - putchar ('\n'); - fflush (stdout); - } - } - } - else if ((subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PIPE)) && wait_sigint_received) - { - /* If waiting for a job in a subshell started to do command - substitution or to run a pipeline element that consists of - something like a while loop or a for loop, simulate getting - and being killed by the SIGINT to pass the status back to our - parent. */ - s = job_signal_status (job); - - if (child_caught_sigint == 0 && signal_is_trapped (SIGINT) == 0) - { - UNBLOCK_CHILD (oset); - old_sigint_handler = set_signal_handler (SIGINT, SIG_DFL); - if (old_sigint_handler == SIG_IGN) - restore_sigint_handler (); - else - kill (getpid (), SIGINT); - } - } - else if (interactive_shell == 0 && IS_FOREGROUND (job) && check_window_size) - get_new_window_size (0, (int *)0, (int *)0); - - /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD - signal handler path */ - if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/) - setjstatus (job); - - /* If this job is dead, notify the user of the status. If the shell - is interactive, this will display a message on the terminal. If - the shell is not interactive, make sure we turn on the notify bit - so we don't get an unwanted message about the job's termination, - and so delete_job really clears the slot in the jobs table. */ - notify_and_cleanup (); - } - -wait_for_return: - - UNBLOCK_CHILD (oset); - - return (termination_state); -} - -/* Wait for the last process in the pipeline for JOB. Returns whatever - wait_for returns: the last process's termination state or -1 if there - are no unwaited-for child processes or an error occurs. */ -int -wait_for_job (job) - int job; -{ - pid_t pid; - int r; - sigset_t set, oset; - - BLOCK_CHILD(set, oset); - if (JOBSTATE (job) == JSTOPPED) - internal_warning (_("wait_for_job: job %d is stopped"), job+1); - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD(oset); - r = wait_for (pid); - - /* POSIX.2: we can remove the job from the jobs table if we just waited - for it. */ - BLOCK_CHILD (set, oset); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - return r; -} - -/* Print info about dead jobs, and then delete them from the list - of known jobs. This does not actually delete jobs when the - shell is not interactive, because the dead jobs are not marked - as notified. */ -void -notify_and_cleanup () -{ - if (jobs_list_frozen) - return; - - if (interactive || interactive_shell == 0 || sourcelevel) - notify_of_job_status (); - - cleanup_dead_jobs (); -} - -/* Make dead jobs disappear from the jobs array without notification. - This is used when the shell is not interactive. */ -void -reap_dead_jobs () -{ - mark_dead_jobs_as_notified (0); - cleanup_dead_jobs (); -} - -/* Return the next closest (chronologically) job to JOB which is in - STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if - there is no next recent job. */ -static int -most_recent_job_in_state (job, state) - int job; - JOB_STATE state; -{ - register int i, result; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - for (result = NO_JOB, i = job - 1; i >= 0; i--) - { - if (jobs[i] && (JOBSTATE (i) == state)) - { - result = i; - break; - } - } - - UNBLOCK_CHILD (oset); - - return (result); -} - -/* Return the newest *stopped* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_stopped (job) - int job; -{ - return (most_recent_job_in_state (job, JSTOPPED)); -} - -/* Return the newest *running* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_running (job) - int job; -{ - return (most_recent_job_in_state (job, JRUNNING)); -} - -/* Make JOB be the current job, and make previous be useful. Must be - called with SIGCHLD blocked. */ -static void -set_current_job (job) - int job; -{ - int candidate; - - if (js.j_current != job) - { - js.j_previous = js.j_current; - js.j_current = job; - } - - /* First choice for previous job is the old current job. */ - if (js.j_previous != js.j_current && - js.j_previous != NO_JOB && - jobs[js.j_previous] && - STOPPED (js.j_previous)) - return; - - /* Second choice: Newest stopped job that is older than - the current job. */ - candidate = NO_JOB; - if (STOPPED (js.j_current)) - { - candidate = job_last_stopped (js.j_current); - - if (candidate != NO_JOB) - { - js.j_previous = candidate; - return; - } - } - - /* If we get here, there is either only one stopped job, in which case it is - the current job and the previous job should be set to the newest running - job, or there are only running jobs and the previous job should be set to - the newest running job older than the current job. We decide on which - alternative to use based on whether or not JOBSTATE(js.j_current) is - JSTOPPED. */ - - candidate = RUNNING (js.j_current) ? job_last_running (js.j_current) - : job_last_running (js.j_jobslots); - - if (candidate != NO_JOB) - { - js.j_previous = candidate; - return; - } - - /* There is only a single job, and it is both `+' and `-'. */ - js.j_previous = js.j_current; -} - -/* Make current_job be something useful, if it isn't already. */ - -/* Here's the deal: The newest non-running job should be `+', and the - next-newest non-running job should be `-'. If there is only a single - stopped job, the js.j_previous is the newest non-running job. If there - are only running jobs, the newest running job is `+' and the - next-newest running job is `-'. Must be called with SIGCHLD blocked. */ - -static void -reset_current () -{ - int candidate; - - if (js.j_jobslots && js.j_current != NO_JOB && jobs[js.j_current] && STOPPED (js.j_current)) - candidate = js.j_current; - else - { - candidate = NO_JOB; - - /* First choice: the previous job. */ - if (js.j_previous != NO_JOB && jobs[js.j_previous] && STOPPED (js.j_previous)) - candidate = js.j_previous; - - /* Second choice: the most recently stopped job. */ - if (candidate == NO_JOB) - candidate = job_last_stopped (js.j_jobslots); - - /* Third choice: the newest running job. */ - if (candidate == NO_JOB) - candidate = job_last_running (js.j_jobslots); - } - - /* If we found a job to use, then use it. Otherwise, there - are no jobs period. */ - if (candidate != NO_JOB) - set_current_job (candidate); - else - js.j_current = js.j_previous = NO_JOB; -} - -/* Set up the job structures so we know the job and its processes are - all running. */ -static void -set_job_running (job) - int job; -{ - register PROCESS *p; - - /* Each member of the pipeline is now running. */ - p = jobs[job]->pipe; - - do - { - if (WIFSTOPPED (p->status)) - p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */ - p = p->next; - } - while (p != jobs[job]->pipe); - - /* This means that the job is running. */ - JOBSTATE (job) = JRUNNING; -} - -/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, - start the job in the background. JOB is a zero-based index into - JOBS. Returns -1 if it is unable to start a job, and the return - status of the job otherwise. */ -int -start_job (job, foreground) - int job, foreground; -{ - register PROCESS *p; - int already_running; - sigset_t set, oset; - char *wd, *s; - static TTYSTRUCT save_stty; - - BLOCK_CHILD (set, oset); - - if (DEADJOB (job)) - { - internal_error (_("%s: job has terminated"), this_command_name); - UNBLOCK_CHILD (oset); - return (-1); - } - - already_running = RUNNING (job); - - if (foreground == 0 && already_running) - { - internal_error (_("%s: job %d already in background"), this_command_name, job + 1); - UNBLOCK_CHILD (oset); - return (0); /* XPG6/SUSv3 says this is not an error */ - } - - wd = current_working_directory (); - - /* You don't know about the state of this job. Do you? */ - jobs[job]->flags &= ~J_NOTIFIED; - - if (foreground) - { - set_current_job (job); - jobs[job]->flags |= J_FOREGROUND; - } - - /* Tell the outside world what we're doing. */ - p = jobs[job]->pipe; - - if (foreground == 0) - { - /* POSIX.2 says `bg' doesn't give any indication about current or - previous job. */ - if (posixly_correct == 0) - s = (job == js.j_current) ? "+ ": ((job == js.j_previous) ? "- " : " "); - else - s = " "; - printf ("[%d]%s", job + 1, s); - } - - do - { - printf ("%s%s", - p->command ? p->command : "", - p->next != jobs[job]->pipe? " | " : ""); - p = p->next; - } - while (p != jobs[job]->pipe); - - if (foreground == 0) - printf (" &"); - - if (strcmp (wd, jobs[job]->wd) != 0) - printf (" (wd: %s)", polite_directory_format (jobs[job]->wd)); - - printf ("\n"); - - /* Run the job. */ - if (already_running == 0) - set_job_running (job); - - /* Save the tty settings before we start the job in the foreground. */ - if (foreground) - { - get_tty_state (); - save_stty = shell_tty_info; - /* Give the terminal to this job. */ - if (IS_JOBCONTROL (job)) - give_terminal_to (jobs[job]->pgrp, 0); - } - else - jobs[job]->flags &= ~J_FOREGROUND; - - /* If the job is already running, then don't bother jump-starting it. */ - if (already_running == 0) - { - jobs[job]->flags |= J_NOTIFIED; - killpg (jobs[job]->pgrp, SIGCONT); - } - - if (foreground) - { - pid_t pid; - int st; - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD (oset); - st = wait_for (pid); - shell_tty_info = save_stty; - set_tty_state (); - return (st); - } - else - { - reset_current (); - UNBLOCK_CHILD (oset); - return (0); - } -} - -/* Give PID SIGNAL. This determines what job the pid belongs to (if any). - If PID does belong to a job, and the job is stopped, then CONTinue the - job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, - then kill the process group associated with PID. */ -int -kill_pid (pid, sig, group) - pid_t pid; - int sig, group; -{ - register PROCESS *p; - int job, result, negative; - sigset_t set, oset; - - if (pid < -1) - { - pid = -pid; - group = negative = 1; - } - else - negative = 0; - - result = EXECUTION_SUCCESS; - if (group) - { - BLOCK_CHILD (set, oset); - p = find_pipeline (pid, 0, &job); - - if (job != NO_JOB) - { - jobs[job]->flags &= ~J_NOTIFIED; - - /* Kill process in backquotes or one started without job control? */ - - /* If we're passed a pid < -1, just call killpg and see what happens */ - if (negative && jobs[job]->pgrp == shell_pgrp) - result = killpg (pid, sig); - /* If we're killing using job control notification, for example, - without job control active, we have to do things ourselves. */ - else if (jobs[job]->pgrp == shell_pgrp) - { - p = jobs[job]->pipe; - do - { - if (PALIVE (p) == 0) - continue; /* avoid pid recycling problem */ - kill (p->pid, sig); - if (PEXITED (p) && (sig == SIGTERM || sig == SIGHUP)) - kill (p->pid, SIGCONT); - p = p->next; - } - while (p != jobs[job]->pipe); - } - else - { - result = killpg (jobs[job]->pgrp, sig); - if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) - killpg (jobs[job]->pgrp, SIGCONT); - /* If we're continuing a stopped job via kill rather than bg or - fg, emulate the `bg' behavior. */ - if (p && STOPPED (job) && (sig == SIGCONT)) - { - set_job_running (job); - jobs[job]->flags &= ~J_FOREGROUND; - jobs[job]->flags |= J_NOTIFIED; - } - } - } - else - result = killpg (pid, sig); - - UNBLOCK_CHILD (oset); - } - else - result = kill (pid, sig); - - return (result); -} - -/* sigchld_handler () flushes at least one of the children that we are - waiting for. It gets run when we have gotten a SIGCHLD signal. */ -static sighandler -sigchld_handler (sig) - int sig; -{ - int n, oerrno; - - oerrno = errno; - REINSTALL_SIGCHLD_HANDLER; - sigchld++; - n = 0; - if (queue_sigchld == 0) - n = waitchld (-1, 0); - errno = oerrno; - SIGRETURN (n); -} - -/* waitchld() reaps dead or stopped children. It's called by wait_for and - sigchld_handler, and runs until there aren't any children terminating any - more. - If BLOCK is 1, this is to be a blocking wait for a single child, although - an arriving SIGCHLD could cause the wait to be non-blocking. It returns - the number of children reaped, or -1 if there are no unwaited-for child - processes. */ -static int -waitchld (wpid, block) - pid_t wpid; - int block; -{ - WAIT status; - PROCESS *child; - pid_t pid; - int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; - static int wcontinued = WCONTINUED; /* run-time fix for glibc problem */ - - call_set_current = children_exited = 0; - last_stopped_job = NO_JOB; - - do - { - /* We don't want to be notified about jobs stopping if job control - is not active. XXX - was interactive_shell instead of job_control */ - waitpid_flags = (job_control && subshell_environment == 0) - ? (WUNTRACED|wcontinued) - : 0; - if (sigchld || block == 0) - waitpid_flags |= WNOHANG; - /* Check for terminating signals and exit the shell if we receive one */ - CHECK_TERMSIG; - - if (block == 1 && queue_sigchld == 0 && (waitpid_flags & WNOHANG) == 0) - { - internal_warning (_("waitchld: turning on WNOHANG to avoid indefinite block")); - waitpid_flags |= WNOHANG; - } - - pid = WAITPID (-1, &status, waitpid_flags); - - /* WCONTINUED may be rejected by waitpid as invalid even when defined */ - if (wcontinued && pid < 0 && errno == EINVAL) - { - wcontinued = 0; - continue; /* jump back to the test and retry without WCONTINUED */ - } - - /* The check for WNOHANG is to make sure we decrement sigchld only - if it was non-zero before we called waitpid. */ - if (sigchld > 0 && (waitpid_flags & WNOHANG)) - sigchld--; - - /* If waitpid returns -1 with errno == ECHILD, there are no more - unwaited-for child processes of this shell. */ - if (pid < 0 && errno == ECHILD) - { - if (children_exited == 0) - return -1; - else - break; - } - - /* If waitpid returns 0, there are running children. If it returns -1, - the only other error POSIX says it can return is EINTR. */ - CHECK_TERMSIG; - - /* If waitpid returns -1/EINTR and the shell saw a SIGINT, then we - assume the child has blocked or handled SIGINT. In that case, we - require the child to actually die due to SIGINT to act on the - SIGINT we received; otherwise we assume the child handled it and - let it go. */ - if (pid < 0 && errno == EINTR && wait_sigint_received) - child_caught_sigint = 1; - - if (pid <= 0) - continue; /* jumps right to the test */ - - /* If the child process did die due to SIGINT, forget our assumption - that it caught or otherwise handled it. */ - if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT) - child_caught_sigint = 0; - - /* children_exited is used to run traps on SIGCHLD. We don't want to - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) - { - children_exited++; - js.c_living--; - } - - /* Locate our PROCESS for this pid. */ - child = find_process (pid, 1, &job); /* want living procs only */ - -#if defined (COPROCESS_SUPPORT) - coproc_pidchk (pid, status); -#endif - - /* It is not an error to have a child terminate that we did - not have a record of. This child could have been part of - a pipeline in backquote substitution. Even so, I'm not - sure child is ever non-zero. */ - if (child == 0) - { - if (WIFEXITED (status) || WIFSIGNALED (status)) - js.c_reaped++; - continue; - } - - /* Remember status, and whether or not the process is running. */ - child->status = status; - child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE; - - if (PEXITED (child)) - { - js.c_totreaped++; - if (job != NO_JOB) - js.c_reaped++; - } - - if (job == NO_JOB) - continue; - - call_set_current += set_job_status_and_cleanup (job); - - if (STOPPED (job)) - last_stopped_job = job; - else if (DEADJOB (job) && last_stopped_job == job) - last_stopped_job = NO_JOB; - } - while ((sigchld || block == 0) && pid > (pid_t)0); - - /* If a job was running and became stopped, then set the current - job. Otherwise, don't change a thing. */ - if (call_set_current) - { - if (last_stopped_job != NO_JOB) - set_current_job (last_stopped_job); - else - reset_current (); - } - - /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ - if (job_control && signal_is_trapped (SIGCHLD) && children_exited && - trap_list[SIGCHLD] != (char *)IGNORE_SIG) - { - if (posixly_correct && this_shell_builtin && this_shell_builtin == wait_builtin) - { - interrupt_immediately = 0; - trap_handler (SIGCHLD); /* set pending_traps[SIGCHLD] */ - wait_signal_received = SIGCHLD; - longjmp (wait_intr_buf, 1); - } - else if (sigchld) /* called from signal handler */ - queue_sigchld_trap (children_exited); - else - run_sigchld_trap (children_exited); - } - - /* We have successfully recorded the useful information about this process - that has just changed state. If we notify asynchronously, and the job - that this process belongs to is no longer running, then notify the user - of that fact now. */ - if (asynchronous_notification && interactive) - notify_of_job_status (); - - return (children_exited); -} - -/* Set the status of JOB and perform any necessary cleanup if the job is - marked as JDEAD. - - Currently, the cleanup activity is restricted to handling any SIGINT - received while waiting for a foreground job to finish. */ -static int -set_job_status_and_cleanup (job) - int job; -{ - PROCESS *child; - int tstatus, job_state, any_stopped, any_tstped, call_set_current; - SigHandler *temp_handler; - - child = jobs[job]->pipe; - jobs[job]->flags &= ~J_NOTIFIED; - - call_set_current = 0; - - /* - * COMPUTE JOB STATUS - */ - - /* If all children are not running, but any of them is stopped, then - the job is stopped, not dead. */ - job_state = any_stopped = any_tstped = 0; - do - { - job_state |= PRUNNING (child); -#if 0 - if (PEXITED (child) && (WIFSTOPPED (child->status))) -#else - /* Only checking for WIFSTOPPED now, not for PS_DONE */ - if (PSTOPPED (child)) -#endif - { - any_stopped = 1; - any_tstped |= job_control && (WSTOPSIG (child->status) == SIGTSTP); - } - child = child->next; - } - while (child != jobs[job]->pipe); - - /* If job_state != 0, the job is still running, so don't bother with - setting the process exit status and job state unless we're - transitioning from stopped to running. */ - if (job_state != 0 && JOBSTATE(job) != JSTOPPED) - return 0; - - /* - * SET JOB STATUS - */ - - /* The job is either stopped or dead. Set the state of the job accordingly. */ - if (any_stopped) - { - jobs[job]->state = JSTOPPED; - jobs[job]->flags &= ~J_FOREGROUND; - call_set_current++; - /* Suspending a job with SIGTSTP breaks all active loops. */ - if (any_tstped && loop_level) - breaking = loop_level; - } - else if (job_state != 0) /* was stopped, now running */ - { - jobs[job]->state = JRUNNING; - call_set_current++; - } - else - { - jobs[job]->state = JDEAD; - js.j_ndead++; - -#if 0 - if (IS_FOREGROUND (job)) - setjstatus (job); -#endif - - /* If this job has a cleanup function associated with it, call it - with `cleanarg' as the single argument, then set the function - pointer to NULL so it is not inadvertently called twice. The - cleanup function is responsible for deallocating cleanarg. */ - if (jobs[job]->j_cleanup) - { - (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); - jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; - } - } - - /* - * CLEANUP - * - * Currently, we just do special things if we got a SIGINT while waiting - * for a foreground job to complete - */ - - if (JOBSTATE (job) == JDEAD) - { - /* If we're running a shell script and we get a SIGINT with a - SIGINT trap handler, but the foreground job handles it and - does not exit due to SIGINT, run the trap handler but do not - otherwise act as if we got the interrupt. */ - if (wait_sigint_received && interactive_shell == 0 && - child_caught_sigint && IS_FOREGROUND (job) && - signal_is_trapped (SIGINT)) - { - int old_frozen; - wait_sigint_received = 0; - last_command_exit_value = process_exit_status (child->status); - - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - } - - /* If the foreground job is killed by SIGINT when job control is not - active, we need to perform some special handling. - - The check of wait_sigint_received is a way to determine if the - SIGINT came from the keyboard (in which case the shell has already - seen it, and wait_sigint_received is non-zero, because keyboard - signals are sent to process groups) or via kill(2) to the foreground - process by another process (or itself). If the shell did receive the - SIGINT, it needs to perform normal SIGINT processing. */ - else if (wait_sigint_received && - child_caught_sigint == 0 && - IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0) - { - int old_frozen; - - wait_sigint_received = 0; - - /* If SIGINT is trapped, set the exit status so that the trap - handler can see it. */ - if (signal_is_trapped (SIGINT)) - last_command_exit_value = process_exit_status (child->status); - - /* If the signal is trapped, let the trap handler get it no matter - what and simply return if the trap handler returns. - maybe_call_trap_handler() may cause dead jobs to be removed from - the job table because of a call to execute_command. We work - around this by setting JOBS_LIST_FROZEN. */ - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - /* wait_sigint_handler () has already seen SIGINT and - allowed the wait builtin to jump out. We need to - call the original SIGINT handler, if necessary. If - the original handler is SIG_DFL, we need to resend - the signal to ourselves. */ - - temp_handler = old_sigint_handler; - - /* Bogus. If we've reset the signal handler as the result - of a trap caught on SIGINT, then old_sigint_handler - will point to trap_handler, which now knows nothing about - SIGINT (if we reset the sighandler to the default). - In this case, we have to fix things up. What a crock. */ - if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0) - temp_handler = trap_to_sighandler (SIGINT); - restore_sigint_handler (); - if (temp_handler == SIG_DFL) - termsig_handler (SIGINT); /* XXX */ - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); - } - } - } - - return call_set_current; -} - -/* Build the array of values for the $PIPESTATUS variable from the set of - exit statuses of all processes in the job J. */ -static void -setjstatus (j) - int j; -{ -#if defined (ARRAY_VARS) - register int i; - register PROCESS *p; - - for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++) - ; - i++; - if (statsize < i) - { - pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int)); - statsize = i; - } - i = 0; - p = jobs[j]->pipe; - do - { - pstatuses[i++] = process_exit_status (p->status); - p = p->next; - } - while (p != jobs[j]->pipe); - - pstatuses[i] = -1; /* sentinel */ - set_pipestatus_array (pstatuses, i); -#endif -} - -void -run_sigchld_trap (nchild) - int nchild; -{ - char *trap_command; - int i; - - /* Turn off the trap list during the call to parse_and_execute () - to avoid potentially infinite recursive calls. Preserve the - values of last_command_exit_value, last_made_pid, and the_pipeline - around the execution of the trap commands. */ - trap_command = savestring (trap_list[SIGCHLD]); - - begin_unwind_frame ("SIGCHLD trap"); - unwind_protect_int (last_command_exit_value); - unwind_protect_int (last_command_exit_signal); - unwind_protect_var (last_made_pid); - unwind_protect_int (interrupt_immediately); - unwind_protect_int (jobs_list_frozen); - unwind_protect_pointer (the_pipeline); - unwind_protect_pointer (subst_assign_varlist); - - /* We have to add the commands this way because they will be run - in reverse order of adding. We don't want maybe_set_sigchld_trap () - to reference freed memory. */ - add_unwind_protect (xfree, trap_command); - add_unwind_protect (maybe_set_sigchld_trap, trap_command); - - subst_assign_varlist = (WORD_LIST *)NULL; - the_pipeline = (PROCESS *)NULL; - - set_impossible_sigchld_trap (); - jobs_list_frozen = 1; - for (i = 0; i < nchild; i++) - { - interrupt_immediately = 1; - parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); - } - - run_unwind_frame ("SIGCHLD trap"); -} - -/* Function to call when you want to notify people of changes - in job status. This prints out all jobs which are pending - notification to stderr, and marks those printed as already - notified, thus making them candidates for cleanup. */ -static void -notify_of_job_status () -{ - register int job, termsig; - char *dir; - sigset_t set, oset; - WAIT s; - - if (jobs == 0 || js.j_jobslots == 0) - return; - - if (old_ttou != 0) - { - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGTTOU); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - } - else - queue_sigchld++; - - /* XXX could use js.j_firstj here */ - for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++) - { - if (jobs[job] && IS_NOTIFIED (job) == 0) - { - s = raw_job_exit_status (job); - termsig = WTERMSIG (s); - - /* POSIX.2 says we have to hang onto the statuses of at most the - last CHILD_MAX background processes if the shell is running a - script. If the shell is running a script, either from a file - or standard input, don't print anything unless the job was - killed by a signal. */ - if (startup_state == 0 && WIFSIGNALED (s) == 0 && - ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) - continue; - -#if 0 - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2, we were started to run `-c command', so - don't print anything. */ - if ((job_control == 0 && interactive_shell) || startup_state == 2) -#else - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2 and subshell_environment has the - SUBSHELL_COMSUB bit turned on, we were started to run a command - substitution, so don't print anything. */ - if ((job_control == 0 && interactive_shell) || - (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB))) -#endif - { - /* POSIX.2 compatibility: if the shell is not interactive, - hang onto the job corresponding to the last asynchronous - pid until the user has been notified of its status or does - a `wait'. */ - if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid))) - jobs[job]->flags |= J_NOTIFIED; - continue; - } - - /* Print info on jobs that are running in the background, - and on foreground jobs that were killed by anything - except SIGINT (and possibly SIGPIPE). */ - switch (JOBSTATE (job)) - { - case JDEAD: - if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && - termsig != SIGINT && -#if defined (DONT_REPORT_SIGTERM) - termsig != SIGTERM && -#endif -#if defined (DONT_REPORT_SIGPIPE) - termsig != SIGPIPE && -#endif - signal_is_trapped (termsig) == 0) - { - /* Don't print `0' for a line number. */ - fprintf (stderr, _("%s: line %d: "), get_name_for_error (), (line_number == 0) ? 1 : line_number); - pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); - } - else if (IS_FOREGROUND (job)) - { -#if !defined (DONT_REPORT_SIGPIPE) - if (termsig && WIFSIGNALED (s) && termsig != SIGINT) -#else - if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE) -#endif - { - fprintf (stderr, "%s", j_strsignal (termsig)); - - if (WIFCORED (s)) - fprintf (stderr, _(" (core dumped)")); - - fprintf (stderr, "\n"); - } - } - else if (job_control) /* XXX job control test added */ - { - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && strcmp (dir, jobs[job]->wd) != 0) - fprintf (stderr, - _("(wd now: %s)\n"), polite_directory_format (dir)); - } - - jobs[job]->flags |= J_NOTIFIED; - break; - - case JSTOPPED: - fprintf (stderr, "\n"); - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && (strcmp (dir, jobs[job]->wd) != 0)) - fprintf (stderr, - _("(wd now: %s)\n"), polite_directory_format (dir)); - jobs[job]->flags |= J_NOTIFIED; - break; - - case JRUNNING: - case JMIXED: - break; - - default: - programming_error ("notify_of_job_status"); - } - } - } - if (old_ttou != 0) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - else - queue_sigchld--; -} - -/* Initialize the job control mechanism, and set up the tty stuff. */ -int -initialize_job_control (force) - int force; -{ - pid_t t; - int t_errno; - - t_errno = -1; - shell_pgrp = getpgid (0); - - if (shell_pgrp == -1) - { - sys_error (_("initialize_job_control: getpgrp failed")); - exit (1); - } - - /* We can only have job control if we are interactive unless we force it. */ - if (interactive == 0 && force == 0) - { - job_control = 0; - original_pgrp = NO_PID; - shell_tty = fileno (stderr); - } - else - { - shell_tty = -1; - - /* If forced_interactive is set, we skip the normal check that stderr - is attached to a tty, so we need to check here. If it's not, we - need to see whether we have a controlling tty by opening /dev/tty, - since trying to use job control tty pgrp manipulations on a non-tty - is going to fail. */ - if (forced_interactive && isatty (fileno (stderr)) == 0) - shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK); - - /* Get our controlling terminal. If job_control is set, or - interactive is set, then this is an interactive shell no - matter where fd 2 is directed. */ - if (shell_tty == -1) - shell_tty = dup (fileno (stderr)); /* fd 2 */ - - if (shell_tty != -1) - shell_tty = move_to_high_fd (shell_tty, 1, -1); - - /* Compensate for a bug in systems that compiled the BSD - rlogind with DEBUG defined, like NeXT and Alliant. */ - if (shell_pgrp == 0) - { - shell_pgrp = getpid (); - setpgid (0, shell_pgrp); - tcsetpgrp (shell_tty, shell_pgrp); - } - - while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1) - { - if (shell_pgrp != terminal_pgrp) - { - SigHandler *ottin; - - ottin = set_signal_handler(SIGTTIN, SIG_DFL); - kill (0, SIGTTIN); - set_signal_handler (SIGTTIN, ottin); - continue; - } - break; - } - - if (terminal_pgrp == -1) - t_errno = errno; - - /* Make sure that we are using the new line discipline. */ - if (set_new_line_discipline (shell_tty) < 0) - { - sys_error (_("initialize_job_control: line discipline")); - job_control = 0; - } - else - { - original_pgrp = shell_pgrp; - shell_pgrp = getpid (); - - if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) - { - sys_error (_("initialize_job_control: setpgid")); - shell_pgrp = original_pgrp; - } - - job_control = 1; - - /* If (and only if) we just set our process group to our pid, - thereby becoming a process group leader, and the terminal - is not in the same process group as our (new) process group, - then set the terminal's process group to our (new) process - group. If that fails, set our process group back to what it - was originally (so we can still read from the terminal) and - turn off job control. */ - if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp) - { - if (give_terminal_to (shell_pgrp, 0) < 0) - { - t_errno = errno; - setpgid (0, original_pgrp); - shell_pgrp = original_pgrp; - errno = t_errno; - sys_error (_("cannot set terminal process group (%d)"), shell_pgrp); - job_control = 0; - } - } - - if (job_control && ((t = tcgetpgrp (shell_tty)) == -1 || t != shell_pgrp)) - { - if (t_errno != -1) - errno = t_errno; - sys_error (_("cannot set terminal process group (%d)"), t); - job_control = 0; - } - } - if (job_control == 0) - internal_error (_("no job control in this shell")); - } - - if (shell_tty != fileno (stderr)) - SET_CLOSE_ON_EXEC (shell_tty); - - set_signal_handler (SIGCHLD, sigchld_handler); - - change_flag ('m', job_control ? '-' : '+'); - - if (interactive) - get_tty_state (); - - if (js.c_childmax < 0) - js.c_childmax = getmaxchild (); - if (js.c_childmax < 0) - js.c_childmax = DEFAULT_CHILD_MAX; - - return job_control; -} - -#ifdef DEBUG -void -debug_print_pgrps () -{ - itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", - (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); - itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", - shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); -} -#endif - -/* Set the line discipline to the best this system has to offer. - Return -1 if this is not possible. */ -static int -set_new_line_discipline (tty) - int tty; -{ -#if defined (NEW_TTY_DRIVER) - int ldisc; - - if (ioctl (tty, TIOCGETD, &ldisc) < 0) - return (-1); - - if (ldisc != NTTYDISC) - { - ldisc = NTTYDISC; - - if (ioctl (tty, TIOCSETD, &ldisc) < 0) - return (-1); - } - return (0); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) -# if defined (TERMIO_LDISC) && (NTTYDISC) - if (ioctl (tty, TCGETA, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIO_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (TERMIOS_LDISC) && defined (NTTYDISC) - if (tcgetattr (tty, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIOS_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIOS_TTY_DRIVER */ - -#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) - return (-1); -#endif -} - -/* Setup this shell to handle C-C, etc. */ -void -initialize_job_signals () -{ - if (interactive) - { - set_signal_handler (SIGINT, sigint_sighandler); - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - } - else if (job_control) - { - old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler); - old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler); - old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler); - } - /* Leave these things alone for non-interactive shells without job - control. */ -} - -/* Here we handle CONT signals. */ -static sighandler -sigcont_sighandler (sig) - int sig; -{ - initialize_job_signals (); - set_signal_handler (SIGCONT, old_cont); - kill (getpid (), SIGCONT); - - SIGRETURN (0); -} - -/* Here we handle stop signals while we are running not as a login shell. */ -static sighandler -sigstop_sighandler (sig) - int sig; -{ - set_signal_handler (SIGTSTP, old_tstp); - set_signal_handler (SIGTTOU, old_ttou); - set_signal_handler (SIGTTIN, old_ttin); - - old_cont = set_signal_handler (SIGCONT, sigcont_sighandler); - - give_terminal_to (shell_pgrp, 0); - - kill (getpid (), sig); - - SIGRETURN (0); -} - -/* Give the terminal to PGRP. */ -int -give_terminal_to (pgrp, force) - pid_t pgrp; - int force; -{ - sigset_t set, oset; - int r, e; - - r = 0; - if (job_control || force) - { - sigemptyset (&set); - sigaddset (&set, SIGTTOU); - sigaddset (&set, SIGTTIN); - sigaddset (&set, SIGTSTP); - sigaddset (&set, SIGCHLD); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - - if (tcsetpgrp (shell_tty, pgrp) < 0) - { - /* Maybe we should print an error message? */ -#if 0 - sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", - shell_tty, (long)getpid(), (long)pgrp); -#endif - r = -1; - e = errno; - } - else - terminal_pgrp = pgrp; - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - if (r == -1) - errno = e; - - return r; -} - -/* Give terminal to NPGRP iff it's currently owned by OPGRP. FLAGS are the - flags to pass to give_terminal_to(). */ -static int -maybe_give_terminal_to (opgrp, npgrp, flags) - pid_t opgrp, npgrp; - int flags; -{ - int tpgrp; - - tpgrp = tcgetpgrp (shell_tty); - if (tpgrp < 0 && errno == ENOTTY) - return -1; - if (tpgrp == npgrp) - { - terminal_pgrp = npgrp; - return 0; - } - else if (tpgrp != opgrp) - { -#if defined (DEBUG) - internal_warning ("maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d", tpgrp, opgrp, npgrp); -#endif - return -1; - } - else - return (give_terminal_to (npgrp, flags)); -} - -/* Clear out any jobs in the job array. This is intended to be used by - children of the shell, who should not have any job structures as baggage - when they start executing (forking subshells for parenthesized execution - and functions with pipes are the two that spring to mind). If RUNNING_ONLY - is nonzero, only running jobs are removed from the table. */ -void -delete_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - /* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */ - if (js.j_jobslots) - { - js.j_current = js.j_previous = NO_JOB; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - delete_job (i, DEL_WARNSTOPPED); - } - if (running_only == 0) - { - free ((char *)jobs); - js.j_jobslots = 0; - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - } - - if (running_only == 0) - bgp_clear (); - - UNBLOCK_CHILD (oset); -} - -/* Mark all jobs in the job array so that they don't get a SIGHUP when the - shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ -void -nohup_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - if (js.j_jobslots) - { - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - nohup_job (i); - } - - UNBLOCK_CHILD (oset); -} - -int -count_all_jobs () -{ - int i, n; - sigset_t set, oset; - - /* This really counts all non-dead jobs. */ - BLOCK_CHILD (set, oset); - /* XXX could use js.j_firstj here */ - for (i = n = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && DEADJOB(i) == 0) - n++; - } - UNBLOCK_CHILD (oset); - return n; -} - -static void -mark_all_jobs_as_dead () -{ - register int i; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return; - - BLOCK_CHILD (set, oset); - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - if (jobs[i]) - { - jobs[i]->state = JDEAD; - js.j_ndead++; - } - - UNBLOCK_CHILD (oset); -} - -/* Mark all dead jobs as notified, so delete_job () cleans them out - of the job table properly. POSIX.2 says we need to save the - status of the last CHILD_MAX jobs, so we count the number of dead - jobs and mark only enough as notified to save CHILD_MAX statuses. */ -static void -mark_dead_jobs_as_notified (force) - int force; -{ - register int i, ndead, ndeadproc; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return; - - BLOCK_CHILD (set, oset); - - /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses - around; just run through the array. */ - if (force) - { - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - jobs[i]->flags |= J_NOTIFIED; - } - UNBLOCK_CHILD (oset); - return; - } - - /* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the - array with the corresponding not marked as notified. This is a better - way to avoid pid aliasing and reuse problems than keeping the POSIX- - mandated CHILD_MAX jobs around. delete_job() takes care of keeping the - bgpids list regulated. */ - - /* Count the number of dead jobs */ - /* XXX could use js.j_firstj here */ - for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && DEADJOB (i)) - { - ndead++; - ndeadproc += processes_in_job (i); - } - } - -#ifdef DEBUG - if (ndeadproc != js.c_reaped) - itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped); - if (ndead != js.j_ndead) - itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead); -#endif - - if (js.c_childmax < 0) - js.c_childmax = getmaxchild (); - if (js.c_childmax < 0) - js.c_childmax = DEFAULT_CHILD_MAX; - - /* Don't do anything if the number of dead processes is less than CHILD_MAX - and we're not forcing a cleanup. */ - if (ndeadproc <= js.c_childmax) - { - UNBLOCK_CHILD (oset); - return; - } - -#if 0 -itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc); -#endif - - /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in - the list. This isn't exactly right yet; changes need to be made - to stop_pipeline so we don't mark the newer jobs after we've - created CHILD_MAX slots in the jobs array. This needs to be - integrated with a way to keep the jobs array from growing without - bound. Maybe we wrap back around to 0 after we reach some max - limit, and there are sufficient job slots free (keep track of total - size of jobs array (js.j_jobslots) and running count of number of jobs - in jobs array. Then keep a job index corresponding to the `oldest job' - and start this loop there, wrapping around as necessary. In effect, - we turn the list into a circular buffer. */ - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - /* If marking this job as notified would drop us down below - child_max, don't mark it so we can keep at least child_max - statuses. XXX -- need to check what Posix actually says - about keeping statuses. */ - if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax) - break; - jobs[i]->flags |= J_NOTIFIED; - } - } - - UNBLOCK_CHILD (oset); -} - -/* Here to allow other parts of the shell (like the trap stuff) to - freeze and unfreeze the jobs list. */ -void -freeze_jobs_list () -{ - jobs_list_frozen = 1; -} - -void -unfreeze_jobs_list () -{ - jobs_list_frozen = 0; -} - -/* Allow or disallow job control to take place. Returns the old value - of job_control. */ -int -set_job_control (arg) - int arg; -{ - int old; - - old = job_control; - job_control = arg; - - /* If we're turning on job control, reset pipeline_pgrp so make_child will - put new child processes into the right pgrp */ - if (job_control != old && job_control) - pipeline_pgrp = 0; - - return (old); -} - -/* Turn off all traces of job control. This is run by children of the shell - which are going to do shellsy things, like wait (), etc. */ -void -without_job_control () -{ - stop_making_children (); - start_pipeline (); -#if defined (PGRP_PIPE) - sh_closepipe (pgrp_pipe); -#endif - delete_all_jobs (0); - set_job_control (0); -} - -/* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. This is done - before the `exec' builtin calls shell_execve. */ -void -end_job_control () -{ - if (interactive_shell) /* XXX - should it be interactive? */ - { - terminate_stopped_jobs (); - - if (original_pgrp >= 0) - give_terminal_to (original_pgrp, 1); - } - - if (original_pgrp >= 0) - setpgid (0, original_pgrp); -} - -/* Restart job control by closing shell tty and reinitializing. This is - called after an exec fails in an interactive shell and we do not exit. */ -void -restart_job_control () -{ - if (shell_tty != -1) - close (shell_tty); - initialize_job_control (0); -} - -/* Set the handler to run when the shell receives a SIGCHLD signal. */ -void -set_sigchld_handler () -{ - set_signal_handler (SIGCHLD, sigchld_handler); -} - -#if defined (PGRP_PIPE) -/* Read from the read end of a pipe. This is how the process group leader - blocks until all of the processes in a pipeline have been made. */ -static void -pipe_read (pp) - int *pp; -{ - char ch; - - if (pp[1] >= 0) - { - close (pp[1]); - pp[1] = -1; - } - - if (pp[0] >= 0) - { - while (read (pp[0], &ch, 1) == -1 && errno == EINTR) - ; - } -} - -/* Functional interface closes our local-to-job-control pipes. */ -void -close_pgrp_pipe () -{ - sh_closepipe (pgrp_pipe); -} - -void -save_pgrp_pipe (p, clear) - int *p; - int clear; -{ - p[0] = pgrp_pipe[0]; - p[1] = pgrp_pipe[1]; - if (clear) - pgrp_pipe[0] = pgrp_pipe[1] = -1; -} - -void -restore_pgrp_pipe (p) - int *p; -{ - pgrp_pipe[0] = p[0]; - pgrp_pipe[1] = p[1]; -} - -#endif /* PGRP_PIPE */ diff --git a/lib/glob/glob.c~ b/lib/glob/glob.c~ deleted file mode 100644 index 43169bb51..000000000 --- a/lib/glob/glob.c~ +++ /dev/null @@ -1,1249 +0,0 @@ -/* glob.c -- file-name wildcard pattern matching for Bash. - - Copyright (C) 1985-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne-Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* To whomever it may concern: I have never seen the code which most - Unix programs use to perform this function. I wrote this from scratch - based on specifications for the pattern matching. --RMS. */ - -#include - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixdir.h" -#include "posixstat.h" -#include "shmbutil.h" -#include "xmalloc.h" - -#include "filecntl.h" -#if !defined (F_OK) -# define F_OK 0 -#endif - -#include "stdc.h" -#include "memalloc.h" - -#include - -#include "shell.h" - -#include "glob.h" -#include "strmatch.h" - -#if !defined (HAVE_BCOPY) && !defined (bcopy) -# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) -#endif /* !HAVE_BCOPY && !bcopy */ - -#if !defined (NULL) -# if defined (__STDC__) -# define NULL ((void *) 0) -# else -# define NULL 0x0 -# endif /* __STDC__ */ -#endif /* !NULL */ - -#if !defined (FREE) -# define FREE(x) if (x) free (x) -#endif - -/* Don't try to alloca() more than this much memory for `struct globval' - in glob_vector() */ -#ifndef ALLOCA_MAX -# define ALLOCA_MAX 100000 -#endif - -struct globval - { - struct globval *next; - char *name; - }; - -extern void throw_to_top_level __P((void)); -extern int sh_eaccess __P((char *, int)); -extern char *sh_makepath __P((const char *, const char *, int)); - -extern int extended_glob; - -/* Global variable which controls whether or not * matches .*. - Non-zero means don't match .*. */ -int noglob_dot_filenames = 1; - -/* Global variable which controls whether or not filename globbing - is done without regard to case. */ -int glob_ignore_case = 0; - -/* Global variable to return to signify an error in globbing. */ -char *glob_error_return; - -static struct globval finddirs_error_return; - -/* Some forward declarations. */ -static int skipname __P((char *, char *, int)); -#if HANDLE_MULTIBYTE -static int mbskipname __P((char *, char *, int)); -#endif -#if HANDLE_MULTIBYTE -static void udequote_pathname __P((char *)); -static void wdequote_pathname __P((char *)); -#else -# define dequote_pathname udequote_pathname -#endif -static void dequote_pathname __P((char *)); -static int glob_testdir __P((char *)); -static char **glob_dir_to_array __P((char *, char **, int)); - -/* Make sure these names continue to agree with what's in smatch.c */ -extern char *glob_patscan __P((char *, char *, int)); -extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int)); - -/* Compile `glob_loop.c' for single-byte characters. */ -#define CHAR unsigned char -#define INT int -#define L(CS) CS -#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p -#include "glob_loop.c" - -/* Compile `glob_loop.c' again for multibyte characters. */ -#if HANDLE_MULTIBYTE - -#define CHAR wchar_t -#define INT wint_t -#define L(CS) L##CS -#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p -#include "glob_loop.c" - -#endif /* HANDLE_MULTIBYTE */ - -/* And now a function that calls either the single-byte or multibyte version - of internal_glob_pattern_p. */ -int -glob_pattern_p (pattern) - const char *pattern; -{ -#if HANDLE_MULTIBYTE - size_t n; - wchar_t *wpattern; - int r; - - if (MB_CUR_MAX == 1) - return (internal_glob_pattern_p ((unsigned char *)pattern)); - - /* Convert strings to wide chars, and call the multibyte version. */ - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - /* Oops. Invalid multibyte sequence. Try it as single-byte sequence. */ - return (internal_glob_pattern_p ((unsigned char *)pattern)); - - r = internal_glob_wpattern_p (wpattern); - free (wpattern); - - return r; -#else - return (internal_glob_pattern_p (pattern)); -#endif -} - -#if EXTENDED_GLOB -/* Return 1 if all subpatterns in the extended globbing pattern PAT indicate - that the name should be skipped. XXX - doesn't handle pattern negation, - not sure if it should */ -static int -extglob_skipname (pat, dname, flags) - char *pat, *dname; - int flags; -{ - char *pp, *pe, *t; - int n, r; - - pp = pat + 2; - pe = pp + strlen (pp) - 1; /*(*/ - if (*pe != ')') - return 0; - if ((t = strchr (pp, '|')) == 0) /* easy case first */ - { - *pe = '\0'; - r = skipname (pp, dname, flags); /*(*/ - *pe = ')'; - return r; - } - while (t = glob_patscan (pp, pe, '|')) - { - n = t[-1]; - t[-1] = '\0'; - r = skipname (pp, dname, flags); - t[-1] = n; - if (r == 0) /* if any pattern says not skip, we don't skip */ - return r; - pp = t; - } /*(*/ - - if (pp == pe) /* glob_patscan might find end of pattern */ - return r; - - *pe = '\0'; - r = mbskipname (pp, dname, flags); /*(*/ - *pe = ')'; - return r; -} -#endif - -/* Return 1 if DNAME should be skipped according to PAT. Mostly concerned - with matching leading `.'. */ -static int -skipname (pat, dname, flags) - char *pat; - char *dname; - int flags; -{ -#if EXTENDED_GLOB - if (extglob_pattern (pat)) /* XXX */ - return (extglob_skipname (pat, dname, flags)); -#endif - - /* If a leading dot need not be explicitly matched, and the pattern - doesn't start with a `.', don't match `.' or `..' */ - if (noglob_dot_filenames == 0 && pat[0] != '.' && - (pat[0] != '\\' || pat[1] != '.') && - (dname[0] == '.' && - (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))) - return 1; - - /* If a dot must be explicity matched, check to see if they do. */ - else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' && - (pat[0] != '\\' || pat[1] != '.')) - return 1; - - return 0; -} - -#if HANDLE_MULTIBYTE - -static int -wchkname (pat_wc, dn_wc) - wchar_t *pat_wc, *dn_wc; -{ - /* If a leading dot need not be explicitly matched, and the - pattern doesn't start with a `.', don't match `.' or `..' */ - if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.') && - (dn_wc[0] == L'.' && - (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0')))) - return 1; - - /* If a leading dot must be explicity matched, check to see if the - pattern and dirname both have one. */ - else if (noglob_dot_filenames && dn_wc[0] == L'.' && - pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.')) - return 1; - - return 0; -} - -static int -wextglob_skipname (pat, dname, flags) - wchar_t *pat, *dname; - int flags; -{ -#if EXTENDED_GLOB - wchar_t *pp, *pe, *t, n; - int r; - - pp = pat + 2; - pe = pp + wcslen (pp) - 1; /*(*/ - if (*pe != L')') - return 0; - if ((t = wcschr (pp, L'|')) == 0) - { - *pe = L'\0'; - r = wchkname (pp, dname); /*(*/ - *pe = L')'; - return r; - } - while (t = glob_patscan_wc (pp, pe, '|')) - { - n = t[-1]; - t[-1] = L'\0'; - r = wchkname (pp, dname); - t[-1] = n; - if (r == 0) - return 0; - pp = t; - } - - if (pp == pe) /* glob_patscan_wc might find end of pattern */ - return r; - - *pe = L'\0'; - r = wchkname (pp, dname); /*(*/ - *pe = L')'; - return r; -#else - return (wchkname (pat, dname)); -#endif -} - -/* Return 1 if DNAME should be skipped according to PAT. Handles multibyte - characters in PAT and DNAME. Mostly concerned with matching leading `.'. */ -static int -mbskipname (pat, dname, flags) - char *pat, *dname; - int flags; -{ - int ret, ext; - wchar_t *pat_wc, *dn_wc; - size_t pat_n, dn_n; - - if (mbsmbchar (dname) == 0 && mbsmbchar (pat) == 0) - return (skipname (pat, dname, flags)); - - ext = 0; -#if EXTENDED_GLOB - ext = extglob_pattern (pat); -#endif - - pat_wc = dn_wc = (wchar_t *)NULL; - - pat_n = xdupmbstowcs (&pat_wc, NULL, pat); - if (pat_n != (size_t)-1) - dn_n = xdupmbstowcs (&dn_wc, NULL, dname); - - ret = 0; - if (pat_n != (size_t)-1 && dn_n !=(size_t)-1) - ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wchkname (pat_wc, dn_wc); - else - ret = skipname (pat, dname, flags); - - FREE (pat_wc); - FREE (dn_wc); - - return ret; -} -#endif /* HANDLE_MULTIBYTE */ - -/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ -static void -udequote_pathname (pathname) - char *pathname; -{ - register int i, j; - - for (i = j = 0; pathname && pathname[i]; ) - { - if (pathname[i] == '\\') - i++; - - pathname[j++] = pathname[i++]; - - if (pathname[i - 1] == 0) - break; - } - if (pathname) - pathname[j] = '\0'; -} - -#if HANDLE_MULTIBYTE -/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */ -static void -wdequote_pathname (pathname) - char *pathname; -{ - mbstate_t ps; - size_t len, n; - wchar_t *wpathname; - int i, j; - wchar_t *orig_wpathname; - - len = strlen (pathname); - /* Convert the strings into wide characters. */ - n = xdupmbstowcs (&wpathname, NULL, pathname); - if (n == (size_t) -1) - /* Something wrong. Fall back to single-byte */ - return udequote_pathname (pathname); - orig_wpathname = wpathname; - - for (i = j = 0; wpathname && wpathname[i]; ) - { - if (wpathname[i] == L'\\') - i++; - - wpathname[j++] = wpathname[i++]; - - if (wpathname[i - 1] == L'\0') - break; - } - if (wpathname) - wpathname[j] = L'\0'; - - /* Convert the wide character string into unibyte character set. */ - memset (&ps, '\0', sizeof(mbstate_t)); - n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps); - pathname[len] = '\0'; - - /* Can't just free wpathname here; wcsrtombs changes it in many cases. */ - free (orig_wpathname); -} - -static void -dequote_pathname (pathname) - char *pathname; -{ - if (MB_CUR_MAX > 1) - wdequote_pathname (pathname); - else - udequote_pathname (pathname); -} -#endif /* HANDLE_MULTIBYTE */ - -/* Test whether NAME exists. */ - -#if defined (HAVE_LSTAT) -# define GLOB_TESTNAME(name) (lstat (name, &finfo)) -#else /* !HAVE_LSTAT */ -# if !defined (AFS) -# define GLOB_TESTNAME(name) (sh_eaccess (name, F_OK)) -# else /* AFS */ -# define GLOB_TESTNAME(name) (access (name, F_OK)) -# endif /* AFS */ -#endif /* !HAVE_LSTAT */ - -/* Return 0 if DIR is a directory, -1 otherwise. */ -static int -glob_testdir (dir) - char *dir; -{ - struct stat finfo; - -/*itrace("glob_testdir: testing %s", dir);*/ - if (stat (dir, &finfo) < 0) - return (-1); - - if (S_ISDIR (finfo.st_mode) == 0) - return (-1); - - return (0); -} - -/* Recursively scan SDIR for directories matching PAT (PAT is always `**'). - FLAGS is simply passed down to the recursive call to glob_vector. Returns - a list of matching directory names. EP, if non-null, is set to the last - element of the returned list. NP, if non-null, is set to the number of - directories in the returned list. These two variables exist for the - convenience of the caller (always glob_vector). */ -static struct globval * -finddirs (pat, sdir, flags, ep, np) - char *pat; - char *sdir; - int flags; - struct globval **ep; - int *np; -{ - char **r, *n; - int ndirs; - struct globval *ret, *e, *g; - -/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/ - e = ret = 0; - r = glob_vector (pat, sdir, flags); - if (r == 0 || r[0] == 0) - { - if (np) - *np = 0; - if (ep) - *ep = 0; - if (r && r != &glob_error_return) - free (r); - return (struct globval *)0; - } - for (ndirs = 0; r[ndirs] != 0; ndirs++) - { - g = (struct globval *) malloc (sizeof (struct globval)); - if (g == 0) - { - while (ret) /* free list built so far */ - { - g = ret->next; - free (ret); - ret = g; - } - - free (r); - if (np) - *np = 0; - if (ep) - *ep = 0; - return (&finddirs_error_return); - } - if (e == 0) - e = g; - - g->next = ret; - ret = g; - - g->name = r[ndirs]; - } - - free (r); - if (ep) - *ep = e; - if (np) - *np = ndirs; - - return ret; -} - -/* Return a vector of names of files in directory DIR - whose names match glob pattern PAT. - The names are not in any particular order. - Wildcards at the beginning of PAT do not match an initial period. - - The vector is terminated by an element that is a null pointer. - - To free the space allocated, first free the vector's elements, - then free the vector. - - Return 0 if cannot get enough memory to hold the pointer - and the names. - - Return -1 if cannot access directory DIR. - Look in errno for more information. */ - -char ** -glob_vector (pat, dir, flags) - char *pat; - char *dir; - int flags; -{ - DIR *d; - register struct dirent *dp; - struct globval *lastlink, *e, *dirlist; - register struct globval *nextlink; - register char *nextname, *npat, *subdir; - unsigned int count; - int lose, skip, ndirs, isdir, sdlen, add_current, patlen; - register char **name_vector; - register unsigned int i; - int mflags; /* Flags passed to strmatch (). */ - int pflags; /* flags passed to sh_makepath () */ - int nalloca; - struct globval *firstmalloc, *tmplink; - char *convfn; - - lastlink = 0; - count = lose = skip = add_current = 0; - - firstmalloc = 0; - nalloca = 0; - -/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/ - /* If PAT is empty, skip the loop, but return one (empty) filename. */ - if (pat == 0 || *pat == '\0') - { - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); - - nextlink = (struct globval *)alloca (sizeof (struct globval)); - if (nextlink == NULL) - return ((char **) NULL); - - nextlink->next = (struct globval *)0; - nextname = (char *) malloc (1); - if (nextname == 0) - lose = 1; - else - { - lastlink = nextlink; - nextlink->name = nextname; - nextname[0] = '\0'; - count = 1; - } - - skip = 1; - } - - patlen = (pat && *pat) ? strlen (pat) : 0; - - /* If the filename pattern (PAT) does not contain any globbing characters, - we can dispense with reading the directory, and just see if there is - a filename `DIR/PAT'. If there is, and we can access it, just make the - vector to return and bail immediately. */ - if (skip == 0 && glob_pattern_p (pat) == 0) - { - int dirlen; - struct stat finfo; - - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); - - dirlen = strlen (dir); - nextname = (char *)malloc (dirlen + patlen + 2); - npat = (char *)malloc (patlen + 1); - if (nextname == 0 || npat == 0) - { - FREE (nextname); - FREE (npat); - lose = 1; - } - else - { - strcpy (npat, pat); - dequote_pathname (npat); - - strcpy (nextname, dir); - nextname[dirlen++] = '/'; - strcpy (nextname + dirlen, npat); - - if (GLOB_TESTNAME (nextname) >= 0) - { - free (nextname); - nextlink = (struct globval *)alloca (sizeof (struct globval)); - if (nextlink) - { - nextlink->next = (struct globval *)0; - lastlink = nextlink; - nextlink->name = npat; - count = 1; - } - else - { - free (npat); - lose = 1; - } - } - else - { - free (nextname); - free (npat); - } - } - - skip = 1; - } - - if (skip == 0) - { - /* Open the directory, punting immediately if we cannot. If opendir - is not robust (i.e., it opens non-directories successfully), test - that DIR is a directory and punt if it's not. */ -#if defined (OPENDIR_NOT_ROBUST) - if (glob_testdir (dir) < 0) - return ((char **) &glob_error_return); -#endif - - d = opendir (dir); - if (d == NULL) - return ((char **) &glob_error_return); - - /* Compute the flags that will be passed to strmatch(). We don't - need to do this every time through the loop. */ - mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; - -#ifdef FNM_CASEFOLD - if (glob_ignore_case) - mflags |= FNM_CASEFOLD; -#endif - - if (extended_glob) - mflags |= FNM_EXTMATCH; - - add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR)); - - /* Scan the directory, finding all names that match. - For each name that matches, allocate a struct globval - on the stack and store the name in it. - Chain those structs together; lastlink is the front of the chain. */ - while (1) - { - /* Make globbing interruptible in the shell. */ - if (interrupt_state || terminating_signal) - { - lose = 1; - break; - } - else if (signal_is_pending (SIGINT)) /* XXX - make SIGINT traps responsive */ - { - lose = 1; - break; - } - - dp = readdir (d); - if (dp == NULL) - break; - - /* If this directory entry is not to be used, try again. */ - if (REAL_DIR_ENTRY (dp) == 0) - continue; - -#if 0 - if (dp->d_name == 0 || *dp->d_name == 0) - continue; -#endif - -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags)) - continue; - else -#endif - if (skipname (pat, dp->d_name, flags)) - continue; - - /* If we're only interested in directories, don't bother with files */ - if (flags & (GX_MATCHDIRS|GX_ALLDIRS)) - { - pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0; - if (flags & GX_NULLDIR) - pflags |= MP_IGNDOT; - subdir = sh_makepath (dir, dp->d_name, pflags); - isdir = glob_testdir (subdir); - if (isdir < 0 && (flags & GX_MATCHDIRS)) - { - free (subdir); - continue; - } - } - - if (flags & GX_ALLDIRS) - { - if (isdir == 0) - { - dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs); - if (dirlist == &finddirs_error_return) - { - free (subdir); - lose = 1; - break; - } - if (ndirs) /* add recursive directories to list */ - { - if (firstmalloc == 0) - firstmalloc = e; - e->next = lastlink; - lastlink = dirlist; - count += ndirs; - } - } - - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (firstmalloc == 0) - firstmalloc = nextlink; - sdlen = strlen (subdir); - nextname = (char *) malloc (sdlen + 1); - if (nextlink == 0 || nextname == 0) - { - FREE (nextlink); - FREE (nextname); - free (subdir); - lose = 1; - break; - } - nextlink->next = lastlink; - lastlink = nextlink; - nextlink->name = nextname; - bcopy (subdir, nextname, sdlen + 1); - free (subdir); - ++count; - continue; - } - else if (flags & GX_MATCHDIRS) - free (subdir); - - convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp)); - if (strmatch (pat, convfn, mflags) != FNM_NOMATCH) - { - if (nalloca < ALLOCA_MAX) - { - nextlink = (struct globval *) alloca (sizeof (struct globval)); - nalloca += sizeof (struct globval); - } - else - { - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (firstmalloc == 0) - firstmalloc = nextlink; - } - - nextname = (char *) malloc (D_NAMLEN (dp) + 1); - if (nextlink == 0 || nextname == 0) - { - FREE (nextlink); - FREE (nextname); - lose = 1; - break; - } - nextlink->next = lastlink; - lastlink = nextlink; - nextlink->name = nextname; - bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); - ++count; - } - } - - (void) closedir (d); - } - - /* compat: if GX_ADDCURDIR, add the passed directory also. Add an empty - directory name as a placeholder if GX_NULLDIR (in which case the passed - directory name is "."). */ - if (add_current) - { - sdlen = strlen (dir); - nextname = (char *)malloc (sdlen + 1); - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (nextlink == 0 || nextname == 0) - { - FREE (nextlink); - FREE (nextname); - lose = 1; - } - else - { - nextlink->name = nextname; - nextlink->next = lastlink; - lastlink = nextlink; - if (flags & GX_NULLDIR) - nextname[0] = '\0'; - else - bcopy (dir, nextname, sdlen + 1); - ++count; - } - } - - if (lose == 0) - { - name_vector = (char **) malloc ((count + 1) * sizeof (char *)); - lose |= name_vector == NULL; - } - - /* Have we run out of memory? */ - if (lose) - { - tmplink = 0; - - /* Here free the strings we have got. */ - while (lastlink) - { - /* Since we build the list in reverse order, the first N entries - will be allocated with malloc, if firstmalloc is set, from - lastlink to firstmalloc. */ - if (firstmalloc) - { - if (lastlink == firstmalloc) - firstmalloc = 0; - tmplink = lastlink; - } - else - tmplink = 0; - free (lastlink->name); - lastlink = lastlink->next; - FREE (tmplink); - } - - /* Don't call QUIT; here; let higher layers deal with it. */ - - return ((char **)NULL); - } - - /* Copy the name pointers from the linked list into the vector. */ - for (tmplink = lastlink, i = 0; i < count; ++i) - { - name_vector[i] = tmplink->name; - tmplink = tmplink->next; - } - - name_vector[count] = NULL; - - /* If we allocated some of the struct globvals, free them now. */ - if (firstmalloc) - { - tmplink = 0; - while (lastlink) - { - tmplink = lastlink; - if (lastlink == firstmalloc) - lastlink = firstmalloc = 0; - else - lastlink = lastlink->next; - free (tmplink); - } - } - - return (name_vector); -} - -/* Return a new array which is the concatenation of each string in ARRAY - to DIR. This function expects you to pass in an allocated ARRAY, and - it takes care of free()ing that array. Thus, you might think of this - function as side-effecting ARRAY. This should handle GX_MARKDIRS. */ -static char ** -glob_dir_to_array (dir, array, flags) - char *dir, **array; - int flags; -{ - register unsigned int i, l; - int add_slash; - char **result, *new; - struct stat sb; - - l = strlen (dir); - if (l == 0) - { - if (flags & GX_MARKDIRS) - for (i = 0; array[i]; i++) - { - if ((stat (array[i], &sb) == 0) && S_ISDIR (sb.st_mode)) - { - l = strlen (array[i]); - new = (char *)realloc (array[i], l + 2); - if (new == 0) - return NULL; - new[l] = '/'; - new[l+1] = '\0'; - array[i] = new; - } - } - return (array); - } - - add_slash = dir[l - 1] != '/'; - - i = 0; - while (array[i] != NULL) - ++i; - - result = (char **) malloc ((i + 1) * sizeof (char *)); - if (result == NULL) - return (NULL); - - for (i = 0; array[i] != NULL; i++) - { - /* 3 == 1 for NUL, 1 for slash at end of DIR, 1 for GX_MARKDIRS */ - result[i] = (char *) malloc (l + strlen (array[i]) + 3); - - if (result[i] == NULL) - { - int ind; - for (ind = 0; ind < i; ind++) - free (result[ind]); - free (result); - return (NULL); - } - - strcpy (result[i], dir); - if (add_slash) - result[i][l] = '/'; - strcpy (result[i] + l + add_slash, array[i]); - if (flags & GX_MARKDIRS) - { - if ((stat (result[i], &sb) == 0) && S_ISDIR (sb.st_mode)) - { - size_t rlen; - rlen = strlen (result[i]); - result[i][rlen] = '/'; - result[i][rlen+1] = '\0'; - } - } - } - result[i] = NULL; - - /* Free the input array. */ - for (i = 0; array[i] != NULL; i++) - free (array[i]); - free ((char *) array); - - return (result); -} - -/* Do globbing on PATHNAME. Return an array of pathnames that match, - marking the end of the array with a null-pointer as an element. - If no pathnames match, then the array is empty (first element is null). - If there isn't enough memory, then return NULL. - If a file system error occurs, return -1; `errno' has the error code. */ -char ** -glob_filename (pathname, flags) - char *pathname; - int flags; -{ - char **result; - unsigned int result_size; - char *directory_name, *filename, *dname; - unsigned int directory_len; - int free_dirname; /* flag */ - int dflags; - - result = (char **) malloc (sizeof (char *)); - result_size = 1; - if (result == NULL) - return (NULL); - - result[0] = NULL; - - directory_name = NULL; - - /* Find the filename. */ - filename = strrchr (pathname, '/'); - if (filename == NULL) - { - filename = pathname; - directory_name = ""; - directory_len = 0; - free_dirname = 0; - } - else - { - directory_len = (filename - pathname) + 1; - directory_name = (char *) malloc (directory_len + 1); - - if (directory_name == 0) /* allocation failed? */ - return (NULL); - - bcopy (pathname, directory_name, directory_len); - directory_name[directory_len] = '\0'; - ++filename; - free_dirname = 1; - } - - /* If directory_name contains globbing characters, then we - have to expand the previous levels. Just recurse. */ - if (glob_pattern_p (directory_name)) - { - char **directories; - register unsigned int i; - - dflags = flags & ~GX_MARKDIRS; - if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0')) - dflags |= GX_ALLDIRS|GX_ADDCURDIR; - - if (directory_name[directory_len - 1] == '/') - directory_name[directory_len - 1] = '\0'; - - directories = glob_filename (directory_name, dflags); - - if (free_dirname) - { - free (directory_name); - directory_name = NULL; - } - - if (directories == NULL) - goto memory_error; - else if (directories == (char **)&glob_error_return) - { - free ((char *) result); - return ((char **) &glob_error_return); - } - else if (*directories == NULL) - { - free ((char *) directories); - free ((char *) result); - return ((char **) &glob_error_return); - } - - /* We have successfully globbed the preceding directory name. - For each name in DIRECTORIES, call glob_vector on it and - FILENAME. Concatenate the results together. */ - for (i = 0; directories[i] != NULL; ++i) - { - char **temp_results; - - /* XXX -- we've recursively scanned any directories resulting from - a `**', so turn off the flag. We turn it on again below if - filename is `**' */ - /* Scan directory even on a NULL filename. That way, `*h/' - returns only directories ending in `h', instead of all - files ending in `h' with a `/' appended. */ - dname = directories[i]; - dflags = flags & ~(GX_MARKDIRS|GX_ALLDIRS|GX_ADDCURDIR); - if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - dflags |= GX_ALLDIRS|GX_ADDCURDIR; - if (dname[0] == '\0' && filename[0]) - { - dflags |= GX_NULLDIR; - dname = "."; /* treat null directory name and non-null filename as current directory */ - } - temp_results = glob_vector (filename, dname, dflags); - - /* Handle error cases. */ - if (temp_results == NULL) - goto memory_error; - else if (temp_results == (char **)&glob_error_return) - /* This filename is probably not a directory. Ignore it. */ - ; - else - { - char **array; - register unsigned int l; - - /* If we're expanding **, we don't need to glue the directory - name to the results; we've already done it in glob_vector */ - if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - array = temp_results; - else - array = glob_dir_to_array (directories[i], temp_results, flags); - l = 0; - while (array[l] != NULL) - ++l; - - result = - (char **)realloc (result, (result_size + l) * sizeof (char *)); - - if (result == NULL) - goto memory_error; - - for (l = 0; array[l] != NULL; ++l) - result[result_size++ - 1] = array[l]; - - result[result_size - 1] = NULL; - - /* Note that the elements of ARRAY are not freed. */ - if (array != temp_results) - free ((char *) array); - else if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - free (temp_results); /* expanding ** case above */ - } - } - /* Free the directories. */ - for (i = 0; directories[i]; i++) - free (directories[i]); - - free ((char *) directories); - - return (result); - } - - /* If there is only a directory name, return it. */ - if (*filename == '\0') - { - result = (char **) realloc ((char *) result, 2 * sizeof (char *)); - if (result == NULL) - return (NULL); - /* Handle GX_MARKDIRS here. */ - result[0] = (char *) malloc (directory_len + 1); - if (result[0] == NULL) - goto memory_error; - bcopy (directory_name, result[0], directory_len + 1); - if (free_dirname) - free (directory_name); - result[1] = NULL; - return (result); - } - else - { - char **temp_results; - - /* There are no unquoted globbing characters in DIRECTORY_NAME. - Dequote it before we try to open the directory since there may - be quoted globbing characters which should be treated verbatim. */ - if (directory_len > 0) - dequote_pathname (directory_name); - - /* We allocated a small array called RESULT, which we won't be using. - Free that memory now. */ - free (result); - - /* Just return what glob_vector () returns appended to the - directory name. */ - /* If flags & GX_ALLDIRS, we're called recursively */ - dflags = flags & ~GX_MARKDIRS; - if (directory_len == 0) - dflags |= GX_NULLDIR; - if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - { - dflags |= GX_ALLDIRS|GX_ADDCURDIR; -#if 0 - /* If we want all directories (dflags & GX_ALLDIRS) and we're not - being called recursively as something like `echo [star][star]/[star].o' - ((flags & GX_ALLDIRS) == 0), we want to prevent glob_vector from - adding a null directory name to the front of the temp_results - array. We turn off ADDCURDIR if not called recursively and - dlen == 0 */ -#endif - if (directory_len == 0 && (flags & GX_ALLDIRS) == 0) - dflags &= ~GX_ADDCURDIR; - } - temp_results = glob_vector (filename, - (directory_len == 0 ? "." : directory_name), - dflags); - - if (temp_results == NULL || temp_results == (char **)&glob_error_return) - { - if (free_dirname) - free (directory_name); - QUIT; /* XXX - shell */ - run_pending_traps (); - return (temp_results); - } - - result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags); - if (free_dirname) - free (directory_name); - return (result); - } - - /* We get to memory_error if the program has run out of memory, or - if this is the shell, and we have been interrupted. */ - memory_error: - if (result != NULL) - { - register unsigned int i; - for (i = 0; result[i] != NULL; ++i) - free (result[i]); - free ((char *) result); - } - - if (free_dirname && directory_name) - free (directory_name); - - QUIT; - run_pending_traps (); - - return (NULL); -} - -#if defined (TEST) - -main (argc, argv) - int argc; - char **argv; -{ - unsigned int i; - - for (i = 1; i < argc; ++i) - { - char **value = glob_filename (argv[i], 0); - if (value == NULL) - puts ("Out of memory."); - else if (value == &glob_error_return) - perror (argv[i]); - else - for (i = 0; value[i] != NULL; i++) - puts (value[i]); - } - - exit (0); -} -#endif /* TEST. */ diff --git a/lib/malloc/getpagesize.h~ b/lib/malloc/getpagesize.h~ deleted file mode 100644 index 7f3234006..000000000 --- a/lib/malloc/getpagesize.h~ +++ /dev/null @@ -1,60 +0,0 @@ -/* Emulation of getpagesize() for systems that need it. - Copyright (C) 1991-2003 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 . -*/ - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -# if defined (_SC_PAGESIZE) -# define getpagesize() sysconf(_SC_PAGESIZE) -# else -# if defined (_SC_PAGE_SIZE) -# define getpagesize() sysconf(_SC_PAGE_SIZE) -# endif /* _SC_PAGE_SIZE */ -# endif /* _SC_PAGESIZE */ -#endif - -#if !defined (getpagesize) -# ifndef _MINIX -# include -# endif -# if defined (PAGESIZE) -# define getpagesize() PAGESIZE -# else /* !PAGESIZE */ -# if defined (EXEC_PAGESIZE) -# define getpagesize() EXEC_PAGESIZE -# else /* !EXEC_PAGESIZE */ -# if defined (NBPG) -# if !defined (CLSIZE) -# define CLSIZE 1 -# endif /* !CLSIZE */ -# define getpagesize() (NBPG * CLSIZE) -# else /* !NBPG */ -# if defined (NBPC) -# define getpagesize() NBPC -# endif /* NBPC */ -# endif /* !NBPG */ -# endif /* !EXEC_PAGESIZE */ -# endif /* !PAGESIZE */ -#endif /* !getpagesize */ - -#if !defined (getpagesize) -# define getpagesize() 4096 /* Just punt and use reasonable value */ -#endif diff --git a/lib/readline/callback.c~ b/lib/readline/callback.c~ deleted file mode 100644 index 438b31153..000000000 --- a/lib/readline/callback.c~ +++ /dev/null @@ -1,289 +0,0 @@ -/* callback.c -- functions to use readline as an X `callback' mechanism. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include "rlconf.h" - -#if defined (READLINE_CALLBACKS) - -#include - -#ifdef HAVE_STDLIB_H -# include -#else -# include "ansi_stdlib.h" -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "readline.h" -#include "rlprivate.h" -#include "xmalloc.h" - -/* Private data for callback registration functions. See comments in - rl_callback_read_char for more details. */ -_rl_callback_func_t *_rl_callback_func = 0; -_rl_callback_generic_arg *_rl_callback_data = 0; - -/* **************************************************************** */ -/* */ -/* Callback Readline Functions */ -/* */ -/* **************************************************************** */ - -/* Allow using readline in situations where a program may have multiple - things to handle at once, and dispatches them via select(). Call - rl_callback_handler_install() with the prompt and a function to call - whenever a complete line of input is ready. The user must then - call rl_callback_read_char() every time some input is available, and - rl_callback_read_char() will call the user's function with the complete - text read in at each end of line. The terminal is kept prepped - all the time, except during calls to the user's function. Signal - handlers are only installed when the application calls back into - readline, so readline doesn't `steal' signals from the application. */ - -rl_vcpfunc_t *rl_linefunc; /* user callback function */ -static int in_handler; /* terminal_prepped and signals set? */ - -/* Make sure the terminal is set up, initialize readline, and prompt. */ -static void -_rl_callback_newline () -{ - rl_initialize (); - - if (in_handler == 0) - { - in_handler = 1; - - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - } - - readline_internal_setup (); - RL_CHECK_SIGNALS (); -} - -/* Install a readline handler, set up the terminal, and issue the prompt. */ -void -rl_callback_handler_install (prompt, linefunc) - const char *prompt; - rl_vcpfunc_t *linefunc; -{ - rl_set_prompt (prompt); - RL_SETSTATE (RL_STATE_CALLBACK); - rl_linefunc = linefunc; - _rl_callback_newline (); -} - -#if defined (HANDLE_SIGNALS) -#define CALLBACK_READ_RETURN() \ - do { \ - rl_clear_signals (); \ - return; \ - } while (0) -#else -#define CALLBACK_READ_RETURN() return -#endif - -/* Read one character, and dispatch to the handler if it ends the line. */ -void -rl_callback_read_char () -{ - char *line; - int eof, jcode; - static procenv_t olevel; - - if (rl_linefunc == NULL) - { - _rl_errmsg ("readline_callback_read_char() called with no handler!"); - abort (); - } - - memcpy ((void *)olevel, (void *)_rl_top_level, sizeof (procenv_t)); - jcode = setjmp (_rl_top_level); - if (jcode) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - memcpy ((void *)_rl_top_level, (void *)olevel, sizeof (procenv_t)); - CALLBACK_READ_RETURN (); - } - -#if defined (HANDLE_SIGNALS) - /* Install signal handlers only when readline has control. */ - rl_set_signals (); -#endif - - do - { - RL_CHECK_SIGNALS (); - if (RL_ISSTATE (RL_STATE_ISEARCH)) - { - eof = _rl_isearch_callback (_rl_iscxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_ISEARCH) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - - CALLBACK_READ_RETURN (); - } - else if (RL_ISSTATE (RL_STATE_NSEARCH)) - { - eof = _rl_nsearch_callback (_rl_nscxt); - - CALLBACK_READ_RETURN (); - } -#if defined (VI_MODE) - else if (RL_ISSTATE (RL_STATE_VIMOTION)) - { - eof = _rl_vi_domove_callback (_rl_vimvcxt); - /* Should handle everything, including cleanup, numeric arguments, - and turning off RL_STATE_VIMOTION */ - if (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) - _rl_internal_char_cleanup (); - - CALLBACK_READ_RETURN (); - } -#endif - else if (RL_ISSTATE (RL_STATE_NUMERICARG)) - { - eof = _rl_arg_callback (_rl_argcxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - /* XXX - this should handle _rl_last_command_was_kill better */ - else if (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) - _rl_internal_char_cleanup (); - - CALLBACK_READ_RETURN (); - } - else if (RL_ISSTATE (RL_STATE_MULTIKEY)) - { - eof = _rl_dispatch_callback (_rl_kscxt); /* For now */ - while ((eof == -1 || eof == -2) && RL_ISSTATE (RL_STATE_MULTIKEY) && _rl_kscxt && (_rl_kscxt->flags & KSEQ_DISPATCHED)) - eof = _rl_dispatch_callback (_rl_kscxt); - if (RL_ISSTATE (RL_STATE_MULTIKEY) == 0) - { - _rl_internal_char_cleanup (); - _rl_want_redisplay = 1; - } - } - else if (_rl_callback_func) - { - /* This allows functions that simply need to read an additional - character (like quoted-insert) to register a function to be - called when input is available. _rl_callback_data is simply a - pointer to a struct that has the argument count originally - passed to the registering function and space for any additional - parameters. */ - eof = (*_rl_callback_func) (_rl_callback_data); - /* If the function `deregisters' itself, make sure the data is - cleaned up. */ - if (_rl_callback_func == 0) - { - if (_rl_callback_data) - { - _rl_callback_data_dispose (_rl_callback_data); - _rl_callback_data = 0; - } - _rl_internal_char_cleanup (); - } - } - else - eof = readline_internal_char (); - - RL_CHECK_SIGNALS (); - if (rl_done == 0 && _rl_want_redisplay) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - if (rl_done) - { - line = readline_internal_teardown (eof); - - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - in_handler = 0; - (*rl_linefunc) (line); - - /* If the user did not clear out the line, do it for him. */ - if (rl_line_buffer[0]) - _rl_init_line_state (); - - /* Redisplay the prompt if readline_handler_{install,remove} - not called. */ - if (in_handler == 0 && rl_linefunc) - _rl_callback_newline (); - } - } - while (rl_pending_input || _rl_pushed_input_available () || RL_ISSTATE (RL_STATE_MACROINPUT)); - - CALLBACK_READ_RETURN (); -} - -/* Remove the handler, and make sure the terminal is in its normal state. */ -void -rl_callback_handler_remove () -{ - rl_linefunc = NULL; - RL_UNSETSTATE (RL_STATE_CALLBACK); - RL_CHECK_SIGNALS (); - if (in_handler) - { - in_handler = 0; - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - } -} - -_rl_callback_generic_arg * -_rl_callback_data_alloc (count) - int count; -{ - _rl_callback_generic_arg *arg; - - arg = (_rl_callback_generic_arg *)xmalloc (sizeof (_rl_callback_generic_arg)); - arg->count = count; - - arg->i1 = arg->i2 = 0; - - return arg; -} - -void _rl_callback_data_dispose (arg) - _rl_callback_generic_arg *arg; -{ - xfree (arg); -} - -#endif diff --git a/lib/readline/doc/Makefile.old b/lib/readline/doc/Makefile.old deleted file mode 100644 index 58d4dd762..000000000 --- a/lib/readline/doc/Makefile.old +++ /dev/null @@ -1,76 +0,0 @@ -# This makefile for Readline library documentation is in -*- text -*- mode. -# Emacs likes it that way. -RM = rm -f - -MAKEINFO = makeinfo -TEXI2DVI = texi2dvi -TEXI2HTML = texi2html -QUIETPS = #set this to -q to shut up dvips -DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky - -INSTALL_DATA = cp -infodir = /usr/local/info - -RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo -HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo - -DVIOBJ = readline.dvi history.dvi -INFOOBJ = readline.info history.info -PSOBJ = readline.ps history.ps -HTMLOBJ = readline.html history.html - -all: info dvi html ps -nodvi: info html - -readline.dvi: $(RLSRC) - $(TEXI2DVI) rlman.texinfo - mv rlman.dvi readline.dvi - -readline.info: $(RLSRC) - $(MAKEINFO) --no-split -o $@ rlman.texinfo - -history.dvi: ${HISTSRC} - $(TEXI2DVI) hist.texinfo - mv hist.dvi history.dvi - -history.info: ${HISTSRC} - $(MAKEINFO) --no-split -o $@ hist.texinfo - -readline.ps: readline.dvi - $(RM) $@ - $(DVIPS) readline.dvi - -history.ps: history.dvi - $(RM) $@ - $(DVIPS) history.dvi - -readline.html: ${RLSRC} - $(TEXI2HTML) rlman.texinfo - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html - $(RM) rlman.html rlman_toc.html - -history.html: ${HISTSRC} - $(TEXI2HTML) hist.texinfo - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html - $(RM) hist.html hist_toc.html - -info: $(INFOOBJ) -dvi: $(DVIOBJ) -ps: $(PSOBJ) -html: $(HTMLOBJ) - -clean: - $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core - -distclean: clean -mostlyclean: clean - -maintainer-clean: clean - $(RM) *.dvi *.info *.info-* *.ps *.html - -install: info - ${INSTALL_DATA} readline.info $(infodir)/readline.info - ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/readline.c~ b/lib/readline/readline.c~ deleted file mode 100644 index aa89ec4f2..000000000 --- a/lib/readline/readline.c~ +++ /dev/null @@ -1,1317 +0,0 @@ -/* readline.c -- a general facility for reading lines of input - with emacs style editing and completion. */ - -/* Copyright (C) 1987-2012 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include "posixstat.h" -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include -#include "posixjmp.h" -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (__EMX__) -# define INCL_DOSPROCESS -# include -#endif /* __EMX__ */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -#ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "5.1" -#endif - -#ifndef RL_READLINE_VERSION -# define RL_READLINE_VERSION 0x0501 -#endif - -extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); - -/* Forward declarations used in this file. */ -static char *readline_internal PARAMS((void)); -static void readline_initialize_everything PARAMS((void)); - -static void bind_arrow_keys_internal PARAMS((Keymap)); -static void bind_arrow_keys PARAMS((void)); - -static void readline_default_bindings PARAMS((void)); -static void reset_default_bindings PARAMS((void)); - -static int _rl_subseq_result PARAMS((int, Keymap, int, int)); -static int _rl_subseq_getchar PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Line editing input utility */ -/* */ -/* **************************************************************** */ - -const char *rl_library_version = RL_LIBRARY_VERSION; - -int rl_readline_version = RL_READLINE_VERSION; - -/* True if this is `real' readline as opposed to some stub substitute. */ -int rl_gnu_readline_p = 1; - -/* A pointer to the keymap that is currently in use. - By default, it is the standard emacs keymap. */ -Keymap _rl_keymap = emacs_standard_keymap; - -/* The current style of editing. */ -int rl_editing_mode = emacs_mode; - -/* The current insert mode: input (the default) or overwrite */ -int rl_insert_mode = RL_IM_DEFAULT; - -/* Non-zero if we called this function from _rl_dispatch(). It's present - so functions can find out whether they were called from a key binding - or directly from an application. */ -int rl_dispatching; - -/* Non-zero if the previous command was a kill command. */ -int _rl_last_command_was_kill = 0; - -/* The current value of the numeric argument specified by the user. */ -int rl_numeric_arg = 1; - -/* Non-zero if an argument was typed. */ -int rl_explicit_arg = 0; - -/* Temporary value used while generating the argument. */ -int rl_arg_sign = 1; - -/* Non-zero means we have been called at least once before. */ -static int rl_initialized; - -#if 0 -/* If non-zero, this program is running in an EMACS buffer. */ -static int running_in_emacs; -#endif - -/* Flags word encapsulating the current readline state. */ -int rl_readline_state = RL_STATE_NONE; - -/* The current offset in the current input line. */ -int rl_point; - -/* Mark in the current input line. */ -int rl_mark; - -/* Length of the current input line. */ -int rl_end; - -/* Make this non-zero to return the current input_line. */ -int rl_done; - -/* The last function executed by readline. */ -rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; - -/* Top level environment for readline_internal (). */ -procenv_t _rl_top_level; - -/* The streams we interact with. */ -FILE *_rl_in_stream, *_rl_out_stream; - -/* The names of the streams that we do input and output to. */ -FILE *rl_instream = (FILE *)NULL; -FILE *rl_outstream = (FILE *)NULL; - -/* Non-zero means echo characters as they are read. Defaults to no echo; - set to 1 if there is a controlling terminal, we can get its attributes, - and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings - for the code that sets it. */ -int _rl_echoing_p = 0; - -/* Current prompt. */ -char *rl_prompt = (char *)NULL; -int rl_visible_prompt_length = 0; - -/* Set to non-zero by calling application if it has already printed rl_prompt - and does not want readline to do it the first time. */ -int rl_already_prompted = 0; - -/* The number of characters read in order to type this complete command. */ -int rl_key_sequence_length = 0; - -/* If non-zero, then this is the address of a function to call just - before readline_internal_setup () prints the first prompt. */ -rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; - -/* If non-zero, this is the address of a function to call just before - readline_internal_setup () returns and readline_internal starts - reading input characters. */ -rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; - -/* What we use internally. You should always refer to RL_LINE_BUFFER. */ -static char *the_line; - -/* The character that can generate an EOF. Really read from - the terminal driver... just defaulted here. */ -int _rl_eof_char = CTRL ('D'); - -/* Non-zero makes this the next keystroke to read. */ -int rl_pending_input = 0; - -/* Pointer to a useful terminal name. */ -const char *rl_terminal_name = (const char *)NULL; - -/* Non-zero means to always use horizontal scrolling in line display. */ -int _rl_horizontal_scroll_mode = 0; - -/* Non-zero means to display an asterisk at the starts of history lines - which have been modified. */ -int _rl_mark_modified_lines = 0; - -/* The style of `bell' notification preferred. This can be set to NO_BELL, - AUDIBLE_BELL, or VISIBLE_BELL. */ -int _rl_bell_preference = AUDIBLE_BELL; - -/* String inserted into the line by rl_insert_comment (). */ -char *_rl_comment_begin; - -/* Keymap holding the function currently being executed. */ -Keymap rl_executing_keymap; - -/* Keymap we're currently using to dispatch. */ -Keymap _rl_dispatching_keymap; - -/* Non-zero means to erase entire line, including prompt, on empty input lines. */ -int rl_erase_empty_line = 0; - -/* Non-zero means to read only this many characters rather than up to a - character bound to accept-line. */ -int rl_num_chars_to_read; - -/* Line buffer and maintenence. */ -char *rl_line_buffer = (char *)NULL; -int rl_line_buffer_len = 0; - -/* Key sequence `contexts' */ -_rl_keyseq_cxt *_rl_kscxt = 0; - -int rl_executing_key; -char *rl_executing_keyseq = 0; -int _rl_executing_keyseq_size = 0; - -/* Timeout (specified in milliseconds) when reading characters making up an - ambiguous multiple-key sequence */ -int _rl_keyseq_timeout = 500; - -#define RESIZE_KEYSEQ_BUFFER() \ - do \ - { \ - if (rl_key_sequence_length + 2 >= _rl_executing_keyseq_size) \ - { \ - _rl_executing_keyseq_size += 16; \ - rl_executing_keyseq = xrealloc (rl_executing_keyseq, _rl_executing_keyseq_size); \ - } \ - } \ - while (0); - -/* Forward declarations used by the display, termcap, and history code. */ - -/* **************************************************************** */ -/* */ -/* `Forward' declarations */ -/* */ -/* **************************************************************** */ - -/* Non-zero means do not parse any lines other than comments and - parser directives. */ -unsigned char _rl_parsing_conditionalized_out = 0; - -/* Non-zero means to convert characters with the meta bit set to - escape-prefixed characters so we can indirect through - emacs_meta_keymap or vi_escape_keymap. */ -int _rl_convert_meta_chars_to_ascii = 1; - -/* Non-zero means to output characters with the meta bit set directly - rather than as a meta-prefixed escape sequence. */ -int _rl_output_meta_chars = 0; - -/* Non-zero means to look at the termios special characters and bind - them to equivalent readline functions at startup. */ -int _rl_bind_stty_chars = 1; - -/* Non-zero means to go through the history list at every newline (or - whenever rl_done is set and readline returns) and revert each line to - its initial state. */ -int _rl_revert_all_at_newline = 0; - -/* Non-zero means to honor the termios ECHOCTL bit and echo control - characters corresponding to keyboard-generated signals. */ -int _rl_echo_control_chars = 1; - -/* **************************************************************** */ -/* */ -/* Top Level Functions */ -/* */ -/* **************************************************************** */ - -/* Non-zero means treat 0200 bit in terminal input as Meta bit. */ -int _rl_meta_flag = 0; /* Forward declaration */ - -/* Set up the prompt and expand it. Called from readline() and - rl_callback_handler_install (). */ -int -rl_set_prompt (prompt) - const char *prompt; -{ - FREE (rl_prompt); - rl_prompt = prompt ? savestring (prompt) : (char *)NULL; - rl_display_prompt = rl_prompt ? rl_prompt : ""; - - rl_visible_prompt_length = rl_expand_prompt (rl_prompt); - return 0; -} - -/* Read a line of input. Prompt with PROMPT. An empty PROMPT means - none. A return value of NULL means that EOF was encountered. */ -char * -readline (prompt) - const char *prompt; -{ - char *value; -#if 0 - int in_callback; -#endif - - /* If we are at EOF return a NULL string. */ - if (rl_pending_input == EOF) - { - rl_clear_pending_input (); - return ((char *)NULL); - } - -#if 0 - /* If readline() is called after installing a callback handler, temporarily - turn off the callback state to avoid ensuing messiness. Patch supplied - by the gdb folks. XXX -- disabled. This can be fooled and readline - left in a strange state by a poorly-timed longjmp. */ - if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK)) - RL_UNSETSTATE (RL_STATE_CALLBACK); -#endif - - rl_set_prompt (prompt); - - rl_initialize (); - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - -#if defined (HANDLE_SIGNALS) - rl_set_signals (); -#endif - - value = readline_internal (); - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - -#if 0 - if (in_callback) - RL_SETSTATE (RL_STATE_CALLBACK); -#endif - -#if HAVE_DECL_AUDIT_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT) - if (value) - _rl_audit_tty (value); -#endif - - return (value); -} - -#if defined (READLINE_CALLBACKS) -# define STATIC_CALLBACK -#else -# define STATIC_CALLBACK static -#endif - -STATIC_CALLBACK void -readline_internal_setup () -{ - char *nprompt; - - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - /* Enable the meta key only for the duration of readline(), if this - terminal has one. */ - if (_rl_enable_meta) - _rl_enable_meta_key (); - - if (rl_startup_hook) - (*rl_startup_hook) (); - - /* If we're not echoing, we still want to at least print a prompt, because - rl_redisplay will not do it for us. If the calling application has a - custom redisplay function, though, let that function handle it. */ - if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay) - { - if (rl_prompt && rl_already_prompted == 0) - { - nprompt = _rl_strip_prompt (rl_prompt); - fprintf (_rl_out_stream, "%s", nprompt); - fflush (_rl_out_stream); - xfree (nprompt); - } - } - else - { - if (rl_prompt && rl_already_prompted) - rl_on_new_line_with_prompt (); - else - rl_on_new_line (); - (*rl_redisplay_function) (); - } - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insert_mode (1, 'i'); -#endif /* VI_MODE */ - - if (rl_pre_input_hook) - (*rl_pre_input_hook) (); - - RL_CHECK_SIGNALS (); -} - -STATIC_CALLBACK char * -readline_internal_teardown (eof) - int eof; -{ - char *temp; - HIST_ENTRY *entry; - - RL_CHECK_SIGNALS (); - - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - entry = current_history (); - - if (entry && rl_undo_list) - { - temp = savestring (the_line); - rl_revert_line (1, 0); - entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); - _rl_free_history_entry (entry); - - strcpy (the_line, temp); - xfree (temp); - } - - if (_rl_revert_all_at_newline) - _rl_revert_all_lines (); - - /* At any rate, it is highly likely that this line has an undo list. Get - rid of it now. */ - if (rl_undo_list) - rl_free_undo_list (); - - /* Disable the meta key, if this terminal has one. */ - _rl_disable_meta_key (); - - /* Restore normal cursor, if available. */ - _rl_set_insert_mode (RL_IM_INSERT, 0); - - return (eof ? (char *)NULL : savestring (the_line)); -} - -void -_rl_internal_char_cleanup () -{ -#if defined (VI_MODE) - /* In vi mode, when you exit insert mode, the cursor moves back - over the previous character. We explicitly check for that here. */ - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) - rl_vi_check (); -#endif /* VI_MODE */ - - if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - rl_newline (1, '\n'); - } - - if (rl_done == 0) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - /* If the application writer has told us to erase the entire line if - the only character typed was something bound to rl_newline, do so. */ - if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && - rl_point == 0 && rl_end == 0) - _rl_erase_entire_line (); -} - -STATIC_CALLBACK int -#if defined (READLINE_CALLBACKS) -readline_internal_char () -#else -readline_internal_charloop () -#endif -{ - static int lastc, eof_found; - int c, code, lk; - - lastc = -1; - eof_found = 0; - -#if !defined (READLINE_CALLBACKS) - while (rl_done == 0) - { -#endif - lk = _rl_last_command_was_kill; - - code = setjmp (_rl_top_level); - - if (code) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - /* If we get here, we're not being called from something dispatched - from _rl_callback_read_char(), which sets up its own value of - _rl_top_level (saving and restoring the old, of course), so - we can just return here. */ - if (RL_ISSTATE (RL_STATE_CALLBACK)) - return (0); - } - - if (rl_pending_input == 0) - { - /* Then initialize the argument and number of keys read. */ - _rl_reset_argument (); - rl_key_sequence_length = 0; - rl_executing_keyseq[0] = 0; - } - - RL_SETSTATE(RL_STATE_READCMD); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_READCMD); - - /* look at input.c:rl_getc() for the circumstances under which this will - be returned; punt immediately on read error without converting it to - a newline. */ - if (c == READERR) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - /* EOF typed to a non-blank line is a . */ - if (c == EOF && rl_end) - c = NEWLINE; - - /* The character _rl_eof_char typed to blank line, and not as the - previous character is interpreted as EOF. */ - if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - lastc = c; - _rl_dispatch ((unsigned char)c, _rl_keymap); - RL_CHECK_SIGNALS (); - - /* If there was no change in _rl_last_command_was_kill, then no kill - has taken place. Note that if input is pending we are reading - a prefix command, so nothing has changed yet. */ - if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) - _rl_last_command_was_kill = 0; - - _rl_internal_char_cleanup (); - -#if defined (READLINE_CALLBACKS) - return 0; -#else - } - - return (eof_found); -#endif -} - -#if defined (READLINE_CALLBACKS) -static int -readline_internal_charloop () -{ - int eof = 1; - - while (rl_done == 0) - eof = readline_internal_char (); - return (eof); -} -#endif /* READLINE_CALLBACKS */ - -/* Read a line of input from the global rl_instream, doing output on - the global rl_outstream. - If rl_prompt is non-null, then that is our prompt. */ -static char * -readline_internal () -{ - int eof; - - readline_internal_setup (); - eof = readline_internal_charloop (); - return (readline_internal_teardown (eof)); -} - -void -_rl_init_line_state () -{ - rl_point = rl_end = rl_mark = 0; - the_line = rl_line_buffer; - the_line[0] = 0; -} - -void -_rl_set_the_line () -{ - the_line = rl_line_buffer; -} - -#if defined (READLINE_CALLBACKS) -_rl_keyseq_cxt * -_rl_keyseq_cxt_alloc () -{ - _rl_keyseq_cxt *cxt; - - cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); - - cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; - - cxt->okey = 0; - cxt->ocxt = _rl_kscxt; - cxt->childval = 42; /* sentinel value */ - - return cxt; -} - -void -_rl_keyseq_cxt_dispose (cxt) - _rl_keyseq_cxt *cxt; -{ - xfree (cxt); -} - -void -_rl_keyseq_chain_dispose () -{ - _rl_keyseq_cxt *cxt; - - while (_rl_kscxt) - { - cxt = _rl_kscxt; - _rl_kscxt = _rl_kscxt->ocxt; - _rl_keyseq_cxt_dispose (cxt); - } -} -#endif - -static int -_rl_subseq_getchar (key) - int key; -{ - int k; - - if (key == ESC) - RL_SETSTATE(RL_STATE_METANEXT); - RL_SETSTATE(RL_STATE_MOREINPUT); - k = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (key == ESC) - RL_UNSETSTATE(RL_STATE_METANEXT); - - return k; -} - -#if defined (READLINE_CALLBACKS) -int -_rl_dispatch_callback (cxt) - _rl_keyseq_cxt *cxt; -{ - int nkey, r; - - /* For now */ - /* The first time this context is used, we want to read input and dispatch - on it. When traversing the chain of contexts back `up', we want to use - the value from the next context down. We're simulating recursion using - a chain of contexts. */ - if ((cxt->flags & KSEQ_DISPATCHED) == 0) - { - nkey = _rl_subseq_getchar (cxt->okey); - if (nkey < 0) - { - _rl_abort_internal (); - return -1; - } - r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); - cxt->flags |= KSEQ_DISPATCHED; - } - else - r = cxt->childval; - - /* For now */ - if (r != -3) /* don't do this if we indicate there will be other matches */ - r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ)); - - RL_CHECK_SIGNALS (); - if (r == 0) /* success! */ - { - _rl_keyseq_chain_dispose (); - RL_UNSETSTATE (RL_STATE_MULTIKEY); - return r; - } - - if (r != -3) /* magic value that says we added to the chain */ - _rl_kscxt = cxt->ocxt; - if (_rl_kscxt) - _rl_kscxt->childval = r; - if (r != -3) - _rl_keyseq_cxt_dispose (cxt); - - return r; -} -#endif /* READLINE_CALLBACKS */ - -/* Do the command associated with KEY in MAP. - If the associated command is really a keymap, then read - another key, and dispatch into that map. */ -int -_rl_dispatch (key, map) - register int key; - Keymap map; -{ - _rl_dispatching_keymap = map; - return _rl_dispatch_subseq (key, map, 0); -} - -int -_rl_dispatch_subseq (key, map, got_subseq) - register int key; - Keymap map; - int got_subseq; -{ - int r, newkey; - char *macro; - rl_command_func_t *func; -#if defined (READLINE_CALLBACKS) - _rl_keyseq_cxt *cxt; -#endif - - if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) - { - if (map[ESC].type == ISKMAP) - { - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (ESC); - RESIZE_KEYSEQ_BUFFER (); - rl_executing_keyseq[rl_key_sequence_length++] = ESC; - map = FUNCTION_TO_KEYMAP (map, ESC); - key = UNMETA (key); - return (_rl_dispatch (key, map)); - } - else - rl_ding (); - return 0; - } - - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (key); - - r = 0; - switch (map[key].type) - { - case ISFUNC: - func = map[key].function; - if (func) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - return (_rl_dispatch (_rl_to_lower (key), map)); - - rl_executing_keymap = map; - rl_executing_key = key; - - RESIZE_KEYSEQ_BUFFER(); - rl_executing_keyseq[rl_key_sequence_length++] = key; - rl_executing_keyseq[rl_key_sequence_length] = '\0'; - - rl_dispatching = 1; - RL_SETSTATE(RL_STATE_DISPATCHING); - (*func) (rl_numeric_arg * rl_arg_sign, key); - RL_UNSETSTATE(RL_STATE_DISPATCHING); - rl_dispatching = 0; - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. Otherwise, - remember the last command executed in this variable. */ - if (rl_pending_input == 0 && map[key].function != rl_digit_argument) - rl_last_func = map[key].function; - - RL_CHECK_SIGNALS (); - } - else if (map[ANYOTHERKEY].function) - { - /* OK, there's no function bound in this map, but there is a - shadow function that was overridden when the current keymap - was created. Return -2 to note that. */ - _rl_unget_char (key); - return -2; - } - else if (got_subseq) - { - /* Return -1 to note that we're in a subsequence, but we don't - have a matching key, nor was one overridden. This means - we need to back up the recursion chain and find the last - subsequence that is bound to a function. */ - _rl_unget_char (key); - return -1; - } - else - { -#if defined (READLINE_CALLBACKS) - RL_UNSETSTATE (RL_STATE_MULTIKEY); - _rl_keyseq_chain_dispose (); -#endif - _rl_abort_internal (); - return -1; - } - break; - - case ISKMAP: - if (map[key].function != 0) - { -#if defined (VI_MODE) - /* The only way this test will be true is if a subsequence has been - bound starting with ESC, generally the arrow keys. What we do is - check whether there's input in the queue, which there generally - will be if an arrow key has been pressed, and, if there's not, - just dispatch to (what we assume is) rl_vi_movement_mode right - away. This is essentially an input test with a zero timeout (by - default) or a timeout determined by the value of `keyseq-timeout' */ - /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued - takes microseconds, so multiply by 1000 */ - if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap - && _rl_input_queued ((_rl_keyseq_timeout > 0) ? _rl_keyseq_timeout*1000 : 0) == 0) - return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); -#endif - - RESIZE_KEYSEQ_BUFFER (); - rl_executing_keyseq[rl_key_sequence_length++] = key; - _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key); - - /* Allocate new context here. Use linked contexts (linked through - cxt->ocxt) to simulate recursion */ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - /* Return 0 only the first time, to indicate success to - _rl_callback_read_char. The rest of the time, we're called - from _rl_dispatch_callback, so we return -3 to indicate - special handling is necessary. */ - r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0; - cxt = _rl_keyseq_cxt_alloc (); - - if (got_subseq) - cxt->flags |= KSEQ_SUBSEQ; - cxt->okey = key; - cxt->oldmap = map; - cxt->dmap = _rl_dispatching_keymap; - cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function; - - RL_SETSTATE (RL_STATE_MULTIKEY); - _rl_kscxt = cxt; - - return r; /* don't indicate immediate success */ - } -#endif - - /* Tentative inter-character timeout for potential multi-key - sequences? If no input within timeout, abort sequence and - act as if we got non-matching input. */ - /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued - takes microseconds, so multiply by 1000 */ - if (_rl_keyseq_timeout > 0 && - (RL_ISSTATE (RL_STATE_INPUTPENDING|RL_STATE_MACROINPUT) == 0) && - _rl_pushed_input_available () == 0 && - _rl_dispatching_keymap[ANYOTHERKEY].function && - _rl_input_queued (_rl_keyseq_timeout*1000) == 0) - return (_rl_subseq_result (-2, map, key, got_subseq)); - - newkey = _rl_subseq_getchar (key); - if (newkey < 0) - { - _rl_abort_internal (); - return -1; - } - - r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function); - return _rl_subseq_result (r, map, key, got_subseq); - } - else - { - _rl_abort_internal (); - return -1; - } - break; - - case ISMACR: - if (map[key].function != 0) - { - rl_executing_keyseq[rl_key_sequence_length] = '\0'; - macro = savestring ((char *)map[key].function); - _rl_with_macro_input (macro); - return 0; - } - break; - } -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && - key != ANYOTHERKEY && - _rl_vi_textmod_command (key)) - _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); -#endif - - return (r); -} - -static int -_rl_subseq_result (r, map, key, got_subseq) - int r; - Keymap map; - int key, got_subseq; -{ - Keymap m; - int type, nt; - rl_command_func_t *func, *nf; - - if (r == -2) - /* We didn't match anything, and the keymap we're indexed into - shadowed a function previously bound to that prefix. Call - the function. The recursive call to _rl_dispatch_subseq has - already taken care of pushing any necessary input back onto - the input queue with _rl_unget_char. */ - { - m = _rl_dispatching_keymap; - type = m[ANYOTHERKEY].type; - func = m[ANYOTHERKEY].function; - if (type == ISFUNC && func == rl_do_lowercase_version) - r = _rl_dispatch (_rl_to_lower (key), map); - else if (type == ISFUNC && func == rl_insert) - { - /* If the function that was shadowed was self-insert, we - somehow need a keymap with map[key].func == self-insert. - Let's use this one. */ - nt = m[key].type; - nf = m[key].function; - - m[key].type = type; - m[key].function = func; - r = _rl_dispatch (key, m); - m[key].type = nt; - m[key].function = nf; - } - else - r = _rl_dispatch (ANYOTHERKEY, m); - } - else if (r && map[ANYOTHERKEY].function) - { - /* We didn't match (r is probably -1), so return something to - tell the caller that it should try ANYOTHERKEY for an - overridden function. */ - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -2; - } - else if (r && got_subseq) - { - /* OK, back up the chain. */ - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -1; - } - - return r; -} - -/* **************************************************************** */ -/* */ -/* Initializations */ -/* */ -/* **************************************************************** */ - -/* Initialize readline (and terminal if not already). */ -int -rl_initialize () -{ - /* If we have never been called before, initialize the - terminal and data structures. */ - if (!rl_initialized) - { - RL_SETSTATE(RL_STATE_INITIALIZING); - readline_initialize_everything (); - RL_UNSETSTATE(RL_STATE_INITIALIZING); - rl_initialized++; - RL_SETSTATE(RL_STATE_INITIALIZED); - } - - /* Initalize the current line information. */ - _rl_init_line_state (); - - /* We aren't done yet. We haven't even gotten started yet! */ - rl_done = 0; - RL_UNSETSTATE(RL_STATE_DONE); - - /* Tell the history routines what is going on. */ - _rl_start_using_history (); - - /* Make the display buffer match the state of the line. */ - rl_reset_line_state (); - - /* No such function typed yet. */ - rl_last_func = (rl_command_func_t *)NULL; - - /* Parsing of key-bindings begins in an enabled state. */ - _rl_parsing_conditionalized_out = 0; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - _rl_vi_initialize_line (); -#endif - - /* Each line starts in insert mode (the default). */ - _rl_set_insert_mode (RL_IM_DEFAULT, 1); - - return 0; -} - -#if 0 -#if defined (__EMX__) -static void -_emx_build_environ () -{ - TIB *tibp; - PIB *pibp; - char *t, **tp; - int c; - - DosGetInfoBlocks (&tibp, &pibp); - t = pibp->pib_pchenv; - for (c = 1; *t; c++) - t += strlen (t) + 1; - tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *)); - t = pibp->pib_pchenv; - while (*t) - { - *tp++ = t; - t += strlen (t) + 1; - } - *tp = 0; -} -#endif /* __EMX__ */ -#endif - -/* Initialize the entire state of the world. */ -static void -readline_initialize_everything () -{ -#if 0 -#if defined (__EMX__) - if (environ == 0) - _emx_build_environ (); -#endif -#endif - -#if 0 - /* Find out if we are running in Emacs -- UNUSED. */ - running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; -#endif - - /* Set up input and output if they are not already set up. */ - if (!rl_instream) - rl_instream = stdin; - - if (!rl_outstream) - rl_outstream = stdout; - - /* Bind _rl_in_stream and _rl_out_stream immediately. These values - may change, but they may also be used before readline_internal () - is called. */ - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - /* Allocate data structures. */ - if (rl_line_buffer == 0) - rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - - /* Initialize the terminal interface. */ - if (rl_terminal_name == 0) - rl_terminal_name = sh_get_env_value ("TERM"); - _rl_init_terminal_io (rl_terminal_name); - - /* Bind tty characters to readline functions. */ - readline_default_bindings (); - - /* Initialize the function names. */ - rl_initialize_funmap (); - - /* Decide whether we should automatically go into eight-bit mode. */ - _rl_init_eightbit (); - - /* Read in the init file. */ - rl_read_init_file ((char *)NULL); - - /* XXX */ - if (_rl_horizontal_scroll_mode && _rl_term_autowrap) - { - _rl_screenwidth--; - _rl_screenchars -= _rl_screenheight; - } - - /* Override the effect of any `set keymap' assignments in the - inputrc file. */ - rl_set_keymap_from_edit_mode (); - - /* Try to bind a common arrow key prefix, if not already bound. */ - bind_arrow_keys (); - - /* If the completion parser's default word break characters haven't - been set yet, then do so now. */ - if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; - -#if defined (COLOR_SUPPORT) - if (_rl_colored_stats) - _rl_parse_colors (); -#endif - - rl_executing_keyseq = malloc (_rl_executing_keyseq_size = 16); - if (rl_executing_keyseq) - rl_executing_keyseq[0] = '\0'; -} - -/* If this system allows us to look at the values of the regular - input editing characters, then bind them to their readline - equivalents, iff the characters are not bound to keymaps. */ -static void -readline_default_bindings () -{ - if (_rl_bind_stty_chars) - rl_tty_set_default_bindings (_rl_keymap); -} - -/* Reset the default bindings for the terminal special characters we're - interested in back to rl_insert and read the new ones. */ -static void -reset_default_bindings () -{ - if (_rl_bind_stty_chars) - { - rl_tty_unset_default_bindings (_rl_keymap); - rl_tty_set_default_bindings (_rl_keymap); - } -} - -/* Bind some common arrow key sequences in MAP. */ -static void -bind_arrow_keys_internal (map) - Keymap map; -{ - Keymap xkeymap; - - xkeymap = _rl_keymap; - _rl_keymap = map; - -#if defined (__MSDOS__) - rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); -#endif - - rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); - - rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); - -#if defined (__MINGW32__) - rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\340M", rl_forward_char); - rl_bind_keyseq_if_unbound ("\340K", rl_backward_char); -#endif - - _rl_keymap = xkeymap; -} - -/* Try and bind the common arrow key prefixes after giving termcap and - the inputrc file a chance to bind them and create `real' keymaps - for the arrow key prefix. */ -static void -bind_arrow_keys () -{ - bind_arrow_keys_internal (emacs_standard_keymap); - -#if defined (VI_MODE) - bind_arrow_keys_internal (vi_movement_keymap); - /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC - in vi command mode while still allowing the arrow keys to work. */ - if (vi_movement_keymap[ESC].type == ISKMAP) - rl_bind_keyseq_in_map ("\033", (rl_command_func_t *)NULL, vi_movement_keymap); - bind_arrow_keys_internal (vi_insertion_keymap); -#endif -} - -/* **************************************************************** */ -/* */ -/* Saving and Restoring Readline's state */ -/* */ -/* **************************************************************** */ - -int -rl_save_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - sp->point = rl_point; - sp->end = rl_end; - sp->mark = rl_mark; - sp->buffer = rl_line_buffer; - sp->buflen = rl_line_buffer_len; - sp->ul = rl_undo_list; - sp->prompt = rl_prompt; - - sp->rlstate = rl_readline_state; - sp->done = rl_done; - sp->kmap = _rl_keymap; - - sp->lastfunc = rl_last_func; - sp->insmode = rl_insert_mode; - sp->edmode = rl_editing_mode; - sp->kseqlen = rl_key_sequence_length; - sp->inf = rl_instream; - sp->outf = rl_outstream; - sp->pendingin = rl_pending_input; - sp->macro = rl_executing_macro; - - sp->catchsigs = rl_catch_signals; - sp->catchsigwinch = rl_catch_sigwinch; - - return (0); -} - -int -rl_restore_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - rl_point = sp->point; - rl_end = sp->end; - rl_mark = sp->mark; - the_line = rl_line_buffer = sp->buffer; - rl_line_buffer_len = sp->buflen; - rl_undo_list = sp->ul; - rl_prompt = sp->prompt; - - rl_readline_state = sp->rlstate; - rl_done = sp->done; - _rl_keymap = sp->kmap; - - rl_last_func = sp->lastfunc; - rl_insert_mode = sp->insmode; - rl_editing_mode = sp->edmode; - rl_key_sequence_length = sp->kseqlen; - rl_instream = sp->inf; - rl_outstream = sp->outf; - rl_pending_input = sp->pendingin; - rl_executing_macro = sp->macro; - - rl_catch_signals = sp->catchsigs; - rl_catch_sigwinch = sp->catchsigwinch; - - return (0); -} diff --git a/lib/readline/rltty.c.save1 b/lib/readline/rltty.c.save1 deleted file mode 100644 index 81a168874..000000000 --- a/lib/readline/rltty.c.save1 +++ /dev/null @@ -1,976 +0,0 @@ -/* rltty.c -- functions to prepare and restore the terminal for readline's - use. */ - -/* Copyright (C) 1992-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -#include "rltty.h" -#include "readline.h" -#include "rlprivate.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; -rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; - -static void set_winsize PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Saving and Restoring the TTY */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that the terminal is in a prepped state. */ -static int terminal_prepped; - -static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars; - -/* If non-zero, means that this process has called tcflow(fd, TCOOFF) - and output is suspended. */ -#if defined (__ksr1__) -static int ksrflow; -#endif - -/* Dummy call to force a backgrounded readline to stop before it tries - to get the tty settings. */ -static void -set_winsize (tty) - int tty; -{ -#if defined (TIOCGWINSZ) - struct winsize w; - - if (ioctl (tty, TIOCGWINSZ, &w) == 0) - (void) ioctl (tty, TIOCSWINSZ, &w); -#endif /* TIOCGWINSZ */ -} - -#if defined (NO_TTY_DRIVER) -/* Nothing */ -#elif defined (NEW_TTY_DRIVER) - -/* Values for the `flags' field of a struct bsdtty. This tells which - elements of the struct bsdtty have been fetched from the system and - are valid. */ -#define SGTTY_SET 0x01 -#define LFLAG_SET 0x02 -#define TCHARS_SET 0x04 -#define LTCHARS_SET 0x08 - -struct bsdtty { - struct sgttyb sgttyb; /* Basic BSD tty driver information. */ - int lflag; /* Local mode flags, like LPASS8. */ -#if defined (TIOCGETC) - struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ -#endif -#if defined (TIOCGLTC) - struct ltchars ltchars; /* 4.2 BSD editing characters */ -#endif - int flags; /* Bitmap saying which parts of the struct are valid. */ -}; - -#define TIOTYPE struct bsdtty - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - if (tiop->flags & SGTTY_SET) - { - _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase; - _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill; - } - - if (tiop->flags & TCHARS_SET) - { - _rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc; - - _rl_tty_chars.t_start = tiop->tchars.t_startc; - _rl_tty_chars.t_stop = tiop->tchars.t_stopc; - _rl_tty_chars.t_eof = tiop->tchars.t_eofc; - _rl_tty_chars.t_eol = '\n'; - _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc; - } - - if (tiop->flags & LTCHARS_SET) - { - _rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc; - - _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc; - _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc; - _rl_tty_chars.t_flush = tiop->ltchars.t_flushc; - _rl_tty_chars.t_werase = tiop->ltchars.t_werasc; - _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc; - } - - _rl_tty_chars.t_status = -1; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - tiop->flags = tiop->lflag = 0; - - errno = 0; - if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0) - return -1; - tiop->flags |= SGTTY_SET; - -#if defined (TIOCLGET) - if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0) - tiop->flags |= LFLAG_SET; -#endif - -#if defined (TIOCGETC) - if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0) - tiop->flags |= TCHARS_SET; -#endif - -#if defined (TIOCGLTC) - if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0) - tiop->flags |= LTCHARS_SET; -#endif - - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (tiop->flags & SGTTY_SET) - { - ioctl (tty, TIOCSETN, &(tiop->sgttyb)); - tiop->flags &= ~SGTTY_SET; - } - _rl_echoing_p = 1; - -#if defined (TIOCLSET) - if (tiop->flags & LFLAG_SET) - { - ioctl (tty, TIOCLSET, &(tiop->lflag)); - tiop->flags &= ~LFLAG_SET; - } -#endif - -#if defined (TIOCSETC) - if (tiop->flags & TCHARS_SET) - { - ioctl (tty, TIOCSETC, &(tiop->tchars)); - tiop->flags &= ~TCHARS_SET; - } -#endif - -#if defined (TIOCSLTC) - if (tiop->flags & LTCHARS_SET) - { - ioctl (tty, TIOCSLTC, &(tiop->ltchars)); - tiop->flags &= ~LTCHARS_SET; - } -#endif - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO); - _rl_echoctl = (oldtio.sgttyb.sg_flags & ECHOCTL); - - /* Copy the original settings to the structure we're going to use for - our settings. */ - tiop->sgttyb = oldtio.sgttyb; - tiop->lflag = oldtio.lflag; -#if defined (TIOCGETC) - tiop->tchars = oldtio.tchars; -#endif -#if defined (TIOCGLTC) - tiop->ltchars = oldtio.ltchars; -#endif - tiop->flags = oldtio.flags; - - /* First, the basic settings to put us into character-at-a-time, no-echo - input mode. */ - tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); - tiop->sgttyb.sg_flags |= CBREAK; - - /* If this terminal doesn't care how the 8th bit is used, then we can - use it for the meta-key. If only one of even or odd parity is - specified, then the terminal is using parity, and we cannot. */ -#if !defined (ANYP) -# define ANYP (EVENP | ODDP) -#endif - if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) || - ((oldtio.sgttyb.sg_flags & ANYP) == 0)) - { - tiop->sgttyb.sg_flags |= ANYP; - - /* Hack on local mode flags if we can. */ -#if defined (TIOCLGET) -# if defined (LPASS8) - tiop->lflag |= LPASS8; -# endif /* LPASS8 */ -#endif /* TIOCLGET */ - } - -#if defined (TIOCGETC) -# if defined (USE_XON_XOFF) - /* Get rid of terminal output start and stop characters. */ - tiop->tchars.t_stopc = -1; /* C-s */ - tiop->tchars.t_startc = -1; /* C-q */ - - /* If there is an XON character, bind it to restart the output. */ - if (oldtio.tchars.t_startc != -1) - rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); -# endif /* USE_XON_XOFF */ - - /* If there is an EOF char, bind _rl_eof_char to it. */ - if (oldtio.tchars.t_eofc != -1) - _rl_eof_char = oldtio.tchars.t_eofc; - -# if defined (NO_KILL_INTR) - /* Get rid of terminal-generated SIGQUIT and SIGINT. */ - tiop->tchars.t_quitc = -1; /* C-\ */ - tiop->tchars.t_intrc = -1; /* C-c */ -# endif /* NO_KILL_INTR */ -#endif /* TIOCGETC */ - -#if defined (TIOCGLTC) - /* Make the interrupt keys go away. Just enough to make people happy. */ - tiop->ltchars.t_dsuspc = -1; /* C-y */ - tiop->ltchars.t_lnextc = -1; /* C-v */ -#endif /* TIOCGLTC */ -} - -#else /* !defined (NEW_TTY_DRIVER) */ - -#if !defined (VMIN) -# define VMIN VEOF -#endif - -#if !defined (VTIME) -# define VTIME VEOL -#endif - -#if defined (TERMIOS_TTY_DRIVER) -# define TIOTYPE struct termios -# define DRAIN_OUTPUT(fd) tcdrain (fd) -# define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) -# ifdef M_UNIX -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) -# else -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) -# endif /* !M_UNIX */ -#else -# define TIOTYPE struct termio -# define DRAIN_OUTPUT(fd) -# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) -# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop)) -#endif /* !TERMIOS_TTY_DRIVER */ - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); -static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); - -#if defined (FLUSHO) -# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) -#else -# define OUTPUT_BEING_FLUSHED(tp) 0 -#endif - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - _rl_tty_chars.t_eof = tiop->c_cc[VEOF]; - _rl_tty_chars.t_eol = tiop->c_cc[VEOL]; -#ifdef VEOL2 - _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2]; -#endif - _rl_tty_chars.t_erase = tiop->c_cc[VERASE]; -#ifdef VWERASE - _rl_tty_chars.t_werase = tiop->c_cc[VWERASE]; -#endif - _rl_tty_chars.t_kill = tiop->c_cc[VKILL]; -#ifdef VREPRINT - _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT]; -#endif - _rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR]; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT]; -#ifdef VSUSP - _rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP]; -#endif -#ifdef VDSUSP - _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP]; -#endif -#ifdef VSTART - _rl_tty_chars.t_start = tiop->c_cc[VSTART]; -#endif -#ifdef VSTOP - _rl_tty_chars.t_stop = tiop->c_cc[VSTOP]; -#endif -#ifdef VLNEXT - _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT]; -#endif -#ifdef VDISCARD - _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD]; -#endif -#ifdef VSTATUS - _rl_tty_chars.t_status = tiop->c_cc[VSTATUS]; -#endif -} - -#if defined (_AIX) || defined (_AIX41) -/* Currently this is only used on AIX */ -static void -rltty_warning (msg) - char *msg; -{ - _rl_errmsg ("warning: %s", msg); -} -#endif - -#if defined (_AIX) -void -setopost(tp) -TIOTYPE *tp; -{ - if ((tp->c_oflag & OPOST) == 0) - { - _rl_errmsg ("warning: turning on OPOST for terminal\r"); - tp->c_oflag |= OPOST|ONLCR; - } -} -#endif - -static int -_get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - int ioctl_ret; - - while (1) - { - ioctl_ret = GETATTR (tty, tiop); - if (ioctl_ret < 0) - { - if (errno != EINTR) - return -1; - else - continue; - } - if (OUTPUT_BEING_FLUSHED (tiop)) - { -_rl_errmsg("get_tty_settings: output is being flushed"); -#if defined (FLUSHO) - _rl_errmsg ("warning: turning off output flushing"); - tiop->c_lflag &= ~FLUSHO; - break; -#else - continue; -#endif - } - break; - } - - return 0; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - errno = 0; - if (_get_tty_settings (tty, tiop) < 0) - return -1; - -#if defined (_AIX) - setopost(tiop); -#endif - - return 0; -} - -static int -_set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - while (SETATTR (tty, tiop) < 0) - { - if (errno != EINTR) - return -1; - errno = 0; - } - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (_set_tty_settings (tty, tiop) < 0) - return -1; - -#if 0 - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (tty, TCOON); - } -# else /* !ksr1 */ - tcflow (tty, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -#else - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -#endif /* !TERMIOS_TTY_DRIVER */ - -#endif /* 0 */ - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.c_lflag & ECHO); -#if defined (ECHOCTL) - _rl_echoctl = (oldtio.c_lflag & ECHOCTL); -#endif - - tiop->c_lflag &= ~(ICANON | ECHO); - - if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) - _rl_eof_char = oldtio.c_cc[VEOF]; - -#if defined (USE_XON_XOFF) -#if defined (IXANY) - tiop->c_iflag &= ~(IXON | IXOFF | IXANY); -#else - /* `strict' Posix systems do not define IXANY. */ - tiop->c_iflag &= ~(IXON | IXOFF); -#endif /* IXANY */ -#endif /* USE_XON_XOFF */ - - /* Only turn this off if we are using all 8 bits. */ - if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) - tiop->c_iflag &= ~(ISTRIP | INPCK); - - /* Make sure we differentiate between CR and NL on input. */ - tiop->c_iflag &= ~(ICRNL | INLCR); - -#if !defined (HANDLE_SIGNALS) - tiop->c_lflag &= ~ISIG; -#else - tiop->c_lflag |= ISIG; -#endif - - tiop->c_cc[VMIN] = 1; - tiop->c_cc[VTIME] = 0; - -#if defined (FLUSHO) - if (OUTPUT_BEING_FLUSHED (tiop)) - { - tiop->c_lflag &= ~FLUSHO; - oldtio.c_lflag &= ~FLUSHO; - } -#endif - - /* Turn off characters that we need on Posix systems with job control, - just to be sure. This includes ^Y and ^V. This should not really - be necessary. */ -#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) - -#if defined (VLNEXT) - tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; -#endif - -#if defined (VDSUSP) - tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif - -#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ -} -#endif /* !NEW_TTY_DRIVER */ - -/* Put the terminal in CBREAK mode so that we can detect key presses. */ -#if defined (NO_TTY_DRIVER) -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - _rl_echoing_p = 1; -} - -void -rl_deprep_terminal () -{ -} - -#else /* ! NO_TTY_DRIVER */ -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - int tty; - TIOTYPE tio; - - if (terminal_prepped) - return; - - /* Try to keep this function from being INTerrupted. */ - _rl_block_sigint (); - - tty = rl_instream ? fileno (rl_instream) : fileno (stdin); - - if (get_tty_settings (tty, &tio) < 0) - { -#if defined (ENOTSUP) - /* MacOS X and Linux, at least, lie about the value of errno if - tcgetattr fails. */ - if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP) -#else - if (errno == ENOTTY || errno == EINVAL) -#endif - _rl_echoing_p = 1; /* XXX */ - - _rl_release_sigint (); - return; - } - - otio = tio; - - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we restore the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - rl_tty_unset_default_bindings (vi_insertion_keymap); - else -#endif - rl_tty_unset_default_bindings (_rl_keymap); - } - save_tty_chars (&otio); - RL_SETSTATE(RL_STATE_TTYCSAVED); - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we set the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - _rl_bind_tty_special_chars (vi_insertion_keymap, tio); - else -#endif - _rl_bind_tty_special_chars (_rl_keymap, tio); - } - - prepare_terminal_settings (meta_flag, otio, &tio); - - if (set_tty_settings (tty, &tio) < 0) - { - _rl_release_sigint (); - return; - } - - if (_rl_enable_keypad) - _rl_control_keypad (1); - - fflush (rl_outstream); - terminal_prepped = 1; - RL_SETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} - -/* Restore the terminal's normal settings and modes. */ -void -rl_deprep_terminal () -{ - int tty; - - if (!terminal_prepped) - return; - - /* Try to keep this function from being interrupted. */ - _rl_block_sigint (); - - tty = rl_instream ? fileno (rl_instream) : fileno (stdin); - - if (_rl_enable_keypad) - _rl_control_keypad (0); - - fflush (rl_outstream); - - if (set_tty_settings (tty, &otio) < 0) - { - _rl_release_sigint (); - return; - } - - terminal_prepped = 0; - RL_UNSETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} -#endif /* !NO_TTY_DRIVER */ - -/* **************************************************************** */ -/* */ -/* Bogus Flow Control */ -/* */ -/* **************************************************************** */ - -int -rl_restart_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else /* !__MING32__ */ - - int fildes = fileno (rl_outstream); -#if defined (TIOCSTART) -#if defined (apollo) - ioctl (&fildes, TIOCSTART, 0); -#else - ioctl (fildes, TIOCSTART, 0); -#endif /* apollo */ - -#else /* !TIOCSTART */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (fildes, TCOON); - } -# else /* !ksr1 */ - tcflow (fildes, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -# else /* !TERMIOS_TTY_DRIVER */ -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTART */ - - return 0; -#endif /* !__MINGW32__ */ -} - -int -rl_stop_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else - - int fildes = fileno (rl_instream); - -#if defined (TIOCSTOP) -# if defined (apollo) - ioctl (&fildes, TIOCSTOP, 0); -# else - ioctl (fildes, TIOCSTOP, 0); -# endif /* apollo */ -#else /* !TIOCSTOP */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - ksrflow = 1; -# endif /* ksr1 */ - tcflow (fildes, TCOOFF); -# else -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTOP */ - - return 0; -#endif /* !__MINGW32__ */ -} - -/* **************************************************************** */ -/* */ -/* Default Key Bindings */ -/* */ -/* **************************************************************** */ - -#if !defined (NO_TTY_DRIVER) -#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func) -#endif - -#if defined (NO_TTY_DRIVER) - -#define SET_SPECIAL(sc, func) -#define RESET_SPECIAL(c) - -#elif defined (NEW_TTY_DRIVER) -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC) - kmap[(unsigned char)sc].function = func; -} - -#define RESET_SPECIAL(c) \ - if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \ - kmap[(unsigned char)c].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - if (ttybuff.flags & SGTTY_SET) - { - SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); - SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); - } - -# if defined (TIOCGLTC) - if (ttybuff.flags & LTCHARS_SET) - { - SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); - SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); - } -# endif /* TIOCGLTC */ -} - -#else /* !NEW_TTY_DRIVER */ -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - unsigned char uc; - - uc = tiop->c_cc[sc]; - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) - kmap[uc].function = func; -} - -/* used later */ -#define RESET_SPECIAL(uc) \ - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ - kmap[uc].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - SET_SPECIAL (VERASE, rl_rubout); - SET_SPECIAL (VKILL, rl_unix_line_discard); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VLNEXT, rl_quoted_insert); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VWERASE, rl_unix_word_rubout); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#endif /* !NEW_TTY_DRIVER */ - -/* Set the system's default editing characters to their readline equivalents - in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ -void -rltty_set_default_bindings (kmap) - Keymap kmap; -{ -#if !defined (NO_TTY_DRIVER) - TIOTYPE ttybuff; - int tty; - - tty = fileno (rl_instream); - - if (get_tty_settings (tty, &ttybuff) == 0) - _rl_bind_tty_special_chars (kmap, ttybuff); -#endif -} - -/* New public way to set the system default editing chars to their readline - equivalents. */ -void -rl_tty_set_default_bindings (kmap) - Keymap kmap; -{ - rltty_set_default_bindings (kmap); -} - -/* Rebind all of the tty special chars that readline worries about back - to self-insert. Call this before saving the current terminal special - chars with save_tty_chars(). This only works on POSIX termios or termio - systems. */ -void -rl_tty_unset_default_bindings (kmap) - Keymap kmap; -{ - /* Don't bother before we've saved the tty special chars at least once. */ - if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0) - return; - - RESET_SPECIAL (_rl_tty_chars.t_erase); - RESET_SPECIAL (_rl_tty_chars.t_kill); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_lnext); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_werase); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#if defined (HANDLE_SIGNALS) - -#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER) -int -_rl_disable_tty_signals () -{ - return 0; -} - -int -_rl_restore_tty_signals () -{ - return 0; -} -#else - -static TIOTYPE sigstty, nosigstty; -static int tty_sigs_disabled = 0; - -int -_rl_disable_tty_signals () -{ - if (tty_sigs_disabled) - return 0; - - if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0) - return -1; - - nosigstty = sigstty; - - nosigstty.c_lflag &= ~ISIG; - nosigstty.c_iflag &= ~IXON; - - if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0) - return (_set_tty_settings (fileno (rl_instream), &sigstty)); - - tty_sigs_disabled = 1; - return 0; -} - -int -_rl_restore_tty_signals () -{ - int r; - - if (tty_sigs_disabled == 0) - return 0; - - r = _set_tty_settings (fileno (rl_instream), &sigstty); - - if (r == 0) - tty_sigs_disabled = 0; - - return r; -} -#endif /* !NEW_TTY_DRIVER */ - -#endif /* HANDLE_SIGNALS */ diff --git a/lib/readline/rltty.c~ b/lib/readline/rltty.c~ deleted file mode 100644 index dd0a5cb46..000000000 --- a/lib/readline/rltty.c~ +++ /dev/null @@ -1,977 +0,0 @@ -/* rltty.c -- functions to prepare and restore the terminal for readline's - use. */ - -/* Copyright (C) 1992-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -#include "rltty.h" -#include "readline.h" -#include "rlprivate.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; -rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; - -static void set_winsize PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Saving and Restoring the TTY */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that the terminal is in a prepped state. */ -static int terminal_prepped; - -static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars; - -/* If non-zero, means that this process has called tcflow(fd, TCOOFF) - and output is suspended. */ -#if defined (__ksr1__) -static int ksrflow; -#endif - -/* Dummy call to force a backgrounded readline to stop before it tries - to get the tty settings. */ -static void -set_winsize (tty) - int tty; -{ -#if defined (TIOCGWINSZ) - struct winsize w; - - if (ioctl (tty, TIOCGWINSZ, &w) == 0) - (void) ioctl (tty, TIOCSWINSZ, &w); -#endif /* TIOCGWINSZ */ -} - -#if defined (NO_TTY_DRIVER) -/* Nothing */ -#elif defined (NEW_TTY_DRIVER) - -/* Values for the `flags' field of a struct bsdtty. This tells which - elements of the struct bsdtty have been fetched from the system and - are valid. */ -#define SGTTY_SET 0x01 -#define LFLAG_SET 0x02 -#define TCHARS_SET 0x04 -#define LTCHARS_SET 0x08 - -struct bsdtty { - struct sgttyb sgttyb; /* Basic BSD tty driver information. */ - int lflag; /* Local mode flags, like LPASS8. */ -#if defined (TIOCGETC) - struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ -#endif -#if defined (TIOCGLTC) - struct ltchars ltchars; /* 4.2 BSD editing characters */ -#endif - int flags; /* Bitmap saying which parts of the struct are valid. */ -}; - -#define TIOTYPE struct bsdtty - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - if (tiop->flags & SGTTY_SET) - { - _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase; - _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill; - } - - if (tiop->flags & TCHARS_SET) - { - _rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc; - - _rl_tty_chars.t_start = tiop->tchars.t_startc; - _rl_tty_chars.t_stop = tiop->tchars.t_stopc; - _rl_tty_chars.t_eof = tiop->tchars.t_eofc; - _rl_tty_chars.t_eol = '\n'; - _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc; - } - - if (tiop->flags & LTCHARS_SET) - { - _rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc; - - _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc; - _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc; - _rl_tty_chars.t_flush = tiop->ltchars.t_flushc; - _rl_tty_chars.t_werase = tiop->ltchars.t_werasc; - _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc; - } - - _rl_tty_chars.t_status = -1; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - tiop->flags = tiop->lflag = 0; - - errno = 0; - if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0) - return -1; - tiop->flags |= SGTTY_SET; - -#if defined (TIOCLGET) - if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0) - tiop->flags |= LFLAG_SET; -#endif - -#if defined (TIOCGETC) - if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0) - tiop->flags |= TCHARS_SET; -#endif - -#if defined (TIOCGLTC) - if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0) - tiop->flags |= LTCHARS_SET; -#endif - - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (tiop->flags & SGTTY_SET) - { - ioctl (tty, TIOCSETN, &(tiop->sgttyb)); - tiop->flags &= ~SGTTY_SET; - } - _rl_echoing_p = 1; - -#if defined (TIOCLSET) - if (tiop->flags & LFLAG_SET) - { - ioctl (tty, TIOCLSET, &(tiop->lflag)); - tiop->flags &= ~LFLAG_SET; - } -#endif - -#if defined (TIOCSETC) - if (tiop->flags & TCHARS_SET) - { - ioctl (tty, TIOCSETC, &(tiop->tchars)); - tiop->flags &= ~TCHARS_SET; - } -#endif - -#if defined (TIOCSLTC) - if (tiop->flags & LTCHARS_SET) - { - ioctl (tty, TIOCSLTC, &(tiop->ltchars)); - tiop->flags &= ~LTCHARS_SET; - } -#endif - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO); - _rl_echoctl = (oldtio.sgttyb.sg_flags & ECHOCTL); - - /* Copy the original settings to the structure we're going to use for - our settings. */ - tiop->sgttyb = oldtio.sgttyb; - tiop->lflag = oldtio.lflag; -#if defined (TIOCGETC) - tiop->tchars = oldtio.tchars; -#endif -#if defined (TIOCGLTC) - tiop->ltchars = oldtio.ltchars; -#endif - tiop->flags = oldtio.flags; - - /* First, the basic settings to put us into character-at-a-time, no-echo - input mode. */ - tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); - tiop->sgttyb.sg_flags |= CBREAK; - - /* If this terminal doesn't care how the 8th bit is used, then we can - use it for the meta-key. If only one of even or odd parity is - specified, then the terminal is using parity, and we cannot. */ -#if !defined (ANYP) -# define ANYP (EVENP | ODDP) -#endif - if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) || - ((oldtio.sgttyb.sg_flags & ANYP) == 0)) - { - tiop->sgttyb.sg_flags |= ANYP; - - /* Hack on local mode flags if we can. */ -#if defined (TIOCLGET) -# if defined (LPASS8) - tiop->lflag |= LPASS8; -# endif /* LPASS8 */ -#endif /* TIOCLGET */ - } - -#if defined (TIOCGETC) -# if defined (USE_XON_XOFF) - /* Get rid of terminal output start and stop characters. */ - tiop->tchars.t_stopc = -1; /* C-s */ - tiop->tchars.t_startc = -1; /* C-q */ - - /* If there is an XON character, bind it to restart the output. */ - if (oldtio.tchars.t_startc != -1) - rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); -# endif /* USE_XON_XOFF */ - - /* If there is an EOF char, bind _rl_eof_char to it. */ - if (oldtio.tchars.t_eofc != -1) - _rl_eof_char = oldtio.tchars.t_eofc; - -# if defined (NO_KILL_INTR) - /* Get rid of terminal-generated SIGQUIT and SIGINT. */ - tiop->tchars.t_quitc = -1; /* C-\ */ - tiop->tchars.t_intrc = -1; /* C-c */ -# endif /* NO_KILL_INTR */ -#endif /* TIOCGETC */ - -#if defined (TIOCGLTC) - /* Make the interrupt keys go away. Just enough to make people happy. */ - tiop->ltchars.t_dsuspc = -1; /* C-y */ - tiop->ltchars.t_lnextc = -1; /* C-v */ -#endif /* TIOCGLTC */ -} - -#else /* !defined (NEW_TTY_DRIVER) */ - -#if !defined (VMIN) -# define VMIN VEOF -#endif - -#if !defined (VTIME) -# define VTIME VEOL -#endif - -#define USE_XON_XOFF - -#if defined (TERMIOS_TTY_DRIVER) -# define TIOTYPE struct termios -# define DRAIN_OUTPUT(fd) tcdrain (fd) -# define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) -# ifdef M_UNIX -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) -# else -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) -# endif /* !M_UNIX */ -#else -# define TIOTYPE struct termio -# define DRAIN_OUTPUT(fd) -# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) -# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop)) -#endif /* !TERMIOS_TTY_DRIVER */ - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); -static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); - -#if defined (FLUSHO) -# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) -#else -# define OUTPUT_BEING_FLUSHED(tp) 0 -#endif - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - _rl_tty_chars.t_eof = tiop->c_cc[VEOF]; - _rl_tty_chars.t_eol = tiop->c_cc[VEOL]; -#ifdef VEOL2 - _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2]; -#endif - _rl_tty_chars.t_erase = tiop->c_cc[VERASE]; -#ifdef VWERASE - _rl_tty_chars.t_werase = tiop->c_cc[VWERASE]; -#endif - _rl_tty_chars.t_kill = tiop->c_cc[VKILL]; -#ifdef VREPRINT - _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT]; -#endif - _rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR]; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT]; -#ifdef VSUSP - _rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP]; -#endif -#ifdef VDSUSP - _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP]; -#endif -#ifdef VSTART - _rl_tty_chars.t_start = tiop->c_cc[VSTART]; -#endif -#ifdef VSTOP - _rl_tty_chars.t_stop = tiop->c_cc[VSTOP]; -#endif -#ifdef VLNEXT - _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT]; -#endif -#ifdef VDISCARD - _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD]; -#endif -#ifdef VSTATUS - _rl_tty_chars.t_status = tiop->c_cc[VSTATUS]; -#endif -} - -#if defined (_AIX) || defined (_AIX41) -/* Currently this is only used on AIX */ -static void -rltty_warning (msg) - char *msg; -{ - _rl_errmsg ("warning: %s", msg); -} -#endif - -#if defined (_AIX) -void -setopost(tp) -TIOTYPE *tp; -{ - if ((tp->c_oflag & OPOST) == 0) - { - _rl_errmsg ("warning: turning on OPOST for terminal\r"); - tp->c_oflag |= OPOST|ONLCR; - } -} -#endif - -static int -_get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - int ioctl_ret; - - while (1) - { - ioctl_ret = GETATTR (tty, tiop); - if (ioctl_ret < 0) - { - if (errno != EINTR) - return -1; - else - continue; - } - if (OUTPUT_BEING_FLUSHED (tiop)) - { -#if defined (FLUSHO) - _rl_errmsg ("warning: turning off output flushing"); - tiop->c_lflag &= ~FLUSHO; - break; -#else - continue; -#endif - } - break; - } - - return 0; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - errno = 0; - if (_get_tty_settings (tty, tiop) < 0) - return -1; - -#if defined (_AIX) - setopost(tiop); -#endif - - return 0; -} - -static int -_set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - while (SETATTR (tty, tiop) < 0) - { - if (errno != EINTR) - return -1; - errno = 0; - } - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (_set_tty_settings (tty, tiop) < 0) - return -1; - -#if 0 - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (tty, TCOON); - } -# else /* !ksr1 */ - tcflow (tty, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -#else - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -#endif /* !TERMIOS_TTY_DRIVER */ - -#endif /* 0 */ - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.c_lflag & ECHO); -#if defined (ECHOCTL) - _rl_echoctl = (oldtio.c_lflag & ECHOCTL); -#endif - - tiop->c_lflag &= ~(ICANON | ECHO); - - if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) - _rl_eof_char = oldtio.c_cc[VEOF]; - -#if defined (USE_XON_XOFF) -#if defined (IXANY) - tiop->c_iflag &= ~(IXON | IXANY); -#else - /* `strict' Posix systems do not define IXANY. */ - tiop->c_iflag &= ~IXON; -#endif /* IXANY */ -#endif /* USE_XON_XOFF */ - - /* Only turn this off if we are using all 8 bits. */ - if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) - tiop->c_iflag &= ~(ISTRIP | INPCK); - - /* Make sure we differentiate between CR and NL on input. */ - tiop->c_iflag &= ~(ICRNL | INLCR); - -#if !defined (HANDLE_SIGNALS) - tiop->c_lflag &= ~ISIG; -#else - tiop->c_lflag |= ISIG; -#endif - - tiop->c_cc[VMIN] = 1; - tiop->c_cc[VTIME] = 0; - -#if defined (FLUSHO) - if (OUTPUT_BEING_FLUSHED (tiop)) - { - tiop->c_lflag &= ~FLUSHO; - oldtio.c_lflag &= ~FLUSHO; - } -#endif - - /* Turn off characters that we need on Posix systems with job control, - just to be sure. This includes ^Y and ^V. This should not really - be necessary. */ -#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) - -#if defined (VLNEXT) - tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; -#endif - -#if defined (VDSUSP) - tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif - -#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ -} -#endif /* !NEW_TTY_DRIVER */ - -/* Put the terminal in CBREAK mode so that we can detect key presses. */ -#if defined (NO_TTY_DRIVER) -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - _rl_echoing_p = 1; -} - -void -rl_deprep_terminal () -{ -} - -#else /* ! NO_TTY_DRIVER */ -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - int tty; - TIOTYPE tio; - - if (terminal_prepped) - return; - - /* Try to keep this function from being INTerrupted. */ - _rl_block_sigint (); - - tty = rl_instream ? fileno (rl_instream) : fileno (stdin); - - if (get_tty_settings (tty, &tio) < 0) - { -#if defined (ENOTSUP) - /* MacOS X and Linux, at least, lie about the value of errno if - tcgetattr fails. */ - if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP) -#else - if (errno == ENOTTY || errno == EINVAL) -#endif - _rl_echoing_p = 1; /* XXX */ - - _rl_release_sigint (); - return; - } - - otio = tio; - - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we restore the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - rl_tty_unset_default_bindings (vi_insertion_keymap); - else -#endif - rl_tty_unset_default_bindings (_rl_keymap); - } - save_tty_chars (&otio); - RL_SETSTATE(RL_STATE_TTYCSAVED); - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we set the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - _rl_bind_tty_special_chars (vi_insertion_keymap, tio); - else -#endif - _rl_bind_tty_special_chars (_rl_keymap, tio); - } - - prepare_terminal_settings (meta_flag, otio, &tio); - - if (set_tty_settings (tty, &tio) < 0) - { - _rl_release_sigint (); - return; - } - - if (_rl_enable_keypad) - _rl_control_keypad (1); - - fflush (rl_outstream); - terminal_prepped = 1; - RL_SETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} - -/* Restore the terminal's normal settings and modes. */ -void -rl_deprep_terminal () -{ - int tty; - - if (!terminal_prepped) - return; - - /* Try to keep this function from being interrupted. */ - _rl_block_sigint (); - - tty = rl_instream ? fileno (rl_instream) : fileno (stdin); - - if (_rl_enable_keypad) - _rl_control_keypad (0); - - fflush (rl_outstream); - - if (set_tty_settings (tty, &otio) < 0) - { - _rl_release_sigint (); - return; - } - - terminal_prepped = 0; - RL_UNSETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} -#endif /* !NO_TTY_DRIVER */ - -/* **************************************************************** */ -/* */ -/* Bogus Flow Control */ -/* */ -/* **************************************************************** */ - -int -rl_restart_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else /* !__MING32__ */ - - int fildes = fileno (rl_outstream); -#if defined (TIOCSTART) -#if defined (apollo) - ioctl (&fildes, TIOCSTART, 0); -#else - ioctl (fildes, TIOCSTART, 0); -#endif /* apollo */ - -#else /* !TIOCSTART */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (fildes, TCOON); - } -# else /* !ksr1 */ - tcflow (fildes, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -# else /* !TERMIOS_TTY_DRIVER */ -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTART */ - - return 0; -#endif /* !__MINGW32__ */ -} - -int -rl_stop_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else - - int fildes = fileno (rl_instream); - -#if defined (TIOCSTOP) -# if defined (apollo) - ioctl (&fildes, TIOCSTOP, 0); -# else - ioctl (fildes, TIOCSTOP, 0); -# endif /* apollo */ -#else /* !TIOCSTOP */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - ksrflow = 1; -# endif /* ksr1 */ - tcflow (fildes, TCOOFF); -# else -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTOP */ - - return 0; -#endif /* !__MINGW32__ */ -} - -/* **************************************************************** */ -/* */ -/* Default Key Bindings */ -/* */ -/* **************************************************************** */ - -#if !defined (NO_TTY_DRIVER) -#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func) -#endif - -#if defined (NO_TTY_DRIVER) - -#define SET_SPECIAL(sc, func) -#define RESET_SPECIAL(c) - -#elif defined (NEW_TTY_DRIVER) -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC) - kmap[(unsigned char)sc].function = func; -} - -#define RESET_SPECIAL(c) \ - if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \ - kmap[(unsigned char)c].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - if (ttybuff.flags & SGTTY_SET) - { - SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); - SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); - } - -# if defined (TIOCGLTC) - if (ttybuff.flags & LTCHARS_SET) - { - SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); - SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); - } -# endif /* TIOCGLTC */ -} - -#else /* !NEW_TTY_DRIVER */ -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - unsigned char uc; - - uc = tiop->c_cc[sc]; - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) - kmap[uc].function = func; -} - -/* used later */ -#define RESET_SPECIAL(uc) \ - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ - kmap[uc].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - SET_SPECIAL (VERASE, rl_rubout); - SET_SPECIAL (VKILL, rl_unix_line_discard); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VLNEXT, rl_quoted_insert); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VWERASE, rl_unix_word_rubout); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#endif /* !NEW_TTY_DRIVER */ - -/* Set the system's default editing characters to their readline equivalents - in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ -void -rltty_set_default_bindings (kmap) - Keymap kmap; -{ -#if !defined (NO_TTY_DRIVER) - TIOTYPE ttybuff; - int tty; - - tty = fileno (rl_instream); - - if (get_tty_settings (tty, &ttybuff) == 0) - _rl_bind_tty_special_chars (kmap, ttybuff); -#endif -} - -/* New public way to set the system default editing chars to their readline - equivalents. */ -void -rl_tty_set_default_bindings (kmap) - Keymap kmap; -{ - rltty_set_default_bindings (kmap); -} - -/* Rebind all of the tty special chars that readline worries about back - to self-insert. Call this before saving the current terminal special - chars with save_tty_chars(). This only works on POSIX termios or termio - systems. */ -void -rl_tty_unset_default_bindings (kmap) - Keymap kmap; -{ - /* Don't bother before we've saved the tty special chars at least once. */ - if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0) - return; - - RESET_SPECIAL (_rl_tty_chars.t_erase); - RESET_SPECIAL (_rl_tty_chars.t_kill); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_lnext); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_werase); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#if defined (HANDLE_SIGNALS) - -#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER) -int -_rl_disable_tty_signals () -{ - return 0; -} - -int -_rl_restore_tty_signals () -{ - return 0; -} -#else - -static TIOTYPE sigstty, nosigstty; -static int tty_sigs_disabled = 0; - -int -_rl_disable_tty_signals () -{ - if (tty_sigs_disabled) - return 0; - - if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0) - return -1; - - nosigstty = sigstty; - - nosigstty.c_lflag &= ~ISIG; - nosigstty.c_iflag &= ~IXON; - - if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0) - return (_set_tty_settings (fileno (rl_instream), &sigstty)); - - tty_sigs_disabled = 1; - return 0; -} - -int -_rl_restore_tty_signals () -{ - int r; - - if (tty_sigs_disabled == 0) - return 0; - - r = _set_tty_settings (fileno (rl_instream), &sigstty); - - if (r == 0) - tty_sigs_disabled = 0; - - return r; -} -#endif /* !NEW_TTY_DRIVER */ - -#endif /* HANDLE_SIGNALS */ diff --git a/lib/readline/signals.c~ b/lib/readline/signals.c~ deleted file mode 100644 index 688c249a0..000000000 --- a/lib/readline/signals.c~ +++ /dev/null @@ -1,724 +0,0 @@ -/* signals.c -- signal handling support for readline. */ - -/* Copyright (C) 1987-2011 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include /* Just for NULL. Yuck. */ -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" - -#if defined (HANDLE_SIGNALS) - -#if !defined (RETSIGTYPE) -# if defined (VOID_SIGHANDLER) -# define RETSIGTYPE void -# else -# define RETSIGTYPE int -# endif /* !VOID_SIGHANDLER */ -#endif /* !RETSIGTYPE */ - -#if defined (VOID_SIGHANDLER) -# define SIGHANDLER_RETURN return -#else -# define SIGHANDLER_RETURN return (0) -#endif - -/* This typedef is equivalent to the one for Function; it allows us - to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef RETSIGTYPE SigHandler (); - -#if defined (HAVE_POSIX_SIGNALS) -typedef struct sigaction sighandler_cxt; -# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) -#else -typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt; -# define sigemptyset(m) -#endif /* !HAVE_POSIX_SIGNALS */ - -#ifndef SA_RESTART -# define SA_RESTART 0 -#endif - -static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); -static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); -static void rl_maybe_restore_sighandler PARAMS((int, sighandler_cxt *)); - -static RETSIGTYPE rl_signal_handler PARAMS((int)); -static RETSIGTYPE _rl_handle_signal PARAMS((int)); - -/* Exported variables for use by applications. */ - -/* If non-zero, readline will install its own signal handlers for - SIGINT, SIGTERM, SIGHUP, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ -int rl_catch_signals = 1; - -/* If non-zero, readline will install a signal handler for SIGWINCH. */ -#ifdef SIGWINCH -int rl_catch_sigwinch = 1; -#else -int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */ -#endif - -/* Private variables. */ -int _rl_interrupt_immediately = 0; -int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including everywhere */ - -/* If non-zero, print characters corresponding to received signals as long as - the user has indicated his desire to do so (_rl_echo_control_chars). */ -int _rl_echoctl = 0; - -int _rl_intr_char = 0; -int _rl_quit_char = 0; -int _rl_susp_char = 0; - -static int signals_set_flag; -static int sigwinch_set_flag; - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ - -static sighandler_cxt old_int, old_term, old_hup, old_alrm, old_quit; -#if defined (SIGTSTP) -static sighandler_cxt old_tstp, old_ttou, old_ttin; -#endif -#if defined (SIGWINCH) -static sighandler_cxt old_winch; -#endif - -_rl_sigcleanup_func_t *_rl_sigcleanup; -void *_rl_sigcleanarg; - -/* Readline signal handler functions. */ - -/* Called from RL_CHECK_SIGNALS() macro */ -RETSIGTYPE -_rl_signal_handler (sig) - int sig; -{ - _rl_caught_signal = 0; /* XXX */ - -#if defined (SIGWINCH) - if (sig == SIGWINCH) - rl_resize_terminal (); - else -#endif - _rl_handle_signal (sig); - SIGHANDLER_RETURN; -} - -static RETSIGTYPE -rl_signal_handler (sig) - int sig; -{ - if (_rl_interrupt_immediately) - { - _rl_interrupt_immediately = 0; - _rl_handle_signal (sig); - } - else - _rl_caught_signal = sig; - - SIGHANDLER_RETURN; -} - -static RETSIGTYPE -_rl_handle_signal (sig) - int sig; -{ -#if defined (HAVE_POSIX_SIGNALS) - sigset_t set; -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - long omask; -# else /* !HAVE_BSD_SIGNALS */ - sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - RL_SETSTATE(RL_STATE_SIGHANDLER); - -#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) - /* Since the signal will not be blocked while we are in the signal - handler, ignore it until rl_clear_signals resets the catcher. */ -# if defined (SIGALRM) - if (sig == SIGINT || sig == SIGALRM) -# else - if (sig == SIGINT) -# endif - rl_set_sighandler (sig, SIG_IGN, &dummy_cxt); -#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ - - /* If there's a sig cleanup function registered, call it and `deregister' - the cleanup function to avoid multiple calls */ - if (_rl_sigcleanup) - { - (*_rl_sigcleanup) (sig, _rl_sigcleanarg); - _rl_sigcleanup = 0; - _rl_sigcleanarg = 0; - } - - switch (sig) - { - case SIGINT: - _rl_reset_completion_state (); - rl_free_line_state (); - /* FALLTHROUGH */ - - case SIGTERM: - case SIGHUP: -#if defined (SIGTSTP) - case SIGTSTP: - case SIGTTOU: - case SIGTTIN: -#endif /* SIGTSTP */ -#if defined (SIGALRM) - case SIGALRM: -#endif -#if defined (SIGQUIT) - case SIGQUIT: -#endif - rl_echo_signal_char (sig); - rl_cleanup_after_signal (); - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&set); - sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set); - sigdelset (&set, sig); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - omask = sigblock (0); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#if defined (__EMX__) - signal (sig, SIG_ACK); -#endif - -#if defined (HAVE_KILL) - kill (getpid (), sig); -#else - raise (sig); /* assume we have raise */ -#endif - - /* Let the signal that we just sent through. */ -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (omask & ~(sigmask (sig))); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - rl_reset_after_signal (); - } - - RL_UNSETSTATE(RL_STATE_SIGHANDLER); - SIGHANDLER_RETURN; -} - -#if defined (SIGWINCH) -static RETSIGTYPE -rl_sigwinch_handler (sig) - int sig; -{ - SigHandler *oh; - -#if defined (MUST_REINSTALL_SIGHANDLERS) - sighandler_cxt dummy_winch; - - /* We don't want to change old_winch -- it holds the state of SIGWINCH - disposition set by the calling application. We need this state - because we call the application's SIGWINCH handler after updating - our own idea of the screen size. */ - rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch); -#endif - - RL_SETSTATE(RL_STATE_SIGHANDLER); - _rl_caught_signal = sig; - - /* If another sigwinch handler has been installed, call it. */ - oh = (SigHandler *)old_winch.sa_handler; - if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL) - (*oh) (sig); - - RL_UNSETSTATE(RL_STATE_SIGHANDLER); - SIGHANDLER_RETURN; -} -#endif /* SIGWINCH */ - -/* Functions to manage signal handling. */ - -#if !defined (HAVE_POSIX_SIGNALS) -static int -rl_sigaction (sig, nh, oh) - int sig; - sighandler_cxt *nh, *oh; -{ - oh->sa_handler = signal (sig, nh->sa_handler); - return 0; -} -#endif /* !HAVE_POSIX_SIGNALS */ - -/* Set up a readline-specific signal handler, saving the old signal - information in OHANDLER. Return the old signal handler, like - signal(). */ -static SigHandler * -rl_set_sighandler (sig, handler, ohandler) - int sig; - SigHandler *handler; - sighandler_cxt *ohandler; -{ - sighandler_cxt old_handler; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act; - - act.sa_handler = handler; -# if defined (SIGWINCH) - act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0; -# else - act.sa_flags = 0; -# endif /* SIGWINCH */ - sigemptyset (&act.sa_mask); - sigemptyset (&ohandler->sa_mask); - sigaction (sig, &act, &old_handler); -#else - old_handler.sa_handler = (SigHandler *)signal (sig, handler); -#endif /* !HAVE_POSIX_SIGNALS */ - - /* XXX -- assume we have memcpy */ - /* If rl_set_signals is called twice in a row, don't set the old handler to - rl_signal_handler, because that would cause infinite recursion. */ - if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler) - memcpy (ohandler, &old_handler, sizeof (sighandler_cxt)); - - return (ohandler->sa_handler); -} - -/* Set disposition of SIG to HANDLER, returning old state in OHANDLER. Don't - change disposition if OHANDLER indicates the signal was ignored. */ -static void -rl_maybe_set_sighandler (sig, handler, ohandler) - int sig; - SigHandler *handler; - sighandler_cxt *ohandler; -{ - sighandler_cxt dummy; - SigHandler *oh; - - sigemptyset (&dummy.sa_mask); - oh = rl_set_sighandler (sig, handler, ohandler); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (sig, ohandler, &dummy); -} - -/* Set the disposition of SIG to HANDLER, if HANDLER->sa_handler indicates the - signal was not being ignored. MUST only be called for signals whose - disposition was changed using rl_maybe_set_sighandler or for which the - SIG_IGN check was performed inline (e.g., SIGALRM below). */ -static void -rl_maybe_restore_sighandler (sig, handler) - int sig; - sighandler_cxt *handler; -{ - sighandler_cxt dummy; - - sigemptyset (&dummy.sa_mask); - if (handler->sa_handler != SIG_IGN) - rl_sigaction (sig, handler, &dummy); -} - -int -rl_set_signals () -{ - sighandler_cxt dummy; - SigHandler *oh; -#if defined (HAVE_POSIX_SIGNALS) - static int sigmask_set = 0; - static sigset_t bset, oset; -#endif - -#if defined (HAVE_POSIX_SIGNALS) - if (rl_catch_signals && sigmask_set == 0) - { - sigemptyset (&bset); - - sigaddset (&bset, SIGINT); - sigaddset (&bset, SIGTERM); - sigaddset (&bset, SIGHUP); -#if defined (SIGQUIT) - sigaddset (&bset, SIGQUIT); -#endif -#if defined (SIGALRM) - sigaddset (&bset, SIGALRM); -#endif -#if defined (SIGTSTP) - sigaddset (&bset, SIGTSTP); -#endif -#if defined (SIGTTIN) - sigaddset (&bset, SIGTTIN); -#endif -#if defined (SIGTTOU) - sigaddset (&bset, SIGTTOU); -#endif - sigmask_set = 1; - } -#endif /* HAVE_POSIX_SIGNALS */ - - if (rl_catch_signals && signals_set_flag == 0) - { -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &bset, &oset); -#endif - - rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int); - rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term); - rl_maybe_set_sighandler (SIGHUP, rl_signal_handler, &old_hup); -#if defined (SIGQUIT) - rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit); -#endif - -#if defined (SIGALRM) - oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (SIGALRM, &old_alrm, &dummy); -#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART) - /* If the application using readline has already installed a signal - handler with SA_RESTART, SIGALRM will cause reads to be restarted - automatically, so readline should just get out of the way. Since - we tested for SIG_IGN above, we can just test for SIG_DFL here. */ - if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) - rl_sigaction (SIGALRM, &old_alrm, &dummy); -#endif /* HAVE_POSIX_SIGNALS */ -#endif /* SIGALRM */ - -#if defined (SIGTSTP) - rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); -#endif /* SIGTSTP */ - -#if defined (SIGTTOU) - rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); -#endif /* SIGTTOU */ - -#if defined (SIGTTIN) - rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); -#endif /* SIGTTIN */ - - signals_set_flag = 1; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); -#endif - } - -#if defined (SIGWINCH) - if (rl_catch_sigwinch && sigwinch_set_flag == 0) - { - rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch); - sigwinch_set_flag = 1; - } -#endif /* SIGWINCH */ - - return 0; -} - -int -rl_clear_signals () -{ - sighandler_cxt dummy; - - if (rl_catch_signals && signals_set_flag == 1) - { - sigemptyset (&dummy.sa_mask); - - /* Since rl_maybe_set_sighandler doesn't override a SIG_IGN handler, - we should in theory not have to restore a handler where - old_xxx.sa_handler == SIG_IGN. That's what rl_maybe_restore_sighandler - does. Fewer system calls should reduce readline's per-line - overhead */ - rl_maybe_restore_sighandler (SIGINT, &old_int); - rl_maybe_restore_sighandler (SIGTERM, &old_term); - rl_maybe_restore_sighandler (SIGHUP, &old_hup); -#if defined (SIGQUIT) - rl_maybe_restore_sighandler (SIGQUIT, &old_quit); -#endif -#if defined (SIGALRM) - rl_maybe_restore_sighandler (SIGALRM, &old_alrm); -#endif - -#if defined (SIGTSTP) - rl_maybe_restore_sighandler (SIGTSTP, &old_tstp); -#endif /* SIGTSTP */ - -#if defined (SIGTTOU) - rl_maybe_restore_sighandler (SIGTTOU, &old_ttou); -#endif /* SIGTTOU */ - -#if defined (SIGTTIN) - rl_maybe_restore_sighandler (SIGTTIN, &old_ttin); -#endif /* SIGTTIN */ - - signals_set_flag = 0; - } - -#if defined (SIGWINCH) - if (rl_catch_sigwinch && sigwinch_set_flag == 1) - { - sigemptyset (&dummy.sa_mask); - rl_sigaction (SIGWINCH, &old_winch, &dummy); - sigwinch_set_flag = 0; - } -#endif - - return 0; -} - -/* Clean up the terminal and readline state after catching a signal, before - resending it to the calling application. */ -void -rl_cleanup_after_signal () -{ - _rl_clean_up_for_exit (); - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - rl_clear_pending_input (); - rl_clear_signals (); -} - -/* Reset the terminal and readline state after a signal handler returns. */ -void -rl_reset_after_signal () -{ - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - rl_set_signals (); -} - -/* Free up the readline variable line state for the current line (undo list, - any partial history entry, any keyboard macros in progress, and any - numeric arguments in process) after catching a signal, before calling - rl_cleanup_after_signal(). */ -void -rl_free_line_state () -{ - register HIST_ENTRY *entry; - - rl_free_undo_list (); - - entry = current_history (); - if (entry) - entry->data = (char *)NULL; - - _rl_kill_kbd_macro (); - rl_clear_message (); - _rl_reset_argument (); -} - -#endif /* HANDLE_SIGNALS */ - -/* **************************************************************** */ -/* */ -/* SIGINT Management */ -/* */ -/* **************************************************************** */ - -#if defined (HAVE_POSIX_SIGNALS) -static sigset_t sigint_set, sigint_oset; -static sigset_t sigwinch_set, sigwinch_oset; -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) -static int sigint_oldmask; -static int sigwinch_oldmask; -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -static int sigint_blocked; -static int sigwinch_blocked; - -/* Cause SIGINT to not be delivered until the corresponding call to - release_sigint(). */ -void -_rl_block_sigint () -{ - if (sigint_blocked) - return; - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&sigint_set); - sigemptyset (&sigint_oset); - sigaddset (&sigint_set, SIGINT); - sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigint_oldmask = sigblock (sigmask (SIGINT)); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sighold (SIGINT); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - sigint_blocked = 1; -} - -/* Allow SIGINT to be delivered. */ -void -_rl_release_sigint () -{ - if (sigint_blocked == 0) - return; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (sigint_oldmask); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sigrelse (SIGINT); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - sigint_blocked = 0; -} - -/* Cause SIGWINCH to not be delivered until the corresponding call to - release_sigwinch(). */ -void -_rl_block_sigwinch () -{ - if (sigwinch_blocked) - return; - -#if defined (SIGWINCH) - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&sigwinch_set); - sigemptyset (&sigwinch_oset); - sigaddset (&sigwinch_set, SIGWINCH); - sigprocmask (SIG_BLOCK, &sigwinch_set, &sigwinch_oset); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigwinch_oldmask = sigblock (sigmask (SIGWINCH)); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sighold (SIGWINCH); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#endif /* SIGWINCH */ - - sigwinch_blocked = 1; -} - -/* Allow SIGWINCH to be delivered. */ -void -_rl_release_sigwinch () -{ - if (sigwinch_blocked == 0) - return; - -#if defined (SIGWINCH) - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &sigwinch_oset, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (sigwinch_oldmask); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sigrelse (SIGWINCH); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#endif /* SIGWINCH */ - - sigwinch_blocked = 0; -} - -/* **************************************************************** */ -/* */ -/* Echoing special control characters */ -/* */ -/* **************************************************************** */ -void -rl_echo_signal_char (sig) - int sig; -{ - char cstr[3]; - int cslen, c; - - if (_rl_echoctl == 0 || _rl_echo_control_chars == 0) - return; - - switch (sig) - { - case SIGINT: c = _rl_intr_char; break; -#if defined (SIGQUIT) - case SIGQUIT: c = _rl_quit_char; break; -#endif -#if defined (SIGTSTP) - case SIGTSTP: c = _rl_susp_char; break; -#endif - default: return; - } - - if (CTRL_CHAR (c) || c == RUBOUT) - { - cstr[0] = '^'; - cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; - cstr[cslen = 2] = '\0'; - } - else - { - cstr[0] = c; - cstr[cslen = 1] = '\0'; - } - - _rl_output_some_chars (cstr, cslen); -} diff --git a/lib/readline/util.c~ b/lib/readline/util.c~ deleted file mode 100644 index 5882371a7..000000000 --- a/lib/readline/util.c~ +++ /dev/null @@ -1,583 +0,0 @@ -/* util.c -- readline utility functions */ - -/* Copyright (C) 1987-2012 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline 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. - - Readline 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 Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include "posixjmp.h" - -#if defined (HAVE_UNISTD_H) -# include /* for _POSIX_VERSION */ -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (TIOCSTAT_IN_SYS_IOCTL) -# include -#endif /* TIOCSTAT_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Return 0 if C is not a member of the class of characters that belong - in words, or 1 if it is. */ - -int _rl_allow_pathname_alphabetic_chars = 0; -static const char * const pathname_alphabetic_chars = "/-_=~.#$"; - -int -rl_alphabetic (c) - int c; -{ - if (ALPHABETIC (c)) - return (1); - - return (_rl_allow_pathname_alphabetic_chars && - strchr (pathname_alphabetic_chars, c) != NULL); -} - -#if defined (HANDLE_MULTIBYTE) -int -_rl_walphabetic (wchar_t wc) -{ - int c; - - if (iswalnum (wc)) - return (1); - - c = wc & 0177; - return (_rl_allow_pathname_alphabetic_chars && - strchr (pathname_alphabetic_chars, c) != NULL); -} -#endif - -/* How to abort things. */ -int -_rl_abort_internal () -{ - rl_ding (); - rl_clear_message (); - _rl_reset_argument (); - rl_clear_pending_input (); - - RL_UNSETSTATE (RL_STATE_MACRODEF); - while (rl_executing_macro) - _rl_pop_executing_macro (); - - rl_last_func = (rl_command_func_t *)NULL; - longjmp (_rl_top_level, 1); - return (0); -} - -int -rl_abort (count, key) - int count, key; -{ - return (_rl_abort_internal ()); -} - -int -_rl_null_function (count, key) - int count, key; -{ - return 0; -} - -int -rl_tty_status (count, key) - int count, key; -{ -#if defined (TIOCSTAT) - ioctl (1, TIOCSTAT, (char *)0); - rl_refresh_line (count, key); -#else - rl_ding (); -#endif - return 0; -} - -/* Return a copy of the string between FROM and TO. - FROM is inclusive, TO is not. */ -char * -rl_copy_text (from, to) - int from, to; -{ - register int length; - char *copy; - - /* Fix it if the caller is confused. */ - if (from > to) - SWAP (from, to); - - length = to - from; - copy = (char *)xmalloc (1 + length); - strncpy (copy, rl_line_buffer + from, length); - copy[length] = '\0'; - return (copy); -} - -/* Increase the size of RL_LINE_BUFFER until it has enough space to hold - LEN characters. */ -void -rl_extend_line_buffer (len) - int len; -{ - while (len >= rl_line_buffer_len) - { - rl_line_buffer_len += DEFAULT_BUFFER_SIZE; - rl_line_buffer = (char *)xrealloc (rl_line_buffer, rl_line_buffer_len); - } - - _rl_set_the_line (); -} - - -/* A function for simple tilde expansion. */ -int -rl_tilde_expand (ignore, key) - int ignore, key; -{ - register int start, end; - char *homedir, *temp; - int len; - - end = rl_point; - start = end - 1; - - if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') - { - homedir = tilde_expand ("~"); - _rl_replace_text (homedir, start, end); - xfree (homedir); - return (0); - } - else if (rl_line_buffer[start] != '~') - { - for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) - ; - start++; - } - - end = start; - do - end++; - while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); - - if (whitespace (rl_line_buffer[end]) || end >= rl_end) - end--; - - /* If the first character of the current word is a tilde, perform - tilde expansion and insert the result. If not a tilde, do - nothing. */ - if (rl_line_buffer[start] == '~') - { - len = end - start + 1; - temp = (char *)xmalloc (len + 1); - strncpy (temp, rl_line_buffer + start, len); - temp[len] = '\0'; - homedir = tilde_expand (temp); - xfree (temp); - - _rl_replace_text (homedir, start, end); - xfree (homedir); - } - - return (0); -} - -#if defined (USE_VARARGS) -void -#if defined (PREFER_STDARG) -_rl_ttymsg (const char *format, ...) -#else -_rl_ttymsg (va_alist) - va_dcl -#endif -{ - va_list args; -#if defined (PREFER_VARARGS) - char *format; -#endif - -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); - format = va_arg (args, char *); -#endif - - fprintf (stderr, "readline: "); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - fflush (stderr); - - va_end (args); - - rl_forced_update_display (); -} - -void -#if defined (PREFER_STDARG) -_rl_errmsg (const char *format, ...) -#else -_rl_errmsg (va_alist) - va_dcl -#endif -{ - va_list args; -#if defined (PREFER_VARARGS) - char *format; -#endif - -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); - format = va_arg (args, char *); -#endif - - fprintf (stderr, "readline: "); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - fflush (stderr); - - va_end (args); -} - -#else /* !USE_VARARGS */ -void -_rl_ttymsg (format, arg1, arg2) - char *format; -{ - fprintf (stderr, "readline: "); - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); - - rl_forced_update_display (); -} - -void -_rl_errmsg (format, arg1, arg2) - char *format; -{ - fprintf (stderr, "readline: "); - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); -} -#endif /* !USE_VARARGS */ - -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -char * -_rl_strindex (s1, s2) - register const char *s1, *s2; -{ - register int i, l, len; - - for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++) - if (_rl_strnicmp (s1 + i, s2, l) == 0) - return ((char *) (s1 + i)); - return ((char *)NULL); -} - -#ifndef HAVE_STRPBRK -/* Find the first occurrence in STRING1 of any character from STRING2. - Return a pointer to the character in STRING1. */ -char * -_rl_strpbrk (string1, string2) - const char *string1, *string2; -{ - register const char *scan; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - register int i, v; - - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - for (; *string1; string1++) - { - for (scan = string2; *scan; scan++) - { - if (*string1 == *scan) - return ((char *)string1); - } -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - v = _rl_get_char_len (string1, &ps); - if (v > 1) - string1 += v - 1; /* -1 to account for auto-increment in loop */ - } -#endif - } - return ((char *)NULL); -} -#endif - -#if !defined (HAVE_STRCASECMP) -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter (strncasecmp). */ -int -_rl_strnicmp (string1, string2, count) - char *string1, *string2; - int count; -{ - register char *s1, *s2; - int d; - - if (count <= 0 || (string1 == string2)) - return 0; - - s1 = string1; - s2 = string2; - do - { - d = _rl_to_lower (*s1) - _rl_to_lower (*s2); /* XXX - cast to unsigned char? */ - if (d != 0) - return d; - if (*s1++ == '\0') - break; - s2++; - } - while (--count != 0) - - return (0); -} - -/* strcmp (), but caseless (strcasecmp). */ -int -_rl_stricmp (string1, string2) - char *string1, *string2; -{ - register char *s1, *s2; - int d; - - s1 = string1; - s2 = string2; - - if (s1 == s2) - return 0; - - while ((d = _rl_to_lower (*s1) - _rl_to_lower (*s2)) == 0) - { - if (*s1++ == '\0') - return 0; - s2++; - } - - return (d); -} -#endif /* !HAVE_STRCASECMP */ - -/* Stupid comparison routine for qsort () ing strings. */ -int -_rl_qsort_string_compare (s1, s2) - char **s1, **s2; -{ -#if defined (HAVE_STRCOLL) - return (strcoll (*s1, *s2)); -#else - int result; - - result = **s1 - **s2; - if (result == 0) - result = strcmp (*s1, *s2); - - return result; -#endif -} - -/* Function equivalents for the macros defined in chardefs.h. */ -#define FUNCTION_FOR_MACRO(f) int (f) (c) int c; { return f (c); } - -FUNCTION_FOR_MACRO (_rl_digit_p) -FUNCTION_FOR_MACRO (_rl_digit_value) -FUNCTION_FOR_MACRO (_rl_lowercase_p) -FUNCTION_FOR_MACRO (_rl_pure_alphabetic) -FUNCTION_FOR_MACRO (_rl_to_lower) -FUNCTION_FOR_MACRO (_rl_to_upper) -FUNCTION_FOR_MACRO (_rl_uppercase_p) - -/* A convenience function, to force memory deallocation to be performed - by readline. DLLs on Windows apparently require this. */ -void -rl_free (mem) - void *mem; -{ - if (mem) - free (mem); -} - -/* Backwards compatibility, now that savestring has been removed from - all `public' readline header files. */ -#undef _rl_savestring -char * -_rl_savestring (s) - const char *s; -{ - return (strcpy ((char *)xmalloc (1 + (int)strlen (s)), (s))); -} - -#if defined (USE_VARARGS) -static FILE *_rl_tracefp; - -void -#if defined (PREFER_STDARG) -_rl_trace (const char *format, ...) -#else -_rl_trace (va_alist) - va_dcl -#endif -{ - va_list args; -#if defined (PREFER_VARARGS) - char *format; -#endif - -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); - format = va_arg (args, char *); -#endif - - if (_rl_tracefp == 0) - _rl_tropen (); - vfprintf (_rl_tracefp, format, args); - fprintf (_rl_tracefp, "\n"); - fflush (_rl_tracefp); - - va_end (args); -} - -int -_rl_tropen () -{ - char fnbuf[128]; - - if (_rl_tracefp) - fclose (_rl_tracefp); - sprintf (fnbuf, "/var/tmp/rltrace.%ld", (long)getpid()); - unlink(fnbuf); - _rl_tracefp = fopen (fnbuf, "w+"); - return _rl_tracefp != 0; -} - -int -_rl_trclose () -{ - int r; - - r = fclose (_rl_tracefp); - _rl_tracefp = 0; - return r; -} - -void -_rl_settracefp (fp) - FILE *fp; -{ - _rl_tracefp = fp; -} -#endif - - -#if HAVE_DECL_AUDIT_USER_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT) -#include -#include -#include - -/* Report STRING to the audit system. */ -void -_rl_audit_tty (string) - char *string; -{ - struct sockaddr_nl addr; - struct msghdr msg; - struct nlmsghdr nlm; - struct iovec iov[2]; - size_t size; - int fd; - - fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_AUDIT); - if (fd < 0) - return; - size = strlen (string) + 1; - - nlm.nlmsg_len = NLMSG_LENGTH (size); - nlm.nlmsg_type = AUDIT_USER_TTY; - nlm.nlmsg_flags = NLM_F_REQUEST; - nlm.nlmsg_seq = 0; - nlm.nlmsg_pid = 0; - - iov[0].iov_base = &nlm; - iov[0].iov_len = sizeof (nlm); - iov[1].iov_base = string; - iov[1].iov_len = size; - - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0; - - msg.msg_name = &addr; - msg.msg_namelen = sizeof (addr); - msg.msg_iov = iov; - msg.msg_iovlen = 2; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - (void)sendmsg (fd, &msg, 0); - close (fd); -} -#endif diff --git a/lib/sh/clktck.c~ b/lib/sh/clktck.c~ deleted file mode 100644 index 096ce06e5..000000000 --- a/lib/sh/clktck.c~ +++ /dev/null @@ -1,59 +0,0 @@ -/* clktck.c - get the value of CLK_TCK. */ - -/* Copyright (C) 1997 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 . -*/ - -#include - -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_LIMITS_H) -# include -#endif - -#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK) -# if !defined (CLK_TCK) -# if defined (HZ) -# define CLK_TCK HZ -# else -# define CLK_TCK 60 -# endif -# endif /* !CLK_TCK */ -#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */ - -long -get_clk_tck () -{ - static long retval = 0; - - if (retval != 0) - return (retval); - -#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK) - retval = sysconf (_SC_CLK_TCK); -#else /* !SYSCONF || !_SC_CLK_TCK */ - retval = CLK_TCK; -#endif /* !SYSCONF || !_SC_CLK_TCK */ - - return (retval); -} diff --git a/lib/sh/inet_aton.c~ b/lib/sh/inet_aton.c~ deleted file mode 100644 index 4b48456f4..000000000 --- a/lib/sh/inet_aton.c~ +++ /dev/null @@ -1,212 +0,0 @@ -/* inet_aton - convert string to numeric IP address */ - -/* Snagged from GNU C library, version 2.0.3. */ - -/* - * ++Copyright++ 1983, 1990, 1993 - * - - * Copyright (c) 1983, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - - * --Copyright-- - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; -static char rcsid[] = "$Id: inet_addr.c,v 1.5 1996/08/14 03:48:37 drepper Exp $"; -#endif /* LIBC_SCCS and not lint */ - -#include - -#if !defined (HAVE_INET_ATON) && defined (HAVE_NETWORK) && defined (HAVE_NETINET_IN_H) && defined (HAVE_ARPA_INET_H) - -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include -#include -#include - -#ifndef INADDR_NONE -# define INADDR_NONE 0xffffffff -#endif - -/* these are compatibility routines, not needed on recent BSD releases */ - -#if 0 -/* Not used, not needed. */ -/* - * Ascii internet address interpretation routine. - * The value returned is in network order. - */ -u_long -inet_addr(cp) - register const char *cp; -{ - struct in_addr val; - - if (inet_aton(cp, &val)) - return (val.s_addr); - return (INADDR_NONE); -} -#endif - -/* - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - */ -int -inet_aton(cp, addr) - register const char *cp; - struct in_addr *addr; -{ - register u_bits32_t val; - register int base, n; - register unsigned char c; - u_int parts[4]; - register u_int *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ -#if 0 - if (!isdigit(c)) -#else - if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && - c != '5' && c != '6' && c != '7' && c != '8' && c != '9') -#endif - return (0); - val = 0; base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') - base = 16, c = *++cp; - else - base = 8; - } - for (;;) { - if (isascii(c) && isdigit(c)) { - val = (val * base) + (c - '0'); - c = *++cp; - } else if (base == 16 && isascii(c) && isxdigit(c)) { - val = (val << 4) | - (c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) - return (0); - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) - return (0); - /* - * Concoct the address according to - * the number of parts specified. - */ - n = pp - parts + 1; - switch (n) { - - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return (0); - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - if (addr) - addr->s_addr = htonl(val); - return (1); -} - -#endif /* !HAVE_INET_ATON */ diff --git a/lib/sh/mailstat.c~ b/lib/sh/mailstat.c~ deleted file mode 100644 index 2b2ac0eaf..000000000 --- a/lib/sh/mailstat.c~ +++ /dev/null @@ -1,159 +0,0 @@ -/* mailstat.c -- stat a mailbox file, handling maildir-type mail directories */ - -/* Copyright (C) 2001 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 . -*/ - -#include - -#include -#include - -#include -#include -#include -#include - -#ifndef _MINIX -# include -#endif - -#include - -/* - * Stat a file. If it's a maildir, check all messages - * in the maildir and present the grand total as a file. - * The fields in the 'struct stat' are from the mail directory. - * The following fields are emulated: - * - * st_nlink always 1, unless st_blocks is not present, in which case it's - * the total number of messages - * st_size total number of bytes in all files - * st_blocks total number of messages, if present in struct stat - * st_atime access time of newest file in maildir - * st_mtime modify time of newest file in maildir - * st_mode S_IFDIR changed to S_IFREG - * - * This is good enough for most mail-checking applications. - */ - -int -mailstat(path, st) - const char *path; - struct stat *st; -{ - static struct stat st_new_last, st_ret_last; - struct stat st_ret, st_tmp; - DIR *dd; - struct dirent *fn; - char dir[PATH_MAX * 2], file[PATH_MAX * 2]; - int i, l; - time_t atime, mtime; - - atime = mtime = 0; - - /* First see if it's a directory. */ - if ((i = stat(path, st)) != 0 || S_ISDIR(st->st_mode) == 0) - return i; - - if (strlen(path) > sizeof(dir) - 5) - { -#ifdef ENAMETOOLONG - errno = ENAMETOOLONG; -#else - errno = EINVAL; -#endif - return -1; - } - - st_ret = *st; - st_ret.st_nlink = 1; - st_ret.st_size = 0; -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - st_ret.st_blocks = 0; -#else - st_ret.st_nlink = 0; -#endif - st_ret.st_mode &= ~S_IFDIR; - st_ret.st_mode |= S_IFREG; - - /* See if cur/ is present */ - sprintf(dir, "%s/cur", path); - if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0) - return 0; - st_ret.st_atime = st_tmp.st_atime; - - /* See if tmp/ is present */ - sprintf(dir, "%s/tmp", path); - if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0) - return 0; - st_ret.st_mtime = st_tmp.st_mtime; - - /* And new/ */ - sprintf(dir, "%s/new", path); - if (stat(dir, &st_tmp) || S_ISDIR(st_tmp.st_mode) == 0) - return 0; - st_ret.st_mtime = st_tmp.st_mtime; - - /* Optimization - if new/ didn't change, nothing else did. */ - if (st_tmp.st_dev == st_new_last.st_dev && - st_tmp.st_ino == st_new_last.st_ino && - st_tmp.st_atime == st_new_last.st_atime && - st_tmp.st_mtime == st_new_last.st_mtime) - { - *st = st_ret_last; - return 0; - } - st_new_last = st_tmp; - - /* Loop over new/ and cur/ */ - for (i = 0; i < 2; i++) - { - sprintf(dir, "%s/%s", path, i ? "cur" : "new"); - sprintf(file, "%s/", dir); - l = strlen(file); - if ((dd = opendir(dir)) == NULL) - return 0; - while ((fn = readdir(dd)) != NULL) - { - if (fn->d_name[0] == '.' || strlen(fn->d_name) + l >= sizeof(file)) - continue; - strcpy(file + l, fn->d_name); - if (stat(file, &st_tmp) != 0) - continue; - st_ret.st_size += st_tmp.st_size; -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - st_ret.st_blocks++; -#else - st_ret.st_nlink++; -#endif - if (st_tmp.st_atime != st_tmp.st_mtime && st_tmp.st_atime > atime) - atime = st_tmp.st_atime; - if (st_tmp.st_mtime > mtime) - mtime = st_tmp.st_mtime; - } - closedir(dd); - } - -/* if (atime) */ /* Set atime even if cur/ is empty */ - st_ret.st_atime = atime; - if (mtime) - st_ret.st_mtime = mtime; - - *st = st_ret_last = st_ret; - return 0; -} diff --git a/lib/sh/oslib.c~ b/lib/sh/oslib.c~ deleted file mode 100644 index b3470d166..000000000 --- a/lib/sh/oslib.c~ +++ /dev/null @@ -1,301 +0,0 @@ -/* oslib.c - functions present only in some unix versions. */ - -/* Copyright (C) 1995,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 . -*/ - -#include - -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_LIMITS_H) -# include -#endif - -#include -#include -#include - -#if !defined (HAVE_KILLPG) -# include -#endif - -#include -#include -#include - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* Make the functions strchr and strrchr if they do not exist. */ -#if !defined (HAVE_STRCHR) -char * -strchr (string, c) - char *string; - int c; -{ - register char *s; - - for (s = string; s && *s; s++) - if (*s == c) - return (s); - - return ((char *) NULL); -} - -char * -strrchr (string, c) - char *string; - int c; -{ - register char *s, *t; - - for (s = string, t = (char *)NULL; s && *s; s++) - if (*s == c) - t = s; - return (t); -} -#endif /* !HAVE_STRCHR */ - -#if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) -/* Replacement for dup2 (), for those systems which either don't have it, - or supply one with broken behaviour. */ -int -dup2 (fd1, fd2) - int fd1, fd2; -{ - int saved_errno, r; - - /* If FD1 is not a valid file descriptor, then return immediately with - an error. */ - if (fcntl (fd1, F_GETFL, 0) == -1) - return (-1); - - if (fd2 < 0 || fd2 >= getdtablesize ()) - { - errno = EBADF; - return (-1); - } - - if (fd1 == fd2) - return (0); - - saved_errno = errno; - - (void) close (fd2); - r = fcntl (fd1, F_DUPFD, fd2); - - if (r >= 0) - errno = saved_errno; - else - if (errno == EINVAL) - errno = EBADF; - - /* Force the new file descriptor to remain open across exec () calls. */ - SET_OPEN_ON_EXEC (fd2); - return (r); -} -#endif /* !HAVE_DUP2 */ - -/* - * Return the total number of available file descriptors. - * - * On some systems, like 4.2BSD and its descendents, there is a system call - * that returns the size of the descriptor table: getdtablesize(). There are - * lots of ways to emulate this on non-BSD systems. - * - * On System V.3, this can be obtained via a call to ulimit: - * return (ulimit(4, 0L)); - * - * On other System V systems, NOFILE is defined in /usr/include/sys/param.h - * (this is what we assume below), so we can simply use it: - * return (NOFILE); - * - * On POSIX systems, there are specific functions for retrieving various - * configuration parameters: - * return (sysconf(_SC_OPEN_MAX)); - * - */ - -#if !defined (HAVE_GETDTABLESIZE) -int -getdtablesize () -{ -# if defined (_POSIX_VERSION) && defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) - return (sysconf(_SC_OPEN_MAX)); /* Posix systems use sysconf */ -# else /* ! (_POSIX_VERSION && HAVE_SYSCONF && _SC_OPEN_MAX) */ -# if defined (ULIMIT_MAXFDS) - return (ulimit (4, 0L)); /* System V.3 systems use ulimit(4, 0L) */ -# else /* !ULIMIT_MAXFDS */ -# if defined (NOFILE) /* Other systems use NOFILE */ - return (NOFILE); -# else /* !NOFILE */ - return (20); /* XXX - traditional value is 20 */ -# endif /* !NOFILE */ -# endif /* !ULIMIT_MAXFDS */ -# endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */ -} -#endif /* !HAVE_GETDTABLESIZE */ - -#if !defined (HAVE_BCOPY) -# if defined (bcopy) -# undef bcopy -# endif -void -bcopy (s,d,n) - char *d, *s; - int n; -{ - FASTCOPY (s, d, n); -} -#endif /* !HAVE_BCOPY */ - -#if !defined (HAVE_BZERO) -# if defined (bzero) -# undef bzero -# endif -void -bzero (s, n) - char *s; - int n; -{ - register int i; - register char *r; - - for (i = 0, r = s; i < n; i++) - *r++ = '\0'; -} -#endif - -#if !defined (HAVE_GETHOSTNAME) -# if defined (HAVE_UNAME) -# include -int -gethostname (name, namelen) - char *name; - int namelen; -{ - int i; - struct utsname ut; - - --namelen; - - uname (&ut); - i = strlen (ut.nodename) + 1; - strncpy (name, ut.nodename, i < namelen ? i : namelen); - name[namelen] = '\0'; - return (0); -} -# else /* !HAVE_UNAME */ -int -gethostname (name, namelen) - char *name; - int namelen; -{ - strncpy (name, "unknown", namelen); - name[namelen] = '\0'; - return 0; -} -# endif /* !HAVE_UNAME */ -#endif /* !HAVE_GETHOSTNAME */ - -#if !defined (HAVE_KILLPG) -int -killpg (pgrp, sig) - pid_t pgrp; - int sig; -{ - return (kill (-pgrp, sig)); -} -#endif /* !HAVE_KILLPG */ - -#if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION) -int -mkfifo (path, mode) - char *path; - int mode; -{ -#if defined (S_IFIFO) - return (mknod (path, (mode | S_IFIFO), 0)); -#else /* !S_IFIFO */ - return (-1); -#endif /* !S_IFIFO */ -} -#endif /* !HAVE_MKFIFO && PROCESS_SUBSTITUTION */ - -#define DEFAULT_MAXGROUPS 64 - -int -getmaxgroups () -{ - static int maxgroups = -1; - - if (maxgroups > 0) - return maxgroups; - -#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX) - maxgroups = sysconf (_SC_NGROUPS_MAX); -#else -# if defined (NGROUPS_MAX) - maxgroups = NGROUPS_MAX; -# else /* !NGROUPS_MAX */ -# if defined (NGROUPS) - maxgroups = NGROUPS; -# else /* !NGROUPS */ - maxgroups = DEFAULT_MAXGROUPS; -# endif /* !NGROUPS */ -# endif /* !NGROUPS_MAX */ -#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */ - - if (maxgroups <= 0) - maxgroups = DEFAULT_MAXGROUPS; - - return maxgroups; -} - -long -getmaxchild () -{ - static long maxchild = -1L; - - if (maxchild > 0) - return maxchild; - -#if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX) - maxchild = sysconf (_SC_CHILD_MAX); -#else -# if defined (CHILD_MAX) - maxchild = CHILD_MAX; -# else -# if defined (MAXUPRC) - maxchild = MAXUPRC; -# endif /* MAXUPRC */ -# endif /* CHILD_MAX */ -#endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */ - - return (maxchild); -} diff --git a/lib/sh/pathcanon.c~ b/lib/sh/pathcanon.c~ deleted file mode 100644 index 98e41cedf..000000000 --- a/lib/sh/pathcanon.c~ +++ /dev/null @@ -1,234 +0,0 @@ -/* pathcanon.c -- canonicalize and manipulate pathnames. */ - -/* Copyright (C) 2000 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 . -*/ - -#include - -#include -#ifndef _MINIX -# include -#endif -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include -#include -#include -#include - -#include "shell.h" - -#if !defined (errno) -extern int errno; -#endif - -#if defined (__CYGWIN__) -#include - -static int -_is_cygdrive (path) - char *path; -{ - static char user[MAXPATHLEN]; - static char system[MAXPATHLEN]; - static int first_time = 1; - - /* If the path is the first part of a network path, treat it as - existing. */ - if (path[0] == '/' && path[1] == '/' && !strchr (path + 2, '/')) - return 1; - /* Otherwise check for /cygdrive prefix. */ - if (first_time) - { - char user_flags[MAXPATHLEN]; - char system_flags[MAXPATHLEN]; - /* Get the cygdrive info */ - cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags, system_flags); - first_time = 0; - } - return !strcasecmp (path, user) || !strcasecmp (path, system); -} -#endif /* __CYGWIN__ */ - -/* Return 1 if PATH corresponds to a directory. A function for debugging. */ -static int -_path_isdir (path) - char *path; -{ - int l; - struct stat sb; - - /* This should leave errno set to the correct value. */ - errno = 0; - l = stat (path, &sb) == 0 && S_ISDIR (sb.st_mode); -#if defined (__CYGWIN__) - if (l == 0) - l = _is_cygdrive (path); -#endif - return l; -} - -/* Canonicalize PATH, and return a new path. The new path differs from PATH - in that: - Multple `/'s are collapsed to a single `/'. - Leading `./'s and trailing `/.'s are removed. - Trailing `/'s are removed. - Non-leading `../'s and trailing `..'s are handled by removing - portions of the path. */ - -/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */ - -#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/') - -char * -sh_canonpath (path, flags) - char *path; - int flags; -{ - char stub_char; - char *result, *p, *q, *base, *dotdot; - int rooted, double_slash_path; - - /* The result cannot be larger than the input PATH. */ - result = (flags & PATH_NOALLOC) ? path : savestring (path); - - /* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any - leading `x:' (dos drive name). */ - if (rooted = ROOTEDPATH(path)) - { - stub_char = DIRSEP; -#if defined (__CYGWIN__) - base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 3 : result + 1; -#else - base = result + 1; -#endif - double_slash_path = DOUBLE_SLASH (path); - base += double_slash_path; - } - else - { - stub_char = '.'; -#if defined (__CYGWIN__) - base = (ISALPHA((unsigned char)result[0]) && result[1] == ':') ? result + 2 : result; -#else - base = result; -#endif - double_slash_path = 0; - } - - /* - * invariants: - * base points to the portion of the path we want to modify - * p points at beginning of path element we're considering. - * q points just past the last path element we wrote (no slash). - * dotdot points just past the point where .. cannot backtrack - * any further (no slash). - */ - p = q = dotdot = base; - - while (*p) - { - if (ISDIRSEP(p[0])) /* null element */ - p++; - else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */ - p += 1; /* don't count the separator in case it is nul */ - else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */ - { - p += 2; /* skip `..' */ - if (q > dotdot) /* can backtrack */ - { - if (flags & PATH_CHECKDOTDOT) - { - char c; - - /* Make sure what we have so far corresponds to a valid - path before we chop some of it off. */ - c = *q; - *q = '\0'; - if (_path_isdir (result) == 0) - { - if ((flags & PATH_NOALLOC) == 0) - free (result); - return ((char *)NULL); - } - *q = c; - } - - while (--q > dotdot && ISDIRSEP(*q) == 0) - ; - } - else if (rooted == 0) - { - /* /.. is / but ./../ is .. */ - if (q != base) - *q++ = DIRSEP; - *q++ = '.'; - *q++ = '.'; - dotdot = q; - } - } - else /* real path element */ - { - /* add separator if not at start of work portion of result */ - if (q != base) - *q++ = DIRSEP; - while (*p && (ISDIRSEP(*p) == 0)) - *q++ = *p++; - /* Check here for a valid directory with _path_isdir. */ - if (flags & PATH_CHECKEXISTS) - { - char c; - - /* Make sure what we have so far corresponds to a valid - path before we chop some of it off. */ - c = *q; - *q = '\0'; - if (_path_isdir (result) == 0) - { - if ((flags & PATH_NOALLOC) == 0) - free (result); - return ((char *)NULL); - } - *q = c; - } - } - } - - /* Empty string is really ``.'' or `/', depending on what we started with. */ - if (q == result) - *q++ = stub_char; - *q = '\0'; - - /* If the result starts with `//', but the original path does not, we - can turn the // into /. Because of how we set `base', this should never - be true, but it's a sanity check. */ - if (DOUBLE_SLASH(result) && double_slash_path == 0) - { - if (result[2] == '\0') /* short-circuit for bare `//' */ - result[1] = '\0'; - else - strcpy (result, result + 1); - } - - return (result); -} diff --git a/lib/sh/pathphys.c~ b/lib/sh/pathphys.c~ deleted file mode 100644 index 15fcd2500..000000000 --- a/lib/sh/pathphys.c~ +++ /dev/null @@ -1,296 +0,0 @@ -/* pathphys.c -- return pathname with all symlinks expanded. */ - -/* Copyright (C) 2000 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 . -*/ - -#include - -#include -#ifndef _MINIX -# include -#endif -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include -#include -#include -#include - -#include "shell.h" - -#if !defined (MAXSYMLINKS) -# define MAXSYMLINKS 32 -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern char *get_working_directory __P((char *)); - -static int -_path_readlink (path, buf, bufsiz) - char *path; - char *buf; - int bufsiz; -{ -#ifdef HAVE_READLINK - return readlink (path, buf, bufsiz); -#else - errno = EINVAL; - return -1; -#endif -} - -/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */ - -#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/') - -/* - * Return PATH with all symlinks expanded in newly-allocated memory. - * This always gets an absolute pathname. - */ - -char * -sh_physpath (path, flags) - char *path; - int flags; -{ - char tbuf[PATH_MAX+1], linkbuf[PATH_MAX+1]; - char *result, *p, *q, *qsave, *qbase, *workpath; - int double_slash_path, linklen, nlink; - - linklen = strlen (path); - -#if 0 - /* First sanity check -- punt immediately if the name is too long. */ - if (linklen >= PATH_MAX) - return (savestring (path)); -#endif - - nlink = 0; - q = result = (char *)xmalloc (PATH_MAX + 1); - - /* Even if we get something longer than PATH_MAX, we might be able to - shorten it, so we try. */ - if (linklen >= PATH_MAX) - workpath = savestring (path); - else - { - workpath = (char *)xmalloc (PATH_MAX + 1); - strcpy (workpath, path); - } - - /* This always gets an absolute pathname. */ - - /* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any - leading `x:' (dos drive name). */ -#if defined (__CYGWIN__) - qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1; -#else - qbase = workpath + 1; -#endif - double_slash_path = DOUBLE_SLASH (workpath); - qbase += double_slash_path; - - for (p = workpath; p < qbase; ) - *q++ = *p++; - qbase = q; - - /* - * invariants: - * qbase points to the portion of the result path we want to modify - * p points at beginning of path element we're considering. - * q points just past the last path element we wrote (no slash). - * - * XXX -- need to fix error checking for too-long pathnames - */ - - while (*p) - { - if (ISDIRSEP(p[0])) /* null element */ - p++; - else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */ - p += 1; /* don't count the separator in case it is nul */ - else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */ - { - p += 2; /* skip `..' */ - if (q > qbase) - { - while (--q > qbase && ISDIRSEP(*q) == 0) - ; - } - } - else /* real path element */ - { - /* add separator if not at start of work portion of result */ - qsave = q; - if (q != qbase) - *q++ = DIRSEP; - while (*p && (ISDIRSEP(*p) == 0)) - { - if (q - result >= PATH_MAX) - { -#ifdef ENAMETOOLONG - errno = ENAMETOOLONG; -#else - errno = EINVAL; -#endif - goto error; - } - - *q++ = *p++; - } - - *q = '\0'; - - linklen = _path_readlink (result, linkbuf, PATH_MAX); - if (linklen < 0) /* if errno == EINVAL, it's not a symlink */ - { - if (errno != EINVAL) - goto error; - continue; - } - - /* It's a symlink, and the value is in LINKBUF. */ - nlink++; - if (nlink > MAXSYMLINKS) - { -#ifdef ELOOP - errno = ELOOP; -#else - errno = EINVAL; -#endif -error: - free (result); - free (workpath); - return ((char *)NULL); - } - - linkbuf[linklen] = '\0'; - - /* If the new path length would overrun PATH_MAX, punt now. */ - if ((strlen (p) + linklen + 2) >= PATH_MAX) - { -#ifdef ENAMETOOLONG - errno = ENAMETOOLONG; -#else - errno = EINVAL; -#endif - goto error; - } - - /* Form the new pathname by copying the link value to a temporary - buffer and appending the rest of `workpath'. Reset p to point - to the start of the rest of the path. If the link value is an - absolute pathname, reset p, q, and qbase. If not, reset p - and q. */ - strcpy (tbuf, linkbuf); - tbuf[linklen] = '/'; - strcpy (tbuf + linklen, p); - strcpy (workpath, tbuf); - - if (ABSPATH(linkbuf)) - { - q = result; - /* Duplicating some code here... */ -#if defined (__CYGWIN__) - qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1; -#else - qbase = workpath + 1; -#endif - double_slash_path = DOUBLE_SLASH (workpath); - qbase += double_slash_path; - - for (p = workpath; p < qbase; ) - *q++ = *p++; - qbase = q; - } - else - { - p = workpath; - q = qsave; - } - } - } - - *q = '\0'; - free (workpath); - - /* If the result starts with `//', but the original path does not, we - can turn the // into /. Because of how we set `qbase', this should never - be true, but it's a sanity check. */ - if (DOUBLE_SLASH(result) && double_slash_path == 0) - { - if (result[2] == '\0') /* short-circuit for bare `//' */ - result[1] = '\0'; - else - strcpy (result, result + 1); - } - - return (result); -} - -char * -sh_realpath (pathname, resolved) - const char *pathname; - char *resolved; -{ - char *tdir, *wd; - - if (pathname == 0 || *pathname == '\0') - { - errno = (pathname == 0) ? EINVAL : ENOENT; - return ((char *)NULL); - } - - if (ABSPATH (pathname) == 0) - { - wd = get_working_directory ("sh_realpath"); - if (wd == 0) - return ((char *)NULL); - tdir = sh_makepath ((char *)pathname, wd, 0); - free (wd); - } - else - tdir = savestring (pathname); - - wd = sh_physpath (tdir, 0); - free (tdir); - - if (resolved == 0) - return (wd); - - if (wd) - { - strncpy (resolved, wd, PATH_MAX - 1); - resolved[PATH_MAX - 1] = '\0'; - free (wd); - return resolved; - } - else - { - resolved[0] = '\0'; - return wd; - } -} diff --git a/lib/sh/spell.c~ b/lib/sh/spell.c~ deleted file mode 100644 index d0394c297..000000000 --- a/lib/sh/spell.c~ +++ /dev/null @@ -1,212 +0,0 @@ -/* spell.c -- spelling correction for pathnames. */ - -/* Copyright (C) 2000 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 . -*/ - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include -#include -#ifndef _MINIX -#include -#endif - -#include - -#include -#include -#include - -static int mindist __P((char *, char *, char *)); -static int spdist __P((char *, char *)); - -/* - * `spname' and its helpers are inspired by the code in "The UNIX - * Programming Environment", Kernighan & Pike, Prentice-Hall 1984, - * pages 209 - 213. - */ - -/* - * `spname' -- return a correctly spelled filename - * - * int spname(char * oldname, char * newname) - * Returns: -1 if no reasonable match found - * 0 if exact match found - * 1 if corrected - * Stores corrected name in `newname'. - */ -int -spname(oldname, newname) - char *oldname; - char *newname; -{ - char *op, *np, *p; - char guess[PATH_MAX + 1], best[PATH_MAX + 1]; - - op = oldname; - np = newname; - for (;;) - { - while (*op == '/') /* Skip slashes */ - *np++ = *op++; - *np = '\0'; - - if (*op == '\0') /* Exact or corrected */ - { - /* `.' is rarely the right thing. */ - if (oldname[1] == '\0' && newname[1] == '\0' && - oldname[0] != '.' && newname[0] == '.') - return -1; - return strcmp(oldname, newname) != 0; - } - - /* Copy next component into guess */ - for (p = guess; *op != '/' && *op != '\0'; op++) - if (p < guess + PATH_MAX) - *p++ = *op; - *p = '\0'; - - if (mindist(newname, guess, best) >= 3) - return -1; /* Hopeless */ - - /* - * Add to end of newname - */ - for (p = best; *np = *p++; np++) - ; - } -} - -/* - * Search directory for a guess - */ -static int -mindist(dir, guess, best) - char *dir; - char *guess; - char *best; -{ - DIR *fd; - struct dirent *dp; - int dist, x; - - dist = 3; /* Worst distance */ - if (*dir == '\0') - dir = "."; - - if ((fd = opendir(dir)) == NULL) - return dist; - - while ((dp = readdir(fd)) != NULL) - { - /* - * Look for a better guess. If the new guess is as - * good as the current one, we take it. This way, - * any single character match will be a better match - * than ".". - */ - x = spdist(dp->d_name, guess); - if (x <= dist && x != 3) - { - strcpy(best, dp->d_name); - dist = x; - if (dist == 0) /* Exact match */ - break; - } - } - (void)closedir(fd); - - /* Don't return `.' */ - if (best[0] == '.' && best[1] == '\0') - dist = 3; - return dist; -} - -/* - * `spdist' -- return the "distance" between two names. - * - * int spname(char * oldname, char * newname) - * Returns: 0 if strings are identical - * 1 if two characters are transposed - * 2 if one character is wrong, added or deleted - * 3 otherwise - */ -static int -spdist(cur, new) - char *cur, *new; -{ - while (*cur == *new) - { - if (*cur == '\0') - return 0; /* Exact match */ - cur++; - new++; - } - - if (*cur) - { - if (*new) - { - if (cur[1] && new[1] && cur[0] == new[1] && cur[1] == new[0] && strcmp (cur + 2, new + 2) == 0) - return 1; /* Transposition */ - - if (strcmp (cur + 1, new + 1) == 0) - return 2; /* One character mismatch */ - } - - if (strcmp(&cur[1], &new[0]) == 0) - return 2; /* Extra character */ - } - - if (*new && strcmp(cur, new + 1) == 0) - return 2; /* Missing character */ - - return 3; -} - -char * -dirspell (dirname) - char *dirname; -{ - int n; - char *guess; - - n = (strlen (dirname) * 3 + 1) / 2 + 1; - guess = (char *)malloc (n); - if (guess == 0) - return 0; - - switch (spname (dirname, guess)) - { - case -1: - default: - free (guess); - return (char *)NULL; - case 0: - case 1: - return guess; - } -} diff --git a/lib/sh/strerror.c~ b/lib/sh/strerror.c~ deleted file mode 100644 index 4081e9c19..000000000 --- a/lib/sh/strerror.c~ +++ /dev/null @@ -1,74 +0,0 @@ -/* strerror.c - string corresponding to a particular value of errno. */ - -/* Copyright (C) 1995 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 . -*/ - -#include - -#if !defined (HAVE_STRERROR) - -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* Return a string corresponding to the error number E. From - the ANSI C spec. */ -#if defined (strerror) -# undef strerror -#endif - -static char *errbase = "Unknown system error "; - -char * -strerror (e) - int e; -{ - static char emsg[40]; -#if defined (HAVE_SYS_ERRLIST) - extern int sys_nerr; - extern char *sys_errlist[]; - - if (e > 0 && e < sys_nerr) - return (sys_errlist[e]); - else -#endif /* HAVE_SYS_ERRLIST */ - { - char *z; - - z = itos (e); - strcpy (emsg, errbase); - strcat (emsg, z); - free (z); - return (&emsg[0]); - } -} -#endif /* HAVE_STRERROR */ diff --git a/mailcheck.c~ b/mailcheck.c~ deleted file mode 100644 index 05f58b9dc..000000000 --- a/mailcheck.c~ +++ /dev/null @@ -1,491 +0,0 @@ -/* mailcheck.c -- The check is in the mail... */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include -#include "bashtypes.h" -#include "posixstat.h" -#ifndef _MINIX -# include -#endif -#if defined (HAVE_UNISTD_H) -# include -#endif -#include "posixtime.h" -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "execute_cmd.h" -#include "mailcheck.h" -#include - -/* Values for flags word in struct _fileinfo */ -#define MBOX_INITIALIZED 0x01 - -extern time_t shell_start_time; - -extern int mailstat __P((const char *, struct stat *)); - -typedef struct _fileinfo { - char *name; - char *msg; - time_t access_time; - time_t mod_time; - off_t file_size; - int flags; -} FILEINFO; - -/* The list of remembered mail files. */ -static FILEINFO **mailfiles = (FILEINFO **)NULL; - -/* Number of mail files that we have. */ -static int mailfiles_count; - -/* The last known time that mail was checked. */ -static time_t last_time_mail_checked = 0; - -/* Non-zero means warn if a mail file has been read since last checked. */ -int mail_warning; - -static int find_mail_file __P((char *)); -static void init_mail_file __P((int)); -static void update_mail_file __P((int)); -static int add_mail_file __P((char *, char *)); - -static FILEINFO *alloc_mail_file __P((char *, char *)); -static void dispose_mail_file __P((FILEINFO *)); - -static int file_mod_date_changed __P((int)); -static int file_access_date_changed __P((int)); -static int file_has_grown __P((int)); - -static char *parse_mailpath_spec __P((char *)); - -/* Returns non-zero if it is time to check mail. */ -int -time_to_check_mail () -{ - char *temp; - time_t now; - intmax_t seconds; - - temp = get_string_value ("MAILCHECK"); - - /* Negative number, or non-numbers (such as empty string) cause no - checking to take place. */ - if (temp == 0 || legal_number (temp, &seconds) == 0 || seconds < 0) - return (0); - - now = NOW; - /* Time to check if MAILCHECK is explicitly set to zero, or if enough - time has passed since the last check. */ - return (seconds == 0 || ((now - last_time_mail_checked) >= seconds)); -} - -/* Okay, we have checked the mail. Perhaps I should make this function - go away. */ -void -reset_mail_timer () -{ - last_time_mail_checked = NOW; -} - -/* Locate a file in the list. Return index of - entry, or -1 if not found. */ -static int -find_mail_file (file) - char *file; -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - if (STREQ (mailfiles[i]->name, file)) - return i; - - return -1; -} - -#define RESET_MAIL_FILE(i) \ - do \ - { \ - mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \ - mailfiles[i]->file_size = 0; \ - mailfiles[i]->flags = 0; \ - } \ - while (0) - -#define UPDATE_MAIL_FILE(i, finfo) \ - do \ - { \ - mailfiles[i]->access_time = finfo.st_atime; \ - mailfiles[i]->mod_time = finfo.st_mtime; \ - mailfiles[i]->file_size = finfo.st_size; \ - mailfiles[i]->flags |= MBOX_INITIALIZED; \ - } \ - while (0) - -static void -init_mail_file (i) - int i; -{ - mailfiles[i]->access_time = mailfiles[i]->mod_time = last_time_mail_checked ? last_time_mail_checked : shell_start_time; - mailfiles[i]->file_size = 0; - mailfiles[i]->flags = 0; -} - -static void -update_mail_file (i) - int i; -{ - char *file; - struct stat finfo; - - file = mailfiles[i]->name; - if (mailstat (file, &finfo) == 0) - UPDATE_MAIL_FILE (i, finfo); - else - RESET_MAIL_FILE (i); -} - -/* Add this file to the list of remembered files and return its index - in the list of mail files. */ -static int -add_mail_file (file, msg) - char *file, *msg; -{ - struct stat finfo; - char *filename; - int i; - - filename = full_pathname (file); - i = find_mail_file (filename); - if (i >= 0) - { - if (mailstat (filename, &finfo) == 0) - UPDATE_MAIL_FILE (i, finfo); - - free (filename); - return i; - } - - i = mailfiles_count++; - mailfiles = (FILEINFO **)xrealloc - (mailfiles, mailfiles_count * sizeof (FILEINFO *)); - - mailfiles[i] = alloc_mail_file (filename, msg); - init_mail_file (i); - - return i; -} - -/* Reset the existing mail files access and modification times to zero. */ -void -reset_mail_files () -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - RESET_MAIL_FILE (i); -} - -static FILEINFO * -alloc_mail_file (filename, msg) - char *filename, *msg; -{ - FILEINFO *mf; - - mf = (FILEINFO *)xmalloc (sizeof (FILEINFO)); - mf->name = filename; - mf->msg = msg ? savestring (msg) : (char *)NULL; - mf->flags = 0; - - return mf; -} - -static void -dispose_mail_file (mf) - FILEINFO *mf; -{ - free (mf->name); - FREE (mf->msg); - free (mf); -} - -/* Free the information that we have about the remembered mail files. */ -void -free_mail_files () -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - dispose_mail_file (mailfiles[i]); - - if (mailfiles) - free (mailfiles); - - mailfiles_count = 0; - mailfiles = (FILEINFO **)NULL; -} - -void -init_mail_dates () -{ - if (mailfiles == 0) - remember_mail_dates (); -} - -/* Return non-zero if FILE's mod date has changed and it has not been - accessed since modified. If the size has dropped to zero, reset - the cached mail file info. */ -static int -file_mod_date_changed (i) - int i; -{ - time_t mtime; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - mtime = mailfiles[i]->mod_time; - - if (mailstat (file, &finfo) != 0) - return (0); - - if (finfo.st_size > 0) - return (mtime < finfo.st_mtime); - - if (finfo.st_size == 0 && mailfiles[i]->file_size > 0) - UPDATE_MAIL_FILE (i, finfo); - - return (0); -} - -/* Return non-zero if FILE's access date has changed. */ -static int -file_access_date_changed (i) - int i; -{ - time_t atime; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - atime = mailfiles[i]->access_time; - - if (mailstat (file, &finfo) != 0) - return (0); - - if (finfo.st_size > 0) - return (atime < finfo.st_atime); - - return (0); -} - -/* Return non-zero if FILE's size has increased. */ -static int -file_has_grown (i) - int i; -{ - off_t size; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - size = mailfiles[i]->file_size; - - return ((mailstat (file, &finfo) == 0) && (finfo.st_size > size)); -} - -/* Take an element from $MAILPATH and return the portion from - the first unquoted `?' or `%' to the end of the string. This is the - message to be printed when the file contents change. */ -static char * -parse_mailpath_spec (str) - char *str; -{ - char *s; - int pass_next; - - for (s = str, pass_next = 0; s && *s; s++) - { - if (pass_next) - { - pass_next = 0; - continue; - } - if (*s == '\\') - { - pass_next++; - continue; - } - if (*s == '?' || *s == '%') - return s; - } - return ((char *)NULL); -} - -char * -make_default_mailpath () -{ -#if defined (DEFAULT_MAIL_DIRECTORY) - char *mp; - - get_current_user_info (); - mp = (char *)xmalloc (2 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name)); - strcpy (mp, DEFAULT_MAIL_DIRECTORY); - mp[sizeof(DEFAULT_MAIL_DIRECTORY) - 1] = '/'; - strcpy (mp + sizeof (DEFAULT_MAIL_DIRECTORY), current_user.user_name); - return (mp); -#else - return ((char *)NULL); -#endif -} - -/* Remember the dates of the files specified by MAILPATH, or if there is - no MAILPATH, by the file specified in MAIL. If neither exists, use a - default value, which we randomly concoct from using Unix. */ - -void -remember_mail_dates () -{ - char *mailpaths; - char *mailfile, *mp; - int i = 0; - - mailpaths = get_string_value ("MAILPATH"); - - /* If no $MAILPATH, but $MAIL, use that as a single filename to check. */ - if (mailpaths == 0 && (mailpaths = get_string_value ("MAIL"))) - { - add_mail_file (mailpaths, (char *)NULL); - return; - } - - if (mailpaths == 0) - { - mailpaths = make_default_mailpath (); - if (mailpaths) - { - add_mail_file (mailpaths, (char *)NULL); - free (mailpaths); - } - return; - } - - while (mailfile = extract_colon_unit (mailpaths, &i)) - { - mp = parse_mailpath_spec (mailfile); - if (mp && *mp) - *mp++ = '\0'; - add_mail_file (mailfile, mp); - free (mailfile); - } -} - -/* check_mail () is useful for more than just checking mail. Since it has - the paranoids dream ability of telling you when someone has read your - mail, it can just as easily be used to tell you when someones .profile - file has been read, thus letting one know when someone else has logged - in. Pretty good, huh? */ - -/* Check for mail in some files. If the modification date of any - of the files in MAILPATH has changed since we last did a - remember_mail_dates () then mention that the user has mail. - Special hack: If the variable MAIL_WARNING is non-zero and the - mail file has been accessed since the last time we remembered, then - the message "The mail in has been read" is printed. */ -void -check_mail () -{ - char *current_mail_file, *message; - int i, use_user_notification; - char *dollar_underscore, *temp; - - dollar_underscore = get_string_value ("_"); - if (dollar_underscore) - dollar_underscore = savestring (dollar_underscore); - - for (i = 0; i < mailfiles_count; i++) - { - current_mail_file = mailfiles[i]->name; - - if (*current_mail_file == '\0') - continue; - - if (file_mod_date_changed (i)) - { - int file_is_bigger; - - use_user_notification = mailfiles[i]->msg != (char *)NULL; - message = mailfiles[i]->msg ? mailfiles[i]->msg : _("You have mail in $_"); - - bind_variable ("_", current_mail_file, 0); - -#define atime mailfiles[i]->access_time -#define mtime mailfiles[i]->mod_time - - /* Have to compute this before the call to update_mail_file, which - resets all the information. */ - file_is_bigger = file_has_grown (i); - - update_mail_file (i); - - /* If the user has just run a program which manipulates the - mail file, then don't bother explaining that the mail - file has been manipulated. Since some systems don't change - the access time to be equal to the modification time when - the mail in the file is manipulated, check the size also. If - the file has not grown, continue. */ - if ((atime >= mtime) && !file_is_bigger) - continue; - - /* If the mod time is later than the access time and the file - has grown, note the fact that this is *new* mail. */ - if (use_user_notification == 0 && (atime < mtime) && file_is_bigger) - message = _("You have new mail in $_"); -#undef atime -#undef mtime - - if (temp = expand_string_to_string (message, Q_DOUBLE_QUOTES)) - { - puts (temp); - free (temp); - } - else - putchar ('\n'); - } - - if (mail_warning && file_access_date_changed (i)) - { - update_mail_file (i); - printf (_("The mail in %s has been read\n"), current_mail_file); - } - } - - if (dollar_underscore) - { - bind_variable ("_", dollar_underscore, 0); - free (dollar_underscore); - } - else - unbind_variable ("_"); -} diff --git a/mksyntax.c~ b/mksyntax.c~ deleted file mode 100644 index 56ade2e45..000000000 --- a/mksyntax.c~ +++ /dev/null @@ -1,415 +0,0 @@ -/* - * mksyntax.c - construct shell syntax table for fast char attribute lookup. - */ - -/* Copyright (C) 2000-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include -#include "bashansi.h" -#include "chartypes.h" -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "syntax.h" - -extern int optind; -extern char *optarg; - -#ifndef errno -extern int errno; -#endif - -#ifndef HAVE_STRERROR -extern char *strerror(); -#endif - -struct wordflag { - int flag; - char *fstr; -} wordflags[] = { - { CWORD, "CWORD" }, - { CSHMETA, "CSHMETA" }, - { CSHBRK, "CSHBRK" }, - { CBACKQ, "CBACKQ" }, - { CQUOTE, "CQUOTE" }, - { CSPECL, "CSPECL" }, - { CEXP, "CEXP" }, - { CBSDQUOTE, "CBSDQUOTE" }, - { CBSHDOC, "CBSHDOC" }, - { CGLOB, "CGLOB" }, - { CXGLOB, "CXGLOB" }, - { CXQUOTE, "CXQUOTE" }, - { CSPECVAR, "CSPECVAR" }, - { CSUBSTOP, "CSUBSTOP" }, - { CBLANK, "CBLANK" }, -}; - -#define N_WFLAGS (sizeof (wordflags) / sizeof (wordflags[0])) -#define SYNSIZE 256 - -int lsyntax[SYNSIZE]; -int debug; -char *progname; - -char preamble[] = "\ -/*\n\ - * This file was generated by mksyntax. DO NOT EDIT.\n\ - */\n\ -\n"; - -char includes[] = "\ -#include \"config.h\"\n\ -#include \"stdc.h\"\n\ -#include \"syntax.h\"\n\n"; - -static void -usage() -{ - fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname); - exit (2); -} - -#ifdef INCLUDE_UNUSED -static int -getcflag (s) - char *s; -{ - int i; - - for (i = 0; i < N_WFLAGS; i++) - if (strcmp (s, wordflags[i].fstr) == 0) - return wordflags[i].flag; - return -1; -} -#endif - -static char * -cdesc (i) - int i; -{ - static char xbuf[16]; - - if (i == ' ') - return "SPC"; - else if (ISPRINT (i)) - { - xbuf[0] = i; - xbuf[1] = '\0'; - return (xbuf); - } - else if (i == CTLESC) - return "CTLESC"; - else if (i == CTLNUL) - return "CTLNUL"; - else if (i == '\033') /* ASCII */ - return "ESC"; - - xbuf[0] = '\\'; - xbuf[2] = '\0'; - - switch (i) - { -#ifdef __STDC__ - case '\a': xbuf[1] = 'a'; break; - case '\v': xbuf[1] = 'v'; break; -#else - case '\007': xbuf[1] = 'a'; break; - case 0x0B: xbuf[1] = 'v'; break; -#endif - case '\b': xbuf[1] = 'b'; break; - case '\f': xbuf[1] = 'f'; break; - case '\n': xbuf[1] = 'n'; break; - case '\r': xbuf[1] = 'r'; break; - case '\t': xbuf[1] = 't'; break; - default: sprintf (xbuf, "%d", i); break; - } - - return xbuf; -} - -static char * -getcstr (f) - int f; -{ - int i; - - for (i = 0; i < N_WFLAGS; i++) - if (f == wordflags[i].flag) - return (wordflags[i].fstr); - return ((char *)NULL); -} - -static void -addcstr (str, flag) - char *str; - int flag; -{ - char *s, *fstr; - unsigned char uc; - - for (s = str; s && *s; s++) - { - uc = *s; - - if (debug) - { - fstr = getcstr (flag); - fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc)); - } - - lsyntax[uc] |= flag; - } -} - -static void -addcchar (c, flag) - unsigned char c; - int flag; -{ - char *fstr; - - if (debug) - { - fstr = getcstr (flag); - fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c)); - } - lsyntax[c] |= flag; -} - -static void -addblanks () -{ - register int i; - unsigned char uc; - - for (i = 0; i < SYNSIZE; i++) - { - uc = i; - /* Since we don't call setlocale(), this defaults to the "C" locale, and - the default blank characters will be space and tab. */ - if (isblank (uc)) - lsyntax[uc] |= CBLANK; - } -} - -/* load up the correct flag values in lsyntax */ -static void -load_lsyntax () -{ - /* shell metacharacters */ - addcstr (shell_meta_chars, CSHMETA); - - /* shell word break characters */ - addcstr (shell_break_chars, CSHBRK); - - addcchar ('`', CBACKQ); - - addcstr (shell_quote_chars, CQUOTE); - - addcchar (CTLESC, CSPECL); - addcchar (CTLNUL, CSPECL); - - addcstr (shell_exp_chars, CEXP); - - addcstr (slashify_in_quotes, CBSDQUOTE); - addcstr (slashify_in_here_document, CBSHDOC); - - addcstr (shell_glob_chars, CGLOB); - -#if defined (EXTENDED_GLOB) - addcstr (ext_glob_chars, CXGLOB); -#endif - - addcstr (shell_quote_chars, CXQUOTE); - addcchar ('\\', CXQUOTE); - - addcstr ("@*#?-$!", CSPECVAR); /* omits $0...$9 and $_ */ - - addcstr ("-=?+", CSUBSTOP); /* OP in ${paramOPword} */ - - addblanks (); -} - -static void -dump_lflags (fp, ind) - FILE *fp; - int ind; -{ - int xflags, first, i; - - xflags = lsyntax[ind]; - first = 1; - - if (xflags == 0) - fputs (wordflags[0].fstr, fp); - else - { - for (i = 1; i < N_WFLAGS; i++) - if (xflags & wordflags[i].flag) - { - if (first) - first = 0; - else - putc ('|', fp); - fputs (wordflags[i].fstr, fp); - } - } -} - -static void -wcomment (fp, i) - FILE *fp; - int i; -{ - fputs ("\t\t/* ", fp); - - fprintf (fp, "%s", cdesc(i)); - - fputs (" */", fp); -} - -static void -dump_lsyntax (fp) - FILE *fp; -{ - int i; - - fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE); - fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE); - - for (i = 0; i < SYNSIZE; i++) - { - putc ('\t', fp); - dump_lflags (fp, i); - putc (',', fp); - wcomment (fp, i); - putc ('\n', fp); - } - - fprintf (fp, "};\n"); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - int opt, i; - char *filename; - FILE *fp; - - if ((progname = strrchr (argv[0], '/')) == 0) - progname = argv[0]; - else - progname++; - - filename = (char *)NULL; - debug = 0; - - while ((opt = getopt (argc, argv, "do:")) != EOF) - { - switch (opt) - { - case 'd': - debug = 1; - break; - case 'o': - filename = optarg; - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - if (filename) - { - fp = fopen (filename, "w"); - if (fp == 0) - { - fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno)); - exit (1); - } - } - else - { - filename = "stdout"; - fp = stdout; - } - - - for (i = 0; i < SYNSIZE; i++) - lsyntax[i] = CWORD; - - load_lsyntax (); - - fprintf (fp, "%s\n", preamble); - fprintf (fp, "%s\n", includes); - - dump_lsyntax (fp); - - if (fp != stdout) - fclose (fp); - exit (0); -} - - -#if !defined (HAVE_STRERROR) - -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -/* Return a string corresponding to the error number E. From - the ANSI C spec. */ -#if defined (strerror) -# undef strerror -#endif - -char * -strerror (e) - int e; -{ - static char emsg[40]; -#if defined (HAVE_SYS_ERRLIST) - extern int sys_nerr; - extern char *sys_errlist[]; - - if (e > 0 && e < sys_nerr) - return (sys_errlist[e]); - else -#endif /* HAVE_SYS_ERRLIST */ - { - sprintf (emsg, "Unknown system error %d", e); - return (&emsg[0]); - } -} -#endif /* HAVE_STRERROR */ diff --git a/patchlevel.h~ b/patchlevel.h~ deleted file mode 100644 index a01ad6ee1..000000000 --- a/patchlevel.h~ +++ /dev/null @@ -1,30 +0,0 @@ -/* patchlevel.h -- current bash patch level */ - -/* Copyright (C) 2001-2011 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 . -*/ - -#if !defined (_PATCHLEVEL_H_) -#define _PATCHLEVEL_H_ - -/* It's important that there be no other strings in this file that match the - regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh - looks for to find the patch level (for the sccs version string). */ - -#define PATCHLEVEL 36 - -#endif /* _PATCHLEVEL_H_ */ diff --git a/shell.c~ b/shell.c~ deleted file mode 100644 index f722f547a..000000000 --- a/shell.c~ +++ /dev/null @@ -1,1883 +0,0 @@ -/* shell.c -- GNU's idea of the POSIX shell specification. */ - -/* Copyright (C) 1987-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 . -*/ - -/* - Birthdate: - Sunday, January 10th, 1988. - Initial author: Brian Fox -*/ -#define INSTALL_DEBUG_MODE - -#include "config.h" - -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#include "posixtime.h" -#include "bashansi.h" -#include -#include -#include -#include "filecntl.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" - -#define NEED_SH_SETLINEBUF_DECL /* used in externs.h */ - -#include "shell.h" -#include "flags.h" -#include "trap.h" -#include "mailcheck.h" -#include "builtins.h" -#include "builtins/common.h" - -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif /* JOB_CONTROL */ - -#include "input.h" -#include "execute_cmd.h" -#include "findcmd.h" - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include -#endif - -#if defined (READLINE) -# include "bashline.h" -#endif - -#include -#include - -#if defined (__OPENNT) -# include -#endif - -#if !defined (HAVE_GETPW_DECLS) -extern struct passwd *getpwuid (); -#endif /* !HAVE_GETPW_DECLS */ - -#if !defined (errno) -extern int errno; -#endif - -#if defined (NO_MAIN_ENV_ARG) -extern char **environ; /* used if no third argument to main() */ -#endif - -extern char *dist_version, *release_status; -extern int patch_level, build_version; -extern int shell_level; -extern int subshell_environment; -extern int last_command_exit_value; -extern int line_number; -extern int expand_aliases; -extern int array_needs_making; -extern int gnu_error_format; -extern char *primary_prompt, *secondary_prompt; -extern char *this_command_name; - -/* Non-zero means that this shell has already been run; i.e. you should - call shell_reinitialize () if you need to start afresh. */ -int shell_initialized = 0; - -COMMAND *global_command = (COMMAND *)NULL; - -/* Information about the current user. */ -struct user_info current_user = -{ - (uid_t)-1, (uid_t)-1, (gid_t)-1, (gid_t)-1, - (char *)NULL, (char *)NULL, (char *)NULL -}; - -/* The current host's name. */ -char *current_host_name = (char *)NULL; - -/* Non-zero means that this shell is a login shell. - Specifically: - 0 = not login shell. - 1 = login shell from getty (or equivalent fake out) - -1 = login shell from "--login" (or -l) flag. - -2 = both from getty, and from flag. - */ -int login_shell = 0; - -/* Non-zero means that at this moment, the shell is interactive. In - general, this means that the shell is at this moment reading input - from the keyboard. */ -int interactive = 0; - -/* Non-zero means that the shell was started as an interactive shell. */ -int interactive_shell = 0; - -/* Non-zero means to send a SIGHUP to all jobs when an interactive login - shell exits. */ -int hup_on_exit = 0; - -/* Non-zero means to list status of running and stopped jobs at shell exit */ -int check_jobs_at_exit = 0; - -/* Non-zero means to change to a directory name supplied as a command name */ -int autocd = 0; - -/* Tells what state the shell was in when it started: - 0 = non-interactive shell script - 1 = interactive - 2 = -c command - 3 = wordexp evaluation - This is a superset of the information provided by interactive_shell. -*/ -int startup_state = 0; - -/* Special debugging helper. */ -int debugging_login_shell = 0; - -/* The environment that the shell passes to other commands. */ -char **shell_environment; - -/* Non-zero when we are executing a top-level command. */ -int executing = 0; - -/* The number of commands executed so far. */ -int current_command_number = 1; - -/* Non-zero is the recursion depth for commands. */ -int indirection_level = 0; - -/* The name of this shell, as taken from argv[0]. */ -char *shell_name = (char *)NULL; - -/* time in seconds when the shell was started */ -time_t shell_start_time; - -/* Are we running in an emacs shell window? */ -int running_under_emacs; - -/* Do we have /dev/fd? */ -#ifdef HAVE_DEV_FD -int have_devfd = HAVE_DEV_FD; -#else -int have_devfd = 0; -#endif - -/* The name of the .(shell)rc file. */ -static char *bashrc_file = "~/.bashrc"; - -/* Non-zero means to act more like the Bourne shell on startup. */ -static int act_like_sh; - -/* Non-zero if this shell is being run by `su'. */ -static int su_shell; - -/* Non-zero if we have already expanded and sourced $ENV. */ -static int sourced_env; - -/* Is this shell running setuid? */ -static int running_setuid; - -/* Values for the long-winded argument names. */ -static int debugging; /* Do debugging things. */ -static int no_rc; /* Don't execute ~/.bashrc */ -static int no_profile; /* Don't execute .profile */ -static int do_version; /* Display interesting version info. */ -static int make_login_shell; /* Make this shell be a `-bash' shell. */ -static int want_initial_help; /* --help option */ - -int debugging_mode = 0; /* In debugging mode with --debugger */ -#if defined (READLINE) -int no_line_editing = 0; /* non-zero -> don't do fancy line editing. */ -#else -int no_line_editing = 1; /* can't have line editing without readline */ -#endif -int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ -int dump_po_strings; /* Dump strings in $"..." in po format */ -int wordexp_only = 0; /* Do word expansion only */ -int protected_mode = 0; /* No command substitution with --wordexp */ - -#if defined (STRICT_POSIX) -int posixly_correct = 1; /* Non-zero means posix.2 superset. */ -#else -int posixly_correct = 0; /* Non-zero means posix.2 superset. */ -#endif - -/* Some long-winded argument names. These are obviously new. */ -#define Int 1 -#define Charp 2 -static const struct { - const char *name; - int type; - int *int_value; - char **char_value; -} long_args[] = { - { "debug", Int, &debugging, (char **)0x0 }, -#if defined (DEBUGGER) - { "debugger", Int, &debugging_mode, (char **)0x0 }, -#endif - { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 }, - { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, - { "help", Int, &want_initial_help, (char **)0x0 }, - { "init-file", Charp, (int *)0x0, &bashrc_file }, - { "login", Int, &make_login_shell, (char **)0x0 }, - { "noediting", Int, &no_line_editing, (char **)0x0 }, - { "noprofile", Int, &no_profile, (char **)0x0 }, - { "norc", Int, &no_rc, (char **)0x0 }, - { "posix", Int, &posixly_correct, (char **)0x0 }, - { "protected", Int, &protected_mode, (char **)0x0 }, - { "rcfile", Charp, (int *)0x0, &bashrc_file }, -#if defined (RESTRICTED_SHELL) - { "restricted", Int, &restricted, (char **)0x0 }, -#endif - { "verbose", Int, &echo_input_at_read, (char **)0x0 }, - { "version", Int, &do_version, (char **)0x0 }, -#if defined (WORDEXP_OPTION) - { "wordexp", Int, &wordexp_only, (char **)0x0 }, -#endif - { (char *)0x0, Int, (int *)0x0, (char **)0x0 } -}; - -/* These are extern so execute_simple_command can set them, and then - longjmp back to main to execute a shell script, instead of calling - main () again and resulting in indefinite, possibly fatal, stack - growth. */ -procenv_t subshell_top_level; -int subshell_argc; -char **subshell_argv; -char **subshell_envp; - -char *exec_argv0; - -#if defined (BUFFERED_INPUT) -/* The file descriptor from which the shell is reading input. */ -int default_buffered_input = -1; -#endif - -/* The following two variables are not static so they can show up in $-. */ -int read_from_stdin; /* -s flag supplied */ -int want_pending_command; /* -c flag supplied */ - -/* This variable is not static so it can be bound to $BASH_EXECUTION_STRING */ -char *command_execution_string; /* argument to -c option */ - -int malloc_trace_at_exit = 0; - -static int shell_reinitialized = 0; - -static FILE *default_input; - -static STRING_INT_ALIST *shopt_alist; -static int shopt_ind = 0, shopt_len = 0; - -static int parse_long_options __P((char **, int, int)); -static int parse_shell_options __P((char **, int, int)); -static int bind_args __P((char **, int, int, int)); - -static void start_debugger __P((void)); - -static void add_shopt_to_alist __P((char *, int)); -static void run_shopt_alist __P((void)); - -static void execute_env_file __P((char *)); -static void run_startup_files __P((void)); -static int open_shell_script __P((char *)); -static void set_bash_input __P((void)); -static int run_one_command __P((char *)); -#if defined (WORDEXP_OPTION) -static int run_wordexp __P((char *)); -#endif - -static int uidget __P((void)); - -static void init_interactive __P((void)); -static void init_noninteractive __P((void)); -static void init_interactive_script __P((void)); - -static void set_shell_name __P((char *)); -static void shell_initialize __P((void)); -static void shell_reinitialize __P((void)); - -static void show_shell_usage __P((FILE *, int)); - -#ifdef __CYGWIN__ -static void -_cygwin32_check_tmp () -{ - struct stat sb; - - if (stat ("/tmp", &sb) < 0) - internal_warning (_("could not find /tmp, please create!")); - else - { - if (S_ISDIR (sb.st_mode) == 0) - internal_warning (_("/tmp must be a valid directory name")); - } -} -#endif /* __CYGWIN__ */ - -#if defined (NO_MAIN_ENV_ARG) -/* systems without third argument to main() */ -int -main (argc, argv) - int argc; - char **argv; -#else /* !NO_MAIN_ENV_ARG */ -int -main (argc, argv, env) - int argc; - char **argv, **env; -#endif /* !NO_MAIN_ENV_ARG */ -{ - register int i; - int code, old_errexit_flag; -#if defined (RESTRICTED_SHELL) - int saverst; -#endif - volatile int locally_skip_execution; - volatile int arg_index, top_level_arg_index; -#ifdef __OPENNT - char **env; - - env = environ; -#endif /* __OPENNT */ - - USE_VAR(argc); - USE_VAR(argv); - USE_VAR(env); - USE_VAR(code); - USE_VAR(old_errexit_flag); -#if defined (RESTRICTED_SHELL) - USE_VAR(saverst); -#endif - - /* Catch early SIGINTs. */ - code = setjmp (top_level); - if (code) - exit (2); - - xtrace_init (); - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# if 1 - malloc_set_register (1); -# endif -#endif - - check_dev_tty (); - -#ifdef __CYGWIN__ - _cygwin32_check_tmp (); -#endif /* __CYGWIN__ */ - - /* Wait forever if we are debugging a login shell. */ - while (debugging_login_shell) sleep (3); - - set_default_locale (); - - running_setuid = uidget (); - - if (getenv ("POSIXLY_CORRECT") || getenv ("POSIX_PEDANTIC")) - posixly_correct = 1; - -#if defined (USE_GNU_MALLOC_LIBRARY) - mcheck (programming_error, (void (*) ())0); -#endif /* USE_GNU_MALLOC_LIBRARY */ - - if (setjmp (subshell_top_level)) - { - argc = subshell_argc; - argv = subshell_argv; - env = subshell_envp; - sourced_env = 0; - } - - shell_reinitialized = 0; - - /* Initialize `local' variables for all `invocations' of main (). */ - arg_index = 1; - if (arg_index > argc) - arg_index = argc; - command_execution_string = (char *)NULL; - want_pending_command = locally_skip_execution = read_from_stdin = 0; - default_input = stdin; -#if defined (BUFFERED_INPUT) - default_buffered_input = -1; -#endif - - /* Fix for the `infinite process creation' bug when running shell scripts - from startup files on System V. */ - login_shell = make_login_shell = 0; - - /* If this shell has already been run, then reinitialize it to a - vanilla state. */ - if (shell_initialized || shell_name) - { - /* Make sure that we do not infinitely recurse as a login shell. */ - if (*shell_name == '-') - shell_name++; - - shell_reinitialize (); - if (setjmp (top_level)) - exit (2); - } - - shell_environment = env; - set_shell_name (argv[0]); - shell_start_time = NOW; /* NOW now defined in general.h */ - - /* Parse argument flags from the input line. */ - - /* Find full word arguments first. */ - arg_index = parse_long_options (argv, arg_index, argc); - - if (want_initial_help) - { - show_shell_usage (stdout, 1); - exit (EXECUTION_SUCCESS); - } - - if (do_version) - { - show_shell_version (1); - exit (EXECUTION_SUCCESS); - } - - /* All done with full word options; do standard shell option parsing.*/ - this_command_name = shell_name; /* for error reporting */ - arg_index = parse_shell_options (argv, arg_index, argc); - - /* If user supplied the "--login" (or -l) flag, then set and invert - LOGIN_SHELL. */ - if (make_login_shell) - { - login_shell++; - login_shell = -login_shell; - } - - set_login_shell ("login_shell", login_shell != 0); - - if (dump_po_strings) - dump_translatable_strings = 1; - - if (dump_translatable_strings) - read_but_dont_execute = 1; - - if (running_setuid && privileged_mode == 0) - disable_priv_mode (); - - /* Need to get the argument to a -c option processed in the - above loop. The next arg is a command to execute, and the - following args are $0...$n respectively. */ - if (want_pending_command) - { - command_execution_string = argv[arg_index]; - if (command_execution_string == 0) - { - report_error (_("%s: option requires an argument"), "-c"); - exit (EX_BADUSAGE); - } - arg_index++; - } - this_command_name = (char *)NULL; - - cmd_init(); /* initialize the command object caches */ - - /* First, let the outside world know about our interactive status. - A shell is interactive if the `-i' flag was given, or if all of - the following conditions are met: - no -c command - no arguments remaining or the -s flag given - standard input is a terminal - standard error is a terminal - Refer to Posix.2, the description of the `sh' utility. */ - - if (forced_interactive || /* -i flag */ - (!command_execution_string && /* No -c command and ... */ - wordexp_only == 0 && /* No --wordexp and ... */ - ((arg_index == argc) || /* no remaining args or... */ - read_from_stdin) && /* -s flag with args, and */ - isatty (fileno (stdin)) && /* Input is a terminal and */ - isatty (fileno (stderr)))) /* error output is a terminal. */ - init_interactive (); - else - init_noninteractive (); - - /* - * Some systems have the bad habit of starting login shells with lots of open - * file descriptors. For instance, most systems that have picked up the - * pre-4.0 Sun YP code leave a file descriptor open each time you call one - * of the getpw* functions, and it's set to be open across execs. That - * means one for login, one for xterm, one for shelltool, etc. There are - * also systems that open persistent FDs to other agents or files as part - * of process startup; these need to be set to be close-on-exec. - */ - if (login_shell && interactive_shell) - { - for (i = 3; i < 20; i++) - SET_CLOSE_ON_EXEC (i); - } - - /* If we're in a strict Posix.2 mode, turn on interactive comments, - alias expansion in non-interactive shells, and other Posix.2 things. */ - if (posixly_correct) - { - bind_variable ("POSIXLY_CORRECT", "y", 0); - sv_strict_posix ("POSIXLY_CORRECT"); - } - - /* Now we run the shopt_alist and process the options. */ - if (shopt_alist) - run_shopt_alist (); - - /* From here on in, the shell must be a normal functioning shell. - Variables from the environment are expected to be set, etc. */ - shell_initialize (); - - set_default_lang (); - set_default_locale_vars (); - - /* - * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) - * M-x shell -> TERM=dumb EMACS=t (no line editing) - * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) - */ - if (interactive_shell) - { - char *term, *emacs; - - term = get_string_value ("TERM"); - emacs = get_string_value ("EMACS"); - - /* Not sure any emacs terminal emulator sets TERM=emacs any more */ - no_line_editing |= term && (STREQ (term, "emacs")); - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); - - /* running_under_emacs == 2 for `eterm' */ - running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); - running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term"); - - if (running_under_emacs) - gnu_error_format = 1; - } - - top_level_arg_index = arg_index; - old_errexit_flag = exit_immediately_on_error; - - /* Give this shell a place to longjmp to before executing the - startup files. This allows users to press C-c to abort the - lengthy startup. */ - code = setjmp (top_level); - if (code) - { - if (code == EXITPROG || code == ERREXIT) - exit_shell (last_command_exit_value); - else - { -#if defined (JOB_CONTROL) - /* Reset job control, since run_startup_files turned it off. */ - set_job_control (interactive_shell); -#endif - /* Reset value of `set -e', since it's turned off before running - the startup files. */ - exit_immediately_on_error += old_errexit_flag; - locally_skip_execution++; - } - } - - arg_index = top_level_arg_index; - - /* Execute the start-up scripts. */ - - if (interactive_shell == 0) - { - unbind_variable ("PS1"); - unbind_variable ("PS2"); - interactive = 0; -#if 0 - /* This has already been done by init_noninteractive */ - expand_aliases = posixly_correct; -#endif - } - else - { - change_flag ('i', FLAG_ON); - interactive = 1; - } - -#if defined (RESTRICTED_SHELL) - /* Set restricted_shell based on whether the basename of $0 indicates that - the shell should be restricted or if the `-r' option was supplied at - startup. */ - restricted_shell = shell_is_restricted (shell_name); - - /* If the `-r' option is supplied at invocation, make sure that the shell - is not in restricted mode when running the startup files. */ - saverst = restricted; - restricted = 0; -#endif - - /* The startup files are run with `set -e' temporarily disabled. */ - if (locally_skip_execution == 0 && running_setuid == 0) - { - old_errexit_flag = exit_immediately_on_error; - exit_immediately_on_error = 0; - - run_startup_files (); - exit_immediately_on_error += old_errexit_flag; - } - - /* If we are invoked as `sh', turn on Posix mode. */ - if (act_like_sh) - { - bind_variable ("POSIXLY_CORRECT", "y", 0); - sv_strict_posix ("POSIXLY_CORRECT"); - } - -#if defined (RESTRICTED_SHELL) - /* Turn on the restrictions after executing the startup files. This - means that `bash -r' or `set -r' invoked from a startup file will - turn on the restrictions after the startup files are executed. */ - restricted = saverst || restricted; - if (shell_reinitialized == 0) - maybe_make_restricted (shell_name); -#endif /* RESTRICTED_SHELL */ - -#if defined (WORDEXP_OPTION) - if (wordexp_only) - { - startup_state = 3; - last_command_exit_value = run_wordexp (argv[arg_index]); - exit_shell (last_command_exit_value); - } -#endif - - if (command_execution_string) - { - arg_index = bind_args (argv, arg_index, argc, 0); - startup_state = 2; - - if (debugging_mode) - start_debugger (); - -#if defined (ONESHOT) - executing = 1; - run_one_command (command_execution_string); - exit_shell (last_command_exit_value); -#else /* ONESHOT */ - with_input_from_string (command_execution_string, "-c"); - goto read_and_execute; -#endif /* !ONESHOT */ - } - - /* Get possible input filename and set up default_buffered_input or - default_input as appropriate. */ - if (arg_index != argc && read_from_stdin == 0) - { - open_shell_script (argv[arg_index]); - arg_index++; - } - else if (interactive == 0) - /* In this mode, bash is reading a script from stdin, which is a - pipe or redirected file. */ -#if defined (BUFFERED_INPUT) - default_buffered_input = fileno (stdin); /* == 0 */ -#else - setbuf (default_input, (char *)NULL); -#endif /* !BUFFERED_INPUT */ - - set_bash_input (); - - /* Bind remaining args to $1 ... $n */ - arg_index = bind_args (argv, arg_index, argc, 1); - - if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0) - start_debugger (); - - /* Do the things that should be done only for interactive shells. */ - if (interactive_shell) - { - /* Set up for checking for presence of mail. */ - reset_mail_timer (); - init_mail_dates (); - -#if defined (HISTORY) - /* Initialize the interactive history stuff. */ - bash_initialize_history (); - /* Don't load the history from the history file if we've already - saved some lines in this session (e.g., by putting `history -s xx' - into one of the startup files). */ - if (shell_initialized == 0 && history_lines_this_session == 0) - load_history (); -#endif /* HISTORY */ - - /* Initialize terminal state for interactive shells after the - .bash_profile and .bashrc are interpreted. */ - get_tty_state (); - } - -#if !defined (ONESHOT) - read_and_execute: -#endif /* !ONESHOT */ - - shell_initialized = 1; - - /* Read commands until exit condition. */ - reader_loop (); - exit_shell (last_command_exit_value); -} - -static int -parse_long_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index, longarg, i; - char *arg_string; - - arg_index = arg_start; - while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && - (*arg_string == '-')) - { - longarg = 0; - - /* Make --login equivalent to -login. */ - if (arg_string[1] == '-' && arg_string[2]) - { - longarg = 1; - arg_string++; - } - - for (i = 0; long_args[i].name; i++) - { - if (STREQ (arg_string + 1, long_args[i].name)) - { - if (long_args[i].type == Int) - *long_args[i].int_value = 1; - else if (argv[++arg_index] == 0) - { - report_error (_("%s: option requires an argument"), long_args[i].name); - exit (EX_BADUSAGE); - } - else - *long_args[i].char_value = argv[arg_index]; - - break; - } - } - if (long_args[i].name == 0) - { - if (longarg) - { - report_error (_("%s: invalid option"), argv[arg_index]); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - break; /* No such argument. Maybe flag arg. */ - } - - arg_index++; - } - - return (arg_index); -} - -static int -parse_shell_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index; - int arg_character, on_or_off, next_arg, i; - char *o_option, *arg_string; - - arg_index = arg_start; - while (arg_index != arg_end && (arg_string = argv[arg_index]) && - (*arg_string == '-' || *arg_string == '+')) - { - /* There are flag arguments, so parse them. */ - next_arg = arg_index + 1; - - /* A single `-' signals the end of options. From the 4.3 BSD sh. - An option `--' means the same thing; this is the standard - getopt(3) meaning. */ - if (arg_string[0] == '-' && - (arg_string[1] == '\0' || - (arg_string[1] == '-' && arg_string[2] == '\0'))) - return (next_arg); - - i = 1; - on_or_off = arg_string[0]; - while (arg_character = arg_string[i++]) - { - switch (arg_character) - { - case 'c': - want_pending_command = 1; - break; - - case 'l': - make_login_shell = 1; - break; - - case 's': - read_from_stdin = 1; - break; - - case 'o': - o_option = argv[next_arg]; - if (o_option == 0) - { - list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); - break; - } - if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - next_arg++; - break; - - case 'O': - /* Since some of these can be overridden by the normal - interactive/non-interactive shell initialization or - initializing posix mode, we save the options and process - them after initialization. */ - o_option = argv[next_arg]; - if (o_option == 0) - { - shopt_listopt (o_option, (on_or_off == '-') ? 0 : 1); - break; - } - add_shopt_to_alist (o_option, on_or_off); - next_arg++; - break; - - case 'D': - dump_translatable_strings = 1; - break; - - default: - if (change_flag (arg_character, on_or_off) == FLAG_ERROR) - { - report_error (_("%c%c: invalid option"), on_or_off, arg_character); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - } - } - /* Can't do just a simple increment anymore -- what about - "bash -abouo emacs ignoreeof -hP"? */ - arg_index = next_arg; - } - - return (arg_index); -} - -/* Exit the shell with status S. */ -void -exit_shell (s) - int s; -{ - fflush (stdout); /* XXX */ - fflush (stderr); - - /* Do trap[0] if defined. Allow it to override the exit status - passed to us. */ - if (signal_is_trapped (0)) - s = run_exit_trap (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (HISTORY) - if (remember_on_history) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (COPROCESS_SUPPORT) - coproc_flush (); -#endif - -#if defined (JOB_CONTROL) - /* If the user has run `shopt -s huponexit', hangup all jobs when we exit - an interactive login shell. ksh does this unconditionally. */ - if (interactive_shell && login_shell && hup_on_exit) - hangup_all_jobs (); - - /* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. Don't do this if we're - in a subshell and calling exit_shell after, for example, a failed - word expansion. */ - if (subshell_environment == 0) - end_job_control (); -#endif /* JOB_CONTROL */ - - /* Always return the exit status of the last command to our parent. */ - sh_exit (s); -} - -/* A wrapper for exit that (optionally) can do other things, like malloc - statistics tracing. */ -void -sh_exit (s) - int s; -{ -#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC) - if (malloc_trace_at_exit) - trace_malloc_stats (get_name_for_error (), (char *)NULL); -#endif - - exit (s); -} - -void -subshell_exit (s) - int s; -{ - fflush (stdout); - fflush (stderr); - - /* Do trap[0] if defined. Allow it to override the exit status - passed to us. */ - if (signal_is_trapped (0)) - s = run_exit_trap (); - - sh_exit (s); -} - -/* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey - the Posix.2 startup file rules: $ENV is expanded, and if the file it - names exists, that file is sourced. The Posix.2 rules are in effect - for interactive shells only. (section 4.56.5.3) */ - -/* Execute ~/.bashrc for most shells. Never execute it if - ACT_LIKE_SH is set, or if NO_RC is set. - - If the executable file "/usr/gnu/src/bash/foo" contains: - - #!/usr/gnu/bin/bash - echo hello - - then: - - COMMAND EXECUTE BASHRC - -------------------------------- - bash -c foo NO - bash foo NO - foo NO - rsh machine ls YES (for rsh, which calls `bash -c') - rsh machine foo YES (for shell started by rsh) NO (for foo!) - echo ls | bash NO - login NO - bash YES -*/ - -static void -execute_env_file (env_file) - char *env_file; -{ - char *fn; - - if (env_file && *env_file) - { - fn = expand_string_unsplit_to_string (env_file, Q_DOUBLE_QUOTES); - if (fn && *fn) - maybe_execute_file (fn, 1); - FREE (fn); - } -} - -static void -run_startup_files () -{ -#if defined (JOB_CONTROL) - int old_job_control; -#endif - int sourced_login, run_by_ssh; - - /* get the rshd/sshd case out of the way first. */ - if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && - act_like_sh == 0 && command_execution_string) - { -#ifdef SSH_SOURCE_BASHRC - run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) || - (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); -#else - run_by_ssh = 0; -#endif - - /* If we were run by sshd or we think we were run by rshd, execute - ~/.bashrc if we are a top-level shell. */ - if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - return; - } - } - -#if defined (JOB_CONTROL) - /* Startup files should be run without job control enabled. */ - old_job_control = interactive_shell ? set_job_control (0) : 0; -#endif - - sourced_login = 0; - - /* A shell begun with the --login (or -l) flag that is not in posix mode - runs the login shell startup files, no matter whether or not it is - interactive. If NON_INTERACTIVE_LOGIN_SHELLS is defined, run the - startup files if argv[0][0] == '-' as well. */ -#if defined (NON_INTERACTIVE_LOGIN_SHELLS) - if (login_shell && posixly_correct == 0) -#else - if (login_shell < 0 && posixly_correct == 0) -#endif - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - - sourced_login = 1; - } - - /* A non-interactive shell not named `sh' and not in posix mode reads and - executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd' - and `-su' as the name of the shell, we want to read the startup files. - No other non-interactive shells read any startup files. */ - if (interactive_shell == 0 && !(su_shell && login_shell)) - { - if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 && - sourced_env++ == 0) - execute_env_file (get_string_value ("BASH_ENV")); - return; - } - - /* Interactive shell or `-su' shell. */ - if (posixly_correct == 0) /* bash, sh */ - { - if (login_shell && sourced_login++ == 0) - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - } - - /* bash */ - if (act_like_sh == 0 && no_rc == 0) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - } - /* sh */ - else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - else /* bash --posix, sh --posix */ - { - /* bash and sh */ - if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - -#if defined (JOB_CONTROL) - set_job_control (old_job_control); -#endif -} - -#if defined (RESTRICTED_SHELL) -/* Return 1 if the shell should be a restricted one based on NAME or the - value of `restricted'. Don't actually do anything, just return a - boolean value. */ -int -shell_is_restricted (name) - char *name; -{ - char *temp; - - if (restricted) - return 1; - temp = base_pathname (name); - if (*temp == '-') - temp++; - return (STREQ (temp, RESTRICTED_SHELL_NAME)); -} - -/* Perhaps make this shell a `restricted' one, based on NAME. If the - basename of NAME is "rbash", then this shell is restricted. The - name of the restricted shell is a configurable option, see config.h. - In a restricted shell, PATH, SHELL, ENV, and BASH_ENV are read-only - and non-unsettable. - Do this also if `restricted' is already set to 1; maybe the shell was - started with -r. */ -int -maybe_make_restricted (name) - char *name; -{ - char *temp; - - temp = base_pathname (name); - if (*temp == '-') - temp++; - if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) - { - set_var_read_only ("PATH"); - set_var_read_only ("SHELL"); - set_var_read_only ("ENV"); - set_var_read_only ("BASH_ENV"); - restricted = 1; - } - return (restricted); -} -#endif /* RESTRICTED_SHELL */ - -/* Fetch the current set of uids and gids and return 1 if we're running - setuid or setgid. */ -static int -uidget () -{ - uid_t u; - - u = getuid (); - if (current_user.uid != u) - { - FREE (current_user.user_name); - FREE (current_user.shell); - FREE (current_user.home_dir); - current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL; - } - current_user.uid = u; - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); - - /* See whether or not we are running setuid or setgid. */ - return (current_user.uid != current_user.euid) || - (current_user.gid != current_user.egid); -} - -void -disable_priv_mode () -{ - setuid (current_user.uid); - setgid (current_user.gid); - current_user.euid = current_user.uid; - current_user.egid = current_user.gid; -} - -#if defined (WORDEXP_OPTION) -static int -run_wordexp (words) - char *words; -{ - int code, nw, nb; - WORD_LIST *wl, *tl, *result; - - code = setjmp (top_level); - - if (code != NOT_JUMPED) - { - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - return last_command_exit_value = 127; - case ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_wordexp", CMDERR_BADJUMP, code, 0); - } - } - - /* Run it through the parser to get a list of words and expand them */ - if (words && *words) - { - with_input_from_string (words, "--wordexp"); - if (parse_command () != 0) - return (126); - if (global_command == 0) - { - printf ("0\n0\n"); - return (0); - } - if (global_command->type != cm_simple) - return (126); - wl = global_command->value.Simple->words; - if (protected_mode) - for (tl = wl; tl; tl = tl->next) - tl->word->flags |= W_NOCOMSUB|W_NOPROCSUB; - result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0; - } - else - result = (WORD_LIST *)0; - - last_command_exit_value = 0; - - if (result == 0) - { - printf ("0\n0\n"); - return (0); - } - - /* Count up the number of words and bytes, and print them. Don't count - the trailing NUL byte. */ - for (nw = nb = 0, wl = result; wl; wl = wl->next) - { - nw++; - nb += strlen (wl->word->word); - } - printf ("%u\n%u\n", nw, nb); - /* Print each word on a separate line. This will have to be changed when - the interface to glibc is completed. */ - for (wl = result; wl; wl = wl->next) - printf ("%s\n", wl->word->word); - - return (0); -} -#endif - -#if defined (ONESHOT) -/* Run one command, given as the argument to the -c option. Tell - parse_and_execute not to fork for a simple command. */ -static int -run_one_command (command) - char *command; -{ - int code; - - code = setjmp (top_level); - - if (code != NOT_JUMPED) - { -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - return last_command_exit_value = 127; - case ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_one_command", CMDERR_BADJUMP, code, 0); - } - } - return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST)); -} -#endif /* ONESHOT */ - -static int -bind_args (argv, arg_start, arg_end, start_index) - char **argv; - int arg_start, arg_end, start_index; -{ - register int i; - WORD_LIST *args; - - for (i = arg_start, args = (WORD_LIST *)NULL; i < arg_end; i++) - args = make_word_list (make_word (argv[i]), args); - if (args) - { - args = REVERSE_LIST (args, WORD_LIST *); - if (start_index == 0) /* bind to $0...$n for sh -c command */ - { - /* Posix.2 4.56.3 says that the first argument after sh -c command - becomes $0, and the rest of the arguments become $1...$n */ - shell_name = savestring (args->word->word); - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (args->word->word); - remember_args (args->next, 1); - push_args (args->next); /* BASH_ARGV and BASH_ARGC */ - } - else /* bind to $1...$n for shell script */ - { - remember_args (args, 1); - push_args (args); /* BASH_ARGV and BASH_ARGC */ - } - - dispose_words (args); - } - - return (i); -} - -void -unbind_args () -{ - remember_args ((WORD_LIST *)NULL, 1); - pop_args (); /* Reset BASH_ARGV and BASH_ARGC */ -} - -static void -start_debugger () -{ -#if defined (DEBUGGER) && defined (DEBUGGER_START_FILE) - int old_errexit; - - old_errexit = exit_immediately_on_error; - exit_immediately_on_error = 0; - - maybe_execute_file (DEBUGGER_START_FILE, 1); - function_trace_mode = 1; - - exit_immediately_on_error += old_errexit; -#endif -} - -static int -open_shell_script (script_name) - char *script_name; -{ - int fd, e, fd_is_tty; - char *filename, *path_filename, *t; - char sample[80]; - int sample_len; - struct stat sb; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; -#endif - - filename = savestring (script_name); - - fd = open (filename, O_RDONLY); - if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) - { - e = errno; - /* If it's not in the current directory, try looking through PATH - for it. */ - path_filename = find_path_file (script_name); - if (path_filename) - { - free (filename); - filename = path_filename; - fd = open (filename, O_RDONLY); - } - else - errno = e; - } - - if (fd < 0) - { - e = errno; - file_error (filename); - exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); - } - - free (dollar_vars[0]); - dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (script_name); - if (exec_argv0) - { - free (exec_argv0); - exec_argv0 = (char *)NULL; - } - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); - - array_push (bash_source_a, filename); - if (bash_lineno_a) - { - t = itos (executing_line_number ()); - array_push (bash_lineno_a, t); - free (t); - } - array_push (funcname_a, "main"); -#endif - -#ifdef HAVE_DEV_FD - fd_is_tty = isatty (fd); -#else - fd_is_tty = 0; -#endif - - /* Only do this with non-tty file descriptors we can seek on. */ - if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) - { - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), - and report an error and exit if it is. */ - sample_len = read (fd, sample, sizeof (sample)); - if (sample_len < 0) - { - e = errno; - if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode)) - internal_error (_("%s: is a directory"), filename); - else - { - errno = e; - file_error (filename); - } - exit (EX_NOEXEC); - } - else if (sample_len > 0 && (check_binary_file (sample, sample_len))) - { - internal_error (_("%s: cannot execute binary file"), filename); - exit (EX_BINARY_FILE); - } - /* Now rewind the file back to the beginning. */ - lseek (fd, 0L, 0); - } - - /* Open the script. But try to move the file descriptor to a randomly - large one, in the hopes that any descriptors used by the script will - not match with ours. */ - fd = move_to_high_fd (fd, 1, -1); - -#if defined (BUFFERED_INPUT) - default_buffered_input = fd; - SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ - default_input = fdopen (fd, "r"); - - if (default_input == 0) - { - file_error (filename); - exit (EX_NOTFOUND); - } - - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); -#endif /* !BUFFERED_INPUT */ - - /* Just about the only way for this code to be executed is if something - like `bash -i /dev/stdin' is executed. */ - if (interactive_shell && fd_is_tty) - { - dup2 (fd, 0); - close (fd); - fd = 0; -#if defined (BUFFERED_INPUT) - default_buffered_input = 0; -#else - fclose (default_input); - default_input = stdin; -#endif - } - else if (forced_interactive && fd_is_tty == 0) - /* But if a script is called with something like `bash -i scriptname', - we need to do a non-interactive setup here, since we didn't do it - before. */ - init_interactive_script (); - - free (filename); - return (fd); -} - -/* Initialize the input routines for the parser. */ -static void -set_bash_input () -{ - /* Make sure the fd from which we are reading input is not in - no-delay mode. */ -#if defined (BUFFERED_INPUT) - if (interactive == 0) - sh_unset_nodelay_mode (default_buffered_input); - else -#endif /* !BUFFERED_INPUT */ - sh_unset_nodelay_mode (fileno (stdin)); - - /* with_input_from_stdin really means `with_input_from_readline' */ - if (interactive && no_line_editing == 0) - with_input_from_stdin (); -#if defined (BUFFERED_INPUT) - else if (interactive == 0) - with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); -#endif /* BUFFERED_INPUT */ - else - with_input_from_stream (default_input, dollar_vars[0]); -} - -/* Close the current shell script input source and forget about it. This is - extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO - is non-zero, we close default_buffered_input even if it's the standard - input (fd 0). */ -void -unset_bash_input (check_zero) - int check_zero; -{ -#if defined (BUFFERED_INPUT) - if ((check_zero && default_buffered_input >= 0) || - (check_zero == 0 && default_buffered_input > 0)) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - bash_input.type = st_none; /* XXX */ - } -#else /* !BUFFERED_INPUT */ - if (default_input) - { - fclose (default_input); - default_input = (FILE *)NULL; - } -#endif /* !BUFFERED_INPUT */ -} - - -#if !defined (PROGRAM) -# define PROGRAM "bash" -#endif - -static void -set_shell_name (argv0) - char *argv0; -{ - /* Here's a hack. If the name of this shell is "sh", then don't do - any startup files; just try to be more like /bin/sh. */ - shell_name = argv0 ? base_pathname (argv0) : PROGRAM; - - if (argv0 && *argv0 == '-') - { - if (*shell_name == '-') - shell_name++; - login_shell++; - } - - if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') - act_like_sh++; - if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') - su_shell++; - - shell_name = argv0 ? argv0 : PROGRAM; - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (shell_name); - - /* A program may start an interactive shell with - "execl ("/bin/bash", "-", NULL)". - If so, default the name of this shell to our name. */ - if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) - shell_name = PROGRAM; -} - -static void -init_interactive () -{ - expand_aliases = interactive_shell = startup_state = 1; - interactive = 1; -} - -static void -init_noninteractive () -{ -#if defined (HISTORY) - bash_history_reinit (0); -#endif /* HISTORY */ - interactive_shell = startup_state = interactive = 0; - expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */ - no_line_editing = 1; -#if defined (JOB_CONTROL) - /* Even if the shell is not interactive, enable job control if the -i or - -m option is supplied at startup. */ - set_job_control (forced_interactive||jobs_m_flag); -#endif /* JOB_CONTROL */ -} - -static void -init_interactive_script () -{ - init_noninteractive (); - expand_aliases = interactive_shell = startup_state = 1; -} - -void -get_current_user_info () -{ - struct passwd *entry; - - /* Don't fetch this more than once. */ - if (current_user.user_name == 0) - { -#if defined (__TANDEM) - entry = getpwnam (getlogin ()); -#else - entry = getpwuid (current_user.uid); -#endif - if (entry) - { - current_user.user_name = savestring (entry->pw_name); - current_user.shell = (entry->pw_shell && entry->pw_shell[0]) - ? savestring (entry->pw_shell) - : savestring ("/bin/sh"); - current_user.home_dir = savestring (entry->pw_dir); - } - else - { - current_user.user_name = _("I have no name!"); - current_user.user_name = savestring (current_user.user_name); - current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring ("/"); - } - endpwent (); - } -} - -/* Do whatever is necessary to initialize the shell. - Put new initializations in here. */ -static void -shell_initialize () -{ - char hostname[256]; - - /* Line buffer output for stderr and stdout. */ - if (shell_initialized == 0) - { - sh_setlinebuf (stderr); - sh_setlinebuf (stdout); - } - - /* Sort the array of shell builtins so that the binary search in - find_shell_builtin () works correctly. */ - initialize_shell_builtins (); - - /* Initialize the trap signal handlers before installing our own - signal handlers. traps.c:restore_original_signals () is responsible - for restoring the original default signal handlers. That function - is called when we make a new child. */ - initialize_traps (); - initialize_signals (0); - - /* It's highly unlikely that this will change. */ - if (current_host_name == 0) - { - /* Initialize current_host_name. */ - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; - else - current_host_name = savestring (hostname); - } - - /* Initialize the stuff in current_user that comes from the password - file. We don't need to do this right away if the shell is not - interactive. */ - if (interactive_shell) - get_current_user_info (); - - /* Initialize our interface to the tilde expander. */ - tilde_initialize (); - - /* Initialize internal and environment variables. Don't import shell - functions from the environment if we are running in privileged or - restricted mode or if the shell is running setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid); -#else - initialize_shell_variables (shell_environment, privileged_mode||running_setuid); -#endif - - /* Initialize the data structures for storing and running jobs. */ - initialize_job_control (jobs_m_flag); - - /* Initialize input streams to null. */ - initialize_bash_input (); - - initialize_flags (); - - /* Initialize the shell options. Don't import the shell options - from the environment variables $SHELLOPTS or $BASHOPTS if we are - running in privileged or restricted mode or if the shell is running - setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_options (privileged_mode||restricted||running_setuid); - initialize_bashopts (privileged_mode||restricted||running_setuid); -#else - initialize_shell_options (privileged_mode||running_setuid); - initialize_bashopts (privileged_mode||running_setuid); -#endif -} - -/* Function called by main () when it appears that the shell has already - had some initialization performed. This is supposed to reset the world - back to a pristine state, as if we had been exec'ed. */ -static void -shell_reinitialize () -{ - /* The default shell prompts. */ - primary_prompt = PPROMPT; - secondary_prompt = SPROMPT; - - /* Things that get 1. */ - current_command_number = 1; - - /* We have decided that the ~/.bashrc file should not be executed - for the invocation of each shell script. If the variable $ENV - (or $BASH_ENV) is set, its value is used as the name of a file - to source. */ - no_rc = no_profile = 1; - - /* Things that get 0. */ - login_shell = make_login_shell = interactive = executing = 0; - debugging = do_version = line_number = last_command_exit_value = 0; - forced_interactive = interactive_shell = subshell_environment = 0; - expand_aliases = 0; - - /* XXX - should we set jobs_m_flag to 0 here? */ - -#if defined (HISTORY) - bash_history_reinit (0); -#endif /* HISTORY */ - -#if defined (RESTRICTED_SHELL) - restricted = 0; -#endif /* RESTRICTED_SHELL */ - - /* Ensure that the default startup file is used. (Except that we don't - execute this file for reinitialized shells). */ - bashrc_file = "~/.bashrc"; - - /* Delete all variables and functions. They will be reinitialized when - the environment is parsed. */ - delete_all_contexts (shell_variables); - delete_all_variables (shell_functions); - - reinit_special_variables (); - -#if defined (READLINE) - bashline_reinitialize (); -#endif - - shell_reinitialized = 1; -} - -static void -show_shell_usage (fp, extra) - FILE *fp; - int extra; -{ - int i; - char *set_opts, *s, *t; - - if (extra) - fprintf (fp, _("GNU bash, version %s-(%s)\n"), shell_version_string (), MACHTYPE); - fprintf (fp, _("Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n"), - shell_name, shell_name); - fputs (_("GNU long options:\n"), fp); - for (i = 0; long_args[i].name; i++) - fprintf (fp, "\t--%s\n", long_args[i].name); - - fputs (_("Shell options:\n"), fp); - fputs (_("\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"), fp); - - for (i = 0, set_opts = 0; shell_builtins[i].name; i++) - if (STREQ (shell_builtins[i].name, "set")) - set_opts = savestring (shell_builtins[i].short_doc); - if (set_opts) - { - s = strchr (set_opts, '['); - if (s == 0) - s = set_opts; - while (*++s == '-') - ; - t = strchr (s, ']'); - if (t) - *t = '\0'; - fprintf (fp, _("\t-%s or -o option\n"), s); - free (set_opts); - } - - if (extra) - { - fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name); - fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name); - fprintf (fp, _("Use the `bashbug' command to report bugs.\n")); - } -} - -static void -add_shopt_to_alist (opt, on_or_off) - char *opt; - int on_or_off; -{ - if (shopt_ind >= shopt_len) - { - shopt_len += 8; - shopt_alist = (STRING_INT_ALIST *)xrealloc (shopt_alist, shopt_len * sizeof (shopt_alist[0])); - } - shopt_alist[shopt_ind].word = opt; - shopt_alist[shopt_ind].token = on_or_off; - shopt_ind++; -} - -static void -run_shopt_alist () -{ - register int i; - - for (i = 0; i < shopt_ind; i++) - if (shopt_setopt (shopt_alist[i].word, (shopt_alist[i].token == '-')) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - free (shopt_alist); - shopt_alist = 0; - shopt_ind = shopt_len = 0; -} diff --git a/sig.c~ b/sig.c~ deleted file mode 100644 index a38eb33f7..000000000 --- a/sig.c~ +++ /dev/null @@ -1,692 +0,0 @@ -/* sig.c - interface for shell signal handlers and signal initialization. */ - -/* Copyright (C) 1994-2012 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 . -*/ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include - -#include "bashintl.h" - -#include "shell.h" -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif /* JOB_CONTROL */ -#include "siglist.h" -#include "sig.h" -#include "trap.h" - -#include "builtins/common.h" - -#if defined (READLINE) -# include "bashline.h" -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int last_command_exit_value; -extern int last_command_exit_signal; -extern int return_catch_flag; -extern int loop_level, continuing, breaking, funcnest; -extern int executing_list; -extern int comsub_ignore_return; -extern int parse_and_execute_level, shell_initialized; -#if defined (HISTORY) -extern int history_lines_this_session; -#endif -extern int no_line_editing; - -extern void initialize_siglist (); - -/* Non-zero after SIGINT. */ -volatile int interrupt_state = 0; - -/* Non-zero after SIGWINCH */ -volatile int sigwinch_received = 0; - -/* Set to the value of any terminating signal received. */ -volatile int terminating_signal = 0; - -/* The environment at the top-level R-E loop. We use this in - the case of error return. */ -procenv_t top_level; - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) -/* The signal masks that this shell runs with. */ -sigset_t top_level_mask; -#endif /* JOB_CONTROL */ - -/* When non-zero, we throw_to_top_level (). */ -int interrupt_immediately = 0; - -/* When non-zero, we call the terminating signal handler immediately. */ -int terminate_immediately = 0; - -#if defined (SIGWINCH) -static SigHandler *old_winch = (SigHandler *)SIG_DFL; -#endif - -static void initialize_shell_signals __P((void)); - -void -initialize_signals (reinit) - int reinit; -{ - initialize_shell_signals (); - initialize_job_signals (); -#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) - if (reinit == 0) - initialize_siglist (); -#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ -} - -/* A structure describing a signal that terminates the shell if not - caught. The orig_handler member is present so children can reset - these signals back to their original handlers. */ -struct termsig { - int signum; - SigHandler *orig_handler; - int orig_flags; -}; - -#define NULL_HANDLER (SigHandler *)SIG_DFL - -/* The list of signals that would terminate the shell if not caught. - We catch them, but just so that we can write the history file, - and so forth. */ -static struct termsig terminating_signals[] = { -#ifdef SIGHUP -{ SIGHUP, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGINT -{ SIGINT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGILL -{ SIGILL, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGTRAP -{ SIGTRAP, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGIOT -{ SIGIOT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGDANGER -{ SIGDANGER, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGEMT -{ SIGEMT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGFPE -{ SIGFPE, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGBUS -{ SIGBUS, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGSEGV -{ SIGSEGV, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGSYS -{ SIGSYS, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGPIPE -{ SIGPIPE, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGALRM -{ SIGALRM, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGTERM -{ SIGTERM, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGXCPU -{ SIGXCPU, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGXFSZ -{ SIGXFSZ, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGVTALRM -{ SIGVTALRM, NULL_HANDLER, 0 }, -#endif - -#if 0 -#ifdef SIGPROF -{ SIGPROF, NULL_HANDLER, 0 }, -#endif -#endif - -#ifdef SIGLOST -{ SIGLOST, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGUSR1 -{ SIGUSR1, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGUSR2 -{ SIGUSR2, NULL_HANDLER, 0 }, -#endif -}; - -#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) - -#define XSIG(x) (terminating_signals[x].signum) -#define XHANDLER(x) (terminating_signals[x].orig_handler) -#define XSAFLAGS(x) (terminating_signals[x].orig_flags) - -static int termsigs_initialized = 0; - -/* Initialize signals that will terminate the shell to do some - unwind protection. For non-interactive shells, we only call - this when a trap is defined for EXIT (0) or when trap is run - to display signal dispositions. */ -void -initialize_terminating_signals () -{ - register int i; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act, oact; -#endif - -itrace("initialize_terminating_signals: termsigs_initialized = %d", termsigs_initialized); - if (termsigs_initialized) - return; - - /* The following code is to avoid an expensive call to - set_signal_handler () for each terminating_signals. Fortunately, - this is possible in Posix. Unfortunately, we have to call signal () - on non-Posix systems for each signal in terminating_signals. */ -#if defined (HAVE_POSIX_SIGNALS) - act.sa_handler = termsig_sighandler; - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - sigaddset (&act.sa_mask, XSIG (i)); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* If we've already trapped it, don't do anything. */ - if (signal_is_trapped (XSIG (i))) - continue; - - sigaction (XSIG (i), &act, &oact); - XHANDLER(i) = oact.sa_handler; - XSAFLAGS(i) = oact.sa_flags; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - /* XXX - should we do this for interactive shells, too? */ - if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) - { - sigaction (XSIG (i), &oact, &act); - set_signal_ignored (XSIG (i)); - } -#if defined (SIGPROF) && !defined (_MINIX) - if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) - sigaction (XSIG (i), &oact, (struct sigaction *)NULL); -#endif /* SIGPROF && !_MINIX */ - } - -#else /* !HAVE_POSIX_SIGNALS */ - - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* If we've already trapped it, don't do anything. */ - if (signal_is_trapped (XSIG (i))) - continue; - - XHANDLER(i) = signal (XSIG (i), termsig_sighandler); - XSAFLAGS(i) = 0; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - /* XXX - should we do this for interactive shells, too? */ - if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) - { - signal (XSIG (i), SIG_IGN); - set_signal_ignored (XSIG (i)); - } -#ifdef SIGPROF - if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) - signal (XSIG (i), XHANDLER (i)); -#endif - } - -#endif /* !HAVE_POSIX_SIGNALS */ - - termsigs_initialized = 1; -} - -static void -initialize_shell_signals () -{ - if (interactive) - initialize_terminating_signals (); - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) - /* All shells use the signal mask they inherit, and pass it along - to child processes. Children will never block SIGCHLD, though. */ - sigemptyset (&top_level_mask); - sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); -# if defined (SIGCHLD) - sigdelset (&top_level_mask, SIGCHLD); -# endif -#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ - - /* And, some signals that are specifically ignored by the shell. */ - set_signal_handler (SIGQUIT, SIG_IGN); - - if (interactive) - { - set_signal_handler (SIGINT, sigint_sighandler); - set_signal_handler (SIGTERM, SIG_IGN); - set_sigwinch_handler (); - } -} - -void -reset_terminating_signals () -{ - register int i; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act; -#endif - - if (termsigs_initialized == 0) - return; - -#if defined (HAVE_POSIX_SIGNALS) - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* Skip a signal if it's trapped or handled specially, because the - trap code will restore the correct value. */ - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - act.sa_handler = XHANDLER (i); - act.sa_flags = XSAFLAGS (i); - sigaction (XSIG (i), &act, (struct sigaction *) NULL); - } -#else /* !HAVE_POSIX_SIGNALS */ - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - signal (XSIG (i), XHANDLER (i)); - } -#endif /* !HAVE_POSIX_SIGNALS */ - - termsigs_initialized = 0; -} -#undef XSIG -#undef XHANDLER - -/* Run some of the cleanups that should be performed when we run - jump_to_top_level from a builtin command context. XXX - might want to - also call reset_parser here. */ -void -top_level_cleanup () -{ - /* Clean up string parser environment. */ - while (parse_and_execute_level) - parse_and_execute_cleanup (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_unwind_protects (); - loop_level = continuing = breaking = funcnest = 0; - executing_list = comsub_ignore_return = return_catch_flag = 0; -} - -/* What to do when we've been interrupted, and it is safe to handle it. */ -void -throw_to_top_level () -{ - int print_newline = 0; - - if (interrupt_state) - { - print_newline = 1; - DELINTERRUPT; - } - - if (interrupt_state) - return; - - last_command_exit_signal = (last_command_exit_value > 128) ? - (last_command_exit_value - 128) : 0; - last_command_exit_value |= 128; - - /* Run any traps set on SIGINT. */ - run_interrupt_trap (); - - /* Clean up string parser environment. */ - while (parse_and_execute_level) - parse_and_execute_cleanup (); - -#if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp, 0); -#endif /* JOB_CONTROL */ - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) - /* This should not be necessary on systems using sigsetjmp/siglongjmp. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif - - reset_parser (); - -#if defined (READLINE) - if (interactive) - bashline_reset (); -#endif /* READLINE */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_unwind_protects (); - loop_level = continuing = breaking = funcnest = 0; - executing_list = comsub_ignore_return = return_catch_flag = 0; - - if (interactive && print_newline) - { - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - /* An interrupted `wait' command in a script does not exit the script. */ - if (interactive || (interactive_shell && !shell_initialized) || - (print_newline && signal_is_trapped (SIGINT))) - jump_to_top_level (DISCARD); - else - jump_to_top_level (EXITPROG); -} - -/* This is just here to isolate the longjmp calls. */ -void -jump_to_top_level (value) - int value; -{ - longjmp (top_level, value); -} - -sighandler -termsig_sighandler (sig) - int sig; -{ - /* If we get called twice with the same signal before handling it, - terminate right away. */ - if ( -#ifdef SIGHUP - sig != SIGHUP && -#endif -#ifdef SIGINT - sig != SIGINT && -#endif -#ifdef SIGDANGER - sig != SIGDANGER && -#endif -#ifdef SIGPIPE - sig != SIGPIPE && -#endif -#ifdef SIGALRM - sig != SIGALRM && -#endif -#ifdef SIGTERM - sig != SIGTERM && -#endif -#ifdef SIGXCPU - sig != SIGXCPU && -#endif -#ifdef SIGXFSZ - sig != SIGXFSZ && -#endif -#ifdef SIGVTALRM - sig != SIGVTALRM && -#endif -#ifdef SIGLOST - sig != SIGLOST && -#endif -#ifdef SIGUSR1 - sig != SIGUSR1 && -#endif -#ifdef SIGUSR2 - sig != SIGUSR2 && -#endif - sig == terminating_signal) - terminate_immediately = 1; - - terminating_signal = sig; - - /* XXX - should this also trigger when interrupt_immediately is set? */ - if (terminate_immediately) - { -#if defined (HISTORY) - /* XXX - will inhibit history file being written */ -# if defined (READLINE) - if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0)) -# endif - history_lines_this_session = 0; -#endif - terminate_immediately = 0; - termsig_handler (sig); - } - -#if defined (READLINE) - if (interactive_shell && interactive && no_line_editing == 0) - bashline_set_event_hook (); -#endif - - SIGRETURN (0); -} - -void -termsig_handler (sig) - int sig; -{ - static int handling_termsig = 0; - - /* Simple semaphore to keep this function from being executed multiple - times. Since we no longer are running as a signal handler, we don't - block multiple occurrences of the terminating signals while running. */ - if (handling_termsig) - return; - handling_termsig = 1; - terminating_signal = 0; /* keep macro from re-testing true. */ - - /* I don't believe this condition ever tests true. */ - if (sig == SIGINT && signal_is_trapped (SIGINT)) - run_interrupt_trap (); - -#if 0 -#if defined (HISTORY) - if (interactive_shell && (sig != SIGABRT && sig != SIGINT && sig != SIGHUP && sig != SIGTERM)) - maybe_save_shell_history (); -#endif /* HISTORY */ -#endif - -#if defined (JOB_CONTROL) - if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)))) - hangup_all_jobs (); - end_job_control (); -#endif /* JOB_CONTROL */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - /* Reset execution context */ - loop_level = continuing = breaking = funcnest = 0; - executing_list = comsub_ignore_return = return_catch_flag = 0; - - run_exit_trap (); - set_signal_handler (sig, SIG_DFL); - kill (getpid (), sig); -} - -/* What we really do when SIGINT occurs. */ -sighandler -sigint_sighandler (sig) - int sig; -{ -#if defined (MUST_REINSTALL_SIGHANDLERS) - signal (sig, sigint_sighandler); -#endif - - /* interrupt_state needs to be set for the stack of interrupts to work - right. Should it be set unconditionally? */ - if (interrupt_state == 0) - ADDINTERRUPT; - - if (interrupt_immediately) - { - interrupt_immediately = 0; - last_command_exit_value = 128 + sig; - throw_to_top_level (); - } - - SIGRETURN (0); -} - -#if defined (SIGWINCH) -sighandler -sigwinch_sighandler (sig) - int sig; -{ -#if defined (MUST_REINSTALL_SIGHANDLERS) - set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* MUST_REINSTALL_SIGHANDLERS */ - sigwinch_received = 1; - SIGRETURN (0); -} -#endif /* SIGWINCH */ - -void -set_sigwinch_handler () -{ -#if defined (SIGWINCH) - old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif -} - -void -unset_sigwinch_handler () -{ -#if defined (SIGWINCH) - set_signal_handler (SIGWINCH, old_winch); -#endif -} - -/* Signal functions used by the rest of the code. */ -#if !defined (HAVE_POSIX_SIGNALS) - -/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ -sigprocmask (operation, newset, oldset) - int operation, *newset, *oldset; -{ - int old, new; - - if (newset) - new = *newset; - else - new = 0; - - switch (operation) - { - case SIG_BLOCK: - old = sigblock (new); - break; - - case SIG_SETMASK: - old = sigsetmask (new); - break; - - default: - internal_error (_("sigprocmask: %d: invalid operation"), operation); - } - - if (oldset) - *oldset = old; -} - -#else - -#if !defined (SA_INTERRUPT) -# define SA_INTERRUPT 0 -#endif - -#if !defined (SA_RESTART) -# define SA_RESTART 0 -#endif - -SigHandler * -set_signal_handler (sig, handler) - int sig; - SigHandler *handler; -{ - struct sigaction act, oact; - - act.sa_handler = handler; - act.sa_flags = 0; - - /* XXX - bash-4.2 */ - /* We don't want a child death to interrupt interruptible system calls, even - if we take the time to reap children */ -#if defined (SIGCHLD) - if (sig == SIGCHLD) - act.sa_flags |= SA_RESTART; /* XXX */ -#endif - - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); -} -#endif /* HAVE_POSIX_SIGNALS */ diff --git a/subst.c~ b/subst.c~ deleted file mode 100644 index 801960084..000000000 --- a/subst.c~ +++ /dev/null @@ -1,9495 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - and globbing substitutions. */ - -/* ``Have a little faith, there's magic in the night. You ain't a - beauty, but, hey, you're alright.'' */ - -/* Copyright (C) 1987-2012 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 . -*/ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" -#include "posixstat.h" -#include "bashintl.h" - -#include "shell.h" -#include "parser.h" -#include "flags.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "filecntl.h" -#include "trap.h" -#include "pathexp.h" -#include "mailcheck.h" - -#include "shmbutil.h" -#include "typemax.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" - -#include "builtins/builtext.h" - -#include -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The size that strings change by. */ -#define DEFAULT_INITIAL_ARRAY_SIZE 112 -#define DEFAULT_ARRAY_SIZE 128 - -/* Variable types. */ -#define VT_VARIABLE 0 -#define VT_POSPARMS 1 -#define VT_ARRAYVAR 2 -#define VT_ARRAYMEMBER 3 -#define VT_ASSOCVAR 4 - -#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */ - -/* Flags for quoted_strchr */ -#define ST_BACKSL 0x01 -#define ST_CTLESC 0x02 -#define ST_SQUOTE 0x04 /* unused yet */ -#define ST_DQUOTE 0x08 /* unused yet */ - -/* Flags for the `pflags' argument to param_expand() */ -#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ -#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */ -#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */ -#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */ - -/* These defs make it easier to use the editor. */ -#define LBRACE '{' -#define RBRACE '}' -#define LPAREN '(' -#define RPAREN ')' - -#if defined (HANDLE_MULTIBYTE) -#define WLPAREN L'(' -#define WRPAREN L')' -#endif - -/* Evaluates to 1 if C is one of the shell's special parameters whose length - can be taken, but is also one of the special expansion characters. */ -#define VALID_SPECIAL_LENGTH_PARAM(c) \ - ((c) == '-' || (c) == '?' || (c) == '#') - -/* Evaluates to 1 if C is one of the shell's special parameters for which an - indirect variable reference may be made. */ -#define VALID_INDIR_PARAM(c) \ - ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*') - -/* Evaluates to 1 if C is one of the OP characters that follows the parameter - in ${parameter[:]OPword}. */ -#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP) - -/* Evaluates to 1 if this is one of the shell's special variables. */ -#define SPECIAL_VAR(name, wi) \ - ((DIGIT (*name) && all_digits (name)) || \ - (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \ - (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))) - -/* An expansion function that takes a string and a quoted flag and returns - a WORD_LIST *. Used as the type of the third argument to - expand_string_if_necessary(). */ -typedef WORD_LIST *EXPFUNC __P((char *, int)); - -/* Process ID of the last command executed within command substitution. */ -pid_t last_command_subst_pid = NO_PID; -pid_t current_command_subst_pid = NO_PID; - -/* Variables used to keep track of the characters in IFS. */ -SHELL_VAR *ifs_var; -char *ifs_value; -unsigned char ifs_cmap[UCHAR_MAX + 1]; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -/* Sentinel to tell when we are performing variable assignments preceding a - command name and putting them into the environment. Used to make sure - we use the temporary environment when looking up variable values. */ -int assigning_in_environment; - -/* Used to hold a list of variable assignments preceding a command. Global - so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a - SIGCHLD trap and so it can be saved and restored by the trap handlers. */ -WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL; - -/* Extern functions and variables from different files. */ -extern int last_command_exit_value, last_command_exit_signal; -extern int subshell_environment, line_number; -extern int subshell_level, parse_and_execute_level, sourcelevel; -extern int eof_encountered; -extern int return_catch_flag, return_catch_value; -extern pid_t dollar_dollar_pid; -extern int posixly_correct; -extern char *this_command_name; -extern struct fd_bitmap *current_fds_to_close; -extern int wordexp_only; -extern int expanding_redir; -extern int tempenv_assign_error; - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup __P((const wchar_t *)); -#endif - -/* Non-zero means to allow unmatched globbed filenames to expand to - a null file. */ -int allow_null_glob_expansion; - -/* Non-zero means to throw an error when globbing fails to match anything. */ -int fail_glob_expansion; - -#if 0 -/* Variables to keep track of which words in an expanded word list (the - output of expand_word_list_internal) are the result of globbing - expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. - (CURRENTLY UNUSED). */ -char *glob_argv_flags; -static int glob_argv_flags_size; -#endif - -static WORD_LIST expand_word_error, expand_word_fatal; -static WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal; -static char extract_string_error, extract_string_fatal; - -/* Tell the expansion functions to not longjmp back to top_level on fatal - errors. Enabled when doing completion and prompt string expansion. */ -static int no_longjmp_on_fatal_error = 0; - -/* Set by expand_word_unsplit; used to inhibit splitting and re-joining - $* on $IFS, primarily when doing assignment statements. */ -static int expand_no_split_dollar_star = 0; - -/* A WORD_LIST of words to be expanded by expand_word_list_internal, - without any leading variable assignments. */ -static WORD_LIST *garglist = (WORD_LIST *)NULL; - -static char *quoted_substring __P((char *, int, int)); -static int quoted_strlen __P((char *)); -static char *quoted_strchr __P((char *, int, int)); - -static char *expand_string_if_necessary __P((char *, int, EXPFUNC *)); -static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *)); -static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); -static WORD_LIST *expand_string_internal __P((char *, int)); -static WORD_LIST *expand_string_leave_quoted __P((char *, int)); -static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *)); - -static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); -static char *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); -#endif -static int do_assignment_internal __P((const WORD_DESC *, int)); - -static char *string_extract_verbatim __P((char *, size_t, int *, char *, int)); -static char *string_extract __P((char *, int *, char *, int)); -static char *string_extract_double_quoted __P((char *, int *, int)); -static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((const char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); -static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); -static char *extract_dollar_brace_string __P((char *, int *, int, int)); -static int skip_matched_pair __P((const char *, int, int, int, int)); - -static char *pos_params __P((char *, int, int, int)); - -static unsigned char *mb_getcharlens __P((char *, int)); - -static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); -#endif -static char *remove_pattern __P((char *, char *, int)); - -static int match_upattern __P((char *, char *, int, char **, char **)); -#if defined (HANDLE_MULTIBYTE) -static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **)); -#endif -static int match_pattern __P((char *, char *, int, char **, char **)); -static int getpatspec __P((int, char *)); -static char *getpattern __P((char *, int, int)); -static char *variable_remove_pattern __P((char *, char *, int, int)); -static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int)); -static char *parameter_list_remove_pattern __P((int, char *, int, int)); -#ifdef ARRAY_VARS -static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int)); -#endif -static char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int)); - -static char *process_substitute __P((char *, int)); - -static char *read_comsub __P((int, int, int *)); - -#ifdef ARRAY_VARS -static arrayind_t array_length_reference __P((char *)); -#endif - -static int valid_brace_expansion_word __P((char *, int)); -static int chk_atstar __P((char *, int, int *, int *)); -static int chk_arithsub __P((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *)); -static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *)); -static void parameter_brace_expand_error __P((char *, char *)); - -static int valid_length_expression __P((char *)); -static intmax_t parameter_brace_expand_length __P((char *)); - -static char *skiparith __P((char *, int)); -static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **)); -static char *mb_substring __P((char *, int, int)); -static char *parameter_brace_substring __P((char *, char *, int, char *, int, int)); - -static int shouldexp_replacement __P((char *)); - -static char *pos_params_pat_subst __P((char *, char *, char *, int)); - -static char *parameter_brace_patsub __P((char *, char *, int, char *, int, int)); - -static char *pos_params_casemod __P((char *, char *, int, int)); -static char *parameter_brace_casemod __P((char *, char *, int, int, char *, int, int)); - -static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *)); -static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int)); - -static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *)); - -static WORD_LIST *word_list_split __P((WORD_LIST *)); - -static void exp_jump_to_top_level __P((int)); - -static WORD_LIST *separate_out_assignments __P((WORD_LIST *)); -static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int)); -#ifdef BRACE_EXPANSION -static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int)); -#endif -#if defined (ARRAY_VARS) -static int make_internal_declare __P((char *, char *)); -#endif -static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int)); -static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int)); - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -#if defined (DEBUG) -void -dump_word_flags (flags) - int flags; -{ - int f; - - f = flags; - fprintf (stderr, "%d -> ", f); - if (f & W_ASSIGNASSOC) - { - f &= ~W_ASSIGNASSOC; - fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : ""); - } - if (f & W_HASCTLESC) - { - f &= ~W_HASCTLESC; - fprintf (stderr, "W_HASCTLESC%s", f ? "|" : ""); - } - if (f & W_NOPROCSUB) - { - f &= ~W_NOPROCSUB; - fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : ""); - } - if (f & W_DQUOTE) - { - f &= ~W_DQUOTE; - fprintf (stderr, "W_DQUOTE%s", f ? "|" : ""); - } - if (f & W_HASQUOTEDNULL) - { - f &= ~W_HASQUOTEDNULL; - fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : ""); - } - if (f & W_ASSIGNARG) - { - f &= ~W_ASSIGNARG; - fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : ""); - } - if (f & W_ASSNBLTIN) - { - f &= ~W_ASSNBLTIN; - fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); - } - if (f & W_ASSNGLOBAL) - { - f &= ~W_ASSNGLOBAL; - fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); - } - if (f & W_COMPASSIGN) - { - f &= ~W_COMPASSIGN; - fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); - } - if (f & W_NOEXPAND) - { - f &= ~W_NOEXPAND; - fprintf (stderr, "W_NOEXPAND%s", f ? "|" : ""); - } - if (f & W_ITILDE) - { - f &= ~W_ITILDE; - fprintf (stderr, "W_ITILDE%s", f ? "|" : ""); - } - if (f & W_NOTILDE) - { - f &= ~W_NOTILDE; - fprintf (stderr, "W_NOTILDE%s", f ? "|" : ""); - } - if (f & W_ASSIGNRHS) - { - f &= ~W_ASSIGNRHS; - fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : ""); - } - if (f & W_NOCOMSUB) - { - f &= ~W_NOCOMSUB; - fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : ""); - } - if (f & W_DOLLARSTAR) - { - f &= ~W_DOLLARSTAR; - fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : ""); - } - if (f & W_DOLLARAT) - { - f &= ~W_DOLLARAT; - fprintf (stderr, "W_DOLLARAT%s", f ? "|" : ""); - } - if (f & W_TILDEEXP) - { - f &= ~W_TILDEEXP; - fprintf (stderr, "W_TILDEEXP%s", f ? "|" : ""); - } - if (f & W_NOSPLIT2) - { - f &= ~W_NOSPLIT2; - fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : ""); - } - if (f & W_NOGLOB) - { - f &= ~W_NOGLOB; - fprintf (stderr, "W_NOGLOB%s", f ? "|" : ""); - } - if (f & W_NOSPLIT) - { - f &= ~W_NOSPLIT; - fprintf (stderr, "W_NOSPLIT%s", f ? "|" : ""); - } - if (f & W_GLOBEXP) - { - f &= ~W_GLOBEXP; - fprintf (stderr, "W_GLOBEXP%s", f ? "|" : ""); - } - if (f & W_ASSIGNMENT) - { - f &= ~W_ASSIGNMENT; - fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : ""); - } - if (f & W_QUOTED) - { - f &= ~W_QUOTED; - fprintf (stderr, "W_QUOTED%s", f ? "|" : ""); - } - if (f & W_HASDOLLAR) - { - f &= ~W_HASDOLLAR; - fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : ""); - } - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif - -#ifdef INCLUDE_UNUSED -static char * -quoted_substring (string, start, end) - char *string; - int start, end; -{ - register int len, l; - register char *result, *s, *r; - - len = end - start; - - /* Move to string[start], skipping quoted characters. */ - for (s = string, l = 0; *s && l < start; ) - { - if (*s == CTLESC) - { - s++; - continue; - } - l++; - if (*s == 0) - break; - } - - r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */ - - /* Copy LEN characters, including quote characters. */ - s = string + l; - for (l = 0; l < len; s++) - { - if (*s == CTLESC) - *r++ = *s++; - *r++ = *s; - l++; - if (*s == 0) - break; - } - *r = '\0'; - return result; -} -#endif - -#ifdef INCLUDE_UNUSED -/* Return the length of S, skipping over quoted characters */ -static int -quoted_strlen (s) - char *s; -{ - register char *p; - int i; - - i = 0; - for (p = s; *p; p++) - { - if (*p == CTLESC) - { - p++; - if (*p == 0) - return (i + 1); - } - i++; - } - - return i; -} -#endif - -/* Find the first occurrence of character C in string S, obeying shell - quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped - characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters - escaped with CTLESC are skipped. */ -static char * -quoted_strchr (s, c, flags) - char *s; - int c, flags; -{ - register char *p; - - for (p = s; *p; p++) - { - if (((flags & ST_BACKSL) && *p == '\\') - || ((flags & ST_CTLESC) && *p == CTLESC)) - { - p++; - if (*p == '\0') - return ((char *)NULL); - continue; - } - else if (*p == c) - return p; - } - return ((char *)NULL); -} - -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - size_t slen; - int sindex, c; - DECLARE_MBSTATE; - - slen = strlen (string); - sindex = 0; - while (c = string[sindex]) - { - if (c == character) - return (1); - - switch (c) - { - default: - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - size_t slen; - int sindex, c, sublen; - DECLARE_MBSTATE; - - if (substr == 0 || *substr == '\0') - return (0); - - slen = strlen (string); - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - if (string[sindex]) - ADVANCE_CHAR (string, slen, sindex); - break; - - case '\'': - sindex = skip_single_quoted (string, slen, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, slen, ++sindex); - break; - - default: - ADVANCE_CHAR (string, slen, sindex); - break; - } - } - return (0); -} - -/* Most of the substitutions must be done in parallel. In order - to avoid using tons of unclear goto's, I have some functions - for manipulating malloc'ed strings. They all take INDX, a - pointer to an integer which is the offset into the string - where manipulation is taking place. They also take SIZE, a - pointer to an integer which is the current length of the - character array for this string. */ - -/* Append SOURCE to TARGET at INDEX. SIZE is the current amount - of space allocated to TARGET. SOURCE can be NULL, in which - case nothing happens. Gets rid of SOURCE by freeing it. - Returns TARGET in case the location has changed. */ -INLINE char * -sub_append_string (source, target, indx, size) - char *source, *target; - int *indx, *size; -{ - if (source) - { - int srclen, n; - - srclen = STRLEN (source); - if (srclen >= (int)(*size - *indx)) - { - n = srclen + *indx; - n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); - target = (char *)xrealloc (target, (*size = n)); - } - - FASTCOPY (source, target + *indx, srclen); - *indx += srclen; - target[*indx] = '\0'; - - free (source); - } - return (target); -} - -#if 0 -/* UNUSED */ -/* Append the textual representation of NUMBER to TARGET. - INDX and SIZE are as in SUB_APPEND_STRING. */ -char * -sub_append_number (number, target, indx, size) - intmax_t number; - int *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif - -/* Extract a substring from STRING, starting at SINDEX and ending with - one of the characters in CHARLIST. Don't make the ending character - part of the string. Leave SINDEX pointing at the ending character. - Understand about backslashes in the string. If (flags & SX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & SX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & SX_VARNAME) && c == '[') - { - int ni; - /* If this is an array subscript, skip over it and continue. */ - ni = skipsubscript (string, i, 0); - if (string[ni] == ']') - i = ni; - } -#endif - else if (MEMBER (c, charlist)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & SX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the contents of STRING as if it is enclosed in double quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening double quote; on exit, SINDEX is left pointing after - the closing double quote. If STRIPDQ is non-zero, unquoted double - quotes are stripped and the string is terminated by a null byte. - Backslashes between the embedded double quotes are processed. If STRIPDQ - is zero, an unquoted `"' terminates the string. */ -static char * -string_extract_double_quoted (string, sindex, stripdq) - char *string; - int *sindex, stripdq; -{ - size_t slen; - char *send; - int j, i, t; - unsigned char c; - char *temp, *ret; /* The new string we return. */ - int pass_next, backquote, si; /* State variables for the machine. */ - int dquote; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - send = string + slen; - - pass_next = backquote = dquote = 0; - temp = (char *)xmalloc (1 + slen - *sindex); - - j = 0; - i = *sindex; - while (c = string[i]) - { - /* Process a character that was quoted by a backslash. */ - if (pass_next) - { - /* XXX - take another look at this in light of Interp 221 */ - /* Posix.2 sez: - - ``The backslash shall retain its special meaning as an escape - character only when followed by one of the characters: - $ ` " \ ''. - - If STRIPDQ is zero, we handle the double quotes here and let - expand_word_internal handle the rest. If STRIPDQ is non-zero, - we have already been through one round of backslash stripping, - and want to strip these backslashes only if DQUOTE is non-zero, - indicating that we are inside an embedded double-quoted string. */ - - /* If we are in an embedded quoted string, then don't strip - backslashes before characters for which the backslash - retains its special meaning, but remove backslashes in - front of other characters. If we are not in an - embedded quoted string, don't strip backslashes at all. - This mess is necessary because the string was already - surrounded by double quotes (and sh has some really weird - quoting rules). - The returned string will be run through expansion as if - it were double-quoted. */ - if ((stripdq == 0 && c != '"') || - (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0))) - temp[j++] = '\\'; - pass_next = 0; - -add_one_character: - COPY_CHAR_I (temp, j, string, send, i); - continue; - } - - /* A backslash protects the next character. The code just above - handles preserving the backslash in front of any character but - a double quote. */ - if (c == '\\') - { - pass_next++; - i++; - continue; - } - - /* Inside backquotes, ``the portion of the quoted string from the - initial backquote and the characters up to the next backquote - that is not preceded by a backslash, having escape characters - removed, defines that command''. */ - if (backquote) - { - if (c == '`') - backquote = 0; - temp[j++] = c; - i++; - continue; - } - - if (c == '`') - { - temp[j++] = c; - backquote++; - i++; - continue; - } - - /* Pass everything between `$(' and the matching `)' or a quoted - ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - int free_ret = 1; - - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_command_subst (string, &si, 0); - else - ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0); - - temp[j++] = '$'; - temp[j++] = string[i + 1]; - - /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error - is set. */ - if (ret == 0 && no_longjmp_on_fatal_error) - { - free_ret = 0; - ret = string + i + 2; - } - - for (t = 0; ret[t]; t++, j++) - temp[j] = ret[t]; - temp[j] = string[si]; - - if (string[si]) - { - j++; - i = si + 1; - } - else - i = si; - - if (free_ret) - free (ret); - continue; - } - - /* Add any character but a double quote to the quoted string we're - accumulating. */ - if (c != '"') - goto add_one_character; - - /* c == '"' */ - if (stripdq) - { - dquote ^= 1; - i++; - continue; - } - - break; - } - temp[j] = '\0'; - - /* Point to after the closing quote. */ - if (c) - i++; - *sindex = i; - - return (temp); -} - -/* This should really be another option to string_extract_double_quoted. */ -static int -skip_double_quoted (string, slen, sind) - char *string; - size_t slen; - int sind; -{ - int c, i; - char *ret; - int pass_next, backquote, si; - DECLARE_MBSTATE; - - pass_next = backquote = 0; - i = sind; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next++; - i++; - continue; - } - else if (backquote) - { - if (c == '`') - backquote = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backquote++; - i++; - continue; - } - else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) - { - si = i + 2; - if (string[i + 1] == LPAREN) - ret = extract_command_subst (string, &si, SX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); - - i = si + 1; - continue; - } - else if (c != '"') - { - ADVANCE_CHAR (string, slen, i); - continue; - } - else - break; - } - - if (c) - i++; - - return (i); -} - -/* Extract the contents of STRING as if it is enclosed in single quotes. - SINDEX, when passed in, is the offset of the character immediately - following the opening single quote; on exit, SINDEX is left pointing after - the closing single quote. */ -static inline char * -string_extract_single_quoted (string, sindex) - char *string; - int *sindex; -{ - register int i; - size_t slen; - char *t; - DECLARE_MBSTATE; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - while (string[i] && string[i] != '\'') - ADVANCE_CHAR (string, slen, i); - - t = substring (string, *sindex, i); - - if (string[i]) - i++; - *sindex = i; - - return (t); -} - -static inline int -skip_single_quoted (string, slen, sind) - const char *string; - size_t slen; - int sind; -{ - register int c; - DECLARE_MBSTATE; - - c = sind; - while (string[c] && string[c] != '\'') - ADVANCE_CHAR (string, slen, c); - - if (string[c]) - c++; - return c; -} - -/* Just like string_extract, but doesn't hack backslashes or any of - that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */ -static char * -string_extract_verbatim (string, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i; -#if defined (HANDLE_MULTIBYTE) - size_t clen; - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - i = *sindex; -#if 0 - /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need - this only if MB_CUR_MAX > 1. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1; -#endif -#if defined (HANDLE_MULTIBYTE) - clen = strlen (charlist); - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) - { - i += 2; - continue; - } - /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL - through, to protect the CTLNULs from later calls to - remove_quoted_nulls. */ - else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) - { - i += 2; - continue; - } - -#if defined (HANDLE_MULTIBYTE) - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - temp = substring (string, *sindex, i); - *sindex = i; - - return (temp); -} - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position of the matching ")". ) - XFLAGS is additional flags to pass to other extraction functions. */ -char * -extract_command_subst (string, sindex, xflags) - char *string; - int *sindex; - int xflags; -{ - if (string[*sindex] == LPAREN) - return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ - else - { - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - return (xparse_dolparen (string, string+*sindex, sindex, xflags)); - } -} - -/* Extract the $[ construct in STRING, and return a new string. (]) - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position of the matching "]". */ -char * -extract_arithmetic_subst (string, sindex) - char *string; - int *sindex; -{ - return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/ -} - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ /*))*/ -char * -extract_process_subst (string, starter, sindex) - char *string; - char *starter; - int *sindex; -{ - return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND)); -} -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (ARRAY_VARS) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); /* ( */ - if (string[slen - 1] == ')') - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 0; -} -#endif - -/* Extract and create a new string from the contents of STRING, a - character string delimited with OPENER and CLOSER. SINDEX is - the address of an int describing the current offset in STRING; - it should point to just after the first OPENER found. On exit, - SINDEX gets the position of the last character of the matching CLOSER. - If OPENER is more than a single character, ALT_OPENER, if non-null, - contains a character string that can also match CLOSER and thus - needs to be skipped. */ -static char * -extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) - char *string; - int *sindex; - char *opener, *alt_opener, *closer; - int flags; -{ - int i, c, si; - size_t slen; - char *t, *result; - int pass_character, nesting_level, in_comment; - int len_closer, len_opener, len_alt_opener; - DECLARE_MBSTATE; - - slen = strlen (string + *sindex) + *sindex; - len_opener = STRLEN (opener); - len_alt_opener = STRLEN (alt_opener); - len_closer = STRLEN (closer); - - pass_character = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. See COMMENT_BEGIN define in parse.y */ - if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) - { - in_comment = 1; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - /* Process a nested command substitution, but only if we're parsing an - arithmetic substitution. */ - if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_command_subst (string, &si, flags|SX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested OPENER. */ - if (STREQN (string + i, opener, len_opener)) - { - si = i + len_opener; - t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC); - i = si + 1; - continue; - } - - /* Process a nested ALT_OPENER */ - if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener)) - { - si = i + len_alt_opener; - t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC); - i = si + 1; - continue; - } - - /* If the current substring terminates the delimited string, decrement - the nesting level. */ - if (STREQN (string + i, closer, len_closer)) - { - i += len_closer - 1; /* move to last byte of the closer */ - nesting_level--; - if (nesting_level == 0) - break; - } - - /* Pass old-style command substitution through verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|SX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass single-quoted and double-quoted strings through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - continue; - } - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("bad substitution: no closing `%s' in %s"), closer, string); - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return (char *)NULL; - } - } - - si = i - *sindex - len_closer + 1; - if (flags & SX_NOALLOC) - result = (char *)NULL; - else - { - result = (char *)xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - } - *sindex = i; - - return (result); -} - -/* Extract a parameter expansion expression within ${ and } from STRING. - Obey the Posix.2 rules for finding the ending `}': count braces while - skipping over enclosed quoted strings and command substitutions. - SINDEX is the address of an int describing the current offset in STRING; - it should point to just after the first `{' found. On exit, SINDEX - gets the position of the matching `}'. QUOTED is non-zero if this - occurs inside double quotes. */ -/* XXX -- this is very similar to extract_delimited_string -- XXX */ -static char * -extract_dollar_brace_string (string, sindex, quoted, flags) - char *string; - int *sindex, quoted, flags; -{ - register int i, c; - size_t slen; - int pass_character, nesting_level, si, dolbrace_state; - char *result, *t; - DECLARE_MBSTATE; - - pass_character = 0; - nesting_level = 1; - slen = strlen (string + *sindex) + *sindex; - - /* The handling of dolbrace_state needs to agree with the code in parse.y: - parse_matched_pair(). The different initial value is to handle the - case where this function is called to parse the word in - ${param op word} (SX_WORD). */ - dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) - dolbrace_state = DOLBRACE_QUOTE; - - i = *sindex; - while (c = string[i]) - { - if (pass_character) - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* CTLESCs and backslashes quote the next character. */ - if (c == CTLESC || c == '\\') - { - pass_character++; - i++; - continue; - } - - if (string[i] == '$' && string[i+1] == LBRACE) - { - nesting_level++; - i += 2; - continue; - } - - if (c == RBRACE) - { - nesting_level--; - if (nesting_level == 0) - break; - i++; - continue; - } - - /* Pass the contents of old-style command substitutions through - verbatim. */ - if (c == '`') - { - si = i + 1; - t = string_extract (string, &si, "`", flags|SX_NOALLOC); - i = si + 1; - continue; - } - - /* Pass the contents of new-style command substitutions and - arithmetic substitutions through verbatim. */ - if (string[i] == '$' && string[i+1] == LPAREN) - { - si = i + 2; - t = extract_command_subst (string, &si, flags|SX_NOALLOC); - i = si + 1; - continue; - } - -#if 0 - /* Pass the contents of single-quoted and double-quoted strings - through verbatim. */ - if (c == '\'' || c == '"') - { - si = i + 1; - i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } -#else /* XXX - bash-4.2 */ - /* Pass the contents of double-quoted strings through verbatim. */ - if (c == '"') - { - si = i + 1; - i = skip_double_quoted (string, slen, si); - /* skip_XXX_quoted leaves index one past close quote */ - continue; - } - - if (c == '\'') - { -/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/ - if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ADVANCE_CHAR (string, slen, i); - else - { - si = i + 1; - i = skip_single_quoted (string, slen, si); - } - - continue; - } -#endif - - /* move past this character, which was not special. */ - ADVANCE_CHAR (string, slen, i); - - /* This logic must agree with parse.y:parse_matched_pair, since they - share the same defines. */ - if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1) - dolbrace_state = DOLBRACE_QUOTE; - else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0) - dolbrace_state = DOLBRACE_OP; - else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0) - dolbrace_state = DOLBRACE_WORD; - } - - if (c == 0 && nesting_level) - { - if (no_longjmp_on_fatal_error == 0) - { /* { */ - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("bad substitution: no closing `%s' in %s"), "}", string); - exp_jump_to_top_level (DISCARD); - } - else - { - *sindex = i; - return ((char *)NULL); - } - } - - result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i); - *sindex = i; - - return (result); -} - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -char * -de_backslash (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - slen = strlen (string); - i = j = 0; - - /* Loop copying string[i] to string[j], i >= j. */ - while (i < slen) - { - if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' || - string[i + 1] == '$')) - i++; - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - do string[j++] = string[prev_i++]; while (prev_i < i); - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -#if 0 -/*UNUSED*/ -/* Replace instances of \! in a string with !. */ -void -unquote_bang (string) - char *string; -{ - register int i, j; - register char *temp; - - temp = (char *)xmalloc (1 + strlen (string)); - - for (i = 0, j = 0; (temp[j] = string[i]); i++, j++) - { - if (string[i] == '\\' && string[i + 1] == '!') - { - temp[j] = '!'; - i++; - } - } - strcpy (string, temp); - free (temp); -} -#endif - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -/* This function assumes s[i] == open; returns with s[ret] == close; used to - parse array subscripts. FLAGS & 1 means to not attempt to skip over - matched pairs of quotes or backquotes, or skip word expansions; it is - intended to be used after expansion has been performed and during final - assignment parsing (see arrayfunc.c:assign_compound_array_list()). */ -static int -skip_matched_pair (string, start, open, close, flags) - const char *string; - int start, open, close, flags; -{ - int i, pass_next, backq, si, c, count; - size_t slen; - char *temp, *ss; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - no_longjmp_on_fatal_error = 1; - - i = start + 1; /* skip over leading bracket */ - count = 1; - pass_next = backq = 0; - ss = (char *)string; - while (c = string[i]) - { - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if ((flags & 1) == 0 && c == '`') - { - backq = 1; - i++; - continue; - } - else if ((flags & 1) == 0 && c == open) - { - count++; - i++; - continue; - } - else if (c == close) - { - count--; - if (count == 0) - break; - i++; - continue; - } - else if ((flags & 1) == 0 && (c == '\'' || c == '"')) - { - i = (c == '\'') ? skip_single_quoted (ss, slen, ++i) - : skip_double_quoted (ss, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -#if defined (ARRAY_VARS) -int -skipsubscript (string, start, flags) - const char *string; - int start, flags; -{ - return (skip_matched_pair (string, start, '[', ']', flags)); -} -#endif - -/* Skip characters in STRING until we find a character in DELIMS, and return - the index of that character. START is the index into string at which we - begin. This is similar in spirit to strpbrk, but it returns an index into - STRING and takes a starting index. This little piece of code knows quite - a lot of shell syntax. It's very similar to skip_double_quoted and other - functions of that ilk. */ -int -skip_to_delim (string, start, delims, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, si, c, invert, skipquote, skipcmd; - size_t slen; - char *temp, open[3]; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - if (flags & SD_NOJMP) - no_longjmp_on_fatal_error = 1; - invert = (flags & SD_INVERT); - skipcmd = (flags & SD_NOSKIPCMD) == 0; - - i = start; - pass_next = backq = 0; - while (c = string[i]) - { - /* If this is non-zero, we should not let quote characters be delimiters - and the current character is a single or double quote. We should not - test whether or not it's a delimiter until after we skip single- or - double-quoted strings. */ - skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"')); - if (pass_next) - { - pass_next = 0; - if (c == 0) - CQ_RETURN(i); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (backq) - { - if (c == '`') - backq = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '`') - { - backq = 1; - i++; - continue; - } - else if (skipquote == 0 && invert == 0 && member (c, delims)) - break; - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - /* no increment, the skip functions increment past the closing quote. */ - } - else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } -#if defined (PROCESS_SUBSTITUTION) - else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si); - free (temp); /* no SX_ALLOC here */ - i = si; - if (string[i] == '\0') - break; - i++; - continue; - } -#endif /* PROCESS_SUBSTITUTION */ -#if defined (EXTENDED_GLOB) - else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@")) - { - si = i + 2; - if (string[si] == '\0') - CQ_RETURN(si); - - open[0] = c; - open[1] = LPAREN; - open[2] = '\0'; - temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */ - - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } -#endif - else if ((skipquote || invert) && (member (c, delims) == 0)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -#if defined (READLINE) -/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is - an unclosed quoted string), or if the character at EINDEX is quoted - by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various - single and double-quoted string parsing functions should not return an - error if there are unclosed quotes or braces. The characters that this - recognizes need to be the same as the contents of - rl_completer_quote_characters. */ - -int -char_is_quoted (string, eindex) - char *string; - int eindex; -{ - int i, pass_next, c; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - no_longjmp_on_fatal_error = 1; - i = pass_next = 0; - while (i <= eindex) - { - c = string[i]; - - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - CQ_RETURN(1); - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (c == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (c == '\'' || c == '"') - { - i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); - if (i > eindex) - CQ_RETURN(1); - /* no increment, the skip_xxx functions go one past end */ - } - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(0); -} - -int -unclosed_pair (string, eindex, openstr) - char *string; - int eindex; - char *openstr; -{ - int i, pass_next, openc, olen; - size_t slen; - DECLARE_MBSTATE; - - slen = strlen (string); - olen = strlen (openstr); - i = pass_next = openc = 0; - while (i <= eindex) - { - if (pass_next) - { - pass_next = 0; - if (i >= eindex) /* XXX was if (i >= eindex - 1) */ - return 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - else if (string[i] == '\\') - { - pass_next = 1; - i++; - continue; - } - else if (STREQN (string + i, openstr, olen)) - { - openc = 1 - openc; - i += olen; - } - else if (string[i] == '\'' || string[i] == '"') - { - i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); - if (i > eindex) - return 0; - } - else - ADVANCE_CHAR (string, slen, i); - } - return (openc); -} - -/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the - individual words. If DELIMS is NULL, the current value of $IFS is used - to split the string, and the function follows the shell field splitting - rules. SENTINEL is an index to look for. NWP, if non-NULL, - gets the number of words in the returned list. CWP, if non-NULL, gets - the index of the word containing SENTINEL. Non-whitespace chars in - DELIMS delimit separate fields. */ -WORD_LIST * -split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp) - char *string; - int slen; - char *delims; - int sentinel, flags; - int *nwp, *cwp; -{ - int ts, te, i, nw, cw, ifs_split, dflags; - char *token, *d, *d2; - WORD_LIST *ret, *tl; - - if (string == 0 || *string == '\0') - { - if (nwp) - *nwp = 0; - if (cwp) - *cwp = 0; - return ((WORD_LIST *)NULL); - } - - d = (delims == 0) ? ifs_value : delims; - ifs_split = delims == 0; - - /* Make d2 the non-whitespace characters in delims */ - d2 = 0; - if (delims) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - d2[ts] = '\0'; - } - - ret = (WORD_LIST *)NULL; - - /* Remove sequences of whitespace characters at the start of the string, as - long as those characters are delimiters. */ - for (i = 0; member (string[i], d) && spctabnl (string[i]); i++) - ; - if (string[i] == '\0') - return (ret); - - ts = i; - nw = 0; - cw = -1; - dflags = flags|SD_NOJMP; - while (1) - { - te = skip_to_delim (string, ts, d, dflags); - - /* If we have a non-whitespace delimiter character, use it to make a - separate field. This is just about what $IFS splitting does and - is closer to the behavior of the shell parser. */ - if (ts == te && d2 && member (string[ts], d2)) - { - te = ts + 1; - /* If we're using IFS splitting, the non-whitespace delimiter char - and any additional IFS whitespace delimits a field. */ - if (ifs_split) - while (member (string[te], d) && spctabnl (string[te])) - te++; - else - while (member (string[te], d2)) - te++; - } - - token = substring (string, ts, te); - - ret = add_string_to_list (token, ret); - free (token); - nw++; - - if (sentinel >= ts && sentinel <= te) - cw = nw; - - /* If the cursor is at whitespace just before word start, set the - sentinel word to the current word. */ - if (cwp && cw == -1 && sentinel == ts-1) - cw = nw; - - /* If the cursor is at whitespace between two words, make a new, empty - word, add it before (well, after, since the list is in reverse order) - the word we just added, and set the current word to that one. */ - if (cwp && cw == -1 && sentinel < ts) - { - tl = make_word_list (make_word (""), ret->next); - ret->next = tl; - cw = nw; - nw++; - } - - if (string[te] == 0) - break; - - i = te; - while (member (string[i], d) && (ifs_split || spctabnl(string[i]))) - i++; - - if (string[i]) - ts = i; - else - break; - } - - /* Special case for SENTINEL at the end of STRING. If we haven't found - the word containing SENTINEL yet, and the index we're looking for is at - the end of STRING (or past the end of the previously-found token, - possible if the end of the line is composed solely of IFS whitespace) - add an additional null argument and set the current word pointer to that. */ - if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te)) - { - if (whitespace (string[sentinel - 1])) - { - token = ""; - ret = add_string_to_list (token, ret); - nw++; - } - cw = nw; - } - - if (nwp) - *nwp = nw; - if (cwp) - *cwp = cw; - - FREE (d2); - - return (REVERSE_LIST (ret, WORD_LIST *)); -} -#endif /* READLINE */ - -#if 0 -/* UNUSED */ -/* Extract the name of the variable to bind to from the assignment string. */ -char * -assignment_name (string) - char *string; -{ - int offset; - char *temp; - - offset = assignment (string, 0); - if (offset == 0) - return (char *)NULL; - temp = substring (string, 0, offset); - return (temp); -} -#endif - -/* **************************************************************** */ -/* */ -/* Functions to convert strings to WORD_LISTs and vice versa */ -/* */ -/* **************************************************************** */ - -/* Return a single string of all the words in LIST. SEP is the separator - to put between individual elements of LIST in the output string. */ -char * -string_list_internal (list, sep) - WORD_LIST *list; - char *sep; -{ - register WORD_LIST *t; - char *result, *r; - int word_len, sep_len, result_size; - - if (list == 0) - return ((char *)NULL); - - /* Short-circuit quickly if we don't need to separate anything. */ - if (list->next == 0) - return (savestring (list->word->word)); - - /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */ - sep_len = STRLEN (sep); - result_size = 0; - - for (t = list; t; t = t->next) - { - if (t != list) - result_size += sep_len; - result_size += strlen (t->word->word); - } - - r = result = (char *)xmalloc (result_size + 1); - - for (t = list; t; t = t->next) - { - if (t != list && sep_len) - { - if (sep_len > 1) - { - FASTCOPY (sep, r, sep_len); - r += sep_len; - } - else - *r++ = sep[0]; - } - - word_len = strlen (t->word->word); - FASTCOPY (t->word->word, r, word_len); - r += word_len; - } - - *r = '\0'; - return (result); -} - -/* Return a single string of all the words present in LIST, separating - each word with a space. */ -char * -string_list (list) - WORD_LIST *list; -{ - return (string_list_internal (list, " ")); -} - -/* An external interface that can be used by the rest of the shell to - obtain a string containing the first character in $IFS. Handles all - the multibyte complications. If LENP is non-null, it is set to the - length of the returned string. */ -char * -ifs_firstchar (lenp) - int *lenp; -{ - char *ret; - int len; - - ret = xmalloc (MB_LEN_MAX + 1); -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc_len == 1) - { - ret[0] = ifs_firstc[0]; - ret[1] = '\0'; - len = ret[0] ? 1 : 0; - } - else - { - memcpy (ret, ifs_firstc, ifs_firstc_len); - ret[len = ifs_firstc_len] = '\0'; - } -#else - ret[0] = ifs_firstc; - ret[1] = '\0'; - len = ret[0] ? 0 : 1; -#endif - - if (lenp) - *lenp = len; - - return ret; -} - -/* Return a single string of all the words present in LIST, obeying the - quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the - expansion [of $*] appears within a double quoted string, it expands - to a single field with the value of each parameter separated by the - first character of the IFS variable, or by a if IFS is unset." */ -char * -string_list_dollar_star (list) - WORD_LIST *list; -{ - char *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - is non-zero, the $@ appears within double quotes, and we should quote - the list before converting it into a string. If IFS is unset, and the - word is not quoted, we just need to quote CTLESC and CTLNUL characters - in the words in the list, because the default value of $IFS is - , IFS characters in the words in the list should - also be split. If IFS is null, and the word is not quoted, we need - to quote the words in the list to preserve the positional parameters - exactly. */ -char * -string_list_dollar_at (list, quoted) - WORD_LIST *list; - int quoted; -{ - char *ifs, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn the positional paramters into a string, understanding quoting and - the various subtleties of using the first character of $IFS as the - separator. Calls string_list_dollar_at, string_list_dollar_star, and - string_list as appropriate. */ -char * -string_list_pos_params (pchar, list, quoted) - int pchar; - WORD_LIST *list; - int quoted; -{ - char *ret; - WORD_LIST *tlist; - - if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list_dollar_star (tlist); - } - else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list (tlist); - } - else if (pchar == '*') - { - /* Even when unquoted, string_list_dollar_star does the right thing - making sure that the first character of $IFS is used as the - separator. */ - ret = string_list_dollar_star (list); - } - else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - /* We use string_list_dollar_at, but only if the string is quoted, since - that quotes the escapes if it's not, which we don't want. We could - use string_list (the old code did), but that doesn't do the right - thing if the first character of $IFS is not a space. We use - string_list_dollar_star if the string is unquoted so we make sure that - the elements of $@ are separated by the first character of $IFS for - later splitting. */ - ret = string_list_dollar_at (list, quoted); - else if (pchar == '@') - ret = string_list_dollar_star (list); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); - - return ret; -} - -/* Return the list of words present in STRING. Separate the string into - words at any of the characters found in SEPARATORS. If QUOTED is - non-zero then word in the list will have its quoted flag set, otherwise - the quoted flag is left as make_word () deemed fit. - - This obeys the P1003.2 word splitting semantics. If `separators' is - exactly , then the splitting algorithm is that of - the Bourne shell, which treats any sequence of characters from `separators' - as a delimiter. If IFS is unset, which results in `separators' being set - to "", no splitting occurs. If separators has some other value, the - following rules are applied (`IFS white space' means zero or more - occurrences of , , or , as long as those characters - are in `separators'): - - 1) IFS white space is ignored at the start and the end of the - string. - 2) Each occurrence of a character in `separators' that is not - IFS white space, along with any adjacent occurrences of - IFS white space delimits a field. - 3) Any nonzero-length sequence of IFS white space delimits a field. - */ - -/* BEWARE! list_string strips null arguments. Don't call it twice and - expect to have "" preserved! */ - -/* This performs word splitting and quoted null character removal on - STRING. */ -#define issep(c) \ - (((separators)[0]) ? ((separators)[1] ? isifs(c) \ - : (c) == (separators)[0]) \ - : 0) - -WORD_LIST * -list_string (string, separators, quoted) - register char *string, *separators; - int quoted; -{ - WORD_LIST *result; - WORD_DESC *t; - char *current_word, *s; - int sindex, sh_style_split, whitesep, xflags; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - slen = 0; - /* Remove sequences of whitespace at the beginning of STRING, as - long as those characters appear in IFS. Do not do this if - STRING is quoted or if there are no separator characters. */ - if (!quoted || !separators || !*separators) - { - for (s = string; *s && spctabnl (*s) && issep (*s); s++); - - if (!*s) - return ((WORD_LIST *)NULL); - - string = s; - } - - /* OK, now STRING points to a word that does not begin with white space. - The splitting algorithm is: - extract a word, stopping at a separator - skip sequences of spc, tab, or nl as long as they are separators - This obeys the field splitting rules in Posix.2. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); - if (current_word == 0) - break; - - /* If we have a quoted empty string, add a quoted null argument. We - want to preserve the quoted null character iff this is a quoted - empty string; otherwise the quoted null characters are removed - below. */ - if (QUOTED_NULL (current_word)) - { - t = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - result = make_word_list (t, result); - } - else if (current_word[0] != '\0') - { - /* If we have something, then add it regardless. However, - perform quoted null character removal on the current word. */ - remove_quoted_nulls (current_word); - result = add_string_to_list (current_word, result); - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - result->word->flags |= W_QUOTED; - } - - /* If we're not doing sequences of separators in the traditional - Bourne shell style, then add a quoted null argument. */ - else if (!sh_style_split && !spctabnl (string[sindex])) - { - t = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - result = make_word_list (t, result); - } - - free (current_word); - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = string[sindex] && spctabnl (string[sindex]); - - /* Move past the current separator character. */ - if (string[sindex]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, sindex); - } - - /* Now skip sequences of space, tab, or newline characters if they are - in the list of separators. */ - while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character - is a non-whitespace IFS character, it should be part of the current - field delimiter, not a separate delimiter that would result in an - empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex])) - { - sindex++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex])) - sindex++; - } - } - return (REVERSE_LIST (result, WORD_LIST *)); -} - -/* Parse a single word from STRING, using SEPARATORS to separate fields. - ENDPTR is set to the first character after the word. This is used by - the `read' builtin. This is never called with SEPARATORS != $IFS; - it should be simplified. - - XXX - this function is very similar to list_string; they should be - combined - XXX */ -char * -get_word_from_string (stringp, separators, endptr) - char **stringp, *separators, **endptr; -{ - register char *s; - char *current_word; - int sindex, sh_style_split, whitesep, xflags; - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - s = *stringp; - slen = 0; - - /* Remove sequences of whitespace at the beginning of STRING, as - long as those characters appear in IFS. */ - if (sh_style_split || !separators || !*separators) - { - for (; *s && spctabnl (*s) && isifs (*s); s++); - - /* If the string is nothing but whitespace, update it and return. */ - if (!*s) - { - *stringp = s; - if (endptr) - *endptr = s; - return ((char *)NULL); - } - } - - /* OK, S points to a word that does not begin with white space. - Now extract a word, stopping at a separator, save a pointer to - the first character after the word, then skip sequences of spc, - tab, or nl as long as they are separators. - - This obeys the field splitting rules in Posix.2. */ - sindex = 0; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (s) : 1; - current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); - - /* Set ENDPTR to the first character after the end of the word. */ - if (endptr) - *endptr = s + sindex; - - /* Note whether or not the separator is IFS whitespace, used later. */ - whitesep = s[sindex] && spctabnl (s[sindex]); - - /* Move past the current separator character. */ - if (s[sindex]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, sindex); - } - - /* Now skip sequences of space, tab, or newline characters if they are - in the list of separators. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex])) - sindex++; - - /* If the first separator was IFS whitespace and the current character is - a non-whitespace IFS character, it should be part of the current field - delimiter, not a separate delimiter that would result in an empty field. - Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex])) - { - sindex++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex])) - sindex++; - } - - /* Update STRING to point to the next field. */ - *stringp = s + sindex; - return (current_word); -} - -/* Remove IFS white space at the end of STRING. Start at the end - of the string and walk backwards until the beginning of the string - or we find a character that's not IFS white space and not CTLESC. - Only let CTLESC escape a white space character if SAW_ESCAPE is - non-zero. */ -char * -strip_trailing_ifs_whitespace (string, separators, saw_escape) - char *string, *separators; - int saw_escape; -{ - char *s; - - s = string + STRLEN (string) - 1; - while (s > string && ((spctabnl (*s) && isifs (*s)) || - (saw_escape && *s == CTLESC && spctabnl (s[1])))) - s--; - *++s = '\0'; - return string; -} - -#if 0 -/* UNUSED */ -/* Split STRING into words at whitespace. Obeys shell-style quoting with - backslashes, single and double quotes. */ -WORD_LIST * -list_string_with_quotes (string) - char *string; -{ - WORD_LIST *list; - char *token, *s; - size_t s_len; - int c, i, tokstart, len; - - for (s = string; s && *s && spctabnl (*s); s++) - ; - if (s == 0 || *s == 0) - return ((WORD_LIST *)NULL); - - s_len = strlen (s); - tokstart = i = 0; - list = (WORD_LIST *)NULL; - while (1) - { - c = s[i]; - if (c == '\\') - { - i++; - if (s[i]) - i++; - } - else if (c == '\'') - i = skip_single_quoted (s, s_len, ++i); - else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); - else if (c == 0 || spctabnl (c)) - { - /* We have found the end of a token. Make a word out of it and - add it to the word list. */ - token = substring (s, tokstart, i); - list = add_string_to_list (token, list); - free (token); - while (spctabnl (s[i])) - i++; - if (s[i]) - tokstart = i; - else - break; - } - else - i++; /* normal character */ - } - return (REVERSE_LIST (list, WORD_LIST *)); -} -#endif - -/********************************************************/ -/* */ -/* Functions to perform assignment statements */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal, mkassoc; - WORD_LIST *list; - - mklocal = flags & ASS_MKLOCAL; - mkassoc = flags & ASS_MKASSOC; - - if (mklocal && variable_context) - { - v = find_variable (name); - list = expand_compound_array_assignment (v, value, flags); - if (mkassoc) - v = make_local_assoc_variable (name); - else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) - v = make_local_array_variable (name, 0); - assign_compound_array_list (v, list, flags); - } - else - v = assign_array_from_string (name, value, flags); - - return (v); -} -#endif - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. If EXPAND is true, then - perform parameter expansion, command substitution, and arithmetic - expansion on the right-hand side. Perform tilde expansion in any - case. Do not perform word splitting on the result of expansion. */ -static int -do_assignment_internal (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, appendop, assign_list, aflags, retval; - char *name, *value, *temp; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#if defined (ARRAY_VARS) - if (t = mbschr (name, '[')) /*]*/ - { - if (assign_list) - { - report_error (_("%s: cannot assign list to array member"), name); - ASSIGN_RETURN (0); - } - entry = assign_array_element (name, value, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) - aflags |= ASS_MKLOCAL; - if (word->flags & W_ASSIGNASSOC) - aflags |= ASS_MKASSOC; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - stupidly_hack_special_variables (name); - - /* Return 1 if the assignment seems to have been performed correctly. */ - if (entry == 0 || readonly_p (entry)) - retval = 0; /* assignment failure */ - else if (noassign_p (entry)) - { - last_command_exit_value = EXECUTION_FAILURE; - retval = 1; /* error status, but not assignment failure */ - } - else - retval = 1; - - if (entry && retval != 0 && noassign_p (entry) == 0) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (retval); -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word, flags) - WORD_DESC *word; - int flags; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 0)); -} - -/*************************************************** - * * - * Functions to manage the positional parameters * - * * - ***************************************************/ - -/* Return the word list that corresponds to `$*'. */ -WORD_LIST * -list_rest_of_args () -{ - register WORD_LIST *list, *args; - int i; - - /* Break out of the loop as soon as one of the dollar variables is null. */ - for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++) - list = make_word_list (make_bare_word (dollar_vars[i]), list); - - for (args = rest_of_args; args; args = args->next) - list = make_word_list (make_bare_word (args->word->word), list); - - return (REVERSE_LIST (list, WORD_LIST *)); -} - -int -number_of_args () -{ - register WORD_LIST *list; - int n; - - for (n = 0; n < 9 && dollar_vars[n+1]; n++) - ; - for (list = rest_of_args; list; list = list->next) - n++; - return n; -} - -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - intmax_t ind; -{ - char *temp; - WORD_LIST *p; - - if (ind < 10) - temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL; - else /* We want something like ${11} */ - { - ind -= 10; - for (p = rest_of_args; p && ind--; p = p->next) - ; - temp = p ? savestring (p->word->word) : (char *)NULL; - } - return (temp); -} - -/* Make a single large string out of the dollar digit variables, - and the rest_of_args. If DOLLAR_STAR is 1, then obey the special - case of "$*" with respect to IFS. */ -char * -string_rest_of_args (dollar_star) - int dollar_star; -{ - register WORD_LIST *list; - char *string; - - list = list_rest_of_args (); - string = dollar_star ? string_list_dollar_star (list) : string_list (list); - dispose_words (list); - return (string); -} - -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. If QUOTED includes - Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise - no quoting chars are added. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - /* see if we can short-circuit. if start == end, we want 0 parameters. */ - if (start == end) - return ((char *)NULL); - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - for (i = start ? 1 : 0; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - - ret = string_list_pos_params (string[0], h, quoted); - - if (t != params) - t->next = params; - - dispose_words (save); - return (ret); -} - -/******************************************************************/ -/* */ -/* Functions to expand strings to strings or WORD_LISTs */ -/* */ -/******************************************************************/ - -#if defined (PROCESS_SUBSTITUTION) -#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#endif - -/* If there are any characters in STRING that require full expansion, - then call FUNC to expand STRING; otherwise just perform quote - removal if necessary. This returns a new string. */ -static char * -expand_string_if_necessary (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - size_t slen; - int i, saw_quote; - char *ret; - DECLARE_MBSTATE; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - i = saw_quote = 0; - while (string[i]) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - ADVANCE_CHAR (string, slen, i); - } - - if (string[i]) - { - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - } - else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - ret = string_quote_removal (string, quoted); - else - ret = savestring (string); - - return ret; -} - -static inline char * -expand_string_to_string_internal (string, quoted, func) - char *string; - int quoted; - EXPFUNC *func; -{ - WORD_LIST *list; - char *ret; - - if (string == 0 || *string == '\0') - return ((char *)NULL); - - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - - return (ret); -} - -char * -expand_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string)); -} - -char * -expand_string_unsplit_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_if_necessary (string, quoted, expand_string)); -} - -#if defined (COND_COMMAND) -/* Just remove backslashes in STRING. Returns a new string. */ -char * -remove_backslashes (string) - char *string; -{ - char *r, *ret, *s; - - r = ret = (char *)xmalloc (strlen (string) + 1); - for (s = string; s && *s; ) - { - if (*s == '\\') - s++; - if (*s == 0) - break; - *r++ = *s++; - } - *r = '\0'; - return ret; -} - -/* This needs better error handling. */ -/* Expand W for use as an argument to a unary or binary operator in a - [[...]] expression. If SPECIAL is 1, this is the rhs argument - to the != or == operator, and should be treated as a pattern. In - this case, we quote the string specially for the globbing code. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - w->flags |= W_NOSPLIT2; - l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0); - if (l) - { - if (special == 0) - { - dequote_list (l); - r = string_list (l); - } - else - { - qflags = QGLOB_CVTNULL; - if (special == 2) - qflags |= QGLOB_REGEXP; - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - free (p); - } - dispose_words (l); - } - else - r = (char *)NULL; - - return r; -} -#endif - -/* Call expand_word_internal to expand W and handle error returns. - A convenience function for functions that don't want to handle - any errors or free any memory before aborting. */ -static WORD_LIST * -call_expand_word_internal (w, q, i, c, e) - WORD_DESC *w; - int q, i, *c, *e; -{ - WORD_LIST *result; - - result = expand_word_internal (w, q, i, c, e); - if (result == &expand_word_error || result == &expand_word_fatal) - { - /* By convention, each time this error is returned, w->word has - already been freed (it sometimes may not be in the fatal case, - but that doesn't result in a memory leak because we're going - to exit in most cases). */ - w->word = (char *)NULL; - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF); - /* NOTREACHED */ - } - else - return (result); -} - -/* Perform parameter expansion, command substitution, and arithmetic - expansion on STRING, as if it were a word. Leave the result quoted. - Since this does not perform word splitting, it leaves quoted nulls - in the result. */ -static WORD_LIST * -expand_string_internal (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *tresult; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = 0; - td.word = savestring (string); - - tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - - FREE (td.word); - return (tresult); -} - -/* Expand STRING by performing parameter expansion, command substitution, - and arithmetic expansion. Dequote the resulting WORD_LIST before - returning it, but do not perform word splitting. The call to - remove_quoted_nulls () is in here because word splitting normally - takes care of quote removal. */ -WORD_LIST * -expand_string_unsplit (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - value = expand_string_internal (string, quoted); - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - - td.flags = W_ASSIGNRHS; - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - - -/* Expand one of the PS? prompt strings. This is a sort of combination of - expand_string_unsplit and expand_string_internal, but returns the - passed string when an error occurs. Might want to trap other calls - to jump_to_top_level here so we don't endlessly loop. */ -WORD_LIST * -expand_prompt_string (string, quoted, wflags) - char *string; - int quoted; - int wflags; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = wflags; - td.word = savestring (string); - - no_longjmp_on_fatal_error = 1; - value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - no_longjmp_on_fatal_error = 0; - - if (value == &expand_word_error || value == &expand_word_fatal) - { - value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL); - return value; - } - FREE (td.word); - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand STRING just as if you were expanding a word, but do not dequote - the resultant WORD_LIST. This is called only from within this file, - and is used to correctly preserve quoted characters when expanding - things like ${1+"$@"}. This does parameter expansion, command - substitution, arithmetic expansion, and word splitting. */ -static WORD_LIST * -expand_string_leave_quoted (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *tlist; - WORD_LIST *tresult; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - tlist = expand_string_internal (string, quoted); - - if (tlist) - { - tresult = word_list_split (tlist); - dispose_words (tlist); - return (tresult); - } - return ((WORD_LIST *)NULL); -} - -/* This does not perform word splitting or dequote the WORD_LIST - it returns. */ -static WORD_LIST * -expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at) - char *string; - int quoted, *dollar_at_p, *has_dollar_at; -{ - WORD_DESC td; - WORD_LIST *tresult; - - if (string == 0 || *string == '\0') - return (WORD_LIST *)NULL; - - td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ - td.word = string; - tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); - return (tresult); -} - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - does parameter expansion, command substitution, arithmetic expansion, - and word splitting. Dequote the resultant WORD_LIST before returning. */ -WORD_LIST * -expand_string (string, quoted) - char *string; - int quoted; -{ - WORD_LIST *result; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - result = expand_string_leave_quoted (string, quoted); - return (result ? dequote_list (result) : result); -} - -/*************************************************** - * * - * Functions to handle quoting chars * - * * - ***************************************************/ - -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* Quote escape characters in string s, but no other characters. This is - used to protect CTLESC and CTLNUL in variable values from the rest of - the word expansion process after the variable is expanded (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - int quote_spaces, skip_ctlesc, skip_ctlnul; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) - *t++ = CTLESC; - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return (result); -} - -static WORD_LIST * -list_quote_escapes (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_escapes (t); - free (t); - } - return list; -} - -/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL. - - The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. - This is necessary to make unquoted CTLESC and CTLNUL characters in the - data stream pass through properly. - - We need to remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. - - Also used by parts of the pattern substitution code. */ -char * -dequote_escapes (string) - char *string; -{ - register char *s, *t, *s1; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return result; -} - -/* Return a new string with the quoted representation of character C. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -static char * -make_quoted_char (c) - int c; -{ - char *temp; - - temp = (char *)xmalloc (3); - if (c == 0) - { - temp[0] = CTLNUL; - temp[1] = '\0'; - } - else - { - temp[0] = CTLESC; - temp[1] = c; - temp[2] = '\0'; - } - return (temp); -} - -/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -char * -quote_string (string) - char *string; -{ - register char *t; - size_t slen; - char *result, *send; - - if (*string == 0) - { - result = (char *)xmalloc (2); - result[0] = CTLNUL; - result[1] = '\0'; - } - else - { - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - result = (char *)xmalloc ((slen * 2) + 1); - - for (t = result; string < send; ) - { - *t++ = CTLESC; - COPY_CHAR_P (t, string, send); - } - *t = '\0'; - } - return (result); -} - -/* De-quote quoted characters in STRING. */ -char * -dequote_string (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - - t = result = (char *)xmalloc (slen + 1); - - if (QUOTED_NULL (string)) - { - result[0] = '\0'; - return (result); - } - - /* If no character in the string can be quoted, don't bother examining - each character. Just return a copy of the string passed to us. */ - if (strchr (string, CTLESC) == NULL) - return (strcpy (result, string)); - - send = string + slen; - s = string; - while (*s) - { - if (*s == CTLESC) - { - s++; - if (*s == '\0') - break; - } - COPY_CHAR_P (t, s, send); - } - - *t = '\0'; - return (result); -} - -/* Quote the entire WORD_LIST list. */ -static WORD_LIST * -quote_list (list) - WORD_LIST *list; -{ - register WORD_LIST *w; - char *t; - - for (w = list; w; w = w->next) - { - t = w->word->word; - w->word->word = quote_string (t); - if (*t == 0) - w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ - w->word->flags |= W_QUOTED; - free (t); - } - return list; -} - -/* De-quote quoted characters in each word in LIST. */ -WORD_LIST * -dequote_list (list) - WORD_LIST *list; -{ - register char *s; - register WORD_LIST *tlist; - - for (tlist = list; tlist; tlist = tlist->next) - { - s = dequote_string (tlist->word->word); - if (QUOTED_NULL (tlist->word->word)) - tlist->word->flags &= ~W_HASQUOTEDNULL; - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -char * -remove_quoted_escapes (string) - char *string; -{ - char *t; - - if (string) - { - t = dequote_escapes (string); - strcpy (string, t); - free (t); - } - - return (string); -} - -/* Perform quoted null character removal on STRING. We don't allow any - quoted null characters in the middle or at the ends of strings because - of how expand_word_internal works. remove_quoted_nulls () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ -char * -remove_quoted_nulls (string) - char *string; -{ - register size_t slen; - register int i, j, prev_i; - DECLARE_MBSTATE; - - if (strchr (string, CTLNUL) == 0) /* XXX */ - return string; /* XXX */ - - slen = strlen (string); - i = j = 0; - - while (i < slen) - { - if (string[i] == CTLESC) - { - /* Old code had j++, but we cannot assume that i == j at this - point -- what if a CTLNUL has already been removed from the - string? We don't want to drop the CTLESC or recopy characters - that we've already copied down. */ - i++; string[j++] = CTLESC; - if (i == slen) - break; - } - else if (string[i] == CTLNUL) - { - i++; - continue; - } - - prev_i = i; - ADVANCE_CHAR (string, slen, i); - if (j < prev_i) - { - do string[j++] = string[prev_i++]; while (prev_i < i); - } - else - j = i; - } - string[j] = '\0'; - - return (string); -} - -/* Perform quoted null character removal on each element of LIST. - This modifies LIST. */ -void -word_list_remove_quoted_nulls (list) - WORD_LIST *list; -{ - register WORD_LIST *t; - - for (t = list; t; t = t->next) - { - remove_quoted_nulls (t->word->word); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* Functions for Matching and Removing Patterns */ -/* */ -/* **************************************************************** */ - -#if defined (HANDLE_MULTIBYTE) -#if 0 /* Currently unused */ -static unsigned char * -mb_getcharlens (string, len) - char *string; - int len; -{ - int i, offset, last; - unsigned char *ret; - char *p; - DECLARE_MBSTATE; - - i = offset = 0; - last = 0; - ret = (unsigned char *)xmalloc (len); - memset (ret, 0, len); - while (string[last]) - { - ADVANCE_CHAR (string, len, offset); - ret[last] = offset - last; - last = offset; - } - return ret; -} -#endif -#endif - -/* Remove the portion of PARAM matched by PATTERN according to OP, where OP - can have one of 4 values: - RP_LONG_LEFT remove longest matching portion at start of PARAM - RP_SHORT_LEFT remove shortest matching portion at start of PARAM - RP_LONG_RIGHT remove longest matching portion at end of PARAM - RP_SHORT_RIGHT remove shortest matching portion at end of PARAM -*/ - -#define RP_LONG_LEFT 1 -#define RP_SHORT_LEFT 2 -#define RP_LONG_RIGHT 3 -#define RP_SHORT_RIGHT 4 - -/* Returns its first argument if nothing matched; new memory otherwise */ -static char * -remove_upattern (param, pattern, op) - char *param, *pattern; - int op; -{ - register int len; - register char *end; - register char *p, *ret, c; - - len = STRLEN (param); - end = param + len; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (p = end; p >= param; p--) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (p = param; p <= end; p++) - { - c = *p; *p = '\0'; - if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - *p = c; - return (savestring (p)); - } - *p = c; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (p = param; p <= end; p++) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (p = end; p >= param; p--) - { - if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - c = *p; *p = '\0'; - ret = savestring (param); - *p = c; - return (ret); - } - } - break; - } - - return (param); /* no match, return original string */ -} - -#if defined (HANDLE_MULTIBYTE) -/* Returns its first argument if nothing matched; new memory otherwise */ -static wchar_t * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - switch (op) - { - case RP_LONG_LEFT: /* remove longest match at start */ - for (n = wstrlen; n >= 0; n--) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_SHORT_LEFT: /* remove shortest match at start */ - for (n = 0; n <= wstrlen; n++) - { - wc = wparam[n]; wparam[n] = L'\0'; - if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wparam[n] = wc; - return (wcsdup (wparam + n)); - } - wparam[n] = wc; - } - break; - - case RP_LONG_RIGHT: /* remove longest match at end */ - for (n = 0; n <= wstrlen; n++) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - - case RP_SHORT_RIGHT: /* remove shortest match at end */ - for (n = wstrlen; n >= 0; n--) - { - if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH) - { - wc = wparam[n]; wparam[n] = L'\0'; - ret = wcsdup (wparam); - wparam[n] = wc; - return (ret); - } - } - break; - } - - return (wparam); /* no match, return original string */ -} -#endif /* HANDLE_MULTIBYTE */ - -static char * -remove_pattern (param, pattern, op) - char *param, *pattern; - int op; -{ - char *xret; - - if (param == NULL) - return (param); - if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */ - return (savestring (param)); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - wchar_t *ret, *oret; - size_t n; - wchar_t *wparam, *wpattern; - mbstate_t ps; - - n = xdupmbstowcs (&wpattern, NULL, pattern); - if (n == (size_t)-1) - { - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } - n = xdupmbstowcs (&wparam, NULL, param); - if (n == (size_t)-1) - { - free (wpattern); - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } - oret = ret = remove_wpattern (wparam, n, wpattern, op); - /* Don't bother to convert wparam back to multibyte string if nothing - matched; just return copy of original string */ - if (ret == wparam) - { - free (wparam); - free (wpattern); - return (savestring (param)); - } - - free (wparam); - free (wpattern); - - n = strlen (param); - xret = (char *)xmalloc (n + 1); - memset (&ps, '\0', sizeof (mbstate_t)); - n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); - xret[n] = '\0'; /* just to make sure */ - free (oret); - return xret; - } - else -#endif - { - xret = remove_upattern (param, pattern, op); - return ((xret == param) ? savestring (param) : xret); - } -} - -/* Match PAT anywhere in STRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. SP - and EP are pointers into the string where the match begins and - ends, respectively. MTYPE controls what kind of match is attempted. - MATCH_BEG and MATCH_END anchor the match at the beginning and end - of the string, respectively. The longest match is returned. */ -static int -match_upattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ - int c, len, mlen; - register char *p, *p1, *npat; - char *end; - int n1; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*') - { - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)) - *p++ = '*'; - while (*p1) - *p++ = *p1++; - if (p1[-1] != '*' || p[-2] == '\\') - *p++ = '*'; - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - len = STRLEN (string); - end = string + len; - - mlen = umatchlen (pat, len); - - switch (mtype) - { - case MATCH_ANY: - for (p = string; p <= end; p++) - { - if (match_pattern_char (pat, p)) - { -#if 0 - for (p1 = end; p1 >= p; p1--) -#else - p1 = (mlen == -1) ? end : p + mlen; - /* p1 - p = length of portion of string to be considered - p = current position in string - mlen = number of characters consumed by match (-1 for entire string) - end = end of string - we want to break immediately if the potential match len - is greater than the number of characters remaining in the - string - */ - if (p1 > end) - break; - for ( ; p1 >= p; p1--) -#endif - { - c = *p1; *p1 = '\0'; - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *p1 = c; - *sp = p; - *ep = p1; - return 1; - } - *p1 = c; -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_char (pat, string) == 0) - return (0); - -#if 0 - for (p = end; p >= string; p--) -#else - for (p = (mlen == -1) ? end : string + mlen; p >= string; p--) -#endif - { - c = *p; *p = '\0'; - if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0) - { - *p = c; - *sp = string; - *ep = p; - return 1; - } - *p = c; -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - - return (0); - - case MATCH_END: -#if 0 - for (p = string; p <= end; p++) -#else - for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++) -#endif - { - if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0) - { - *sp = p; - *ep = end; - return 1; - } -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - - return (0); - } - - return (0); -} - -#if defined (HANDLE_MULTIBYTE) -/* Match WPAT anywhere in WSTRING and return the match boundaries. - This returns 1 in case of a successful match, 0 otherwise. Wide - character version. */ -static int -match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) - wchar_t *wstring; - char **indices; - size_t wstrlen; - wchar_t *wpat; - int mtype; - char **sp, **ep; -{ - wchar_t wc, *wp, *nwpat, *wp1; - size_t len; - int mlen; - int n, n1, n2, simple; - - simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); -#if defined (EXTENDED_GLOB) - if (extended_glob) - simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - len = wcslen (wpat); - if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*') - { - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob)) - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - mlen = wmatchlen (wpat, wstrlen); - -/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */ - switch (mtype) - { - case MATCH_ANY: - for (n = 0; n <= wstrlen; n++) - { -#if 1 - n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n); -#else - n2 = match_pattern_wchar (wpat, wstring + n); -#endif - if (n2) - { -#if 0 - for (n1 = wstrlen; n1 >= n; n1--) -#else - n1 = (mlen == -1) ? wstrlen : n + mlen; - if (n1 > wstrlen) - break; - - for ( ; n1 >= n; n1--) -#endif - { - wc = wstring[n1]; wstring[n1] = L'\0'; - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - wstring[n1] = wc; - *sp = indices[n]; - *ep = indices[n1]; - return 1; - } - wstring[n1] = wc; -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - } - } - - return (0); - - case MATCH_BEG: - if (match_pattern_wchar (wpat, wstring) == 0) - return (0); - -#if 0 - for (n = wstrlen; n >= 0; n--) -#else - for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--) -#endif - { - wc = wstring[n]; wstring[n] = L'\0'; - if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0) - { - wstring[n] = wc; - *sp = indices[0]; - *ep = indices[n]; - return 1; - } - wstring[n] = wc; -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - - return (0); - - case MATCH_END: -#if 0 - for (n = 0; n <= wstrlen; n++) -#else - for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++) -#endif - { - if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0) - { - *sp = indices[n]; - *ep = indices[wstrlen]; - return 1; - } -#if 1 - /* If MLEN != -1, we have a fixed length pattern. */ - if (mlen != -1) - break; -#endif - } - - return (0); - } - - return (0); -} -#endif /* HANDLE_MULTIBYTE */ - -static int -match_pattern (string, pat, mtype, sp, ep) - char *string, *pat; - int mtype; - char **sp, **ep; -{ -#if defined (HANDLE_MULTIBYTE) - int ret; - size_t n; - wchar_t *wstring, *wpat; - char **indices; - size_t slen, plen, mslen, mplen; -#endif - - if (string == 0 || *string == 0 || pat == 0 || *pat == 0) - return (0); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { -#if 0 - slen = STRLEN (string); - mslen = MBSLEN (string); - plen = STRLEN (pat); - mplen = MBSLEN (pat); - if (slen == mslen && plen == mplen) -#else - if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0) -#endif - return (match_upattern (string, pat, mtype, sp, ep)); - - n = xdupmbstowcs (&wpat, NULL, pat); - if (n == (size_t)-1) - return (match_upattern (string, pat, mtype, sp, ep)); - n = xdupmbstowcs (&wstring, &indices, string); - if (n == (size_t)-1) - { - free (wpat); - return (match_upattern (string, pat, mtype, sp, ep)); - } - ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep); - - free (wpat); - free (wstring); - free (indices); - - return (ret); - } - else -#endif - return (match_upattern (string, pat, mtype, sp, ep)); -} - -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for strmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; -#if 0 - int i; -#endif - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? - POSIX.2 says that enclosing double quotes do not cause the pattern to - be quoted, but does that leave us a problem with @ and array[@] and their - expansions inside a pattern? */ -#if 0 - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } -#endif - - /* expand_string_for_rhs () leaves WORD quoted and does not perform - word splitting. */ - l = *value ? expand_string_for_rhs (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); - free (pat); - pat = tword; - } - return (pat); -} - -#if 0 -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -variable_remove_pattern (value, pattern, patspec, quoted) - char *value, *pattern; - int patspec, quoted; -{ - char *tword; - - tword = remove_pattern (value, pattern, patspec); - - return (tword); -} -#endif - -static char * -list_remove_pattern (list, pattern, patspec, itype, quoted) - WORD_LIST *list; - char *pattern; - int patspec, itype, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - tword = string_list_pos_params (itype, l, quoted); - dispose_words (l); - - return (tword); -} - -static char * -parameter_list_remove_pattern (itype, pattern, patspec, quoted) - int itype; - char *pattern; - int patspec, quoted; -{ - char *ret; - WORD_LIST *list; - - list = list_rest_of_args (); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - return (ret); -} - -#if defined (ARRAY_VARS) -static char * -array_remove_pattern (var, pattern, patspec, varname, quoted) - SHELL_VAR *var; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - ARRAY *a; - HASH_TABLE *h; - int itype; - char *ret; - WORD_LIST *list; - SHELL_VAR *v; - - /* compute itype from varname here */ - v = array_variable_part (varname, &ret, 0); - itype = ret[0]; - - a = (v && array_p (v)) ? array_cell (v) : 0; - h = (v && assoc_p (v)) ? assoc_cell (v) : 0; - - list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); - if (list == 0) - return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); - dispose_words (list); - - return ret; -} -#endif /* ARRAY_VARS */ - -static char * -parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags) - char *varname, *value; - int ind; - char *patstr; - int rtype, quoted, flags; -{ - int vtype, patspec, starsub; - char *temp1, *val, *pattern; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - patspec = getpatspec (rtype, patstr); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - patstr++; - - /* Need to pass getpattern newly-allocated memory in case of expansion -- - the expansion code will free the passed string on an error. */ - temp1 = savestring (patstr); - pattern = getpattern (temp1, quoted, 1); - free (temp1); - - temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp1 = remove_pattern (val, pattern, patspec); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp1) - { - val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#endif - case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); - if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) - { - val = quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; - } - - FREE (pattern); - return temp1; -} - -/******************************************* - * * - * Functions to expand WORD_DESCs * - * * - *******************************************/ - -/* Expand WORD, performing word splitting on the result. This does - parameter expansion, command substitution, arithmetic expansion, - word splitting, and quote removal. */ - -WORD_LIST * -expand_word (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result, *tresult; - - tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - result = word_list_split (tresult); - dispose_words (tresult); - return (result ? dequote_list (result) : result); -} - -/* Expand WORD, but do not perform word splitting on the result. This - does parameter expansion, command substitution, arithmetic expansion, - and quote removal. */ -WORD_LIST * -expand_word_unsplit (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc[0] == 0) -#else - if (ifs_firstc == 0) -#endif - word->flags |= W_NOSPLIT; - word->flags |= W_NOSPLIT2; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return (result ? dequote_list (result) : result); -} - -/* Perform shell expansions on WORD, but do not perform word splitting or - quote removal on the result. Virtually identical to expand_word_unsplit; - could be combined if implementations don't diverge. */ -WORD_LIST * -expand_word_leave_quoted (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_LIST *result; - - expand_no_split_dollar_star = 1; -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc[0] == 0) -#else - if (ifs_firstc == 0) -#endif - word->flags |= W_NOSPLIT; - word->flags |= W_NOSPLIT2; - result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); - expand_no_split_dollar_star = 0; - - return result; -} - -#if defined (PROCESS_SUBSTITUTION) - -/*****************************************************************/ -/* */ -/* Hacking Process Substitution */ -/* */ -/*****************************************************************/ - -#if !defined (HAVE_DEV_FD) -/* Named pipes must be removed explicitly with `unlink'. This keeps a list - of FIFOs the shell has open. unlink_fifo_list will walk the list and - unlink all of them. add_fifo_list adds the name of an open FIFO to the - list. NFIFO is a count of the number of FIFOs in the list. */ -#define FIFO_INCR 20 - -struct temp_fifo { - char *file; - pid_t proc; -}; - -static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL; -static int nfifo; -static int fifo_list_size; - -char * -copy_fifo_list (sizep) - int *sizep; -{ - if (sizep) - *sizep = 0; - return (char *)NULL; -} - -static void -add_fifo_list (pathname) - char *pathname; -{ - if (nfifo >= fifo_list_size - 1) - { - fifo_list_size += FIFO_INCR; - fifo_list = (struct temp_fifo *)xrealloc (fifo_list, - fifo_list_size * sizeof (struct temp_fifo)); - } - - fifo_list[nfifo].file = savestring (pathname); - nfifo++; -} - -void -unlink_fifo (i) - int i; -{ - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } -} - -void -unlink_fifo_list () -{ - int saved, i, j; - - if (nfifo == 0) - return; - - for (i = saved = 0; i < nfifo; i++) - { - if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1)) - { - unlink (fifo_list[i].file); - free (fifo_list[i].file); - fifo_list[i].file = (char *)NULL; - fifo_list[i].proc = -1; - } - else - saved++; - } - - /* If we didn't remove some of the FIFOs, compact the list. */ - if (saved) - { - for (i = j = 0; i < nfifo; i++) - if (fifo_list[i].file) - { - fifo_list[j].file = fifo_list[i].file; - fifo_list[j].proc = fifo_list[i].proc; - j++; - } - nfifo = j; - } - else - nfifo = 0; -} - -/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list - from some point in the past, and close all open FIFOs in fifo_list - that are not marked as active in LIST. If LIST is NULL, close - everything in fifo_list. LSIZE is the number of elements in LIST, in - case it's larger than fifo_list_size (size of fifo_list). */ -void -close_new_fifos (list, lsize) - char *list; - int lsize; -{ - int i; - - if (list == 0) - { - unlink_fifo_list (); - return; - } - - for (i = 0; i < lsize; i++) - if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1) - unlink_fifo (i); - - for (i = lsize; i < fifo_list_size; i++) - unlink_fifo (i); -} - -int -fifos_pending () -{ - return nfifo; -} - -int -num_fifos () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - if (mkfifo (tname, 0600) < 0) - { - free (tname); - return ((char *)NULL); - } - - add_fifo_list (tname); - return (tname); -} - -#else /* HAVE_DEV_FD */ - -/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell - has open to children. NFDS is a count of the number of bits currently - set in DEV_FD_LIST. TOTFDS is a count of the highest possible number - of open files. */ -static char *dev_fd_list = (char *)NULL; -static int nfds; -static int totfds; /* The highest possible number of open files. */ - -char * -copy_fifo_list (sizep) - int *sizep; -{ - char *ret; - - if (nfds == 0 || totfds == 0) - { - if (sizep) - *sizep = 0; - return (char *)NULL; - } - - if (sizep) - *sizep = totfds; - ret = (char *)xmalloc (totfds); - return (memcpy (ret, dev_fd_list, totfds)); -} - -static void -add_fifo_list (fd) - int fd; -{ - if (dev_fd_list == 0 || fd >= totfds) - { - int ofds; - - ofds = totfds; - totfds = getdtablesize (); - if (totfds < 0 || totfds > 256) - totfds = 256; - if (fd >= totfds) - totfds = fd + 2; - - dev_fd_list = (char *)xrealloc (dev_fd_list, totfds); - memset (dev_fd_list + ofds, '\0', totfds - ofds); - } - - dev_fd_list[fd] = 1; - nfds++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -int -num_fifos () -{ - return nfds; -} - -void -unlink_fifo (fd) - int fd; -{ - if (dev_fd_list[fd]) - { - close (fd); - dev_fd_list[fd] = 0; - nfds--; - } -} - -void -unlink_fifo_list () -{ - register int i; - - if (nfds == 0) - return; - - for (i = 0; nfds && i < totfds; i++) - unlink_fifo (i); - - nfds = 0; -} - -/* Take LIST, which is a snapshot copy of dev_fd_list from some point in - the past, and close all open fds in dev_fd_list that are not marked - as open in LIST. If LIST is NULL, close everything in dev_fd_list. - LSIZE is the number of elements in LIST, in case it's larger than - totfds (size of dev_fd_list). */ -void -close_new_fifos (list, lsize) - char *list; - int lsize; -{ - int i; - - if (list == 0) - { - unlink_fifo_list (); - return; - } - - for (i = 0; i < lsize; i++) - if (list[i] == 0 && i < totfds && dev_fd_list[i]) - unlink_fifo (i); - - for (i = lsize; i < totfds; i++) - unlink_fifo (i); -} - -#if defined (NOTDEF) -print_dev_fd_list () -{ - register int i; - - fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ()); - fflush (stderr); - - for (i = 0; i < totfds; i++) - { - if (dev_fd_list[i]) - fprintf (stderr, " %d", i); - } - fprintf (stderr, "\n"); -} -#endif /* NOTDEF */ - -static char * -make_dev_fd_filename (fd) - int fd; -{ - char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p; - - ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8); - - strcpy (ret, DEV_FD_PREFIX); - p = inttostr (fd, intbuf, sizeof (intbuf)); - strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p); - - add_fifo_list (fd); - return (ret); -} - -#endif /* HAVE_DEV_FD */ - -/* Return a filename that will open a connection to the process defined by - executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return - a filename in /dev/fd corresponding to a descriptor that is one of the - ends of the pipe. If not defined, we use named pipes on systems that have - them. Systems without /dev/fd and named pipes are out of luck. - - OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or - use the read end of the pipe and dup that file descriptor to fd 0 in - the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for - writing or use the write end of the pipe in the child, and dup that - file descriptor to fd 1 in the child. The parent does the opposite. */ - -static char * -process_substitute (string, open_for_read_in_child) - char *string; - int open_for_read_in_child; -{ - char *pathname; - int fd, result; - pid_t old_pid, pid; -#if defined (HAVE_DEV_FD) - int parent_pipe_fd, child_pipe_fd; - int fildes[2]; -#endif /* HAVE_DEV_FD */ -#if defined (JOB_CONTROL) - pid_t old_pipeline_pgrp; -#endif - - if (!string || !*string || wordexp_only) - return ((char *)NULL); - -#if !defined (HAVE_DEV_FD) - pathname = make_named_pipe (); -#else /* HAVE_DEV_FD */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of - the pipe in the parent, otherwise the read end. */ - parent_pipe_fd = fildes[open_for_read_in_child]; - child_pipe_fd = fildes[1 - open_for_read_in_child]; - /* Move the parent end of the pipe to some high file descriptor, to - avoid clashes with FDs used by the script. */ - parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64); - - pathname = make_dev_fd_filename (parent_pipe_fd); -#endif /* HAVE_DEV_FD */ - - if (pathname == 0) - { - sys_error (_("cannot make pipe for process substitution")); - return ((char *)NULL); - } - - old_pid = last_made_pid; - -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - pipeline_pgrp = shell_pgrp; - save_pipeline (1); -#endif /* JOB_CONTROL */ - - pid = make_child ((char *)NULL, 1); - if (pid == 0) - { - reset_terminating_signals (); /* XXX */ - free_pushed_string_input (); - /* Cancel traps, in trap.c. */ - restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */ - setup_async_signals (); - subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - /* XXX - should we only do this in the parent? (as in command subst) */ - pipeline_pgrp = old_pipeline_pgrp; -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for process substitution")); - free (pathname); -#if defined (HAVE_DEV_FD) - close (parent_pipe_fd); - close (child_pipe_fd); -#endif /* HAVE_DEV_FD */ - return ((char *)NULL); - } - - if (pid > 0) - { -#if defined (JOB_CONTROL) - restore_pipeline (1); -#endif - -#if !defined (HAVE_DEV_FD) - fifo_list[nfifo-1].proc = pid; -#endif - - last_made_pid = old_pid; - -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - -#if defined (HAVE_DEV_FD) - close (child_pipe_fd); -#endif /* HAVE_DEV_FD */ - - return (pathname); - } - - set_sigint_handler (); - -#if defined (JOB_CONTROL) - set_job_control (0); -#endif /* JOB_CONTROL */ - -#if !defined (HAVE_DEV_FD) - /* Open the named pipe in the child. */ - fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY); - if (fd < 0) - { - /* Two separate strings for ease of translation. */ - if (open_for_read_in_child) - sys_error (_("cannot open named pipe %s for reading"), pathname); - else - sys_error (_("cannot open named pipe %s for writing"), pathname); - - exit (127); - } - if (open_for_read_in_child) - { - if (sh_unset_nodelay_mode (fd) < 0) - { - sys_error (_("cannot reset nodelay mode for fd %d"), fd); - exit (127); - } - } -#else /* HAVE_DEV_FD */ - fd = child_pipe_fd; -#endif /* HAVE_DEV_FD */ - - if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0) - { - sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname, - open_for_read_in_child ? 0 : 1); - exit (127); - } - - if (fd != (open_for_read_in_child ? 0 : 1)) - close (fd); - - /* Need to close any files that this process has open to pipes inherited - from its parent. */ - if (current_fds_to_close) - { - close_fd_bitmap (current_fds_to_close); - current_fds_to_close = (struct fd_bitmap *)NULL; - } - -#if defined (HAVE_DEV_FD) - /* Make sure we close the parent's end of the pipe and clear the slot - in the fd list so it is not closed later, if reallocated by, for - instance, pipe(2). */ - close (parent_pipe_fd); - dev_fd_list[parent_pipe_fd] = 0; -#endif /* HAVE_DEV_FD */ - - result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); - -#if !defined (HAVE_DEV_FD) - /* Make sure we close the named pipe in the child before we exit. */ - close (open_for_read_in_child ? 0 : 1); -#endif /* !HAVE_DEV_FD */ - - exit (result); - /*NOTREACHED*/ -} -#endif /* PROCESS_SUBSTITUTION */ - -/***********************************/ -/* */ -/* Command Substitution */ -/* */ -/***********************************/ - -static char * -read_comsub (fd, quoted, rflag) - int fd, quoted; - int *rflag; -{ - char *istring, buf[128], *bufp, *s; - int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 0; - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - - /* Read the output of the command through the pipe. This may need to be - changed to understand multibyte characters in the future. */ - while (1) - { - if (fd < 0) - break; - if (--bufn <= 0) - { - bufn = zread (fd, buf, sizeof (buf)); - if (bufn <= 0) - break; - bufp = buf; - } - c = *bufp++; - - if (c == 0) - { -#if 0 - internal_warning ("read_comsub: ignored null byte in input"); -#endif - continue; - } - - /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (skip_ctlesc == 0 && c == CTLESC) - { - tflag |= W_HASCTLESC; - istring[istring_index++] = CTLESC; - } - else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) - istring[istring_index++] = CTLESC; - - istring[istring_index++] = c; - -#if 0 -#if defined (__CYGWIN__) - if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r') - { - istring_index--; - istring[istring_index - 1] = '\n'; - } -#endif -#endif - } - - if (istring) - istring[istring_index] = '\0'; - - /* If we read no output, just return now and save ourselves some - trouble. */ - if (istring_index == 0) - { - FREE (istring); - if (rflag) - *rflag = tflag; - return (char *)NULL; - } - - /* Strip trailing newlines from the output of the command. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - { - while (istring_index > 0) - { - if (istring[istring_index - 1] == '\n') - { - --istring_index; - - /* If the newline was quoted, remove the quoting char. */ - if (istring[istring_index - 1] == CTLESC) - --istring_index; - } - else - break; - } - istring[istring_index] = '\0'; - } - else - strip_trailing (istring, istring_index - 1, 1); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring; - int result, fildes[2], function_value, pflags, rc, tflag; - WORD_DESC *ret; - - istring = (char *)NULL; - - /* Don't fork () if there is no need to. In the case of no command to - run, just return NULL. */ - if (!string || !*string || (string[0] == '\n' && !string[1])) - return ((WORD_DESC *)NULL); - - if (wordexp_only && read_but_dont_execute) - { - last_command_exit_value = EX_WEXPCOMSUB; - jump_to_top_level (EXITPROG); - } - - /* We're making the assumption here that the command substitution will - eventually run a command from the file system. Since we'll run - maybe_make_export_env in this subshell before executing that command, - the parent shell and any other shells it starts will have to remake - the environment. If we make it before we fork, other shells won't - have to. Don't bother if we have any temporary variable assignments, - though, because the export environment will be remade after this - command completes anyway, but do it if all the words to be expanded - are variable assignments. */ - if (subst_assign_varlist == 0 || garglist == 0) - maybe_make_export_env (); /* XXX */ - - /* Flags to pass to parse_and_execute() */ - pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0; - - /* Pipe the output of executing STRING into the current shell. */ - if (pipe (fildes) < 0) - { - sys_error (_("cannot make pipe for command substitution")); - goto error_exit; - } - - old_pid = last_made_pid; -#if defined (JOB_CONTROL) - old_pipeline_pgrp = pipeline_pgrp; - /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */ - if ((subshell_environment & SUBSHELL_PIPE) == 0) - pipeline_pgrp = shell_pgrp; - cleanup_the_pipeline (); -#endif /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC); - last_asynchronous_pid = old_async_pid; - - if (pid == 0) - { - /* Reset the signal handlers in the child, but don't free the - trap strings. Set a flag noting that we have to free the - trap strings if we run trap to change a signal disposition. */ - reset_signal_handlers (); - subshell_environment |= SUBSHELL_RESETTRAP; - } - -#if defined (JOB_CONTROL) - /* XXX DO THIS ONLY IN PARENT ? XXX */ - set_sigchld_handler (); -itrace("command_substitute: stop_making_children"); - stop_making_children (); - if (pid != 0) - pipeline_pgrp = old_pipeline_pgrp; -#else - stop_making_children (); -#endif /* JOB_CONTROL */ - - if (pid < 0) - { - sys_error (_("cannot make child for command substitution")); - error_exit: - - last_made_pid = old_pid; - - FREE (istring); - close (fildes[0]); - close (fildes[1]); - return ((WORD_DESC *)NULL); - } - - if (pid == 0) - { - set_sigint_handler (); /* XXX */ - - free_pushed_string_input (); - - if (dup2 (fildes[1], 1) < 0) - { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); - exit (EXECUTION_FAILURE); - } - - /* If standard output is closed in the parent shell - (such as after `exec >&-'), file descriptor 1 will be - the lowest available file descriptor, and end up in - fildes[0]. This can happen for stdin and stderr as well, - but stdout is more important -- it will cause no output - to be generated from this command. */ - if ((fildes[1] != fileno (stdin)) && - (fildes[1] != fileno (stdout)) && - (fildes[1] != fileno (stderr))) - close (fildes[1]); - - if ((fildes[0] != fileno (stdin)) && - (fildes[0] != fileno (stdout)) && - (fildes[0] != fileno (stderr))) - close (fildes[0]); - -#ifdef __CYGWIN__ - /* Let stdio know the fd may have changed from text to binary mode, and - make sure to preserve stdout line buffering. */ - freopen (NULL, "w", stdout); - sh_setlinebuf (stdout); -#endif /* __CYGWIN__ */ - - /* The currently executing shell is not interactive. */ - interactive = 0; - - /* This is a subshell environment. */ - subshell_environment |= SUBSHELL_COMSUB; - - /* When not in POSIX mode, command substitution does not inherit - the -e flag. */ - if (posixly_correct == 0) - exit_immediately_on_error = 0; - - remove_quoted_escapes (string); - - startup_state = 2; /* see if we can avoid a fork */ - /* Give command substitution a place to jump back to on failure, - so we don't go back up to main (). */ - result = setjmp (top_level); - - /* If we're running a command substitution inside a shell function, - trap `return' so we don't return from the function in the subshell - and go off to never-never land. */ - if (result == 0 && return_catch_flag) - function_value = setjmp (return_catch); - else - function_value = 0; - - if (result == ERREXIT) - rc = last_command_exit_value; - else if (result == EXITPROG) - rc = last_command_exit_value; - else if (result) - rc = EXECUTION_FAILURE; - else if (function_value) - rc = return_catch_value; - else - { - subshell_level++; - rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; - } - - last_command_exit_value = rc; - rc = run_exit_trap (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - tflag = 0; - istring = read_comsub (fildes[0], quoted, &tflag); - - close (fildes[0]); - - current_command_subst_pid = pid; - last_command_exit_value = wait_for (pid); - last_command_subst_pid = pid; - last_made_pid = old_pid; - -#if defined (JOB_CONTROL) - /* If last_command_exit_value > 128, then the substituted command - was terminated by a signal. If that signal was SIGINT, then send - SIGINT to ourselves. This will break out of loops, for instance. */ - if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT) - kill (getpid (), SIGINT); - - /* wait_for gives the terminal back to shell_pgrp. If some other - process group should have it, give it away to that group here. - pipeline_pgrp is non-zero only while we are constructing a - pipline, so what we are concerned about is whether or not that - pipeline was started in the background. A pipeline started in - the background should never get the tty back here. */ - if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0) - give_terminal_to (pipeline_pgrp, 0); -#endif /* JOB_CONTROL */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *akey; - char *t, c; - ARRAY *array; - HASH_TABLE *h; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* If unbound variables should generate an error, report one and return - failure. */ - if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error) - { - c = *--t; - *t = '\0'; - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (s); - *t = c; - return (-1); - } - else if (var == 0) - return 0; - - /* We support a couple of expansions for variables that are not arrays. - We'll return the length of the value for v[0], and 1 for v[@] or - v[*]. Return 0 for everything else. */ - - array = array_p (var) ? array_cell (var) : (ARRAY *)NULL; - h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL; - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - { - if (assoc_p (var)) - return (h ? assoc_num_elements (h) : 0); - else if (array_p (var)) - return (array ? array_num_elements (array) : 0); - else - return (var_isset (var) ? 1 : 0); - } - - if (assoc_p (var)) - { - t[len - 1] = '\0'; - akey = expand_assignment_string_to_string (t, 0); /* [ */ - t[len - 1] = ']'; - if (akey == 0 || *akey == 0) - { - err_badarraysub (t); - FREE (akey); - return (-1); - } - t = assoc_reference (assoc_cell (var), akey); - free (akey); - } - else - { - ind = array_expand_index (var, t, len); - if (ind < 0) - { - err_badarraysub (t); - return (-1); - } - if (array_p (var)) - t = array_reference (array, ind); - else - t = (ind == 0) ? value_cell (var) : (char *)NULL; - } - - len = MB_STRLEN (t); - return (len); -} -#endif /* ARRAY_VARS */ - -static int -valid_brace_expansion_word (name, var_is_special) - char *name; - int var_is_special; -{ - if (DIGIT (*name) && all_digits (name)) - return 1; - else if (var_is_special) - return 1; -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - return 1; -#endif /* ARRAY_VARS */ - else if (legal_identifier (name)) - return 1; - else - return 0; -} - -static int -chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp1; - - if (name == 0) - { - if (quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - return 0; - } - - /* check for $@ and $* */ - if (name[0] == '@' && name[1] == 0) - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - else if (name[0] == '*' && name[1] == '\0' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - - /* Now check for ${array[@]} and ${array[*]} */ -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { - temp1 = mbschr (name, '['); - if (temp1 && temp1[1] == '@' && temp1[2] == ']') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } /* [ */ - /* ${array[*]}, when unquoted, should be treated like ${array[@]}, - which should result in separate words even when IFS is unset. */ - if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0) - { - if (contains_dollar_at) - *contains_dollar_at = 1; - return 1; - } - } -#endif - return 0; -} - -/* Parameter expand NAME, and return a new string which is the expansion, - or NULL if there was no expansion. - VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in - the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that - NAME was found inside of a double-quoted expression. */ -static WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp) - char *name; - int var_is_special, quoted, pflags; - arrayind_t *indp; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype, rflags; - arrayind_t ind; - - ret = 0; - temp = 0; - rflags = 0; - - if (indp) - *indp = INTMAX_MIN; - - /* Handle multiple digit arguments, as in ${11}. */ - if (legal_number (name, &arg_index)) - { - tt = get_dollar_var_value (arg_index); - if (tt) - temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (tt) - : quote_escapes (tt); - else - temp = (char *)NULL; - FREE (tt); - } - else if (var_is_special) /* ${@} */ - { - int sindex; - tt = (char *)xmalloc (2 + strlen (name)); - tt[sindex = 0] = '$'; - strcpy (tt + 1, name); - - ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, - (int *)NULL, (int *)NULL, pflags); - free (tt); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name)) - { -expand_arrayref: - /* XXX - does this leak if name[@] or name[*]? */ - temp = array_value (name, quoted, 0, &atype, &ind); - if (atype == 0 && temp) - { - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - rflags |= W_ARRAYIND; - if (indp) - *indp = ind; - } - else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - rflags |= W_HASQUOTEDNULL; - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - if (assoc_p (var)) - temp = assoc_reference (assoc_cell (var), "0"); - else if (array_p (var)) - temp = array_reference (array_cell (var), 0); - else - temp = value_cell (var); -#else - temp = value_cell (var); -#endif - - if (temp) - temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - ? quote_string (temp) - : quote_escapes (temp); - } - else - temp = (char *)NULL; - } -#if defined (ARRAY_VARS) - /* Handle expanding nameref whose value is x[n] */ - else if (var = find_variable_last_nameref (name)) - { - temp = nameref_cell (var); - if (temp && *temp && valid_array_reference (temp)) - { - name = temp; - goto expand_arrayref; - } - temp = (char *)NULL; - } -#endif - else - temp = (char *)NULL; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - ret->flags |= rflags; - } - return ret; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at) - char *name; - int var_is_special, quoted; - int *quoted_dollar_atp, *contains_dollar_at; -{ - char *temp, *t; - WORD_DESC *w; - SHELL_VAR *v; - - /* See if it's a nameref first, behave in ksh93-compatible fashion. - There is at least one incompatibility: given ${!foo[0]} where foo=bar, - bash performs an indirect lookup on foo[0] and expands the result; - ksh93 expands bar[0]. We could do that here -- there are enough usable - primitives to do that -- but do not at this point. */ - if (var_is_special == 0 && (v = find_variable_last_nameref (name))) - { - if (nameref_p (v) && (t = nameref_cell (v)) && *t) - { - w = alloc_word_desc (); - w->word = savestring (t); - w->flags = 0; - return w; - } - } - - w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0); - t = w->word; - /* Have to dequote here if necessary */ - if (t) - { - temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - ? dequote_string (t) - : dequote_escapes (t); - free (t); - t = temp; - } - dispose_word_desc (w); - - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (WORD_DESC *)NULL; - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0); - free (t); - - return w; -} - -/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE}, - depending on the value of C, the separating character. C can be one of - "-", "+", or "=". QUOTED is true if the entire brace expression occurs - between double quotes. */ -static WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* If the entire expression is between double quotes, we want to treat - the value as a double-quoted string, with the exception that we strip - embedded unescaped double quotes (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); - } - else - temp = value; - - w = alloc_word_desc (); - hasdol = 0; - /* XXX was 0 not quoted */ - l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL) - : (WORD_LIST *)0; - if (hasdollarat) - *hasdollarat = hasdol || (l && l->next); - if (temp != value) - free (temp); - if (l) - { - /* The expansion of TEMP returned something. We need to treat things - slightly differently if HASDOL is non-zero. If we have "$@", the - individual words have already been quoted. We need to turn them - into a string with the words separated by the first character of - $IFS without any additional quoting, so string_list_dollar_at won't - do the right thing. We use string_list_dollar_star instead. */ - temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l); - - /* If l->next is not null, we know that TEMP contained "$@", since that - is the only expansion that creates more than one word. */ - if (qdollaratp && ((hasdol && quoted) || l->next)) - *qdollaratp = 1; - /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is - a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the - flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the - expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - (which is more paranoia than anything else), we need to return the - quoted null string and set the flags to indicate it. */ - if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) - { - w->flags |= W_HASQUOTEDNULL; - } - dispose_words (l); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) - { - /* The brace expansion occurred between double quotes and there was - a $@ in TEMP. It does not matter if the $@ is quoted, as long as - it does not expand to anything. In this case, we want to return - a quoted empty string. */ - temp = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - { - w->word = temp; - return w; - } - - /* c == '=' */ - t = temp ? savestring (temp) : savestring (""); - t1 = dequote_string (t); - free (t); -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - assign_array_element (name, t1, 0); - else -#endif /* ARRAY_VARS */ - bind_variable (name, t1, 0); - - /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */ - free (temp); - - w->word = t1; - return w; -} - -/* Deal with the right hand side of a ${name:?value} expansion in the case - that NAME is null or not set. If VALUE is non-null it is expanded and - used as the error message to print, otherwise a standard message is - printed. */ -static void -parameter_brace_expand_error (name, value) - char *name, *value; -{ - WORD_LIST *l; - char *temp; - - last_command_exit_value = EXECUTION_FAILURE; /* ensure it's non-zero */ - if (value && *value) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else - report_error (_("%s: parameter null or not set"), name); - - /* Free the data we have allocated during this expansion, since we - are about to longjmp out. */ - free (name); - FREE (value); -} - -/* Return 1 if NAME is something for which parameter_brace_expand_length is - OK to do. */ -static int -valid_length_expression (name) - char *name; -{ - return (name[1] == '\0' || /* ${#} */ - ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */ - (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */ -#if defined (ARRAY_VARS) - valid_array_reference (name + 1) || /* ${#a[7]} */ -#endif - legal_identifier (name + 1)); /* ${#PS1} */ -} - -/* Handle the parameter brace expansion that requires us to return the - length of a parameter. */ -static intmax_t -parameter_brace_expand_length (name) - char *name; -{ - char *t, *newname; - intmax_t number, arg_index; - WORD_LIST *list; -#if defined (ARRAY_VARS) - SHELL_VAR *var; -#endif - - if (name[1] == '\0') /* ${#} */ - number = number_of_args (); - else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ - number = number_of_args (); - else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') - { - /* Take the lengths of some of the shell's special parameters. */ - switch (name[1]) - { - case '-': - t = which_set_flags (); - break; - case '?': - t = itos (last_command_exit_value); - break; - case '$': - t = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - t = (char *)NULL; /* XXX - error if set -u set? */ - else - t = itos (last_asynchronous_pid); - break; - case '#': - t = itos (number_of_args ()); - break; - } - number = STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if (valid_array_reference (name + 1)) - number = array_length_reference (name + 1); -#endif /* ARRAY_VARS */ - else - { - number = 0; - - if (legal_number (name + 1, &arg_index)) /* ${#1} */ - { - t = get_dollar_var_value (arg_index); - if (t == 0 && unbound_vars_is_error) - return INTMAX_MIN; - number = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) - { - if (assoc_p (var)) - t = assoc_reference (assoc_cell (var), "0"); - else - t = array_reference (array_cell (var), 0); - if (t == 0 && unbound_vars_is_error) - return INTMAX_MIN; - number = MB_STRLEN (t); - } -#endif - else /* ${#PS1} */ - { - newname = savestring (name); - newname[0] = '$'; - list = expand_string (newname, Q_DOUBLE_QUOTES); - t = list ? string_list (list) : (char *)NULL; - free (newname); - if (list) - dispose_words (list); - - number = t ? MB_STRLEN (t) : 0; - FREE (t); - } - } - - return (number); -} - -/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression, - so we do some ad-hoc parsing of an arithmetic expression to find - the first DELIM, instead of using strchr(3). Two rules: - 1. If the substring contains a `(', read until closing `)'. - 2. If the substring contains a `?', read past one `:' for each `?'. -*/ - -static char * -skiparith (substr, delim) - char *substr; - int delim; -{ - size_t sublen; - int skipcol, pcount, i; - DECLARE_MBSTATE; - - sublen = strlen (substr); - i = skipcol = pcount = 0; - while (substr[i]) - { - /* Balance parens */ - if (substr[i] == LPAREN) - { - pcount++; - i++; - continue; - } - if (substr[i] == RPAREN && pcount) - { - pcount--; - i++; - continue; - } - if (pcount) - { - ADVANCE_CHAR (substr, sublen, i); - continue; - } - - /* Skip one `:' for each `?' */ - if (substr[i] == ':' && skipcol) - { - skipcol--; - i++; - continue; - } - if (substr[i] == delim) - break; - if (substr[i] == '?') - { - skipcol++; - i++; - continue; - } - ADVANCE_CHAR (substr, sublen, i); - } - - return (substr + i); -} - -/* Verify and limit the start and end of the desired substring. If - VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional parameters are being used; if it is 2, then - VALUE is really a pointer to an array variable that should be used. - Return value is 1 if both values were OK, 0 if there was a problem - with an invalid expression, or -1 if the values were out of range. */ -static int -verify_substring_values (v, value, substr, vtype, e1p, e2p) - SHELL_VAR *v; - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; - HASH_TABLE *h; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. Associative - arrays treat the number of elements as the maximum index. */ - if (assoc_p (v)) - { - h = assoc_cell (v); - len = assoc_num_elements (h) + (*e1p < 0); - } - else - { - a = (ARRAY *)value; - len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */ - } - break; -#endif - } - - if (len == -1) /* paranoia */ - return -1; - - if (*e1p < 0) /* negative offsets count from end */ - *e1p += len; - - if (*e1p > len || *e1p < 0) - return (-1); - -#if defined (ARRAY_VARS) - /* For arrays, the second offset deals with the number of elements. */ - if (vtype == VT_ARRAYVAR) - len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - free (temp2); - t[-1] = ':'; - *e2p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); -#if 1 - if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0) -#else - /* bash-4.3: allow positional parameter length < 0 to count backwards - from end of positional parameters */ - if (vtype == VT_ARRAYVAR && *e2p < 0) -#endif - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } -#if defined (ARRAY_VARS) - /* In order to deal with sparse arrays, push the intelligence about how - to deal with the number of elements desired down to the array- - specific functions. */ - if (vtype != VT_ARRAYVAR) -#endif - { - if (*e2p < 0) - { - *e2p += len; - if (*e2p < 0 || *e2p < *e1p) - { - internal_error (_("%s: substring expression < 0"), t); - return (0); - } - } - else - *e2p += *e1p; /* want E2 chars starting at E1 */ - if (*e2p > len) - *e2p = len; - } - } - else - *e2p = len; - - return (1); -} - -/* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable). Also return the value specified - by VARNAME (value of a variable or a reference to an array element). - QUOTED is the standard description of quoting state, using Q_* defines. - FLAGS is currently a set of flags to pass to array_value. If IND is - non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is - passed to array_value so the array index is not computed again. - If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL - characters in the value are quoted with CTLESC and takes appropriate - steps. For convenience, *VALP is set to the dequoted VALUE. */ -static int -get_var_and_type (varname, value, ind, quoted, flags, varp, valp) - char *varname, *value; - arrayind_t ind; - int quoted, flags; - SHELL_VAR **varp; - char **valp; -{ - int vtype; - char *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *v; -#endif - arrayind_t lind; - - /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ - vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; - if (vtype == VT_POSPARMS && varname[0] == '*') - vtype |= VT_STARSUB; - *varp = (SHELL_VAR *)NULL; - -#if defined (ARRAY_VARS) - if (valid_array_reference (varname)) - { - v = array_variable_part (varname, &temp, (int *)0); - /* If we want to signal array_value to use an already-computed index, - set LIND to that index */ - lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0; - if (v && (array_p (v) || assoc_p (v))) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - /* Callers have to differentiate betwen indexed and associative */ - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); - } - *varp = v; - } - else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind); - } - } - else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); - } - else -#endif - { - if (value && vtype == VT_VARIABLE) - { - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - *valp = value; - } - - return vtype; -} - -/******************************************************/ -/* */ -/* Functions to extract substrings of variable values */ -/* */ -/******************************************************/ - -#if defined (HANDLE_MULTIBYTE) -/* Character-oriented rather than strictly byte-oriented substrings. S and - E, rather being strict indices into STRING, indicate character (possibly - multibyte character) positions that require calculation. - Used by the ${param:offset[:length]} expansion. */ -static char * -mb_substring (string, s, e) - char *string; - int s, e; -{ - char *tt; - int start, stop, i, slen; - DECLARE_MBSTATE; - - start = 0; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - i = s; - while (string[start] && i--) - ADVANCE_CHAR (string, slen, start); - stop = start; - i = e - s; - while (string[stop] && i--) - ADVANCE_CHAR (string, slen, stop); - tt = substring (string, start, stop); - return tt; -} -#endif - -/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME - is `@', use the positional parameters; otherwise, use the value of - VARNAME. If VARNAME is an array variable, use the array elements. */ - -static char * -parameter_brace_substring (varname, value, ind, substr, quoted, flags) - char *varname, *value; - int ind; - char *substr; - int quoted, flags; -{ - intmax_t e1, e2; - int vtype, r, starsub; - char *temp, *val, *tt, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (v, val, substr, vtype, &e1, &e2); - this_command_name = oname; - if (r <= 0) - { - if (vtype == VT_VARIABLE) - FREE (val); - return ((r == 0) ? &expand_param_error : (char *)NULL); - } - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - tt = mb_substring (val, e1, e2); - else -#endif - tt = substring (val, e1, e2); - - if (vtype == VT_VARIABLE) - FREE (val); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - temp = quote_string (tt); - else - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - break; - case VT_POSPARMS: - tt = pos_params (varname, e1, e2, quoted); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - { - temp = tt ? quote_escapes (tt) : (char *)NULL; - FREE (tt); - } - else - temp = tt; - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - if (assoc_p (v)) - /* we convert to list and take first e2 elements starting at e1th - element -- officially undefined for now */ - temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted); - else - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - break; -#endif - default: - temp = (char *)NULL; - } - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform pattern substitution on variable values */ -/* */ -/****************************************************************/ - -static int -shouldexp_replacement (s) - char *s; -{ - register char *p; - - for (p = s; p && *p; p++) - { - if (*p == '\\') - p++; - else if (*p == '&') - return 1; - } - return 0; -} - -char * -pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - char *ret, *s, *e, *str, *rstr, *mstr; - int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen; - - if (string == 0) - return (savestring ("")); - - mtype = mflags & MATCH_TYPEMASK; - -#if 0 /* bash-4.2 ? */ - rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0; -#else - rxpand = 0; -#endif - - /* Special cases: - * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING - * with REP and return the result. - * 2. A null pattern with mtype == MATCH_END means to append REP to - * STRING and return the result. - * These don't understand or process `&' in the replacement string. - */ - if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END)) - { - replen = STRLEN (rep); - l = STRLEN (string); - ret = (char *)xmalloc (replen + l + 2); - if (replen == 0) - strcpy (ret, string); - else if (mtype == MATCH_BEG) - { - strcpy (ret, rep); - strcpy (ret + replen, string); - } - else - { - strcpy (ret, string); - strcpy (ret + l, rep); - } - return (ret); - } - - ret = (char *)xmalloc (rsize = 64); - ret[0] = '\0'; - - for (replen = STRLEN (rep), rptr = 0, str = string;;) - { - if (match_pattern (str, pat, mtype, &s, &e) == 0) - break; - l = s - str; - - if (rxpand) - { - int x; - mlen = e - s; - mstr = xmalloc (mlen + 1); - for (x = 0; x < mlen; x++) - mstr[x] = s[x]; - mstr[mlen] = '\0'; - rstr = strcreplace (rep, '&', mstr, 0); - rslen = strlen (rstr); - } - else - { - rstr = rep; - rslen = replen; - } - - RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); - - /* OK, now copy the leading unmatched portion of the string (from - str to s) to ret starting at rptr (the current offset). Then copy - the replacement string at ret + rptr + (s - str). Increment - rptr (if necessary) and str and go on. */ - if (l) - { - strncpy (ret + rptr, str, l); - rptr += l; - } - if (replen) - { - strncpy (ret + rptr, rstr, rslen); - rptr += rslen; - } - str = e; /* e == end of match */ - - if (rstr != rep) - free (rstr); - - if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY) - break; - - if (s == e) - { - /* On a zero-length match, make sure we copy one character, since - we increment one character to avoid infinite recursion. */ - RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64); - ret[rptr++] = *str++; - e++; /* avoid infinite recursion on zero-length match */ - } - } - - /* Now copy the unmatched portion of the input string */ - if (str && *str) - { - RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64); - strcpy (ret + rptr, str); - } - else - ret[rptr] = '\0'; - - return ret; -} - -/* Do pattern match and replacement on the positional parameters. */ -static char * -pos_params_pat_subst (string, pat, rep, mflags) - char *string, *pat, *rep; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret; - int pchar, qflags; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = pat_subst (params->word->word, pat, rep, mflags); - w = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - -#if 0 - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB) - ret = string_list_dollar_star (save); - else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED) - ret = string_list_dollar_at (save, qflags); - else - ret = string_list_dollar_star (save); -#else - ret = string_list_pos_params (pchar, save, qflags); -#endif - - dispose_words (save); - - return (ret); -} - -/* Perform pattern substitution on VALUE, which is the expansion of - VARNAME. PATSUB is an expression supplying the pattern to match - and the string to substitute. QUOTED is a flags word containing - the type of quoting currently in effect. */ -static char * -parameter_brace_patsub (varname, value, ind, patsub, quoted, flags) - char *varname, *value; - int ind; - char *patsub; - int quoted, flags; -{ - int vtype, mflags, starsub, delim; - char *val, *temp, *pat, *rep, *p, *lpatsub, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - mflags = 0; - /* PATSUB is never NULL when this is called. */ - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ - lpatsub = savestring (patsub); - - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - - if (starsub) - mflags |= MATCH_STARSUB; - - /* If the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ - delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); - if (lpatsub[delim] == '/') - { - lpatsub[delim] = 0; - rep = lpatsub + delim + 1; - } - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - if (rep) - /* We want to perform quote removal on the expanded replacement even if - the entire expansion is double-quoted because the parser and string - extraction functions treated quotes in the replacement string as - special. */ - rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit); - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; - p++; - } - else if (pat && pat[0] == '%') - { - mflags |= MATCH_END; - p++; - } - else - mflags |= MATCH_ANY; - - /* OK, we now want to substitute REP for PAT in VAL. If - flags & MATCH_GLOBREP is non-zero, the substitution is done - everywhere, otherwise only the first occurrence of PAT is - replaced. The pattern matching code doesn't understand - CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable - values passed in (VT_VARIABLE) so the pattern substitution - code works right. We need to requote special chars after - we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the - other cases if QUOTED == 0, since the posparams and arrays - indexed by * or @ do special things when QUOTED != 0. */ - - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = pat_subst (val, p, rep, mflags); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); - free (temp); - temp = tt; - } - break; - case VT_POSPARMS: - temp = pos_params_pat_subst (val, p, rep, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags) - : array_patsub (array_cell (v), p, rep, mflags); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators; ditto for assoc_patsub. */ - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform case modification on variable values */ -/* */ -/****************************************************************/ - -/* Do case modification on the positional parameters. */ - -static char * -pos_params_modcase (string, pat, modop, mflags) - char *string, *pat; - int modop; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret; - int pchar, qflags; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = sh_modcase (params->word->word, pat, modop); - w = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - - ret = string_list_pos_params (pchar, save, qflags); - dispose_words (save); - - return (ret); -} - -/* Perform case modification on VALUE, which is the expansion of - VARNAME. MODSPEC is an expression supplying the type of modification - to perform. QUOTED is a flags word containing the type of quoting - currently in effect. */ -static char * -parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags) - char *varname, *value; - int ind, modspec; - char *patspec; - int quoted, flags; -{ - int vtype, starsub, modop, mflags, x; - char *val, *temp, *pat, *p, *lpat, *tt; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - this_command_name = varname; - - vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val); - if (vtype == -1) - return ((char *)NULL); - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - modop = 0; - mflags = 0; - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - if (starsub) - mflags |= MATCH_STARSUB; - - p = patspec; - if (modspec == '^') - { - x = p && p[0] == modspec; - modop = x ? CASE_UPPER : CASE_UPFIRST; - p += x; - } - else if (modspec == ',') - { - x = p && p[0] == modspec; - modop = x ? CASE_LOWER : CASE_LOWFIRST; - p += x; - } - else if (modspec == '~') - { - x = p && p[0] == modspec; - modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; - p += x; - } - - lpat = p ? savestring (p) : 0; - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. FOR LATER */ - pat = lpat ? getpattern (lpat, quoted, 1) : 0; - - /* OK, now we do the case modification. */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = sh_modcase (val, pat, modop); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); - free (temp); - temp = tt; - } - break; - - case VT_POSPARMS: - temp = pos_params_modcase (val, pat, modop, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) - : array_modcase (array_cell (v), pat, modop, mflags); - /* Don't call quote_escapes; array_modcase calls array_quote_escapes - as appropriate before adding the space separators; ditto for - assoc_modcase. */ - break; -#endif - } - - FREE (pat); - free (lpat); - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == LPAREN) - count++; - else if (s[i] == RPAREN) - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at) - char *string; - int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags; -{ - int check_nullness, var_is_set, var_is_null, var_is_special; - int want_substring, want_indir, want_patsub, want_casemod; - char *name, *value, *temp, *temp1; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag, modspec; - intmax_t number; - arrayind_t ind; - - temp = temp1 = value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = want_casemod = 0; - - sindex = *indexp; - t_index = ++sindex; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", SX_VARNAME); - else -#if defined (CASEMOD_EXPANSIONS) - /* To enable case-toggling expansions using the `~' operator character - change the 1 to 0. */ -# if defined (CASEMOD_CAPCASE) - name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME); -# else - name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME); -# endif /* CASEMOD_CAPCASE */ -#else - name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME); -#endif /* CASEMOD_EXPANSIONS */ - - ret = 0; - tflag = 0; - - ind = INTMAX_MIN; - - /* If the name really consists of a special variable, then make sure - that we have the entire name. We don't allow indirect references - to special variables except `#', `?', `@' and `*'. */ - if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) || - (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index]))) - { - t_index++; - temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); - name = (char *)xrealloc (name, 3 + (strlen (temp1))); - *name = string[sindex]; - if (string[sindex] == '!') - { - /* indirect reference of $#, $?, $@, or $* */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); - } - else - strcpy (name + 1, temp1); - free (temp1); - } - sindex = t_index; - - /* Find out what character ended the variable name. Then - do the appropriate thing. */ - if (c = string[sindex]) - sindex++; - - /* If c is followed by one of the valid parameter expansion - characters, move past it as normal. If not, assume that - a substring specification is being given, and do not move - past it. */ - if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex])) - { - check_nullness++; - if (c = string[sindex]) - sindex++; - } - else if (c == ':' && string[sindex] != RBRACE) - want_substring = 1; - else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */ - want_patsub = 1; -#if defined (CASEMOD_EXPANSIONS) - else if (c == '^' || c == ',' || c == '~') - { - modspec = c; - want_casemod = 1; - } -#endif - - /* Catch the valid and invalid brace expressions that made it through the - tests above. */ - /* ${#-} is a valid expansion and means to take the length of $-. - Similarly for ${#?} and ${##}... */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE) - { - name = (char *)xrealloc (name, 3); - name[1] = c; - name[2] = '\0'; - c = string[sindex++]; - } - - /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */ - if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 && - member (c, "%:=+/") && string[sindex] == RBRACE) - { - temp = (char *)NULL; - goto bad_substitution; - } - - /* Indirect expansion begins with a `!'. A valid indirect expansion is - either a variable name, one of the positional parameters or a special - variable that expands to one of the positional parameters. */ - want_indir = *name == '!' && - (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) - || VALID_INDIR_PARAM (name[1])); - - /* Determine the value of this variable. */ - - /* Check for special variables, directly referenced. */ - if (SPECIAL_VAR (name, want_indir)) - var_is_special++; - - /* Check for special expansion things, like the length of a parameter */ - if (*name == '#' && name[1]) - { - /* If we are not pointing at the character just after the - closing brace, then we haven't gotten all of the name. - Since it begins with a special character, this is a bad - substitution. Also check NAME for validity before trying - to go on. */ - if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) - { - temp = (char *)NULL; - goto bad_substitution; - } - - number = parameter_brace_expand_length (name); - if (number == INTMAX_MIN && unbound_vars_is_error) - { - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (name+1); - free (name); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - free (name); - - *indexp = sindex; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} is identical to $@. */ - if (name[0] == '@' && name[1] == '\0') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - - /* Process ${!PREFIX*} expansion. */ - if (want_indir && string[sindex - 1] == RBRACE && - (string[sindex - 2] == '*' || string[sindex - 2] == '@') && - legal_variable_starter ((unsigned char) name[1])) - { - char **x; - WORD_LIST *xlist; - - temp1 = savestring (name + 1); - number = strlen (temp1); - temp1[number - 1] = '\0'; - x = all_variables_matching_prefix (temp1); - xlist = strvec_to_word_list (x, 0, 0); - if (string[sindex - 2] == '*') - temp = string_list_dollar_star (xlist); - else - { - temp = string_list_dollar_at (xlist, quoted); - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - free (x); - dispose_words (xlist); - free (temp1); - *indexp = sindex; - - free (name); - - ret = alloc_word_desc (); - ret->word = temp; - ret->flags = tflag; /* XXX */ - return ret; - } - -#if defined (ARRAY_VARS) - /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */ - if (want_indir && string[sindex - 1] == RBRACE && - string[sindex - 2] == ']' && valid_array_reference (name+1)) - { - char *x, *x1; - - temp1 = savestring (name + 1); - x = array_variable_name (temp1, &x1, (int *)0); /* [ */ - FREE (x); - if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']') - { - temp = array_keys (temp1, quoted); /* handles assoc vars too */ - if (x1[0] == '@') - { - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - tflag |= W_DOLLARAT; - } - - free (temp1); - *indexp = sindex; - - ret = alloc_word_desc (); - ret->word = temp; - ret->flags = tflag; /* XXX */ - return ret; - } - - free (temp1); - } -#endif /* ARRAY_VARS */ - - /* Make sure that NAME is valid before trying to go on. */ - if (valid_brace_expansion_word (want_indir ? name + 1 : name, - var_is_special) == 0) - { - temp = (char *)NULL; - goto bad_substitution; - } - - if (want_indir) - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind); - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - -#if defined (ARRAY_VARS) - if (valid_array_reference (name)) - chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at); -#endif - - var_is_set = temp != (char *)0; - var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); - - /* Get the rest of the stuff inside the braces. */ - if (c && c != RBRACE) - { - /* Extract the contents of the ${ ... } expansion - according to the Posix.2 rules. */ - value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); - if (string[sindex] == RBRACE) - sindex++; - else - goto bad_substitution; - } - else - value = (char *)NULL; - - *indexp = sindex; - - /* All the cases where an expansion can possibly generate an unbound - variable error. */ - if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE) - { - if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1])) - { - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (name); - FREE (value); - FREE (temp); - free (name); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - } - - /* If this is a substring spec, process it and add the result. */ - if (want_substring) - { - temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } -#if defined (CASEMOD_EXPANSIONS) - else if (want_casemod) - { - temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } -#endif - - /* Do the right thing based on which character ended the variable name. */ - switch (c) - { - default: - case '\0': - bad_substitution: - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("%s: bad substitution"), string ? string : "??"); - FREE (value); - FREE (temp); - free (name); - return &expand_wdesc_error; - - case RBRACE: - break; - - case '#': /* ${param#[#]pattern} */ - case '%': /* ${param%[%]pattern} */ - if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0') - { - FREE (value); - break; - } - temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - free (temp); - free (value); - free (name); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - - case '-': - case '=': - case '?': - case '+': - if (var_is_set && var_is_null == 0) - { - /* If the operator is `+', we don't want the value of the named - variable for anything, just the value of the right hand side. */ - if (c == '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - FREE (temp); - if (value) - { - /* From Posix discussion on austin-group list. Issue 221 - requires that backslashes escaping `}' inside - double-quoted ${...} be removed. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - quoted |= Q_DOLBRACE; - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - free (value); - } - else - temp = (char *)NULL; - } - else - { - FREE (value); - } - /* Otherwise do nothing; just use the value in TEMP. */ - } - else /* VAR not set or VAR is NULL. */ - { - FREE (temp); - temp = (char *)NULL; - if (c == '=' && var_is_special) - { - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("$%s: cannot assign in this way"), name); - free (name); - free (value); - return &expand_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - else if (c != '+') - { - /* XXX -- if we're double-quoted and the named variable is "$@", - we want to turn off any special handling of "$@" -- - we're not using it, so whatever is on the rhs applies. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp) - *quoted_dollar_atp = 0; - if (contains_dollar_at) - *contains_dollar_at = 0; - - /* From Posix discussion on austin-group list. Issue 221 requires - that backslashes escaping `}' inside double-quoted ${...} be - removed. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - quoted |= Q_DOLBRACE; - ret = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* Expand a single ${xxx} expansion. The braces are optional. When - the braces are used, parameter_brace_expand() does the work, - possibly calling param_expand recursively. */ -static WORD_DESC * -param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, - pflags) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at_p, *had_quoted_null_p, pflags; -{ - char *temp, *temp1, uerror[3]; - int zindex, t_index, expok; - unsigned char c; - intmax_t number; - SHELL_VAR *var; - WORD_LIST *list; - WORD_DESC *tdesc, *ret; - int tflag; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* Do simple cases first. Switch on what follows '$'. */ - switch (c) - { - /* $0 .. $9? */ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - temp1 = dollar_vars[TODIGIT (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (char *)NULL; - - break; - - /* $$ -- pid of the invoking shell. */ - case '$': - temp = itos (dollar_dollar_pid); - break; - - /* $# -- number of positional parameters. */ - case '#': - temp = itos (number_of_args ()); - break; - - /* $? -- return value of the last synchronous command. */ - case '?': - temp = itos (last_command_exit_value); - break; - - /* $- -- flags supplied to the shell on invocation or by `set'. */ - case '-': - temp = which_set_flags (); - break; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - /* If no asynchronous pids have been created, expand to nothing. - If `set -u' has been executed, and no async processes have - been created, this is an expansion error. */ - if (last_asynchronous_pid == NO_PID) - { - if (expanded_something) - *expanded_something = 0; - temp = (char *)NULL; - if (unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = c; - uerror[2] = '\0'; - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - } - else - temp = itos (last_asynchronous_pid); - break; - - /* The only difference between this and $@ is when the arg is quoted. */ - case '*': /* `$*' */ - list = list_rest_of_args (); - -#if 0 - /* According to austin-group posix proposal by Geoff Clare in - <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: - - "The shell shall write a message to standard error and - immediately exit when it tries to expand an unset parameter - other than the '@' and '*' special parameters." - */ - - if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) - { - uerror[0] = '$'; - uerror[1] = '*'; - uerror[2] = '\0'; - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } -#endif - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) - temp = (char *)NULL; - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE)) - { - /* If we have "$*" we want to make a string of the positional - parameters, separated by the first character of $IFS, and - quote the whole string, including the separators. If IFS - is unset, the parameters are separated by ' '; if $IFS is - null, the parameters are concatenated. */ - temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list); - if (temp) - { - temp1 = quote_string (temp); - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - free (temp); - temp = temp1; - } - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ -#if 1 -# if defined (HANDLE_MULTIBYTE) - if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - temp = string_list_dollar_star (list); - else - temp = string_list_dollar_at (list, quoted); -#else - temp = string_list_dollar_at (list, quoted); -#endif - if (expand_no_split_dollar_star == 0 && contains_dollar_at) - *contains_dollar_at = 1; - } - - dispose_words (list); - break; - - /* When we have "$@" what we want is "$1" "$2" "$3" ... This - means that we have to turn quoting off after we split into - the individually quoted arguments so that the final split - on the first character of $IFS is still done. */ - case '@': /* `$@' */ - list = list_rest_of_args (); - -#if 0 - /* According to austin-group posix proposal by Geoff Clare in - <20090505091501.GA10097@squonk.masqnet> of 5 May 2009: - - "The shell shall write a message to standard error and - immediately exit when it tries to expand an unset parameter - other than the '@' and '*' special parameters." - */ - - if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0) - { - uerror[0] = '$'; - uerror[1] = '@'; - uerror[2] = '\0'; - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (uerror); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } -#endif - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - /* XXX - should this test include Q_PATQUOTE? */ - if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - *quoted_dollar_at_p = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - - /* We want to separate the positional parameters with the first - character of $IFS in case $IFS is something other than a space. - We also want to make sure that splitting is done no matter what -- - according to POSIX.2, this expands to a list of the positional - parameters no matter what IFS is set to. */ - temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted); - - tflag |= W_DOLLARAT; - dispose_words (list); - break; - - case LBRACE: - tdesc = parameter_brace_expand (string, &zindex, quoted, pflags, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* XXX */ - /* Quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. The exception to - this is when we have "${@}" and $1 is '', since $@ needs - special handling. */ - if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - goto return0; - - /* Do command or arithmetic substitution. */ - case LPAREN: - /* We have to extract the contents of this paren substitution. */ - t_index = zindex + 1; - temp = extract_command_subst (string, &t_index, 0); - zindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == LPAREN) - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != RPAREN) - { - free (temp2); - goto comsub; - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); -#if 0 - internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution")); -#endif - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - free (temp2); - -arithsub: - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - if (interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - return (&expand_wdesc_fatal); - } - else - return (&expand_wdesc_error); - } - temp = itos (number); - break; - } - -comsub: - if (pflags & PF_NOCOMSUB) - /* we need zindex+1 because string[zindex] == RPAREN */ - temp1 = substring (string, *sindex, zindex+1); - else - { - tdesc = command_substitute (temp, quoted); - temp1 = tdesc ? tdesc->word : (char *)NULL; - if (tdesc) - dispose_word_desc (tdesc); - } - FREE (temp); - temp = temp1; - break; - - /* Do POSIX.2d9-style arithmetic substitution. This will probably go - away in a future bash release. */ - case '[': - /* Extract the contents of this arithmetic substitution. */ - t_index = zindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - zindex = t_index; - if (temp == 0) - { - temp = savestring (string); - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* Do initial variable expansion. */ - temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES); - - goto arithsub; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) - ; - temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = (char *)xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && var_isset (var)) - { -#if defined (ARRAY_VARS) - if (assoc_p (var) || array_p (var)) - { - temp = array_p (var) ? array_reference (array_cell (var), 0) - : assoc_reference (assoc_cell (var), "0"); - if (temp) - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - else if (unbound_vars_is_error) - goto unbound_variable; - } - else -#endif - { - temp = value_cell (var); - - temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp) - : quote_escapes (temp); - } - - free (temp1); - - goto return0; - } -#if defined (ARRAY_VARS) - else if (var = find_variable_last_nameref (temp1)) - { - temp = nameref_cell (var); - if (temp && *temp && valid_array_reference (temp)) - { - tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (int *)NULL); - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - ret = tdesc; - goto return0; - } - else - temp = (char *)NULL; - } -#endif - - temp = (char *)NULL; - -unbound_variable: - if (unbound_vars_is_error) - { - last_command_exit_value = EXECUTION_FAILURE; - err_unboundvar (temp1); - } - else - { - free (temp1); - goto return0; - } - - free (temp1); - last_command_exit_value = EXECUTION_FAILURE; - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -/* Make a word list which is the result of parameter and variable - expansion, command substitution, arithmetic substitution, and - quote removal of WORD. Return a pointer to a WORD_LIST which is - the result of the expansion. If WORD contains a null word, the - word list returned is also null. - - QUOTED contains flag values defined in shell.h. - - ISEXP is used to tell expand_word_internal that the word should be - treated as the result of an expansion. This has implications for - how IFS characters in the word are treated. - - CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null - they point to an integer value which receives information about expansion. - CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero. - EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions, - else zero. - - This only does word splitting in the case of $@ expansion. In that - case, we split on ' '. */ - -/* Values for the local variable quoted_state. */ -#define UNQUOTED 0 -#define PARTIALLY_QUOTED 1 -#define WHOLLY_QUOTED 2 - -static WORD_LIST * -expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something) - WORD_DESC *word; - int quoted, isexp; - int *contains_dollar_at; - int *expanded_something; -{ - WORD_LIST *list; - WORD_DESC *tword; - - /* The intermediate string that we build while expanding. */ - char *istring; - - /* The current size of the above object. */ - int istring_size; - - /* Index into ISTRING. */ - int istring_index; - - /* Temporary string storage. */ - char *temp, *temp1; - - /* The text of WORD. */ - register char *string; - - /* The size of STRING. */ - size_t string_size; - - /* The index into STRING. */ - int sindex; - - /* This gets 1 if we see a $@ while quoted. */ - int quoted_dollar_at; - - /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on - whether WORD contains no quoting characters, a partially quoted - string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */ - int quoted_state; - - /* State flags */ - int had_quoted_null; - int has_dollar_at, temp_has_dollar_at; - int tflag; - int pflags; /* flags passed to param_expand */ - - int assignoff; /* If assignment, offset of `=' */ - - register unsigned char c; /* Current character. */ - int t_index; /* For calls to string_extract_xxx. */ - - char twochars[2]; - - DECLARE_MBSTATE; - - istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); - istring[istring_index = 0] = '\0'; - quoted_dollar_at = had_quoted_null = has_dollar_at = 0; - quoted_state = UNQUOTED; - - string = word->word; - if (string == 0) - goto finished_with_string; - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible. */ - string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* Begin the expansion. */ - - for (sindex = 0; ;) - { - c = string[sindex]; - - /* Case on toplevel character. */ - switch (c) - { - case '\0': - goto finished_with_string; - - case CTLESC: - sindex++; -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && string[sindex]) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - temp = (char *)xmalloc (3); - temp[0] = CTLESC; - temp[1] = c = string[sindex]; - temp[2] = '\0'; - } - -dollar_add_string: - if (string[sindex]) - sindex++; - -add_string: - if (temp) - { - istring = sub_append_string (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - -#if defined (PROCESS_SUBSTITUTION) - /* Process substitution. */ - case '<': - case '>': - { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct) - { - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - t_index = sindex + 1; /* skip past both '<' and LPAREN */ - - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ - sindex = t_index; - - /* If the process substitution specification is `<()', we want to - open the pipe for writing in the child and produce output; if - it is `>()', we want to open the pipe for reading in the child - and consume input. */ - temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0; - - FREE (temp1); - - goto dollar_add_string; - } -#endif /* PROCESS_SUBSTITUTION */ - - case '=': - /* Posix.2 section 3.6.1 says that tildes following `=' in words - which are not assignment statements are not expanded. If the - shell isn't in posix mode, though, we perform tilde expansion - on `likely candidate' unquoted assignment statements (flags - include W_ASSIGNMENT but not W_QUOTED). A likely candidate - contains an unquoted :~ or =~. Something to think about: we - now have a flag that says to perform tilde expansion on arguments - to `assignment builtins' like declare and export that look like - assignment statements. We now do tilde expansion on such words - even in POSIX mode. */ - if (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - { - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - } - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the `=' appears in the word and prepare to - do tilde expansion following the first `='. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; -#if 0 - else if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; -#endif - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - - case ':': - if (word->flags & W_NOTILDE) - { - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - } - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; - else - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. */ - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) - goto add_ifs_character; - else - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bash_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bash_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_quoted_string; /* XXX was add_string */ - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - - temp_has_dollar_at = 0; - pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; - if (word->flags & W_NOSPLIT2) - pflags |= PF_NOSPLIT2; - if (word->flags & W_ASSIGNRHS) - pflags |= PF_ASSIGNRHS; - tword = param_expand (string, &sindex, quoted, expanded_something, - &temp_has_dollar_at, "ed_dollar_at, - &had_quoted_null, pflags); - has_dollar_at += temp_has_dollar_at; - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - temp = tword ? tword->word : (char *)NULL; - dispose_word_desc (tword); - - /* Kill quoted nulls; we will add them back at the end of - expand_word_internal if nothing else in the string */ - if (had_quoted_null && temp && QUOTED_NULL (temp)) - { - FREE (temp); - temp = (char *)NULL; - } - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", SX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted); - temp1 = tword ? tword->word : (char *)NULL; - if (tword) - dispose_word_desc (tword); - } - FREE (temp); - temp = temp1; - goto dollar_add_string; - } - - case '\\': - if (string[sindex + 1] == '\n') - { - sindex += 2; - continue; - } - - c = string[++sindex]; - - if (quoted & Q_HERE_DOCUMENT) - tflag = CBSHDOC; - else if (quoted & Q_DOUBLE_QUOTES) - tflag = CBSDQUOTE; - else - tflag = 0; - - /* From Posix discussion on austin-group list: Backslash escaping - a } in ${...} is removed. Issue 0000221 */ - if ((quoted & Q_DOLBRACE) && c == RBRACE) - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0)) - { - SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size); - } - else if (c == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - { - SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size); - } - - sindex++; -add_twochars: - /* BEFORE jumping here, we need to increment sindex if appropriate */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = twochars[0]; - istring[istring_index++] = twochars[1]; - istring[istring_index] = '\0'; - - break; - - case '"': -#if 0 - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE)) -#else - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_double_quoted (string, &sindex, 0); - - /* If the quotes surrounded the entire string, then the - whole word was quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - if (temp && *temp) - { - tword = alloc_word_desc (); - tword->word = temp; - - temp = (char *)NULL; - - temp_has_dollar_at = 0; /* XXX */ - /* Need to get W_HASQUOTEDNULL flag through this function. */ - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL); - has_dollar_at += temp_has_dollar_at; - - if (list == &expand_word_error || list == &expand_word_fatal) - { - free (istring); - free (string); - /* expand_word_internal has already freed temp_word->word - for us because of the way it prints error messages. */ - tword->word = (char *)NULL; - dispose_word (tword); - return list; - } - - dispose_word (tword); - - /* "$@" (a double-quoted dollar-at) expands into nothing, - not even a NULL word, when there are no positional - parameters. */ - if (list == 0 && has_dollar_at) - { - quoted_dollar_at++; - break; - } - - /* If we get "$@", we know we have expanded something, so we - need to remember it for the final split on $IFS. This is - a special case; it's the only case where a quoted string - can expand into more than one word. It's going to come back - from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ - if (list) - dequote_list (list); - - if (list && list->word && (list->word->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; /* XXX */ - - if (has_dollar_at) - { - quoted_dollar_at++; - if (contains_dollar_at) - *contains_dollar_at = 1; - if (expanded_something) - *expanded_something = 1; - } - } - else - { - /* What we have is "". This is a minor optimization. */ - FREE (temp); - list = (WORD_LIST *)NULL; - } - - /* The code above *might* return a list (consider the case of "$@", - where it returns "$1", "$2", etc.). We can't throw away the - rest of the list, and we have to make sure each word gets added - as quoted. We test on tresult->next: if it is non-NULL, we - quote the whole list, save it to a string with string_list, and - add that string. We don't need to quote the results of this - (and it would be wrong, since that would quote the separators - as well), so we go directly to add_string. */ - if (list) - { - if (list->next) - { -#if 0 - if (quoted_dollar_at && (word->flags & W_NOSPLIT2)) - temp = string_list_internal (quote_list (list), " "); - else -#endif - /* Testing quoted_dollar_at makes sure that "$@" is - split correctly when $IFS does not contain a space. */ - temp = quoted_dollar_at - ? string_list_dollar_at (list, Q_DOUBLE_QUOTES) - : string_list (quote_list (list)); - dispose_words (list); - goto add_string; - } - else - { - temp = savestring (list->word->word); - tflag = list->word->flags; - dispose_words (list); - - /* If the string is not a quoted null string, we want - to remove any embedded unquoted CTLNUL characters. - We do not want to turn quoted null strings back into - the empty string, though. We do this because we - want to remove any quoted nulls from expansions that - contain other characters. For example, if we have - x"$*"y or "x$*y" and there are no positional parameters, - the $* should expand into nothing. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - else - temp = (char *)NULL; - - /* We do not want to add quoted nulls to strings that are only - partially quoted; we can throw them away. The exception to - this is when we are going to be performing word splitting, - since we have to preserve a null argument if the next character - will cause word splitting. */ - if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) - continue; - - add_quoted_string: - - if (temp) - { - temp1 = temp; - temp = quote_string (temp); - free (temp1); - goto add_string; - } - else - { - /* Add NULL arg. */ - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - - /* break; */ - - case '\'': -#if 0 - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE)) -#else - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) -#endif - goto add_character; - - t_index = ++sindex; - temp = string_extract_single_quoted (string, &sindex); - - /* If the entire STRING was surrounded by single quotes, - then the string is wholly quoted. */ - quoted_state = (t_index == 1 && string[sindex] == '\0') - ? WHOLLY_QUOTED - : PARTIALLY_QUOTED; - - /* If all we had was '', it is a null expansion. */ - if (*temp == '\0') - { - free (temp); - temp = (char *)NULL; - } - else - remove_quoted_escapes (temp); /* ??? */ - - /* We do not want to add quoted nulls to strings that are only - partially quoted; such nulls are discarded. */ - if (temp == 0 && (quoted_state == PARTIALLY_QUOTED)) - continue; - - /* If we have a quoted null expansion, add a quoted NULL to istring. */ - if (temp == 0) - { - c = CTLNUL; - sindex--; /* add_character: label increments sindex */ - goto add_character; - } - else - goto add_quoted_string; - - /* break; */ - - default: - /* This is the fix for " $@ " */ - add_ifs_character: - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c))) - { - if (string[sindex]) /* from old goto dollar_add_string */ - sindex++; - if (c == 0) - { - c = CTLNUL; - goto add_character; - } - else - { -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1) - sindex--; - - if (MB_CUR_MAX > 1) - { - SADD_MBQCHAR_BODY(temp, string, sindex, string_size); - } - else -#endif - { - twochars[0] = CTLESC; - twochars[1] = c; - goto add_twochars; - } - } - } - - SADD_MBCHAR (temp, string, sindex, string_size); - - add_character: - RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size, - DEFAULT_ARRAY_SIZE); - istring[istring_index++] = c; - istring[istring_index] = '\0'; - - /* Next character. */ - sindex++; - } - } - -finished_with_string: - /* OK, we're ready to return. If we have a quoted string, and - quoted_dollar_at is not set, we do no splitting at all; otherwise - we split on ' '. The routines that call this will handle what to - do if nothing has been expanded. */ - - /* Partially and wholly quoted strings which expand to the empty - string are retained as an empty arguments. Unquoted strings - which expand to the empty string are discarded. The single - exception is the case of expanding "$@" when there are no - positional parameters. In that case, we discard the expansion. */ - - /* Because of how the code that handles "" and '' in partially - quoted strings works, we need to make ISTRING into a QUOTED_NULL - if we saw quoting characters, but the expansion was empty. - "" and '' are tossed away before we get to this point when - processing partially quoted strings. This makes "" and $xxx"" - equivalent when xxx is unset. We also look to see whether we - saw a quoted null from a ${} expansion and add one back if we - need to. */ - - /* If we expand to nothing and there were no single or double quotes - in the word, we throw it away. Otherwise, we return a NULL word. - The single exception is for $@ surrounded by double quotes when - there are no positional parameters. In that case, we also throw - the word away. */ - - if (*istring == '\0') - { - if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED)) - { - istring[0] = CTLNUL; - istring[1] = '\0'; - tword = make_bare_word (istring); - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - } - /* According to sh, ksh, and Posix.2, if a word expands into nothing - and a double-quoted "$@" appears anywhere in it, then the entire - word is removed. */ - else if (quoted_state == UNQUOTED || quoted_dollar_at) - list = (WORD_LIST *)NULL; -#if 0 - else - { - tword = make_bare_word (istring); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - if (had_quoted_null && QUOTED_NULL (istring)) - tword->flags |= W_HASQUOTEDNULL; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - else - { - char *ifs_chars; - - ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL; - - /* If we have $@, we need to split the results no matter what. If - IFS is unset or NULL, string_list_dollar_at has separated the - positional parameters with a space, so we split on space (we have - set ifs_chars to " \t\n" above if ifs is unset). If IFS is set, - string_list_dollar_at has separated the positional parameters - with the first character of $IFS, so we split on $IFS. */ - if (has_dollar_at && ifs_chars) - list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); - else - { - tword = make_bare_word (istring); - if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) - tword->flags |= W_QUOTED; - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; - if (had_quoted_null && QUOTED_NULL (istring)) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - free (istring); - return (list); -} - -/* **************************************************************** */ -/* */ -/* Functions for Quote Removal */ -/* */ -/* **************************************************************** */ - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes or a here document. */ -char * -string_quote_removal (string, quoted) - char *string; - int quoted; -{ - size_t slen; - char *r, *result_string, *temp, *send; - int sindex, tindex, dquote; - unsigned char c; - DECLARE_MBSTATE; - - /* The result can be no longer than the original string. */ - slen = strlen (string); - send = string + slen; - - r = result_string = (char *)xmalloc (slen + 1); - - for (dquote = sindex = 0; c = string[sindex];) - { - switch (c) - { - case '\\': - c = string[++sindex]; - if (c == 0) - { - *r++ = '\\'; - break; - } - if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0) - *r++ = '\\'; - /* FALLTHROUGH */ - - default: - SCOPY_CHAR_M (r, string, send, sindex); - break; - - case '\'': - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) - { - *r++ = c; - sindex++; - break; - } - tindex = sindex + 1; - temp = string_extract_single_quoted (string, &tindex); - if (temp) - { - strcpy (r, temp); - r += strlen (r); - free (temp); - } - sindex = tindex; - break; - - case '"': - dquote = 1 - dquote; - sindex++; - break; - } - } - *r = '\0'; - return (result_string); -} - -#if 0 -/* UNUSED */ -/* Perform quote removal on word WORD. This allocates and returns a new - WORD_DESC *. */ -WORD_DESC * -word_quote_removal (word, quoted) - WORD_DESC *word; - int quoted; -{ - WORD_DESC *w; - char *t; - - t = string_quote_removal (word->word, quoted); - w = alloc_word_desc (); - w->word = t ? t : savestring (""); - return (w); -} - -/* Perform quote removal on all words in LIST. If QUOTED is non-zero, - the members of the list are treated as if they are surrounded by - double quotes. Return a new list, or NULL if LIST is NULL. */ -WORD_LIST * -word_list_quote_removal (list, quoted) - WORD_LIST *list; - int quoted; -{ - WORD_LIST *result, *t, *tresult, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - return (result); -} -#endif - -/******************************************* - * * - * Functions to perform word splitting * - * * - *******************************************/ - -void -setifs (v) - SHELL_VAR *v; -{ - char *t; - unsigned char uc; - - ifs_var = v; - ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; - ifs_firstc_len = 1; - } - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -char * -getifs () -{ - return ifs_value; -} - -/* This splits a single word into a WORD LIST on $IFS, but only if the word - is not quoted. list_string () performs quote removal for us, even if we - don't do any splitting. */ -WORD_LIST * -word_split (w, ifs_chars) - WORD_DESC *w; - char *ifs_chars; -{ - WORD_LIST *result; - - if (w) - { - char *xifs; - - xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars; - result = list_string (w->word, xifs, w->flags & W_QUOTED); - } - else - result = (WORD_LIST *)NULL; - - return (result); -} - -/* Perform word splitting on LIST and return the RESULT. It is possible - to return (WORD_LIST *)NULL. */ -static WORD_LIST * -word_list_split (list) - WORD_LIST *list; -{ - WORD_LIST *result, *t, *tresult, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - return (result); -} - -/************************************************** - * * - * Functions to expand an entire WORD_LIST * - * * - **************************************************/ - -/* Do any word-expansion-specific cleanup and jump to top_level */ -static void -exp_jump_to_top_level (v) - int v; -{ - set_pipestatus_from_exit (last_command_exit_value); - - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - assigning_in_environment = 0; - - if (parse_and_execute_level == 0) - top_level_cleanup (); /* from sig.c */ - - jump_to_top_level (v); -} - -/* Put NLIST (which is a WORD_LIST * of only one element) at the front of - ELIST, and set ELIST to the new list. */ -#define PREPEND_LIST(nlist, elist) \ - do { nlist->next = elist; elist = nlist; } while (0) - -/* Separate out any initial variable assignments from TLIST. If set -k has - been executed, remove all assignment statements from TLIST. Initial - variable assignments and other environment assignments are placed - on SUBST_ASSIGN_VARLIST. */ -static WORD_LIST * -separate_out_assignments (tlist) - WORD_LIST *tlist; -{ - register WORD_LIST *vp, *lp; - - if (tlist == 0) - return ((WORD_LIST *)NULL); - - if (subst_assign_varlist) - dispose_words (subst_assign_varlist); /* Clean up after previous error */ - - subst_assign_varlist = (WORD_LIST *)NULL; - vp = lp = tlist; - - /* Separate out variable assignments at the start of the command. - Loop invariant: vp->next == lp - Loop postcondition: - lp = list of words left after assignment statements skipped - tlist = original list of words - */ - while (lp && (lp->word->flags & W_ASSIGNMENT)) - { - vp = lp; - lp = lp->next; - } - - /* If lp != tlist, we have some initial assignment statements. - We make SUBST_ASSIGN_VARLIST point to the list of assignment - words and TLIST point to the remaining words. */ - if (lp != tlist) - { - subst_assign_varlist = tlist; - /* ASSERT(vp->next == lp); */ - vp->next = (WORD_LIST *)NULL; /* terminate variable list */ - tlist = lp; /* remainder of word list */ - } - - /* vp == end of variable list */ - /* tlist == remainder of original word list without variable assignments */ - if (!tlist) - /* All the words in tlist were assignment statements */ - return ((WORD_LIST *)NULL); - - /* ASSERT(tlist != NULL); */ - /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */ - - /* If the -k option is in effect, we need to go through the remaining - words, separate out the assignment words, and place them on - SUBST_ASSIGN_VARLIST. */ - if (place_keywords_in_env) - { - WORD_LIST *tp; /* tp == running pointer into tlist */ - - tp = tlist; - lp = tlist->next; - - /* Loop Invariant: tp->next == lp */ - /* Loop postcondition: tlist == word list without assignment statements */ - while (lp) - { - if (lp->word->flags & W_ASSIGNMENT) - { - /* Found an assignment statement, add this word to end of - subst_assign_varlist (vp). */ - if (!subst_assign_varlist) - subst_assign_varlist = vp = lp; - else - { - vp->next = lp; - vp = lp; - } - - /* Remove the word pointed to by LP from TLIST. */ - tp->next = lp->next; - /* ASSERT(vp == lp); */ - lp->next = (WORD_LIST *)NULL; - lp = tp->next; - } - else - { - tp = lp; - lp = lp->next; - } - } - } - return (tlist); -} - -#define WEXP_VARASSIGN 0x001 -#define WEXP_BRACEEXP 0x002 -#define WEXP_TILDEEXP 0x004 -#define WEXP_PARAMEXP 0x008 -#define WEXP_PATHEXP 0x010 - -/* All of the expansions, including variable assignments at the start of - the list. */ -#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the expansions except variable assignments at the start of - the list. */ -#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP) - -/* All of the `shell expansions': brace expansion, tilde expansion, parameter - expansion, command substitution, arithmetic expansion, word splitting, and - quote removal. */ -#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP) - -/* Take the list of words in LIST and do the various substitutions. Return - a new list of words which is the expanded list, and without things like - variable assignments. */ - -WORD_LIST * -expand_words (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_ALL)); -} - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -WORD_LIST * -expand_words_no_vars (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_NOVARS)); -} - -WORD_LIST * -expand_words_shellexp (list) - WORD_LIST *list; -{ - return (expand_word_list_internal (list, WEXP_SHELLEXP)); -} - -static WORD_LIST * -glob_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - char **glob_array, *temp_string; - register int glob_index; - WORD_LIST *glob_list, *output_list, *disposables, *next; - WORD_DESC *tword; - - output_list = disposables = (WORD_LIST *)NULL; - glob_array = (char **)NULL; - while (tlist) - { - /* For each word, either globbing is attempted or the word is - added to orig_list. If globbing succeeds, the results are - added to orig_list and the word (tlist) is added to the list - of disposable words. If globbing fails and failed glob - expansions are left unchanged (the shell default), the - original word is added to orig_list. If globbing fails and - failed glob expansions are removed, the original word is - added to the list of disposable words. orig_list ends up - in reverse order and requires a call to REVERSE_LIST to - be set right. After all words are examined, the disposable - words are freed. */ - next = tlist->next; - - /* If the word isn't an assignment and contains an unquoted - pattern matching character, then glob it. */ - if ((tlist->word->flags & W_NOGLOB) == 0 && - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); - - /* Handle error cases. - I don't think we should report errors like "No such file - or directory". However, I would like to report errors - like "Read failed". */ - - if (glob_array == 0 || GLOB_FAILED (glob_array)) - { - glob_array = (char **)xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } - - /* Dequote the current word in case we have to use it. */ - if (glob_array[0] == NULL) - { - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - } - - /* Make the array into a word list. */ - glob_list = (WORD_LIST *)NULL; - for (glob_index = 0; glob_array[glob_index]; glob_index++) - { - tword = make_bare_word (glob_array[glob_index]); - tword->flags |= W_GLOBEXP; /* XXX */ - glob_list = make_word_list (tword, glob_list); - } - - if (glob_list) - { - output_list = (WORD_LIST *)list_append (glob_list, output_list); - PREPEND_LIST (tlist, disposables); - } - else if (fail_glob_expansion != 0) - { - last_command_exit_value = EXECUTION_FAILURE; - report_error (_("no match: %s"), tlist->word->word); - exp_jump_to_top_level (DISCARD); - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - PREPEND_LIST (tlist, output_list); - } - else - { - /* Failed glob expressions are removed. */ - PREPEND_LIST (tlist, disposables); - } - } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - PREPEND_LIST (tlist, output_list); - } - - strvec_dispose (glob_array); - glob_array = (char **)NULL; - - tlist = next; - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} - -#if defined (BRACE_EXPANSION) -static WORD_LIST * -brace_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - register char **expansions; - char *temp_string; - WORD_LIST *disposables, *output_list, *next; - WORD_DESC *w; - int eindex; - - for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next) - { - next = tlist->next; - - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { -/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/ - PREPEND_LIST (tlist, output_list); - continue; - } - - /* Only do brace expansion if the word has a brace character. If - not, just add the word list element to BRACES and continue. In - the common case, at least when running shell scripts, this will - degenerate to a bunch of calls to `mbschr', and then what is - basically a reversal of TLIST into BRACES, which is corrected - by a call to REVERSE_LIST () on BRACES when the end of TLIST - is reached. */ - if (mbschr (tlist->word->word, LBRACE)) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; temp_string = expansions[eindex]; eindex++) - { - w = alloc_word_desc (); - w->word = temp_string; - - /* If brace expansion didn't change the word, preserve - the flags. We may want to preserve the flags - unconditionally someday -- XXX */ - if (STREQ (temp_string, tlist->word->word)) - w->flags = tlist->word->flags; - else - w = make_word_flags (w, temp_string); - - output_list = make_word_list (w, output_list); - } - free (expansions); - - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - PREPEND_LIST (tlist, disposables); - } - else - PREPEND_LIST (tlist, output_list); - } - - if (disposables) - dispose_words (disposables); - - if (output_list) - output_list = REVERSE_LIST (output_list, WORD_LIST *); - - return (output_list); -} -#endif - -#if defined (ARRAY_VARS) -/* Take WORD, a compound associative array assignment, and internally run - 'declare -A w', where W is the variable name portion of WORD. */ -static int -make_internal_declare (word, option) - char *word; - char *option; -{ - int t; - WORD_LIST *wl; - WORD_DESC *w; - - w = make_word (word); - - t = assignment (w->word, 0); - w->word[t] = '\0'; - - wl = make_word_list (w, (WORD_LIST *)NULL); - wl = make_word_list (make_word (option), wl); - - return (declare_builtin (wl)); -} -#endif - -static WORD_LIST * -shell_expand_word_list (tlist, eflags) - WORD_LIST *tlist; - int eflags; -{ - WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list; - int expanded_something, has_dollar_at; - char *temp_string; - - /* We do tilde expansion all the time. This is what 1003.2 says. */ - new_list = (WORD_LIST *)NULL; - for (orig_list = tlist; tlist; tlist = next) - { - temp_string = tlist->word->word; - - next = tlist->next; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { - int t; - - if (tlist->word->flags & W_ASSIGNASSOC) - make_internal_declare (tlist->word->word, "-A"); - - t = do_word_assignment (tlist->word, 0); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC); - } -#endif - - expanded_something = 0; - expanded = expand_word_internal - (tlist->word, 0, 0, &has_dollar_at, &expanded_something); - - if (expanded == &expand_word_error || expanded == &expand_word_fatal) - { - /* By convention, each time this error is returned, - tlist->word->word has already been freed. */ - tlist->word->word = (char *)NULL; - - /* Dispose our copy of the original list. */ - dispose_words (orig_list); - /* Dispose the new list we're building. */ - dispose_words (new_list); - - last_command_exit_value = EXECUTION_FAILURE; - if (expanded == &expand_word_error) - exp_jump_to_top_level (DISCARD); - else - exp_jump_to_top_level (FORCE_EOF); - } - - /* Don't split words marked W_NOSPLIT. */ - if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0) - { - temp_list = word_list_split (expanded); - dispose_words (expanded); - } - else - { - /* If no parameter expansion, command substitution, process - substitution, or arithmetic substitution took place, then - do not do word splitting. We still have to remove quoted - null characters from the result. */ - word_list_remove_quoted_nulls (expanded); - temp_list = expanded; - } - - expanded = REVERSE_LIST (temp_list, WORD_LIST *); - new_list = (WORD_LIST *)list_append (expanded, new_list); - } - - if (orig_list) - dispose_words (orig_list); - - if (new_list) - new_list = REVERSE_LIST (new_list, WORD_LIST *); - - return (new_list); -} - -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg EFLAGS is a flags word controlling which expansions are - performed. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion, according - to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits - set, or for which no expansion is done, do not undergo word splitting. - Words with the W_NOGLOB bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, eflags) - WORD_LIST *list; - int eflags; -{ - WORD_LIST *new_list, *temp_list; - int tint; - - if (list == 0) - return ((WORD_LIST *)NULL); - - garglist = new_list = copy_word_list (list); - if (eflags & WEXP_VARASSIGN) - { - garglist = new_list = separate_out_assignments (new_list); - if (new_list == 0) - { - if (subst_assign_varlist) - { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_word_assignment (temp_list->word, 0); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - } - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - return ((WORD_LIST *)NULL); - } - } - - /* Begin expanding the words that remain. The expansions take place on - things that aren't really variable assignments. */ - -#if defined (BRACE_EXPANSION) - /* Do brace expansion on this word if there are any brace characters - in the string. */ - if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list) - new_list = brace_expand_word_list (new_list, eflags); -#endif /* BRACE_EXPANSION */ - - /* Perform the `normal' shell expansions: tilde expansion, parameter and - variable substitution, command substitution, arithmetic expansion, - and word splitting. */ - new_list = shell_expand_word_list (new_list, eflags); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ - if (new_list) - { - if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0) - /* Glob expand the word list unless globbing has been disabled. */ - new_list = glob_expand_word_list (new_list, eflags); - else - /* Dequote the words, because we're not performing globbing. */ - new_list = dequote_list (new_list); - } - - if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) - { - sh_wassign_func_t *assign_func; - int is_special_builtin, is_builtin_or_func; - - /* If the remainder of the words expand to nothing, Posix.2 requires - that the variable and environment assignments affect the shell's - environment. */ - assign_func = new_list ? assign_in_env : do_word_assignment; - tempenv_assign_error = 0; - - is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word))); - /* Posix says that special builtins exit if a variable assignment error - occurs in an assignment preceding it. */ - is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word)); - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - assigning_in_environment = (assign_func == assign_in_env); - tint = (*assign_func) (temp_list->word, is_builtin_or_func); - assigning_in_environment = 0; - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_assignment) - { - last_command_exit_value = EXECUTION_FAILURE; - if (interactive_shell == 0 && posixly_correct && is_special_builtin) - exp_jump_to_top_level (FORCE_EOF); - else - exp_jump_to_top_level (DISCARD); - } - else - tempenv_assign_error++; - } - } - - dispose_words (subst_assign_varlist); - subst_assign_varlist = (WORD_LIST *)NULL; - } - -#if 0 - tint = list_length (new_list) + 1; - RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16); - for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next) - glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0'; - glob_argv_flags[tint] = '\0'; -#endif - - return (new_list); -} diff --git a/test.c~ b/test.c~ deleted file mode 100644 index dbbd0d7a2..000000000 --- a/test.c~ +++ /dev/null @@ -1,852 +0,0 @@ -/* test.c - GNU test program (ksb and mjb) */ - -/* Modified to run with the GNU shell Apr 25, 1988 by bfox. */ - -/* Copyright (C) 1987-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 . -*/ - -/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching - binary operators. */ -/* #define PATTERN_MATCHING */ - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#include "bashtypes.h" - -#if !defined (HAVE_LIMITS_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H) -# include -#endif /* !_POSIX_VERSION */ -#include "posixstat.h" -#include "filecntl.h" -#include "stat-time.h" - -#include "bashintl.h" - -#include "shell.h" -#include "pathexp.h" -#include "test.h" -#include "builtins/common.h" - -#include - -#if !defined (STRLEN) -# define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) -#endif - -#if !defined (STREQ) -# define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0) -#endif /* !STREQ */ -#define STRCOLLEQ(a, b) ((a)[0] == (b)[0] && strcoll ((a), (b)) == 0) - -#if !defined (R_OK) -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 -#define F_OK 0 -#endif /* R_OK */ - -#define EQ 0 -#define NE 1 -#define LT 2 -#define GT 3 -#define LE 4 -#define GE 5 - -#define NT 0 -#define OT 1 -#define EF 2 - -/* The following few defines control the truth and false output of each stage. - TRUE and FALSE are what we use to compute the final output value. - SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. - Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */ -#define TRUE 1 -#define FALSE 0 -#define SHELL_BOOLEAN(value) (!(value)) - -#define TEST_ERREXIT_STATUS 2 - -static procenv_t test_exit_buf; -static int test_error_return; -#define test_exit(val) \ - do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) - -extern int sh_stat __P((const char *, struct stat *)); - -static int pos; /* The offset of the current argument in ARGV. */ -static int argc; /* The number of arguments present in ARGV. */ -static char **argv; /* The argument list. */ -static int noeval; - -static void test_syntax_error __P((char *, char *)) __attribute__((__noreturn__)); -static void beyond __P((void)) __attribute__((__noreturn__)); -static void integer_expected_error __P((char *)) __attribute__((__noreturn__)); - -static int unary_operator __P((void)); -static int binary_operator __P((void)); -static int two_arguments __P((void)); -static int three_arguments __P((void)); -static int posixtest __P((void)); - -static int expr __P((void)); -static int term __P((void)); -static int and __P((void)); -static int or __P((void)); - -static int filecomp __P((char *, char *, int)); -static int arithcomp __P((char *, char *, int, int)); -static int patcomp __P((char *, char *, int)); - -static void -test_syntax_error (format, arg) - char *format, *arg; -{ - builtin_error (format, arg); - test_exit (TEST_ERREXIT_STATUS); -} - -/* - * beyond - call when we're beyond the end of the argument list (an - * error condition) - */ -static void -beyond () -{ - test_syntax_error (_("argument expected"), (char *)NULL); -} - -/* Syntax error for when an integer argument was expected, but - something else was found. */ -static void -integer_expected_error (pch) - char *pch; -{ - test_syntax_error (_("%s: integer expression expected"), pch); -} - -/* Increment our position in the argument list. Check that we're not - past the end of the argument list. This check is supressed if the - argument is FALSE. Made a macro for efficiency. */ -#define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0) -#define unary_advance() do { advance (1); ++pos; } while (0) - -/* - * expr: - * or - */ -static int -expr () -{ - if (pos >= argc) - beyond (); - - return (FALSE ^ or ()); /* Same with this. */ -} - -/* - * or: - * and - * and '-o' or - */ -static int -or () -{ - int value, v2; - - value = and (); - if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) - { - advance (0); - v2 = or (); - return (value || v2); - } - - return (value); -} - -/* - * and: - * term - * term '-a' and - */ -static int -and () -{ - int value, v2; - - value = term (); - if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) - { - advance (0); - v2 = and (); - return (value && v2); - } - return (value); -} - -/* - * term - parse a term and return 1 or 0 depending on whether the term - * evaluates to true or false, respectively. - * - * term ::= - * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename - * '-'('G'|'L'|'O'|'S'|'N') filename - * '-t' [int] - * '-'('z'|'n') string - * '-o' option - * string - * string ('!='|'='|'==') string - * '-'(eq|ne|le|lt|ge|gt) - * file '-'(nt|ot|ef) file - * '(' ')' - * int ::= - * positive and negative integers - */ -static int -term () -{ - int value; - - if (pos >= argc) - beyond (); - - /* Deal with leading `not's. */ - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - value = 0; - while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = 1 - value; - } - - return (value ? !term() : term()); - } - - /* A paren-bracketed argument. */ - if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */ - { - advance (1); - value = expr (); - if (argv[pos] == 0) /* ( */ - test_syntax_error (_("`)' expected"), (char *)NULL); - else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */ - test_syntax_error (_("`)' expected, found %s"), argv[pos]); - advance (0); - return (value); - } - - /* are there enough arguments left that this could be dyadic? */ - if ((pos + 3 <= argc) && test_binop (argv[pos + 1])) - value = binary_operator (); - - /* Might be a switch type argument */ - else if (argv[pos][0] == '-' && argv[pos][2] == '\0') - { - if (test_unop (argv[pos])) - value = unary_operator (); - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - } - else - { - value = argv[pos][0] != '\0'; - advance (0); - } - - return (value); -} - -static int -stat_mtime (fn, st, ts) - char *fn; - struct stat *st; - struct timespec *ts; -{ - int r; - - r = sh_stat (fn, st); - if (r < 0) - return r; - *ts = get_stat_mtime (st); - return 0; -} - -static int -filecomp (s, t, op) - char *s, *t; - int op; -{ - struct stat st1, st2; - struct timespec ts1, ts2; - int r1, r2; - - if ((r1 = stat_mtime (s, &st1, &ts1)) < 0) - { - if (op == EF) - return (FALSE); - } - if ((r2 = stat_mtime (t, &st2, &ts2)) < 0) - { - if (op == EF) - return (FALSE); - } - - switch (op) - { - case OT: return (r1 < r2 || (r2 == 0 && timespec_cmp (ts1, ts2) < 0)); - case NT: return (r1 > r2 || (r1 == 0 && timespec_cmp (ts1, ts2) > 0)); - case EF: return (same_file (s, t, &st1, &st2)); - } - return (FALSE); -} - -static int -arithcomp (s, t, op, flags) - char *s, *t; - int op, flags; -{ - intmax_t l, r; - int expok; - - if (flags & TEST_ARITHEXP) - { - l = evalexp (s, &expok); - if (expok == 0) - return (FALSE); /* should probably longjmp here */ - r = evalexp (t, &expok); - if (expok == 0) - return (FALSE); /* ditto */ - } - else - { - if (legal_number (s, &l) == 0) - integer_expected_error (s); - if (legal_number (t, &r) == 0) - integer_expected_error (t); - } - - switch (op) - { - case EQ: return (l == r); - case NE: return (l != r); - case LT: return (l < r); - case GT: return (l > r); - case LE: return (l <= r); - case GE: return (l >= r); - } - - return (FALSE); -} - -static int -patcomp (string, pat, op) - char *string, *pat; - int op; -{ - int m; - - m = strmatch (pat, string, FNMATCH_EXTFLAG|FNMATCH_IGNCASE); - return ((op == EQ) ? (m == 0) : (m != 0)); -} - -int -binary_test (op, arg1, arg2, flags) - char *op, *arg1, *arg2; - int flags; -{ - int patmatch; - - patmatch = (flags & TEST_PATMATCH); - - if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0'))) - return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2)); - else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0') - { - if (shell_compatibility_level > 40 && flags & TEST_LOCALE) - return ((op[0] == '>') ? (strcoll (arg1, arg2) > 0) : (strcoll (arg1, arg2) < 0)); - else - return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0)); - } - else if (op[0] == '!' && op[1] == '=' && op[2] == '\0') - return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0)); - - - else if (op[2] == 't') - { - switch (op[1]) - { - case 'n': return (filecomp (arg1, arg2, NT)); /* -nt */ - case 'o': return (filecomp (arg1, arg2, OT)); /* -ot */ - case 'l': return (arithcomp (arg1, arg2, LT, flags)); /* -lt */ - case 'g': return (arithcomp (arg1, arg2, GT, flags)); /* -gt */ - } - } - else if (op[1] == 'e') - { - switch (op[2]) - { - case 'f': return (filecomp (arg1, arg2, EF)); /* -ef */ - case 'q': return (arithcomp (arg1, arg2, EQ, flags)); /* -eq */ - } - } - else if (op[2] == 'e') - { - switch (op[1]) - { - case 'n': return (arithcomp (arg1, arg2, NE, flags)); /* -ne */ - case 'g': return (arithcomp (arg1, arg2, GE, flags)); /* -ge */ - case 'l': return (arithcomp (arg1, arg2, LE, flags)); /* -le */ - } - } - - return (FALSE); /* should never get here */ -} - - -static int -binary_operator () -{ - int value; - char *w; - - w = argv[pos + 1]; - if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */ - ((w[0] == '>' || w[0] == '<') && w[1] == '\0') || /* <, > */ - (w[0] == '!' && w[1] == '=' && w[2] == '\0')) /* != */ - { - value = binary_test (w, argv[pos], argv[pos + 2], 0); - pos += 3; - return (value); - } - -#if defined (PATTERN_MATCHING) - if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0') - { - value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE); - pos += 3; - return (value); - } -#endif - - if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0) - { - test_syntax_error (_("%s: binary operator expected"), w); - /* NOTREACHED */ - return (FALSE); - } - - value = binary_test (w, argv[pos], argv[pos + 2], 0); - pos += 3; - return value; -} - -static int -unary_operator () -{ - char *op; - intmax_t r; - - op = argv[pos]; - if (test_unop (op) == 0) - return (FALSE); - - /* the only tricky case is `-t', which may or may not take an argument. */ - if (op[1] == 't') - { - advance (0); - if (pos < argc) - { - if (legal_number (argv[pos], &r)) - { - advance (0); - return (unary_test (op, argv[pos - 1])); - } - else - return (FALSE); - } - else - return (unary_test (op, "1")); - } - - /* All of the unary operators take an argument, so we first call - unary_advance (), which checks to make sure that there is an - argument, and then advances pos right past it. This means that - pos - 1 is the location of the argument. */ - unary_advance (); - return (unary_test (op, argv[pos - 1])); -} - -int -unary_test (op, arg) - char *op, *arg; -{ - intmax_t r; - struct stat stat_buf; - SHELL_VAR *v; - - switch (op[1]) - { - case 'a': /* file exists in the file system? */ - case 'e': - return (sh_stat (arg, &stat_buf) == 0); - - case 'r': /* file is readable? */ - return (sh_eaccess (arg, R_OK) == 0); - - case 'w': /* File is writeable? */ - return (sh_eaccess (arg, W_OK) == 0); - - case 'x': /* File is executable? */ - return (sh_eaccess (arg, X_OK) == 0); - - case 'O': /* File is owned by you? */ - return (sh_stat (arg, &stat_buf) == 0 && - (uid_t) current_user.euid == (uid_t) stat_buf.st_uid); - - case 'G': /* File is owned by your group? */ - return (sh_stat (arg, &stat_buf) == 0 && - (gid_t) current_user.egid == (gid_t) stat_buf.st_gid); - - case 'N': - return (sh_stat (arg, &stat_buf) == 0 && - stat_buf.st_atime <= stat_buf.st_mtime); - - case 'f': /* File is a file? */ - if (sh_stat (arg, &stat_buf) < 0) - return (FALSE); - - /* -f is true if the given file exists and is a regular file. */ -#if defined (S_IFMT) - return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0); -#else - return (S_ISREG (stat_buf.st_mode)); -#endif /* !S_IFMT */ - - case 'd': /* File is a directory? */ - return (sh_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode))); - - case 's': /* File has something in it? */ - return (sh_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0); - - case 'S': /* File is a socket? */ -#if !defined (S_ISSOCK) - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode)); -#endif /* S_ISSOCK */ - - case 'c': /* File is character special? */ - return (sh_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode)); - - case 'b': /* File is block special? */ - return (sh_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode)); - - case 'p': /* File is a named pipe? */ -#ifndef S_ISFIFO - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode)); -#endif /* S_ISFIFO */ - - case 'L': /* Same as -h */ - case 'h': /* File is a symbolic link? */ -#if !defined (S_ISLNK) || !defined (HAVE_LSTAT) - return (FALSE); -#else - return ((arg[0] != '\0') && - (lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode)); -#endif /* S_IFLNK && HAVE_LSTAT */ - - case 'u': /* File is setuid? */ - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0); - - case 'g': /* File is setgid? */ - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0); - - case 'k': /* File has sticky bit set? */ -#if !defined (S_ISVTX) - /* This is not Posix, and is not defined on some Posix systems. */ - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0); -#endif - - case 't': /* File fd is a terminal? */ - if (legal_number (arg, &r) == 0) - return (FALSE); - return ((r == (int)r) && isatty ((int)r)); - - case 'n': /* True if arg has some length. */ - return (arg[0] != '\0'); - - case 'z': /* True if arg has no length. */ - return (arg[0] == '\0'); - - case 'o': /* True if option `arg' is set. */ - return (minus_o_option_value (arg) == 1); - - case 'v': - v = find_variable (arg); - return (v && var_isset (v) ? TRUE : FALSE); - } - - /* We can't actually get here, but this shuts up gcc. */ - return (FALSE); -} - -/* Return TRUE if OP is one of the test command's binary operators. */ -int -test_binop (op) - char *op; -{ - if (op[0] == '=' && op[1] == '\0') - return (1); /* '=' */ - else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0') /* string <, > */ - return (1); - else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0') - return (1); /* `==' and `!=' */ -#if defined (PATTERN_MATCHING) - else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!')) - return (1); -#endif - else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0') - return (0); - else - { - if (op[2] == 't') - switch (op[1]) - { - case 'n': /* -nt */ - case 'o': /* -ot */ - case 'l': /* -lt */ - case 'g': /* -gt */ - return (1); - default: - return (0); - } - else if (op[1] == 'e') - switch (op[2]) - { - case 'q': /* -eq */ - case 'f': /* -ef */ - return (1); - default: - return (0); - } - else if (op[2] == 'e') - switch (op[1]) - { - case 'n': /* -ne */ - case 'g': /* -ge */ - case 'l': /* -le */ - return (1); - default: - return (0); - } - else - return (0); - } -} - -/* Return non-zero if OP is one of the test command's unary operators. */ -int -test_unop (op) - char *op; -{ - if (op[0] != '-' || op[2] != 0) - return (0); - - switch (op[1]) - { - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'k': case 'n': - case 'o': case 'p': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'z': - case 'G': case 'L': case 'O': case 'S': case 'N': - return (1); - } - - return (0); -} - -static int -two_arguments () -{ - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - return (argv[pos + 1][0] == '\0'); - else if (argv[pos][0] == '-' && argv[pos][2] == '\0') - { - if (test_unop (argv[pos])) - return (unary_operator ()); - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - } - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - - return (0); -} - -#define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o')) - -/* This could be augmented to handle `-t' as equivalent to `-t 1', but - POSIX requires that `-t' be given an argument. */ -#define ONE_ARG_TEST(s) ((s)[0] != '\0') - -static int -three_arguments () -{ - int value; - - if (test_binop (argv[pos+1])) - { - value = binary_operator (); - pos = argc; - } - else if (ANDOR (argv[pos+1])) - { - if (argv[pos+1][1] == 'a') - value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]); - else - value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); - pos = argc; - } - else if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = !two_arguments (); - } - else if (argv[pos][0] == '(' && argv[pos+2][0] == ')') - { - value = ONE_ARG_TEST(argv[pos+1]); - pos = argc; - } - else - test_syntax_error (_("%s: binary operator expected"), argv[pos+1]); - - return (value); -} - -/* This is an implementation of a Posix.2 proposal by David Korn. */ -static int -posixtest () -{ - int value; - - switch (argc - 1) /* one extra passed in */ - { - case 0: - value = FALSE; - pos = argc; - break; - - case 1: - value = ONE_ARG_TEST(argv[1]); - pos = argc; - break; - - case 2: - value = two_arguments (); - pos = argc; - break; - - case 3: - value = three_arguments (); - break; - - case 4: - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = !three_arguments (); - break; - } - /* FALLTHROUGH */ - default: - value = expr (); - } - - return (value); -} - -/* - * [: - * '[' expr ']' - * test: - * test expr - */ -int -test_command (margc, margv) - int margc; - char **margv; -{ - int value; - int code; - - USE_VAR(margc); - - code = setjmp (test_exit_buf); - - if (code) - return (test_error_return); - - argv = margv; - - if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0') - { - --margc; - - if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1])) - test_syntax_error (_("missing `]'"), (char *)NULL); - - if (margc < 2) - test_exit (SHELL_BOOLEAN (FALSE)); - } - - argc = margc; - pos = 1; - - if (pos >= argc) - test_exit (SHELL_BOOLEAN (FALSE)); - - noeval = 0; - value = posixtest (); - - if (pos != argc) - test_syntax_error (_("too many arguments"), (char *)NULL); - - test_exit (SHELL_BOOLEAN (value)); -} diff --git a/tests/RUN-ONE-TEST~ b/tests/RUN-ONE-TEST~ deleted file mode 100755 index 3efcf32d6..000000000 --- a/tests/RUN-ONE-TEST~ +++ /dev/null @@ -1,9 +0,0 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current -THIS_SH=$BUILD_DIR/bash -PATH=$PATH:$BUILD_DIR - -export THIS_SH PATH - -rm -f /tmp/xx - -/bin/sh "$@" diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig deleted file mode 100644 index c1f1e1991..000000000 --- a/tests/misc/regress/log.orig +++ /dev/null @@ -1,50 +0,0 @@ -:; ./shx - -sh: -<&$fd ok -nlbq Mon Aug 3 02:45:00 EDT 1992 -bang geoff -quote 712824302 -setbq defmsgid=<1992Aug3.024502.6176@host> -bgwait sleep done... wait 6187 - - -bash: -<&$fd ok -nlbq Mon Aug 3 02:45:09 EDT 1992 -bang geoff -quote 712824311 -setbq defmsgid=<1992Aug3.024512.6212@host> -bgwait sleep done... wait 6223 - - -ash: -<&$fd shx1: 4: Syntax error: Bad fd number -nlbq Mon Aug 3 02:45:19 EDT 1992 -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.` echo 024521 -bgwait sleep done... wait 6241 - - -ksh: -<&$fd ok -nlbq ./shx: 6248 Memory fault - core dumped -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.024530.6257@host> -bgwait no such job: 6265 -wait 6265 -sleep done... - -zsh: -<&$fd ok -nlbq Mon Aug 3 02:45:36 EDT 1992 -bang shx3: event not found: /s/ [4] -quote 712824337 -setbq defmsgid=<..6290@host> -bgwait shx7: unmatched " [9] -sleep done... -:; diff --git a/tests/misc/regress/shx.orig b/tests/misc/regress/shx.orig deleted file mode 100644 index 4b3bf2b82..000000000 --- a/tests/misc/regress/shx.orig +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh -for cmd in sh bash ash ksh zsh -do - echo - echo $cmd: - for demo in shx? - do - $cmd $demo - done -done diff --git a/trap.c~ b/trap.c~ deleted file mode 100644 index 2c0e4d066..000000000 --- a/trap.c~ +++ /dev/null @@ -1,1151 +0,0 @@ -/* trap.c -- Not the trap command, but useful functions for manipulating - those objects. The trap command is in builtins/trap.def. */ - -/* Copyright (C) 1987-2012 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 . -*/ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashtypes.h" -#include "bashansi.h" - -#include -#include - -#include "bashintl.h" - -#include "trap.h" - -#include "shell.h" -#include "flags.h" -#include "input.h" /* for save_token_state, restore_token_state */ -#include "jobs.h" -#include "signames.h" -#include "builtins.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#ifndef errno -extern int errno; -#endif - -/* Flags which describe the current handling state of a signal. */ -#define SIG_INHERITED 0x0 /* Value inherited from parent. */ -#define SIG_TRAPPED 0x1 /* Currently trapped. */ -#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */ -#define SIG_SPECIAL 0x4 /* Treat this signal specially. */ -#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */ -#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ -#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ -#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ - -#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP) - -/* An array of such flags, one for each signal, describing what the - shell will do with a signal. DEBUG_TRAP == NSIG; some code below - assumes this. */ -static int sigmodes[BASH_NSIG]; - -static void free_trap_command __P((int)); -static void change_signal __P((int, char *)); - -static void get_original_signal __P((int)); - -static int _run_trap_internal __P((int, char *)); - -static void free_trap_string __P((int)); -static void reset_signal __P((int)); -static void restore_signal __P((int)); -static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *)); - -/* Variables used here but defined in other files. */ -extern int last_command_exit_value; -extern int line_number; - -extern char *this_command_name; -extern sh_builtin_func_t *this_shell_builtin; -extern procenv_t wait_intr_buf; -extern int return_catch_flag, return_catch_value; -extern int subshell_level; -extern WORD_LIST *subst_assign_varlist; - -/* The list of things to do originally, before we started trapping. */ -SigHandler *original_signals[NSIG]; - -/* For each signal, a slot for a string, which is a command to be - executed when that signal is recieved. The slot can also contain - DEFAULT_SIG, which means do whatever you were going to do before - you were so rudely interrupted, or IGNORE_SIG, which says ignore - this signal. */ -char *trap_list[BASH_NSIG]; - -/* A bitmap of signals received for which we have trap handlers. */ -int pending_traps[NSIG]; - -/* Set to the number of the signal we're running the trap for + 1. - Used in execute_cmd.c and builtins/common.c to clean up when - parse_and_execute does not return normally after executing the - trap command (e.g., when `return' is executed in the trap command). */ -int running_trap; - -/* Set to last_command_exit_value before running a trap. */ -int trap_saved_exit_value; - -/* The (trapped) signal received while executing in the `wait' builtin */ -int wait_signal_received; - -int trapped_signal_received; - -#define GETORIGSIG(sig) \ - do { \ - original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \ - set_signal_handler (sig, original_signals[sig]); \ - if (original_signals[sig] == SIG_IGN) \ - sigmodes[sig] |= SIG_HARD_IGNORE; \ - } while (0) - -#define SETORIGSIG(sig,handler) \ - do { \ - original_signals[sig] = handler; \ - if (original_signals[sig] == SIG_IGN) \ - sigmodes[sig] |= SIG_HARD_IGNORE; \ - } while (0) - -#define GET_ORIGINAL_SIGNAL(sig) \ - if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ - GETORIGSIG(sig) - -void -initialize_traps () -{ - register int i; - - initialize_signames(); - - trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; - sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED; - original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; - - for (i = 1; i < NSIG; i++) - { - pending_traps[i] = 0; - trap_list[i] = (char *)DEFAULT_SIG; - sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */ - original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; - } - - /* Show which signals are treated specially by the shell. */ -#if defined (SIGCHLD) - GETORIGSIG (SIGCHLD); - sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); -#endif /* SIGCHLD */ - - GETORIGSIG (SIGINT); - sigmodes[SIGINT] |= SIG_SPECIAL; - -#if defined (__BEOS__) - /* BeOS sets SIGINT to SIG_IGN! */ - original_signals[SIGINT] = SIG_DFL; - sigmodes[SIGINT] &= ~SIG_HARD_IGNORE; -#endif - - GETORIGSIG (SIGQUIT); - sigmodes[SIGQUIT] |= SIG_SPECIAL; - - if (interactive) - { - GETORIGSIG (SIGTERM); - sigmodes[SIGTERM] |= SIG_SPECIAL; - } -} - -#ifdef DEBUG -/* Return a printable representation of the trap handler for SIG. */ -static char * -trap_handler_string (sig) - int sig; -{ - if (trap_list[sig] == (char *)DEFAULT_SIG) - return "DEFAULT_SIG"; - else if (trap_list[sig] == (char *)IGNORE_SIG) - return "IGNORE_SIG"; - else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) - return "IMPOSSIBLE_TRAP_HANDLER"; - else if (trap_list[sig]) - return trap_list[sig]; - else - return "NULL"; -} -#endif - -/* Return the print name of this signal. */ -char * -signal_name (sig) - int sig; -{ - char *ret; - - /* on cygwin32, signal_names[sig] could be null */ - ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL) - ? _("invalid signal number") - : signal_names[sig]; - - return ret; -} - -/* Turn a string into a signal number, or a number into - a signal number. If STRING is "2", "SIGINT", or "INT", - then (int)2 is returned. Return NO_SIG if STRING doesn't - contain a valid signal descriptor. */ -int -decode_signal (string, flags) - char *string; - int flags; -{ - intmax_t sig; - char *name; - - if (legal_number (string, &sig)) - return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG); - - /* A leading `SIG' may be omitted. */ - for (sig = 0; sig < BASH_NSIG; sig++) - { - name = signal_names[sig]; - if (name == 0 || name[0] == '\0') - continue; - - /* Check name without the SIG prefix first case sensitivly or - insensitively depending on whether flags includes DSIG_NOCASE */ - if (STREQN (name, "SIG", 3)) - { - name += 3; - - if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) - return ((int)sig); - else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) - return ((int)sig); - /* If we can't use the `SIG' prefix to match, punt on this - name now. */ - else if ((flags & DSIG_SIGPREFIX) == 0) - continue; - } - - /* Check name with SIG prefix case sensitively or insensitively - depending on whether flags includes DSIG_NOCASE */ - name = signal_names[sig]; - if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) - return ((int)sig); - else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) - return ((int)sig); - } - - return (NO_SIG); -} - -/* Non-zero when we catch a trapped signal. */ -static int catch_flag; - -void -run_pending_traps () -{ - register int sig; - int old_exit_value, *token_state; - WORD_LIST *save_subst_varlist; -#if defined (ARRAY_VARS) - ARRAY *ps; -#endif - - if (catch_flag == 0) /* simple optimization */ - return; - - catch_flag = trapped_signal_received = 0; - - /* Preserve $? when running trap. */ - old_exit_value = last_command_exit_value; -#if defined (ARRAY_VARS) - ps = save_pipestatus_array (); -#endif - - for (sig = 1; sig < NSIG; sig++) - { - /* XXX this could be made into a counter by using - while (pending_traps[sig]--) instead of the if statement. */ - if (pending_traps[sig]) - { - sigset_t set, oset; - - BLOCK_SIGNAL (sig, set, oset); - - if (sig == SIGINT) - { - run_interrupt_trap (); - CLRINTERRUPT; - } -#if defined (JOB_CONTROL) && defined (SIGCHLD) - else if (sig == SIGCHLD && - trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER && - (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0) - { - run_sigchld_trap (pending_traps[sig]); /* use as counter */ - } -#endif - else if (trap_list[sig] == (char *)DEFAULT_SIG || - trap_list[sig] == (char *)IGNORE_SIG || - trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) - { - /* This is possible due to a race condition. Say a bash - process has SIGTERM trapped. A subshell is spawned - using { list; } & and the parent does something and kills - the subshell with SIGTERM. It's possible for the subshell - to set pending_traps[SIGTERM] to 1 before the code in - execute_cmd.c eventually calls restore_original_signals - to reset the SIGTERM signal handler in the subshell. The - next time run_pending_traps is called, pending_traps[SIGTERM] - will be 1, but the trap handler in trap_list[SIGTERM] will - be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG). - Unless we catch this, the subshell will dump core when - trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is - usually 0x0. */ - internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"), - sig, trap_list[sig]); - if (trap_list[sig] == (char *)DEFAULT_SIG) - { - internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig)); - kill (getpid (), sig); - } - } - else - { - token_state = save_token_state (); - save_subst_varlist = subst_assign_varlist; - subst_assign_varlist = 0; - - parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); - restore_token_state (token_state); - free (token_state); - - subst_assign_varlist = save_subst_varlist; - } - - pending_traps[sig] = 0; - - UNBLOCK_SIGNAL (oset); - } - } - -#if defined (ARRAY_VARS) - restore_pipestatus_array (ps); -#endif - last_command_exit_value = old_exit_value; -} - -sighandler -trap_handler (sig) - int sig; -{ - int oerrno; - - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - { -#if defined (DEBUG) - internal_warning ("trap_handler: signal %d: signal not trapped", sig); -#endif - SIGRETURN (0); - } - - if ((sig >= NSIG) || - (trap_list[sig] == (char *)DEFAULT_SIG) || - (trap_list[sig] == (char *)IGNORE_SIG)) - programming_error (_("trap_handler: bad signal %d"), sig); - else - { - oerrno = errno; -#if defined (MUST_REINSTALL_SIGHANDLERS) -# if defined (JOB_CONTROL) && defined (SIGCHLD) - if (sig != SIGCHLD) -# endif /* JOB_CONTROL && SIGCHLD */ - set_signal_handler (sig, trap_handler); -#endif /* MUST_REINSTALL_SIGHANDLERS */ - - catch_flag = 1; - pending_traps[sig]++; - - trapped_signal_received = sig; - - if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin)) - { - wait_signal_received = sig; - longjmp (wait_intr_buf, 1); - } - - if (interrupt_immediately) - run_pending_traps (); - - errno = oerrno; - } - - SIGRETURN (0); -} - -int -first_pending_trap () -{ - register int i; - - for (i = 1; i < NSIG; i++) - if (pending_traps[i]) - return i; - return -1; -} - -#if defined (JOB_CONTROL) && defined (SIGCHLD) - -#ifdef INCLUDE_UNUSED -/* Make COMMAND_STRING be executed when SIGCHLD is caught. */ -void -set_sigchld_trap (command_string) - char *command_string; -{ - set_signal (SIGCHLD, command_string); -} -#endif - -/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD - is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel - to make sure that a SIGCHLD trap handler run via run_sigchld_trap can - reset the disposition to the default and not have the original signal - accidentally restored, undoing the user's command. */ -void -maybe_set_sigchld_trap (command_string) - char *command_string; -{ - if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER) - set_signal (SIGCHLD, command_string); -} - -/* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used - as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether - or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */ -void -set_impossible_sigchld_trap () -{ - restore_default_signal (SIGCHLD); - change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER); - sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */ -} - -/* Act as if we received SIGCHLD NCHILD times and increment - pending_traps[SIGCHLD] by that amount. This allows us to still run the - SIGCHLD trap once for each exited child. */ -void -queue_sigchld_trap (nchild) - int nchild; -{ - if (nchild > 0) - pending_traps[SIGCHLD] += nchild; -} -#endif /* JOB_CONTROL && SIGCHLD */ - -void -set_debug_trap (command) - char *command; -{ - set_signal (DEBUG_TRAP, command); -} - -void -set_error_trap (command) - char *command; -{ - set_signal (ERROR_TRAP, command); -} - -void -set_return_trap (command) - char *command; -{ - set_signal (RETURN_TRAP, command); -} - -#ifdef INCLUDE_UNUSED -void -set_sigint_trap (command) - char *command; -{ - set_signal (SIGINT, command); -} -#endif - -/* Reset the SIGINT handler so that subshells that are doing `shellsy' - things, like waiting for command substitution or executing commands - in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ -SigHandler * -set_sigint_handler () -{ - if (sigmodes[SIGINT] & SIG_HARD_IGNORE) - return ((SigHandler *)SIG_IGN); - - else if (sigmodes[SIGINT] & SIG_IGNORED) - return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ - - else if (sigmodes[SIGINT] & SIG_TRAPPED) - return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); - - /* The signal is not trapped, so set the handler to the shell's special - interrupt handler. */ - else if (interactive) /* XXX - was interactive_shell */ - return (set_signal_handler (SIGINT, sigint_sighandler)); - else - return (set_signal_handler (SIGINT, termsig_sighandler)); -} - -/* Return the correct handler for signal SIG according to the values in - sigmodes[SIG]. */ -SigHandler * -trap_to_sighandler (sig) - int sig; -{ - if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE)) - return (SIG_IGN); - else if (sigmodes[sig] & SIG_TRAPPED) - return (trap_handler); - else - return (SIG_DFL); -} - -/* Set SIG to call STRING as a command. */ -void -set_signal (sig, string) - int sig; - char *string; -{ - sigset_t set, oset; - - if (SPECIAL_TRAP (sig)) - { - change_signal (sig, savestring (string)); - if (sig == EXIT_TRAP && interactive == 0) -{ -itrace("set_signal: EXIT_TRAP: interactive_shell = %d interactive = %d subshell_environment = %d", interactive_shell, interactive, subshell_environment); - initialize_terminating_signals (); -} - return; - } - - /* A signal ignored on entry to the shell cannot be trapped or reset, but - no error is reported when attempting to do so. -- Posix.2 */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* Make sure we have original_signals[sig] if the signal has not yet - been trapped. */ - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - { - /* If we aren't sure of the original value, check it. */ - if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) - GETORIGSIG (sig); - if (original_signals[sig] == SIG_IGN) - return; - } - - /* Only change the system signal handler if SIG_NO_TRAP is not set. - The trap command string is changed in either case. The shell signal - handlers for SIGINT and SIGCHLD run the user specified traps in an - environment in which it is safe to do so. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - { - BLOCK_SIGNAL (sig, set, oset); - change_signal (sig, savestring (string)); - set_signal_handler (sig, trap_handler); - UNBLOCK_SIGNAL (oset); - } - else - change_signal (sig, savestring (string)); -} - -static void -free_trap_command (sig) - int sig; -{ - if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && - (trap_list[sig] != (char *)IGNORE_SIG) && - (trap_list[sig] != (char *)DEFAULT_SIG) && - (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) - free (trap_list[sig]); -} - -/* If SIG has a string assigned to it, get rid of it. Then give it - VALUE. */ -static void -change_signal (sig, value) - int sig; - char *value; -{ - if ((sigmodes[sig] & SIG_INPROGRESS) == 0) - free_trap_command (sig); - trap_list[sig] = value; - - sigmodes[sig] |= SIG_TRAPPED; - if (value == (char *)IGNORE_SIG) - sigmodes[sig] |= SIG_IGNORED; - else - sigmodes[sig] &= ~SIG_IGNORED; - if (sigmodes[sig] & SIG_INPROGRESS) - sigmodes[sig] |= SIG_CHANGED; -} - -static void -get_original_signal (sig) - int sig; -{ - /* If we aren't sure the of the original value, then get it. */ - if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) - GETORIGSIG (sig); -} - -void -get_all_original_signals () -{ - register int i; - - for (i = 1; i < NSIG; i++) - GET_ORIGINAL_SIGNAL (i); -} - -void -set_original_signal (sig, handler) - int sig; - SigHandler *handler; -{ - if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) - SETORIGSIG (sig, handler); -} - -/* Restore the default action for SIG; i.e., the action the shell - would have taken before you used the trap command. This is called - from trap_builtin (), which takes care to restore the handlers for - the signals the shell treats specially. */ -void -restore_default_signal (sig) - int sig; -{ - if (SPECIAL_TRAP (sig)) - { - if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) || - (sigmodes[sig] & SIG_INPROGRESS) == 0) - free_trap_command (sig); - trap_list[sig] = (char *)NULL; - sigmodes[sig] &= ~SIG_TRAPPED; - if (sigmodes[sig] & SIG_INPROGRESS) - sigmodes[sig] |= SIG_CHANGED; - return; - } - - GET_ORIGINAL_SIGNAL (sig); - - /* A signal ignored on entry to the shell cannot be trapped or reset, but - no error is reported when attempting to do so. Thanks Posix.2. */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* If we aren't trapping this signal, don't bother doing anything else. */ - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - return; - - /* Only change the signal handler for SIG if it allows it. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - set_signal_handler (sig, original_signals[sig]); - - /* Change the trap command in either case. */ - change_signal (sig, (char *)DEFAULT_SIG); - - /* Mark the signal as no longer trapped. */ - sigmodes[sig] &= ~SIG_TRAPPED; -} - -/* Make this signal be ignored. */ -void -ignore_signal (sig) - int sig; -{ - if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0)) - { - change_signal (sig, (char *)IGNORE_SIG); - return; - } - - GET_ORIGINAL_SIGNAL (sig); - - /* A signal ignored on entry to the shell cannot be trapped or reset. - No error is reported when the user attempts to do so. */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* If already trapped and ignored, no change necessary. */ - if (sigmodes[sig] & SIG_IGNORED) - return; - - /* Only change the signal handler for SIG if it allows it. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - set_signal_handler (sig, SIG_IGN); - - /* Change the trap command in either case. */ - change_signal (sig, (char *)IGNORE_SIG); -} - -/* Handle the calling of "trap 0". The only sticky situation is when - the command to be executed includes an "exit". This is why we have - to provide our own place for top_level to jump to. */ -int -run_exit_trap () -{ - char *trap_command; - int code, function_code, retval; -#if defined (ARRAY_VARS) - ARRAY *ps; -#endif - - trap_saved_exit_value = last_command_exit_value; -#if defined (ARRAY_VARS) - ps = save_pipestatus_array (); -#endif - function_code = 0; - - /* Run the trap only if signal 0 is trapped and not ignored, and we are not - currently running in the trap handler (call to exit in the list of - commands given to trap 0). */ - if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && - (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) - { - trap_command = savestring (trap_list[EXIT_TRAP]); - sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; - sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; - - retval = trap_saved_exit_value; - running_trap = 1; - - code = setjmp (top_level); - - /* If we're in a function, make sure return longjmps come here, too. */ - if (return_catch_flag) - function_code = setjmp (return_catch); - - if (code == 0 && function_code == 0) - { - reset_parser (); - parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); - } - else if (code == ERREXIT) - retval = last_command_exit_value; - else if (code == EXITPROG) - retval = last_command_exit_value; - else if (function_code != 0) - retval = return_catch_value; - else - retval = trap_saved_exit_value; - - running_trap = 0; - return retval; - } - -#if defined (ARRAY_VARS) - restore_pipestatus_array (ps); -#endif - return (trap_saved_exit_value); -} - -void -run_trap_cleanup (sig) - int sig; -{ - sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); -} - -/* Run a trap command for SIG. SIG is one of the signals the shell treats - specially. Returns the exit status of the executed trap command list. */ -static int -_run_trap_internal (sig, tag) - int sig; - char *tag; -{ - char *trap_command, *old_trap; - int trap_exit_value, *token_state; - volatile int save_return_catch_flag, function_code; - int flags; - procenv_t save_return_catch; - WORD_LIST *save_subst_varlist; -#if defined (ARRAY_VARS) - ARRAY *ps; -#endif - - trap_exit_value = function_code = 0; - /* Run the trap only if SIG is trapped and not ignored, and we are not - currently executing in the trap handler. */ - if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && - (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && - ((sigmodes[sig] & SIG_INPROGRESS) == 0)) - { - old_trap = trap_list[sig]; - sigmodes[sig] |= SIG_INPROGRESS; - sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ - trap_command = savestring (old_trap); - - running_trap = sig + 1; - trap_saved_exit_value = last_command_exit_value; -#if defined (ARRAY_VARS) - ps = save_pipestatus_array (); -#endif - - token_state = save_token_state (); - save_subst_varlist = subst_assign_varlist; - subst_assign_varlist = 0; - - /* If we're in a function, make sure return longjmps come here, too. */ - save_return_catch_flag = return_catch_flag; - if (return_catch_flag) - { - COPY_PROCENV (return_catch, save_return_catch); - function_code = setjmp (return_catch); - } - - flags = SEVAL_NONINT|SEVAL_NOHIST; - if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP) - flags |= SEVAL_RESETLINE; - if (function_code == 0) - parse_and_execute (trap_command, tag, flags); - - restore_token_state (token_state); - free (token_state); - - subst_assign_varlist = save_subst_varlist; - - trap_exit_value = last_command_exit_value; - last_command_exit_value = trap_saved_exit_value; -#if defined (ARRAY_VARS) - restore_pipestatus_array (ps); -#endif - running_trap = 0; - - sigmodes[sig] &= ~SIG_INPROGRESS; - - if (sigmodes[sig] & SIG_CHANGED) - { -#if 0 - /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in - the places where they can be changed using unwind-protects. For - example, look at execute_cmd.c:execute_function(). */ - if (SPECIAL_TRAP (sig) == 0) -#endif - free (old_trap); - sigmodes[sig] &= ~SIG_CHANGED; - } - - if (save_return_catch_flag) - { - return_catch_flag = save_return_catch_flag; - return_catch_value = trap_exit_value; - COPY_PROCENV (save_return_catch, return_catch); - if (function_code) - longjmp (return_catch, 1); - } - } - - return trap_exit_value; -} - -int -run_debug_trap () -{ - int trap_exit_value; - pid_t save_pgrp; - int save_pipe[2]; - - /* XXX - question: should the DEBUG trap inherit the RETURN trap? */ - trap_exit_value = 0; - if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)) - { -#if defined (JOB_CONTROL) - save_pgrp = pipeline_pgrp; - pipeline_pgrp = 0; - save_pipeline (1); -# if defined (PGRP_PIPE) - save_pgrp_pipe (save_pipe, 1); -# endif - stop_making_children (); -#endif - - trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap"); - -#if defined (JOB_CONTROL) - pipeline_pgrp = save_pgrp; - restore_pipeline (1); -# if defined (PGRP_PIPE) - close_pgrp_pipe (); - restore_pgrp_pipe (save_pipe); -# endif - if (pipeline_pgrp > 0) - give_terminal_to (pipeline_pgrp, 1); - notify_and_cleanup (); -#endif - -#if defined (DEBUGGER) - /* If we're in the debugger and the DEBUG trap returns 2 while we're in - a function or sourced script, we force a `return'. */ - if (debugging_mode && trap_exit_value == 2 && return_catch_flag) - { - return_catch_value = trap_exit_value; - longjmp (return_catch, 1); - } -#endif - } - return trap_exit_value; -} - -void -run_error_trap () -{ - if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0) - _run_trap_internal (ERROR_TRAP, "error trap"); -} - -void -run_return_trap () -{ - int old_exit_value; - -#if 0 - if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS)) - return; -#endif - - if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0) - { - old_exit_value = last_command_exit_value; - _run_trap_internal (RETURN_TRAP, "return trap"); - last_command_exit_value = old_exit_value; - } -} - -/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and - declared here to localize the trap functions. */ -void -run_interrupt_trap () -{ - _run_trap_internal (SIGINT, "interrupt trap"); -} - -/* Free all the allocated strings in the list of traps and reset the trap - values to the default. Intended to be called from subshells that want - to complete work done by reset_signal_handlers upon execution of a - subsequent `trap' command that changes a signal's disposition. We need - to make sure that we duplicate the behavior of - reset_or_restore_signal_handlers and not change the disposition of signals - that are set to be ignored. */ -void -free_trap_strings () -{ - register int i; - - for (i = 0; i < BASH_NSIG; i++) - { - if (trap_list[i] != (char *)IGNORE_SIG) - free_trap_string (i); - } - trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; -} - -/* Free a trap command string associated with SIG without changing signal - disposition. Intended to be called from free_trap_strings() */ -static void -free_trap_string (sig) - int sig; -{ - change_signal (sig, (char *)DEFAULT_SIG); - sigmodes[sig] &= ~SIG_TRAPPED; -} - -/* Reset the handler for SIG to the original value but leave the trap string - in place. */ -static void -reset_signal (sig) - int sig; -{ - set_signal_handler (sig, original_signals[sig]); - sigmodes[sig] &= ~SIG_TRAPPED; -} - -/* Set the handler signal SIG to the original and free any trap - command associated with it. */ -static void -restore_signal (sig) - int sig; -{ - set_signal_handler (sig, original_signals[sig]); - change_signal (sig, (char *)DEFAULT_SIG); - sigmodes[sig] &= ~SIG_TRAPPED; -} - -static void -reset_or_restore_signal_handlers (reset) - sh_resetsig_func_t *reset; -{ - register int i; - - /* Take care of the exit trap first */ - if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) - { - sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; - if (reset != reset_signal) - { - free_trap_command (EXIT_TRAP); - trap_list[EXIT_TRAP] = (char *)NULL; - } - } - - for (i = 1; i < NSIG; i++) - { - if (sigmodes[i] & SIG_TRAPPED) - { - if (trap_list[i] == (char *)IGNORE_SIG) - set_signal_handler (i, SIG_IGN); - else - (*reset) (i); - } - else if (sigmodes[i] & SIG_SPECIAL) - (*reset) (i); - } - - /* Command substitution and other child processes don't inherit the - debug, error, or return traps. If we're in the debugger, and the - `functrace' or `errtrace' options have been set, then let command - substitutions inherit them. Let command substitution inherit the - RETURN trap if we're in the debugger and tracing functions. */ - if (function_trace_mode == 0) - { - sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED; - sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED; - } - if (error_trace_mode == 0) - sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED; -} - -/* Reset trapped signals to their original values, but don't free the - trap strings. Called by the command substitution code and other places - that create a "subshell environment". */ -void -reset_signal_handlers () -{ - reset_or_restore_signal_handlers (reset_signal); -} - -/* Reset all trapped signals to their original values. Signals set to be - ignored with trap '' SIGNAL should be ignored, so we make sure that they - are. Called by child processes after they are forked. */ -void -restore_original_signals () -{ - reset_or_restore_signal_handlers (restore_signal); -} - -/* If a trap handler exists for signal SIG, then call it; otherwise just - return failure. Returns 1 if it called the trap handler. */ -int -maybe_call_trap_handler (sig) - int sig; -{ - /* Call the trap handler for SIG if the signal is trapped and not ignored. */ - if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) - { - switch (sig) - { - case SIGINT: - run_interrupt_trap (); - break; - case EXIT_TRAP: - run_exit_trap (); - break; - case DEBUG_TRAP: - run_debug_trap (); - break; - case ERROR_TRAP: - run_error_trap (); - break; - default: - trap_handler (sig); - break; - } - return (1); - } - else - return (0); -} - -int -signal_is_trapped (sig) - int sig; -{ - return (sigmodes[sig] & SIG_TRAPPED); -} - -int -signal_is_pending (sig) - int sig; -{ - return (pending_traps[sig]); -} - -int -signal_is_special (sig) - int sig; -{ - return (sigmodes[sig] & SIG_SPECIAL); -} - -int -signal_is_ignored (sig) - int sig; -{ - return (sigmodes[sig] & SIG_IGNORED); -} - -int -signal_is_hard_ignored (sig) - int sig; -{ - return (sigmodes[sig] & SIG_HARD_IGNORE); -} - -void -set_signal_ignored (sig) - int sig; -{ - sigmodes[sig] |= SIG_HARD_IGNORE; - original_signals[sig] = SIG_IGN; -} - -int -signal_in_progress (sig) - int sig; -{ - return (sigmodes[sig] & SIG_INPROGRESS); -} -- 2.47.2