From 947f04912e4715e7a9df526cd99412bffa729368 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Tue, 27 Jan 2015 11:10:49 -0500 Subject: [PATCH] commit bash-20150116 snapshot --- CWRU/CWRU.chlog | 64 + CWRU/CWRU.chlog~ | 7901 +++++++++++++++++++ CWRU/POSIX.NOTES.old | 82 + CWRU/old/set.def.save | 544 ++ CWRU/save/unwind_prot.h.save | 50 + bashhist.c | 2 + bashline.c | 4 + bashline.c~ | 4280 +++++++++++ builtins/complete.def | 1 + builtins/complete.def~ | 874 +++ builtins/read.def | 2 + cross-build/cygwin32.cache.old | 42 + doc/FAQ.orig | 1745 +++++ doc/aosa-bash.pdf.old | Bin 0 -> 153472 bytes doc/bash.1 | 7 +- doc/bash.1~ | 10482 ++++++++++++++++++++++++++ doc/version.texi | 4 +- doc/version.texi~ | 11 + examples/loadables/Makefile.in.save | 238 + execute_cmd.c | 2 + jobs.c | 1 + jobs.c~ | 4545 +++++++++++ lib/readline/complete.c | 5 +- lib/readline/doc/Makefile.old | 76 + lib/readline/doc/rluser.texi | 3 + lib/readline/doc/rluser.texi~ | 2301 ++++++ lib/readline/funmap.c | 1 + lib/readline/funmap.c~ | 267 + lib/readline/isearch.c | 10 +- lib/readline/kill.c | 34 + lib/readline/kill.c~ | 744 ++ lib/readline/readline.h | 1 + lib/readline/readline.h~ | 933 +++ lib/readline/signals.c~ | 709 ++ lib/readline/vi_mode.c~ | 2217 ++++++ pcomplete.c | 2 + pcomplete.c~ | 1667 ++++ pcomplete.h | 1 + pcomplete.h~ | 164 + po/._fr.po | Bin 4096 -> 4096 bytes redir.c | 5 +- tests/RUN-ONE-TEST | 2 +- tests/misc/regress/log.orig | 50 + tests/misc/regress/shx.orig | 10 + 44 files changed, 40075 insertions(+), 8 deletions(-) create mode 100644 CWRU/CWRU.chlog~ create mode 100644 CWRU/POSIX.NOTES.old create mode 100644 CWRU/old/set.def.save create mode 100644 CWRU/save/unwind_prot.h.save create mode 100644 bashline.c~ create mode 100644 builtins/complete.def~ create mode 100644 cross-build/cygwin32.cache.old create mode 100644 doc/FAQ.orig create mode 100644 doc/aosa-bash.pdf.old create mode 100644 doc/bash.1~ create mode 100644 doc/version.texi~ create mode 100644 examples/loadables/Makefile.in.save create mode 100644 jobs.c~ create mode 100644 lib/readline/doc/Makefile.old create mode 100644 lib/readline/doc/rluser.texi~ create mode 100644 lib/readline/funmap.c~ create mode 100644 lib/readline/kill.c~ create mode 100644 lib/readline/readline.h~ create mode 100644 lib/readline/signals.c~ create mode 100644 lib/readline/vi_mode.c~ create mode 100644 pcomplete.c~ create mode 100644 pcomplete.h~ create mode 100644 tests/misc/regress/log.orig create mode 100644 tests/misc/regress/shx.orig diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5987a71a2..59157ae82 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -7838,3 +7838,67 @@ bashhist.c history expansion character should be skipped because, for instance, it is in a command substitution. Fixes issue reported by Zigmund.Ozean@zig-home.localdomain + + 1/14 + ---- +lib/readline/isearch.c + - _rl_isearch_dispatch: if we are in a multibyte locale, make sure to use + _rl_find_prev_mbchar when trying to delete characters from the search + string, instead of just chopping off the previous byte. Fixes bug + reported by Kyrylo Shpytsya + +lib/readline/complete.c + - rl_filename_completion_function: if we tilde-expand `dirname', make + sure we use the expanded result instead of throwing it away for the + quote-removed `users_dirname', which still has any leading tilde. + Fixes bug reported by Dave Rutherford + +execute_cmd.c + - select_query: if the read builtin doesn't return anything in REPLY, + return NULL (failure). Fixes bug reported by Etherial Raine + + +builtins/read.def + - read_builtin: if REPLY has the readonly or noassign attribute, return + failure + + 1/16 + ---- +redir.c + - redir_open: if open() returns -1/EINTR, check traps as well as + using QUIT to handle signals + + 1/18 + ---- +jobs.c + - wait_for: make sure queue_sigchld is set to 1 before unblocking + SIGCHLD if MUST_UNBLOCK_CHLD is defined + + 1/19 + ---- +pcomplete.h + - new progcomp option: COPT_NOSORT, means to not sort list of possible + completions + +pcomplete.c + - pcomp_set_readline_variables: if COPT_NOSORT set in compspec flags, + set rl_sort_completion_duplicates to 0 + +builtins/complete.def + - _compopt: new option value: -o nosort, sets COPT_NOSORT in compspec + option flags. Provides new -o nosort option for complete and compgen + +bashline.c + - attempt_shell_completion: make sure rl_sort_completion_matches is + set to 1 before completion is attempted; allow a compspec to turn + it off + +lib/readline/kill.c + - rl_vi_yank_pop: new function, vi-mode version of yank-pop. Original + code from Ian Kelling + +lib/readline/funmap.c + - `vi-yank-pop': bindable name mapped to rl_vi_yank_pop + +lib/readline/readline.h + - rl_vi_yank_pop: extern declaration diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ new file mode 100644 index 000000000..9bafa0462 --- /dev/null +++ b/CWRU/CWRU.chlog~ @@ -0,0 +1,7901 @@ + 2/14/2011 + --------- +[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 glob_asciirange is 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 +lib/sh/{clktck,fpurge,inet_aton,mailstat,oslib,pathcanon,pathphys,spell,strerror}.c + - make inclusion of dependent on HAVE_SYS_PARAM_H + consistently + + 8/6 + --- +lib/readline/histexpand.c + - history_expand_internal: now takes an additional argument saying + whether the history expansion occurs within a quoted string, set to + the open quote character + - history_expand_internal: use new argument instead of checking prev + char and initializing quoted_search_delimiter, pass qc directly to + get_history_event, where it allows a matching quote to terminate a + string defining an event + - history_expand: change single-quote handling code so that if + history_quotes_inhibit_expansion is 0, single quotes are treated + like double quotes + - history_expand: change call to history_expand_internal to pass new + argument of `"' if double-quoted string, `'' if single-quoted string; + this lets history_expand decide what is a quoted string and what + is not + + 8/7 + --- +configure.in + - AC_CANONICAL_BUILD: invoke for later use + +lib/readline/macro.c + - _rl_prev_macro_key: new function, inverse of _rl_next_macro_key: + backs up the index into the current macro by 1 + +lib/readline/rlprivate.h + - _rl_prev_macro_key: extern declaration + + +lib/readline/readline.c + - _rl_dispatch_subseq, _rl_subseq_result: don't call _rl_unget_char + if we're currently reading from a macro; call _rl_prev_macro_key + instead. Fixes bug reported by Clark Wang + + 8/13 + ---- +builtins/evalstring.c + - evalstring(): new function, wrapper around parse_and_execute. + make sure we handle cases where parse_and_execute can call `return' + and short-circuit without cleaning up properly. We call + parse_and_execute_cleanup() then jump to the previous-saved return + location + +builtins/common.h + - extern declaration for evalstring() + +builtins/eval.def + - eval_builtin: make sure we handle `eval " ... return"' in contexts + where `return' is valid by calling evalstring(). Fixes bug with + `eval return' in sourced files reported by Clark Wang + + +trap.c + - run_pending_traps: call evalstring instead of parse_and_execute. + XXX - still needs to handle saving and restoring token state in the + presence of `return'; could use unwind_protects for that + +builtins/mapfile.def + - run_callback: call evalstring instead of parse_and_execute + + 8/15 + ---- +bashline.c + - bash_filename_stat_hook: make sure we don't free local_dirname + before using it to canonicalize any expanded filename. Make sure + it always points to *dirname and only free it if we're replacing + it. + +lib/readline/complete.c + - append_to_match: make sure we call rl_filename_stat_hook with + newly-allocated memory to avoid problems with freeing it twice + + 8/17 + ---- +variables.c,config-top.h + - if ARRAY_EXPORT is defined to 1 when variables.c is compiled, the + code that allows indexed arrays to be exported is enabled and + included + + 8/19 + ---- +shell.c + - call start_debugger from main() only if dollar_vars[1] != 0 (close + enough to a non-interactive shell, since we can be interactive with + -i while running a shell script). Fixes oddity reported by + Techlive Zheng + + 8/20 + ---- +arrayfunc.c + - quote_array_assignment_chars: don't bother quoting if the word has + not been marked as an assignment (W_ASSIGNMENT) + - quote_array_assignment_chars: turn on W_NOGLOB in the word flags + so assignment statements don't undergo globbing. Partial fix for + problems reported by Dan Douglas + + 8/21 + ---- +command.h + - W_NOBRACE: new word flag that means to inhibit brace expansion + +subst.c + - brace_expand_word_list: suppress brace expansion for words with + W_NOBRACE flag + + 8/22 + ---- +builtins/read.def + - read_builtin: don't call dequote_string on what we've read, even if + we saw an escape character, unless (input_string && *input_string). + We may have escaped an IFS whitespace character. Fixes seg fault + reported by + +execute_cmd.c + - execute_command_internal: set the_printed_command_except trap when + about to execute a ( ... ) user subshell. For now, set it only if + ERR is trapped; can relax that later. Fixes bug reported by + Mike Frysinger + + 8/23 + ---- +jobs.c + - remove references to first_pid and pid_wrap, since we're not using + them for anything anymore + + 8/24 + ---- +subst.c + - changes for W_NOBRACE everywhere appropriate: so it can be displayed + for debugging, and passed out of expand_word_internal + +doc/{bash.1,bashref.texi} + - small changes to make it clearer that the = and == operators are + equivalent, and will cause pattern matching when used with [[. + From a question from Michal Soltys + +doc/bashref.texi + - some small formatting changes from Karl Berry + + 8/27 + ---- +lib/readline/doc/{history,rlman,rluserman}.texi + - some small formatting changes from Karl Berry + +arrayfunc.c + - assign_array_element_internal, assign_compound_array_list, + unbind_array_element, array_value_internal: changes to make + assignment statements to negative indices (a[-1]=2) and unsetting + array elements using negative indices (unset 'a[-1]') work. + From suggestions by Dennis Williamson + and Chris F. A. Johnson + +subst.c + - array_length_reference: changes to make length references to array + elements using negative indices (${#a[-1]}) work + + 8/28 + ---- +doc/{bash.1,bashref.texi} + - document new treatment of negative indices to indexed arrays when + assigning, referencing, calculating length, and unsetting + + 8/29 + ---- +shell.c + - show_shell_usage: add -l to list of shell invocation options (short + for --login). From Red Hat bug 852469 + +configure.ac + - renamed from configure.in, as latest autoconf versions want. Patches + Stefano Lattarini + +MANIFEST,Makefile.in,doc/bashref.texi,support/mkconffiles + - configure.in -> configure.ac + + 9/1 + --- + +parse.y + - read_token_word: allow words like {array[ind]} to be valid redirection + words for constructs like {x} + +lib/readline/display.c + - update_line: if the first difference between the old and new lines + is completely before any invisible characters in the prompt, we + should not adjust _rl_last_c_pos, since it's before any invisible + characters. Fixed in two places + - prompt_modechar: return a character indicating the editing mode: + emacs (@), vi command (:), or vi insert (+) + - _rl_reset_prompt: new function, just calls rl_expand_prompt. Will be + inlined, placeholder for more changes + - expand_prompt: if show-mode-in-prompt is enabled, add a character to + the front of the prompt indicating the editing mode, adjusting the + various variables as appropriate to keep track of the number of + visible characters and number of screen positions + +lib/readline/bind.c + - show-mode-in-prompt: new bindable boolean variable, shadowed by + _rl_show_mode_in_prompt variable + - hack_special_boolean_var: call _rl_reset_prompt when toggling or + setting show-mode-in-prompt + +lib/readline/readline.c + - readline_internal_setup: make sure the correct vi mode keymap is set + before expanding the prompt string for the first time + +lib/readline/misc.c + - rl_emacs_editing_mode: make sure to call _rl_reset_prompt if we're + showing the editing mode in the prompt + +lib/readline/rlprivate.h + - _rl_reset_prompt, _rl_show_mode_in_prompt: extern declarations + +lib/readline/vi_mode.c + - rl_vi_insertion_mode: call _rl_reset_prompt + - rl_vi_movement_mode: call _rl_reset_prompt. Finishes changes for + showing mode in prompt string, originally requested by Miroslav + Koskar and most recently by Jordan Michael + Ziegler + +doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} + - document new show-mode-in-prompt variable, off by default + + 9/3 + --- + +jobs.c + - set_childmax: new function, external mechanism for other parts of + the shell to set js.c_childmax, the number of saved exited child + statuses to remember +jobs.h + - set_childmax: extern declaration + +variables.c + - CHILD_MAX: new special variable, with sv_childmax function to + run when it changes. Setting CHILD_MAX to a value greater than + zero but less than some maximum (currently 8192) sets the number of + exited child statuses to remember. set_childmax (jobs.c) ensures + that the number does not drop below the posix-mandated minimum + (CHILD_MAX) + +doc/{bash.1,bashref.texi} + - CHILD_MAX: document new meaning and action when variable is set + + 9/5 + --- +redir.c + - redir_varassign: call stupidly_hack_special_variables after + assigning fd number to specified variable, so we can use constructs + like {BASH_XTRACEFD}>foo. Suggested by Pierre Gaston + + + 9/8 + --- +expr.c + - readtok: invalidate previous contents of `curlval' before freeing + and reallocating tokstr (which, chances are, will get the same + pointer as before and render curlval inconsistent). Fixes other + bug reported by Dan Douglas + + 9/9 + --- +lib/readline/complete.c + - rl_username_completion_function: protect call to setpwent() with + #ifdef (HAVE_GETPWENT)/#endif. Fixes bug reported by + Gerd Hofmann + +lib/readline/display.c + - rl_message: second and subsequent calls to rl_message can result in + local_prompt being overwritten with new values (e.g., from the + successive calls displaying the incremental search string). Need + to free before overwriting if it's not the same as the value saved + in saved_local_prompt. Fixes memory leak reported by + Wouter Vermaelen + +lib/readline/{terminal.c,rlprivate.h} + - move CUSTOM_REDISPLAY_FUNC and CUSTOM_INPUT_FUNC defines from + terminal.c to rlprivate.h so other files can use them + +expr.c + - expr_streval: if noeval is non-zero, just return 0 right away, + short-circuiting evaluation completely. readtok will leave curtok + set correctly without re-entering the evaluator at all. Rest of + fix for bug reported by Dan Douglas + + 9/11 + ---- + +parse.y + - parse_comsub: make sure the `reserved word ok in this context' flag + is preserved after we read `do' followed by whitespace. Fixes bug + reported by Benoit Vaugon + + 9/13 + ---- +configure.ac,config.h.in + - enable-direxpand-default: new configure option, turns the `direxpand' + shell option on by default + +bashline.c + - dircomplete_expand, dircomplete_expand_relpath: initialize to 1 if + DIRCOMPLETE_EXPAND_DEFAULT is defined and non-zero + +doc/bashref.texi + - enable-direxpand-default: document new configure option + + 9/14 + ---- +shell.c + - --protected: make option valid only when wordexp is compiled into + the shell. Fix from Roman Rakus + +configure.ac + - HP NonStop (*-nsk*): compile --without-bash-malloc. Change from + Joachim Schmitz + + 9/16 + ---- +subst.c,execute_cmd.c,lib/glob/sm_loop.c,lib/sh/shquote.c + - minor code cleanups from Joachim Schmitz + +lib/readline/colors.h + - workaround for HP NonStop compiler issue with from + Joachim Schmitz + + 9/17 + ---- +builtins/printf.def + - printf_builtin: handle localtime returning NULL, as can happen when + encountering overflow. Bug report and initial fix from + Eduardo A. Bustamante López + +doc/{bash.1,bashref.texi} + - emphasize that brace expansion using character ranges ({a..c}) acts + as if the C locale were in use. Prompted by message from + Marcel Giannelia + + 9/20 + ---- +lib/sh/wcsnwidth.c + - wcsnwidth: new function, variant of wcwidth, returns the number of + wide characters from a string that will be displayed to not exceed + a specified max column position + + 9/21 + ---- +builtins/help.def + - show_builtin_command_help: break code that displays the short-doc + for each builtin in two columns into a new function: dispcolumn + - wdispcolumn: multibyte-char version of dispcolumn; uses wide + chars and printf "%ls" format. Fixes problem reported by + Nguyá»n Thái Ngá»c Duy + + 9/22 + ---- +execute_cmd.c + - execute_disk_command: before running the command-not-found hook, + call kill_current_pipeline() to make sure we don't add processes + to an existing pipeline or wait for processes erroneously + + 9/23 + ---- +lib/readline/input.c + - rl_input_available_hook: new hook function, called from + _rl_input_available (or _rl_input_queued) to return whether or not + input is available wherever the input source is + +lib/readline/doc/rltech.texi + - rl_input_available_hook: document + + 9/27 + ---- +lib/glob/sm_loop.c: + - GMATCH: after one or more `*', an instance of ?(x) can match zero or + 1 times (unlike ?, which has to match one character). The old code + failed if it didn't match at least once. Fixes `a*?(x)' bug. + - GMATCH: if we hit the end of the search string, but not the end of + the pattern, and the rest of the pattern is something that can + match the NUL at the end of the search string, we should successfully + match. Fixes `a*!(x)' bug reported by + + 10/2 + ---- +command.h + - add c_lock member to coproc structure for future use to tell who is + manipulating it + +execute_cmd.c + - execute_coproc: block SIGCHLD while parent is forking coproc + process and adding pid to sh_coproc struct to avoid race condition + where child is reaped before the pid is assigned and the coproc is + never marked as having died. Fixes race condition identified by + Davide Baldini + - add assignments to c_lock member of struct coproc in various + functions that manipulate it; was used to identify race condition + - coproc_pidchk: don't call coproc_dispose to avoid using malloc and + other functions in a signal handler context + - coproc_dispose: call BLOCK_SIGNAL/UNBLOCK_SIGNAL for SIGCHLD while + manipulating the sh_coproc struct + + 10/6 + ---- +lib/readline/complete.c + - rl_display_match_list: if printing completions horizontally, don't + bother with spacing calculations if limit == 1, which means we are + printing one completion per line no matter what. Fixes bug + reported by David Kaasen + + 10/7 + ---- +builtins/declare.def + - declare_internal: add error checking for nameref attribute and + variable assignments: self-references, attempts to make an array + variable a nameref + +subst.c + - parameter_brace_expand: handle parameter_brace_expand_word returning + &expand_param_fatal or &expand_param_error and return the appropriate + error value + - parameter_brace_expand_word: if a nameref variable's value is not a + valid identifier, return an error + - param_expand: if a nameref variable's value is not a valid identifier, + return an error + +test.c + - unary_operator: add new -R variable, returns true if variable is set + and has the nameref attribute. From ksh93 + +builtins/test.def + - add -R to description of conditional commands for help test + +doc/{bash.1,bashref.texi} + - document new -R unary conditional operator + + 10/13 + ----- +trap.c + - check_signals_and_traps: new function, convenience function for the + rest of the shell to check for pending terminating and interrupt + signals, and to check for and process any pending traps + - any_signals_trapped: new function, returns non-zero if any signals + are trapped and -1 if not + +trap.h + - extern declaration for check_signals_and_traps + +bashline.c + - bashline_reset: make sure we reset the event hook + - bash_event_hook: call check_signals_and_traps instead of just + checking for terminating signals so we can run pending traps and + react to interrupts, and reset the event hook when we're done + + + 10/14 + ----- +trap.c + - trap_handler: if executing in a readline signal handler context, + call bashline_set_event_hook to install bash_event_hook to process + the signal (if bash cares about it) + +sig.c + - sigint_sighandler: call bashline_set_event_hook to set the event + hook if we're executing in a readline signal handler context + +lib/readline/input.c + - rl_getc: call RL_CHECK_SIGNALS if read returns -1/EINTR and the caught + signal is SIGINT or SIGQUIT rather than waiting until the next time + around the loop + - rl_getc: call rl_event_hook after calling RL_CHECK_SIGNALS to allow + an application signal handler to set the event hook in its own + signal handler (e.g., like bash trap_handler or sigint_sighandler) + + +parse.y + - yy_readline_get: don't set interrupt_immediately before we call + readline(). Inspired by report from lanshun zhou + + +input.c + - getc_with_restart: add call to run_pending_traps after call to + CHECK_TERMSIG + +lib/sh/zread.c + - zread: call check_signals_and_traps if read() returns -1/EINTR + instead of just ignoring the EINTR and deferring handling any + signal that generated it + +builtins/mapfile.def + - mapfile: don't set interrupt_immediately before calling zgetline() + (which uses zread internally) + +builtins/read.def + - read_builtin: don't set interrupt_immediately before calling zread + (moved code around so that it was only being set right around calls + to zread to avoid signal handler conflicts). Inspired by report + from lanshun zhou + - edit_line: don't set interrupt_immediately around call to readline() + - include shmbutil.h + - read_builtin: don't call read_mbchar unless is_basic(c) returns + false for the character we just read + + 10/15 + ----- +sig.c + - throw_to_top_level: if interrupt_state is non-zero, make sure that + last_command_exit_value reflects 128+SIGINT if it's not already + greater than 128 + + 10/20 + ----- +builtins/wait.def + - WAIT_RETURN: set wait_signal_received back to 0 for the potential + next call to wait + +quit.h + - CHECK_WAIT_INTR: macro to check whether trap_handler handled a + signal and set wait_signal_received; longjmp to wait_intr_buf in + that case + +jobs.c + - wait_for, waitchld: call CHECK_WAIT_INTR at the same places we call + CHECK_TERMSIG to check for terminating signals + - wait_sigint_handler: don't longjmp out of the wait builtin unless + interrupt_immediately is set; otherwise just SIGRETURN from the + handler + - wait_sigint_handler: if interrupt_immediately not set, but we are + executing in the wait builtin and SIGINT is not trapped, treat it + as a `normally received' SIGINT: restore the signal handler and + send SIGINT to ourselves + - waitchld: when in posix mode and running SIGCHLD traps, don't longjmp + to wait_intr_buf (and let wait be interrupted) if we're running from + a signal handler. Wait for CHECK_WAIT_INTR to do the longjmp. + run_pending_traps will run the SIGCHLD trap later + +nojobs.c + - reap_zombie_children, wait_for_single_pid, wait_for: call + CHECK_WAIT_INTR where we call CHECK_TERMSIG + - wait_sigint_handler: don't longjmp out of the wait builtin unless + interrupt_immediately is set; otherwise just SIGRETURN from the + handler + +trap.c + - trap_handler: make sure wait_signal_received is set if the wait + builtin is executing, and only longjmp if interrupt_immediately is + set. This whole set of fixes was prompted by report from + lanshun zhou + + 10/24 + ----- +lib/glob/glob.c + - glob_filename: only check directory_name for globbing chars if + it's of non-zero length + +lib/sh/strchrnul.c + - new simpler implementation + +subst.c + - command_substitute: call set_shellopts after turning off errexit + in subshells so it's reflected in $SHELLOPTS + + 11/7 + ---- +builtins/evalstring.c + - parse_and_execute: treat ERREXIT case like reader_loop does: set + variable_context to 0 before longjmping back to top_level. Don't + run the unwind-protect context to avoid side effects from popping + function contexts. Part of fix for problem reported by Nikolai + Kondrashov + +execute_cmd.c + - execute_simple_command: call unlink_fifo_list only if this is the + last element of a pipeline (or not in a pipeline), rather than for + every child. Fixes difference in behavior between /dev/fd and + FIFOs reported by Zev Weiss + - execute_null_command: do the same thing in the parent branch after + make_child + + 11/14 + ----- +subst.c + - parameter_brace_expand: a variable is null if it's special ($@, $*), + the expansion occurs within double quotes, and the expansion turns + into a quoted null. Fixes debian bug 692447 reported by + Matrosov Dmitriy + +jobs.c + - run_sigchld_trap: make sure `running_trap' sentinel is set + appropriately + - waitchld: only run the sigchld trap if we're not in a signal + handler, not running a trap, and executing the wait builtin. + Otherwise, queue for later handling. We still run one instance + of the trap handler per exited child. Bulk of fix for bug + reported by Elliott Forney + +trap.c + - queue_sigchld_trap: set catch_flag so run_pending_traps notices, + and set trapped_signal_received for completeness. Rest of fix + for bug reported by Elliott Forney + +lib/malloc/malloc.c + - block_signals: renamed to _malloc_block_signals, made public + - unblock_signals: renamed to _malloc_unblock_signals, made public + +lib/malloc/imalloc.h + - extern declarations for _malloc_{un,}block_signals + +lib/malloc/table.c + - mregister_alloc, mregister_free: block signals around table + manipulation + + 11/15 + ----- +trap.c + - run_pending_traps: set SIG_INPROGRESS flag around calls to + run_sigchld_handler so other parts of the shell know that the + SIGCHLD trap handler is executing + - run_pending_traps: if we get a situation where we are looking at + running a SIGCHLD trap but the trap string is IMPOSSIBLE_TRAP_HANDLER + and the SIG_INPROGRESS flag is set, just skip it. This is possible + if run_pending_traps is called from a SIGCHLD trap handler run by + run_sigchld_trap + +doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} + - corrected description of the effect of `set history-size 0'. Report + from Vesa-Matti J Kari + +include/stdc.h + - CPP_STRING: new define, replaces __STRING + +lib/malloc/{malloc.c,imalloc.h} + - replace __STRING with CPP_STRING + + 11/16 + ----- +lib/readline/bind.c + - sv_histsize: if argument evaluates to a value < 0, unstifle the + history + + 11/22 + ----- +redir.c + - do_redirection_internal: if we have REDIR_VARASSIGN set in the + redirection flags and we set up `redirector' using fcntl or dup2, + don't add a redirect to make sure it stays open. Let the + script programmer manage the file handle. Fixes bug reported by + Sam Liddicott + + 11/24 + ----- +jobs.c + - wait_for_any_job: new function, waits for an unspecified background + job to exit and returns its exit status. Returns -1 on no background + jobs or no children or other errors. Calls wait_for with new + sentinel value ANY_PID + - wait_for: changes to handle argument of ANY_PID: don't look up or + try to modify the child struct, only go through the wait loop once. + Return -1 if waitpid returns no children + +jobs.h + - ANY_PID: new define + +builtins/wait.def + - new option: -n. Means to wait for the next job and return its exit + status. Returns 127 if there are no background jobs (or no + children). Feature most recently requested by Elliott Forney + + +doc/{bash.1,bashref.texi} + - document new `wait -n' option + +execute_cmd.c + - execute_command_internal: save make_command_string () result in a + temp variable before calling savestring() on it; avoids evaluating + make_command_string() result twice. Fix from John E. Malmberg + + + 11/28 + ----- + +builtins/declare.def + - declare_internal: if an array variable is declared using `declare -a' + or `declare -A', but not assigned a value, set the `invisible' + attribute so the variable does not show up as set. Fix for bug + about variable initialization reported by Tim Friske + +builtins/{mapfile,read}.def + - after calling find_or_make_array_variable, make sure the invisible + flag is turned off, in case the variable was declared previously + using `declare -a' or `declare -A'. Side effect of above change to + declare_internal + +subst.c + - shell_expand_word_list: handle the W_ASSNGLOBAL flag and put -g into + the list of options passed to make_internal_declare as appropriate. + Fix for bug reported by Tim Friske + + 11/30 + ----- +test.c + - unary_op: make sure -v and -n check that the variable is not marked + as invisible before calling var_isset. Fix for bug reported by Tim + Friske + + 12/2 + ---- +subst.c + - process_substitute: turn off the `expanding_redir' flag, which + controls whether or not variables.c:find_variable_internal uses the + temporary environment to find variables. We want to use the + temp environment, since we don't have to worry about order of + evaluation in a subshell. Fixes bug reported by Andrey Borzenkov + + + 12/4 + ---- +lib/glob/glob.c + - glob_filename: changes to avoid null filenames and multiple entries + returned for patterns like **/** (globstar enabled). Fixes bug + reported by Ulf Magnusson + + 12/10 + ----- +lib/glob/glob.c + - glob_filename: finish up a series of changes to make globstar-style + globbing more efficient, avoid more duplicate filenames, and be more + compatible with other shells that implement it + o collapse a sequence of **/**/** to one ** + o note when the directory name is all ** or ends in ** so we + can treat it specially when the filename is ** + All inspired by report from Andrey Borzenkov + +lib/sh/zread.c + - zreadn: new function, like zread, but takes an additional argument + saying how many bytes to read into the local buffer. Can be used to + implement `read -N' without so many one-byte calls to zreadc. Code + from Mike Frysinger + + 12/12 + ----- +lib/glob/sm_loop.c + - PATSCAN (glob_patscan): if passed string already points to end of + pattern, return NULL immediately. Fixes problem with + extglob_skipname reported by Raphaël Droz + + 12/13 + ----- +execute_cmd.c + - execute_coproc: handle the command's exit status being inverted + (an oversight). Fixes bug reported by DJ Mills + and Andreas Schwab + + 12/14 + ----- +lib/readline/readline.c + - bind_arrow_keys_internal: add MINGW key bindings for Home, End, + Delete, and Insert keys. Fix from Pierre Muller + + +builtins/printf.def + - printf_builtin: '%()T' conversion: if there is no argument supplied, + behave as if -1 had been supplied (current time). ksh93-like feature + suggested by Clark Wang + +doc/{bash.1,bashref.texi} + - document new printf %()T default argument behavior + + 12/15 + ----- +lib/readline/display.c + - displaying_prompt_first_line: new variable, indicates whether or + not the first line of output is displaying the prompt. Always true + in normal mode, sometimes false in horizontal scrolling mode + - rl_redisplay: set displaying_prompt_first_line to true unless we + are in horizontal mode; set to false in horizontal mode if the left + margin of the displayed line is greater than the end of the prompt + string + - rl_redisplay: when in horizontal scroll mode, don't adjust + _rl_last_c_pos by the wrap offset unless the line is displaying + a prompt containing invisible chars + - update line: don't adjust _rl_last_c_pos by the wrap offset unless + the line is displaying a prompt containing invisible chars + - update_line: if shrinking the line by reducing the number of + displayed characters, but we have already moved the cursor to the + beginning of the line where the first difference starts, don't + try to delete characters + +builtins/read.def + - unbuffered_read: set to 2 if invoked as `read -N' + - if unbuffered_read is set to 2, compute the number of chars we + need to read and read that many with zreadn. Posix mode still + uses zreadintr. Code from Mike Frysinger + +doc/{bash.1,bashref.texi} + - read: make it clear that if read times out, it saves any input + read to that point into the variable arguments. Report from + Fiedler Roman + +subst.c + - command_substitute: change direct assignment of exit_immediately_on_error + to use change_flag ('e', FLAG_OFF) instead + +flags.c + - use errexit_flag as the variable modified by changes to the -e + option, reflect those changes to exit_immediately_on_error + +execute_cmd.c + - execute_builtin: new global variable, builtin_ignoring_errexit, set + to 0 by default and set to 1 if eval/source/command executing in a + context where -e should be ignored + - execute_builtin: set exit_immediately_on_error to errextit_flag + after executing eval/source/command in a context where -e should + be ignored + +flags.c + - if builtin_ignoring_errexit is set, changes to errexit_flag are + not reflected in the setting of exit_immediately_on_error. Fixes + bug reported by Robert Schiele + + 12/23 + ----- +include/posixjmp.h + - setjmp_nosigs: new define, call setjmp in such a way that it will + not manipulate the signal mask + +{expr,test,trap}.c + - setjmp_nosigs: call instead of setjmp; don't need to manipulate + signal mask + +builtins/read.def + - read_builtin: setjmp_nosigs: call instead of setjmp; don't need + to manipulate signal mask + +builtins/evalstring.c: + - parse_and_execute: setjmp_nosigs: call instead of setjmp; don't need + to manipulate signal mask + - parse_string: setjmp_nosigs: call instead of setjmp; don't need + to manipulate signal mask + - parse_and_execute: save and restore the signal mask if we get a + longjmp that doesn't cause us to return or exit (case DISCARD) + + 12/24 + ----- +general.c + - bash_tilde_expand: only set interrupt_immediately if there are no + signals trapped; we want to jump to top level if interrupted but + not run any trap commands + + 12/25 + ----- +jobs.c + - run_sigchld_trap: no longer set interrupt_immediately before calling + parse_and_execute, even if this is no longer run in a signal handler + context + +input.c + - getc_with_restart: add call to QUIT instead of CHECK_TERMSIG + +parse.y + - yy_stream_get: now that getc_with_restart calls QUIT, don't need to + set interrupt_immediately (already had call to run_pending_traps) + +execute_cmd.c + - execute_subshell_builtin_or_function,execute_function,execute_in_subshell: + setjmp_nosigs: call instead of setjmp when saving return_catch; don't + need to manipulate signal mask + - execute_subshell_builtin_or_function,execute_in_subshell: + setjmp_nosigs: call instead of setjmp where appropriate when saving + top_level; don't need to manipulate signal mask if we're going to + exit right away + +subst.c + - command_substitute: setjmp_nosigs: call instead of setjmp when saving + return_catch; don't need to manipulate signal mask + - command_substitute: setjmp_nosigs: call instead of setjmp where + appropriate when saving top_level; don't need to manipulate signal + mask if we're going to exit right away + +trap.c + - run_exit_trap: setjmp_nosigs: call instead of setjmp when saving + return_catch; don't need to manipulate signal mask + - run_exit_trap: setjmp_nosigs: call instead of setjmp where + appropriate when saving top_level; don't need to manipulate signal + mask if we're going to exit right away + - _run_trap_internal: setjmp_nosigs: call instead of setjmp when saving + return_catch; don't need to manipulate signal mask + +builtins/evalfile.c + - _evalfile: setjmp_nosigs: call instead of setjmp when saving + return_catch; don't need to manipulate signal mask + +builtins/evalstring.c + - evalstring: setjmp_nosigs: call instead of setjmp when saving + return_catch; don't need to manipulate signal mask + +shell.c + - main: setjmp_nosigs: call instead of setjmp where appropriate when + saving top_level; don't need to manipulate signal mask if we're + going to exit right away + - run_one_command: setjmp_nosigs: call instead of setjmp where + appropriate when saving top_level; don't need to manipulate signal + mask if we're going to exit right away + - run_wordexp: setjmp_nosigs: call instead of setjmp where + appropriate when saving top_level; don't need to manipulate signal + mask if we're going to exit right away + +eval.c + - reader_loop: save and restore the signal mask if we get a longjmp + that doesn't cause us to return or exit (case DISCARD) + + 12/26 + ----- +parse.y + - shell_input_line_{index,size,len}: now of type size_t; in some cases + the unsigned property makes a difference + - STRING_SAVER: saved_line_{size,index} now of type size_t + - shell_getc: don't allow shell_input_line to grow larger than SIZE_MAX; + lines longer than that are truncated until read sees a newline; + addresses theoretical buffer overflow described by Paul Eggert + + - set_line_mbstate: size_t changes like shell_getc + - shell_getc: if shell_input_line is larger than 32K, free it and + start over to avoid large memory allocations sticking around + +variables.c + - bind_global_variable: new function, binds value to a variable in + the global shell_variables table + +variables.h + - bind_global_variable: new extern declaration + +builtins/declare.def + - declare_internal: if -g given with name=value, but variable is not + found in the global variable table, make sure to call + bind_global_variable so the variable is created and modified at + global scope. Fixes a bug where declare -g x=y could modify `x' + at a previous function scope + +command.h + - W_ASSIGNARRAY: new word flag, compound indexed array assignment + +subst.h + - ASS_MKGLOBAL: new assignment flag, forcing global assignment even in + a function context, used by declare -g + +execute_cmd.c + - fix_assignment_words: set W_ASSIGNARRAY flag if -a option given to + declaration builtin + +subst.c + - do_assignment_internal: explicitly handle case where we are + executing in a function and we want to create a global array or + assoc variable + - shell_expand_word_list: call make_internal_declare if -a option + given to declaration builtin (W_ASSIGNARRAY); handle -g option with + it (W_ASSNGLOBAL). Fixes inconsistency noticed by Vicente Couce + Diaz , where declare -ag foo=(bar) could modify + array variable foo at previous function scope, not global scope + + 12/27 + ----- +bashline.c + - Minix needs the third argument to tputs to be a void funtion taking + an int argument, not an int-returning function. Fix from + John E. Malmberg as part of VMS bash port + + 12/29 + ----- +configure.ac,version.c,patchlevel.h + - bash-4.3-devel: new version, new shell compatibility level (43) + +subst.c + - parameter_brace_patsub: put the bash-4.2 code back in from the + change of 3/3 that runs the replacement string through quote + removal, make it dependent on shell_compatibility_level <= 42 + +builtins/shopt.def + - compat42: new shopt option + - set_compatibility_level: change logic to set and unset various + compat variables and shell_compatibility_level + +COMPAT + - new documentation for bash-4.3 compatibility changes + +doc/{bash.1,bashref.texi} + - compat42: document new shopt option + +builtins/shopt.def + - set_compatibility_opts: new function, sets the various shopt + compat variables based on the value of shell_compatibility_level + +builtins/common.h + - set_compatibility_opts: new extern declaration + +variables.c + - BASH_COMPAT: new special variable; sets the shell compatibility + level. Accepts values in decimal (4.2) or integer (42) form; + Unsetting variable, setting it to empty string, or setting it to + out-of-range value sets the shell's compatibility level to the + default for the current version. Valid values are 3.1/31 through + the current version + - sv_shcompat: new function implementing logic for BASH_COMPAT + +variables.h + - sv_shcompat: new extern declaration + +doc/{bash.1,bashref.texi} + - BASH_COMPAT: description of new variable + +lib/readline/complete.c + - _rl_colored_stats: default back to 0 for 4.3 release branch + + 1/5/2013 + -------- +quit.h + - remove spurious call to itrace in CHECK_WAIT_INTR + +bashline.c + - bash_event_hook: if we're going to jump to top_level, make sure we + clean up after readline() by calling rl_cleanup_after_signal(). + Fixes bug reported against devel branch by Raphaël Droz + + - bash_event_hook: reset the event hook before checking for signals + or traps in case we longjmp + +doc/{bash.1,bashref.texi} + - small additions to the set -e section to make it more clear that + contexts where -e is ignored extend to compound commands as well + as shell functions + +lib/readline/readline.h + - rl_signal_event_hook: new extern declaration + +lib/readline/input.c + - rl_signal_event_hook: new variable, hook function to call when a + function (currently just read(2)) is interrupted by a signal and + not restarted + - rl_getc: call rl_signal_event_hook instead of rl_event_hook + +lib/readline/doc/rltech.texi + - rl_signal_event_hook: document new function + +bashline.c + - changes to set rl_signal_event_hook instead of rl_event_hook + +lib/readline/readline.h + - change readline version numbers to 6.3 + + 1/6 + --- +doc/{bash.1,bashref.texi} + - a couple of changes to the descriptions of the ERR trap and its + effects based on a message from Rob Nagler + + 1/9 + --- +expr.c + - expassign: invalidate curlval before freeing and NULLing tokstr to + avoid aliasing issues. Fixes bug reported by Eduardo A. Bustamante + López and Dan Douglas + +braces.c + - array_concat: don't be so aggressive in trying to short-circuit. We + can only short-circuit if we have a single-element array where the + element is an empty string (array[0] == "" array[1] = 0x0). Existing + practice requires us to replicate arrays and prefix or append empty + strings. Fixes bug reported by Eduardo A. Bustamante López + + + 1/11 + ---- +execute_cmd.c + - execute_builtin: since mapfile uses evalstring() to run its callbacks + internally, just like eval, so it needs to handle the case where the + temp environment given to mapfile persists throughout the entire + set of callback commands. This might be a problem with trap also, but + trap isn't run in the same way. Fixes bug reported by Dan Douglas + + + 1/13 + ---- +redir.c + - redirection_error: before expanding the redirection word (if + expandable_redirection_filename returns true), disable command + substitution during expansion. Fixes bug reported by Dan Douglas + + +subst.c + - expand_word_internal: case '\\': if the next character is an IFS + character, and the expansion occurs within double quotes, and the + character is not one for which backslash retains its meaning, add + the (escaped) '\' and the (escaped) character. Fixes bug reported + by Dan Douglas + + 1/15 + ---- +builtins/cd.def + - cd_builtin: make sure call to internal_getopt handles -e option. + Fixes bug reported by + + 1/17 + ---- +subst.c + - expand_word_list_internal: make sure tempenv_assign_error is + initialized to 0 + +execute_cmd.c + - execute_simple_command: make sure tempenv_assign_error is reset to 0 + after it's tested to see if an error should force the shell to exit. + Fixes problem where a the failure of a tempenv assignment preceding + a non-special builtin `sticks' and causes the next special builtin + to exit the shell. From a discussion on bug-bash started by + douxin + + 1/20 + ---- +subst.c + - parameter_brace_expand_rhs: call stupidly_hack_special_variables + after assigning with ${param[:]=word} even if IFS is changing. + Suggested by Dan Douglas [TENTATIVE, needs work + on IFS side effects] + +command.h + - W_GLOBEXP (which was unused) is now W_SPLITSPACE (which isn't used + yet) + +{execute_cmd,subst,variables}.c + - removed all code that mentioned W_GLOBEXP + - removed mention of gnu_argv_flags and code that set it + + 1/22 + ---- +subst.c + - param_expand: set W_SPLITSPACE if we expand (unquoted) $* and + IFS is unset or null so we can be sure to split this on spaces + no matter what happens with IFS later + - expand_word_internal: note that param_expand returns W_SPLITSPACE + in the returned word flags and keep track of that state with + `split_on_spaces' + + 1/23 + ---- +subst.c + - expand_word_internal: if split_on_spaces is non-zero, make sure + we split `istring' on spaces and return the resultant word. The + previous expansions should have quoted spaces in the positional + parameters where necessary. Suggested by Dan Douglas + + +execute_cmd.c + - execute_command_internal: make sure any subshell forked to run a + group command or user subshell at the end of a pipeline runs any + EXIT trap it sets. Fixes debian bash bug 698411 + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=698411 + +subst.c + - shell_expand_word_list: fix code that creates args for and calls + make_internal_declare to avoid calling it twice (missing `else' + in 12/26 change) + - do_assignment_internal: fix code from 12/26 change to fix problem + where an existing assoc variable could be converted to an array + without checking `mkassoc' + + 1/24 + ---- +builtins/evalfile.c + - _evalfile: add missing `close (fd)' calls before returning to + avoid fd leaks. Bug and fix from Roman Rakus + + 1/25 + ---- +builtins/read.def + - read_builtin: don't try to play tricks with the top of the unwind- + protect stack after read gets a SIGALRM; save input_string to new + memory, run the stack, then restore input_string and assign the + variables. Part of fix for bug reported by konsolebox + ; the rest of the fix is with the changes in + trap and signal handling and doing away with interrupt_immediately + + 1/26 + ---- +redir.c + - redirection_expand, write_here_string, write_here_document: before + calling any of the word expansion functions, after setting + expanding_redir to 1 (which bypasses the temp environment in the + variable lookup functions), call sv_ifs to reset the cached IFS- + related variables set by subst.c:setifs(). This ensures that + redirections will not get any IFS values that are set in the + temporary environment, as Posix specifies. Then, after the word + expansions, after resetting expanding_redir to 0, call sv_ifs + again to make sure the cached IFS values are set from any + assignments in the temporary environment. We force executing_builtin + to 1 to `fool' the variable lookup functions into using any temp + environment, then reset it to its old value after sv_ifs returns. + This is what allows read() to use the (cached) IFS variables set + in the temp environment. Fixes inconsistency reported by Dan Douglas + + + 1/29 + ---- +lib/readline/display.c + - update_line: fix off-by-one error when updating vis_lbreaks array + in a multibyte locale that occurs when moving multibyte chars from + one line down to another. Bug report and fix from Egmont + Koblinger + + 1/30 + ---- +configure.ac + - changed version to 4.3-alpha + +redir.c + - redir_open: handle open returning -1/EINTR, which seems to happen + a lot with FIFOs and SIGCHLD, and call QUIT to handle other + signals that can interrupt open(2). Bug report and initial fix + from Mike Frysinger + + 1/31 + ---- +subst.c + - parameter_brace_expand: make sure to propagate the PF_ASSIGNRHS flag + to parameter_brace_expand_word + - parameter_brace_expand_word: make sure that if the PF_ASSIGNRHS flag + is set and we are expanding ${a[@]} or ${a[*]} we set quoted to + include Q_DOUBLE_QUOTES before calling array_value_internal, mirroring + what we do for $@ and $*. Fixes inconsistency reported by Dan + Douglas + +configure.ac + - use AC_CHECK_TOOL instead of AC_CHECK_PROG to check for ar, since it + will find $host-prefixed versions of utilities. Report and fix from + Mike Frysinger + +builtins/setattr.def + - set_var_attribute: check whether bind_variable (called when the + variable whose attributes are being modified is found in the temp + environment) just modified a read-only global variable, and don't + bother marking the temporary variable for propagation if so. The + propagation is superfluous and will result in a strange error + message + + 2/2 + --- +variables.c + - initialize_shell_variables: don't try to import function definitions + with invalid names from the environment if already in posix mode, + but create them as (invisible) exported variables so they pass + through the environment. Print an error message so user knows + what's wrong. Fixes bug reported by Tomas Trnka + + 2/9 + --- + +builtins/read.def + - sigalrm_seen, alrmbuf: now global so the rest of the shell (trap.c) + can use them + - sigalrm: just sets flag, no longer longjmps to alrmbuf; problem was + longjmp without manipulating signal mask, leaving SIGALRM blocked + +quit.h + - move CHECK_ALRM macro here from builtins/read.def so trap.c: + check_signals() can call it + +trap.c + - check_signals: add call to CHECK_ALRM before QUIT + - check_signals_and_traps: call check_signals() instead of including + CHECK_ALRM and QUIT inline. Integrating check for read builtin's + SIGALRM (where zread call to check_signals_and_traps can see it) + fixes problem reported by Mike Frysinger + + 2/12 + ---- +lib/glob/xmbsrtowcs.c + - xdupmbstowcs2: fixed but where end of string was not handled + correctly, causing loop to go past end of string in a bunch of cases. + Fixes bug reported by "Dashing" + + + 2/13 + ---- +builtins/pushd.def + - popd_builtin: treat any argument that isn't -n or of the form + [-+][[:digit:]]* as an error. Fixes problem reported by Bruce + Korb + + 2/14 + ---- +configure.ac + - add check for sig_atomic_t; already a placeholder for it in + config.h.in + + 2/15 + ---- +subst.c + - do_compound_assignment: don't call assign_compound_array_list with + a NULL variable in case make_local_xxx_variable returns NULL + (it will if you try to shadow a readonly or noassign variable). + Fixes bug reported by Richard Tollerton + + 2/16 + ---- +variables.c + - make_local_variable: print error messager if an attempt is made to + create a local variable shadowing a `noassign' variable. Previously + we just silently refused to do it + +trap.[ch] + - get_original_signal: now global so rest of the shell can use it + +sig.c + - initialize_shell_signals: install a signal handler for SIGTERM + that does nothing except set a sigterm_received flag instead of + ignoring it with SIG_IGN, as long as SIGTERM is not ignored when + the shell is started. Use get_original_signal early to get the + original handler, since we will do that later anyway + - set_signal_handler: if installing sigterm_sighandler as the SIGTERM + handler, make sure to add SA_RESTART flag to make it as close to + SIG_IGN as possible + +sig.h + - sigterm_sighandler: new extern declaration + +quit.h + - RESET_SIGTERM: set sigterm_receved to 0 + - CHECK_SIGTERM: check sigterm_received; if it's non-zero, treat it + as a fatal signal and call termsig_handler to exit the shell + +jobs.c + - make_child: call RESET_SIGTERM just before fork() so we can detect + if the child process received a SIGTERM before it's able to change + the signal handler back to what it was when the shell started + (presumably SIG_DFL). Only has effect if the shell installed + sigterm_sighandler for SIGTERM, interactive shells that were not + started with SIG_IGN as the SIGTERM handler + - make_child: call RESET_SIGTERM in the parent after fork() so the + rest of the shell won't react to it + +execute_cmd.c + - execute_simple_command: call CHECK_SIGTERM after make_child in child + to catch SIGTERM received after fork() and before restoring old + signal handlers + - execute_disk_command: call CHECK_SIGTERM after make_child in child + process after restoring old signal handlers and again just before + calling shell_execve. Fixes race condition observed by + Padraig Brady when testing with his `timeout' + program + +lib/readline/display.c + - open_some_spaces: new function, subset of insert_some_chars that just + opens up a specified number of spaces to be overwritten + - insert_some_spaces: now just calls to open_some_spaces followed by + _rl_output_some_chars + - update_line: use col_temp instead of recalculating it using + _rl_col_width in the case where we use more columns with fewer bytes + - update_line: use open_some_spaces and then output the right number + of chars instead of trying to print new characters then overwrite + existing characters in two separate calls. This includes removing + some dodgy code and making things simpler. Fix from Egmont + Koblinger + - use new variable `bytes_to_insert' instead of overloading temp in + some code blocks (nls - nfd, bytes that comprise the characters + different in the new line from the old) + + 2/18 + ---- +redir.c + - do_redirection_internal: add undoable redirection for the implicit + close performed by the <&n- and >&n- redirections. Fixes bug + reported by Stephane Chazelas + + 2/19 + ---- +sig.c + - termsig_handler: an interactive shell killed by SIGHUP and keeping + command history will try to save the shell history before exiting. + This is an attempt to preserve the save-history-when-the-terminal- + window-is-closed behavior + + 2/21 + ---- +braces.c + - brace_expand: if a sequence expansion fails (e.g. because the + integers overflow), treat that expansion as a simple string, including + the braces, and try to process any remainder of the string. The + remainder may include brace expansions. Derived from SuSE bug + 804551 example (https://bugzilla.novell.com/show_bug.cgi?id=804551) + + 2/23 + ---- +{quit,sig}.h,sig.c + - sigterm_received declaration now in sig.h; type is sig_atomic_t + - sigwinch_received type now sig_atomic_t + - sig.h includes bashtypes.h and if SIG_DFL not defined + (same logic as trap.h) to pick up sig_atomic_t + +unwind_prot.c + - include sig.h before quit.h (reverse order) + + 2/27 + ---- +builtins/shopt.def + - reset_shopt_options: make sure check_window_size is reset to the + default from config.h, not unconditionally to 0 + +jobs.[ch] + - last_made_pid, last_asynchronous_pid: now volatile. Change from SuSE + +jobs.c + - wait_for: if we're using sigaction to install a handler for SIGCHLD, + make sure we specify SA_RESTART + +lib/{tilde,readline}/shell.c + - get_home_dir: instead of looking in the password file every time, + look once and cache the result + +sig.[ch] + - sigwinch_received, sigterm_received: now `volatile' qualified + +sig.c,quit.h + - interrupt_state,terminating_signal: now sig_atomic_t + + 3/1 + --- +MANIFEST,examples/* + - removed around 120 files without FSF copyrights; requested by + Karl Berry in early January + + 3/2 + --- +lib/malloc/malloc.c + - morecore: only check whether SIGCHLD is trapped if SIGCHLD is defined + +doc/bashref.texi + - Fixed most of the examples in the GNU Parallel section to use better + shell idioms following complaints on bug-bash; added a couple of + examples and smoothed out the text + +quit.h + - include "sig.h" for sig_atomic_t + +lib/readline/display.c + - update_line: when inserting one or more characters at the end of + the display line in a non-multibyte environment, just write from the + first difference to the end of the line and return. We don't have + to adjust _rl_last_c_pos. This is needed to adjust from the old + two-part copy to a single call to _rl_output_some_chars (change of + 2/16) + + 3/4 + --- +Makefile.in,doc/Makefile.in + - PACKAGE_TARNAME, docdir: new variables substituted by autoconf + - OTHER_DOCS,OTHER_INSTALLED_DOCS: new variables with auxiliary + documentation files to be installed into $(docdir) + - install: add new rule to install $(OTHER_DOCS) + - uninstall: add new rule to uninstall $(docdir)/$(OTHER_INSTALLED_DOCS) + +doc/bash.1 + - add URL to `POSIX' file in `SEE ALSO' section; put pointer to that + section in --posix and set -o posix descriptions + +examples/ + - removed around 110 examples at the request of the FSF due to copyright + issues + + 3/5 + --- +builtins/setattr.def + - readonly: modified help text slightly to make it clearer that + functions aren't changed or displayed unless the -f option is given. + Report from + + 3/9 + --- +include/typemax.h + - SIZE_MAX: define to 65535 (Posix minimum maximum) if not defined + +parse.y + - include "typemax.h" for possible SIZE_MAX definition, make sure we + include it after shell.h + +{braces,expr}.c + - include "typemax.h" for possible INTMAX_MIN and INTMAX_MAX definitions + + 3/10 + ---- +bashline.c + - bash_default_completion: make sure completion type of `!' (same as + TAB but with show-all-if-ambiguous set) and glob-word-completion + sets rl_filename_completion_desired to 0 so extra backslashes don't + get inserted by `quoting' the completion. We can't kill all the + matches because show-all-if-ambiguous needs them. Bug report from + Marcel (Felix) Giannelia + +[bash-4.3-alpha frozen] + + 3/14 + ---- +general.c + - trim_pathname: use memmove instead of memcpy since the source and + destination pathnames may overlap. Report and fix from Matthew + Riley + + 3/18 + ---- +configure.ac + - socklen_t is defined as `unsigned int' if configure can't find it + + 3/20 + ---- +lib/readline/complete.c + - S_ISVTX: since it's not defined on all platforms (Minix), make sure + its use is protected with #ifdef + + 3/21 + ---- +doc/{bash.1,bashref.texi} + - Added mention of ${!name[@]} and ${!name[*]} expansions to get all + indices of an array. Suggested by Jonathan Leffler + + + 3/24 + ---- +subst.h + - SD_IGNOREQUOTE: new define for skip_to_delim; if set, means that + single quotes (for now) will be treated as ordinary characters + +subst.c + - skip_to_delim: handle SD_IGNOREQUOTE. no callers use it for now + + 3/25 + ---- +support/config.{guess,sub} + - updated to versions from autoconf-2.69 + + 3/31 + ---- +lib/sh/shquote.c + - sh_single_quote: short-circuit quoting a single "'" instead of + creating a long string with empty single-quoted strings + +parser.h + - DOLBRACE_QUOTE2: new define, like DOLBRACE_QUOTE, but need to single- + quote results of $'...' expansion because quote removal will be + done later. Right now this is only done for ${word/pat/rep} + +parse.y + - parse_matched_pair: set state to DOLBRACE_QUOTE2 for pattern + substitution word expansion so we don't treat single quote specially + in the pattern or replacement string + - parse_matched_pair: if we're parsing a dollar-brace word expansion + (${...}) and we're not treating single quote specially within + double quotes, single-quote the translation of $'...' ansi-c + escaped strings. Original report and fix from Eduardo A. + Bustamante López + +subst.c + - extract_dollar_brace_string: ${word/pat/rep} scanning now sets the + DOLBRACE_QUOTE2 flag instead of DOLBRACE_QUOTE so we don't treat + single quotes specially within a double-quoted string + +execute_cmd.c + - fix_assignment_words: skip over assignment statements preceding a + command word before trying to figure out whether or not assignment + statements following a possible declaration command should be + treated specially. Fixes bug reported by Dan Douglas + + + 4/4 + --- +lib/readline/readline.c + - _rl_dispatch_subseq: only call _rl_vi_set_last (and check whether + the key is a text modification command) if the key sequence length + is 1. That keeps the arrow keys from setting the last command + when called in vi command mode. Fixes bug reported by Ian A. + Watson + + 4/6 + --- +lib/readline/bind.c + - rl_parse_and_bind: when parsing a double-quoted string as the value + of a variable, make sure we skip past the leading double quote. + Fix from Andreas Schwab + +variables.c + - hash_lookup: set new local variable last_table_searched to the table + a successful lookup appears in; tested in make_local_variable to + solve the problem below + - make_local_variable: if we find a variable with the tempenv flag + set at the same `level' as variable_context', but not found in the + temporary_env (temp environment preceding the builtin), return it. + The temp environment preceding the function call has already been + merged (in execute_function) into the list of variable contexts the + function sees as shell_variables by the time this is called. Fixes + inconsistency pointed out by Dan Douglas + +subst.c + - expand_arith_string: expanded out contents of expand_string, + expand_string_internal, expand_string_if_necessary to create a + WORD_DESC and call call_expand_word_internal() on it directly. + We don't want process substitution to be performed ( 1<(2) ) should + mean something different in an arithmetic expression context. + It doesn't work to just turn on the DQUOTE flag, since that means + that things like ${x["expression"]} are not expanded correctly. + Fixes problem pointed out by Dan Douglas + + 4/13 + ---- +subst.c + - process_substitute: run the EXIT trap before exiting, as other + shells seem to. Fixes problem pointed out by Dan Douglas + + +lib/readline/readline.c + - readline_internal_setup: call rl_vi_insertion_mode to enter vi + mode instead of rl_vi_insert_mode to avoid resetting the saved last + command information. Posix says that `.' can repeat a command + that was entered on a previous line so we need to save the info. + Fixes bug reported by Ian A. Watson + + 4/14 + ---- +lib/readline/complete.c + - rl_completion_matches: make sure xrealloc returns something non-null + (can happen when interrupted by a signal) before trying to add + matches to match_list + +subst.c + - array_remove_pattern: return NULL right away if array_variable_part + returns an invisible variable + - array_length_reference: handle array_variable_part returning an + invisible variable + - get_var_and_type: handle array_variable_part returning an invisible + variable + + 4/15 + ---- +execute_cmd.c + - execute_command_internal: make sure to run the EXIT trap for group + commands anywhere in pipelines, not just at the end. From a point + raised by Andreas Schwab + +variables.c + - bind_int_variable: make sure invisible flag is unset. Fixes problems + like "declare -ai a; : $(( a[4]=4 ));" + +arrayfunc.c + - array_variable_part: return variable even if invisible flag set, + callers must handle invisible vars + + 4/18 + ---- +builtins/set.def + - unset_builtin: if -n flag given, call unset_nameref instead of + unset_variable + +variables.c + - find_variable_nameref: print warning message if nameref circular + reference detected, return NULL and let caller deal with it + +builtins/declare.def + - declare_builtin: only disallow global references at this point if + we are at the global scope + + 5/16 + ---- +configure.ac + - update release status to beta + + 5/23 + ---- +trap.c + - run_pending_traps: save and restore pipeline around calls to + evalstring() in case we get a trap while running a trap. Have to + figure out the recursive running traps issue elsewhere. Fixes + bug reported by Roman Rakus + - run_pending_traps: make sure to set running_trap to the appropriate + signal value when running a trap command + - run_pending_traps: short-circuit immediately if running_trap set + when invoked. Could change this later to only skip if it would + run the same trap as currently being run (running_trap == sig + 1) + +configure.ac + - add warning if bison not found + +lib/readline/doc/rltech.texi + - new section with an example program illustrating the callback + interface. Suggested by Peng Yu + +examples/loadables/Makefile.in + - remove references to `cut' and `getconf', which were removed in + early March + + 5/28 + ---- +lib/sh/pathphys.c + - sh_realpath: correct inverted two arguments to call to sh_makepath. + Report and fix from Julien Thomas + + 6/7 + --- +execute_cmd.c + - executing_line_number: the else clauses that are conditional on + various options being defined can simply be if clauses -- they are + mutually exclusive and all have `return' in the body. Fixes bug + reported by Flavio Medeiros + + 6/25 + ---- +lib/readline/readline.c + - readline_internal_setup: only sent the meta-key enable string to the + terminal if we've been told to use one and the terminal has been + successfully initialized (RL_ISSTATE (RL_STATE_TERMPREPPED) != 0). + Suggested by Dan Mick + +lib/readline/signals.c + - _rl_signal_handler: call any defined signal hook after calling + rl_resize_terminal when handling a SIGWINCH. We already have called + the original SIGWINCH handler but will not be resending the signal + to ourselves + + 6/27 + ---- +lib/readline/doc/history.3, doc/bash.1 + - fix description of the `$' modifier to note that it expands to the + last *word*, which is not always the last argument. Report from + ariyetz@gmail.com via gnu.org RT + + 6/29 + ---- +lib/glob/smatch.c + - glob_asciiranges: initialize to value of GLOBASCII_DEFAULT instead + of 0 (0 if not defined) + +configure.ac,config.h.in + - --enable-glob-asciiranges-default: new option, controls the value of + GLOBASCII_DEFAULT; use it to turn globasciiranges shopt option on + by default + +doc/bashref.texi + - document new --enable-glob-asciiranges-default configure option + +variables.c + - assign_in_env: implement += value appending semantics for assignments + preceding command names + + 7/4 + --- +expr.c + - set lasttok = NUM in all of the functions that result in a number, + even if it's a boolean, to avoid errors with constructs like + 1 * x = 1, which should be an asignment error. Fixes problem + pointed out by Dan Douglas + +parse.y + - decode_prompt_string: don't bother to call strcpy if + polite_directory_format returns its argument unchanged. It's not + necessary and Mac OS X 10.9 aborts because of a supposed overlapping + string copy. Bug and fix from simon@hitzemann.org + +subst.c + - parameter_brace_find_indir: new function, code from + parameter_brace_expand_indir that looks up the indirectly-referenced + variable, but does not expand it + - parameter_brace_expand_indir: call parameter_brace_find_indir to + look up indirected variable reference + - get_var_and_type: call parameter_brace_find_indir if it looks like we + are trying to manipulate an indirect variable reference like + ${!b%%foo}. This makes a difference if !b references an array + variable. Bug report from Dan Douglas + + 7/6 + --- +lib/sh/casemod.c + - sh_modcase: make sure argument passed to is_basic is <= UCHAR_MAX, + since cval can convert something to a wchar_t greater than UCHAR_MAX. + Fixes bug reported by Tomasz Tomasik + + 7/8 + --- +lib/readline/history.c + - add_history_time: if history_length == 0, referencing history_length + - 1 will result in an array bounds error, so make history_length be + at least 1 before going on. Fixes bug reported by Geng Sheng Liu + + +builtins/setattr.def + - show_func_attributes: display definition (if NODEFS argument is 0) and + attributes for a particular function; used by `declare -fp name' + +builtins/declare.def + - declare_internal: call show_func_attributes if -f supplied with -p. + Fixes inconsistency observed by Linda Walsh + +builtins/common.h + - new extern declaration for show_func_attributes + +builtins/read.def + - read_builtin: check the first supplied variable name for validity + before attempting to read any input, since we know we will have to + at least use that one. Don't check any other names yet. Suggested + by jidanni@jidanni.org + + 7/10 + ---- +redir.c + - do_redirection_internal: when closing a file descriptor with + r_close_this ([n]<&-) count close errors as redirection errors if + errno ends up as EIO or ENOSPC. Originally reported back in April + 2012 by Andrey Zaitsev + + 7/11 + ---- +redir.c + - do_redirection_internal: before calling check_bash_input, make sure + that we don't call check_bash_input for an asynchronous process that + is replacing stdin with something else. The seek backwards affects + the parent process as well, since parents and children share the + file pointer. Fixes problem originally reported in March 2013 by + Martin Jackson + + 7/13 + ---- +doc/{bash.1,bashref.texi} + - slight change to add a description of `shopt -o' suggested by Bruce + Korb + + 7/19 + ---- +lib/readline/histfile.c + - history_do_write: if close returns < 0, make sure we restore the + backup history file and return a non-zero value + - history_truncate_file: if write or close return < 0, make sure we + return a non-zero value + +[bash-4.3-beta frozen] + + 7/21 + ---- +lib/readline/isearch.c + - rl_display_search: now takes an entire search context flags word as + the second argument, instead of just reverse flag; changed callers + - rl_display_search: if the search has failed, add `failed ' to the + beginning of the search prompt + - _rl_isearch_dispatch: if the search has failed, display the entire + search string with an indication that the search failed but with the + last matching line. Suggested by jidanni@jidanni.org + +command.h + - W_ASSIGNINT: new word flag; used internally for make_internal_declare + and set by fix_assignment_words + +execute_cmd.c + - fix_assignment_words: set W_ASSIGNINT if compound assignment and -i + given as option. We don't do anything with the value yet + +subst.c + - shell_expand_word_list: rework the way the option list that is + passed to make_internal_declare is created + + 8/1 + --- +doc/{bash.1,bashref.texi} + - minor changes to description of $! based on a report from Chris + Down + +arrayfunc.c + - assign_array_element_internal: before trying to get an array's max + index to process a negative subscript, make sure the array exists. + Bug report from Geir Hauge + + 8/2 + --- +arrayfunc.c + - assign_array_element_internal: before using array_max_index() when + processing a negative subscript, make sure the variable is an array. + if it's not, use 0 as array_max_index assuming it's a string. + Fixes bug report from Geir Hauge + + 8/3 + --- +Makefile.in + - pcomplete.o: add dependency on $(DEFDIR)/builtext.h. Suggested by + Curtis Doty + + 8/5 + --- +lib/glob/sm_loop.c + - strcompare: short-circuit and return FNM_NOMATCH if the lengths of the + pattern and string (pe - p and se - s, respectively) are not equal + - strcompare: don't bother trying to set *pe or *se to '\0' if that's + what they already are. Fixes bug reported by Geir Hauge + + + 8/6 + --- +doc/{bash.1,bashref.texi},builtins/hash.def,lib/readline/doc/rluser.texi + - minor typo changes from Geir Hauge + +bultins/help.def + - show_longdoc: avoid trying to translate the empty string because it + often translates to some boilerplate about the project and + translation. Report and fix from Geir Hauge + + 8/8 + --- +builtins/help.def + - help_builtin: try two passes through the list of help topics for each + argument: one doing exact string matching and one, if the first pass + fails to find a match, doing string prefix matching like previous + versions. This prevents `help read' from matching both `read' and + `readonly', but allows `help r' to match everything beginning with + `r'. Inspired by report from Geir Hauge + + 8/13 + ---- +builtins/fc.def + - fc_builtin,fc_gethnum: calculate `real' end of the history list and + use it if -0 is specified as the beginning or end of the history + range to list. Doesn't work for fc -e or fc -s by design. Feature + requested by Mike Fied + + 8/16 + ---- +trap.c + - _run_trap_internal: use {save,restore}_parser_state instead of + {save,restore}_token_state. It's more comprehensive + + 8/23 + ---- +doc/bash.1 + - disown: remove repeated text. Report and fix from Thomas Hood + + + 8/25 + ---- +lib/readline/rltty.c + - set_special_char: fix prototype (last arg is rl_command_func_t *) + +sig.c + - set_signal_handler: return oact.sa_handler only if sigaction + succeeds; if it doesn't, return SIG_DFL (reasonable default). From + https://bugzilla.redhat.com/show_bug.cgi?id=911404 + +bashline.c + - attempt_shell_completion: fix to skip assignment statements preceding + command name even if there are no programmable completions defined. + From https://bugzilla.redhat.com/show_bug.cgi?id=994659 + - attempt_shell_completion: if still completing command word following + assignment statements, do command completion even if programmable + completion defined for partial command name entered so far + + 8/26 + ---- +pcomplete.c + - pcomp_filename_completion_function: make sure rl_filename_dequoting_function + is non-NULL before trying to call it. Bug and fix from + Andreas Schwab + +bashline.c + - bash_command_name_stat_hook: if *name is not something we're going + to look up in $PATH (absolute_program(*name) != 0), just call the + usual bash_filename_stat_hook and return those results. This makes + completions like $PWD/exam[TAB] add a trailing slash + + 9/2 + --- +builtins/read.def + - read_builtin: before comparing what we read to the delim, make sure + we are not supposed to be ignoring the delimiter (read -N). We + set the delim to -1, but it's possible to read a character whose + int value ends up being between -1 and -128. Fixes bug + reported by Stephane Chazelas + +doc/{bash.1,bashref.texi} + - word splitting: crib some language from Posix to make it clear that + characters in IFS are treated as field *terminators*, not field + *separators*. Addresses issue raised by DJ Mills + + +lib/readline/{util.c,rldefs.h} + - _rl_stricmp,_rl_strnicmp: now take const char * string arguments; + changed prototype declarations + + 9/5 + --- +doc/{bash.1,bashref.texi} + - [[: modify description of pattern matching to make it clear that the + match is performed as if the extglob option were enabled. From Red + Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=1002078 + + 9/12 + ---- +lib/readline/isearch.c + - _rl_isearch_dispatch: if we read an ESC and it's supposed to + terminate the search, make sure we check for typeahead with + _rl_pushed_input_available, since installing a hook function causes + typeahead to be collected in `ibuffer' (input.c). If there is any, + make sure we still use the ESC as a prefix character. Bug and fix + from Mike Miller + + 9/16 + ---- +builtins/{caller,cd,kill,pushd,wait}.def + - builtin_usage(): make sure call to this sets return status to + EX_USAGE + + 9/18 + ---- +terminal.c + - rl_change_environment: new application-settable variable; if non- + zero (the default), readline will modify LINES and COLUMNS in the + environment when it handles SIGWINCH + - _rl_get_screen_size: if rl_change_environment is non-zero, use setenv + to modify LINES and COLUMNS environment variables + +readline.h + - rl_change_environment: new extern declaration for applications + + 9/22 + ---- +configure.ac + - relstatus: bumped version to bash-4.3-beta2 + + 9/24 + ---- + +lib/readline/readline.c + - bind_arrow_keys_internal: added more key bindings for the numeric key + pad arrow keys on mingw32. Patch from Pierre Muller + + + 10/19 + ----- + +bashline.c + - maybe_restore_tilde: version of restore_tilde that honors `direxpand'; + calls restore_tilde after saving directory expansion hook if + necessary. Report from Andreas Schwab + +builtins/cd.def + - -@: new option, allows cd to use `extended attributes' present in + NFSv4, ZFS; idea taken from ksh93. Attributes associated with a + file are presented as a directory containing the attributes as + individual files. Original patch contributed by Cedric Blancher + + + 10/20 + ----- +aclocal.m4 + - BASH_CHECK_MULTIBYTE: check for wcwidth being broken with unicode + combining characters needs a value to use when cross-compiling. + Bug report from Bert Sutherland + +doc/{bash.1,bashref.texi} + - document new -@ option to cd builtin + + 10/28 + ----- +lib/glob/{{gmisc,glob}.c,glob.h} + - extglob_pattern renamed to extglob_pattern_p, declared in glob.h + +subst.c + - expand_word_internal: typo fix: case to fix " $@\ " bug in bash-4.2 + had a typo (& isexp instead of &&) + + 10/29 + ----- +input.c + - getc_with_restart: make sure local_index and local_bufused are + reset to 0 before returning EOF, in case we are running an interactive + shell without line editing and ignoreeof is set. Report and fix + from Yong Zhang + +lib/readline/search.c + - _rl_nsearch_init: take out extra third argument to rl_message; it + only matches prototype (and maybe format) in cases where + PREFER_STDARG and USE_VARARGS are both undefined, which is rare + + 10/31 + ----- +subst.c + - process_substitute: when opening the named pipe in the child, open + without O_NONBLOCK to avoid race conditions. Happens often on AIX. + Bug report and fix from Michael Haubenwallner + + +builtins/ulimit.def + - RLIMIT_NTHR: if RLIMIT_PTHREAD is not defined, but RLIMIT_NTHR is, + use RLIMIT_NTHR (NetBSD) + + 11/5 + ---- +locale.c + - set_default_locale_vars,set_locale_var: if TEXTDOMAINDIR has been + set, and default_dir has a non-null value, call bindtextdomain(3) + when TEXTDOMAIN is assigned a value. Fixes problem reported by + Michael Arlt + + 11/6 + ---- +builtins/cd.def + - cdxattr: only create synthetic pathname in `buf' if NDIRP argument + is non-null + - change_to_directory: if we have specified -@ and cdxattr returns + failure, fail immediately. Fixes bug reported by Joshuah Hurst + + + 11/12 + ----- +redir.c + - print_redirection: change r_err_and_out (&>) and its append form, + r_append_err_and_out (&>>) cases to separate redirection operator + from filename by a space, in case we have a process substitution. + Fixes bug reported by admn ombres + + 11/15 + ----- +execute_cmd.c + - execute_simple_command: don't close process substitution fds until + we are finished executing any current shell function. Partial fix + for bug reported by John Dawson + +support/shobj-conf + - add support for Darwin 13 (Mac OS X 10.9, Mavericks). Based on a + report by Ludwig Schwardt + + 11/20 + ----- +[bash-4.3-rc1 frozen] + + 11/24 + ----- +builtins/printf.def + - bind_printf_variable: make sure that the variable assigned to is + no longer marked as invisible. Fixes bug reported by NBaH + + + 11/28 + ----- +jobs.c + - delete_old_job: fix off-by-one error in job index in call to + internal_warning. Bug report from Peter Cordes + + 11/30 + ----- +doc/bashref.texi + - add string to description of special parameters with name of + special parameter prefixed by a $, so you can search for $#, + for instance + + 12/2 + ---- +lib/readline/{histexpand.c + - get_history_event: account for current_history() possibly returning + NULL. Report and fix from Pankaj Sharma + + + 12/11 + ----- + +lib/readline/parse-colors.c + - get_funky_string: don't call abort if we see something we can't + parse; just return an error + - _rl_parse_colors: if we encounter an error while parsing $LS_COLORS + we need to leave _rl_color_ext_list as NULL after freeing its + elements, then turn off _rl_colored_stats. Report and fix from Martin + Wesdorp + + 12/13 + ----- + +lib/readline/parse-colors.c + - _rl_parse_colors: if we encounter an unrecognized prefix, throw an + error but try to recover and go on to the next specification + +variables.c + - make_local_variable: for new variables this function creates, set + the att_invisible attribute. All callers from declare_internal. + Indirectly, this is a fix for bug with `declare -n var; var=foo;' + reported by Pierre Gaston + - bind_variable: if assigning to nameref variable that doesn't have + a value yet (e.g., with `declare -n var; var=foo'), don't try to + use the unset name. Fixes a segfault reported by Pierre Gaston + + +execute_cmd.c + - execute_command_internal: make sure last_command_exit_value is set + to 0 after any command executed in the background. Fixes bug + reported by Martin Kealey + + 12/17 + ----- +support/config.{guess,sub} + - updated to latest versions from git + + 12/19 + ----- +parse.y + - struct STRING_SAVER: now has a new `flags' element, to identify the + caller: alias expansion, double-paren parsing, or parse_and_execute + - push_string: now sets flags to PSH_ALIAS if `ap' argument is non-NULL + - push_string: now doesn't attempt to call strlen on a NULL string to + set shell_input_line_size + - parser_expanding_alias, parser_save_alias, parser_restore_alias: new + functions to provide an external interface to push_string and + pop_string; parser_save_alias sets flags element to PSH_SOURCE (could + be renamed PSH_EXTERN someday) + - shell_getc: when yy_getc returns '\0', instead of just testing + whether the pushed_string_list is not-empty before popping it, don't + pop if if the saved string has flags PSH_SOURCE, indicating that + parse_and_execute set it before setting bash_input to the string. + We should continue reading to the end of that string before popping + back to a potential alias. Partial solution for the problem of aliases + with embedded newlines containing `.' commands being executed out of + order reported by Andrew Martin + - shell_getc: when yy_getc returns '\0' and there is a saved string of + type PSH_SOURCE, restart the read without popping the string stack + if we have not read to the end of bash_input.location.string. Rest + of fix for out-of-order execution problem + +externs.h + - parser_expanding_alias, parser_save_alias, parser_restore_alias: new + extern function declarations + +builtins/evalstring.c + - pe_prologue: if the parser is expanding an alias, make sure to add + an unwind-protect to restore the alias; undoes the work that will be + performed by parse_and_execute/parse_string + - parse_and_execute,parse_string: after calling push_stream to save + bash_input, check whether or not the parser is currently expanding + an alias (parser_expanding_alias() != 0). If it is, we want to save + that string in the pushed_string_list, which we do with + parser_save_alias. + + 12/23 + ----- +execute_cmd.c + - execute_for_command: make sure to set line_number before expanding + the word list, so expansion errors have the right line number. + From a report from Ben Okopnik + +expr.c + - exp2: save token pointer before calling readtok(), arrange to use + saved token pointer when printing error token on a division by 0 + error + + 12/27 + ----- +lib/readline/display.c + - rl_redisplay: when calculating effects of invisible characters in a + prompt that is split across physical screen lines to set the indices + of linebreaks, don't bother testing local_prompt_prefix (line 751). + That prefix doesn't matter when calculating prompt visible and + invisible characters. Fixes problem reported by Jinesh Choksi + + +Makefile.in + - install: make sure to use $(DESTDIR) when installing OTHER_DOCS. + Report and fix from Matthias Klose + +doc/texinfo.tex + - updated to version of 2013-09-11 + + 12/28 + ----- +lib/readline/undo.c + - rl_do_undo: if we are undoing from a history entry (rl_undo_list == + current_history()->data), make sure the change to rl_line_buffer is + reflected in the history entry. We use the guts of + rl_maybe_replace_line to do the work. Fixes problem reported by + gregrwm + + 12/30 + ----- +sig.c + - sigint_sighandler: if we get a SIGINT (and this signal handler is + installed) while the wait builtin is running, note that we received + it in the same way as jobs.c:wait_sigint_handler and return. The + various wait_for functions will look for that with CHECK_WAIT_INTR. + This fixes the wait builtin not being interruptible in an interactive + job control shell + + 12/31 + ----- +trap.c + - set_signal_hard_ignored: rename set_signal_ignored to this, since it + both sets original_signals[sig] and sets the HARD_IGNORE flag + - set_signal_ignored: new function, now just sets original_signals[sig] + +trap.h + - set_signal_hard_ignored: new external declaration + +sig.c + - initialize_terminating_signals: call set_signal_hard_ignored instead + of set_signal_ignored for signals with disposition SIG_IGN when the + shell starts + +execute_cmd.c + - setup_async_signals: make sure we get the original dispositions for + SIGINT and SIGQUIT before starting the subshell, and don't call + set_signal_ignored because that sets original_signals[sig]. If we + don't, subsequent attempts to reset handling using trap will fail + because it thinks the original dispositions were SIG_IGN. Posix + interpretation 751 (http://austingroupbugs.net/view.php?id=751) + + 1/2/2014 + -------- +lib/sh/stringvec.c + - strvec_mcreate, strvec_mresize: versions of create and resize that + use malloc and realloc, respectively, instead of xmalloc/xrealloc + +braces.c + - expand_amble,mkseq: use strvec_mcreate/strvec_mresize so we can + catch and handle memory allocation failures instead of aborting + with the xmalloc/xrealloc interface + +lib/sh/strdup.c + - strdup replacement function for ancient systems that don't have it + +lib/sh/itos.c + - mitos: new function, itos that uses strdup instead of savestring + +externs.h + - strvec_mcreate/strvec_mresize: new extern declarations + - mitos: new extern declaration + +configure.ac + - bash version moved to 4.3-rc2 + + 1/6 + --- +doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} + - separate the description of what happens when readline reads the + tty EOF character from the description of delete-char, leaving a + note in the delete-char description about common binding for ^D. + From suggestion by Parke + +lib/readline/doc/{version.texi,history.3,*.texi} + - updated email addresses and copyright dates + + 1/7 + --- +variables.c + - delete_var: new function, just removes a variable from a hash table + and frees it, without doing anything else + - make_variable_value: if we are trying to assign to a nameref variable, + return NULL if the value is null or the empty string or not a valid + identifier + +variables.h + - delete_var: new extern declaration + +subst.h + - ASS_NAMEREF: new define for assignments, means assigning to a nameref + variable + +builtins/declare.def + - declare_internal: if we are creating and assigning to a nameref + variable, make sure the value is a valid variable name (checks done + by make_variable_value via bind_variable_value) and display an + error message, deleting the variable we just created, if it is not. + Fixes bug reported by Peggy Russell + + 1/9 + --- +builtins/declare.def + - declare_internal: turning on nameref attribute for an existing + variable turns off -i/-l/-u/-c attributes (essentially the ones + that cause evaluation at assignment time) for ksh93 compat + +builtins/setattr.def + - show_name_attributes: if asked to display attributes and values for + a nameref variable, don't follow the nameref chain to the end. More + ksh93 compat + + 1/10 + ---- +trap.c + - _run_trap_internal: use {save,restore}_parser_state instead of + {save,restore}_token_state, like in run_pending_traps(); don't + need to save and restore last_command_exit_value as a result + - _run_trap_internal: call {save,restore}_pipeline like in + run_pending_traps() + - run_pending_traps: since we no longer run traps in a signal handler + context, do not block and unblock the trapped signal while the + trap is executing + - run_pending_traps: allow recursive invocations (basically, running + traps from a trap handler) with only a warning if the shell is + compiled in debug mode. If a caller doesn't want this to happen, + it should test running_trap > 0. signal_in_progress (sig) only works + for the signals the shell handles specially + +bashline.c + - bash_event_hook: make sure we clean up readline if interrupt_state + is set, not only when SIGINT is not trapped. check_signals_and_traps + will call check_signals, which calls QUIT, which will longjmp back + to top_level, running the interrupt trap along the way. Fixes the + problem of signal handlers being reset out from under readline, and + not being set properly the next time readline is called, because + signals_set_flag is still set to 1. XXX - might need to do this + for other signals too? + + 1/11 + ---- +subst.h + - SD_GLOB: new define for skip_to_delim; means we are scanning a + glob pattern. + +subst.c + - skip_to_delim: if flags include SD_GLOB, assume we are scanning a + glob pattern. Currently only used to skip bracket expressions + which may contain one of the delimiters + + 1/12 + ---- +subst.c + - parameter_brace_expand: when expanding $@ as part of substring + expansion, pattern substitution, or case modification, don't turn + on the QUOTED_NULL flag. The code that constructs the word to be + returned from expand_word_internal expects a different code path + when $@ is being expanded. Fixes bug reported by Theodoros + V. Kalamatianos + + 1/19 + ---- +subst.c + - list_dequote_escapes: new function; analogue of list_quote_escapes + +pathexp.c + - quote_string_for_globbing: fix case where unescaped ^A is last char + in string; need to pass it through unaltered instead of turning it + into a bare backslash + - quote_string_for_globbing: when quoting for regexp matching in [[, + don't treat backslash as a quote character; quote the backslash as + any other character. Part of investigation into reports from + Eduardo A. Bustamante López + + 1/25 + ---- +builtins/gen-helpfiles.c + - write_helpfiles: add prototype + - make sure to #undef xmalloc/xfree/xrealloc/free if USING_BASH_MALLOC + is defined. the code does not use them, and we don't link against + xmalloc.o. Report from Linda Walsh + +Makefile.in + - variables.o: add dependency on builtins/builtext.h; helps with + parallel builds. Report from Linda Walsh + +support/shobj-conf + - darwin: combine the stanzas into one that will not require them to + be updated on each Mac OS X release. Report and fix from Max Horn + + + 1/27 + ---- +support/shobj-conf + - darwin: changed the install_name embedded into the shared library + to contain only the major version number, not the minor one. The + idea is that the minor versions should all be API/ABI compatible, + and it is better to link automatically with the latest one. Idea + from Max Horn + + 1/29 + ---- +[bash-4.3-rc2 released] + + 1/30 + ---- +lib/readline/readline.h + - rl_clear_history, rl_free_keymap: add extern declarations. Report + from Hiroo Hayashi + +general.c + - include trap.h for any_signals_trapped() prototype + +lib/sh/unicode.c + - include for sprintf prototype + + 1/31 + ---- +execute_cmd.c + - execute_simple_command: only posix-mode shells should exit on an + assignment failure in the temporary environment preceding a special + builtin. This is what the documentation and code comments have + always said + - execute_simple_command: make sure redirection errors, word expansion + errors, and assignment errors to Posix special builtins cause a + non-interactive posix mode shell to exit. Previously the shell + would not exit if the failed special builtin was on the LHS of || + or && + +pathexp.c + - quote_string_for_globbing: when quoting a regular expression + (QGLOB_REGEXP), allow an unquoted backslash to pass through + unaltered. Don't use it as a quote character or quote it. More + investigation from 1/24 and report by Mike Frysinger + + - quote_string_for_globbing: when quoting a regular expression + (QGLOB_REGEXP), turn CTLESC CTLESC into CTLESC without adding a + backslash to quote it. We should not have to quote it because it is + not a character special to EREs. More investigation from 1/24 + +lib/glob/glob.c + - glob_testdir: now takes a second flags argument (currently unused); + changed prototype and callers + + 2/1 + --- +lib/glob/glob.c + - glob_testdir: if flags argument includes GX_ALLDIRS (globstar), use + lstat so we skip symlinks when traversing the directory tree. + Originally reported by Chris Down + + 2/2 + --- +lib/readline/undo.c + - rl_do_undo: make sure CUR is non-zero before dereferencing it to + check cur->data against rl_undo_list. Report and fix from + Andreas Schwab + +doc/{bash.1,bashref.texi} + - added slight clarifying language to the description of $*, + describing what happens when the expansion is not within double + quotes + + 2/4 + --- +test.c + - unary_test: add code to -v case so that it interprets `bare' array + references (foo[1]) and returns true if that index has a value + + 2/5 + --- +trap.c + - restore_default_signal: fix SIGCHLD special case for SIG_TRAPPED flag + off but SIG_INPROGRESS mode set and handler IMPOSSIBLE_TRAP_HANDLER; + continue with resetting handler in this case. maybe_set_sigchld_trap + will check these things before resetting sigchld trap from + run_sigchld_trap. Fixes (apparently long-standing?) problem reported + by Alexandru Damian + + 2/6 + --- +lib/sh/strtrans.c + - ansic_quote: fixed a bug when copying a printable character that + consumes more than one byte; byte counter was not being incremented. + Bug report from jidanni@jidanni.org + + 2/7 + --- +input.c + - getc_with_restart: if read(2) returns -1/EINTR and interrupt_state or + terminating_signal is set (which means QUIT; will longjmp out of this + function), make sure the local buffer variables are zeroed out to + avoid reading past the end of the buffer on the next call. Bug report + from Dan Jacobson + + 2/9 + --- +bashline.c + - command_word_completion_function: if a directory in $PATH contains + quote characters, we need to quote them before passing the candidate + path to rl_filename_completion_function, which performs dequoting on + the pathname it's passed. Fixes bug reported by Ilyushkin Nikita + + + 2/11 + ---- +parse.y + - xparse_dolparen: save and restore shell_eof_token around call to + parse_string, intead of just leaving it set to ')' + - shell_getc: when -v is set, only print the command line when + shell_eof_token is 0, so we don't print it multiple times when + recursively entering the parser to parse $(...) commands. Fixes + bug reported by Greg Wooledge + +[changed release status to 4.3-release] + + 2/13 + ---- +lib/sh/strtrans.c + - ansic_quote: handle case where mbrtowc reports that the multibyte + sequence is incomplete or invalid. Fixes bug reported by + Eduardo A. Bustamante López + + 2/14 + ---- +variables.c + - find_variable_nameref_context: fix a problem that caused the loop + to go one context too close to the global context. In some cases, + simple variable assignment would set a variable in the global + context instead of a local context. Bug report from + Geir Hauge + + 2/26 + ---- +[bash-4.3 released] + + 2/27 + ---- +aclocal.m4 + - broken wcwidth check: fix typo reported by David Michael + + + 2/28 + ---- +support/bashbug.sh + - add ${BUGADDR} to error message printed if sending mail fails + +trap.c + - _run_trap_internal: don't call {save,restore}_pipeline if running + DEBUG trap; run_debug_trap calls them itself. Fixes bug reported + by Moe Tunes + +test.c + - unary_test: fix 'R' case by using find_variable_noref instead of + find_variable + - test_unop: add back missing 'R' case. Fixes bug reported by + NBaH + + 3/2 + --- +jobs.c + - end_job_control: if job control is active, we changed the terminal's + process group, so make sure we restore it. Fixes bug reported by + Eduardo A. Bustamante López + + 3/7 + --- +pcomplete.c + - pcomp_curtxt: new variable, holds the original text to be completed + as passed to the programmable completion code + - pcomp_filename_completion_function: if we are running compgen + (presumably in a shell function completion) and performing readline + completion, check the word being completed. If it's not empty, but + the original word passed to the programmable completion code is an + empty string (""), call a dequoting function if one is available. + This compensates for an assumption in bash-completion. Reported by + Albert Shih + +lib/readline/readline.c + - _rl_dispatch_subseq: when deciding whether or not to set vi mode's + idea of the last command, use whether or not the dispatching keymap + is vi_movement_keymap instead of the key sequence length. The `c', + `d', and `y' commands all take motion commands as `arguments' and + will produce key sequences longer than 1 character. The arrow keys + will end up dispatching out of a different keymap, so the test will + prevent arrow keys from setting the last command (the problem in + bash-4.2). Bug report from Daan van Rossum + +lib/readline/vi_mode.c + - _rl_vi_motion_command: convenience function to test whether a key is + a vi-mode motion command + +lib/readline/rlprivate.h + - _rl_vi_motion_command: extern declaration + +parse.y + - parse_matched_pair: we should not skip processing single quotes in + posix mode if dolbrace_state == DOLBRACE_QUOTE2 (pattern + substitution). Fixes bug reported by David Sines + + + 3/10 + ---- +lib/readline/readline.c + - _rl_dispatch_callback: treat a return value of -1 as the end of + a command dispatch sequence if the current context doesn't + indicate that we're reading a multi-key sequence + ((cxt->flags & KSEQ_SUBSEQ) == 0). Turn off the multikey flag + and free the context chain in this case. Fixes one bug reported + by Felix Yan to bug-readline list + - _rl_dispatch_callback: treat a return value of > 0 the same as 0 + and return from the function, since only values < 0 cause us to + simulate recursion. Rest of fix for bug tracked down by + Anatol Pomozov + + 3/11 + ---- + +execute_cmd.c + - execute_in_subshell: if a longjmp occurs, set result to + EXECUTION_FAILURE only if last_command_exit_value == EXECUTION_SUCCESS; + use value of last_command_exit_value otherwise. Fixes cosmetic + issue reported by Dennis Lambe Jr. + +doc/bash.1 + - shell-kill-word and shell-backward-kill-word should be documented + as unbound by default. Report from Oliver Hartley + + +trap.c + - run_pending_traps: save value of $? before running trap commands in + trap_saved_exit_value, like run_exit_trap + - _run_trap_internal: save value of $? before running trap commands in + trap_saved_exit_value, like run_exit_trap + +builtins/common.c + - get_exitstat: when running `return' in a trap action, and it is not + supplied an argument, use the saved exit status in + trap_saved_exit_value. Fixes Posix problem reported by + Eduardo A. Bustamante López + + 3/13 + ---- +lib/sh/shquote.c + - sh_contains_quotes: new function, returns true if a given string + contains any of the shell quote characters (single quote, double + quote, or backslash) + +externs.h + - sh_contains_quotes: new extern declaration + +pcomplete.c + - pcomp_filename_completion_function: more changes for the benefit of + bash-completion: if the argument is not the same as the original + argument passed to the programmable completion code (pcomp_curtxt), + and we are being run by compgen as part of a completion, dequote the + argument as bash-completion expects. Fix for the complete-word- + with-quoted-special-chars problem with bash-completion + + 3/17 + ---- +execute_cmd.c + - execute_intern_function: when in posix mode, make defining a function + with the same name as a special builtin a fatal error only when the + shell is not interactive. Interactive shells display an error + message and go on. From a discussion with Doug McIlroy + + + 3/18 + ---- +arrayfunc.c + - assign_compound_array_list: when using expand_assignment_string_to_string + to expand the value in a ( [x]=y ) compound assignment, make sure + that we convert 0x0 to "" when expanding [x]= so it doesn't appear as + if the index is unset. Fixes bug reported by Geir Hauge + + +builtins/common.c + - get_exitstat: update fix of 3/11 to allow the DEBUG trap to use the + current value of $? instead of the value it had before the trap + action was run. This is one reason the DEBUG trap exists, and + extended debug mode uses it. Might want to do this only in Posix + mode + +doc/{bash.1,bashref.texi} + - return: add language cribbed from Posix saying what happens when + return is run without an argument from a trap, including the DEBUG + trap exception + + 3/19 + ---- +lib/glob/gmisc.c + - extglob_pattern_p: make sure ?(patlist) is flagged as an extglob + pattern + +lib/glob/glob.c + - extglob_skipname: rewrite to handle patterns that begin but do not + end with an extglob pattern; change test for easy case and loop + through patterns accordingly. Fixes problem with matching filenames + with a leading dot reported by Stephane Chazelas + + - wextglob_skipname: make analogous changes + + 3/20 + ---- +Makefile.in + - pass -DDEBUG down to builds in readline and history directories + +lib/readline/util.c + - _rl_trace and related functions are now only compiled in if DEBUG + is defined + +lib/readline/Makefile.in + - substitute @DEBUG@ and pass -DDEBUG, if necessary, to compilation + in LOCAL_CFLAGS + + 3/21 + ---- +parse.y + - shell_getc: when checking whether or not to reallocate + shell_input_line to add trailing newline, don't try to subtract from + shell_input_line_size. size_t is unsigned, so if its value is less + than 3 (like, say, 2), size-3 is a very large number and the string + will not be reallocated. Use len+3 > size instead of len > size-3. + Fixes bug reported in + https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1295467 + + 3/27 + ---- +lib/readline/display.c + - _rl_clean_up_for_exit: don't bother to call _rl_move_vert to whatever + readline thinks the last displayed line is if it's 0. Two reasons: a + minor optimization, and it protects against unwanted moving if this + function is called twice, as it is when ^C is pressed. Fixes bug + reported by Egmont Koblinger + + 3/28 + ---- +bashline.c + - invalid_completion: new function, used to identify attempts to + complete words that are syntax errors + - attempt_shell_completion: if invalid_completion returns true for a + word in a command position, punt on all completions. Fixes cosmetic + issue reported by Uwe Storbeck + - attempt_shell_completion: add clause so that in_command_position + remains set to 1 for an empty word following a command separator like + (, &, or | + +lib/readline/kill.c + - rl_yank, rl_yank_nth_arg_internal: don't return -1 from bindable + functions, return 1 instead + +lib/readline/text.c + - rl_rubout, _rl_rubout_char, rl_delete, rl_change_case, + rl_transpose_chars, rl_transpose_words, _rl_set_mark_at_pos, + rl_exchange_point_and_mark, _rl_insert_next, _rl_char_search, + _rl_char_search_internal: + don't return -1 from bindable functions, return 1 instead + +lib/readline/vi_mode.c + - rl_vi_end_word, rl_vi_rubout, rl_vi_delete, rl_vi_char_search, + rl_vi_match, _rl_vi_set_mark, _rl_vi_goto_mark: + don't return -1 from bindable functions, return 1 instead + +lib/readline/macro.c + - rl_start_kbd_macro, rl_end_kbd_macro: + don't return -1 from bindable functions, return 1 instead + +builtins/setattr.def + - set_var_attribute: honor setting of no_invisible_vars when setting + att_invisible on a variable + - include "../flags.h" for no_invisible_vars + +builtins/declare.def + - declare_internal: honor setting of no_invisible_vars when setting + att_invisible on a variable + - include "../flags.h" for no_invisible_vars + +Makefile.in,builtins/Makefile.in + - make sure declare.o and setattr.o depend on flags.h + +execute_cmd.c + - decpoint: new function, returns locale's decimal point or `.' default + - mkfmt: use decpoint() to get decimal point instead of unconditionally + using `.'. Fixes bug reported by Andrey Tataranovich + in debian bug 741669 + + 4/10 + ---- +lib/readline/rltypedefs.h + - add back old Function/VFunction/etc typedefs, since other packages + (python, samba) use them. Mark as deprecated using gcc and clang + attributes. Report and fix from Max Horn + + 4/14 + ---- +jobs.c + - run_sigchld_trap: unwind-protect value of this_shell_builtin, since + it matters in some cases whether or not we are running `wait' or + `eval'. Fixes bug reported by Eduardo A. Bustamante López + + + 4/18 + ---- +shell.h + - sh_parser_state_t: add `need_here_doc' flags member, since + xparse_dolparen (via parse_command) sets it to 0 + +parse.y + - gather_here_documents: make sure need_here_doc is > 0, since we + don't want to just decrement it forever if it ends up < 0. Partial + fix for bug reported by Jared Yanovich + - {save,restore}_parser_state: save and restore need_here_doc flag. + Rest of fix for bug reported by Jared Yanovich + + 4/19 + ---- +subst.c + - cond_expand_word: since we are not supposed to be performing word + splitting here, set expand_no_split_dollar_star to 1 in addition to + setting W_NOSPLIT2 + - expand_word_internal: if we have a case where we have an unquoted + $@ but we are in a case where we don't want to split (W_NOSPLIT2), + make sure we return a list consisting of a single word with the + arguments separated by spaces and don't do word splitting. Fixes + bug reported by Greg Wooledge from an IRC + discussion + +builtins/hash.def + - print_portable_hash_info: single-quote pathnames and hashed filenames + that contain shell metacharacters. Fixes bug reported by + in debian bash bug #739853 + + 4/20 + ---- +lib/readline/display.c + - When using horizontal scrolling, the redisplay code erases too much + of the line containing successful results, so make sure we only + erase to the end of the line after making sure we move the cursor + to the end. Fixes bug reported by + + 4/23 + ---- +{bashhist,bashline}.c +builtins{bind,help,type}.def +lib/glob/glob.c, lib/intl/{loadmsgcat,localealias}.c,lib/sh/mktime.c + - fixes to memory leaks uncovered by coverity scan + + 4/24 + ---- +{bashhist,subst,redir,assoc,jobs,array,trap}.c +lib/intl/l10flist.c +builtins/complete.def + - fixes to memory leaks and other resource usage problems uncovered by + coverity scan + +redir.c + - do_redirection_internal: if dup2 fails (presumably because of a + resource limit), close the file descriptor we opened before returning + error + + 4/25 + ---- +config-top.h + - DEFAULT_BASHRC: new define with the name of the default shell + startup file + +bashline.c + - bash_directory_completion_matches: don't dequote the directory name. + If rl_completion_found_quote is non-zero, readline will dequote the + filename itself. Fixes bug reported by Clark Wang + + + 4/27 + ---- +subst.c + - parameter_brace_expand_rhs: if parameter_brace_find_indir returns + NULL or "", or if it returns something that is not a valid identifier, + report an error and return &expand_wdesc_error so the error can + propagate up. Fixes bug reported by Andre Holzhey + + + 4/29 + ---- +subst.c + - parameter_brace_substring: don't short-circuit right away if the + value is NULL but we are looking at the positional parameters. Part + of fix for bug reported by Pierre Gaston + - pos_params: if there are no positional parameters, only short-circuit + if we are looking for $1 and above. Rest of fix for bug reported + by Pierre Gaston + +subst.h + - SD_NOPROCSUB: new flag for skip_to_delim, means to not allow any + process subsitutions (should not have overloaded SD_NOSKIPCMD) + +subst.c + - skip_to_delim: honor SD_NOPROCSUB flag + +make_cmd.c + - make_arith_for_expr: set W_NOPROCSUB flag in the created word + - make_arith_for_command: set SD_NOPROCSUB in the flags argument to + skip_to_delim so we don't treat <( or >( as a process substitution + (we won't evaluate them in eval_arith_for_expr anyway). Fixes + bug reported by Pierre Gaston + + 5/1 + --- +lib/glob/gmisc.c + - glob_dirscan: new function, takes a pattern and a directory separator + argument and advances the pattern to the last occurrence of the + separator. Like strrchr, but understands extended glob patterns and + uses glob_patscan to skip over them + +lib/glob/glob.c + - extglob_skipname: if the extended globbing pattern is invalid, don't + skip the name + - glob_filename: if there is a slash in the pattern to be matched, and + extglob is enabled, use glob_dirscan to find the real last occurrence + of `/' to avoid being confused by slashes in extglob patterns. Fix + for bug reported by Pierre Gaston + + 5/6 + --- +variables.c + - make_local_variable: only set the att_invisible attribute if + no_invisible_vars isn't set + - find_variable_for_assignment: new function, intended to be called by + code that eventually wants to assign a value to the variable; will not + skip invisible variables; currently identical to find_variable + - find_variable_no_invisible: new function, finds the first visible + instance of variable with a given name in the variable context chain; + eventually will be used to replace find_variable; separate right now + for testing + +variables.h + - find_variable_for_assignment: extern declaration + - find_variable_no_invisible: extern declaration + + 5/7 + --- +variables.c + - make_local_variable: don't clear `invisible' attribute if we are + returning an existing local variable at the right context. Let the + upper layers do that. Fixes bug reported by Dan Douglas + + + 5/8 + --- +lib/readline/input.c + - rl_getc: call RL_CHECK_SIGNALS if a read(2) is interrupted (-1/EINTR) + by SIGALRM or SIGVTALRM (placeholder for non-keyboard-generated + signals of interest) + +builtins/read.def + - edit_line: call bashline_set_event_hook and + bashline_reset_event_hook around call to readline(), so the right + signal handling happens + - read_builtin: make sure we add an unwind_protect call to + bashline_reset_event_hook. These changes fix bug reported in + https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1317476 + +bashline.c + - bash_event_hook: make sure we clean up the readline state by calling + rl_cleanup_after_signal if sigalrm_seen is non-zero. The read builtin + sets this when it times out + + 5/12 + ---- +doc/{bash.1,bashref.texi} + - clarify language to make it clear that changing attributes of a + nameref variable (e.g., export), actually changes the attributes of + the referenced variable. Fixes omission noted by Jeff Haemer + + +arrayfunc.c + - bind_array_var_internal: make sure ENTRY no longer has invisible + attribute before returning. Fixes bug reported by Geir Hauge + + + 5/22 + ---- +execute_cmd.c + - shell_execve: if execve fails and we return 127 or 126, make sure to + set last_command_exit_value if a call to file_error or report_error + causes the shell to exit. This ensures that the shell exits with + the right value. + + 6/6 + --- +shell.c + - drop_priv_mode: print an error message on setuid() failure, optionally + exit if errno == EAGAIN, as it can be on Linux when RLIMIT_NPROC for + the target user is exceeded. + +config-top.h + - EXIT_ON_SETUID_FAILURE: new settable define, will cause the shell to + exit if setuid fails with errno == EAGAIN + + 6/10 + ---- +parse.y + - time_command_acceptable: fix so time is accepted everywhere the + grammar is looking for a `compound_list'. Fixes bug reported by + Dale Worley + + 6/12 + ---- +subst.c + - clear_fifo_list: new function, clears FDs associated with open pipes + in current FIFO list without closing the file descriptors. Can + possibly be used when shell_execve fails and the shell jumps back + to top_level and we don't want the shell to close the open FIFOs + each time through the read-execute loop. Bug reported by Harald + Koenig + + + 6/16 + ---- +builtins/shopt.def + - compat42: make sure the `compat42' option sets the correct variable + for compatibility level. Fixes bug reported by Ondrej Oprala + + +support/bashbug.sh + - fix typo when echoing $USAGE. Report from Shantanu Kulkarni + + +execute_cmd.c + - shell_execve: before longjmp back to subshell_top_level, clear out the + FIFO fd list by calling clear_fifo_list so the FDs (which we inherited + from our parent) aren't closed every time through the read-eval loop. + Fix for bug reported by Harald Koenig + + 6/18 + ---- +subst.c + - extract_process_subst: add additional argument: xflags, allow callers to + pass flags like extract_command_subst + - extract_process_subst: call xparse_dolparen like command substitution + to avoid problems when parsing commands constructs with embedded open + parens. Fixes bug reported by Tim Friske + +subst.h + - extract_process_subst: modified prototype for extern declaration + + 6/19 + ---- +execute_cmd.c + - execute_pipeline: if running with lastpipe enabled, make sure that we + check whether or not the job id is valid using INVALID_JOB before + calling job_exit_status. the jobs list can get frozen and unfrozen in + the presence of nested pipelines and loops and wait_for can clear a + job table entry. Fixes bug reported by + +jobs.c + - freeze_jobs_list: now returns old value of jobs_list_frozen; unused at + current time + +jobs.h + - freeze_jobs_list: change return value + + 6/20 + ---- +lib/glob/smatch.c + - MEMCHR: single-byte and wide character defines (memchr/wmemchr) + +lib/glob/sm_loop.c + - GMATCH: when the wildcards are the last element of the pattern, make + sure they do not match a string containing a `/' if FNM_PATHNAME is + set in FLAGS + - GMATCH: when recursively calling GMATCH after we see a `*', don't + try to consume the rest of the pattern with `*' if FNM_PATHNAME is + set in FLAGS, just consume up to the next slash and then see whether + or not the rest of the pattern matches. Fixes bug reported by Ian + Kelling + - GMATCH: when processing `*' in the pattern, after skipping consecutive + wildcards, if we hit a literal `/' in the pattern and we're looking + for a pathname, skip characters in the string until we find a `/' + (no slash means the match fails), and try to match the rest of the + pattern against the portion of the string after the next `/'. Picked + up from gnulib/glibc + +pathexp.c + - split_ignorespec: since split_ignorespec gets globbing patterns, + make sure we call skip_to_delim with the SD_GLOB flag so delimiters + that occur within bracket expressions don't delimit the pattern. + Fixes problem with [[:digit:]] in GLOBIGNORE reported by Ian Kelling + + +unwind_prot.c + - unwind_protect_tag_on_stack: new function, returns 1 if unwind-protect + frame corresponding to `tag' argument is on unwind-protect stack + +unwind_prot.h + - unwind_protect_tag_on_stack: extern declaration + + 6/30 + ---- +lib/readline/misc.c + - _rl_revert_all_lines: set entry->data to 0 after assigning it to + rl_undo_list to avoid pointer aliasing problems that would result + in entry->line being freed by an undo. The subsequent free would + be a double free. Report and fix from Jared Yanovich + + +subst.c + - command_substitute: other shells do not appear to inherit the -v + option when reading and executing command substitutions. Reported + by Ondrej Oprala + + 7/1 + --- +config-top.h + - CHECKHASH_DEFAULT: new define that supplies the default value for + check_hashed_filenames (`checkhash' shopt option); still 0 by default + +findcmd.c + - check_hashed_filenames: initialize using CHECKHASH_DEFAULT + +lib/readline/histexpand.c + - history_expand: double quotes can inhibit recognition of the history + comment character if history_quotes_inhibit_expansion is non-zero + +lib/readline/doc/{history.3,hstech.texi} + - history_quotes_inhibit_expansion: expand definition to note that it + inhibits scanning for the history comment character as well; correct + typo to make it clear that it only works on double-quoted strings + +lib/sh/zgetline.c + - add new fourth argument: DELIM, allows delimiter to be something + other than newline (if DELIM != '\n', UNBUFFERED_READ should be + non-zero) + - UNBUFFERED_READ is now fifth argument + - check character against DELIM rather than strictly newline + +externs.h + - zgetline: change function prototype for extern declaration + +builtins/mapfile.def + - mapfile: change calling sequence for zgetline calls + - mapfile_builtin: new -d option: DELIM, like in read builtin + - mapfile_builtin: pass `delim' to mapfile() as new argument; default + to '\n' unless -d option supplied + - mapfile: take new DELIM argument, pass to zgetline + - mapfile: if DELIM != '\n', set unbuffered_read to 1 + +doc/{bash.1,bashref.texi} + - mapfile: document new `-d DELIM' option + + 7/5 + --- +lib/readline/histfile.c + - history_truncate_file: if there is an error writing the truncated + history list back to the history file, use the same strategy as + history_do_write: create a backup file, rename the history file to + the backup file, and restore the original history file from the + backup file name if the write or the close fails. Suggestion from + Chen Gang to bug-readline + +execute_cmd.c + - evalnest, evalnest_max: new variables establishing maximum number of + recursive `eval' calls; current max is 4096 + - execute_builtin: unwind-protect value of evalnest around calls to + eval builtin. Suggested by Oliver Morais + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + evalnest to 0 in a subshell + +builtins/setattr.def + - show_name_attributes: show a variable's attributes even if it's + invisible (don't show any value since it has none). This means that + declare -p var will display VAR's attributes even when var marked + as invisible. Feature request from Peggy Russell + + - show_var_attributes: don't print assignment if array or assoc + attribute is set but variable marked as invisible + +tests/array.right + - special note: changed all declare -a output tests because the shell + will no longer print out values for invisible array variables. This + is a change, but one for correctness: + + declare -a foo='()' + and + declare -a foo + are not equivalent + + 7/22 + ---- +subst.c + - parameter_brace_expand: after calling parameter_brace_expand_indir, + turn off the W_ARRAYIND flag in the word it returns, because there + is no way for it to return the index that should be used, and the + rest of the function assumes that IND is valid if W_ARRAYIND is set. + Fixes bug reported by Corentin Peuvrel + + 8/2 + --- +parse.y + - read_token_word: if we read a character that will end a command + substitution, don't skip over quoted newlines when we read an + additional character to figure out whether it's a two-character + token. This lets the higher layers deal with quoted newlines after + the command substitution. Fixes bug reported by EmanueL Czirai + + + 8/11 + ---- +execute_cmd.c + - execute_pipeline: check whether lastpipe_jid corresponds to a valid + job before calling append_process, for the same reason as fix from + 6/19. Fixes bug reported by + + 8/12 + ---- +lib/sh/unicode.c + - stub_charset: use strncpy instead of strcpy because we are copying + into a local fixed-length buffer. Fixes vulnerability reported by + + +execute_cmd.c + - execute_pipeline: if we don't call append_process, call + wait_for_single_pid to get the status of `lastpid', since that will + check the status of already-reaped processes. Fixes spurious error + message about non-existent process from fix of 8/11 + + 8/15 + ---- +jobs.c + - running_in_background: new variable, keeps track of whether or not we + are running in the background (not perfect yet) + - initialize_job_control: even if we are not turning on job control, + get the terminal pgrp so we can use it later + - {set_job_control,initialize_job_control}: set running_in_background + to 1 if terminal pgrp != shell pgrp + - {stop_pipeline,make_child,wait_for}: if we are running in the + background, don't mess with the terminal's process group; assume that + the parent shell will do that. Fixes bug reprted by Greg Wooledge + + +shell.c + - shell_reinitialize: reset running_in_background back to 0 + + 8/24 + ---- +execute_cmd.c + - {execute_connection,execute_command_internal}: make sure that + asynchronous commands always set $? to 0 and are not affected by the + command's exit status being inverted using `!'. Fixes bug reported + by Vincent Lefevre + +lib/readline/display.c + - rl_message: call vsnprintf with full msg_bufsiz, since it counts + one fewer than the buffer length passed as an argument. Bug report + and fix from Dylan Cali + + 8/26 + ---- +builtins/evalstring.c + - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This + is instead of calling reset_parser(); that might still be needed. + Fixes bug with eval and a subsequent statement ending with EOF + reported by + +pcomplete.c + - filter_stringlist: when extglob is on, a leading ! in the filter + pattern should be left alone when it introduces a !(pat) pattern; + otherwise it messes up the pattern. Fixes bug reported by David + Korn + + 8/27 + ---- +doc/{bash.1,bashref.texi} + - clarify the behavior of bash when given the -c option, since $0 is + technically not a positional parameter. Bug reported by Stephane + Chazelas + + 8/28 + ---- +lib/readline/history.c + - add_history: use history_max_entries (if history is stifled) or + DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502) + to size the initial allocation of the history array. Assumption + is that this will reduce the number of allocations + + 8/29 + ---- +execute_command.c: + - sourcenest, sourcenest_max: new variables used to track level of + sourced files and (maybe) one day catch infinite source recursion + - execute_builtin: if current source level exceeds sourcenest_max, + trigger an error and jump back to the top level + - {initialize_subshell,execute_subshell_builtin_or_function}: reset + sourcenest to 0 in a subshell + + 9/2 + --- +variables.c + - bind_variable: if a nameref expands to an array reference, make + sure that assign_array_element gets called (maybe even + recursively) instead of bind_variable_internal, so invalid variable + names (like arr[0]) don't get created. Fixes bug reported by + + + 9/3 + --- +execute_cmd.c + - evalnest_max,sourcenest_max: initialize from EVALNEST_MAX and + SOURCENEST_MAX, respectively. Feature suggested by + + +config-top.h + - define EVALNEST_MAX and SOURCENEST_MAX to 0 + + 9/6 + --- +bashline.c + - find_cmd_start: fix to (crudely) deal with >| token; even though + skip_to_delim finds `|' as a delimiter, we call it again and use + what the second call finds. Fixes bug reported by Dan Jacobson + + +findcmd.c + - find_in_path_element: if in posix mode, do not expand a literal + tilde in a $PATH element + +doc/bashref.texi + - add change to tilde expansion in $PATH elements to posix mode + description + +builtins/common.h + - ISHELP: new define for builtins that do their own option parsing + and don't use internal_getopt(); checks whether argument is --help + - CHECK_HELPOPT: convenience define to help builtins that do their + own option parsing to check for --help with one line of code + - CASE_HELPOPT: convenience define to help builtins that use + internal_getopt() check for --help with one line of code + +builtins/help.def + - builtin_help: new function, prints out --help output for current + builtin + +builtins/{kill,let,pushd}.def + - add CHECK_HELPOPT to builtins that use ISOPTION; call builtin_help + and return EX_USAGE (kill/let/pushd/popd/dirs) + +builtins/{caller,fg_bg}.def + - use CHECK_HELPOPT to recognize --help, since these builtins perform + checks that can cause them to return before calling no_options + (caller/fg/bg) + +builtins/{exit,return}.def + - use CHECK_HELPOPT to recognize --help before calling get_exitstat() + (return/exit/logout) + +builtins/{break,shift}.def + - use CHECK_HELPOPT to recognize --help before any other checks + (break/continue/shift) + +builtins/bashgetopt.h + - GETOPT_EOF: convenience define + - GETOPT_HELP: new define, to indicate internal_getopt saw --help + +builtins/bashgetopt.c + - internal_getopt: return GETOPT_HELP for --help + +builtins/common.c + - no_options: recognize --help, call builtin_help and return 2 + (builtin/eval/source/./times) + +builtins/command.def + - use CASE_HELPOPT() to handle --help after calling internal_getopt() + (command) + +builtins/{colon,echo,test}.def + - do not recognize --help (:/true/false/echo/test) + + 9/8 + --- +sig.c + - termsig_sighandler: if readline is active now, set the bashline event + hook. Old code just set it for interactive shells. Part of fix for + bug reported by + +bashline.c + - bash_event_hook: call rl_cleanup_after_signal if terminating_signal + is non-zero, since check_signals_and_traps() will cause the shell to + exit if it is and we want to clean up the readline state first. Rest + of fix for bug reported by + + 9/9 + --- +jobs.c + - waitchld: when running the wait builtin in posix mode, with a trap set + on SIGCHLD, use queue_sigchld_trap instead of trap_handler (SIGCHLD), + otherwise you will lose SIGCHLDs when children_exited > 1. Fixes bug + reported by + +builtins/read.def + - read_builtin: if we are changing the tty settings, call + initialize_terminating_signals so we have a chance to catch all + terminating signals and potentially clean up the terminal before + exiting + - read_builtin: tty_modified: new variable, set to 1 if we change the + terminal attributes and have to call ttyrestore() to restore them + - if one of the `reads' returns -1/EINTR due to a terminating signal, + and we have modified the terminal, call ttyrestore before calling + CHECK_TERMSIG + - ttyrestore: set tty_modified to 0 when called + + 9/10 + ---- +builtins/read.def + - termsave: now global to file so other functions can use it + - read_tty_cleanup: if tty_modified is non-zero, call ttycleanup to restore + old terminal settings and turn off tty_modified + +sig.c + - termsig_handler: call read_tty_cleanup if currently executing read + builtin; it does the right thing. Final piece of fix for bug reported + by Jan Rome + + 9/11 + ---- +general.c + - printable_filename: general function to return a printable representation + of a string (presumed to be a filename) + +general.h + - extern declaration for printable_filename + +execute_cmd.c + - execute_disk_command: use printable_filename + +builtins/{bind,cd,enable,hash,source}.def + - use printable_filename as appropriate when printing error messages. + From a suggestion by Vincent Lefevre + +builtins/bind.def + - use CASE_HELPOPT() to handle --help after calling internal_getopt() + (bind) + + 9/12 + ---- +builtins/common.h + - SEVAL_FUNCDEF: new flag for parse_and_execute; it means that we only + accept a single function definition command, as when we are importing + functions from the environment + - SEVAL_ONECMD: new flag for parse_and_execute; for future use + +builtins/evalstring.c + - parse_and_execute: if the SEVAL_FUNCDEF flag is set, disallow anything + but a function definition command + +variables.c + - initialize_shell_variables: don't allow functions with invalid names + to be imported from the environment, even though we still allow them + to be defined + - initialize_shell_variables: when importing function definitions from + the environment, call parse_and_execute with the SEVAL_FUNCDEF flag + to force the command to be just a function definition + +subst.c + - param_expand: when expanding a $name variable expansion, make sure that + the variable is visible and set before following the nameref chain + - param_expand: when expanding a $name variable expansion and following the + nameref chain, make sure the resulting variable is visible and set + before using it + + 9/13 + ---- +variables.c + - initialize_shell_variables: when importing function definitions from + environment, use SEVAL_ONECMD flag for parse_and_execute. Part of + CVE-2014-6271 + +builtins/evalstring.c + - parse_and_execute: if SEVAL_ONECMD flag set, return immediately after + calling execute_command_internal. Final piece for fix for bug + reported by Stephane Chazelas . Part of + CVE-2014-6271 + + 9/24 + ---- +parse.y + - reset_parser: reset eol_ungetc_lookahead to 0 here, since we don't want + shell_getc returning it on the next call. Fixes problem reported by + Tavis Ormandy and Michal Zalewski + . Potentially part of CVE-2014-6271; fix for + CVE-2014-7169 + + 9/25 + ---- +parse.y + - push_heredoc: new function, pushes a here-doc redirection onto + redir_stack handling overflow of redir_stack. Exits on overflow. + Original fix from Florian Weimer . Fix for + CVE-2014-7186 + - change straight assignments to redir_stack to call push_redir + - add one to size of word_lineno stack to avoid off-by-one error + below in read_token_word. Overflow just results in line numbers + being wrong. Fix for CVE-2014-7187 + + 9/27 + ---- +{execute_cmd,trap}.c + - changes to make minimal-config builds work again, mostly missing + #ifdefs for optional features + +builtins/common.c + - builtin_help: dummy version to be included if HELP_BUILTIN not + defined, for minimal-config builds + +variables.c + - initialize_shell_variables: incorporated patches from Florian + Weimer to change the strings bash looks + for when importing shell functions from the environment. It + adds a prefix (BASH_FUNC_) and a suffix (%%) to the name to + mark it as having been created by bash as an exported function. + Fix for remote attacks part of CVE-2014-6271 and CVE-2014-7169 + - mk_env_string: takes new argument, indicating whether we are + constructing a function + - mk_env_string: encodes function names as described above, so + initialize_shell_variables can find them + + 9/28 + ---- +copy_cmd.c + - copy_redirects: before calling savestring on here_doc_eof, make + sure it's not NULL (it could have been the result of a here + document delimited by EOF or EOS). Fixes bug reported by + Michal Zalewski . Fix for CVE-2014-6277 + +make_cmd.c + - make_redirection: initialize here_doc_eof member to NULL. Rest of + fix for CVE-2014-6277 + + 9/29 + ---- +parse.y + - current_input_line_state: return a sh_input_line_state_t containing + the current shell_input_line and its index and size variables + +shell.h + - current_input_line_state: extern declaration + +builtins/evalstring.c + - parse_and_execute: call reset_parser() before returning if + SEVAL_ONECMD set. Fixes bug reported by Michal Zalewski + and designated CVE-2014-6278 + - parse_and_execute: if we parse a function definition when + SEVAL_FUNCDEF is set, but don't consume the entire passed string, + throw an error, reset the parser, and return. Part of fix for + CVE-2014-6278 + - parse_and_execute: if parsing the shell function definition when + SEVAL_FUNCDEF is set transforms the function name (e.g., if it + begins with a newline or begins or ends with whitespace), throw + an error, reset the parser, and return. Fixes bug reported by + Eric Kobrin + + 10/2 + ---- +jobs.c + - bgp_prune: don't do anything if bgpids.npid == 0 or bgpids.list == NULL. + This can happen if something gets run before the job control framework + is initialized. Bug report from + + 10/3 + ---- +parse.y + - xparse_dolparen: don't set token_to_read to newline after calling + parse_string() and cleaning up when the shell is not interactive. This + makes the parser thing it's ok to read new commands even if it's not in + a state where that should be possible. Underlying fix for bug reported + by Michal Zalewski and designated CVE-6278 + - parser_remaining_input: new function, returns the portion of + shell_input_line that hasn't yet been read + - current_input_line_state: removed + +shell.h + - parser_remaining_input: extern declaration + - current_input_line_state: removed + +builtins/evalstring.c + - parse_and_execute: change code that checks whether parse_command has + consumed the entire passed string when SEVAL_FUNCDEF is used to use + parser_remaining_input instead of messing around with (new) + current_input_line_state. Part of fix for CVE-2014-6278 + +variables.c + - initialize_shell_variables: if we don't call parse_and_execute, free the + temporary string, since parse_and_execute won't. Report and fix from + Eric Kobrin + + 10/4 + ---- +print_cmd.c + - print_function_def: when in posix mode, print shell function + definitions as posix specifies them, without the leading + `function' keyword + +general.c + - exportable_function_name: return 1 if the passed string can be + added to the environment as an exported function name. Currently + prohibits function names containing `/' and `=' from being + exported + +general.h + - exportable_function_name: extern declaration + +builtins/setattr.def + - set_or_show_attributes: if exporting a function with export -f, + call exportable_function_name to determine whether the function + should be exported; don't export function if it returns 0 + + 10/7 + ---- +builtins/setattr.def + - set_or_show_attributes: don't show identifiers that are invisible + and imported from the environment, since that combination of + attributes means that the imported variable is not a valid shell + identifier. Report from Stephane Chazelas + + 10/8 + ---- +shell.c + - shell_initialize: set new variable should_be_restricted, which + says whether or not the shell will be a restricted one based on the + shell name; use in calls to initialize_shell_variables (to inhibit + importing shell functions) and initialize_shell_options (to inhibit + parsing $SHELLOPTS) and initialize_bashopts (to inhibit parsing + $BASHOPTS). Report from + + 10/12 + ----- +execute_cmd.c + - execute_function: unwind-protect loop_level, set loop_level to 0 + when entering a function so break and continue in functions don't + break loops running outside of the function. Fix picked up from + dash via Herbert Xu + + 10/13 + ----- +doc/Makefile.in + - bashref.pdf: create using texi2dvi --pdf rather than postprocessing the + dvi file, so we have PDF bookmarks and links. Fix from + Siep Kroonenberg + + 10/14 + ----- +subst.h + - Q_ARITH: new quoting flag. Semantics are per Posix's spec for arithmetic + expansion: act as if string is quoted, but don't treat double quotes + specially (in this case, they will be removed by quote removal) + - Q_ARRAYSUB: new quoting flag, indicates we are expanding an indexed array + subscript + +subst.c + - expand_arith_string: if we are not expanding the string, but we saw a quote + with Q_ARITH specified as one of quoting flags, perform quote removal even + if Q_DOUBLE_QUOTES is specified + - param_expand: change calls to expand_arith_string for $[ and $(( cases to + specify Q_ARITH. Now $(( "$x" )) and $(( "x" )) work if x has a value that + evaluates to a valid number, as Posix specifies + - expand_word_internal: add test for quoted&Q_ARITH to the tilde case, so we + continue to perform tilde expansion in arithmetic contexts + - expand_word_internal: if quoted&Q_ARITH, continue processing when we see a + `"', acting as if the double quote isn't present (already Q_DOUBLE_QUOTED) + +arrayfunc.c + - array_expand_index: pass Q_DOUBLE_QUOTED|Q_ARITH|Q_ARRAYSUB as quoted argument + in call to expand_arith_string. This inhibits word splitting + (Q_DOUBLE_QUOTED) while discarding double quotes (Q_ARITH), identical to the + quote flags passed while expanding $(( )) and $[ ]. Q_ARRAYSUB reserved for + future use. Fixes problem reported by Stephane Chazelas + + + 10/16 + ----- +subst.c + - parameter_brace_expand_word: if the PF_ASSIGNRHS flag is set and we + are expanding what looks like an array subscripted with @ or *, + make sure the variable we're expanding is actually an array before + we add Q_DOUBLE_QUOTES to the flags. If we don't, things like + scalar[@] will remain quoted. Fixes ubuntu bug 1381567 + https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1381567 + + 10/17 + ----- +{jobs,nojobs}.c + - get_original_tty_job_signals: get original signal dispostions for + SIGTSTP, SIGTTIN, SIGTTOU before we start manipulating them in + make_child + - default_tty_job_signals: make sure we set SIGTSTP, SIGTTIN, or + SIGTTOU to SIG_IGN if they were ignored at shell startup instead of + unconditionally setting them to SIG_DFL. Fixes bug reported by + idallen@idallen.ca + +jobs.h + - get_original_tty_job_signals: extern declaration + +trap.c + - initialize_traps: add call to get_original_tty_job_signals + + 10/22 + ----- +subst.c + - expand_string_for_rhs: when expanding in this context (rhs of a word + expansion or pattern removal), we don't perform word splitting, so + we don't want to split $* if IFS is empty. Fixes bug reported by + Stephane Chazelas + + 10/23 + ----- +subst.c + - param_expand: when expanding $* in a pattern context where the + expansion is quoted (Q_PATQUOTE), don't quote the expansion -- + the outer quotes don't make the characters in the expansion of + $* special. Posix interp 221. Reported by Stephane Chazelas + + + 10/28 + ----- +lib/readline/bind.c + - enable-bracketed-paste: new bindable variable, enables support for + a terminal's `bracketed paste mode'. Code contributed by + Daniel Colascione + +doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} + - enable-bracketed-paste: add description + +lib/readline/{readline.c,rlprivate.h} + - _rl_enable_bracketed_paste: declarations + - #defines for use by bracketed paste implementation + +lib/readline/rltty.c + - rl_prep_terminal: send BRACK_PASTE_INIT string to terminal if we + are supposed to enable bracketed-paste mode; change terminal_prepped + to indicate we sent that string and need to clean up + - rl_deprep_terminal: if terminal_prepped indicates we sent the + bracketed-paste mode init string to the terminal, send the cleanup + string before restoring the terminal modes + +lib/readline/kill.c + - rl_bracketed_paste_begin: function to read bracketed paste until + BRACK_PASTE_SUFF; discard the suffix, and insert the rest of the + paste as a single (undoable) object. Bound to BRACK_PASTE_PREF + +lib/readline/funmap.c + - bracketed-paste-begin: new bindable command, executes + rl_bracketed_paste_begin + +lib/readline/readline.c + - bind_bracketed_paste_prefix: new function, sets up to recognize + the bracketed paste prefix sequence (BRACK_PASTE_PREF) in emacs + keymap and vi insertion keymap + - readline_initialize_everything: call bind_bracketed_paste_prefix + + 11/1 + ---- +builtins/ulimit.def + - RLIMIT_POSIXLOCKS: now synonym for RLIMIT_LOCKS + - -k: new option: RLIMIT_KQUEUES, max kqueues allocated for this + process + - -P: new option: RLIMIT_NPTS, max number of pseudoterminals available + to this process + +doc/{bash.1,bashref.texi} + - document `ulimit -k' option + - document `ulimit -P' option + +parse.y + - `timespec list_terminator' production: if the list terminator is `;' + set last_read_token to `;' to allow things like `time ; command' to + time null commands and not throw a syntax error. Patch from + Piotr Grzybowski + - `BANG list_terminator' production: do the same thing + +variables.c + - sv_optind: use find_shell_variable and get_variable_value so we can + have the variable's context in the case we need to do something + when we are restoring a previous variable context's value + +builtins/getopt.h + - sh_getopt_state_t: struct to save sh_getopt's internal state so we + can restore it around function calls in the event that we have a + local copy of OPTIND + +builtins/getopt.[ch] + - sh_getopt_{save,restore}_istate: new functions to save and restore + getopt's internal state + - sh_getopt_{alloc,dispose}_istate: new functions to allocate and + deallocate sh_getopt_istate_t objects + +execute_cmd.c + - maybe_restore_getopt_state: restore sh_getopt state after executing + function body iff the funtion declared a local copy of OPTIND + - execute_function: save sh_getopt state before executing function body + - execute_function: note in getopt_state->flags whether or not the + function declared a local copy of OPTIND; used by maybe_restore_getopt_state + - execute_function: maybe restore sh_getopt state before returning via + call to maybe_restore_getopt_state. Fixes bugs with getopts and + state between calls reported in 2011 by Bernd Eggink + and in 2014 by Oyvind Hvidsten + +configure.ac + - enable-function-import: new option, controls whether function imports + are included. Enabled by default. Patch from David Galos + + +config.h.in + - FUNCTION_IMPORT: define controlled by enable-function-import above + +variables.c + - initialize_shell_variables: include code to import function definitions + from the environment if FUNCTION_IMPORT is defined + +doc/bashref.texi + - --enable_function-import: document new configuration option + + 11/5 + ---- +lib/readline/history.c + - history_lines_read_from_file: new variable, set by read_history and + read_history_range to the actual number of lines read from the + history file. The value is valid immediately after a call to one + of those functions + - history_lines_written_to_file: new variable, set by write_history, + history_do_write, and history_truncate_file to the actual number of + lines written to the history file. The value is valid immediately + after a call to one of those functions + +variables.c + - sv_histsize: set history_lines_in_file after history_truncate_file() + only if hmax < history_lines_in_file (lines we've already read); a + cosmetic change only + +bashhist.c + - load_history: set history_lines_in_file after read_history() from + history_lines_read_from_file, since read_history reads all of the + lines from the history file even if it's more than $HISTSIZE + - maybe_save_shell_history: after calling write_history(), set + history_lines_in_file to history_lines_written_to_file, since we + can assume that we read everyhing we just wrote + +builtins/history.def + - history_builtin: after calling read_history (history -r), set the + new value of history_lines_in_file, for the same reason as above + - history_builtin: after calling read_history_range (history -n), set + history_lines_in_file from history_lines_read_from_file + + 11/6 + ---- +lib/readline/histfile.c + - history_truncate_file: since we move the old file to a backup copy + before truncating, make sure the new file is owned by the same uid + as the old + - history_do_write: use chown in the same way as history_truncate_file + + 11/12 + ----- +lib/readline/display.c + - expand_prompt: takes a new `flags' argument; only one flag defined + so far: PMT_MULTILINE + - expand_prompt: changed all callers to add new flags argument + - rl_expand_prompt, redraw_prompt: make sure to set PMT_MULTILINE in + FLAGS argument to expand_prompt if expanding parts of a prompt + containing embedded newlines + - expand_prompt: only add mode char to last line of a prompt with + embedded newlines, so mode indicator doesn't get lost and gets + updated properly. Fixes problem reported by Renlin Li + + + 11/13 + ----- + +lib/readline/display.c + - prompt_modestr: changed prompt_modechar to return a string denoting + the editing mode; default strings for emacs and both vi modes are + #defines in this file. prompt_modestr takes an argument in which + it returns the length of the mode string + - expand_prompt: if expanding mode strings in the prompt, get the + mode string to use and add it at the beginning of the prompt string, + before expanding it. This will allow future work allowing the mode + string to contain invisible characters + + 11/15 + ----- +lib/readline/rlprivate.h + - _rl_{emacs,vi_cmd,vi_ins}_mode_str: extern declarations for + variables to hold current values of user-settable mode strings; + variables to hold lengths + +lib/readline/rlconf.h + - defines for default values of the mode strings for each editing mode + and keymap + +lib/readline/display.c + - _rl_{emacs,vi_cmd,vi_ins}_mode_str: new variables to hold values of + user-settable mode strings + - _rl_{emacs,vi_cmd,vi_ins}_modestr_len: new variables to hold lengths + of corresponding mode string variables + - prompt_modestr: return appropriate user-settable mode string + variables + +lib/readline/bind.c + - {emacs,vi-ins,vi-cmd}-mode-string: new user-settable mode string + variables + - sv_{emacs,viins,vicmd}_modestr: variable handling functions for user- + settable mode string variables. Non-null values are run through + rl_translate_keyseq so users can include invisible character + sequences in the mode strings; null values restore the default + - _rl_get_string_variable_value: handle values for new user-settable + mode string variables. Original code contributed by Dylan Cali + + +lib/readline/doc/rluser.texi + - {emacs,vi-ins,vi-cmd}-mode-string: document, including the fact that + you can use \1 and \2 to bracket sequences of non-printing + characters + + 11/16 + ----- +lib/readline/history.c + - add_history: replace loop that copies history list down one item + with call to memmove to take advantage of whatever efficiencies + libc can offer. Won't be any slower than current loop + +lib/readline/display.c + - rl_redraw_prompt_last_line: new function, calls redraw_prompt if + the prompt contains multiple lines; calls rl_forced_update_display + if not + +lib/readline/readline.h + - rl_redraw_prompt_last_line: extern declaration, undocumented in + texinfo manual until I get it a little more work + +bashline.c + - bash_execute_unix_command: instead of unconditionally calling + rl_forced_update_display, call rl_redraw_prompt_last_line if we + cleared the last line before executing the command. This keeps + commands that don't display any other output but just manipulate + the contents of the line buffer from redisplaying the prompt lines + before the last newline multiple times. Fixes bug reported by + Jesper Nygards and Rob Foehl + . This means that commands that display output + will *only* display the final line of the prompt + - bash_execute_unix_command: if the command returns 124, we redraw + the line unconditionally, including all lines of the prompt + + 11/18 + ----- +builtins/mapfile.def + - mapfile_builtin: don't allow a valid array reference through to + mapfile(), since it will just create a shell variable with that name. + Bug and fix from Eduardo A. Bustamante López + + 11/19 + ----- +lib/readline/complete.c + - _rl_colored_completion_prefix: new variable, if non-zero, and color + support is compiled in, and the $LS_COLORS variable exists and + contains color definitions, display any common prefix of a set of + completions in blue when displaying all the possible completions. + Doesn't work with menu-complete, which inserts possible completions + inline + - colored_prefix_start(), colored_prefix_end(): new functions, used to + bracket colored completion prefixes + - fnprint: if prefix_bytes is non-zero, and _rl_colored_completion_prefix + is > 0, display the first PREFIX_BYTES bytes of the word bracketed + by calls to colored_prefix_start and colored_prefix_end + - print_filename: if _rl_colored_completion_prefix is > 0, compute the + length in bytes of the common prefix and pass that to fnprint + +lib/readline/readline.c + - readline_initialize_everything: initialize the colors from $LS_COLORS + if _rl_colored_completion_prefix is non-zero + +lib/readline/colors.c + - _rl_print_prefix_color: new function, changes text color to that + defined for the common prefix of a set of possible completions + (currently cyan, same as directories); currently uses C_PREFIX, + defined in colors.h as C_DIR + +lib/readline/colors.h + - _rl_print_prefix_color: new extern declaration + +lib/readline/bind.c + - colored-completion-prefix: new bindable variable, if set, common + prefix of a set of possible completions is displayed in color. + Feature requested by several, most recently by Richard Neill + (in a slightly different form) and + Duy Nguyen + + 11/20 + ----- +builtins/printf.def + - printf_builtin: allow null (empty) format strings supplied with + -v var to set `var' to the empty string. That is, printf -v var "" + is now the same as var="". Change suggested by Mike Frysinger + + +pathexp.h + - FNMATCH_NOCASEGLOB: macro to decide whether or not to pass + FNM_CASEFOLD flag to strmatch depending on whether glob_ignore_case + is set; analogout to FNMATCH_IGNCASE + +pathexp.c + - glob_name_is_acceptable: use FNMATCH_NOCASEMATCH to determine flags + passed to strmatch; if nocaseglob is used to generate glob matches, + it should be used to generate ignored matches + + 11/21 + ----- +pcomplete.c + - filter_stringlist: the call to strmatch now honors the setting of + nocasematch. Feature request from Ville Skytta + back in 2010 + +doc/bash.1,lib/readline/doc/rluser.texi + - complete -X: document that filtering the list of possible completions + honors the nocasematch option when performing matching + +lib/glob/gmisc.c + - include chartypes.h and strmatch.h for new defines + - match_pattern_{wchar,char}: now take new third FLAGS argument, flags + have same meanings as strmatch(); intent is to handle case + insensitive comparisons under same conditions as strmatch + - FOLD: imported case-folding define from sm_loop.c; wide and single- + byte character versions + - match_pattern_{wchar,char}: use FOLD when comparing characters to + honor FNM_CASEFOLD if set in FLAGS argument + +externs.h + - match_pattern_{wchar,char}: updated extern declarations + +subst.c + - match_{upattern,wpattern}: update strmatch/wcsmatch calls to include + FNMATCH_IGNCASE in flags argument + - match_{upattern,wpattern}: update match_pattern_{char,wchar} calls + to include FNMATCH_IGNCASE in flags argument (consistent with calls + to strmatch). This makes pattern substitution word expansion honor + nocasematch shell option. Feature requested by Davide Baldini + + - match_wpattern: make sure to fold case if necessary when doing simple + matching + +doc/{bash.1,bashref.texi} + - pattern substitution: updated description to include honoring setting + of nocasematch when performing matching + +subst.c + - expand_word_internal: optimize handling of "$@" idiom by calling + list_rest_of_args() and quote_list() directly at the top of the + function instead of going through normal code path + - cached_quoted_dollar_at: WORD_LIST of quoted positional parameters, + used by same code above that optimizes "$@"; if non-null we just + return a copy of the list; if null, we save a copy of the list we + create + - invalidate_cached_quoted_dollar_at: convenience function to allow + other parts of the shell (e.g., remember_args()) to destroy the + cached list of quoted positional parameter when the positional + parameters change + +builtins/common.c + - remember_args: call invalidate_cached_quoted_dollar_at() + +builtins/shift.def + - shift_builtin: call invalidate_cached_quoted_dollar_at after modifying + dollar_vars[] + +builtins/source.def + - maybe_pop_dollar_vars: call invalidate_cached_quoted_dollar_at just + to be safe + + 11/23 + ----- +builtins/evalfile.c + - _evalfile: return -1 if errno == ENOENT and the flags don't include + FEVAL_ENOENTOK. If we print an error message we should return an + error + - force_execute_file: new function, reads and executes commands from + a file but returns an error if file doesn't exist + +builtins/common.h + - force_execute_file: new extern declaration + +shell.c + - main: call start_debugger even if dollar_vars[1] == 0 if the shell + isn't interactive (interactive_shell == 0) + - start_debugger: call force_execute_file instead of maybe_execute_file; + turn off debugging mode if it returns value < 0 + + 11/24 + ----- +hashlib.h + - DEFAULT_HASH_BUCKETS: doubled to 128, cost in memory use is small but + changes traversal order when not sorting results + + 11/25 + ----- +doc/{bash.1,bashref.texi} + - make it clearer, by breaking it out into a separate paragraph, that + referencing an array without a subscript is equivalent to referencing + it with subscript 0 + - add text saying that referencing any variable using a valid subscript + is OK + + 11/28 + ----- + +arrayfunc.c + - bind_array_variable, bind_assoc_variable: allow binding value to a + readonly variable if the ASS_FORCE flag is set in the FLAGS + argument + +subst.h + - ASS_FORCE: new assignment flag; means to allow assignment even if + variable is marked readonly + +builtins/declare.def + - when assigning a value to an array or assoc variable using + something like `declare -r foo=bar' where foo is an existing array + variable, pass the ASS_FORCE to assign_array_var_from_string so + the assignment is allowed. Fixes debian bug 765759 + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=765759 + +builtins/setattr.def + - var_attribute_string: new function to return (as argument) a char + array with attribute flag values for a given variable; returns the + length of the array + +lib/sh/shquote.c + - sh_quote_reusable: function returning a version of its string + argument that is quoted for reuse + +externs.h + - sh_quote_reusable: extern declaration + +builtins/common.h + - MAX_ATTRIBUTES: define used to size arrays for attribute flag + characters + - var_attribute_string: new extern function declaration + +subst.c + - array_remove_pattern: fixed a bug where `var' instead of `v' was + tested for invisible attribute + - get_var_and_type: fill in a valid *VARP if returning VT_VARIABLE + because callers may need to use it + - parameter_brace_transform: family of functions to implement the new + mksh-inspired ${param@spec} transformation word expansions. Some + of the operators transform the (expanded) value of the parameter, + the rest expand to information about the parameter itself + (array_transform, parameter_list_transform, list_transform, + string_transform, pos_params_assignment, array_var_assignment, + string_var_assignment) + - parameter_brace_expand: changes to parse the new `@' word expansion + operator and call parameter_brace_transform appropriately + - parameter_brace_expand: make sure we handle ${#@} as we have before + even in the presence of the new `@' operator + +variables.c + - push_temp_var: make sure to call bind_variable_internal with the + ASS_FORCE flag so we override readonly variables created with + something like `tempvar=foo declare -r foo'. + - bind_variable_internal: honor ASS_FORCE flag to allow binding even + if a variable is readonly + +execute_cmd.c + - struct func_array_state: new state to save state of BASH_LINENO, + BASH_SOURCE, and FUNCNAME during function execution so it can be + restored on a jump to top level + - restore_funcarray_state: new function to restore func_array_state + - execute_function: fill in func_array_state variable, add unwind- + protect to restore it on jump to top level, call explicitly at + end of function if subshell != 0 (may not be necessary, but safe + for now). Fixes bug with local assignments to FUNCNAME reported + by Arfrever Frehtes Taifersar Arahesis + + 11/29 + ----- +arrayfunc.c + - assign_compound_array_list: turn off ASS_APPEND flag when processing + each individual assignment inside the parens in var+=(...). The + outer += should not affect assignments to existing subscripts; + those should be treated like usual assignments unless += supplied + inside the parens. Bug report from Maarten Billemont + , fix from Eduardo A. Bustamante López + + +config.h.in + - HAVE_PSELECT: define if pselect(2) available + +configure.ac + - check for pselect(2), define HAVE_PSELECT if found + +lib/readline/input.c + - rl_getc: use pselect(2) to wait for input ready on readline's + input fd or for a signal to arrive, will handle SIGWINCH (which + does not interrupt read(2)) and thus allow resize to happen without + having to wait to read more input. Only works if pselect available + and returns -1/EINTR on a signal even if the signal was installed + with SA_RESTART. From a suggestion from Egmont Koblinger + + + 12/3 + ---- +variables.c + - flush_temporary_env: new function, disposes all temp variables in + temporary_env hash table + - bind_variable: only try to update a temporary variable's value in the + temporary env if the value argument is not null. Fixes bug reported + by + +variables.h + - flush_temporary_env: new extern declaration + +subst.c + - command_substitute: if running command substitution as part of + expanding a redirection (expanding_redir == 1), flush any temporary + environment we've inherited as part of this command, since we are not + supposed to have access to the temporary environment. Since + expanding_redir only controls access to the temporary environment for + variable lookup and binding, we can turn it off in the subshell + + 12/4 + ---- +builtins/printf.def + - printstr: make sure a missing precision specifier after a `.' is + treated as 0, as printf(3) specifies. Fixes ubuntu bash bug + 1399087 (https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1399087) + + 12/5 + ---- +subst.c + - skip_to_delim: if scanning past process substitution (skipcmd == 1, + noprocsub == 0), use extract_delimited_string instead of + extract_process_subst, which was changed a while back (bash-4.3.23) + to use xparse_dolparen. xparse_dolparen complains if the command + or process substitution is unterminated, since it runs the parser, + which is not what we want here. Command substitution does the same + thing. Fixes bug reported by Daniel Kahn Gillmor + as Debian bash bug 771968 + (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=771968) + + 12/6 + ---- +subst.c + - command_substitute: short-circuit without forking on a command string + that consists entirely of s and newlines + +jobs.c + - make_child: changes to allow interrupts through if fork fails and + we are sleeping for `forksleep' seconds + - waitchld: make things a little more resilient if CHILD ends up NULL + + 12/12 + ----- +lib/readline/complete.c + - rl_display_match_list: when calculating common prefix to display in + color, make sure we correctly handle a common prefix with a trailing + `/' as we do when checking whether or not to add an ellipis. + printable_part() doesn't return the whole pathname if it ends in a + slash, to avoid printing null strings, so we have to make sure we + have the entire prefix + +lib/readline/complete.c + - _rl_complete_display_matches_interrupt: new variable, set to 1 by + _rl_complete_sigcleanup to let rl_display_match_list know it has + freed the match list + - display_matches: check for signals during the printing loops with + RL_SIG_RECEIVED(), return immediately if there is a pending signal + (might not want to do this if it's SIGWINCH -- CHECK) + - rl_complete_internal: if _rl_complete_display_matches_interrupt + set after calling display_matches, just null out `matches' since + it's already been freed and call any application-set signal hook + + 12/14 + ----- +parse.y + - time_command_acceptable: if the token before a newline is `|', + return 0, since it's not really valid to time inside a pipeline. + Only handles a single newline but allows things like + echo a | + time cat + to invoke /usr/bin/time, which is probably enough to catch the + stray carriage return. Fixes bug reported by Andre Majorel + + +builtins/declare.def + - declare_internal: don't try to perform compound assignments unless + the WORD_DESC has flags including W_COMPASSIGN (maybe should check + W_ASSIGNMENT as well), avoiding unexpected evaluation if a word + is of the form (word) and is assigned to an array variable like so: + declare -x var=$value. Bug reported by Stephane Chazelas + . Will eventually be contingent on + compatibility level > 43, but not there yet. TENTATIVE + + 12/15 + ----- +lib/sh/Makefile.in + - add missing dependencies for shmatch.o. Pointed out by Sergey + Mikhailov + + 12/16 + ----- +{execute_cmd,subst}.c + - W_ASSIGNINT: remove, not used any more + +execute_cmd.c + - fix_assignment_words: don't look for `-i' option and set W_ASSIGNINT + flag any more; doing things a different way + - shell_expand_word_list: instead of using W_ASSIGNINT flag, since it + doesn't take into account all options that can transform values on + assignment (-l/-u/-c can also), go through option arguments looking + for options that need special handling and add them to the `opts' + array for make_internal_declare to use. Fixes bug with constructs + like `declare -al foo=(UPONE UPTWO UPTHREE)' not being lowercased on + assignment reported by Linda Walsh + + + + 12/18 + ----- +lib/readline/readline.c + - rl_internal_char: when we read EOF on a non-empty line, check for + signals and invoke any readline signal handling and any application- + installed signal hook + + 12/20 + ----- +lib/readline/readline.c + - rl_internal_char: if we read EOF on a non-empty line, set c to + _rl_eof_char the first time through. If we read EOF the next time, + return EOF from readline(). If callbacks are defined, this returns + EOF immediately, since lastc isn't available. Fix for problem + most recently identified by Jiri Kukacka , + it has come up in the past + + 12/21 + ----- +builtins/declare.def + - declare_internal: keep track of whether or not an assignment statement + argument to declare is an array subscript assignment; need to + differentiate assignments from straight declarations (declare a[4]) + which are accepted for backwards compatibility + - assignment statements like declare a[2]=foo are now treated as + straight subscript assignment statements if a already exists as an + array variable + - declare foo='(1 2 3)' is treated as an assignment to foo[0] if foo + exists and is an array, just as it would be if it were an assignment + statement and `declare' was not present. All this from a proposal + by Stephane Chazelas + + 12/22 + ----- +builtins/read.def + - read_tty_modified: function to tell the rest of the shell if the + read builtin has modified the tty + - read_builtin: make sure to initialize terminating signals before + installing a SIGALRM signal handler in case we modify the tty as + well as ask for a timeout; the subsequent call to + initialize_terminating_signals would overwrite the read-builtin- + local SIGALRM handler + +builtins/common.h + - read_tty_modified: new extern declaration + +shell.c + - exit_shell: if read_tty_modified() returns true, call read_tty_cleanup + to undo the terminal modifications. Extension of previous fixes; + fixes bug with read -s reported by Richard W. Marsden + + + + 12/23 + ----- +builtins/setattr.def + - show_var_attributes: call print_array_assignment and print_assoc_assignment + with a `not quoted' flag so the assignment statements are not + surrounded by single quotes. Caused changes to a lot of test output + + 12/29 + ----- +lib/readline/complete.c + - stat_char: Windows doesn't handle X_OK flag to access(2); use file + extensions to determine whether or not a file is executable. Bug + report and fix from Eli Zaretskii + +configure.ac + - changed version to bash-4.4-devel + +lib/readline/readline.h + - changed version to readline-6.4 + + 12/30 + ----- +readline.h + - struct readline_state: fix types of `ignorefunc' and `attemptfunc' + members + +lib/sh/shquote.c,externs.h + - sh_contains_shell_metas, sh_contains_quotes: now take `const char *' + as parameter + +stringlib.c,externs.h + - strcreplace: `text' argument now `const char *' + +pathexp.[ch] + - quote_globbing_chars: `string' argument now `const char *', accompanying + changes to function local variables + +pcomplete.c + - preproc_filterpat: `text' argument now `const char *' + - filter_stringlist: `text' argument now `const char *' + + 12/31 + ----- +builtins/evalstring.c + - should_suppress_fork: new function, broke code that decides whether + to turn on CMD_NO_FORK flag out of parse_and_execute into a separate + function + +execute_cmd.c + - execute_command_internal: AND_AND, OR_OR: call should_suppress_fork + for the RHS of && and ||, make `make' invocations marginally more + efficient + +flags.c + - get_current_flags: returns a bitmap of all single-letter shell + options with a non-zero value meaning option is enabled + - set_current_flags: set current single-letter options from a passed + bitmap, which has presumably been initialized with get_current_flags + +flags.h + - {get,set}_current_flags: new extern declarations + +builtins/declare.def + - declare_internal: if invoked as `local', interpret name argument of + `-' to mean to save (and restore at shell return) single-letter + shell options + +variables.c + - push_func_var: if we encounter `-' as the name of a local variable, + take the value and call set_current_flags on it to restore old + flag settings + +builtins/set.def + - get_current_options: returns a bitmap of all shell options settable + with `set', with a non-zero value meaning option is enabled + - set_current_options: set current shell options from a passed + bitmap, which has presumably been initialized with get_current_options + + + 1/1/2015 + -------- +lib/readline/parens.c + - _rl_blink_matching_paren: initialize to 0 whether or not select(2) is + available. Inconsistency reported by Mark Karpov + + +builtins/declare.def + - declare_internal: use get_current_options instead of get_current_flags, + so `local -' can be generalized + +variables.c + - push_func_var: use set_current_options instead of set_current_flags + so `local -' can be generalized + +doc/{bash.1,bashref.texi} + - document new `local -' feature; originally inspired by Robert Elz + describing feature in NetBSD sh + + 1/3 + --- +lib/readline/{complete,funmap,kill,histfile,util} +lib/readline/readline.h +lib/tilde/tilde.c + - fixes for filename- and evironment-related issues on Windows. Fixes + from Eli Zaretskii + - Windows can paste to the console from the clipboard like Cygwin + - Windows uses $APPDATA as a pseudo-$HOME + +lib/readline/input.c + - rl_getc: use _getch on Windows to avoid being overridden by a getch + ncurses function + - win32_isatty: replace Windows isatty(3) with a function that does + additional checks, sinces Windows isatty returns non-zero for + every character device. From Eli Zaretskii + +lib/readline/display.c + - delete_chars: if compiled with ncurses on Windows, this code can + work, so build it in if NCURSES_VERSION defined + - open_some_spaces: ditto + + 1/6 + --- +doc/{bash.1,bashref.texi} + - minor grammar and typo corrections from TonyMc + + 1/8 + --- +sig.c + - throw_to_top_level: only attempt to run the interrupt trap if SIGINT + is trapped -- minor optimization + - throw_to_top_level: if we are running a trap, call run_trap_cleanup + to turn off the sigmodes flags + +trap.c + - _run_trap_internal: temporarily suppress pending SIGINTs while running + one of the traps the shell handles internally (e.g., ERR). Fixes bug + reported by Keith Thompson + + 1/10 + ---- +bashhist.c + - bash_history_inhibit_expansion: use skip_to_delim with the history + expansion character to see whether or not the instance of the + history expansion character should be skipped because, for instance, + it is in a command substitution. Fixes issue reported by + Zigmund.Ozean@zig-home.localdomain + + 1/14 + ---- +lib/readline/isearch.c + - _rl_isearch_dispatch: if we are in a multibyte locale, make sure to use + _rl_find_prev_mbchar when trying to delete characters from the search + string, instead of just chopping off the previous byte. Fixes bug + reported by Kyrylo Shpytsya + +lib/readline/complete.c + - rl_filename_completion_function: if we tilde-expand `dirname', make + sure we use the expanded result instead of throwing it away for the + quote-removed `users_dirname', which still has any leading tilde. + Fixes bug reported by Dave Rutherford + +execute_cmd.c + - select_query: if the read builtin doesn't return anything in REPLY, + return NULL (failure). Fixes bug reported by Etherial Raine + + +builtins/read.def + - read_builtin: if REPLY has the readonly or noassign attribute, return + failure + + 1/16 + ---- +redir.c + - redir_open: if open() returns -1/EINTR, check traps as well as + using QUIT to handle signals + + 1/18 + ---- +jobs.c + - wait_for: make sure queue_sigchld is set to 1 before unblocking + SIGCHLD if MUST_UNBLOCK_CHLD is defined + + 1/19 + ---- +pcomplete.h + - new progcomp option: COPT_NOSORT, means to not sort list of possible + completions + +pcomplete.c + - pcomp_set_readline_variables: if COPT_NOSORT set in compspec flags, + set rl_sort_completion_duplicates to 0 + +builtins/complete.def + - _compopt: new option value: -o nosort, sets COPT_NOSORT in compspec + option flags. Provides new -o nosort option for complete and compgen + +bashline.c + - attempt_shell_completion: make sure rl_sort_completion_matches is + set to 1 before completion is attempted; allow a compspec to turn + it off + +lib/readline/kill.c + - rl_vi_yank_pop: new function, vi-mode version of yank-pop. Original + code from Ian Kelling + +lib/readline/funmap.c + - `vi-yank-pop': bindable name mapped to rl_vi_yank_pop diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old new file mode 100644 index 000000000..1707ab10c --- /dev/null +++ b/CWRU/POSIX.NOTES.old @@ -0,0 +1,82 @@ +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 new file mode 100644 index 000000000..87b78d7cc --- /dev/null +++ b/CWRU/old/set.def.save @@ -0,0 +1,544 @@ +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 new file mode 100644 index 000000000..998fd72b6 --- /dev/null +++ b/CWRU/save/unwind_prot.h.save @@ -0,0 +1,50 @@ +/* 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/bashhist.c b/bashhist.c index 7f87921c2..6d0762882 100644 --- a/bashhist.c +++ b/bashhist.c @@ -226,10 +226,12 @@ bash_history_inhibit_expansion (string, i) else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2)) return (1); #endif +#if 0 /* bash-4.4 */ /* Make sure the history expansion should not be skipped by quoting or command/process substitution. */ else if (t = skip_to_delim (string, 0, hx, SD_NOJMP) > 0 && t > i) return (1); +#endif else return (0); } diff --git a/bashline.c b/bashline.c index 79ad03068..7f200778f 100644 --- a/bashline.c +++ b/bashline.c @@ -631,6 +631,8 @@ bashline_reset () rl_filename_stat_hook = bash_filename_stat_hook; bashline_reset_event_hook (); + + rl_sort_completion_matches = 1; } /* Contains the line to push into readline. */ @@ -1429,6 +1431,8 @@ attempt_shell_completion (text, start, end) set_directory_hook (); rl_filename_stat_hook = bash_filename_stat_hook; + rl_sort_completion_matches = 1; /* sort by default */ + /* 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 diff --git a/bashline.c~ b/bashline.c~ new file mode 100644 index 000000000..79ad03068 --- /dev/null +++ b/bashline.c~ @@ -0,0 +1,4280 @@ +/* bashline.c -- Bash's interface to the readline library. */ + +/* Copyright (C) 1987-2013 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 +#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 "trap.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. */ +#ifdef _MINIX +extern int tputs __P((const char *string, int nlines, void (*outx)(int))); +#else +extern int tputs __P((const char *string, int nlines, int (*outx)(int))); +#endif + +/* 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 *maybe_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 *)); + +#ifdef _MINIX +static void putx __P((int)); +#else +static int putx __P((int)); +#endif +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 int sigalrm_seen; +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. */ +#if DIRCOMPLETE_EXPAND_DEFAULT +int dircomplete_expand = 1; +int dircomplete_expand_relpath = 1; +#else +int dircomplete_expand = 0; +int dircomplete_expand_relpath = 0; +#endif + +/* 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_signal_event_hook = bash_event_hook; +} + +void +bashline_reset_event_hook () +{ + rl_signal_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; + + bashline_reset_event_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 necessary. + 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 (); + current_command_line_count++; /* for rl_newline above */ + bash_add_history (rl_line_buffer); + current_command_line_count = 0; /* for dummy history entry */ + 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, ns; + + 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]) + { + /* Handle >| token crudely; treat as > not | */ + if (rl_line_buffer[s] == '|' && rl_line_buffer[s-1] == '>') + { + ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/); + if (ns > start || rl_line_buffer[ns] == 0) + return os; + os = ns+1; + continue; + } + 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 */ + +/* Try and catch completion attempts that are syntax errors or otherwise + invalid. */ +static int +invalid_completion (text, ind) + const char *text; + int ind; +{ + int pind; + + /* If we don't catch these here, the next clause will */ + if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ + member (rl_line_buffer[ind-1], "$<>")) + return 0; + + pind = ind - 1; + while (pind > 0 && whitespace (rl_line_buffer[pind])) + pind--; + /* If we have only whitespace preceding a paren, it's valid */ + if (ind >= 0 && pind <= 0 && rl_line_buffer[ind] == '(') /*)*/ + return 0; + /* Flag the invalid completions, which are mostly syntax errors */ + if (ind > 0 && rl_line_buffer[ind] == '(' && /*)*/ + member (rl_line_buffer[pind], COMMAND_SEPARATORS) == 0) + return 1; + + return 0; +} + +/* 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; +#if defined (PROGRAMMABLE_COMPLETION) + int have_progcomps, was_assignment; +#endif + + 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. */ + } + + if (in_command_position && invalid_completion (text, ti)) + { + rl_attempted_completion_over = 1; + return ((char **)NULL); + } + + /* 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. */ + have_progcomps = prog_completion_enabled && (progcomp_size () > 0); + if (matches == 0 && (in_command_position == 0 || text[0] == '\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 (was_assignment = assignment (n, 0)); + s = s1; /* reset to index where name begins */ + + /* s == index of where command name begins (reset above) + e == end of current command, may be end of line + s1 = index of where command name begins + e1 == index of where command name ends + start == index of where word to be completed begins + end == index of where word to be completed ends + if (s == start) we are doing command word completion for sure + if (e1 == end) we are at the end of the command name and completing it */ + 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' && have_progcomps) /* 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 && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0) + { + /* not assignment statement, but still want to perform command + completion if we are composing command word. */ + foundcs = 0; + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + else if (e > s && was_assignment == 0 && have_progcomps) + { + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + /* command completion if programmable completion fails */ + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + /* empty command name following command separator */ + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0 && + was_assignment == 0 && member (rl_line_buffer[start-1], COMMAND_SEPARATORS)) + { + foundcs = 0; + in_command_position = 1; + } + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) + { + foundcs = 0; /* empty command name following assignments */ + in_command_position = was_assignment; + } + 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; + } + else if (matches && matches[1] && rl_completion_type == '!') + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + + return (matches); +} + +static int +bash_command_name_stat_hook (name) + char **name; +{ + char *cname, *result; + + /* If it's not something we're going to look up in $PATH, just call the + normal filename stat hook. */ + if (absolute_program (*name)) + return (bash_filename_stat_hook (name)); + + 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 *fnhint = (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); + + fnhint = 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 = maybe_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 (fnhint && fnhint != filename_hint) + free (fnhint); + if (filename_hint) + free (filename_hint); + + filename_hint = sh_makepath (current_path, hint, 0); + /* Need a quoted version (though it doesn't matter much in most + cases) because rl_filename_completion_function dequotes the + filename it gets, assuming that it's been quoted as part of + the input line buffer. */ + if (strpbrk (filename_hint, "\"'\\")) + fnhint = sh_backslash_quote (filename_hint, filename_bstab, 0); + else + fnhint = filename_hint; + free (current_path); /* XXX */ + } + + inner: + val = rl_filename_completion_function (fnhint, 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 = maybe_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); +} + +static char * +maybe_restore_tilde (val, directory_part) + char *val, *directory_part; +{ + rl_icppfunc_t *save; + char *ret; + + save = (dircomplete_expand == 0) ? save_directory_hook () : (rl_icppfunc_t *)0; + ret = restore_tilde (val, directory_part); + if (save) + restore_directory_hook (save); + 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) + { + free (local_dirname); /* XXX */ + local_dirname = *dirname = new_dirname; + return_value = STREQ (local_dirname, *dirname) == 0; + } + else + free (new_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; + +#ifdef _MINIX +static void +#else +static int +#endif +putx(c) + int c; +{ + int x; + x = putc (c, rl_outstream); +#ifndef _MINIX + return x; +#endif +} + +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. */ + /* If we clear the last line of the prompt above, redraw only that last + line. If the command returns 124, we redraw unconditionally as in + previous versions. */ + if (ce && r != 124) + rl_redraw_prompt_last_line (); + else + 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; + /* If rl_completion_found_quote != 0, rl_completion_matches will call the + filename dequoting function, causing the directory name to be dequoted + twice. */ + if (rl_dispatching && rl_completion_found_quote == 0) + dfn = bash_dequote_filename ((char *)text, qc); + else + dfn = (char *)text; + m1 = rl_completion_matches (dfn, rl_filename_completion_function); + if (dfn != text) + 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); +} + +/* This event hook is designed to be called after readline receives a signal + that interrupts read(2). It gives reasonable responsiveness to interrupts + and fatal signals without executing too much code in a signal handler + context. */ +static int +bash_event_hook () +{ + /* If we're going to longjmp to top_level, make sure we clean up readline. + check_signals will call QUIT, which will eventually longjmp to top_level, + calling run_interrupt_trap along the way. The check for sigalrm_seen is + to clean up the read builtin's state. */ + if (terminating_signal || interrupt_state || sigalrm_seen) + rl_cleanup_after_signal (); + bashline_reset_event_hook (); + check_signals_and_traps (); /* XXX */ + return 0; +} + +#endif /* READLINE */ diff --git a/builtins/complete.def b/builtins/complete.def index 0a292ac7a..4d18c1386 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -138,6 +138,7 @@ static const struct _compopt { { "dirnames", COPT_DIRNAMES }, { "filenames",COPT_FILENAMES}, { "noquote", COPT_NOQUOTE }, + { "nosort", COPT_NOSORT }, { "nospace", COPT_NOSPACE }, { "plusdirs", COPT_PLUSDIRS }, { (char *)NULL, 0 }, diff --git a/builtins/complete.def~ b/builtins/complete.def~ new file mode 100644 index 000000000..0a292ac7a --- /dev/null +++ b/builtins/complete.def~ @@ -0,0 +1,874 @@ +This file is complete.def, from which is created complete.c. +It implements the builtins "complete", "compgen", and "compopt" in Bash. + +Copyright (C) 1999-2014 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 complete.c + +$BUILTIN complete +$DEPENDS_ON PROGRAMMABLE_COMPLETION +$FUNCTION complete_builtin +$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...] +Specify how arguments are to be completed by Readline. + +For each NAME, specify how arguments are to be completed. If no options +are supplied, existing completion specifications are printed in a way that +allows them to be reused as input. + +Options: + -p print existing completion specifications in a reusable format + -r remove a completion specification for each NAME, or, if no + NAMEs are supplied, all completion specifications + -D apply the completions and actions as the default for commands + without any specific completion defined + -E apply the completions and actions to "empty" commands -- + completion attempted on a blank line + +When completion is attempted, the actions are applied in the order the +uppercase-letter options are listed above. The -D option takes +precedence over -E. + +Exit Status: +Returns success unless an invalid option is supplied or an error occurs. +$END + +#include + +#include + +#include "../bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "../bashansi.h" +#include "../bashintl.h" + +#include "../shell.h" +#include "../builtins.h" +#include "../pcomplete.h" +#include "../bashline.h" + +#include "common.h" +#include "bashgetopt.h" + +#include + +#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL) + +/* Structure containing all the non-action (binary) options; filled in by + build_actions(). */ +struct _optflags { + int pflag; + int rflag; + int Dflag; + int Eflag; +}; + +static int find_compact __P((char *)); +static int find_compopt __P((char *)); + +static int build_actions __P((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *)); + +static int remove_cmd_completions __P((WORD_LIST *)); + +static int print_one_completion __P((char *, COMPSPEC *)); +static int print_compitem __P((BUCKET_CONTENTS *)); +static void print_compopts __P((const char *, COMPSPEC *, int)); +static void print_all_completions __P((void)); +static int print_cmd_completions __P((WORD_LIST *)); + +static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg; + +static const struct _compacts { + const char * const actname; + int actflag; + int actopt; +} compacts[] = { + { "alias", CA_ALIAS, 'a' }, + { "arrayvar", CA_ARRAYVAR, 0 }, + { "binding", CA_BINDING, 0 }, + { "builtin", CA_BUILTIN, 'b' }, + { "command", CA_COMMAND, 'c' }, + { "directory", CA_DIRECTORY, 'd' }, + { "disabled", CA_DISABLED, 0 }, + { "enabled", CA_ENABLED, 0 }, + { "export", CA_EXPORT, 'e' }, + { "file", CA_FILE, 'f' }, + { "function", CA_FUNCTION, 0 }, + { "helptopic", CA_HELPTOPIC, 0 }, + { "hostname", CA_HOSTNAME, 0 }, + { "group", CA_GROUP, 'g' }, + { "job", CA_JOB, 'j' }, + { "keyword", CA_KEYWORD, 'k' }, + { "running", CA_RUNNING, 0 }, + { "service", CA_SERVICE, 's' }, + { "setopt", CA_SETOPT, 0 }, + { "shopt", CA_SHOPT, 0 }, + { "signal", CA_SIGNAL, 0 }, + { "stopped", CA_STOPPED, 0 }, + { "user", CA_USER, 'u' }, + { "variable", CA_VARIABLE, 'v' }, + { (char *)NULL, 0, 0 }, +}; + +/* This should be a STRING_INT_ALIST */ +static const struct _compopt { + const char * const optname; + int optflag; +} compopts[] = { + { "bashdefault", COPT_BASHDEFAULT }, + { "default", COPT_DEFAULT }, + { "dirnames", COPT_DIRNAMES }, + { "filenames",COPT_FILENAMES}, + { "noquote", COPT_NOQUOTE }, + { "nospace", COPT_NOSPACE }, + { "plusdirs", COPT_PLUSDIRS }, + { (char *)NULL, 0 }, +}; + +static int +find_compact (name) + char *name; +{ + register int i; + + for (i = 0; compacts[i].actname; i++) + if (STREQ (name, compacts[i].actname)) + return i; + return -1; +} + +static int +find_compopt (name) + char *name; +{ + register int i; + + for (i = 0; compopts[i].optname; i++) + if (STREQ (name, compopts[i].optname)) + return i; + return -1; +} + +/* Build the actions and compspec options from the options specified in LIST. + ACTP is a pointer to an unsigned long in which to place the bitmap of + actions. OPTP is a pointer to an unsigned long in which to place the + btmap of compspec options (arguments to `-o'). PP, if non-null, gets 1 + if -p is supplied; RP, if non-null, gets 1 if -r is supplied. + If either is null, the corresponding option generates an error. + This also sets variables corresponding to options that take arguments as + a side effect; the caller should ensure that those variables are set to + NULL before calling build_actions. Return value: + EX_USAGE = bad option + EXECUTION_SUCCESS = some options supplied + EXECUTION_FAILURE = no options supplied +*/ + +static int +build_actions (list, flagp, actp, optp) + WORD_LIST *list; + struct _optflags *flagp; + unsigned long *actp, *optp; +{ + int opt, ind, opt_given; + unsigned long acts, copts; + + acts = copts = (unsigned long)0L; + opt_given = 0; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DE")) != -1) + { + opt_given = 1; + switch (opt) + { + case 'r': + if (flagp) + { + flagp->rflag = 1; + break; + } + else + { + sh_invalidopt ("-r"); + builtin_usage (); + return (EX_USAGE); + } + + case 'p': + if (flagp) + { + flagp->pflag = 1; + break; + } + else + { + sh_invalidopt ("-p"); + builtin_usage (); + return (EX_USAGE); + } + + case 'a': + acts |= CA_ALIAS; + break; + case 'b': + acts |= CA_BUILTIN; + break; + case 'c': + acts |= CA_COMMAND; + break; + case 'd': + acts |= CA_DIRECTORY; + break; + case 'e': + acts |= CA_EXPORT; + break; + case 'f': + acts |= CA_FILE; + break; + case 'g': + acts |= CA_GROUP; + break; + case 'j': + acts |= CA_JOB; + break; + case 'k': + acts |= CA_KEYWORD; + break; + case 's': + acts |= CA_SERVICE; + break; + case 'u': + acts |= CA_USER; + break; + case 'v': + acts |= CA_VARIABLE; + break; + case 'o': + ind = find_compopt (list_optarg); + if (ind < 0) + { + sh_invalidoptname (list_optarg); + return (EX_USAGE); + } + copts |= compopts[ind].optflag; + break; + case 'A': + ind = find_compact (list_optarg); + if (ind < 0) + { + builtin_error (_("%s: invalid action name"), list_optarg); + return (EX_USAGE); + } + acts |= compacts[ind].actflag; + break; + case 'C': + Carg = list_optarg; + break; + case 'D': + if (flagp) + { + flagp->Dflag = 1; + break; + } + else + { + sh_invalidopt ("-D"); + builtin_usage (); + return (EX_USAGE); + } + case 'E': + if (flagp) + { + flagp->Eflag = 1; + break; + } + else + { + sh_invalidopt ("-E"); + builtin_usage (); + return (EX_USAGE); + } + case 'F': + Farg = list_optarg; + break; + case 'G': + Garg = list_optarg; + break; + case 'P': + Parg = list_optarg; + break; + case 'S': + Sarg = list_optarg; + break; + case 'W': + Warg = list_optarg; + break; + case 'X': + Xarg = list_optarg; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + + *actp = acts; + *optp = copts; + + return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE); +} + +/* Add, remove, and display completion specifiers. */ +int +complete_builtin (list) + WORD_LIST *list; +{ + int opt_given, rval; + unsigned long acts, copts; + COMPSPEC *cs; + struct _optflags oflags; + WORD_LIST *l, *wl; + + if (list == 0) + { + print_all_completions (); + return (EXECUTION_SUCCESS); + } + + opt_given = oflags.pflag = oflags.rflag = oflags.Dflag = oflags.Eflag = 0; + + acts = copts = (unsigned long)0L; + Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; + cs = (COMPSPEC *)NULL; + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = build_actions (list, &oflags, &acts, &copts); + if (rval == EX_USAGE) + return (rval); + opt_given = rval != EXECUTION_FAILURE; + + list = loptend; + + wl = oflags.Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL) + : (oflags.Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0); + + /* -p overrides everything else */ + if (oflags.pflag || (list == 0 && opt_given == 0)) + { + if (wl) + { + rval = print_cmd_completions (wl); + dispose_words (wl); + return rval; + } + else if (list == 0) + { + print_all_completions (); + return (EXECUTION_SUCCESS); + } + return (print_cmd_completions (list)); + } + + /* next, -r overrides everything else. */ + if (oflags.rflag) + { + if (wl) + { + rval = remove_cmd_completions (wl); + dispose_words (wl); + return rval; + } + else if (list == 0) + { + progcomp_flush (); + return (EXECUTION_SUCCESS); + } + return (remove_cmd_completions (list)); + } + + if (wl == 0 && list == 0 && opt_given) + { + builtin_usage (); + return (EX_USAGE); + } + + /* If we get here, we need to build a compspec and add it for each + remaining argument. */ + cs = compspec_create (); + cs->actions = acts; + cs->options = copts; + + cs->globpat = STRDUP (Garg); + cs->words = STRDUP (Warg); + cs->prefix = STRDUP (Parg); + cs->suffix = STRDUP (Sarg); + cs->funcname = STRDUP (Farg); + cs->command = STRDUP (Carg); + cs->filterpat = STRDUP (Xarg); + + for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next) + { + /* Add CS as the compspec for the specified commands. */ + if (progcomp_insert (l->word->word, cs) == 0) + rval = EXECUTION_FAILURE; + } + + dispose_words (wl); + return (rval); +} + +static int +remove_cmd_completions (list) + WORD_LIST *list; +{ + WORD_LIST *l; + int ret; + + for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next) + { + if (progcomp_remove (l->word->word) == 0) + { + builtin_error (_("%s: no completion specification"), l->word->word); + ret = EXECUTION_FAILURE; + } + } + return ret; +} + +#define SQPRINTARG(a, f) \ + do { \ + if (a) \ + { \ + x = sh_single_quote (a); \ + printf ("%s %s ", f, x); \ + free (x); \ + } \ + } while (0) + +#define PRINTARG(a, f) \ + do { \ + if (a) \ + printf ("%s %s ", f, a); \ + } while (0) + +#define PRINTOPT(a, f) \ + do { \ + if (acts & a) \ + printf ("%s ", f); \ + } while (0) + +#define PRINTACT(a, f) \ + do { \ + if (acts & a) \ + printf ("-A %s ", f); \ + } while (0) + +#define PRINTCOMPOPT(a, f) \ + do { \ + if (copts & a) \ + printf ("-o %s ", f); \ + } while (0) + +#define XPRINTCOMPOPT(a, f) \ + do { \ + if (copts & a) \ + printf ("-o %s ", f); \ + else \ + printf ("+o %s ", f); \ + } while (0) + +static int +print_one_completion (cmd, cs) + char *cmd; + COMPSPEC *cs; +{ + unsigned long acts, copts; + char *x; + + printf ("complete "); + + copts = cs->options; + + /* First, print the -o options. */ + PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + PRINTCOMPOPT (COPT_DEFAULT, "default"); + PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOSPACE, "nospace"); + PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + + acts = cs->actions; + + /* simple flags next */ + PRINTOPT (CA_ALIAS, "-a"); + PRINTOPT (CA_BUILTIN, "-b"); + PRINTOPT (CA_COMMAND, "-c"); + PRINTOPT (CA_DIRECTORY, "-d"); + PRINTOPT (CA_EXPORT, "-e"); + PRINTOPT (CA_FILE, "-f"); + PRINTOPT (CA_GROUP, "-g"); + PRINTOPT (CA_JOB, "-j"); + PRINTOPT (CA_KEYWORD, "-k"); + PRINTOPT (CA_SERVICE, "-s"); + PRINTOPT (CA_USER, "-u"); + PRINTOPT (CA_VARIABLE, "-v"); + + /* now the rest of the actions */ + PRINTACT (CA_ARRAYVAR, "arrayvar"); + PRINTACT (CA_BINDING, "binding"); + PRINTACT (CA_DISABLED, "disabled"); + PRINTACT (CA_ENABLED, "enabled"); + PRINTACT (CA_FUNCTION, "function"); + PRINTACT (CA_HELPTOPIC, "helptopic"); + PRINTACT (CA_HOSTNAME, "hostname"); + PRINTACT (CA_RUNNING, "running"); + PRINTACT (CA_SETOPT, "setopt"); + PRINTACT (CA_SHOPT, "shopt"); + PRINTACT (CA_SIGNAL, "signal"); + PRINTACT (CA_STOPPED, "stopped"); + + /* now the rest of the arguments */ + + /* arguments that require quoting */ + SQPRINTARG (cs->globpat, "-G"); + SQPRINTARG (cs->words, "-W"); + SQPRINTARG (cs->prefix, "-P"); + SQPRINTARG (cs->suffix, "-S"); + SQPRINTARG (cs->filterpat, "-X"); + + SQPRINTARG (cs->command, "-C"); + + /* simple arguments that don't require quoting */ + PRINTARG (cs->funcname, "-F"); + + if (STREQ (cmd, EMPTYCMD)) + printf ("-E\n"); + else if (STREQ (cmd, DEFAULTCMD)) + printf ("-D\n"); + else + printf ("%s\n", cmd); + + return (0); +} + +static void +print_compopts (cmd, cs, full) + const char *cmd; + COMPSPEC *cs; + int full; +{ + int copts; + + printf ("compopt "); + copts = cs->options; + + if (full) + { + XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + XPRINTCOMPOPT (COPT_DEFAULT, "default"); + XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + XPRINTCOMPOPT (COPT_FILENAMES, "filenames"); + XPRINTCOMPOPT (COPT_NOSPACE, "nospace"); + XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + } + else + { + PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + PRINTCOMPOPT (COPT_DEFAULT, "default"); + PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOSPACE, "nospace"); + PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + } + + if (STREQ (cmd, EMPTYCMD)) + printf ("-E\n"); + else if (STREQ (cmd, DEFAULTCMD)) + printf ("-D\n"); + else + printf ("%s\n", cmd); +} + +static int +print_compitem (item) + BUCKET_CONTENTS *item; +{ + COMPSPEC *cs; + char *cmd; + + cmd = item->key; + cs = (COMPSPEC *)item->data; + + return (print_one_completion (cmd, cs)); +} + +static void +print_all_completions () +{ + progcomp_walk (print_compitem); +} + +static int +print_cmd_completions (list) + WORD_LIST *list; +{ + WORD_LIST *l; + COMPSPEC *cs; + int ret; + + for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next) + { + cs = progcomp_search (l->word->word); + if (cs) + print_one_completion (l->word->word, cs); + else + { + builtin_error (_("%s: no completion specification"), l->word->word); + ret = EXECUTION_FAILURE; + } + } + + return (sh_chkwrite (ret)); +} + +$BUILTIN compgen +$DEPENDS_ON PROGRAMMABLE_COMPLETION +$FUNCTION compgen_builtin +$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word] +Display possible completions depending on the options. + +Intended to be used from within a shell function generating possible +completions. If the optional WORD argument is supplied, matches against +WORD are generated. + +Exit Status: +Returns success unless an invalid option is supplied or an error occurs. +$END + +int +compgen_builtin (list) + WORD_LIST *list; +{ + int rval; + unsigned long acts, copts; + COMPSPEC *cs; + STRINGLIST *sl; + char *word, **matches; + + if (list == 0) + return (EXECUTION_SUCCESS); + + acts = copts = (unsigned long)0L; + Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; + cs = (COMPSPEC *)NULL; + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts); + if (rval == EX_USAGE) + return (rval); + if (rval == EXECUTION_FAILURE) + return (EXECUTION_SUCCESS); + + list = loptend; + + word = (list && list->word) ? list->word->word : ""; + + if (Farg) + builtin_error (_("warning: -F option may not work as you expect")); + if (Carg) + builtin_error (_("warning: -C option may not work as you expect")); + + /* If we get here, we need to build a compspec and evaluate it. */ + cs = compspec_create (); + cs->actions = acts; + cs->options = copts; + cs->refcount = 1; + + cs->globpat = STRDUP (Garg); + cs->words = STRDUP (Warg); + cs->prefix = STRDUP (Parg); + cs->suffix = STRDUP (Sarg); + cs->funcname = STRDUP (Farg); + cs->command = STRDUP (Carg); + cs->filterpat = STRDUP (Xarg); + + rval = EXECUTION_FAILURE; + sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0); + + /* If the compspec wants the bash default completions, temporarily + turn off programmable completion and call the bash completion code. */ + if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT)) + { + matches = bash_default_completion (word, 0, 0, 0, 0); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + /* This isn't perfect, but it's the best we can do, given what readline + exports from its set of completion utility functions. */ + if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT)) + { + matches = rl_completion_matches (word, rl_filename_completion_function); + strlist_dispose (sl); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + if (sl) + { + if (sl->list && sl->list_len) + { + rval = EXECUTION_SUCCESS; + strlist_print (sl, (char *)NULL); + } + strlist_dispose (sl); + } + + compspec_dispose (cs); + return (rval); +} + +$BUILTIN compopt +$DEPENDS_ON PROGRAMMABLE_COMPLETION +$FUNCTION compopt_builtin +$SHORT_DOC compopt [-o|+o option] [-DE] [name ...] +Modify or display completion options. + +Modify the completion options for each NAME, or, if no NAMEs are supplied, +the completion currently being executed. If no OPTIONs are given, print +the completion options for each NAME or the current completion specification. + +Options: + -o option Set completion option OPTION for each NAME + -D Change options for the "default" command completion + -E Change options for the "empty" command completion + +Using `+o' instead of `-o' turns off the specified option. + +Arguments: + +Each NAME refers to a command for which a completion specification must +have previously been defined using the `complete' builtin. If no NAMEs +are supplied, compopt must be called by a function currently generating +completions, and the options for that currently-executing completion +generator are modified. + +Exit Status: +Returns success unless an invalid option is supplied or NAME does not +have a completion specification defined. +$END + +int +compopt_builtin (list) + WORD_LIST *list; +{ + int opts_on, opts_off, *opts, opt, oind, ret, Dflag, Eflag; + WORD_LIST *l, *wl; + COMPSPEC *cs; + + opts_on = opts_off = Eflag = Dflag = 0; + ret = EXECUTION_SUCCESS; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "+o:DE")) != -1) + { + opts = (list_opttype == '-') ? &opts_on : &opts_off; + + switch (opt) + { + case 'o': + oind = find_compopt (list_optarg); + if (oind < 0) + { + sh_invalidoptname (list_optarg); + return (EX_USAGE); + } + *opts |= compopts[oind].optflag; + break; + case 'D': + Dflag = 1; + break; + case 'E': + Eflag = 1; + break; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + wl = Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL) + : (Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0); + + if (list == 0 && wl == 0) + { + if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0) + { + builtin_error (_("not currently executing completion function")); + return (EXECUTION_FAILURE); + } + cs = pcomp_curcs; + + if (opts_on == 0 && opts_off == 0) + { + print_compopts (pcomp_curcmd, cs, 1); + return (sh_chkwrite (ret)); + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + + /* And change the readline variables the options control */ + pcomp_set_readline_variables (opts_on, 1); + pcomp_set_readline_variables (opts_off, 0); + + return (ret); + } + + for (l = wl ? wl : list; l; l = l->next) + { + cs = progcomp_search (l->word->word); + if (cs == 0) + { + builtin_error (_("%s: no completion specification"), l->word->word); + ret = EXECUTION_FAILURE; + continue; + } + if (opts_on == 0 && opts_off == 0) + { + print_compopts (l->word->word, cs, 1); + continue; /* XXX -- fill in later */ + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + } + + if (wl) + dispose_words (wl); + + return (ret); +} diff --git a/builtins/read.def b/builtins/read.def index 56c23010b..83bcddf44 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -794,6 +794,8 @@ assign_vars: else var = bind_variable ("REPLY", input_string, 0); VUNSETATTR (var, att_invisible); + if (readonly_p (var) || noassign_p (var)) + retval = EXECUTION_FAILURE; xfree (input_string); return (retval); diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old new file mode 100644 index 000000000..640390fbf --- /dev/null +++ b/cross-build/cygwin32.cache.old @@ -0,0 +1,42 @@ +# 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/doc/FAQ.orig b/doc/FAQ.orig new file mode 100644 index 000000000..1cff3c8ef --- /dev/null +++ b/doc/FAQ.orig @@ -0,0 +1,1745 @@ +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/aosa-bash.pdf.old b/doc/aosa-bash.pdf.old new file mode 100644 index 0000000000000000000000000000000000000000..006a767769451694f5f25a9dfdb18282067d982b GIT binary patch literal 153472 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 Sk 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 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 error, in addition to its +standard output, is connected to +\fIcommand2\fP's standard input through the pipe; +it is shorthand for \fB2>&1 |\fP. +This implicit redirection of the standard error to the standard output 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, +as if the \fBextglob\fP shell option were enabled. +The \fB=\fP operator is equivalent to \fB==\fP. +If the +.B nocasematch +shell option 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 +.B nocasematch +shell option 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 expansion, +command substitution, process substitution and quote removal. +Each \fIpattern\fP examined is expanded using tilde +expansion, parameter and variable expansion, arithmetic expansion, +command substitution, and process substitution. +If the +.B nocasematch +shell option 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 +Since the coprocess is created as an asynchronous command, +the \fBcoproc\fP command always returns success. +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, +with one exception: If the \fBfunction\fP reserved word is used, but the +parentheses are not supplied, the braces are required. +\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 (\fIdeclaration\fP 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. +This includes arguments to builtin commands such as \fBdeclare\fP that +accept assignment statements (\fIdeclaration\fP commands). +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, assigned to, unset, or has +its attributes modified (other than the \fInameref\fP attribute itself), 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, and changes to its attributes, +are treated as references, assignments, and attribute modifications +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 \fBnameref\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 is not within double quotes, each positional parameter +expands to a separate word. +In contexts where it is performed, those words +are subject to further word splitting and pathname expansion. +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 job most recently placed into the +background, whether executed as an asynchronous command or using +the \fBbg\fP builtin (see +.SM +.B "JOB CONTROL" +below). +.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_COMPAT +The value is used to set the shell's compatibility level. +See the description of the \fBshopt\fP builtin below under +\fBSHELL BUILTIN COMMANDS\fP +for a description of the various compatibility +levels and their effects. +The value may be a decimal number (e.g., 4.2) or an integer (e.g., 42) +corresponding to the desired compatibility level. +If \fBBASH_COMPAT\fP is unset or set to the empty string, the compatibility +level is set to the default for the current version. +If \fBBASH_COMPAT\fP is set to a value that is not one of the valid +compatibility levels, the shell prints an error message and sets the +compatibility level to the default for the current version. +The valid compatibility levels correspond to the compatibility options +accepted by the \fBshopt\fP builtin described below (for example, +\fBcompat42\fP means that 4.2 and 42 are valid values). +The current version is also a valid value. +.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 CHILD_MAX +Set the number of exited child status values for the shell to remember. +Bash will not allow this value to be decreased below a POSIX-mandated +minimum, and there is a maximum value (currently 8192) that this may +not exceed. +The minimum value is system-dependent. +.TP +.B COLUMNS +Used by the \fBselect\fP compound command to determine the terminal width +when printing selection lists. +Automatically set if the +.B checkwinsize +option is enabled or 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 if the +.B checkwinsize +option is enabled or in 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\et%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. +When assigning to an indexed array, if +.I name +is subscripted by a negative number, that number is +interpreted as relative to one greater than the maximum index of +\fIname\fP, so negative indices count back from the end of the +array, and an index of \-1 references the last element. +.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. +If the +.I subscript +used to reference an element of an indexed array +evaluates to a number less than zero, it is +interpreted as relative to one greater than the maximum index of the array, +so negative indices count back from the end of the +array, and an index of \-1 references the last element. +.PP +Referencing an array variable without a subscript is equivalent to +referencing the array with a subscript of 0. +Any reference to a variable using a valid subscript is legal, and +.B bash +will create an array if necessary. +.PP +An array variable is considered set if a subscript has been assigned a +value. The null string is a valid value. +.PP +It is possible to obtain the keys (indices) of an array as well as the values. +${\fB!\fP\fIname\fP[\fI@\fP]} and ${\fB!\fP\fIname\fP[\fI*\fP]} +expand to the indices assigned in array variable \fIname\fP. +The treatment when in double quotes is similar to the expansion of the +special parameters \fI@\fP and \fI*\fP within double quotes. +.PP +The +.B unset +builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] +destroys the array element at index \fIsubscript\fP. +Negative subscripts to indexed arrays are interpreted as described above. +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 and variable expansion, 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. +This is performed at the +same time as tilde, parameter, variable, and arithmetic expansion and +command substitution. +.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, +using the default C locale. +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), +and \fIparameter\fP is not a \fInameref\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. +If \fIparameter\fP is a nameref, this expands to the name of the +variable referenced by \fIparameter\fP instead of performing the +complete indirect expansion. +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. +If +.I parameter +is an indexed array name subscripted by a negative number, that number is +interpreted as relative to one greater than the maximum index of +\fIparameter\fP, so negative indices count back from the end of the +array, and an index of \-1 references the last element. +.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 the +.B nocasematch +shell option is enabled, the match is performed without regard to the case +of alphabetic characters. +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. +.TP +${\fIparameter\fP\fB@\fP\fIoperator\fP} +\fBParameter transformation\fP. +The expansion is either a transformation of the value of \fIparameter\fP +or information about \fIparameter\fP itself, depending on the value of +\fIoperator\fP. Each \fIoperator\fP is a single letter: +.sp 1 +.RS +.PD 0 +.TP +.B Q +The expansion is a string that is the value of \fIparameter\fP quoted in a +format that can be reused as input. +.TP +.B E +The expansion is a string that is the value of \fIparameter\fP with backslash +escape sequences expanded as with the \fB$'...'\fP quoting mechansim. +.TP +.B P +The expansion is a string that is the result of expanding the value of +\fIparameter\fP as if it were a prompt string (see \fBPROMPTING\fP below). +.TP +.B A +The expansion is a string in the form of a \fBdeclare\fP command that, if +evaluated, will recreate \fIparameter\fP with its attributes and value. +.TP +.B a +The expansion is a string consisting of flag values representing +\fIparameter\fP's attributes. +.PD +.PP +If +.I parameter +is +.B @ +or +.BR * , +the 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. +.sp 1 +The result of the expansion is subject to word splitting and pathname +expansion as described below. +.RE +.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 and variable expansion, +command substitution, and quote removal. +The result is treated as the arithmetic expression to be evaluated. +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 using these characters as field terminators. +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. +If the \fBnocaseglob\fP option is set, the matching against the patterns in +.SM +.B GLOBIGNORE +is performed without regard to case. +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 falls 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 (or file descriptor \fIn\fP if \fIn\fP is specified) for a command. +.PP +The format of here-documents is: +.RS +.PP +.nf +[\fIn\fP]\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 +[\fIn\fP]\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 (or file descriptor \fIn\fP if \fIn\fP is specified). +.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 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 \-R \fIvarname\fP +True if the shell variable +.I varname +is set and is a name reference. +.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. +When used with the \fB[[\fP command, this performs pattern matching as +described above (\fBCompound Commands\fP). +.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, +generally invalid options or missing arguments. +.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\-completion\-prefix (Off) +If set to \fBOn\fP, when listing completions, readline displays the +common prefix of the set of possible completions using a different color. +The color definitions are taken from the value of the \fBLS_COLORS\fP +environment variable. +.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\-bracketed\-paste (Off) +When set to \fBOn\fP, readline will configure the terminal in a way +that will enable it to insert each paste into the editing buffer as a +single string of characters, instead of treating each character as if +it had been read from the keyboard. This can prevent pasted characters +from being interpreted as editing commands. +.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 (unset) +Set the maximum number of history entries saved in the history list. +If set to zero, any existing history entries are deleted and no new entries +are saved. +If set to a value less than zero, the number of history entries is not +limited. +By default, the number of history entries 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 emacs\-mode\-string (@) +This string is displayed immediately before the last line of the primary +prompt when emacs editing mode is active. The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the \e1 and \e2 escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +.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 show\-mode\-in\-prompt (Off) +If set to \fBOn\fP, add a character to the beginning of the prompt +indicating the editing mode: emacs (@), vi command (:) or vi +insertion (+). +.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 vi\-cmd\-mode\-string ((cmd)) +This string is displayed immediately before the last line of the primary +prompt when vi editing mode is active and in command mode. +The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the \e1 and \e2 escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +.TP +.B vi\-ins\-mode\-string ((ins)) +This string is displayed immediately before the last line of the primary +prompt when vi editing mode is active and in insertion mode. +The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the \e1 and \e2 escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +.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 both the 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 word, +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 \fIend\-of\-file\fP (usually C\-d) +The character indicating end-of-file as set, for example, by +.if t \f(CWstty\fP. +.if n ``stty''. +If this character is read when there are no characters +on the line, and point is at the beginning of the line, Readline +interprets it as the end of input and returns +.SM +.BR EOF . +.TP +.B delete\-char (C\-d) +Delete the character at point. +If this function is bound to the +same character as the tty \fBEOF\fP character, as \fBC\-d\fP +commonly is, see above for the effects. +.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 +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 +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 nor 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. +.TP +.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. +If the +.B nocasematch +shell option is enabled, the match is performed without regard to the case +of alphabetic characters. +.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 -o bashdefault -o default +.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 word. This is usually the last argument, but will expand to the +zeroth word if there is only one word in the line. +.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 [\fB\-m\fP \fIkeymap\fP] \fIkeyseq\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. +On systems that support it, the \fB\-@\fP option presents the extended +attributes associated with a file as a directory. +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 nosort +Tell readline not to sort the list of possible completions alphabetically. +.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, +other than \fB\-f\fP and \fB\-F\fP, 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, assignments, and attribute modifications +to \fIname\fP, except for changing the +\fB\-n\fP attribute itself, are performed on the variable referenced by +\fIname\fP's value. +The nameref 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. +When using \fB\-a\fP or \fB\-A\fP and the compound assignment syntax to +create array variables, additional attributes do not take effect until +subsequent assignments. +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 the \fB\-a\fP nor the \fB\-r\fP option +is supplied, 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 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. +If \fIname\fP is \-, the set of shell options is made local to the function +in which \fBlocal\fP is invoked: shell options changed using the +\fBset\fP builtin inside the function are restored to their original values +when the function returns. +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\-d\fP \fIdelim\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\-d\fP \fIdelim\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 \-d +The first character of \fIdelim\fP is used to terminate each input line, +rather than newline. +.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. +If no argument is specified, conversion behaves as if -1 had been given. +This is an exception to the usual \fBprintf\fP behavior. +.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 using the same rules the shell +uses for expansion (described above under \fBWord Splitting\fP). +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 honors 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 (or a specified number of characters) +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 \fBread\fP times out, \fBread\fP saves any partial input read into +the specified variable \fIname\fP. +If \fItimeout\fP is 0, \fBread\fP returns immediately, without trying to +read any 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. +.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 \fBreturn\fP is executed by a trap handler, the last command used to +determine the status is the last command executed before the trap handler. +if \fBreturn\fP is executed during a \fBDEBUG\fP trap, the last command +used to determine the status is the last command executed by the trap +handler before \fBreturn\fP was invoked. +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\fP mode, 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. +.if t .sp 0.5 +.if n .sp 1 +If a compound command or shell function executes in a context +where \fB\-e\fP is being ignored, +none of the commands executed within the compound command or function body +will be affected by the \fB\-e\fP setting, even if \fB\-e\fP is set +and a command returns a failure status. +If a compound command or shell function sets \fB\-e\fP while executing in +a context where \fB\-e\fP is ignored, that setting will not have any +effect until the compound command or the command containing the function +call completes. +.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). +See +.SM +.B "SEE ALSO" +below for a reference to a document that details how posix mode affects +bash's behavior. +.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 settings controlling optional shell behavior. +The settings can be either those listed below, or, if the +.B \-o +option is used, those available with the +.B \-o +option to the \fBset\fP builtin command. +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 \fIposix\fP 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 compat42 +If set, +.B bash +does not process the replacement string in the pattern substitution word +expansion using quote removal. +.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), the shell simulates +a call to \fBreturn\fP. +.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 bracket expressions (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, +when performing pattern substitution word expansions, +or when filtering possible completions as part of programmable completion. +.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 +a pipeline (which may consist of a single simple +command), a list, or a compound command returns 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 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 using +.BR ! . +These are the same conditions obeyed by the \fBerrexit\fP (\fB\-e\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\-HSabcdefiklmnpqrstuvxPT\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 \-k +The maximum number of kqueues that may be allocated +.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 \-P +The maximum number of pseudoterminals +.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 \-P , +.BR \-T , +.BR \-b , +.BR \-k , +.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 [\fB\-n\fP] [\fIn ...\fP] +Wait for each specified child 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 the \fB\-n\fP option is supplied, \fBwait\fP waits for any job to +terminate and returns its exit status. +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 -- +http://pubs.opengroup.org/onlinepubs/9699919799/ +.TP +http://tiswww.case.edu/~chet/bash/POSIX -- a description of posix mode +.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/version.texi b/doc/version.texi index a666278cc..15447f969 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2015 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Thu Jan 1 14:44:06 EST 2015 +@set LASTCHANGE Mon Jan 19 14:47:45 EST 2015 @set EDITION 4.4 @set VERSION 4.4 -@set UPDATED 1 January 2015 +@set UPDATED 19 January 2015 @set UPDATED-MONTH January 2015 diff --git a/doc/version.texi~ b/doc/version.texi~ new file mode 100644 index 000000000..a666278cc --- /dev/null +++ b/doc/version.texi~ @@ -0,0 +1,11 @@ +@ignore +Copyright (C) 1988-2015 Free Software Foundation, Inc. +@end ignore + +@set LASTCHANGE Thu Jan 1 14:44:06 EST 2015 + +@set EDITION 4.4 +@set VERSION 4.4 + +@set UPDATED 1 January 2015 +@set UPDATED-MONTH January 2015 diff --git a/examples/loadables/Makefile.in.save b/examples/loadables/Makefile.in.save new file mode 100644 index 000000000..f6208f5cc --- /dev/null +++ b/examples/loadables/Makefile.in.save @@ -0,0 +1,238 @@ +# +# 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/execute_cmd.c b/execute_cmd.c index 7932ec24e..929e1437f 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -3122,6 +3122,8 @@ select_query (list, list_len, prompt, print_menu) return ((char *)NULL); } repl_string = get_string_value ("REPLY"); + if (repl_string == 0) + return ((char *)NULL); if (*repl_string == 0) { print_menu = 1; diff --git a/jobs.c b/jobs.c index 56444e89d..223cfc356 100644 --- a/jobs.c +++ b/jobs.c @@ -2510,6 +2510,7 @@ wait_for (pid) struct sigaction act, oact; sigset_t nullset, chldset; + queue_sigchld = 1; sigemptyset (&nullset); sigemptyset (&chldset); sigprocmask (SIG_SETMASK, &nullset, &chldset); diff --git a/jobs.c~ b/jobs.c~ new file mode 100644 index 000000000..56444e89d --- /dev/null +++ b/jobs.c~ @@ -0,0 +1,4545 @@ +/* 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-2013 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 +#if defined (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 + +#if !DEFAULT_CHILD_MAX +# define DEFAULT_CHILD_MAX 32 +#endif + +#if !MAX_CHILD_MAX +# define MAX_CHILD_MAX 8192 +#endif + +#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. */ +volatile pid_t last_made_pid = NO_PID; + +/* Pid of the last asynchronous child. */ +volatile 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; + +/* Are we running in background? (terminal_pgrp != shell_pgrp) */ +int running_in_background = 0; + +/* 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]; + +#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; +} + +/* 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 or if we're a (presumably non-interactive) shell running + * in the background. + * + */ + if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0 && running_in_background == 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; + + if (bgpids.npid == 0 || bgpids.list == 0) + return; /* just paranoia */ + + 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 + { +#ifdef DEBUG + internal_warning (_("forked pid %d appears in running job %d"), pid, job+1); +#endif + 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 0 + 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 (); + +#if 0 + 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. Assume 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 (); + +#if 0 + 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; + + /* XXX - block SIGTERM here and unblock in child after fork resets the + set of pending signals? */ + 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 */ + + RESET_SIGTERM; + + /* Create the child, handle severe errors. Retry on EAGAIN. */ + while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) + { + /* bash-4.2 */ + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + /* If we can't create any children, try to reap some dead ones. */ + waitchld (-1, 0); + + sys_error ("fork: retry"); + RESET_SIGTERM; + + if (sleep (forksleep) != 0) + break; + forksleep <<= 1; + + if (interrupt_state) + break; + sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); + } + + if (pid != 0) + RESET_SIGTERM; + + 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) && running_in_background == 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 (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); +} + +/* Reset the tty-generated job control signals to SIG_DFL unless that signal + was ignored at entry to the shell, in which case we need to set it to + SIG_IGN in the child. We can't rely on resetting traps, since the hard + ignored signals can't be trapped. */ +void +default_tty_job_signals () +{ + if (signal_is_trapped (SIGTSTP) == 0 && signal_is_hard_ignored (SIGTSTP)) + set_signal_handler (SIGTSTP, SIG_IGN); + else + set_signal_handler (SIGTSTP, SIG_DFL); + + if (signal_is_trapped (SIGTTIN) == 0 && signal_is_hard_ignored (SIGTTIN)) + set_signal_handler (SIGTTIN, SIG_IGN); + else + set_signal_handler (SIGTTIN, SIG_DFL); + + if (signal_is_trapped (SIGTTOU) == 0 && signal_is_hard_ignored (SIGTTOU)) + set_signal_handler (SIGTTOU, SIG_IGN); + else + set_signal_handler (SIGTTOU, SIG_DFL); +} + +/* Called once in a parent process. */ +void +get_original_tty_job_signals () +{ + static int fetched = 0; + + if (fetched == 0) + { + get_original_signal (SIGTSTP); + get_original_signal (SIGTTIN); + get_original_signal (SIGTTOU); + fetched = 1; + } +} + +/* 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 = 128+SIGINT; + 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)) + { + trap_handler (SIGINT); /* set pending_traps[SIGINT] */ + wait_signal_received = SIGINT; + if (interrupt_immediately) + { + interrupt_immediately = 0; + longjmp (wait_intr_buf, 1); + } + else + /* Let CHECK_WAIT_INTR handle it in wait_for/waitchld */ + SIGRETURN (0); + } + else if (interrupt_immediately) + { + ADDINTERRUPT; + QUIT; + } + else /* wait_builtin but signal not trapped, treat as interrupt */ + kill (getpid (), SIGINT); + } + + /* 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. */ + child = 0; + 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; + + /* Check for a trapped signal interrupting the wait builtin and jump out */ + CHECK_WAIT_INTR; + + /* 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 + { + if (pid != ANY_PID) + 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) /* XXX -- && pid != ANY_PID ? */ + 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 (pid == ANY_PID || 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; +# if defined (SA_RESTART) + act.sa_flags |= SA_RESTART; +# endif + sigaction (SIGCHLD, &act, &oact); +# endif /* MUST_UNBLOCK_CHLD */ + queue_sigchld = 1; + waiting_for_child++; + r = waitchld (pid, 1); /* XXX */ + waiting_for_child--; +#if 0 +itrace("wait_for: blocking wait for %d returns %d child = %p", (int)pid, r, child); +#endif +# 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; + /* XXX - restore sigint handler here? */ + 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) + { + if (child) + { + 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++; + } + if (pid == ANY_PID) + { + termination_state = -1; + break; + } + } +#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; + + /* Check for a trapped signal interrupting the wait builtin and jump out */ + CHECK_WAIT_INTR; + + if (pid == ANY_PID) + /* XXX - could set child but we don't have a handle on what waitchld + reaps. Leave termination_state alone. */ + goto wait_for_return; + } + 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) + : (child ? process_exit_status (child->status) : EXECUTION_SUCCESS); + last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job) + : (child ? process_exit_signal (child->status) : 0); + + /* XXX */ + if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || (child && 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 + /* Don't modify terminal pgrp if we are running in the background */ + if (running_in_background == 0) + 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; +} + +/* Wait for any background job started by this shell to finish. Very + similar to wait_for_background_pids(). Returns the exit status of + the next exiting job, -1 if there are no background jobs. The caller + is responsible for translating -1 into the right return value. */ +int +wait_for_any_job () +{ + pid_t pid; + int i, r, waited_for; + sigset_t set, oset; + + if (jobs_list_frozen) + return -1; + + /* First see if there are any unnotified dead jobs that we can report on */ + BLOCK_CHILD (set, oset); + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i) == 0) + { +return_job: + r = job_exit_status (i); + notify_of_job_status (); /* XXX */ + delete_job (i, 0); +#if defined (COPROCESS_SUPPORT) + coproc_reap (); +#endif + UNBLOCK_CHILD (oset); + return r; + } + } + UNBLOCK_CHILD (oset); + + /* At this point, we have no dead jobs in the jobs table. Wait until we + get one, even if it takes multiple pids exiting. */ + for (waited_for = 0;;) + { + /* Make sure there is a background job to wait for */ + BLOCK_CHILD (set, oset); + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) + break; + if (i == js.j_jobslots) + { + UNBLOCK_CHILD (oset); + return -1; + } + + UNBLOCK_CHILD (oset); + + QUIT; + CHECK_TERMSIG; + CHECK_WAIT_INTR; + + errno = 0; + r = wait_for (ANY_PID); /* special sentinel value for wait_for */ + if (r == -1 && errno == ECHILD) + mark_all_jobs_as_dead (); + + /* Now we see if we have any dead jobs and return the first one */ + BLOCK_CHILD (set, oset); + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i] && DEADJOB (i)) + goto return_job; + UNBLOCK_CHILD (oset); + } + + return -1; +} + +/* 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; + /* Check for a trapped signal interrupting the wait builtin and jump out */ + CHECK_WAIT_INTR; + + 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); + +#if 0 +if (wpid != -1 && block) + itrace("waitchld: blocking waitpid returns %d", pid); +#endif + /* 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 0 +itrace("waitchld: waitpid returns %d block = %d children_exited = %d", pid, block, children_exited); +#endif + /* 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; + CHECK_WAIT_INTR; + + /* 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, WSTATUS(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; + /* This was trap_handler (SIGCHLD) but that can lose traps if + children_exited > 1 */ + queue_sigchld_trap (children_exited); + wait_signal_received = SIGCHLD; + /* If we're in a signal handler, let CHECK_WAIT_INTR pick it up; + run_pending_traps will call run_sigchld_trap later */ + if (sigchld == 0) + longjmp (wait_intr_buf, 1); + } + /* If not in posix mode and not executing the wait builtin, queue the + signal for later handling. Run the trap immediately if we are + executing the wait builtin, but don't break out of `wait'. */ + else if (sigchld) /* called from signal handler */ + queue_sigchld_trap (children_exited); + else if (running_trap) + queue_sigchld_trap (children_exited); + else if (this_shell_builtin == wait_builtin) + run_sigchld_trap (children_exited); /* XXX */ + else + queue_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); + unwind_protect_pointer (this_shell_builtin); + + /* 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; + + running_trap = SIGCHLD + 1; + + set_impossible_sigchld_trap (); + jobs_list_frozen = 1; + for (i = 0; i < nchild; i++) + { +#if 0 + interrupt_immediately = 1; +#endif + parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); + } + + run_unwind_frame ("SIGCHLD trap"); + running_trap = 0; +} + +/* 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); + terminal_pgrp = tcgetpgrp (shell_tty); /* for checking later */ + } + 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); + if (shell_tty != -1) + 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")); + } + + running_in_background = terminal_pgrp != shell_pgrp; + + 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 disposition unmodified 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 ("%d: maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d in_background = %d", (int)getpid(), tpgrp, opgrp, npgrp, running_in_background); +#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 0 + if (ndeadproc != js.c_reaped) + itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped); +# endif + 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. */ +int +freeze_jobs_list () +{ + int o; + + o = jobs_list_frozen; + jobs_list_frozen = 1; + return o; +} + +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 (terminal_pgrp == NO_PID) + terminal_pgrp = tcgetpgrp (shell_tty); + + running_in_background = (terminal_pgrp != shell_pgrp); + +#if 0 + if (interactive_shell == 0 && running_in_background == 0 && job_control != old) + { + if (job_control) + initialize_job_signals (); + else + default_tty_job_signals (); + } +#endif + + /* 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 || job_control) /* XXX - should it be just job_control? */ + { + 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); +} + +void +set_maxchild (nchild) + int nchild; +{ + static int lmaxchild = -1; + + if (lmaxchild < 0) + lmaxchild = getmaxchild (); + if (lmaxchild < 0) + lmaxchild = DEFAULT_CHILD_MAX; + + /* Clamp value we set. Minimum is what Posix requires, maximum is defined + above as MAX_CHILD_MAX. */ + if (nchild < lmaxchild) + nchild = lmaxchild; + else if (nchild > MAX_CHILD_MAX) + nchild = MAX_CHILD_MAX; + + js.c_childmax = nchild; +} + +/* 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/readline/complete.c b/lib/readline/complete.c index 79a99d109..302ea1ddb 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -2455,6 +2455,7 @@ rl_filename_completion_function (text, state) static int filename_len; char *temp, *dentry, *convfn; int dirlen, dentlen, convlen; + int tilde_dirname; struct dirent *entry; /* If we don't have any state, then do some initialization. */ @@ -2512,11 +2513,13 @@ rl_filename_completion_function (text, state) else users_dirname = savestring (dirname); + tilde_dirname = 0; if (*dirname == '~') { temp = tilde_expand (dirname); xfree (dirname); dirname = temp; + tilde_dirname = 1; } /* We have saved the possibly-dequoted version of the directory name @@ -2535,7 +2538,7 @@ rl_filename_completion_function (text, state) xfree (users_dirname); users_dirname = savestring (dirname); } - else if (rl_completion_found_quote && rl_filename_dequoting_function) + else if (tilde_dirname == 0 && rl_completion_found_quote && rl_filename_dequoting_function) { /* delete single and double quotes */ xfree (dirname); diff --git a/lib/readline/doc/Makefile.old b/lib/readline/doc/Makefile.old new file mode 100644 index 000000000..58d4dd762 --- /dev/null +++ b/lib/readline/doc/Makefile.old @@ -0,0 +1,76 @@ +# 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/doc/rluser.texi b/lib/readline/doc/rluser.texi index 3b48b9bfb..284f46657 100644 --- a/lib/readline/doc/rluser.texi +++ b/lib/readline/doc/rluser.texi @@ -2013,6 +2013,9 @@ with @option{-F}. Tell Readline not to quote the completed words if they are filenames (quoting filenames is the default). +@item nosort +Tell Readline not to sort the list of possible completions alphabetically. + @item nospace Tell Readline not to append a space (the default) to words completed at the end of the line. diff --git a/lib/readline/doc/rluser.texi~ b/lib/readline/doc/rluser.texi~ new file mode 100644 index 000000000..3b48b9bfb --- /dev/null +++ b/lib/readline/doc/rluser.texi~ @@ -0,0 +1,2301 @@ +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rluser.info +@comment %**end of header (This is for running Texinfo on a region.) + +@ignore +This file documents the end user interface to the GNU command line +editing features. It is to be an appendix to manuals for programs which +use these features. There is a document entitled "readline.texinfo" +which contains both end-user and programmer documentation for the +GNU Readline Library. + +Copyright (C) 1988--2014 Free Software Foundation, Inc. + +Authored by Brian Fox and Chet Ramey. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +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. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ignore + +@comment If you are including this manual as an appendix, then set the +@comment variable readline-appendix. + +@ifclear BashFeatures +@defcodeindex bt +@end ifclear + +@node Command Line Editing +@chapter Command Line Editing + +This chapter describes the basic features of the @sc{gnu} +command line editing interface. +@ifset BashFeatures +Command line editing is provided by the Readline library, which is +used by several different programs, including Bash. +Command line editing is enabled by default when using an interactive shell, +unless the @option{--noediting} option is supplied at shell invocation. +Line editing is also used when using the @option{-e} option to the +@code{read} builtin command (@pxref{Bash Builtins}). +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 @option{-o emacs} or +@option{-o vi} options to the @code{set} builtin command +(@pxref{The Set Builtin}), or disabled using the @option{+o emacs} or +@option{+o vi} options to @code{set}. +@end ifset + +@menu +* Introduction and Notation:: Notation used in this text. +* Readline Interaction:: The minimum set of commands for editing a line. +* Readline Init File:: Customizing Readline from a user's view. +* Bindable Readline Commands:: A description of most of the Readline commands + available for binding +* Readline vi Mode:: A short description of how to make Readline + behave like the vi editor. +@ifset BashFeatures +* Programmable Completion:: How to specify the possible completions for + a specific command. +* Programmable Completion Builtins:: Builtin commands to specify how to + complete arguments for a particular command. +* A Programmable Completion Example:: An example shell function for + generating possible completions. +@end ifset +@end menu + +@node Introduction and Notation +@section Introduction to Line Editing + +The following paragraphs describe the notation used to represent +keystrokes. + +The text @kbd{C-k} is read as `Control-K' and describes the character +produced when the @key{k} key is pressed while the Control key +is depressed. + +The text @kbd{M-k} is read as `Meta-K' and describes the character +produced when the Meta key (if you have one) is depressed, and the @key{k} +key is pressed. +The Meta key is labeled @key{ALT} on many keyboards. +On keyboards with two keys labeled @key{ALT} (usually to either side of +the space bar), the @key{ALT} on the left side is generally set to +work as a Meta key. +The @key{ALT} key on the right may also be configured to work as a +Meta key or may be configured as some other modifier, such as a +Compose key for typing accented characters. + +If you do not have a Meta or @key{ALT} key, or another key working as +a Meta key, the identical keystroke can be generated by typing @key{ESC} +@emph{first}, and then typing @key{k}. +Either process is known as @dfn{metafying} the @key{k} key. + +The text @kbd{M-C-k} is read as `Meta-Control-k' and describes the +character produced by @dfn{metafying} @kbd{C-k}. + +In addition, several keys have their own names. Specifically, +@key{DEL}, @key{ESC}, @key{LFD}, @key{SPC}, @key{RET}, and @key{TAB} all +stand for themselves when seen in this text, or in an init file +(@pxref{Readline Init File}). +If your keyboard lacks a @key{LFD} key, typing @key{C-j} will +produce the desired character. +The @key{RET} key may be labeled @key{Return} or @key{Enter} on +some keyboards. + +@node Readline Interaction +@section Readline Interaction +@cindex interaction, readline + +Often during an interactive session you type in a long line of text, +only to notice that the first word on the line is misspelled. The +Readline library gives you a set of commands for manipulating the text +as you type it in, allowing you to just fix your typo, and not forcing +you to retype the majority of the line. Using these editing commands, +you move the cursor to the place that needs correction, and delete or +insert the text of the corrections. Then, when you are satisfied with +the line, you simply press @key{RET}. You do not have to be at the +end of the line to press @key{RET}; the entire line is accepted +regardless of the location of the cursor within the line. + +@menu +* Readline Bare Essentials:: The least you need to know about Readline. +* Readline Movement Commands:: Moving about the input line. +* Readline Killing Commands:: How to delete text, and how to get it back! +* Readline Arguments:: Giving numeric arguments to commands. +* Searching:: Searching through previous lines. +@end menu + +@node Readline Bare Essentials +@subsection Readline Bare Essentials +@cindex notation, readline +@cindex command editing +@cindex editing command lines + +In order to enter characters into the line, simply type them. The typed +character appears where the cursor was, and then the cursor moves one +space to the right. If you mistype a character, you can use your +erase character to back up and delete the mistyped character. + +Sometimes you may mistype a character, and +not notice the error until you have typed several other characters. In +that case, you can type @kbd{C-b} to move the cursor to the left, and then +correct your mistake. Afterwards, you can move the cursor to the right +with @kbd{C-f}. + +When you add text in the middle of a line, you will notice that characters +to the right of the cursor are `pushed over' to make room for the text +that you have inserted. Likewise, when you delete text behind the cursor, +characters to the right of the cursor are `pulled back' to fill in the +blank space created by the removal of the text. A list of the bare +essentials for editing the text of an input line follows. + +@table @asis +@item @kbd{C-b} +Move back one character. +@item @kbd{C-f} +Move forward one character. +@item @key{DEL} or @key{Backspace} +Delete the character to the left of the cursor. +@item @kbd{C-d} +Delete the character underneath the cursor. +@item @w{Printing characters} +Insert the character into the line at the cursor. +@item @kbd{C-_} or @kbd{C-x C-u} +Undo the last editing command. You can undo all the way back to an +empty line. +@end table + +@noindent +(Depending on your configuration, the @key{Backspace} key be set to +delete the character to the left of the cursor and the @key{DEL} key set +to delete the character underneath the cursor, like @kbd{C-d}, rather +than the character to the left of the cursor.) + +@node Readline Movement Commands +@subsection Readline Movement Commands + + +The above table describes the most basic keystrokes that you need +in order to do editing of the input line. For your convenience, many +other commands have been added in addition to @kbd{C-b}, @kbd{C-f}, +@kbd{C-d}, and @key{DEL}. Here are some commands for moving more rapidly +about the line. + +@table @kbd +@item C-a +Move to the start of the line. +@item C-e +Move to the end of the line. +@item M-f +Move forward a word, where a word is composed of letters and digits. +@item M-b +Move backward a word. +@item C-l +Clear the screen, reprinting the current line at the top. +@end table + +Notice how @kbd{C-f} moves forward a character, while @kbd{M-f} moves +forward a word. It is a loose convention that control keystrokes +operate on characters while meta keystrokes operate on words. + +@node Readline Killing Commands +@subsection Readline Killing Commands + +@cindex killing text +@cindex yanking text + +@dfn{Killing} text means to delete the text from the line, but to save +it away for later use, usually by @dfn{yanking} (re-inserting) +it back into the line. +(`Cut' and `paste' are more recent jargon for `kill' and `yank'.) + +If the description for a command says that it `kills' text, then you can +be sure that you can get the text back in a different (or the same) +place later. + +When you use a kill command, the text is saved in a @dfn{kill-ring}. +Any number of consecutive kills save all of the killed text together, so +that when you yank it back, you get it all. The kill +ring is not line specific; the text that you killed on a previously +typed line is available to be yanked back later, when you are typing +another line. +@cindex kill ring + +Here is the list of commands for killing text. + +@table @kbd +@item C-k +Kill the text from the current cursor position to the end of the line. + +@item M-d +Kill from the cursor 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 @kbd{M-f}. + +@item M-@key{DEL} +Kill from the cursor the start of the current word, or, if between +words, to the start of the previous word. +Word boundaries are the same as those used by @kbd{M-b}. + +@item C-w +Kill from the cursor to the previous whitespace. This is different than +@kbd{M-@key{DEL}} because the word boundaries differ. + +@end table + +Here is how to @dfn{yank} the text back into the line. Yanking +means to copy the most-recently-killed text from the kill buffer. + +@table @kbd +@item C-y +Yank the most recently killed text back into the buffer at the cursor. + +@item M-y +Rotate the kill-ring, and yank the new top. You can only do this if +the prior command is @kbd{C-y} or @kbd{M-y}. +@end table + +@node Readline Arguments +@subsection Readline Arguments + +You can pass numeric arguments to Readline commands. Sometimes the +argument acts as a repeat count, other times it is the @i{sign} of the +argument that is significant. If you pass a negative argument to a +command which normally acts in a forward direction, that command will +act in a backward direction. For example, to kill text back to the +start of the line, you might type @samp{M-- C-k}. + +The general way to pass numeric arguments to a command is to type meta +digits before the command. If the first `digit' typed is a minus +sign (@samp{-}), then the sign of the argument will be negative. Once +you have typed one meta digit to get the argument started, you can type +the remainder of the digits, and then the command. For example, to give +the @kbd{C-d} command an argument of 10, you could type @samp{M-1 0 C-d}, +which will delete the next ten characters on the input line. + +@node Searching +@subsection Searching for Commands in the History + +Readline provides commands for searching through the command history +@ifset BashFeatures +(@pxref{Bash History Facilities}) +@end ifset +for lines containing a specified string. +There are two search modes: @dfn{incremental} and @dfn{non-incremental}. + +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. +To search backward in the history for a particular string, type +@kbd{C-r}. Typing @kbd{C-s} searches forward through the history. +The characters present in the value of the @code{isearch-terminators} variable +are used to terminate an incremental search. +If that variable has not been assigned a value, the @key{ESC} and +@kbd{C-J} characters will terminate an incremental search. +@kbd{C-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. + +To find other matching entries in the history list, type @kbd{C-r} or +@kbd{C-s} 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 @key{RET} will terminate the search and accept +the line, thereby executing the command from the history list. +A movement command will terminate the search, make the last line found +the current line, and begin editing. + +Readline remembers the last incremental search string. If two +@kbd{C-r}s are typed without any intervening characters defining a new +search string, any remembered search string is used. + +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. + +@node Readline Init File +@section Readline Init File +@cindex initialization file, readline + +Although the Readline library comes with a set of Emacs-like +keybindings installed by default, it is possible to use a different set +of keybindings. +Any user can customize programs that use Readline by putting +commands in an @dfn{inputrc} file, conventionally in his home directory. +The name of this +@ifset BashFeatures +file is taken from the value of the shell variable @env{INPUTRC}. If +@end ifset +@ifclear BashFeatures +file is taken from the value of the environment variable @env{INPUTRC}. If +@end ifclear +that variable is unset, the default is @file{~/.inputrc}. If that +file does not exist or cannot be read, the ultimate default is +@file{/etc/inputrc}. + +When a program which uses the Readline library starts up, the +init file is read, and the key bindings are set. + +In addition, the @code{C-x C-r} command re-reads this init file, thus +incorporating any changes that you might have made to it. + +@menu +* Readline Init File Syntax:: Syntax for the commands in the inputrc file. + +* Conditional Init Constructs:: Conditional key bindings in the inputrc file. + +* Sample Init File:: An example inputrc file. +@end menu + +@node Readline Init File Syntax +@subsection Readline Init File Syntax + +There are only a few basic constructs allowed in the +Readline init file. Blank lines are ignored. +Lines beginning with a @samp{#} are comments. +Lines beginning with a @samp{$} indicate conditional +constructs (@pxref{Conditional Init Constructs}). Other lines +denote variable settings and key bindings. + +@table @asis +@item Variable Settings +You can modify the run-time behavior of Readline by +altering the values of variables in Readline +using the @code{set} command within the init file. +The syntax is simple: + +@example +set @var{variable} @var{value} +@end example + +@noindent +Here, for example, is how to +change from the default Emacs-like key binding to use +@code{vi} line editing commands: + +@example +set editing-mode vi +@end example + +Variable names and values, where appropriate, are recognized without regard +to case. Unrecognized variable names are ignored. + +Boolean variables (those that can be set to on or off) are set to on if +the value is null or empty, @var{on} (case-insensitive), or 1. Any other +value results in the variable being set to off. + +@ifset BashFeatures +The @w{@code{bind -V}} command lists the current Readline variable names +and values. @xref{Bash Builtins}. +@end ifset + +A great deal of run-time behavior is changeable with the following +variables. + +@cindex variables, readline +@table @code + +@item bell-style +@vindex bell-style +Controls what happens when Readline wants to ring the terminal bell. +If set to @samp{none}, Readline never rings the bell. If set to +@samp{visible}, Readline uses a visible bell if one is available. +If set to @samp{audible} (the default), Readline attempts to ring +the terminal's bell. + +@item bind-tty-special-chars +@vindex bind-tty-special-chars +If set to @samp{on} (the default), Readline attempts to bind the control +characters treated specially by the kernel's terminal driver to their +Readline equivalents. + +@item blink-matching-paren +@vindex blink-matching-paren +If set to @samp{on}, Readline attempts to briefly move the cursor to an +opening parenthesis when a closing parenthsis is inserted. The default +is @samp{off}. + +@item colored-completion-prefix +@vindex colored-completion-prefix +If set to @samp{on}, when listing completions, Readline displays the +common prefix of the set of possible completions using a different color. +The color definitions are taken from the value of the @env{LS_COLORS} +environment variable. +The default is @samp{off}. + +@item colored-stats +@vindex colored-stats +If set to @samp{on}, Readline displays possible completions using different +colors to indicate their file type. +The color definitions are taken from the value of the @env{LS_COLORS} +environment variable. +The default is @samp{off}. + +@item comment-begin +@vindex comment-begin +The string to insert at the beginning of the line when the +@code{insert-comment} command is executed. The default value +is @code{"#"}. + +@item completion-display-width +@vindex completion-display-width +The number of screen columns used to display possible matches +when performing completion. +The value is ignored if it is less than 0 or greater than the terminal +screen width. +A value of 0 will cause matches to be displayed one per line. +The default value is -1. + +@item completion-ignore-case +@vindex completion-ignore-case +If set to @samp{on}, Readline performs filename matching and completion +in a case-insensitive fashion. +The default value is @samp{off}. + +@item completion-map-case +@vindex completion-map-case +If set to @samp{on}, and @var{completion-ignore-case} is enabled, Readline +treats hyphens (@samp{-}) and underscores (@samp{_}) as equivalent when +performing case-insensitive filename matching and completion. + +@item completion-prefix-display-length +@vindex completion-prefix-display-length +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. + +@item completion-query-items +@vindex completion-query-items +The number of possible completions that determines when the user is +asked whether the list of possibilities should be displayed. +If the number of possible completions is greater than this value, +Readline will ask the user whether or not he wishes to view +them; otherwise, they are simply listed. +This variable must be set to an integer value greater than or equal to 0. +A negative value means Readline should never ask. +The default limit is @code{100}. + +@item convert-meta +@vindex convert-meta +If set to @samp{on}, Readline will convert characters with the +eighth bit set to an @sc{ascii} key sequence by stripping the eighth +bit and prefixing an @key{ESC} character, converting them to a +meta-prefixed key sequence. The default value is @samp{on}. + +@item disable-completion +@vindex disable-completion +If set to @samp{On}, Readline will inhibit word completion. +Completion characters will be inserted into the line as if they had +been mapped to @code{self-insert}. The default is @samp{off}. + +@item editing-mode +@vindex editing-mode +The @code{editing-mode} variable controls which default set of +key bindings is used. By default, Readline starts up in Emacs editing +mode, where the keystrokes are most similar to Emacs. This variable can be +set to either @samp{emacs} or @samp{vi}. + +@item emacs-mode-string +@vindex emacs-mode-string +This string is displayed immediately before the last line of the primary +prompt when emacs editing mode is active. The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the @samp{\1} and @samp{\2} escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +The default is @samp{@@}. + +@item echo-control-characters +@vindex echo-control-characters +When set to @samp{on}, on operating systems that indicate they support it, +readline echoes a character corresponding to a signal generated from the +keyboard. The default is @samp{on}. + +@item enable-bracketed-paste +@vindex enable-bracketed-paste +When set to @samp{On}, Readline will configure the terminal in a way +that will enable it to insert each paste into the editing buffer as a +single string of characters, instead of treating each character as if +it had been read from the keyboard. This can prevent pasted characters +from being interpreted as editing commands. The default is @samp{off}. + +@item enable-keypad +@vindex enable-keypad +When set to @samp{on}, Readline will try to enable the application +keypad when it is called. Some systems need this to enable the +arrow keys. The default is @samp{off}. + +@item enable-meta-key +When set to @samp{on}, 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. +The default is @samp{on}. + +@item expand-tilde +@vindex expand-tilde +If set to @samp{on}, tilde expansion is performed when Readline +attempts word completion. The default is @samp{off}. + +@item history-preserve-point +@vindex history-preserve-point +If set to @samp{on}, the history code attempts to place the point (the +current cursor position) at the +same location on each history line retrieved with @code{previous-history} +or @code{next-history}. The default is @samp{off}. + +@item history-size +@vindex history-size +Set the maximum number of history entries saved in the history list. +If set to zero, any existing history entries are deleted and no new entries +are saved. +If set to a value less than zero, the number of history entries is not +limited. +By default, the number of history entries is not limited. + +@item horizontal-scroll-mode +@vindex horizontal-scroll-mode +This variable can be set to either @samp{on} or @samp{off}. Setting it +to @samp{on} means that the text of the lines being edited will scroll +horizontally on a single screen line when they are longer than the width +of the screen, instead of wrapping onto a new screen line. By default, +this variable is set to @samp{off}. + +@item input-meta +@vindex input-meta +@vindex meta-flag +If set to @samp{on}, Readline will enable eight-bit input (it +will not clear the eighth bit in the characters it reads), +regardless of what the terminal claims it can support. The +default value is @samp{off}. The name @code{meta-flag} is a +synonym for this variable. + +@item isearch-terminators +@vindex isearch-terminators +The string of characters that should terminate an incremental search without +subsequently executing the character as a command (@pxref{Searching}). +If this variable has not been given a value, the characters @key{ESC} and +@kbd{C-J} will terminate an incremental search. + +@item keymap +@vindex keymap +Sets Readline's idea of the current keymap for key binding commands. +Acceptable @code{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}. The default value is @code{emacs}. +The value of the @code{editing-mode} variable also affects the +default keymap. + +@item keyseq-timeout +Specifies the duration Readline 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, Readline will use the shorter +but complete key sequence. +Readline uses this value to determine whether or not input is +available on the current input source (@code{rl_instream} by default). +The value is specified in milliseconds, so a value of 1000 means that +Readline 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, Readline will wait until another key is pressed to +decide which key sequence to complete. +The default value is @code{500}. + +@item mark-directories +If set to @samp{on}, completed directory names have a slash +appended. The default is @samp{on}. + +@item mark-modified-lines +@vindex mark-modified-lines +This variable, when set to @samp{on}, causes Readline to display an +asterisk (@samp{*}) at the start of history lines which have been modified. +This variable is @samp{off} by default. + +@item mark-symlinked-directories +@vindex mark-symlinked-directories +If set to @samp{on}, completed names which are symbolic links +to directories have a slash appended (subject to the value of +@code{mark-directories}). +The default is @samp{off}. + +@item match-hidden-files +@vindex match-hidden-files +This variable, when set to @samp{on}, causes Readline to match files whose +names begin with a @samp{.} (hidden files) when performing filename +completion. +If set to @samp{off}, the leading @samp{.} must be +supplied by the user in the filename to be completed. +This variable is @samp{on} by default. + +@item menu-complete-display-prefix +@vindex menu-complete-display-prefix +If set to @samp{on}, menu completion displays the common prefix of the +list of possible completions (which may be empty) before cycling through +the list. The default is @samp{off}. + +@item output-meta +@vindex output-meta +If set to @samp{on}, Readline will display characters with the +eighth bit set directly rather than as a meta-prefixed escape +sequence. The default is @samp{off}. + +@item page-completions +@vindex page-completions +If set to @samp{on}, Readline uses an internal @code{more}-like pager +to display a screenful of possible completions at a time. +This variable is @samp{on} by default. + +@item print-completions-horizontally +If set to @samp{on}, Readline will display completions with matches +sorted horizontally in alphabetical order, rather than down the screen. +The default is @samp{off}. + +@item revert-all-at-newline +@vindex revert-all-at-newline +If set to @samp{on}, Readline will undo all changes to history lines +before returning when @code{accept-line} is executed. By default, +history lines may be modified and retain individual undo lists across +calls to @code{readline}. The default is @samp{off}. + +@item show-all-if-ambiguous +@vindex show-all-if-ambiguous +This alters the default behavior of the completion functions. If +set to @samp{on}, +words which have more than one possible completion cause the +matches to be listed immediately instead of ringing the bell. +The default value is @samp{off}. + +@item show-all-if-unmodified +@vindex show-all-if-unmodified +This alters the default behavior of the completion functions in +a fashion similar to @var{show-all-if-ambiguous}. +If set to @samp{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. +The default value is @samp{off}. + +@item show-mode-in-prompt +@vindex show-mode-in-prompt +If set to @samp{on}, add a character to the beginning of the prompt +indicating the editing mode: emacs, vi command, or vi insertion. +The mode strings are user-settable. +The default value is @samp{off}. + +@item skip-completed-text +@vindex skip-completed-text +If set to @samp{on}, 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. +For instance, if this is enabled, attempting completion when the cursor +is after the @samp{e} in @samp{Makefile} will result in @samp{Makefile} +rather than @samp{Makefilefile}, assuming there is a single possible +completion. +The default value is @samp{off}. + +@item vi-cmd-mode-string +@vindex vi-cmd-mode-string +This string is displayed immediately before the last line of the primary +prompt when vi editing mode is active and in command mode. +The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the @samp{\1} and @samp{\2} escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +The default is @samp{(cmd)}. + +@item vi-ins-mode-string +@vindex vi-ins-mode-string +This string is displayed immediately before the last line of the primary +prompt when vi editing mode is active and in insertion mode. +The value is expanded like a +key binding, so the standard set of meta- and control prefixes and +backslash escape sequences is available. +Use the @samp{\1} and @samp{\2} escapes to begin and end sequences of +non-printing characters, which can be used to embed a terminal control +sequence into the mode string. +The default is @samp{(ins)}. + +@item visible-stats +@vindex visible-stats +If set to @samp{on}, a character denoting a file's type +is appended to the filename when listing possible +completions. The default is @samp{off}. + +@end table + +@item Key Bindings +The syntax for controlling key bindings in the init file is +simple. First you need to find the name of the command that you +want to change. The following sections contain tables of the command +name, the default keybinding, if any, and a short description of what +the command does. + +Once you know the name of the command, simply place on a line +in the init file the name of the key +you wish to bind the command to, a colon, and then the name of the +command. +There can be no space between the key name and the colon -- that will be +interpreted as part of the key name. +The name of the key can be expressed in different ways, depending on +what you find most comfortable. + +In addition to command names, readline allows keys to be bound +to a string that is inserted when the key is pressed (a @var{macro}). + +@ifset BashFeatures +The @w{@code{bind -p}} command displays Readline function names and +bindings in a format that can put directly into an initialization file. +@xref{Bash Builtins}. +@end ifset + +@table @asis +@item @w{@var{keyname}: @var{function-name} or @var{macro}} +@var{keyname} is the name of a key spelled out in English. For example: +@example +Control-u: universal-argument +Meta-Rubout: backward-kill-word +Control-o: "> output" +@end example + +In the above example, @kbd{C-u} is bound to the function +@code{universal-argument}, +@kbd{M-DEL} is bound to the function @code{backward-kill-word}, and +@kbd{C-o} is bound to run the macro +expressed on the right hand side (that is, to insert the text +@samp{> output} into the line). + +A number of symbolic character names are recognized while +processing this key binding syntax: +@var{DEL}, +@var{ESC}, +@var{ESCAPE}, +@var{LFD}, +@var{NEWLINE}, +@var{RET}, +@var{RETURN}, +@var{RUBOUT}, +@var{SPACE}, +@var{SPC}, +and +@var{TAB}. + +@item @w{"@var{keyseq}": @var{function-name} or @var{macro}} +@var{keyseq} differs from @var{keyname} above in that strings +denoting an entire key sequence can be specified, by placing +the key sequence in double quotes. Some @sc{gnu} Emacs style key +escapes can be used, as in the following example, but the +special character names are not recognized. + +@example +"\C-u": universal-argument +"\C-x\C-r": re-read-init-file +"\e[11~": "Function Key 1" +@end example + +In the above example, @kbd{C-u} is again bound to the function +@code{universal-argument} (just as it was in the first example), +@samp{@kbd{C-x} @kbd{C-r}} is bound to the function @code{re-read-init-file}, +and @samp{@key{ESC} @key{[} @key{1} @key{1} @key{~}} is bound to insert +the text @samp{Function Key 1}. + +@end table + +The following @sc{gnu} Emacs style escape sequences are available when +specifying key sequences: + +@table @code +@item @kbd{\C-} +control prefix +@item @kbd{\M-} +meta prefix +@item @kbd{\e} +an escape character +@item @kbd{\\} +backslash +@item @kbd{\"} +@key{"}, a double quotation mark +@item @kbd{\'} +@key{'}, a single quote or apostrophe +@end table + +In addition to the @sc{gnu} Emacs style escape sequences, a second +set of backslash escapes is available: + +@table @code +@item \a +alert (bell) +@item \b +backspace +@item \d +delete +@item \f +form feed +@item \n +newline +@item \r +carriage return +@item \t +horizontal tab +@item \v +vertical tab +@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) +@end table + +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 @samp{"} and @samp{'}. +For example, the following binding will make @samp{@kbd{C-x} \} +insert a single @samp{\} into the line: +@example +"\C-x\\": "\\" +@end example + +@end table + +@node Conditional Init Constructs +@subsection Conditional Init Constructs + +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. + +@table @code +@item $if +The @code{$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. + +@table @code +@item mode +The @code{mode=} form of the @code{$if} directive is used to test +whether Readline is in @code{emacs} or @code{vi} mode. +This may be used in conjunction +with the @samp{set keymap} command, for instance, to set bindings in +the @code{emacs-standard} and @code{emacs-ctlx} keymaps only if +Readline is starting out in @code{emacs} mode. + +@item term +The @code{term=} 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 +@samp{=} is tested against both the full name of the terminal and +the portion of the terminal name before the first @samp{-}. This +allows @code{sun} to match both @code{sun} and @code{sun-cmd}, +for instance. + +@item application +The @var{application} construct is used to include +application-specific settings. Each program using the Readline +library sets the @var{application name}, and you 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 Bash: +@example +$if Bash +# Quote the current or previous word +"\C-xq": "\eb\"\ef\"" +$endif +@end example +@end table + +@item $endif +This command, as seen in the previous example, terminates an +@code{$if} command. + +@item $else +Commands in this branch of the @code{$if} directive are executed if +the test fails. + +@item $include +This directive takes a single filename as an argument and reads commands +and bindings from that file. +For example, the following directive reads from @file{/etc/inputrc}: +@example +$include /etc/inputrc +@end example +@end table + +@node Sample Init File +@subsection Sample Init File + +Here is an example of an @var{inputrc} file. This illustrates key +binding, variable assignment, and conditional syntax. + +@example +@page +# This file controls the behaviour of line input editing for +# programs that use the GNU Readline library. Existing +# programs include FTP, Bash, and GDB. +# +# You can re-read the inputrc file with C-x C-r. +# Lines beginning with '#' are comments. +# +# First, include any system-wide bindings and variable +# assignments from /etc/Inputrc +$include /etc/Inputrc + +# +# Set various bindings for emacs mode. + +set editing-mode emacs + +$if mode=emacs + +Meta-Control-h: backward-kill-word Text after the function name is ignored + +# +# Arrow keys in keypad mode +# +#"\M-OD": backward-char +#"\M-OC": forward-char +#"\M-OA": previous-history +#"\M-OB": next-history +# +# Arrow keys in ANSI mode +# +"\M-[D": backward-char +"\M-[C": forward-char +"\M-[A": previous-history +"\M-[B": next-history +# +# Arrow keys in 8 bit keypad mode +# +#"\M-\C-OD": backward-char +#"\M-\C-OC": forward-char +#"\M-\C-OA": previous-history +#"\M-\C-OB": next-history +# +# Arrow keys in 8 bit ANSI mode +# +#"\M-\C-[D": backward-char +#"\M-\C-[C": forward-char +#"\M-\C-[A": previous-history +#"\M-\C-[B": next-history + +C-q: quoted-insert + +$endif + +# An old-style binding. This happens to be the default. +TAB: complete + +# Macros that are convenient for shell interaction +$if Bash +# edit the path +"\C-xp": "PATH=$@{PATH@}\e\C-e\C-a\ef\C-f" +# prepare to type a quoted word -- +# insert open and close double quotes +# and move to just after the open quote +"\C-x\"": "\"\"\C-b" +# insert a backslash (testing backslash escapes +# in sequences and macros) +"\C-x\\": "\\" +# Quote the current or previous word +"\C-xq": "\eb\"\ef\"" +# Add a binding to refresh the line, which is unbound +"\C-xr": redraw-current-line +# Edit variable on current line. +"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y=" +$endif + +# use a visible bell if one is available +set bell-style visible + +# don't strip characters to 7 bits when reading +set input-meta on + +# allow iso-latin1 characters to be inserted rather +# than converted to prefix-meta sequences +set convert-meta off + +# display characters with the eighth bit set directly +# rather than as meta-prefixed characters +set output-meta on + +# if there are more than 150 possible completions for +# a word, ask the user if he wants to see all of them +set completion-query-items 150 + +# For FTP +$if Ftp +"\C-xg": "get \M-?" +"\C-xt": "put \M-?" +"\M-.": yank-last-arg +$endif +@end example + +@node Bindable Readline Commands +@section Bindable Readline Commands + +@menu +* Commands For Moving:: Moving about the line. +* Commands For History:: Getting at previous lines. +* Commands For Text:: Commands for changing text. +* Commands For Killing:: Commands for killing and yanking. +* Numeric Arguments:: Specifying numeric arguments, repeat counts. +* Commands For Completion:: Getting Readline to do the typing for you. +* Keyboard Macros:: Saving and re-executing typed characters +* Miscellaneous Commands:: Other miscellaneous commands. +@end menu + +This section describes Readline commands that may be bound to key +sequences. +@ifset BashFeatures +You can list your key bindings by executing +@w{@code{bind -P}} or, for a more terse format, suitable for an +@var{inputrc} file, @w{@code{bind -p}}. (@xref{Bash Builtins}.) +@end ifset +Command names without an accompanying key sequence are unbound by default. + +In the following descriptions, @dfn{point} refers to the current cursor +position, and @dfn{mark} refers to a cursor position saved by the +@code{set-mark} command. +The text between the point and mark is referred to as the @dfn{region}. + +@node Commands For Moving +@subsection Commands For Moving +@ftable @code +@item beginning-of-line (C-a) +Move to the start of the current line. + +@item end-of-line (C-e) +Move to the end of the line. + +@item forward-char (C-f) +Move forward a character. + +@item backward-char (C-b) +Move back a character. + +@item forward-word (M-f) +Move forward to the end of the next word. +Words are composed of letters and digits. + +@item backward-word (M-b) +Move back to the start of the current or previous word. +Words are composed of letters and digits. + +@ifset BashFeatures +@item shell-forward-word () +Move forward to the end of the next word. +Words are delimited by non-quoted shell metacharacters. + +@item shell-backward-word () +Move back to the start of the current or previous word. +Words are delimited by non-quoted shell metacharacters. +@end ifset + +@item clear-screen (C-l) +Clear the screen and redraw the current line, +leaving the current line at the top of the screen. + +@item redraw-current-line () +Refresh the current line. By default, this is unbound. + +@end ftable + +@node Commands For History +@subsection Commands For Manipulating The History + +@ftable @code +@item accept-line (Newline or Return) +@ifset BashFeatures +Accept the line regardless of where the cursor is. +If this line is +non-empty, add it to the history list according to the setting of +the @env{HISTCONTROL} and @env{HISTIGNORE} variables. +If this line is a modified history line, then restore the history line +to its original state. +@end ifset +@ifclear BashFeatures +Accept the line regardless of where the cursor is. +If this line is +non-empty, it may be added to the history list for future recall with +@code{add_history()}. +If this line is a modified history line, the history line is restored +to its original state. +@end ifclear + +@item previous-history (C-p) +Move `back' through the history list, fetching the previous command. + +@item next-history (C-n) +Move `forward' through the history list, fetching the next command. + +@item beginning-of-history (M-<) +Move to the first line in the history. + +@item end-of-history (M->) +Move to the end of the input history, i.e., the line currently +being entered. + +@item 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. + +@item 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. + +@item non-incremental-reverse-search-history (M-p) +Search backward starting at the current line and moving `up' +through the history as necessary using a non-incremental search +for a string supplied by the user. +The search string may match anywhere in a history line. + +@item non-incremental-forward-search-history (M-n) +Search forward starting at the current line and moving `down' +through the history as necessary using a non-incremental search +for a string supplied by the user. +The search string may match anywhere in a history line. + +@item history-search-forward () +Search forward through the history for the string of characters +between the start of the current line and the point. +The search string must match at the beginning of a history line. +This is a non-incremental search. +By default, this command is unbound. + +@item history-search-backward () +Search backward through the history for the string of characters +between the start of the current line and the point. +The search string must match at the beginning of a history line. +This is a non-incremental search. +By default, this command is unbound. + +@item history-substr-search-forward () +Search forward through the history for the string of characters +between the start of the current line and the point. +The search string may match anywhere in a history line. +This is a non-incremental search. +By default, this command is unbound. + +@item history-substr-search-backward () +Search backward through the history for the string of characters +between the start of the current line and the point. +The search string may match anywhere in a history line. +This is a non-incremental search. +By default, this command is unbound. + +@item 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 @var{n}, +insert the @var{n}th word from the previous command (the words +in the previous command begin with word 0). A negative argument +inserts the @var{n}th word from the end of the previous command. +Once the argument @var{n} is computed, the argument is extracted +as if the @samp{!@var{n}} history expansion had been specified. + +@item yank-last-arg (M-. or M-_) +Insert last argument to the previous command (the last word of the +previous history entry). +With a numeric argument, behave exactly like @code{yank-nth-arg}. +Successive calls to @code{yank-last-arg} 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 @samp{!$} history expansion had been specified. + +@end ftable + +@node Commands For Text +@subsection Commands For Changing Text + +@ftable @code + +@item @i{end-of-file} (usually C-d) +The character indicating end-of-file as set, for example, by +@code{stty}. If this character is read when there are no characters +on the line, and point is at the beginning of the line, Readline +interprets it as the end of input and returns @sc{eof}. + +@item delete-char (C-d) +Delete the character at point. If this function is bound to the +same character as the tty @sc{eof} character, as @kbd{C-d} +commonly is, see above for the effects. + +@item backward-delete-char (Rubout) +Delete the character behind the cursor. A numeric argument means +to kill the characters instead of deleting them. + +@item 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. By default, this is not bound to a key. + +@item quoted-insert (C-q or C-v) +Add the next character typed to the line verbatim. This is +how to insert key sequences like @kbd{C-q}, for example. + +@ifclear BashFeatures +@item tab-insert (M-@key{TAB}) +Insert a tab character. +@end ifclear + +@item self-insert (a, b, A, 1, !, @dots{}) +Insert yourself. + +@item bracketed-paste-begin () +This function is intended to be bound to the "bracketed paste" escape +sequence sent by some terminals, and such a binding is assigned by default. +It allows Readline to insert the pasted text as a single unit without treating +each character as if it had been read from the keyboard. The characters +are inserted as if each one was bound to @code{self-insert}) instead of +executing any editing commands. + +@item transpose-chars (C-t) +Drag the character before the cursor forward over +the character at the cursor, moving the +cursor forward as well. If the insertion point +is at the end of the line, then this +transposes the last two characters of the line. +Negative arguments have no effect. + +@item transpose-words (M-t) +Drag the word before point past the word after point, +moving point past that word as well. +If the insertion point is at the end of the line, this transposes +the last two words on the line. + +@item upcase-word (M-u) +Uppercase the current (or following) word. With a negative argument, +uppercase the previous word, but do not move the cursor. + +@item downcase-word (M-l) +Lowercase the current (or following) word. With a negative argument, +lowercase the previous word, but do not move the cursor. + +@item capitalize-word (M-c) +Capitalize the current (or following) word. With a negative argument, +capitalize the previous word, but do not move the cursor. + +@item 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 +@code{emacs} mode; @code{vi} mode does overwrite differently. +Each call to @code{readline()} starts in insert mode. + +In overwrite mode, characters bound to @code{self-insert} replace +the text at point rather than pushing the text to the right. +Characters bound to @code{backward-delete-char} replace the character +before point with a space. + +By default, this command is unbound. + +@end ftable + +@node Commands For Killing +@subsection Killing And Yanking + +@ftable @code + +@item kill-line (C-k) +Kill the text from point to the end of the line. + +@item backward-kill-line (C-x Rubout) +Kill backward from the cursor to the beginning of the current line. + +@item unix-line-discard (C-u) +Kill backward from the cursor to the beginning of the current line. + +@item kill-whole-line () +Kill all characters on the current line, no matter where point is. +By default, this is unbound. + +@item 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 @code{forward-word}. + +@item backward-kill-word (M-@key{DEL}) +Kill the word behind point. +Word boundaries are the same as @code{backward-word}. + +@ifset BashFeatures +@item shell-kill-word () +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 @code{shell-forward-word}. + +@item shell-backward-kill-word () +Kill the word behind point. +Word boundaries are the same as @code{shell-backward-word}. +@end ifset + +@item 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. + +@item 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. + +@item delete-horizontal-space () +Delete all spaces and tabs around point. By default, this is unbound. + +@item kill-region () +Kill the text in the current region. +By default, this command is unbound. + +@item copy-region-as-kill () +Copy the text in the region to the kill buffer, so it can be yanked +right away. By default, this command is unbound. + +@item copy-backward-word () +Copy the word before point to the kill buffer. +The word boundaries are the same as @code{backward-word}. +By default, this command is unbound. + +@item copy-forward-word () +Copy the word following point to the kill buffer. +The word boundaries are the same as @code{forward-word}. +By default, this command is unbound. + +@item yank (C-y) +Yank the top of the kill ring into the buffer at point. + +@item yank-pop (M-y) +Rotate the kill-ring, and yank the new top. You can only do this if +the prior command is @code{yank} or @code{yank-pop}. +@end ftable + +@node Numeric Arguments +@subsection Specifying Numeric Arguments +@ftable @code + +@item digit-argument (@kbd{M-0}, @kbd{M-1}, @dots{} @kbd{M--}) +Add this digit to the argument already accumulating, or start a new +argument. @kbd{M--} starts a negative argument. + +@item 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 @code{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 nor 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. +By default, this is not bound to a key. +@end ftable + +@node Commands For Completion +@subsection Letting Readline Type For You + +@ftable @code +@item complete (@key{TAB}) +Attempt to perform completion on the text before point. +The actual completion performed is application-specific. +@ifset BashFeatures +Bash attempts completion treating the text as a variable (if the +text begins with @samp{$}), username (if the text begins with +@samp{~}), hostname (if the text begins with @samp{@@}), or +command (including aliases and functions) in turn. If none +of these produces a match, filename completion is attempted. +@end ifset +@ifclear BashFeatures +The default is filename completion. +@end ifclear + +@item possible-completions (M-?) +List the possible completions of the text before point. +When displaying completions, Readline sets the number of columns used +for display to the value of @code{completion-display-width}, the value of +the environment variable @env{COLUMNS}, or the screen width, in that order. + +@item insert-completions (M-*) +Insert all completions of the text before point that would have +been generated by @code{possible-completions}. + +@item menu-complete () +Similar to @code{complete}, but replaces the word to be completed +with a single match from the list of possible completions. +Repeated execution of @code{menu-complete} 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 @code{bell-style}) +and the original text is restored. +An argument of @var{n} moves @var{n} 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 @key{TAB}, but is unbound +by default. + +@item menu-complete-backward () +Identical to @code{menu-complete}, but moves backward through the list +of possible completions, as if @code{menu-complete} had been given a +negative argument. + +@item delete-char-or-list () +Deletes the character under the cursor if not at the beginning or +end of the line (like @code{delete-char}). +If at the end of the line, behaves identically to +@code{possible-completions}. +This command is unbound by default. + +@ifset BashFeatures +@item complete-filename (M-/) +Attempt filename completion on the text before point. + +@item possible-filename-completions (C-x /) +List the possible completions of the text before point, +treating it as a filename. + +@item complete-username (M-~) +Attempt completion on the text before point, treating +it as a username. + +@item possible-username-completions (C-x ~) +List the possible completions of the text before point, +treating it as a username. + +@item complete-variable (M-$) +Attempt completion on the text before point, treating +it as a shell variable. + +@item possible-variable-completions (C-x $) +List the possible completions of the text before point, +treating it as a shell variable. + +@item complete-hostname (M-@@) +Attempt completion on the text before point, treating +it as a hostname. + +@item possible-hostname-completions (C-x @@) +List the possible completions of the text before point, +treating it as a hostname. + +@item 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. + +@item possible-command-completions (C-x !) +List the possible completions of the text before point, +treating it as a command name. + +@item dynamic-complete-history (M-@key{TAB}) +Attempt completion on the text before point, comparing +the text against lines from the history list for possible +completion matches. + +@item dabbrev-expand () +Attempt menu completion on the text before point, comparing +the text against lines from the history list for possible +completion matches. + +@item 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 +(@pxref{Brace Expansion}). + +@end ifset +@end ftable + +@node Keyboard Macros +@subsection Keyboard Macros +@ftable @code + +@item start-kbd-macro (C-x () +Begin saving the characters typed into the current keyboard macro. + +@item end-kbd-macro (C-x )) +Stop saving the characters typed into the current keyboard macro +and save the definition. + +@item 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. + +@item print-last-kbd-macro () +Print the last keboard macro defined in a format suitable for the +@var{inputrc} file. + +@end ftable + +@node Miscellaneous Commands +@subsection Some Miscellaneous Commands +@ftable @code + +@item re-read-init-file (C-x C-r) +Read in the contents of the @var{inputrc} file, and incorporate +any bindings or variable assignments found there. + +@item abort (C-g) +Abort the current editing command and +ring the terminal's bell (subject to the setting of +@code{bell-style}). + +@item do-uppercase-version (M-a, M-b, M-@var{x}, @dots{}) +If the metafied character @var{x} is lowercase, run the command +that is bound to the corresponding uppercase character. + +@item prefix-meta (@key{ESC}) +Metafy the next character typed. This is for keyboards +without a meta key. Typing @samp{@key{ESC} f} is equivalent to typing +@kbd{M-f}. + +@item undo (C-_ or C-x C-u) +Incremental undo, separately remembered for each line. + +@item revert-line (M-r) +Undo all changes made to this line. This is like executing the @code{undo} +command enough times to get back to the beginning. + +@ifset BashFeatures +@item tilde-expand (M-&) +@end ifset +@ifclear BashFeatures +@item tilde-expand (M-~) +@end ifclear +Perform tilde expansion on the current word. + +@item set-mark (C-@@) +Set the mark to the point. If a +numeric argument is supplied, the mark is set to that position. + +@item 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. + +@item 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. + +@item 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. + +@item 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-[. + +@item insert-comment (M-#) +Without a numeric argument, the value of the @code{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 @code{comment-begin}, the value is inserted, otherwise +the characters in @code{comment-begin} are deleted from the beginning of +the line. +In either case, the line is accepted as if a newline had been typed. +@ifset BashFeatures +The default value of @code{comment-begin} 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. +@end ifset + +@item 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 @var{inputrc} file. This command is unbound by default. + +@item dump-variables () +Print all of the settable 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 @var{inputrc} file. This command is unbound by default. + +@item 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 @var{inputrc} file. This command is unbound by default. + +@ifset BashFeatures +@item 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 file names for possible completions. + +@item glob-expand-word (C-x *) +The word before point is treated as a pattern for pathname expansion, +and the list of matching file names is inserted, replacing the word. +If a numeric argument is supplied, a @samp{*} is appended before +pathname expansion. + +@item glob-list-expansions (C-x g) +The list of expansions that would have been generated by +@code{glob-expand-word} is displayed, and the line is redrawn. +If a numeric argument is supplied, a @samp{*} is appended before +pathname expansion. + +@item display-shell-version (C-x C-v) +Display version information about the current instance of Bash. + +@item 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 (@pxref{Shell Expansions}). + +@item history-expand-line (M-^) +Perform history expansion on the current line. + +@item magic-space () +Perform history expansion on the current line and insert a space +(@pxref{History Interaction}). + +@item alias-expand-line () +Perform alias expansion on the current line (@pxref{Aliases}). + +@item history-and-alias-expand-line () +Perform history and alias expansion on the current line. + +@item insert-last-argument (M-. or M-_) +A synonym for @code{yank-last-arg}. + +@item 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. + +@item edit-and-execute-command (C-xC-e) +Invoke an editor on the current command line, and execute the result as shell +commands. +Bash attempts to invoke +@code{$VISUAL}, @code{$EDITOR}, and @code{emacs} +as the editor, in that order. + +@end ifset + +@ifclear BashFeatures +@item emacs-editing-mode (C-e) +When in @code{vi} command mode, this causes a switch to @code{emacs} +editing mode. + +@item vi-editing-mode (M-C-j) +When in @code{emacs} editing mode, this causes a switch to @code{vi} +editing mode. + +@end ifclear + +@end ftable + +@node Readline vi Mode +@section Readline vi Mode + +While the Readline library does not have a full set of @code{vi} +editing functions, it does contain enough to allow simple editing +of the line. The Readline @code{vi} mode behaves as specified in +the @sc{posix} standard. + +@ifset BashFeatures +In order to switch interactively between @code{emacs} and @code{vi} +editing modes, use the @samp{set -o emacs} and @samp{set -o vi} +commands (@pxref{The Set Builtin}). +@end ifset +@ifclear BashFeatures +In order to switch interactively between @code{emacs} and @code{vi} +editing modes, use the command @kbd{M-C-j} (bound to emacs-editing-mode +when in @code{vi} mode and to vi-editing-mode in @code{emacs} mode). +@end ifclear +The Readline default is @code{emacs} mode. + +When you enter a line in @code{vi} mode, you are already placed in +`insertion' mode, as if you had typed an @samp{i}. Pressing @key{ESC} +switches you into `command' mode, where you can edit the text of the +line with the standard @code{vi} movement keys, move to previous +history lines with @samp{k} and subsequent lines with @samp{j}, and +so forth. + +@ifset BashFeatures +@node Programmable Completion +@section Programmable Completion +@cindex programmable completion + +When word completion is attempted for an argument to a command for +which a completion specification (a @var{compspec}) has been defined +using the @code{complete} builtin (@pxref{Programmable Completion Builtins}), +the programmable completion facilities are invoked. + +First, the command name is identified. +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 the empty string (completion attempted at the +beginning of an empty line), any compspec defined with +the @option{-E} option to @code{complete} is used. +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 @option{-D} option to @code{complete} is used as the default. + +Once a compspec has been found, it is used to generate the list of +matching words. +If a compspec is not found, the default Bash completion +described above (@pxref{Commands For Completion}) is performed. + +First, the actions specified by the compspec are used. +Only matches which are prefixed by the word being completed are +returned. +When the @option{-f} or @option{-d} option is used for filename or +directory name completion, the shell variable @env{FIGNORE} is +used to filter the matches. +@xref{Bash Variables}, for a description of @env{FIGNORE}. + +Any completions specified by a filename expansion pattern to the +@option{-G} option are generated next. +The words generated by the pattern need not match the word being completed. +The @env{GLOBIGNORE} shell variable is not used to filter the matches, +but the @env{FIGNORE} shell variable is used. + +Next, the string specified as the argument to the @option{-W} option +is considered. +The string is first split using the characters in the @env{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 (@pxref{Shell Expansions}). +The results are split using the rules described above +(@pxref{Word Splitting}). +The results of the expansion are prefix-matched against the word being +completed, and the matching words become the possible completions. + +After these matches have been generated, any shell function or command +specified with the @option{-F} and @option{-C} options is invoked. +When the command or function is invoked, the @env{COMP_LINE}, +@env{COMP_POINT}, @env{COMP_KEY}, and @env{COMP_TYPE} variables are +assigned values as described above (@pxref{Bash Variables}). +If a shell function is being invoked, the @env{COMP_WORDS} and +@env{COMP_CWORD} variables are also set. +When the function or command is invoked, the first argument ($1) is the +name of the command whose arguments are being completed, the +second argument ($2) is the word being completed, and the third argument +($3) 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. + +Any function specified with @option{-F} is invoked first. +The function may use any of the shell facilities, including the +@code{compgen} and @code{compopt} builtins described below +(@pxref{Programmable Completion Builtins}), to generate the matches. +It must put the possible completions in the @env{COMPREPLY} array +variable, one per array element. + +Next, any command specified with the @option{-C} 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. + +After all of the possible completions are generated, any filter +specified with the @option{-X} option is applied to the list. +The filter is a pattern as used for pathname expansion; a @samp{&} +in the pattern is replaced with the text of the word being completed. +A literal @samp{&} 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 @samp{!} negates the pattern; in this case any completion +not matching the pattern will be removed. +If the @code{nocasematch} shell option +(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. + +Finally, any prefix and suffix specified with the @option{-P} and @option{-S} +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. + +If the previously-applied actions do not generate any matches, and the +@option{-o dirnames} option was supplied to @code{complete} when the +compspec was defined, directory name completion is attempted. + +If the @option{-o plusdirs} option was supplied to @code{complete} when +the compspec was defined, directory name completion is attempted and any +matches are added to the results of the other actions. + +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 Bash completions are not attempted, and the Readline default +of filename completion is disabled. +If the @option{-o bashdefault} option was supplied to @code{complete} when +the compspec was defined, the default Bash completions are attempted +if the compspec generates no matches. +If the @option{-o default} option was supplied to @code{complete} when the +compspec was defined, Readline's default completion will be performed +if the compspec (and, if attempted, the default Bash completions) +generate no matches. + +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 @var{mark-directories} Readline variable, regardless +of the setting of the @var{mark-symlinked-directories} Readline variable. + +There is some support for dynamically modifying completions. This is +most useful when used in combination with a default completion specified +with @option{-D}. 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. + +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: + +@example +_completion_loader() +@{ + . "/etc/bash_completion.d/$1.sh" >/dev/null 2>&1 && return 124 +@} +complete -D -F _completion_loader -o bashdefault -o default +@end example + +@node Programmable Completion Builtins +@section Programmable Completion Builtins +@cindex completion builtins + +Three builtin commands are available to manipulate the programmable completion +facilities: one to specify how the arguments to a particular command are to +be completed, and two to modify the completion as it is happening. + +@table @code +@item compgen +@btindex compgen +@example +@code{compgen [@var{option}] [@var{word}]} +@end example + +Generate possible completion matches for @var{word} according to +the @var{option}s, which may be any option accepted by the +@code{complete} +builtin with the exception of @option{-p} and @option{-r}, and write +the matches to the standard output. +When using the @option{-F} or @option{-C} options, the various shell variables +set by the programmable completion facilities, while available, will not +have useful values. + +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 @var{word} is specified, only those completions matching @var{word} +will be displayed. + +The return value is true unless an invalid option is supplied, or no +matches were generated. + +@item complete +@btindex complete +@example +@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-DE] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}] +[-F @var{function}] [-C @var{command}] [-X @var{filterpat}] +[-P @var{prefix}] [-S @var{suffix}] @var{name} [@var{name} @dots{}]} +@code{complete -pr [-DE] [@var{name} @dots{}]} +@end example + +Specify how arguments to each @var{name} should be completed. +If the @option{-p} 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 @option{-r} option removes a completion specification for +each @var{name}, or, if no @var{name}s are supplied, all +completion specifications. +The @option{-D} 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 @option{-E} option indicates that the remaining options and actions should +apply to ``empty'' command completion; that is, completion attempted on a +blank line. + +The process of applying these completion specifications when word completion +is attempted is described above (@pxref{Programmable Completion}). The +@option{-D} option takes precedence over @option{-E}. + +Other options, if specified, have the following meanings. +The arguments to the @option{-G}, @option{-W}, and @option{-X} options +(and, if necessary, the @option{-P} and @option{-S} options) +should be quoted to protect them from expansion before the +@code{complete} builtin is invoked. + + +@table @code +@item -o @var{comp-option} +The @var{comp-option} controls several aspects of the compspec's behavior +beyond the simple generation of completions. +@var{comp-option} may be one of: + +@table @code + +@item bashdefault +Perform the rest of the default Bash completions if the compspec +generates no matches. + +@item default +Use Readline's default filename completion if the compspec generates +no matches. + +@item dirnames +Perform directory name completion if the compspec generates no matches. + +@item 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). +This option is intended to be used with shell functions specified +with @option{-F}. + +@item noquote +Tell Readline not to quote the completed words if they are filenames +(quoting filenames is the default). + +@item nospace +Tell Readline not to append a space (the default) to words completed at +the end of the line. + +@item 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. + +@end table + +@item -A @var{action} +The @var{action} may be one of the following to generate a list of possible +completions: + +@table @code +@item alias +Alias names. May also be specified as @option{-a}. + +@item arrayvar +Array variable names. + +@item binding +Readline key binding names (@pxref{Bindable Readline Commands}). + +@item builtin +Names of shell builtin commands. May also be specified as @option{-b}. + +@item command +Command names. May also be specified as @option{-c}. + +@item directory +Directory names. May also be specified as @option{-d}. + +@item disabled +Names of disabled shell builtins. + +@item enabled +Names of enabled shell builtins. + +@item export +Names of exported shell variables. May also be specified as @option{-e}. + +@item file +File names. May also be specified as @option{-f}. + +@item function +Names of shell functions. + +@item group +Group names. May also be specified as @option{-g}. + +@item helptopic +Help topics as accepted by the @code{help} builtin (@pxref{Bash Builtins}). + +@item hostname +Hostnames, as taken from the file specified by the +@env{HOSTFILE} shell variable (@pxref{Bash Variables}). + +@item job +Job names, if job control is active. May also be specified as @option{-j}. + +@item keyword +Shell reserved words. May also be specified as @option{-k}. + +@item running +Names of running jobs, if job control is active. + +@item service +Service names. May also be specified as @option{-s}. + +@item setopt +Valid arguments for the @option{-o} option to the @code{set} builtin +(@pxref{The Set Builtin}). + +@item shopt +Shell option names as accepted by the @code{shopt} builtin +(@pxref{Bash Builtins}). + +@item signal +Signal names. + +@item stopped +Names of stopped jobs, if job control is active. + +@item user +User names. May also be specified as @option{-u}. + +@item variable +Names of all shell variables. May also be specified as @option{-v}. +@end table + +@item -C @var{command} +@var{command} is executed in a subshell environment, and its output is +used as the possible completions. + +@item -F @var{function} +The shell function @var{function} is executed in the current shell +environment. +When it is executed, $1 is the name of the command whose arguments are +being completed, $2 is the word being completed, and $3 is the word +preceding the word being completed, as described above +(@pxref{Programmable Completion}). +When it finishes, the possible completions are retrieved from the value +of the @env{COMPREPLY} array variable. + +@item -G @var{globpat} +The filename expansion pattern @var{globpat} is expanded to generate +the possible completions. + +@item -P @var{prefix} +@var{prefix} is added at the beginning of each possible completion +after all other options have been applied. + +@item -S @var{suffix} +@var{suffix} is appended to each possible completion +after all other options have been applied. + +@item -W @var{wordlist} +The @var{wordlist} is split using the characters in the +@env{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. + +@item -X @var{filterpat} +@var{filterpat} is a pattern as used for filename expansion. +It is applied to the list of possible completions generated by the +preceding options and arguments, and each completion matching +@var{filterpat} is removed from the list. +A leading @samp{!} in @var{filterpat} negates the pattern; in this +case, any completion not matching @var{filterpat} is removed. +@end table + +The return value is true unless an invalid option is supplied, an option +other than @option{-p} or @option{-r} is supplied without a @var{name} +argument, an attempt is made to remove a completion specification for +a @var{name} for which no specification exists, or +an error occurs adding a completion specification. + +@item compopt +@btindex compopt +@example +@code{compopt} [-o @var{option}] [-DE] [+o @var{option}] [@var{name}] +@end example +Modify completion options for each @var{name} according to the +@var{option}s, or for the currently-executing completion if no @var{name}s +are supplied. +If no @var{option}s are given, display the completion options for each +@var{name} or the current completion. +The possible values of @var{option} are those valid for the @code{complete} +builtin described above. +The @option{-D} 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 @option{-E} option indicates that the remaining options should +apply to ``empty'' command completion; that is, completion attempted on a +blank line. + +The @option{-D} option takes precedence over @option{-E}. + +The return value is true unless an invalid option is supplied, an attempt +is made to modify the options for a @var{name} for which no completion +specification exists, or an output error occurs. + +@end table + +@node A Programmable Completion Example +@section A Programmable Completion Example + +The most common way to obtain additional completion functionality beyond +the default actions @code{complete} and @code{compgen} provide is to use +a shell function and bind it to a particular command using @code{complete -F}. + +The following function provides completions for the @code{cd} builtin. +It is a reasonably good example of what shell functions must do when +used for completion. This function uses the word passsed as @code{$2} +to determine the directory name to complete. You can also use the +@code{COMP_WORDS} array variable; the current word is indexed by the +@code{COMP_CWORD} variable. + +The function relies on the @code{complete} and @code{compgen} builtins +to do much of the work, adding only the things that the Bash @code{cd} +does beyond accepting basic directory names: +tilde expansion (@pxref{Tilde Expansion}), +searching directories in @var{$CDPATH}, which is described above +(@pxref{Bourne Shell Builtins}), +and basic support for the @code{cdable_vars} shell option +(@pxref{The Shopt Builtin}). +@code{_comp_cd} modifies the value of @var{IFS} so that it contains only +a newline to accommodate file names containing spaces and tabs -- +@code{compgen} prints the possible completions it generates one per line. + +Possible completions go into the @var{COMPREPLY} array variable, one +completion per array element. The programmable completion system retrieves +the completions from there when the function returns. + +@example +# A completion function for the cd builtin +# based on the cd completion function from the bash_completion package +_comp_cd() +@{ + local IFS=$' \t\n' # normalize IFS + local cur _skipdot _cdpath + local i j k + + # Tilde expansion, with side effect of expanding tilde to full pathname + case "$2" in + \~*) eval cur="$2" ;; + *) cur=$2 ;; + esac + + # no cdpath or absolute pathname -- straight directory completion + if [[ -z "$@{CDPATH:-@}" ]] || [[ "$cur" == @@(./*|../*|/*) ]]; then + # compgen prints paths one per line; could also use while loop + IFS=$'\n' + COMPREPLY=( $(compgen -d -- "$cur") ) + IFS=$' \t\n' + # CDPATH+directories in the current directory if not in CDPATH + else + IFS=$'\n' + _skipdot=false + # preprocess CDPATH to convert null directory names to . + _cdpath=$@{CDPATH/#:/.:@} + _cdpath=$@{_cdpath//::/:.:@} + _cdpath=$@{_cdpath/%:/:.@} + for i in $@{_cdpath//:/$'\n'@}; do + if [[ $i -ef . ]]; then _skipdot=true; fi + k="$@{#COMPREPLY[@@]@}" + for j in $( compgen -d -- "$i/$cur" ); do + COMPREPLY[k++]=$@{j#$i/@} # cut off directory + done + done + $_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") ) + IFS=$' \t\n' + fi + + # variable names if appropriate shell option set and no completions + if shopt -q cdable_vars && [[ $@{#COMPREPLY[@@]@} -eq 0 ]]; then + COMPREPLY=( $(compgen -v -- "$cur") ) + fi + + return 0 +@} +@end example + +We install the completion function using the @option{-F} option to +@code{complete}: + +@example +# Tell readline to quote appropriate and append slashes to directories; +# use the bash default completion for other arguments +complete -o filenames -o nospace -o bashdefault -F _comp_cd cd +@end example + +@noindent +Since we'd like Bash and Readline to take care of some +of the other details for us, we use several other options to tell Bash +and Readline what to do. The @option{-o filenames} option tells Readline +that the possible completions should be treated as filenames, and quoted +appropriately. That option will also cause Readline to append a slash to +filenames it can determine are directories (which is why we might want to +extend @code{_comp_cd} to append a slash if we're using directories found +via @var{CDPATH}: Readline can't tell those completions are directories). +The @option{-o nospace} option tells Readline to not append a space +character to the directory name, in case we want to append to it. +The @option{-o bashdefault} option brings in the rest of the "Bash default" +completions -- possible completion that Bash adds to the default Readline +set. These include things like command name completion, variable completion +for words beginning with @samp{@{}, completions containing pathname +expansion patterns (@pxref{Filename Expansion}), and so on. + +Once installed using @code{complete}, @code{_comp_cd} will be called every +time we attempt word completion for a @code{cd} command. + +Many more examples -- an extensive collection of completions for most of +the common GNU, Unix, and Linux commands -- are available as part of the +bash_completion project. This is installed by default on many GNU/Linux +distributions. Originally written by Ian Macdonald, the project now lives +at @url{http://bash-completion.alioth.debian.org/}. There are ports for +other systems such as Solaris and Mac OS X. + +An older version of the bash_completion package is distributed with bash +in the @file{examples/complete} subdirectory. + +@end ifset diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c index 7e04b67da..64b0e411a 100644 --- a/lib/readline/funmap.c +++ b/lib/readline/funmap.c @@ -195,6 +195,7 @@ static const FUNMAP default_funmap[] = { { "vi-subst", rl_vi_subst }, { "vi-tilde-expand", rl_vi_tilde_expand }, { "vi-yank-arg", rl_vi_yank_arg }, + { "vi-yank-pop", rl_vi_yank_pop }, { "vi-yank-to", rl_vi_yank_to }, #endif /* VI_MODE */ diff --git a/lib/readline/funmap.c~ b/lib/readline/funmap.c~ new file mode 100644 index 000000000..7e04b67da --- /dev/null +++ b/lib/readline/funmap.c~ @@ -0,0 +1,267 @@ +/* funmap.c -- attach names to functions. */ + +/* Copyright (C) 1987-2010 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 + +#if !defined (BUFSIZ) +#include +#endif /* BUFSIZ */ + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "rlconf.h" +#include "readline.h" + +#include "xmalloc.h" + +#ifdef __STDC__ +typedef int QSFUNC (const void *, const void *); +#else +typedef int QSFUNC (); +#endif + +extern int _rl_qsort_string_compare PARAMS((char **, char **)); + +FUNMAP **funmap; +static int funmap_size; +static int funmap_entry; + +/* After initializing the function map, this is the index of the first + program specific function. */ +int funmap_program_specific_entry_start; + +static const FUNMAP default_funmap[] = { + { "abort", rl_abort }, + { "accept-line", rl_newline }, + { "arrow-key-prefix", rl_arrow_keys }, + { "backward-byte", rl_backward_byte }, + { "backward-char", rl_backward_char }, + { "backward-delete-char", rl_rubout }, + { "backward-kill-line", rl_backward_kill_line }, + { "backward-kill-word", rl_backward_kill_word }, + { "backward-word", rl_backward_word }, + { "beginning-of-history", rl_beginning_of_history }, + { "beginning-of-line", rl_beg_of_line }, + { "bracketed-paste-begin", rl_bracketed_paste_begin }, + { "call-last-kbd-macro", rl_call_last_kbd_macro }, + { "capitalize-word", rl_capitalize_word }, + { "character-search", rl_char_search }, + { "character-search-backward", rl_backward_char_search }, + { "clear-screen", rl_clear_screen }, + { "complete", rl_complete }, + { "copy-backward-word", rl_copy_backward_word }, + { "copy-forward-word", rl_copy_forward_word }, + { "copy-region-as-kill", rl_copy_region_to_kill }, + { "delete-char", rl_delete }, + { "delete-char-or-list", rl_delete_or_show_completions }, + { "delete-horizontal-space", rl_delete_horizontal_space }, + { "digit-argument", rl_digit_argument }, + { "do-lowercase-version", rl_do_lowercase_version }, + { "downcase-word", rl_downcase_word }, + { "dump-functions", rl_dump_functions }, + { "dump-macros", rl_dump_macros }, + { "dump-variables", rl_dump_variables }, + { "emacs-editing-mode", rl_emacs_editing_mode }, + { "end-kbd-macro", rl_end_kbd_macro }, + { "end-of-history", rl_end_of_history }, + { "end-of-line", rl_end_of_line }, + { "exchange-point-and-mark", rl_exchange_point_and_mark }, + { "forward-backward-delete-char", rl_rubout_or_delete }, + { "forward-byte", rl_forward_byte }, + { "forward-char", rl_forward_char }, + { "forward-search-history", rl_forward_search_history }, + { "forward-word", rl_forward_word }, + { "history-search-backward", rl_history_search_backward }, + { "history-search-forward", rl_history_search_forward }, + { "history-substring-search-backward", rl_history_substr_search_backward }, + { "history-substring-search-forward", rl_history_substr_search_forward }, + { "insert-comment", rl_insert_comment }, + { "insert-completions", rl_insert_completions }, + { "kill-whole-line", rl_kill_full_line }, + { "kill-line", rl_kill_line }, + { "kill-region", rl_kill_region }, + { "kill-word", rl_kill_word }, + { "menu-complete", rl_menu_complete }, + { "menu-complete-backward", rl_backward_menu_complete }, + { "next-history", rl_get_next_history }, + { "non-incremental-forward-search-history", rl_noninc_forward_search }, + { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, + { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again }, + { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again }, + { "old-menu-complete", rl_old_menu_complete }, + { "overwrite-mode", rl_overwrite_mode }, +#if defined (_WIN32) + { "paste-from-clipboard", rl_paste_from_clipboard }, +#endif + { "possible-completions", rl_possible_completions }, + { "previous-history", rl_get_previous_history }, + { "print-last-kbd-macro", rl_print_last_kbd_macro }, + { "quoted-insert", rl_quoted_insert }, + { "re-read-init-file", rl_re_read_init_file }, + { "redraw-current-line", rl_refresh_line}, + { "reverse-search-history", rl_reverse_search_history }, + { "revert-line", rl_revert_line }, + { "self-insert", rl_insert }, + { "set-mark", rl_set_mark }, + { "skip-csi-sequence", rl_skip_csi_sequence }, + { "start-kbd-macro", rl_start_kbd_macro }, + { "tab-insert", rl_tab_insert }, + { "tilde-expand", rl_tilde_expand }, + { "transpose-chars", rl_transpose_chars }, + { "transpose-words", rl_transpose_words }, + { "tty-status", rl_tty_status }, + { "undo", rl_undo_command }, + { "universal-argument", rl_universal_argument }, + { "unix-filename-rubout", rl_unix_filename_rubout }, + { "unix-line-discard", rl_unix_line_discard }, + { "unix-word-rubout", rl_unix_word_rubout }, + { "upcase-word", rl_upcase_word }, + { "yank", rl_yank }, + { "yank-last-arg", rl_yank_last_arg }, + { "yank-nth-arg", rl_yank_nth_arg }, + { "yank-pop", rl_yank_pop }, + +#if defined (VI_MODE) + { "vi-append-eol", rl_vi_append_eol }, + { "vi-append-mode", rl_vi_append_mode }, + { "vi-arg-digit", rl_vi_arg_digit }, + { "vi-back-to-indent", rl_vi_back_to_indent }, + { "vi-backward-bigword", rl_vi_bWord }, + { "vi-backward-word", rl_vi_bword }, + { "vi-bWord", rl_vi_bWord }, + { "vi-bword", rl_vi_bword }, + { "vi-change-case", rl_vi_change_case }, + { "vi-change-char", rl_vi_change_char }, + { "vi-change-to", rl_vi_change_to }, + { "vi-char-search", rl_vi_char_search }, + { "vi-column", rl_vi_column }, + { "vi-complete", rl_vi_complete }, + { "vi-delete", rl_vi_delete }, + { "vi-delete-to", rl_vi_delete_to }, + { "vi-eWord", rl_vi_eWord }, + { "vi-editing-mode", rl_vi_editing_mode }, + { "vi-end-bigword", rl_vi_eWord }, + { "vi-end-word", rl_vi_end_word }, + { "vi-eof-maybe", rl_vi_eof_maybe }, + { "vi-eword", rl_vi_eword }, + { "vi-fWord", rl_vi_fWord }, + { "vi-fetch-history", rl_vi_fetch_history }, + { "vi-first-print", rl_vi_first_print }, + { "vi-forward-bigword", rl_vi_fWord }, + { "vi-forward-word", rl_vi_fword }, + { "vi-fword", rl_vi_fword }, + { "vi-goto-mark", rl_vi_goto_mark }, + { "vi-insert-beg", rl_vi_insert_beg }, + { "vi-insertion-mode", rl_vi_insertion_mode }, + { "vi-match", rl_vi_match }, + { "vi-movement-mode", rl_vi_movement_mode }, + { "vi-next-word", rl_vi_next_word }, + { "vi-overstrike", rl_vi_overstrike }, + { "vi-overstrike-delete", rl_vi_overstrike_delete }, + { "vi-prev-word", rl_vi_prev_word }, + { "vi-put", rl_vi_put }, + { "vi-redo", rl_vi_redo }, + { "vi-replace", rl_vi_replace }, + { "vi-rubout", rl_vi_rubout }, + { "vi-search", rl_vi_search }, + { "vi-search-again", rl_vi_search_again }, + { "vi-set-mark", rl_vi_set_mark }, + { "vi-subst", rl_vi_subst }, + { "vi-tilde-expand", rl_vi_tilde_expand }, + { "vi-yank-arg", rl_vi_yank_arg }, + { "vi-yank-to", rl_vi_yank_to }, +#endif /* VI_MODE */ + + {(char *)NULL, (rl_command_func_t *)NULL } +}; + +int +rl_add_funmap_entry (name, function) + const char *name; + rl_command_func_t *function; +{ + if (funmap_entry + 2 >= funmap_size) + { + funmap_size += 64; + funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *)); + } + + funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); + funmap[funmap_entry]->name = name; + funmap[funmap_entry]->function = function; + + funmap[++funmap_entry] = (FUNMAP *)NULL; + return funmap_entry; +} + +static int funmap_initialized; + +/* Make the funmap contain all of the default entries. */ +void +rl_initialize_funmap () +{ + register int i; + + if (funmap_initialized) + return; + + for (i = 0; default_funmap[i].name; i++) + rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); + + funmap_initialized = 1; + funmap_program_specific_entry_start = i; +} + +/* Produce a NULL terminated array of known function names. The array + is sorted. The array itself is allocated, but not the strings inside. + You should free () the array when you done, but not the pointers. */ +const char ** +rl_funmap_names () +{ + const char **result; + int result_size, result_index; + + /* Make sure that the function map has been initialized. */ + rl_initialize_funmap (); + + for (result_index = result_size = 0, result = (const char **)NULL; funmap[result_index]; result_index++) + { + if (result_index + 2 > result_size) + { + result_size += 20; + result = (const char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index] = funmap[result_index]->name; + result[result_index + 1] = (char *)NULL; + } + + qsort (result, result_index, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); + return (result); +} diff --git a/lib/readline/isearch.c b/lib/readline/isearch.c index 6f6a7a658..d768560bd 100644 --- a/lib/readline/isearch.c +++ b/lib/readline/isearch.c @@ -553,8 +553,16 @@ add_character: do until we have a real isearch-undo. */ if (cxt->search_string_index == 0) rl_ding (); - else + else if (MB_CUR_MAX == 1 || rl_byte_oriented) cxt->search_string[--cxt->search_string_index] = '\0'; + else + { + wstart = _rl_find_prev_mbchar (cxt->search_string, cxt->search_string_index, MB_FIND_NONZERO); + if (wstart >= 0) + cxt->search_string[cxt->search_string_index = wstart] = '\0'; + else + rl_ding (); + } break; case -4: /* C-G, abort */ diff --git a/lib/readline/kill.c b/lib/readline/kill.c index d4012da30..166302cfa 100644 --- a/lib/readline/kill.c +++ b/lib/readline/kill.c @@ -550,6 +550,40 @@ rl_yank_pop (count, key) } } +#if defined (VI_MODE) +int +rl_vi_yank_pop (count, key) + int count, key; +{ + int l, n; + + if (((rl_last_func != rl_vi_yank_pop) && (rl_last_func != rl_vi_put)) || + !rl_kill_ring) + { + _rl_abort_internal (); + return 1; + } + + l = strlen (rl_kill_ring[rl_kill_index]); + n = rl_point - l; + if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l)) + { + rl_delete_text (n, rl_point); + rl_point = n; + rl_kill_index--; + if (rl_kill_index < 0) + rl_kill_index = rl_kill_ring_length - 1; + rl_vi_put (1, 'p'); + return 0; + } + else + { + _rl_abort_internal (); + return 1; + } +} +#endif /* VI_MODE */ + /* Yank the COUNTh argument from the previous history line, skipping HISTORY_SKIP lines before looking for the `previous line'. */ static int diff --git a/lib/readline/kill.c~ b/lib/readline/kill.c~ new file mode 100644 index 000000000..d4012da30 --- /dev/null +++ b/lib/readline/kill.c~ @@ -0,0 +1,744 @@ +/* kill.c -- kill ring management. */ + +/* Copyright (C) 1994 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 + +#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 + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Killing Mechanism */ +/* */ +/* **************************************************************** */ + +/* What we assume for a max number of kills. */ +#define DEFAULT_MAX_KILLS 10 + +/* The real variable to look at to find out when to flush kills. */ +static int rl_max_kills = DEFAULT_MAX_KILLS; + +/* Where to store killed text. */ +static char **rl_kill_ring = (char **)NULL; + +/* Where we are in the kill ring. */ +static int rl_kill_index; + +/* How many slots we have in the kill ring. */ +static int rl_kill_ring_length; + +static int _rl_copy_to_kill_ring PARAMS((char *, int)); +static int region_kill_internal PARAMS((int)); +static int _rl_copy_word_as_kill PARAMS((int, int)); +static int rl_yank_nth_arg_internal PARAMS((int, int, int)); + +/* How to say that you only want to save a certain amount + of kill material. */ +int +rl_set_retained_kills (num) + int num; +{ + return 0; +} + +/* Add TEXT to the kill ring, allocating a new kill ring slot as necessary. + This uses TEXT directly, so the caller must not free it. If APPEND is + non-zero, and the last command was a kill, the text is appended to the + current kill ring slot, otherwise prepended. */ +static int +_rl_copy_to_kill_ring (text, append) + char *text; + int append; +{ + char *old, *new; + int slot; + + /* First, find the slot to work with. */ + if (_rl_last_command_was_kill == 0) + { + /* Get a new slot. */ + if (rl_kill_ring == 0) + { + /* If we don't have any defined, then make one. */ + rl_kill_ring = (char **) + xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); + rl_kill_ring[slot = 0] = (char *)NULL; + } + else + { + /* We have to add a new slot on the end, unless we have + exceeded the max limit for remembering kills. */ + slot = rl_kill_ring_length; + if (slot == rl_max_kills) + { + register int i; + xfree (rl_kill_ring[0]); + for (i = 0; i < slot; i++) + rl_kill_ring[i] = rl_kill_ring[i + 1]; + } + else + { + slot = rl_kill_ring_length += 1; + rl_kill_ring = (char **)xrealloc (rl_kill_ring, slot * sizeof (char *)); + } + rl_kill_ring[--slot] = (char *)NULL; + } + } + else + slot = rl_kill_ring_length - 1; + + /* If the last command was a kill, prepend or append. */ + if (_rl_last_command_was_kill && rl_editing_mode != vi_mode) + { + old = rl_kill_ring[slot]; + new = (char *)xmalloc (1 + strlen (old) + strlen (text)); + + if (append) + { + strcpy (new, old); + strcat (new, text); + } + else + { + strcpy (new, text); + strcat (new, old); + } + xfree (old); + xfree (text); + rl_kill_ring[slot] = new; + } + else + rl_kill_ring[slot] = text; + + rl_kill_index = slot; + return 0; +} + +/* The way to kill something. This appends or prepends to the last + kill, if the last command was a kill command. if FROM is less + than TO, then the text is appended, otherwise prepended. If the + last command was not a kill command, then a new slot is made for + this kill. */ +int +rl_kill_text (from, to) + int from, to; +{ + char *text; + + /* Is there anything to kill? */ + if (from == to) + { + _rl_last_command_was_kill++; + return 0; + } + + text = rl_copy_text (from, to); + + /* Delete the copied text from the line. */ + rl_delete_text (from, to); + + _rl_copy_to_kill_ring (text, from < to); + + _rl_last_command_was_kill++; + return 0; +} + +/* Now REMEMBER! In order to do prepending or appending correctly, kill + commands always make rl_point's original position be the FROM argument, + and rl_point's extent be the TO argument. */ + +/* **************************************************************** */ +/* */ +/* Killing Commands */ +/* */ +/* **************************************************************** */ + +/* Delete the word at point, saving the text in the kill ring. */ +int +rl_kill_word (count, key) + int count, key; +{ + int orig_point; + + if (count < 0) + return (rl_backward_kill_word (-count, key)); + else + { + orig_point = rl_point; + rl_forward_word (count, key); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + + rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Rubout the word before point, placing it on the kill ring. */ +int +rl_backward_kill_word (count, ignore) + int count, ignore; +{ + int orig_point; + + if (count < 0) + return (rl_kill_word (-count, ignore)); + else + { + orig_point = rl_point; + rl_backward_word (count, ignore); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Kill from here to the end of the line. If DIRECTION is negative, kill + back to the line start instead. */ +int +rl_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point; + + if (direction < 0) + return (rl_backward_kill_line (1, ignore)); + else + { + orig_point = rl_point; + rl_end_of_line (1, ignore); + if (orig_point != rl_point) + rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Kill backwards to the start of the line. If DIRECTION is negative, kill + forwards to the line end instead. */ +int +rl_backward_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point; + + if (direction < 0) + return (rl_kill_line (1, ignore)); + else + { + if (rl_point == 0) + rl_ding (); + else + { + orig_point = rl_point; + rl_beg_of_line (1, ignore); + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + } + return 0; +} + +/* Kill the whole line, no matter where point is. */ +int +rl_kill_full_line (count, ignore) + int count, ignore; +{ + rl_begin_undo_group (); + rl_point = 0; + rl_kill_text (rl_point, rl_end); + rl_mark = 0; + rl_end_undo_group (); + return 0; +} + +/* The next two functions mimic unix line editing behaviour, except they + save the deleted text on the kill ring. This is safer than not saving + it, and since we have a ring, nobody should get screwed. */ + +/* This does what C-w does in Unix. We can't prevent people from + using behaviour that they expect. */ +int +rl_unix_word_rubout (count, key) + int count, key; +{ + int orig_point; + + if (rl_point == 0) + rl_ding (); + else + { + orig_point = rl_point; + if (count <= 0) + count = 1; + + while (count--) + { + while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point && (whitespace (rl_line_buffer[rl_point - 1]) == 0)) + rl_point--; + } + + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + + return 0; +} + +/* This deletes one filename component in a Unix pathname. That is, it + deletes backward to directory separator (`/') or whitespace. */ +int +rl_unix_filename_rubout (count, key) + int count, key; +{ + int orig_point, c; + + if (rl_point == 0) + rl_ding (); + else + { + orig_point = rl_point; + if (count <= 0) + count = 1; + + while (count--) + { + c = rl_line_buffer[rl_point - 1]; + while (rl_point && (whitespace (c) || c == '/')) + { + rl_point--; + c = rl_line_buffer[rl_point - 1]; + } + + while (rl_point && (whitespace (c) == 0) && c != '/') + { + rl_point--; + c = rl_line_buffer[rl_point - 1]; + } + } + + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + + return 0; +} + +/* Here is C-u doing what Unix does. You don't *have* to use these + key-bindings. We have a choice of killing the entire line, or + killing from where we are to the start of the line. We choose the + latter, because if you are a Unix weenie, then you haven't backspaced + into the line at all, and if you aren't, then you know what you are + doing. */ +int +rl_unix_line_discard (count, key) + int count, key; +{ + if (rl_point == 0) + rl_ding (); + else + { + rl_kill_text (rl_point, 0); + rl_point = 0; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Copy the text in the `region' to the kill ring. If DELETE is non-zero, + delete the text from the line as well. */ +static int +region_kill_internal (delete) + int delete; +{ + char *text; + + if (rl_mark != rl_point) + { + text = rl_copy_text (rl_point, rl_mark); + if (delete) + rl_delete_text (rl_point, rl_mark); + _rl_copy_to_kill_ring (text, rl_point < rl_mark); + } + + _rl_last_command_was_kill++; + return 0; +} + +/* Copy the text in the region to the kill ring. */ +int +rl_copy_region_to_kill (count, ignore) + int count, ignore; +{ + return (region_kill_internal (0)); +} + +/* Kill the text between the point and mark. */ +int +rl_kill_region (count, ignore) + int count, ignore; +{ + int r, npoint; + + npoint = (rl_point < rl_mark) ? rl_point : rl_mark; + r = region_kill_internal (1); + _rl_fix_point (1); + rl_point = npoint; + return r; +} + +/* Copy COUNT words to the kill ring. DIR says which direction we look + to find the words. */ +static int +_rl_copy_word_as_kill (count, dir) + int count, dir; +{ + int om, op, r; + + om = rl_mark; + op = rl_point; + + if (dir > 0) + rl_forward_word (count, 0); + else + rl_backward_word (count, 0); + + rl_mark = rl_point; + + if (dir > 0) + rl_backward_word (count, 0); + else + rl_forward_word (count, 0); + + r = region_kill_internal (0); + + rl_mark = om; + rl_point = op; + + return r; +} + +int +rl_copy_forward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_backward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, 1)); +} + +int +rl_copy_backward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_forward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, -1)); +} + +/* Yank back the last killed text. This ignores arguments. */ +int +rl_yank (count, ignore) + int count, ignore; +{ + if (rl_kill_ring == 0) + { + _rl_abort_internal (); + return 1; + } + + _rl_set_mark_at_pos (rl_point); + rl_insert_text (rl_kill_ring[rl_kill_index]); + return 0; +} + +/* If the last command was yank, or yank_pop, and the text just + before point is identical to the current kill item, then + delete that text from the line, rotate the index down, and + yank back some other text. */ +int +rl_yank_pop (count, key) + int count, key; +{ + int l, n; + + if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || + !rl_kill_ring) + { + _rl_abort_internal (); + return 1; + } + + l = strlen (rl_kill_ring[rl_kill_index]); + n = rl_point - l; + if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l)) + { + rl_delete_text (n, rl_point); + rl_point = n; + rl_kill_index--; + if (rl_kill_index < 0) + rl_kill_index = rl_kill_ring_length - 1; + rl_yank (1, 0); + return 0; + } + else + { + _rl_abort_internal (); + return 1; + } +} + +/* Yank the COUNTh argument from the previous history line, skipping + HISTORY_SKIP lines before looking for the `previous line'. */ +static int +rl_yank_nth_arg_internal (count, ignore, history_skip) + int count, ignore, history_skip; +{ + register HIST_ENTRY *entry; + char *arg; + int i, pos; + + pos = where_history (); + + if (history_skip) + { + for (i = 0; i < history_skip; i++) + entry = previous_history (); + } + + entry = previous_history (); + + history_set_pos (pos); + + if (entry == 0) + { + rl_ding (); + return 1; + } + + arg = history_arg_extract (count, count, entry->line); + if (!arg || !*arg) + { + rl_ding (); + FREE (arg); + return 1; + } + + rl_begin_undo_group (); + + _rl_set_mark_at_pos (rl_point); + +#if defined (VI_MODE) + /* Vi mode always inserts a space before yanking the argument, and it + inserts it right *after* rl_point. */ + if (rl_editing_mode == vi_mode) + { + rl_vi_append_mode (1, ignore); + rl_insert_text (" "); + } +#endif /* VI_MODE */ + + rl_insert_text (arg); + xfree (arg); + + rl_end_undo_group (); + return 0; +} + +/* Yank the COUNTth argument from the previous history line. */ +int +rl_yank_nth_arg (count, ignore) + int count, ignore; +{ + return (rl_yank_nth_arg_internal (count, ignore, 0)); +} + +/* Yank the last argument from the previous history line. This `knows' + how rl_yank_nth_arg treats a count of `$'. With an argument, this + behaves the same as rl_yank_nth_arg. */ +int +rl_yank_last_arg (count, key) + int count, key; +{ + static int history_skip = 0; + static int explicit_arg_p = 0; + static int count_passed = 1; + static int direction = 1; + static int undo_needed = 0; + int retval; + + if (rl_last_func != rl_yank_last_arg) + { + history_skip = 0; + explicit_arg_p = rl_explicit_arg; + count_passed = count; + direction = 1; + } + else + { + if (undo_needed) + rl_do_undo (); + if (count < 0) /* XXX - was < 1 */ + direction = -direction; + history_skip += direction; + if (history_skip < 0) + history_skip = 0; + } + + if (explicit_arg_p) + retval = rl_yank_nth_arg_internal (count_passed, key, history_skip); + else + retval = rl_yank_nth_arg_internal ('$', key, history_skip); + + undo_needed = retval == 0; + return retval; +} + +/* Having read the special escape sequence denoting the beginning of a + `bracketed paste' sequence, read the rest of the pasted input until the + closing sequence and insert the pasted text as a single unit without + interpretation. */ +int +rl_bracketed_paste_begin (count, key) + int count, key; +{ + int retval, c; + size_t len, cap; + char *buf; + + retval = 1; + len = 0; + buf = xmalloc (cap = 64); + + RL_SETSTATE (RL_STATE_MOREINPUT); + while ((c = rl_read_key ()) >= 0) + { + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (c); + + if (c == '\r') /* XXX */ + c = '\n'; + + if (len == cap) + buf = xrealloc (buf, cap *= 2); + + buf[len++] = c; + if (len >= BRACK_PASTE_SLEN && c == BRACK_PASTE_LAST && + STREQN (buf + len - BRACK_PASTE_SLEN, BRACK_PASTE_SUFF, BRACK_PASTE_SLEN)) + { + len -= BRACK_PASTE_SLEN; + break; + } + } + RL_UNSETSTATE (RL_STATE_MOREINPUT); + + if (c >= 0) + { + if (len == cap) + buf = xrealloc (buf, cap + 1); + buf[len] = '\0'; + retval = rl_insert_text (buf); + } + + xfree (buf); + return (retval); +} + +/* A special paste command for Windows users.. */ +#if defined (_WIN32) +#include + +int +rl_paste_from_clipboard (count, key) + int count, key; +{ + char *data, *ptr; + int len; + + if (OpenClipboard (NULL) == 0) + return (0); + + data = (char *)GetClipboardData (CF_TEXT); + if (data) + { + ptr = strchr (data, '\r'); + if (ptr) + { + len = ptr - data; + ptr = (char *)xmalloc (len + 1); + ptr[len] = '\0'; + strncpy (ptr, data, len); + } + else + ptr = data; + _rl_set_mark_at_pos (rl_point); + rl_insert_text (ptr); + if (ptr != data) + xfree (ptr); + CloseClipboard (); + } + return (0); +} +#endif /* _WIN32 */ diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 5c7ffb007..a68ecaa0e 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -248,6 +248,7 @@ extern int rl_vi_column PARAMS((int, int)); extern int rl_vi_delete_to PARAMS((int, int)); extern int rl_vi_change_to PARAMS((int, int)); extern int rl_vi_yank_to PARAMS((int, int)); +extern int rl_vi_yank_pop PARAMS((int, int)); extern int rl_vi_rubout PARAMS((int, int)); extern int rl_vi_delete PARAMS((int, int)); extern int rl_vi_back_to_indent PARAMS((int, int)); diff --git a/lib/readline/readline.h~ b/lib/readline/readline.h~ new file mode 100644 index 000000000..5c7ffb007 --- /dev/null +++ b/lib/readline/readline.h~ @@ -0,0 +1,933 @@ +/* Readline.h -- the names of functions callable from within readline. */ + +/* Copyright (C) 1987-2013 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 . +*/ + +#if !defined (_READLINE_H_) +#define _READLINE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (READLINE_LIBRARY) +# include "rlstdc.h" +# include "rltypedefs.h" +# include "keymaps.h" +# include "tilde.h" +#else +# include +# include +# include +# include +#endif + +/* Hex-encoded Readline version number. */ +#define RL_READLINE_VERSION 0x0604 /* Readline 6.4 */ +#define RL_VERSION_MAJOR 6 +#define RL_VERSION_MINOR 4 + +/* Readline data structures. */ + +/* Maintaining the state of undo. We remember individual deletes and inserts + on a chain of things to do. */ + +/* The actions that undo knows how to undo. Notice that UNDO_DELETE means + to insert some text, and UNDO_INSERT means to delete some text. I.e., + the code tells undo what to undo, not how to undo it. */ +enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; + +/* What an element of THE_UNDO_LIST looks like. */ +typedef struct undo_list { + struct undo_list *next; + int start, end; /* Where the change took place. */ + char *text; /* The text to insert, if undoing a delete. */ + enum undo_code what; /* Delete, Insert, Begin, End. */ +} UNDO_LIST; + +/* The current undo list for RL_LINE_BUFFER. */ +extern UNDO_LIST *rl_undo_list; + +/* The data structure for mapping textual names to code addresses. */ +typedef struct _funmap { + const char *name; + rl_command_func_t *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* **************************************************************** */ +/* */ +/* Functions available to bind to key sequences */ +/* */ +/* **************************************************************** */ + +/* Bindable commands for numeric arguments. */ +extern int rl_digit_argument PARAMS((int, int)); +extern int rl_universal_argument PARAMS((int, int)); + +/* Bindable commands for moving the cursor. */ +extern int rl_forward_byte PARAMS((int, int)); +extern int rl_forward_char PARAMS((int, int)); +extern int rl_forward PARAMS((int, int)); +extern int rl_backward_byte PARAMS((int, int)); +extern int rl_backward_char PARAMS((int, int)); +extern int rl_backward PARAMS((int, int)); +extern int rl_beg_of_line PARAMS((int, int)); +extern int rl_end_of_line PARAMS((int, int)); +extern int rl_forward_word PARAMS((int, int)); +extern int rl_backward_word PARAMS((int, int)); +extern int rl_refresh_line PARAMS((int, int)); +extern int rl_clear_screen PARAMS((int, int)); +extern int rl_skip_csi_sequence PARAMS((int, int)); +extern int rl_arrow_keys PARAMS((int, int)); + +/* Bindable commands for inserting and deleting text. */ +extern int rl_insert PARAMS((int, int)); +extern int rl_quoted_insert PARAMS((int, int)); +extern int rl_tab_insert PARAMS((int, int)); +extern int rl_newline PARAMS((int, int)); +extern int rl_do_lowercase_version PARAMS((int, int)); +extern int rl_rubout PARAMS((int, int)); +extern int rl_delete PARAMS((int, int)); +extern int rl_rubout_or_delete PARAMS((int, int)); +extern int rl_delete_horizontal_space PARAMS((int, int)); +extern int rl_delete_or_show_completions PARAMS((int, int)); +extern int rl_insert_comment PARAMS((int, int)); + +/* Bindable commands for changing case. */ +extern int rl_upcase_word PARAMS((int, int)); +extern int rl_downcase_word PARAMS((int, int)); +extern int rl_capitalize_word PARAMS((int, int)); + +/* Bindable commands for transposing characters and words. */ +extern int rl_transpose_words PARAMS((int, int)); +extern int rl_transpose_chars PARAMS((int, int)); + +/* Bindable commands for searching within a line. */ +extern int rl_char_search PARAMS((int, int)); +extern int rl_backward_char_search PARAMS((int, int)); + +/* Bindable commands for readline's interface to the command history. */ +extern int rl_beginning_of_history PARAMS((int, int)); +extern int rl_end_of_history PARAMS((int, int)); +extern int rl_get_next_history PARAMS((int, int)); +extern int rl_get_previous_history PARAMS((int, int)); + +/* Bindable commands for managing the mark and region. */ +extern int rl_set_mark PARAMS((int, int)); +extern int rl_exchange_point_and_mark PARAMS((int, int)); + +/* Bindable commands to set the editing mode (emacs or vi). */ +extern int rl_vi_editing_mode PARAMS((int, int)); +extern int rl_emacs_editing_mode PARAMS((int, int)); + +/* Bindable commands to change the insert mode (insert or overwrite) */ +extern int rl_overwrite_mode PARAMS((int, int)); + +/* Bindable commands for managing key bindings. */ +extern int rl_re_read_init_file PARAMS((int, int)); +extern int rl_dump_functions PARAMS((int, int)); +extern int rl_dump_macros PARAMS((int, int)); +extern int rl_dump_variables PARAMS((int, int)); + +/* Bindable commands for word completion. */ +extern int rl_complete PARAMS((int, int)); +extern int rl_possible_completions PARAMS((int, int)); +extern int rl_insert_completions PARAMS((int, int)); +extern int rl_old_menu_complete PARAMS((int, int)); +extern int rl_menu_complete PARAMS((int, int)); +extern int rl_backward_menu_complete PARAMS((int, int)); + +/* Bindable commands for killing and yanking text, and managing the kill ring. */ +extern int rl_kill_word PARAMS((int, int)); +extern int rl_backward_kill_word PARAMS((int, int)); +extern int rl_kill_line PARAMS((int, int)); +extern int rl_backward_kill_line PARAMS((int, int)); +extern int rl_kill_full_line PARAMS((int, int)); +extern int rl_unix_word_rubout PARAMS((int, int)); +extern int rl_unix_filename_rubout PARAMS((int, int)); +extern int rl_unix_line_discard PARAMS((int, int)); +extern int rl_copy_region_to_kill PARAMS((int, int)); +extern int rl_kill_region PARAMS((int, int)); +extern int rl_copy_forward_word PARAMS((int, int)); +extern int rl_copy_backward_word PARAMS((int, int)); +extern int rl_yank PARAMS((int, int)); +extern int rl_yank_pop PARAMS((int, int)); +extern int rl_yank_nth_arg PARAMS((int, int)); +extern int rl_yank_last_arg PARAMS((int, int)); +extern int rl_bracketed_paste_begin PARAMS((int, int)); +/* Not available unless _WIN32 is defined. */ +#if defined (_WIN32) +extern int rl_paste_from_clipboard PARAMS((int, int)); +#endif + +/* Bindable commands for incremental searching. */ +extern int rl_reverse_search_history PARAMS((int, int)); +extern int rl_forward_search_history PARAMS((int, int)); + +/* Bindable keyboard macro commands. */ +extern int rl_start_kbd_macro PARAMS((int, int)); +extern int rl_end_kbd_macro PARAMS((int, int)); +extern int rl_call_last_kbd_macro PARAMS((int, int)); +extern int rl_print_last_kbd_macro PARAMS((int, int)); + +/* Bindable undo commands. */ +extern int rl_revert_line PARAMS((int, int)); +extern int rl_undo_command PARAMS((int, int)); + +/* Bindable tilde expansion commands. */ +extern int rl_tilde_expand PARAMS((int, int)); + +/* Bindable terminal control commands. */ +extern int rl_restart_output PARAMS((int, int)); +extern int rl_stop_output PARAMS((int, int)); + +/* Miscellaneous bindable commands. */ +extern int rl_abort PARAMS((int, int)); +extern int rl_tty_status PARAMS((int, int)); + +/* Bindable commands for incremental and non-incremental history searching. */ +extern int rl_history_search_forward PARAMS((int, int)); +extern int rl_history_search_backward PARAMS((int, int)); +extern int rl_history_substr_search_forward PARAMS((int, int)); +extern int rl_history_substr_search_backward PARAMS((int, int)); +extern int rl_noninc_forward_search PARAMS((int, int)); +extern int rl_noninc_reverse_search PARAMS((int, int)); +extern int rl_noninc_forward_search_again PARAMS((int, int)); +extern int rl_noninc_reverse_search_again PARAMS((int, int)); + +/* Bindable command used when inserting a matching close character. */ +extern int rl_insert_close PARAMS((int, int)); + +/* Not available unless READLINE_CALLBACKS is defined. */ +extern void rl_callback_handler_install PARAMS((const char *, rl_vcpfunc_t *)); +extern void rl_callback_read_char PARAMS((void)); +extern void rl_callback_handler_remove PARAMS((void)); + +/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */ +/* VI-mode bindable commands. */ +extern int rl_vi_redo PARAMS((int, int)); +extern int rl_vi_undo PARAMS((int, int)); +extern int rl_vi_yank_arg PARAMS((int, int)); +extern int rl_vi_fetch_history PARAMS((int, int)); +extern int rl_vi_search_again PARAMS((int, int)); +extern int rl_vi_search PARAMS((int, int)); +extern int rl_vi_complete PARAMS((int, int)); +extern int rl_vi_tilde_expand PARAMS((int, int)); +extern int rl_vi_prev_word PARAMS((int, int)); +extern int rl_vi_next_word PARAMS((int, int)); +extern int rl_vi_end_word PARAMS((int, int)); +extern int rl_vi_insert_beg PARAMS((int, int)); +extern int rl_vi_append_mode PARAMS((int, int)); +extern int rl_vi_append_eol PARAMS((int, int)); +extern int rl_vi_eof_maybe PARAMS((int, int)); +extern int rl_vi_insertion_mode PARAMS((int, int)); +extern int rl_vi_insert_mode PARAMS((int, int)); +extern int rl_vi_movement_mode PARAMS((int, int)); +extern int rl_vi_arg_digit PARAMS((int, int)); +extern int rl_vi_change_case PARAMS((int, int)); +extern int rl_vi_put PARAMS((int, int)); +extern int rl_vi_column PARAMS((int, int)); +extern int rl_vi_delete_to PARAMS((int, int)); +extern int rl_vi_change_to PARAMS((int, int)); +extern int rl_vi_yank_to PARAMS((int, int)); +extern int rl_vi_rubout PARAMS((int, int)); +extern int rl_vi_delete PARAMS((int, int)); +extern int rl_vi_back_to_indent PARAMS((int, int)); +extern int rl_vi_first_print PARAMS((int, int)); +extern int rl_vi_char_search PARAMS((int, int)); +extern int rl_vi_match PARAMS((int, int)); +extern int rl_vi_change_char PARAMS((int, int)); +extern int rl_vi_subst PARAMS((int, int)); +extern int rl_vi_overstrike PARAMS((int, int)); +extern int rl_vi_overstrike_delete PARAMS((int, int)); +extern int rl_vi_replace PARAMS((int, int)); +extern int rl_vi_set_mark PARAMS((int, int)); +extern int rl_vi_goto_mark PARAMS((int, int)); + +/* VI-mode utility functions. */ +extern int rl_vi_check PARAMS((void)); +extern int rl_vi_domove PARAMS((int, int *)); +extern int rl_vi_bracktype PARAMS((int)); + +extern void rl_vi_start_inserting PARAMS((int, int, int)); + +/* VI-mode pseudo-bindable commands, used as utility functions. */ +extern int rl_vi_fWord PARAMS((int, int)); +extern int rl_vi_bWord PARAMS((int, int)); +extern int rl_vi_eWord PARAMS((int, int)); +extern int rl_vi_fword PARAMS((int, int)); +extern int rl_vi_bword PARAMS((int, int)); +extern int rl_vi_eword PARAMS((int, int)); + +/* **************************************************************** */ +/* */ +/* Well Published Functions */ +/* */ +/* **************************************************************** */ + +/* Readline functions. */ +/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ +extern char *readline PARAMS((const char *)); + +extern int rl_set_prompt PARAMS((const char *)); +extern int rl_expand_prompt PARAMS((char *)); + +extern int rl_initialize PARAMS((void)); + +/* Undocumented; unused by readline */ +extern int rl_discard_argument PARAMS((void)); + +/* Utility functions to bind keys to readline commands. */ +extern int rl_add_defun PARAMS((const char *, rl_command_func_t *, int)); +extern int rl_bind_key PARAMS((int, rl_command_func_t *)); +extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap)); +extern int rl_unbind_key PARAMS((int)); +extern int rl_unbind_key_in_map PARAMS((int, Keymap)); +extern int rl_bind_key_if_unbound PARAMS((int, rl_command_func_t *)); +extern int rl_bind_key_if_unbound_in_map PARAMS((int, rl_command_func_t *, Keymap)); +extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap)); +extern int rl_unbind_command_in_map PARAMS((const char *, Keymap)); +extern int rl_bind_keyseq PARAMS((const char *, rl_command_func_t *)); +extern int rl_bind_keyseq_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); +extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *)); +extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); +extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap)); + +extern char *rl_variable_value PARAMS((const char *)); +extern int rl_variable_bind PARAMS((const char *, const char *)); + +/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */ +extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap)); + +/* Backwards compatibility, use rl_generic_bind instead. */ +extern int rl_macro_bind PARAMS((const char *, const char *, Keymap)); + +/* Undocumented in the texinfo manual; not really useful to programs. */ +extern int rl_translate_keyseq PARAMS((const char *, char *, int *)); +extern char *rl_untranslate_keyseq PARAMS((int)); + +extern rl_command_func_t *rl_named_function PARAMS((const char *)); +extern rl_command_func_t *rl_function_of_keyseq PARAMS((const char *, Keymap, int *)); + +extern void rl_list_funmap_names PARAMS((void)); +extern char **rl_invoking_keyseqs_in_map PARAMS((rl_command_func_t *, Keymap)); +extern char **rl_invoking_keyseqs PARAMS((rl_command_func_t *)); + +extern void rl_function_dumper PARAMS((int)); +extern void rl_macro_dumper PARAMS((int)); +extern void rl_variable_dumper PARAMS((int)); + +extern int rl_read_init_file PARAMS((const char *)); +extern int rl_parse_and_bind PARAMS((char *)); + +/* Functions for manipulating keymaps. */ +extern Keymap rl_make_bare_keymap PARAMS((void)); +extern Keymap rl_copy_keymap PARAMS((Keymap)); +extern Keymap rl_make_keymap PARAMS((void)); +extern void rl_discard_keymap PARAMS((Keymap)); +extern void rl_free_keymap PARAMS((Keymap)); + +extern Keymap rl_get_keymap_by_name PARAMS((const char *)); +extern char *rl_get_keymap_name PARAMS((Keymap)); +extern void rl_set_keymap PARAMS((Keymap)); +extern Keymap rl_get_keymap PARAMS((void)); +/* Undocumented; used internally only. */ +extern void rl_set_keymap_from_edit_mode PARAMS((void)); +extern char *rl_get_keymap_name_from_edit_mode PARAMS((void)); + +/* Functions for manipulating the funmap, which maps command names to functions. */ +extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *)); +extern const char **rl_funmap_names PARAMS((void)); +/* Undocumented, only used internally -- there is only one funmap, and this + function may be called only once. */ +extern void rl_initialize_funmap PARAMS((void)); + +/* Utility functions for managing keyboard macros. */ +extern void rl_push_macro_input PARAMS((char *)); + +/* Functions for undoing, from undo.c */ +extern void rl_add_undo PARAMS((enum undo_code, int, int, char *)); +extern void rl_free_undo_list PARAMS((void)); +extern int rl_do_undo PARAMS((void)); +extern int rl_begin_undo_group PARAMS((void)); +extern int rl_end_undo_group PARAMS((void)); +extern int rl_modifying PARAMS((int, int)); + +/* Functions for redisplay. */ +extern void rl_redisplay PARAMS((void)); +extern int rl_on_new_line PARAMS((void)); +extern int rl_on_new_line_with_prompt PARAMS((void)); +extern int rl_forced_update_display PARAMS((void)); +extern int rl_clear_message PARAMS((void)); +extern int rl_reset_line_state PARAMS((void)); +extern int rl_crlf PARAMS((void)); + +#if defined (USE_VARARGS) && defined (PREFER_STDARG) +extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); +#else +extern int rl_message (); +#endif + +extern int rl_show_char PARAMS((int)); + +/* Undocumented in texinfo manual. */ +extern int rl_character_len PARAMS((int, int)); +extern void rl_redraw_prompt_last_line PARAMS((void)); + +/* Save and restore internal prompt redisplay information. */ +extern void rl_save_prompt PARAMS((void)); +extern void rl_restore_prompt PARAMS((void)); + +/* Modifying text. */ +extern void rl_replace_line PARAMS((const char *, int)); +extern int rl_insert_text PARAMS((const char *)); +extern int rl_delete_text PARAMS((int, int)); +extern int rl_kill_text PARAMS((int, int)); +extern char *rl_copy_text PARAMS((int, int)); + +/* Terminal and tty mode management. */ +extern void rl_prep_terminal PARAMS((int)); +extern void rl_deprep_terminal PARAMS((void)); +extern void rl_tty_set_default_bindings PARAMS((Keymap)); +extern void rl_tty_unset_default_bindings PARAMS((Keymap)); + +extern int rl_reset_terminal PARAMS((const char *)); +extern void rl_resize_terminal PARAMS((void)); +extern void rl_set_screen_size PARAMS((int, int)); +extern void rl_get_screen_size PARAMS((int *, int *)); +extern void rl_reset_screen_size PARAMS((void)); + +extern char *rl_get_termcap PARAMS((const char *)); + +/* Functions for character input. */ +extern int rl_stuff_char PARAMS((int)); +extern int rl_execute_next PARAMS((int)); +extern int rl_clear_pending_input PARAMS((void)); +extern int rl_read_key PARAMS((void)); +extern int rl_getc PARAMS((FILE *)); +extern int rl_set_keyboard_input_timeout PARAMS((int)); + +/* `Public' utility functions . */ +extern void rl_extend_line_buffer PARAMS((int)); +extern int rl_ding PARAMS((void)); +extern int rl_alphabetic PARAMS((int)); +extern void rl_free PARAMS((void *)); + +/* Readline signal handling, from signals.c */ +extern int rl_set_signals PARAMS((void)); +extern int rl_clear_signals PARAMS((void)); +extern void rl_cleanup_after_signal PARAMS((void)); +extern void rl_reset_after_signal PARAMS((void)); +extern void rl_free_line_state PARAMS((void)); + +extern void rl_echo_signal_char PARAMS((int)); + +extern int rl_set_paren_blink_timeout PARAMS((int)); + +/* History management functions. */ + +extern void rl_clear_history PARAMS((void)); + +/* Undocumented. */ +extern int rl_maybe_save_line PARAMS((void)); +extern int rl_maybe_unsave_line PARAMS((void)); +extern int rl_maybe_replace_line PARAMS((void)); + +/* Completion functions. */ +extern int rl_complete_internal PARAMS((int)); +extern void rl_display_match_list PARAMS((char **, int, int)); + +extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *)); +extern char *rl_username_completion_function PARAMS((const char *, int)); +extern char *rl_filename_completion_function PARAMS((const char *, int)); + +extern int rl_completion_mode PARAMS((rl_command_func_t *)); + +#if 0 +/* Backwards compatibility (compat.c). These will go away sometime. */ +extern void free_undo_list PARAMS((void)); +extern int maybe_save_line PARAMS((void)); +extern int maybe_unsave_line PARAMS((void)); +extern int maybe_replace_line PARAMS((void)); + +extern int ding PARAMS((void)); +extern int alphabetic PARAMS((int)); +extern int crlf PARAMS((void)); + +extern char **completion_matches PARAMS((char *, rl_compentry_func_t *)); +extern char *username_completion_function PARAMS((const char *, int)); +extern char *filename_completion_function PARAMS((const char *, int)); +#endif + +/* **************************************************************** */ +/* */ +/* Well Published Variables */ +/* */ +/* **************************************************************** */ + +/* The version of this incarnation of the readline library. */ +extern const char *rl_library_version; /* e.g., "4.2" */ +extern int rl_readline_version; /* e.g., 0x0402 */ + +/* True if this is real GNU readline. */ +extern int rl_gnu_readline_p; + +/* Flags word encapsulating the current readline state. */ +extern int rl_readline_state; + +/* Says which editing mode readline is currently using. 1 means emacs mode; + 0 means vi mode. */ +extern int rl_editing_mode; + +/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means + overwrite mode. Reset to insert mode on each input line. */ +extern int rl_insert_mode; + +/* The name of the calling program. You should initialize this to + whatever was in argv[0]. It is used when parsing conditionals. */ +extern const char *rl_readline_name; + +/* The prompt readline uses. This is set from the argument to + readline (), and should not be assigned to directly. */ +extern char *rl_prompt; + +/* The prompt string that is actually displayed by rl_redisplay. Public so + applications can more easily supply their own redisplay functions. */ +extern char *rl_display_prompt; + +/* The line buffer that is in use. */ +extern char *rl_line_buffer; + +/* The location of point, and end. */ +extern int rl_point; +extern int rl_end; + +/* The mark, or saved cursor position. */ +extern int rl_mark; + +/* Flag to indicate that readline has finished with the current input + line and should return it. */ +extern int rl_done; + +/* If set to a character value, that will be the next keystroke read. */ +extern int rl_pending_input; + +/* 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. */ +extern int rl_dispatching; + +/* Non-zero if the user typed a numeric argument before executing the + current function. */ +extern int rl_explicit_arg; + +/* The current value of the numeric argument specified by the user. */ +extern int rl_numeric_arg; + +/* The address of the last command function Readline executed. */ +extern rl_command_func_t *rl_last_func; + +/* The name of the terminal to use. */ +extern const char *rl_terminal_name; + +/* The input and output streams. */ +extern FILE *rl_instream; +extern FILE *rl_outstream; + +/* If non-zero, Readline gives values of LINES and COLUMNS from the environment + greater precedence than values fetched from the kernel when computing the + screen dimensions. */ +extern int rl_prefer_env_winsize; + +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +extern rl_hook_func_t *rl_startup_hook; + +/* 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. */ +extern rl_hook_func_t *rl_pre_input_hook; + +/* The address of a function to call periodically while Readline is + awaiting character input, or NULL, for no event handling. */ +extern rl_hook_func_t *rl_event_hook; + +/* The address of a function to call if a read is interrupted by a signal. */ +extern rl_hook_func_t *rl_signal_event_hook; + +/* The address of a function to call if Readline needs to know whether or not + there is data available from the current input source. */ +extern rl_hook_func_t *rl_input_available_hook; + +/* The address of the function to call to fetch a character from the current + Readline input stream */ +extern rl_getc_func_t *rl_getc_function; + +extern rl_voidfunc_t *rl_redisplay_function; + +extern rl_vintfunc_t *rl_prep_term_function; +extern rl_voidfunc_t *rl_deprep_term_function; + +/* Dispatch variables. */ +extern Keymap rl_executing_keymap; +extern Keymap rl_binding_keymap; + +extern int rl_executing_key; +extern char *rl_executing_keyseq; +extern int rl_key_sequence_length; + +/* Display variables. */ +/* If non-zero, readline will erase the entire line, including any prompt, + if the only thing typed on an otherwise-blank line is something bound to + rl_newline. */ +extern int rl_erase_empty_line; + +/* If non-zero, the application has already printed the prompt (rl_prompt) + before calling readline, so readline should not output it the first time + redisplay is done. */ +extern int rl_already_prompted; + +/* A non-zero value means to read only this many characters rather than + up to a character bound to accept-line. */ +extern int rl_num_chars_to_read; + +/* The text of a currently-executing keyboard macro. */ +extern char *rl_executing_macro; + +/* Variables to control readline signal handling. */ +/* If non-zero, readline will install its own signal handlers for + SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ +extern int rl_catch_signals; + +/* If non-zero, readline will install a signal handler for SIGWINCH + that also attempts to call any calling application's SIGWINCH signal + handler. Note that the terminal is not cleaned up before the + application's signal handler is called; use rl_cleanup_after_signal() + to do that. */ +extern int rl_catch_sigwinch; + +/* If non-zero, the readline SIGWINCH handler will modify LINES and + COLUMNS in the environment. */ +extern int rl_change_environment; + +/* Completion variables. */ +/* Pointer to the generator function for completion_matches (). + NULL means to use rl_filename_completion_function (), the default + filename completer. */ +extern rl_compentry_func_t *rl_completion_entry_function; + +/* Optional generator for menu completion. Default is + rl_completion_entry_function (rl_filename_completion_function). */ + extern rl_compentry_func_t *rl_menu_completion_entry_function; + +/* If rl_ignore_some_completions_function is non-NULL it is the address + of a function to call after all of the possible matches have been + generated, but before the actual completion is done to the input line. + The function is called with one argument; a NULL terminated array + of (char *). If your function removes any of the elements, they + must be free()'ed. */ +extern rl_compignore_func_t *rl_ignore_some_completions_function; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +extern rl_completion_func_t *rl_attempted_completion_function; + +/* The basic list of characters that signal a break between words for the + completer routine. The initial contents of this variable is what + breaks words in the shell, i.e. "n\"\\'`@$>". */ +extern const char *rl_basic_word_break_characters; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +extern /*const*/ char *rl_completer_word_break_characters; + +/* Hook function to allow an application to set the completion word + break characters before readline breaks up the line. Allows + position-dependent word break characters. */ +extern rl_cpvfunc_t *rl_completion_word_break_hook; + +/* List of characters which can be used to quote a substring of the line. + Completion occurs on the entire substring, and within the substring + rl_completer_word_break_characters are treated as any other character, + unless they also appear within this list. */ +extern const char *rl_completer_quote_characters; + +/* List of quote characters which cause a word break. */ +extern const char *rl_basic_quote_characters; + +/* List of characters that need to be quoted in filenames by the completer. */ +extern const char *rl_filename_quote_characters; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +extern const char *rl_special_prefixes; + +/* If non-zero, then this is the address of a function to call when + completing on a directory name. The function is called with + the address of a string (the current directory name) as an arg. It + changes what is displayed when the possible completions are printed + or inserted. The directory completion hook should perform + any necessary dequoting. This function should return 1 if it modifies + the directory name pointer passed as an argument. If the directory + completion hook returns 0, it should not modify the directory name + pointer passed as an argument. */ +extern rl_icppfunc_t *rl_directory_completion_hook; + +/* If non-zero, this is the address of a function to call when completing + a directory name. This function takes the address of the directory name + to be modified as an argument. Unlike rl_directory_completion_hook, it + only modifies the directory name used in opendir(2), not what is displayed + when the possible completions are printed or inserted. If set, it takes + precedence over rl_directory_completion_hook. The directory rewrite + hook should perform any necessary dequoting. This function has the same + return value properties as the directory_completion_hook. + + I'm not happy with how this works yet, so it's undocumented. I'm trying + it in bash to see how well it goes. */ +extern rl_icppfunc_t *rl_directory_rewrite_hook; + +/* If non-zero, this is the address of a function for the completer to call + before deciding which character to append to a completed name. It should + modify the directory name passed as an argument if appropriate, and return + non-zero if it modifies the name. This should not worry about dequoting + the filename; that has already happened by the time it gets here. */ +extern rl_icppfunc_t *rl_filename_stat_hook; + +/* If non-zero, this is the address of a function to call when reading + directory entries from the filesystem for completion and comparing + them to the partial word to be completed. The function should + either return its first argument (if no conversion takes place) or + newly-allocated memory. This can, for instance, convert filenames + between character sets for comparison against what's typed at the + keyboard. The returned value is what is added to the list of + matches. The second argument is the length of the filename to be + converted. */ +extern rl_dequote_func_t *rl_filename_rewrite_hook; + +/* Backwards compatibility with previous versions of readline. */ +#define rl_symbolic_link_hook rl_directory_completion_hook + +/* If non-zero, then this is the address of a function to call when + completing a word would normally display the list of possible matches. + This function is called instead of actually doing the display. + It takes three arguments: (char **matches, int num_matches, int max_length) + where MATCHES is the array of strings that matched, NUM_MATCHES is the + number of strings in that array, and MAX_LENGTH is the length of the + longest string in that array. */ +extern rl_compdisp_func_t *rl_completion_display_matches_hook; + +/* Non-zero means that the results of the matches are to be treated + as filenames. This is ALWAYS zero on entry, and can only be changed + within a completion entry finder function. */ +extern int rl_filename_completion_desired; + +/* Non-zero means that the results of the matches are to be quoted using + double quotes (or an application-specific quoting mechanism) if the + filename contains any characters in rl_word_break_chars. This is + ALWAYS non-zero on entry, and can only be changed within a completion + entry finder function. */ +extern int rl_filename_quoting_desired; + +/* Set to a function to quote a filename in an application-specific fashion. + Called with the text to quote, the type of match found (single or multiple) + and a pointer to the quoting character to be used, which the function can + reset if desired. */ +extern rl_quote_func_t *rl_filename_quoting_function; + +/* Function to call to remove quoting characters from a filename. Called + before completion is attempted, so the embedded quotes do not interfere + with matching names in the file system. */ +extern rl_dequote_func_t *rl_filename_dequoting_function; + +/* Function to call to decide whether or not a word break character is + quoted. If a character is quoted, it does not break words for the + completer. */ +extern rl_linebuf_func_t *rl_char_is_quoted_p; + +/* Non-zero means to suppress normal filename completion after the + user-specified completion function has been called. */ +extern int rl_attempted_completion_over; + +/* Set to a character describing the type of completion being attempted by + rl_complete_internal; available for use by application completion + functions. */ +extern int rl_completion_type; + +/* Set to the last key used to invoke one of the completion functions */ +extern int rl_completion_invoking_key; + +/* Up to this many items will be displayed in response to a + possible-completions call. After that, we ask the user if she + is sure she wants to see them all. The default value is 100. */ +extern int rl_completion_query_items; + +/* Character appended to completed words when at the end of the line. The + default is a space. Nothing is added if this is '\0'. */ +extern int rl_completion_append_character; + +/* If set to non-zero by an application completion function, + rl_completion_append_character will not be appended. */ +extern int rl_completion_suppress_append; + +/* Set to any quote character readline thinks it finds before any application + completion function is called. */ +extern int rl_completion_quote_character; + +/* Set to a non-zero value if readline found quoting anywhere in the word to + be completed; set before any application completion function is called. */ +extern int rl_completion_found_quote; + +/* If non-zero, the completion functions don't append any closing quote. + This is set to 0 by rl_complete_internal and may be changed by an + application-specific completion function. */ +extern int rl_completion_suppress_quote; + +/* If non-zero, readline will sort the completion matches. On by default. */ +extern int rl_sort_completion_matches; + +/* If non-zero, a slash will be appended to completed filenames that are + symbolic links to directory names, subject to the value of the + mark-directories variable (which is user-settable). This exists so + that application completion functions can override the user's preference + (set via the mark-symlinked-directories variable) if appropriate. + It's set to the value of _rl_complete_mark_symlink_dirs in + rl_complete_internal before any application-specific completion + function is called, so without that function doing anything, the user's + preferences are honored. */ +extern int rl_completion_mark_symlink_dirs; + +/* If non-zero, then disallow duplicates in the matches. */ +extern int rl_ignore_completion_duplicates; + +/* If this is non-zero, completion is (temporarily) inhibited, and the + completion character will be inserted as any other. */ +extern int rl_inhibit_completion; + +/* Input error; can be returned by (*rl_getc_function) if readline is reading + a top-level command (RL_ISSTATE (RL_STATE_READCMD)). */ +#define READERR (-2) + +/* Definitions available for use by readline clients. */ +#define RL_PROMPT_START_IGNORE '\001' +#define RL_PROMPT_END_IGNORE '\002' + +/* Possible values for do_replace argument to rl_filename_quoting_function, + called by rl_complete_internal. */ +#define NO_MATCH 0 +#define SINGLE_MATCH 1 +#define MULT_MATCH 2 + +/* Possible state values for rl_readline_state */ +#define RL_STATE_NONE 0x000000 /* no state; before first call */ + +#define RL_STATE_INITIALIZING 0x0000001 /* initializing */ +#define RL_STATE_INITIALIZED 0x0000002 /* initialization done */ +#define RL_STATE_TERMPREPPED 0x0000004 /* terminal is prepped */ +#define RL_STATE_READCMD 0x0000008 /* reading a command key */ +#define RL_STATE_METANEXT 0x0000010 /* reading input after ESC */ +#define RL_STATE_DISPATCHING 0x0000020 /* dispatching to a command */ +#define RL_STATE_MOREINPUT 0x0000040 /* reading more input in a command function */ +#define RL_STATE_ISEARCH 0x0000080 /* doing incremental search */ +#define RL_STATE_NSEARCH 0x0000100 /* doing non-inc search */ +#define RL_STATE_SEARCH 0x0000200 /* doing a history search */ +#define RL_STATE_NUMERICARG 0x0000400 /* reading numeric argument */ +#define RL_STATE_MACROINPUT 0x0000800 /* getting input from a macro */ +#define RL_STATE_MACRODEF 0x0001000 /* defining keyboard macro */ +#define RL_STATE_OVERWRITE 0x0002000 /* overwrite mode */ +#define RL_STATE_COMPLETING 0x0004000 /* doing completion */ +#define RL_STATE_SIGHANDLER 0x0008000 /* in readline sighandler */ +#define RL_STATE_UNDOING 0x0010000 /* doing an undo */ +#define RL_STATE_INPUTPENDING 0x0020000 /* rl_execute_next called */ +#define RL_STATE_TTYCSAVED 0x0040000 /* tty special chars saved */ +#define RL_STATE_CALLBACK 0x0080000 /* using the callback interface */ +#define RL_STATE_VIMOTION 0x0100000 /* reading vi motion arg */ +#define RL_STATE_MULTIKEY 0x0200000 /* reading multiple-key command */ +#define RL_STATE_VICMDONCE 0x0400000 /* entered vi command mode at least once */ +#define RL_STATE_REDISPLAYING 0x0800000 /* updating terminal display */ + +#define RL_STATE_DONE 0x1000000 /* done; accepted line */ + +#define RL_SETSTATE(x) (rl_readline_state |= (x)) +#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) +#define RL_ISSTATE(x) (rl_readline_state & (x)) + +struct readline_state { + /* line state */ + int point; + int end; + int mark; + char *buffer; + int buflen; + UNDO_LIST *ul; + char *prompt; + + /* global state */ + int rlstate; + int done; + Keymap kmap; + + /* input state */ + rl_command_func_t *lastfunc; + int insmode; + int edmode; + char *kseq; + int kseqlen; + FILE *inf; + FILE *outf; + int pendingin; + char *macro; + + /* signal state */ + int catchsigs; + int catchsigwinch; + + /* search state */ + + /* completion state */ + rl_compentry_func_t *entryfunc; + rl_compentry_func_t *menuentryfunc; + rl_compignore_func_t *ignorefunc; + rl_completion_func_t *attemptfunc; + char *wordbreakchars; + + /* options state */ + + /* hook state */ + + /* reserved for future expansion, so the struct size doesn't change */ + char reserved[64]; +}; + +extern int rl_save_state PARAMS((struct readline_state *)); +extern int rl_restore_state PARAMS((struct readline_state *)); + +#ifdef __cplusplus +} +#endif + +#endif /* _READLINE_H_ */ diff --git a/lib/readline/signals.c~ b/lib/readline/signals.c~ new file mode 100644 index 000000000..2dd34af23 --- /dev/null +++ b/lib/readline/signals.c~ @@ -0,0 +1,709 @@ +/* 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 (); + /* XXX - experimental for now */ + /* Call a signal hook because though we called the original signal handler + in rl_sigwinch_handler below, we will not resend the signal to + ourselves. */ + if (rl_signal_event_hook) + (*rl_signal_event_hook) (); + } + 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; +_rl_errmsg("rl_sigwinch_handler"); + /* 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); + dummy.sa_flags = 0; + 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); + dummy.sa_flags = 0; + 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; + + sigint_blocked = 1; +} + +/* Allow SIGINT to be delivered. */ +void +_rl_release_sigint () +{ + if (sigint_blocked == 0) + return; + + sigint_blocked = 0; + RL_CHECK_SIGNALS (); +} + +/* 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/vi_mode.c~ b/lib/readline/vi_mode.c~ new file mode 100644 index 000000000..0802aaa36 --- /dev/null +++ b/lib/readline/vi_mode.c~ @@ -0,0 +1,2217 @@ +/* vi_mode.c -- A vi emulation mode for Bash. + Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ + +/* 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 + +/* **************************************************************** */ +/* */ +/* VI Emulation Mode */ +/* */ +/* **************************************************************** */ +#include "rlconf.h" + +#if defined (VI_MODE) + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#if defined (HAVE_STDLIB_H) +# include +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +/* Some standard library routines. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +#ifndef member +#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) +#endif + +int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ + +_rl_vimotion_cxt *_rl_vimvcxt = 0; + +/* Non-zero means enter insertion mode. */ +static int _rl_vi_doing_insert; + +/* Command keys which do movement for xxx_to commands. */ +static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`"; + +/* Keymap used for vi replace characters. Created dynamically since + rarely used. */ +static Keymap vi_replace_map; + +/* The number of characters inserted in the last replace operation. */ +static int vi_replace_count; + +/* If non-zero, we have text inserted after a c[motion] command that put + us implicitly into insert mode. Some people want this text to be + attached to the command so that it is `redoable' with `.'. */ +static int vi_continued_command; +static char *vi_insert_buffer; +static int vi_insert_buffer_size; + +static int _rl_vi_last_repeat = 1; +static int _rl_vi_last_arg_sign = 1; +static int _rl_vi_last_motion; +#if defined (HANDLE_MULTIBYTE) +static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; +static int _rl_vi_last_search_mblen; +#else +static int _rl_vi_last_search_char; +#endif +static int _rl_vi_last_replacement; + +static int _rl_vi_last_key_before_insert; + +static int vi_redoing; + +/* Text modification commands. These are the `redoable' commands. */ +static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; + +/* Arrays for the saved marks. */ +static int vi_mark_chars['z' - 'a' + 1]; + +static void _rl_vi_replace_insert PARAMS((int)); +static void _rl_vi_save_replace PARAMS((void)); +static void _rl_vi_stuff_insert PARAMS((int)); +static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); + +static void vi_save_insert_buffer PARAMS ((int, int)); + +static void _rl_vi_backup PARAMS((void)); + +static int _rl_vi_arg_dispatch PARAMS((int)); +static int rl_digit_loop1 PARAMS((void)); + +static int _rl_vi_set_mark PARAMS((void)); +static int _rl_vi_goto_mark PARAMS((void)); + +static void _rl_vi_append_forward PARAMS((int)); + +static int _rl_vi_callback_getchar PARAMS((char *, int)); + +#if defined (READLINE_CALLBACKS) +static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); +#endif + +static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *)); +static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *)); +static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *)); + +static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *)); +static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *)); +static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *)); + +static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *)); + +void +_rl_vi_initialize_line () +{ + register int i, n; + + n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]); + for (i = 0; i < n; i++) + vi_mark_chars[i] = -1; + + RL_UNSETSTATE(RL_STATE_VICMDONCE); +} + +void +_rl_vi_reset_last () +{ + _rl_vi_last_command = 'i'; + _rl_vi_last_repeat = 1; + _rl_vi_last_arg_sign = 1; + _rl_vi_last_motion = 0; +} + +void +_rl_vi_set_last (key, repeat, sign) + int key, repeat, sign; +{ + _rl_vi_last_command = key; + _rl_vi_last_repeat = repeat; + _rl_vi_last_arg_sign = sign; +} + +/* A convenience function that calls _rl_vi_set_last to save the last command + information and enters insertion mode. */ +void +rl_vi_start_inserting (key, repeat, sign) + int key, repeat, sign; +{ + _rl_vi_set_last (key, repeat, sign); + rl_vi_insertion_mode (1, key); +} + +/* Is the command C a VI mode text modification command? */ +int +_rl_vi_textmod_command (c) + int c; +{ + return (member (c, vi_textmod)); +} + +int +_rl_vi_motion_command (c) + int c; +{ + return (member (c, vi_motion)); +} + +static void +_rl_vi_replace_insert (count) + int count; +{ + int nchars; + + nchars = strlen (vi_insert_buffer); + + rl_begin_undo_group (); + while (count--) + /* nchars-1 to compensate for _rl_replace_text using `end+1' in call + to rl_delete_text */ + _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1); + rl_end_undo_group (); +} + +static void +_rl_vi_stuff_insert (count) + int count; +{ + rl_begin_undo_group (); + while (count--) + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); +} + +/* Bound to `.'. Called from command mode, so we know that we have to + redo a text modification command. The default for _rl_vi_last_command + puts you back into insert mode. */ +int +rl_vi_redo (count, c) + int count, c; +{ + int r; + + if (rl_explicit_arg == 0) + { + rl_numeric_arg = _rl_vi_last_repeat; + rl_arg_sign = _rl_vi_last_arg_sign; + } + + r = 0; + vi_redoing = 1; + /* If we're redoing an insert with `i', stuff in the inserted text + and do not go into insertion mode. */ + if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) + { + _rl_vi_stuff_insert (count); + /* And back up point over the last character inserted. */ + if (rl_point > 0) + _rl_vi_backup (); + } + else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer) + { + _rl_vi_replace_insert (count); + /* And back up point over the last character inserted. */ + if (rl_point > 0) + _rl_vi_backup (); + } + /* Ditto for redoing an insert with `I', but move to the beginning of the + line like the `I' command does. */ + else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer) + { + rl_beg_of_line (1, 'I'); + _rl_vi_stuff_insert (count); + if (rl_point > 0) + _rl_vi_backup (); + } + /* Ditto for redoing an insert with `a', but move forward a character first + like the `a' command does. */ + else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer) + { + _rl_vi_append_forward ('a'); + _rl_vi_stuff_insert (count); + if (rl_point > 0) + _rl_vi_backup (); + } + /* Ditto for redoing an insert with `A', but move to the end of the line + like the `A' command does. */ + else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer) + { + rl_end_of_line (1, 'A'); + _rl_vi_stuff_insert (count); + if (rl_point > 0) + _rl_vi_backup (); + } + else + r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); + vi_redoing = 0; + + return (r); +} + +/* A placeholder for further expansion. */ +int +rl_vi_undo (count, key) + int count, key; +{ + return (rl_undo_command (count, key)); +} + +/* Yank the nth arg from the previous line into this line at point. */ +int +rl_vi_yank_arg (count, key) + int count, key; +{ + /* Readline thinks that the first word on a line is the 0th, while vi + thinks the first word on a line is the 1st. Compensate. */ + if (rl_explicit_arg) + rl_yank_nth_arg (count - 1, 0); + else + rl_yank_nth_arg ('$', 0); + + return (0); +} + +int +rl_vi_yank_pop (count, key) + int count, key; +{ + int l, n; + + if (((rl_last_func != rl_vi_yank_pop) && (rl_last_func != rl_vi_put)) || + !rl_kill_ring) + { + _rl_abort_internal (); + return 1; + } + + l = strlen (rl_kill_ring[rl_kill_index]); + n = rl_point - l; + if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l)) + { + rl_delete_text (n, rl_point); + rl_point = n; + rl_kill_index--; + if (rl_kill_index < 0) + rl_kill_index = rl_kill_ring_length - 1; + rl_vi_put (1, 'p'); + return 0; + } + else + { + _rl_abort_internal (); + return 1; + } +} + +/* With an argument, move back that many history lines, else move to the + beginning of history. */ +int +rl_vi_fetch_history (count, c) + int count, c; +{ + int wanted; + + /* Giving an argument of n means we want the nth command in the history + file. The command number is interpreted the same way that the bash + `history' command does it -- that is, giving an argument count of 450 + to this command would get the command listed as number 450 in the + output of `history'. */ + if (rl_explicit_arg) + { + wanted = history_base + where_history () - count; + if (wanted <= 0) + rl_beginning_of_history (0, 0); + else + rl_get_previous_history (wanted, c); + } + else + rl_beginning_of_history (count, 0); + return (0); +} + +/* Search again for the last thing searched for. */ +int +rl_vi_search_again (count, key) + int count, key; +{ + switch (key) + { + case 'n': + rl_noninc_reverse_search_again (count, key); + break; + + case 'N': + rl_noninc_forward_search_again (count, key); + break; + } + return (0); +} + +/* Do a vi style search. */ +int +rl_vi_search (count, key) + int count, key; +{ + switch (key) + { + case '?': + _rl_free_saved_history_line (); + rl_noninc_forward_search (count, key); + break; + + case '/': + _rl_free_saved_history_line (); + rl_noninc_reverse_search (count, key); + break; + + default: + rl_ding (); + break; + } + return (0); +} + +/* Completion, from vi's point of view. */ +int +rl_vi_complete (ignore, key) + int ignore, key; +{ + 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++; + } + + if (key == '*') + rl_complete_internal ('*'); /* Expansion and replacement. */ + else if (key == '=') + rl_complete_internal ('?'); /* List possible completions. */ + else if (key == '\\') + rl_complete_internal (TAB); /* Standard Readline completion. */ + else + rl_complete (0, key); + + if (key == '*' || key == '\\') + rl_vi_start_inserting (key, 1, rl_arg_sign); + + return (0); +} + +/* Tilde expansion for vi mode. */ +int +rl_vi_tilde_expand (ignore, key) + int ignore, key; +{ + rl_tilde_expand (0, key); + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); +} + +/* Previous word in vi mode. */ +int +rl_vi_prev_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_next_word (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return (0); + } + + if (_rl_uppercase_p (key)) + rl_vi_bWord (count, key); + else + rl_vi_bword (count, key); + + return (0); +} + +/* Next word in vi mode. */ +int +rl_vi_next_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_prev_word (-count, key)); + + if (rl_point >= (rl_end - 1)) + { + rl_ding (); + return (0); + } + + if (_rl_uppercase_p (key)) + rl_vi_fWord (count, key); + else + rl_vi_fword (count, key); + return (0); +} + +/* Move to the end of the ?next? word. */ +int +rl_vi_end_word (count, key) + int count, key; +{ + if (count < 0) + { + rl_ding (); + return 1; + } + + if (_rl_uppercase_p (key)) + rl_vi_eWord (count, key); + else + rl_vi_eword (count, key); + return (0); +} + +/* Move forward a word the way that 'W' does. */ +int +rl_vi_fWord (count, ignore) + int count, ignore; +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Skip until whitespace. */ + while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + + /* Now skip whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +int +rl_vi_bWord (count, ignore) + int count, ignore; +{ + while (count-- && rl_point > 0) + { + /* If we are at the start of a word, move back to whitespace so + we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +int +rl_vi_eWord (count, ignore) + int count, ignore; +{ + while (count-- && rl_point < (rl_end - 1)) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move to the next non-whitespace character (to the start of the + next word). */ + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (rl_point && rl_point < rl_end) + { + /* Skip whitespace. */ + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Skip until whitespace. */ + while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move back to the last character of the word. */ + rl_point--; + } + } + return (0); +} + +int +rl_vi_fword (count, ignore) + int count, ignore; +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Move to white space (really non-identifer). */ + if (_rl_isident (rl_line_buffer[rl_point])) + { + while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + else /* if (!whitespace (rl_line_buffer[rl_point])) */ + { + while (!_rl_isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + + /* Move past whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +int +rl_vi_bword (count, ignore) + int count, ignore; +{ + while (count-- && rl_point > 0) + { + int last_is_ident; + + /* If we are at the start of a word, move back to whitespace + so we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + /* If this character and the previous character are `opposite', move + back so we don't get messed up by the rl_point++ down there in + the while loop. Without this code, words like `l;' screw up the + function. */ + last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); + if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || + (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + if (_rl_isident (rl_line_buffer[rl_point])) + while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); + else + while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +int +rl_vi_eword (count, ignore) + int count, ignore; +{ + while (count-- && rl_point < rl_end - 1) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (rl_point < rl_end) + { + if (_rl_isident (rl_line_buffer[rl_point])) + while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); + else + while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) + && !whitespace (rl_line_buffer[rl_point])); + } + rl_point--; + } + return (0); +} + +int +rl_vi_insert_beg (count, key) + int count, key; +{ + rl_beg_of_line (1, key); + rl_vi_insert_mode (1, key); + return (0); +} + +static void +_rl_vi_append_forward (key) + int key; +{ + int point; + + if (rl_point < rl_end) + { + if (MB_CUR_MAX == 1 || rl_byte_oriented) + rl_point++; + else + { + point = rl_point; +#if 0 + rl_forward_char (1, key); +#else + rl_point = _rl_forward_char_internal (1); +#endif + if (point == rl_point) + rl_point = rl_end; + } + } +} + +int +rl_vi_append_mode (count, key) + int count, key; +{ + _rl_vi_append_forward (key); + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); +} + +int +rl_vi_append_eol (count, key) + int count, key; +{ + rl_end_of_line (1, key); + rl_vi_append_mode (1, key); + return (0); +} + +/* What to do in the case of C-d. */ +int +rl_vi_eof_maybe (count, c) + int count, c; +{ + return (rl_newline (1, '\n')); +} + +/* Insertion mode stuff. */ + +/* Switching from one mode to the other really just involves + switching keymaps. */ +int +rl_vi_insertion_mode (count, key) + int count, key; +{ + _rl_keymap = vi_insertion_keymap; + _rl_vi_last_key_before_insert = key; + if (_rl_show_mode_in_prompt) + _rl_reset_prompt (); + return (0); +} + +int +rl_vi_insert_mode (count, key) + int count, key; +{ + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); +} + +static void +vi_save_insert_buffer (start, len) + int start, len; +{ + /* Same code as _rl_vi_save_insert below */ + if (len >= vi_insert_buffer_size) + { + vi_insert_buffer_size += (len + 32) - (len % 32); + vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); + } + strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); + vi_insert_buffer[len-1] = '\0'; +} + +static void +_rl_vi_save_replace () +{ + int len, start, end; + UNDO_LIST *up; + + up = rl_undo_list; + if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0) + { + if (vi_insert_buffer_size >= 1) + vi_insert_buffer[0] = '\0'; + return; + } + /* Let's try it the quick and easy way for now. This should essentially + accommodate every UNDO_INSERT and save the inserted text to + vi_insert_buffer */ + end = rl_point; + start = end - vi_replace_count + 1; + len = vi_replace_count + 1; + + vi_save_insert_buffer (start, len); +} + +static void +_rl_vi_save_insert (up) + UNDO_LIST *up; +{ + int len, start, end; + + if (up == 0 || up->what != UNDO_INSERT) + { + if (vi_insert_buffer_size >= 1) + vi_insert_buffer[0] = '\0'; + return; + } + + start = up->start; + end = up->end; + len = end - start + 1; + + vi_save_insert_buffer (start, len); +} + +void +_rl_vi_done_inserting () +{ + if (_rl_vi_doing_insert) + { + /* The `C', `s', and `S' commands set this. */ + rl_end_undo_group (); + /* Now, the text between rl_undo_list->next->start and + rl_undo_list->next->end is what was inserted while in insert + mode. It gets copied to VI_INSERT_BUFFER because it depends + on absolute indices into the line which may change (though they + probably will not). */ + _rl_vi_doing_insert = 0; + if (_rl_vi_last_key_before_insert == 'R') + _rl_vi_save_replace (); /* Half the battle */ + else + _rl_vi_save_insert (rl_undo_list->next); + vi_continued_command = 1; + } + else + { + if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' || + _rl_vi_last_key_before_insert == 'a' || + _rl_vi_last_key_before_insert == 'I' || + _rl_vi_last_key_before_insert == 'A')) + _rl_vi_save_insert (rl_undo_list); + /* XXX - Other keys probably need to be checked. */ + else if (_rl_vi_last_key_before_insert == 'C') + rl_end_undo_group (); + while (_rl_undo_group_level > 0) + rl_end_undo_group (); + vi_continued_command = 0; + } +} + +int +rl_vi_movement_mode (count, key) + int count, key; +{ + if (rl_point > 0) + rl_backward_char (1, key); + + _rl_keymap = vi_movement_keymap; + _rl_vi_done_inserting (); + + /* This is how POSIX.2 says `U' should behave -- everything up until the + first time you go into command mode should not be undone. */ + if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0) + rl_free_undo_list (); + + if (_rl_show_mode_in_prompt) + _rl_reset_prompt (); + + RL_SETSTATE (RL_STATE_VICMDONCE); + return (0); +} + +int +rl_vi_arg_digit (count, c) + int count, c; +{ + if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) + return (rl_beg_of_line (1, c)); + else + return (rl_digit_argument (count, c)); +} + +/* Change the case of the next COUNT characters. */ +#if defined (HANDLE_MULTIBYTE) +static int +_rl_vi_change_mbchar_case (count) + int count; +{ + wchar_t wc; + char mb[MB_LEN_MAX+1]; + int mlen, p; + size_t m; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) + count--; + while (count-- && rl_point < rl_end) + { + m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); + if (MB_INVALIDCH (m)) + wc = (wchar_t)rl_line_buffer[rl_point]; + else if (MB_NULLWCH (m)) + wc = L'\0'; + if (iswupper (wc)) + wc = towlower (wc); + else if (iswlower (wc)) + wc = towupper (wc); + else + { + /* Just skip over chars neither upper nor lower case */ + rl_forward_char (1, 0); + continue; + } + + /* Vi is kind of strange here. */ + if (wc) + { + p = rl_point; + mlen = wcrtomb (mb, wc, &ps); + if (mlen >= 0) + mb[mlen] = '\0'; + rl_begin_undo_group (); + rl_vi_delete (1, 0); + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; /* XXX - should we advance more than 1 for mbchar? */ + rl_insert_text (mb); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward_char (1, 0); + } + + return 0; +} +#endif + +int +rl_vi_change_case (count, ignore) + int count, ignore; +{ + int c, p; + + /* Don't try this on an empty line. */ + if (rl_point >= rl_end) + return (0); + + c = 0; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + return (_rl_vi_change_mbchar_case (count)); +#endif + + while (count-- && rl_point < rl_end) + { + if (_rl_uppercase_p (rl_line_buffer[rl_point])) + c = _rl_to_lower (rl_line_buffer[rl_point]); + else if (_rl_lowercase_p (rl_line_buffer[rl_point])) + c = _rl_to_upper (rl_line_buffer[rl_point]); + else + { + /* Just skip over characters neither upper nor lower case. */ + rl_forward_char (1, c); + continue; + } + + /* Vi is kind of strange here. */ + if (c) + { + p = rl_point; + rl_begin_undo_group (); + rl_vi_delete (1, c); + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; + _rl_insert_char (1, c); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward_char (1, c); + } + return (0); +} + +int +rl_vi_put (count, key) + int count, key; +{ + if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); + + while (count--) + rl_yank (1, key); + + rl_backward_char (1, key); + return (0); +} + +static void +_rl_vi_backup () +{ + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; +} + +int +rl_vi_check () +{ + if (rl_point && rl_point == rl_end) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; + } + return (0); +} + +int +rl_vi_column (count, key) + int count, key; +{ + if (count > rl_end) + rl_end_of_line (1, key); + else + rl_point = count - 1; + return (0); +} + +/* Process C as part of the current numeric argument. Return -1 if the + argument should be aborted, 0 if we should not read any more chars, and + 1 if we should continue to read chars. */ +static int +_rl_vi_arg_dispatch (c) + int c; +{ + int key; + + key = c; + if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) + { + rl_numeric_arg *= 4; + return 1; + } + + c = UNMETA (c); + + if (_rl_digit_p (c)) + { + if (rl_explicit_arg) + rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); + else + rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; + return 1; /* keep going */ + } + else + { + rl_clear_message (); + rl_stuff_char (key); + return 0; /* done */ + } +} + +/* A simplified loop for vi. Don't dispatch key at end. + Don't recognize minus sign? + Should this do rl_save_prompt/rl_restore_prompt? */ +static int +rl_digit_loop1 () +{ + int c, r; + + while (1) + { + if (_rl_arg_overflow ()) + return 1; + + c = _rl_arg_getchar (); + + r = _rl_vi_arg_dispatch (c); + if (r <= 0) + break; + } + + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (0); +} + +static void +_rl_mvcxt_init (m, op, key) + _rl_vimotion_cxt *m; + int op, key; +{ + m->op = op; + m->state = m->flags = 0; + m->ncxt = 0; + m->numeric_arg = -1; + m->start = rl_point; + m->end = rl_end; + m->key = key; + m->motion = -1; +} + +static _rl_vimotion_cxt * +_rl_mvcxt_alloc (op, key) + int op, key; +{ + _rl_vimotion_cxt *m; + + m = xmalloc (sizeof (_rl_vimotion_cxt)); + _rl_mvcxt_init (m, op, key); + return m; +} + +static void +_rl_mvcxt_dispose (m) + _rl_vimotion_cxt *m; +{ + xfree (m); +} + +static int +rl_domove_motion_callback (m) + _rl_vimotion_cxt *m; +{ + int c, save, r; + int old_end; + + _rl_vi_last_motion = c = m->motion; + + /* Append a blank character temporarily so that the motion routines + work right at the end of the line. */ + old_end = rl_end; + rl_line_buffer[rl_end++] = ' '; + rl_line_buffer[rl_end] = '\0'; + + _rl_dispatch (c, _rl_keymap); + + /* Remove the blank that we added. */ + rl_end = old_end; + rl_line_buffer[rl_end] = '\0'; + if (rl_point > rl_end) + rl_point = rl_end; + + /* No change in position means the command failed. */ + if (rl_mark == rl_point) + return (-1); + + /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next + word. If we are not at the end of the line, and we are on a + non-whitespace character, move back one (presumably to whitespace). */ + if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && + !whitespace (rl_line_buffer[rl_point])) + rl_point--; + + /* If cw or cW, back up to the end of a word, so the behaviour of ce + or cE is the actual result. Brute-force, no subtlety. */ + if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) + { + /* Don't move farther back than where we started. */ + while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + /* Posix.2 says that if cw or cW moves the cursor towards the end of + the line, the character under the cursor should be deleted. */ + if (rl_point == rl_mark) + rl_point++; + else + { + /* Move past the end of the word so that the kill doesn't + remove the last letter of the previous word. Only do this + if we are not at the end of the line. */ + if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + } + } + + if (rl_mark < rl_point) + SWAP (rl_point, rl_mark); + +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + (*rl_redisplay_function)(); /* make sure motion is displayed */ +#endif + + r = vidomove_dispatch (m); + + return (r); +} + +#define RL_VIMOVENUMARG() (RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG)) + +static int +rl_domove_read_callback (m) + _rl_vimotion_cxt *m; +{ + int c, save; + + c = m->motion; + + if (member (c, vi_motion)) + { +#if defined (READLINE_CALLBACKS) + /* If we just read a vi-mode motion command numeric argument, turn off + the `reading numeric arg' state */ + if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG()) + RL_UNSETSTATE (RL_STATE_NUMERICARG); +#endif + /* Should do everything, including turning off RL_STATE_VIMOTION */ + return (rl_domove_motion_callback (m)); + } + else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c')) + { + rl_mark = rl_end; + rl_beg_of_line (1, c); + _rl_vi_last_motion = c; + RL_UNSETSTATE (RL_STATE_VIMOTION); + return (vidomove_dispatch (m)); + } +#if defined (READLINE_CALLBACKS) + /* XXX - these need to handle rl_universal_argument bindings */ + /* Reading vi motion char continuing numeric argument */ + else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG()) + { + return (_rl_vi_arg_dispatch (c)); + } + /* Readine vi motion char starting numeric argument */ + else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0)) + { + RL_SETSTATE (RL_STATE_NUMERICARG); + return (_rl_vi_arg_dispatch (c)); + } +#endif + else if (_rl_digit_p (c)) + { + /* This code path taken when not in callback mode */ + save = rl_numeric_arg; + rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; + RL_SETSTATE (RL_STATE_NUMERICARG); + rl_digit_loop1 (); + rl_numeric_arg *= save; + c = rl_vi_domove_getchar (m); + if (c < 0) + { + m->motion = 0; + return -1; + } + m->motion = c; + return (rl_domove_motion_callback (m)); + } + else + { + RL_UNSETSTATE (RL_STATE_VIMOTION); + RL_UNSETSTATE (RL_STATE_NUMERICARG); + return (1); + } +} + +static int +rl_vi_domove_getchar (m) + _rl_vimotion_cxt *m; +{ + int c; + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + return c; +} + +#if defined (READLINE_CALLBACKS) +int +_rl_vi_domove_callback (m) + _rl_vimotion_cxt *m; +{ + int c, r; + + m->motion = c = rl_vi_domove_getchar (m); + /* XXX - what to do if this returns -1? Should we return 1 for eof to + callback code? */ + r = rl_domove_read_callback (m); + + return ((r == 0) ? r : 1); /* normalize return values */ +} +#endif + +/* This code path taken when not in callback mode. */ +int +rl_vi_domove (x, ignore) + int x, *ignore; +{ + int r; + _rl_vimotion_cxt *m; + + m = _rl_vimvcxt; + *ignore = m->motion = rl_vi_domove_getchar (m); + + if (m->motion < 0) + { + m->motion = 0; + return -1; + } + + return (rl_domove_read_callback (m)); +} + +static int +vi_delete_dispatch (m) + _rl_vimotion_cxt *m; +{ + /* These are the motion commands that do not require adjusting the + mark. */ + if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) && + (rl_mark < rl_end)) + rl_mark++; + + rl_kill_text (rl_point, rl_mark); + return (0); +} + +int +rl_vi_delete_to (count, key) + int count, key; +{ + int c, r; + + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key); + _rl_vimvcxt->start = rl_point; + + rl_mark = rl_point; + if (_rl_uppercase_p (key)) + { + _rl_vimvcxt->motion = '$'; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing) /* handle redoing `dd' here */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + rl_mark = rl_end; + rl_beg_of_line (1, key); + RL_UNSETSTATE (RL_STATE_VIMOTION); + r = vidomove_dispatch (_rl_vimvcxt); + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + RL_SETSTATE (RL_STATE_VIMOTION); + return (0); + } +#endif + else + r = rl_vi_domove (key, &c); + + if (r < 0) + { + rl_ding (); + r = -1; + } + + _rl_mvcxt_dispose (_rl_vimvcxt); + _rl_vimvcxt = 0; + + return r; +} + +static int +vi_change_dispatch (m) + _rl_vimotion_cxt *m; +{ + /* These are the motion commands that do not require adjusting the + mark. c[wW] are handled by special-case code in rl_vi_domove(), + and already leave the mark at the correct location. */ + if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) && + (rl_mark < rl_end)) + rl_mark++; + + /* The cursor never moves with c[wW]. */ + if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start) + rl_point = m->start; + + if (vi_redoing) + { + if (vi_insert_buffer && *vi_insert_buffer) + rl_begin_undo_group (); + rl_delete_text (rl_point, rl_mark); + if (vi_insert_buffer && *vi_insert_buffer) + { + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); + } + } + else + { + rl_begin_undo_group (); /* to make the `u' command work */ + rl_kill_text (rl_point, rl_mark); + /* `C' does not save the text inserted for undoing or redoing. */ + if (_rl_uppercase_p (m->key) == 0) + _rl_vi_doing_insert = 1; + /* XXX -- TODO -- use m->numericarg? */ + rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign); + } + + return (0); +} + +int +rl_vi_change_to (count, key) + int count, key; +{ + int c, r; + + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key); + _rl_vimvcxt->start = rl_point; + + rl_mark = rl_point; + if (_rl_uppercase_p (key)) + { + _rl_vimvcxt->motion = '$'; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing) /* handle redoing `cc' here */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + rl_mark = rl_end; + rl_beg_of_line (1, key); + RL_UNSETSTATE (RL_STATE_VIMOTION); + r = vidomove_dispatch (_rl_vimvcxt); + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + RL_SETSTATE (RL_STATE_VIMOTION); + return (0); + } +#endif + else + r = rl_vi_domove (key, &c); + + if (r < 0) + { + rl_ding (); + r = -1; /* normalize return value */ + } + + _rl_mvcxt_dispose (_rl_vimvcxt); + _rl_vimvcxt = 0; + + return r; +} + +static int +vi_yank_dispatch (m) + _rl_vimotion_cxt *m; +{ + /* These are the motion commands that do not require adjusting the + mark. */ + if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) && + (rl_mark < rl_end)) + rl_mark++; + + rl_begin_undo_group (); + rl_kill_text (rl_point, rl_mark); + rl_end_undo_group (); + rl_do_undo (); + rl_point = m->start; + + return (0); +} + +int +rl_vi_yank_to (count, key) + int count, key; +{ + int c, r; + + _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key); + _rl_vimvcxt->start = rl_point; + + rl_mark = rl_point; + if (_rl_uppercase_p (key)) + { + _rl_vimvcxt->motion = '$'; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + r = rl_domove_motion_callback (_rl_vimvcxt); + } + else if (vi_redoing) /* handle redoing `yy' here */ + { + _rl_vimvcxt->motion = _rl_vi_last_motion; + rl_mark = rl_end; + rl_beg_of_line (1, key); + RL_UNSETSTATE (RL_STATE_VIMOTION); + r = vidomove_dispatch (_rl_vimvcxt); + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + RL_SETSTATE (RL_STATE_VIMOTION); + return (0); + } +#endif + else + r = rl_vi_domove (key, &c); + + if (r < 0) + { + rl_ding (); + r = -1; + } + + _rl_mvcxt_dispose (_rl_vimvcxt); + _rl_vimvcxt = 0; + + return r; +} + +static int +vidomove_dispatch (m) + _rl_vimotion_cxt *m; +{ + int r; + + switch (m->op) + { + case VIM_DELETE: + r = vi_delete_dispatch (m); + break; + case VIM_CHANGE: + r = vi_change_dispatch (m); + break; + case VIM_YANK: + r = vi_yank_dispatch (m); + break; + default: + _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op); + r = 1; + break; + } + + RL_UNSETSTATE (RL_STATE_VIMOTION); + return r; +} + +int +rl_vi_rubout (count, key) + int count, key; +{ + int opoint; + + if (count < 0) + return (rl_vi_delete (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return 1; + } + + opoint = rl_point; + if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, key); + else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point -= count; + + if (rl_point < 0) + rl_point = 0; + + rl_kill_text (rl_point, opoint); + + return (0); +} + +int +rl_vi_delete (count, key) + int count, key; +{ + int end; + + if (count < 0) + return (rl_vi_rubout (-count, key)); + + if (rl_end == 0) + { + rl_ding (); + return 1; + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + else + end = rl_point + count; + + if (end >= rl_end) + end = rl_end; + + rl_kill_text (rl_point, end); + + if (rl_point > 0 && rl_point == rl_end) + rl_backward_char (1, key); + + return (0); +} + +int +rl_vi_back_to_indent (count, key) + int count, key; +{ + rl_beg_of_line (1, key); + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + return (0); +} + +int +rl_vi_first_print (count, key) + int count, key; +{ + return (rl_vi_back_to_indent (1, key)); +} + +static int _rl_cs_dir, _rl_cs_orig_dir; + +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_char_search (data) + _rl_callback_generic_arg *data; +{ + int c; +#if defined (HANDLE_MULTIBYTE) + c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); +#else + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); +#endif + + if (c <= 0) + return -1; + +#if !defined (HANDLE_MULTIBYTE) + _rl_vi_last_search_char = c; +#endif + + _rl_callback_func = 0; + _rl_want_redisplay = 1; + +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); +#else + return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); +#endif +} +#endif + +int +rl_vi_char_search (count, key) + int count, key; +{ + int c; +#if defined (HANDLE_MULTIBYTE) + static char *target; + static int tlen; +#else + static char target; +#endif + + if (key == ';' || key == ',') + { + if (_rl_cs_orig_dir == 0) + return 1; +#if defined (HANDLE_MULTIBYTE) + if (_rl_vi_last_search_mblen == 0) + return 1; +#else + if (_rl_vi_last_search_char == 0) + return 1; +#endif + _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; + } + else + { + switch (key) + { + case 't': + _rl_cs_orig_dir = _rl_cs_dir = FTO; + break; + + case 'T': + _rl_cs_orig_dir = _rl_cs_dir = BTO; + break; + + case 'f': + _rl_cs_orig_dir = _rl_cs_dir = FFIND; + break; + + case 'F': + _rl_cs_orig_dir = _rl_cs_dir = BFIND; + break; + } + + if (vi_redoing) + { + /* set target and tlen below */ + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = _rl_callback_data_alloc (count); + _rl_callback_data->i1 = _rl_cs_dir; + _rl_callback_func = _rl_vi_callback_char_search; + return (0); + } +#endif + else + { +#if defined (HANDLE_MULTIBYTE) + c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); + if (c <= 0) + return -1; + _rl_vi_last_search_mblen = c; +#else + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (c < 0) + return -1; + _rl_vi_last_search_char = c; +#endif + } + } + +#if defined (HANDLE_MULTIBYTE) + target = _rl_vi_last_search_mbchar; + tlen = _rl_vi_last_search_mblen; +#else + target = _rl_vi_last_search_char; +#endif + +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); +#else + return (_rl_char_search_internal (count, _rl_cs_dir, target)); +#endif +} + +/* Match brackets */ +int +rl_vi_match (ignore, key) + int ignore, key; +{ + int count = 1, brack, pos, tmp, pre; + + pos = rl_point; + if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + pre = rl_point; + rl_forward_char (1, key); + if (pre == rl_point) + break; + } + } + else + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && + rl_point < rl_end - 1) + rl_forward_char (1, key); + + if (brack <= 0) + { + rl_point = pos; + rl_ding (); + return 1; + } + } + + pos = rl_point; + + if (brack < 0) + { + while (count) + { + tmp = pos; + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos--; + else + { + pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); + if (tmp == pos) + pos--; + } + if (pos >= 0) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + rl_ding (); + return 1; + } + } + } + else + { /* brack > 0 */ + while (count) + { + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos++; + else + pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); + + if (pos < rl_end) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + rl_ding (); + return 1; + } + } + } + rl_point = pos; + return (0); +} + +int +rl_vi_bracktype (c) + int c; +{ + switch (c) + { + case '(': return 1; + case ')': return -1; + case '[': return 2; + case ']': return -2; + case '{': return 3; + case '}': return -3; + default: return 0; + } +} + +static int +_rl_vi_change_char (count, c, mb) + int count, c; + char *mb; +{ + int p; + + if (c == '\033' || c == CTRL ('C')) + return -1; + + rl_begin_undo_group (); + while (count-- && rl_point < rl_end) + { + p = rl_point; + rl_vi_delete (1, c); + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mb); + else +#endif + _rl_insert_char (1, c); + } + + /* The cursor shall be left on the last character changed. */ + rl_backward_char (1, c); + + rl_end_undo_group (); + + return (0); +} + +static int +_rl_vi_callback_getchar (mb, mlen) + char *mb; + int mlen; +{ + int c; + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c < 0) + return -1; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, mlen); +#endif + + return c; +} + +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_change_char (data) + _rl_callback_generic_arg *data; +{ + int c; + char mb[MB_LEN_MAX]; + + _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); + + if (c < 0) + return -1; + + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_change_char (data->count, c, mb)); +} +#endif + +int +rl_vi_change_char (count, key) + int count, key; +{ + int c; + char mb[MB_LEN_MAX]; + + if (vi_redoing) + { + c = _rl_vi_last_replacement; + mb[0] = c; + mb[1] = '\0'; + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = _rl_callback_data_alloc (count); + _rl_callback_func = _rl_vi_callback_change_char; + return (0); + } +#endif + else + _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); + + if (c < 0) + return -1; + + return (_rl_vi_change_char (count, c, mb)); +} + +int +rl_vi_subst (count, key) + int count, key; +{ + /* If we are redoing, rl_vi_change_to will stuff the last motion char */ + if (vi_redoing == 0) + rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ + + return (rl_vi_change_to (count, 'c')); +} + +int +rl_vi_overstrike (count, key) + int count, key; +{ + if (_rl_vi_doing_insert == 0) + { + _rl_vi_doing_insert = 1; + rl_begin_undo_group (); + } + + if (count > 0) + { + _rl_overwrite_char (count, key); + vi_replace_count += count; + } + + return (0); +} + +int +rl_vi_overstrike_delete (count, key) + int count, key; +{ + int i, s; + + for (i = 0; i < count; i++) + { + if (vi_replace_count == 0) + { + rl_ding (); + break; + } + s = rl_point; + + if (rl_do_undo ()) + vi_replace_count--; + + if (rl_point == s) + rl_backward_char (1, key); + } + + if (vi_replace_count == 0 && _rl_vi_doing_insert) + { + rl_end_undo_group (); + rl_do_undo (); + _rl_vi_doing_insert = 0; + } + return (0); +} + +int +rl_vi_replace (count, key) + int count, key; +{ + int i; + + vi_replace_count = 0; + + if (vi_replace_map == 0) + { + vi_replace_map = rl_make_bare_keymap (); + + for (i = 0; i < ' '; i++) + if (vi_insertion_keymap[i].type == ISFUNC) + vi_replace_map[i].function = vi_insertion_keymap[i].function; + + for (i = ' '; i < KEYMAP_SIZE; i++) + vi_replace_map[i].function = rl_vi_overstrike; + + vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; + + /* Make sure these are what we want. */ + vi_replace_map[ESC].function = rl_vi_movement_mode; + vi_replace_map[RETURN].function = rl_newline; + vi_replace_map[NEWLINE].function = rl_newline; + + /* If the normal vi insertion keymap has ^H bound to erase, do the + same here. Probably should remove the assignment to RUBOUT up + there, but I don't think it will make a difference in real life. */ + if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && + vi_insertion_keymap[CTRL ('H')].function == rl_rubout) + vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; + + } + + rl_vi_start_inserting (key, 1, rl_arg_sign); + + _rl_vi_last_key_before_insert = key; + _rl_keymap = vi_replace_map; + + return (0); +} + +#if 0 +/* Try to complete the word we are standing on or the word that ends with + the previous character. A space matches everything. Word delimiters are + space and ;. */ +int +rl_vi_possible_completions() +{ + int save_pos = rl_point; + + if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') + { + while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && + rl_line_buffer[rl_point] != ';') + rl_point++; + } + else if (rl_line_buffer[rl_point - 1] == ';') + { + rl_ding (); + return (0); + } + + rl_possible_completions (); + rl_point = save_pos; + + return (0); +} +#endif + +/* Functions to save and restore marks. */ +static int +_rl_vi_set_mark () +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ + { + rl_ding (); + return 1; + } + ch -= 'a'; + vi_mark_chars[ch] = rl_point; + return 0; +} + +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_set_mark (data) + _rl_callback_generic_arg *data; +{ + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_set_mark ()); +} +#endif + +int +rl_vi_set_mark (count, key) + int count, key; +{ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = 0; + _rl_callback_func = _rl_vi_callback_set_mark; + return (0); + } +#endif + + return (_rl_vi_set_mark ()); +} + +static int +_rl_vi_goto_mark () +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (ch == '`') + { + rl_point = rl_mark; + return 0; + } + else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ + { + rl_ding (); + return 1; + } + + ch -= 'a'; + if (vi_mark_chars[ch] == -1) + { + rl_ding (); + return 1; + } + rl_point = vi_mark_chars[ch]; + return 0; +} + +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_goto_mark (data) + _rl_callback_generic_arg *data; +{ + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_goto_mark ()); +} +#endif + +int +rl_vi_goto_mark (count, key) + int count, key; +{ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = 0; + _rl_callback_func = _rl_vi_callback_goto_mark; + return (0); + } +#endif + + return (_rl_vi_goto_mark ()); +} +#endif /* VI_MODE */ diff --git a/pcomplete.c b/pcomplete.c index 85d3cc50a..ea7ea4842 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -1527,6 +1527,8 @@ pcomp_set_readline_variables (flags, nval) option is supposed to turn it off */ if (flags & COPT_NOQUOTE) rl_filename_quoting_desired = 1 - nval; + if (flags & COPT_NOSORT) + rl_sort_completion_matches = 1 - nval; } /* Set or unset FLAGS in the options word of the current compspec. diff --git a/pcomplete.c~ b/pcomplete.c~ new file mode 100644 index 000000000..85d3cc50a --- /dev/null +++ b/pcomplete.c~ @@ -0,0 +1,1667 @@ +/* pcomplete.c - functions to generate lists of matches for programmable completion. */ + +/* Copyright (C) 1999-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 + +#if defined (PROGRAMMABLE_COMPLETION) + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#if defined (PREFER_STDARG) +# include +#else +# include +#endif + +#include + +#include +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "pcomplete.h" +#include "alias.h" +#include "bashline.h" +#include "execute_cmd.h" +#include "pathexp.h" + +#if defined (JOB_CONTROL) +# include "jobs.h" +#endif + +#if !defined (NSIG) +# include "trap.h" +#endif + +#include "shmbutil.h" + +#include "builtins.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#include +#include + +#include +#include +#include + +#define PCOMP_RETRYFAIL 256 + +#ifdef STRDUP +# undef STRDUP +#endif +#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL) + +typedef SHELL_VAR **SVFUNC (); + +#ifndef HAVE_STRPBRK +extern char *strpbrk __P((char *, char *)); +#endif + +extern int array_needs_making; +extern STRING_INT_ALIST word_token_alist[]; +extern char *signal_names[]; +extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; + +#if defined (DEBUG) +#if defined (PREFER_STDARG) +static void debug_printf (const char *, ...) __attribute__((__format__ (printf, 1, 2))); +#endif +#endif /* DEBUG */ + +static int it_init_joblist __P((ITEMLIST *, int)); + +static int it_init_aliases __P((ITEMLIST *)); +static int it_init_arrayvars __P((ITEMLIST *)); +static int it_init_bindings __P((ITEMLIST *)); +static int it_init_builtins __P((ITEMLIST *)); +static int it_init_disabled __P((ITEMLIST *)); +static int it_init_enabled __P((ITEMLIST *)); +static int it_init_exported __P((ITEMLIST *)); +static int it_init_functions __P((ITEMLIST *)); +static int it_init_helptopics __P((ITEMLIST *)); +static int it_init_hostnames __P((ITEMLIST *)); +static int it_init_jobs __P((ITEMLIST *)); +static int it_init_running __P((ITEMLIST *)); +static int it_init_stopped __P((ITEMLIST *)); +static int it_init_keywords __P((ITEMLIST *)); +static int it_init_signals __P((ITEMLIST *)); +static int it_init_variables __P((ITEMLIST *)); +static int it_init_setopts __P((ITEMLIST *)); +static int it_init_shopts __P((ITEMLIST *)); + +static int shouldexp_filterpat __P((char *)); +static char *preproc_filterpat __P((char *, const char *)); + +static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *)); + +static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *)); +static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *, + const char *, + char *, int, WORD_LIST *, + int, int, int *)); +static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, + const char *, + char *, int, WORD_LIST *, + int, int)); + +static STRINGLIST *gen_progcomp_completions __P((const char *, const char *, + const char *, + int, int, int *, int *, + COMPSPEC **)); + +static char *pcomp_filename_completion_function __P((const char *, int)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *bind_comp_words __P((WORD_LIST *)); +#endif +static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int)); +static void unbind_compfunc_variables __P((int)); +static WORD_LIST *build_arg_list __P((char *, const char *, const char *, WORD_LIST *, int)); +static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *)); + +#ifdef DEBUG +static int progcomp_debug = 0; +#endif + +int prog_completion_enabled = 1; + +/* These are used to manage the arrays of strings for possible completions. */ +ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 }; +ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 }; +ITEMLIST it_bindings = { 0, it_init_bindings, (STRINGLIST *)0 }; +ITEMLIST it_builtins = { 0, it_init_builtins, (STRINGLIST *)0 }; +ITEMLIST it_commands = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_directories = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 }; +ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 }; +ITEMLIST it_exports = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 }; +ITEMLIST it_files = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_functions = { 0, it_init_functions, (STRINGLIST *)0 }; +ITEMLIST it_helptopics = { 0, it_init_helptopics, (STRINGLIST *)0 }; +ITEMLIST it_hostnames = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 }; +ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 }; +ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 }; +ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 }; +ITEMLIST it_services = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 }; +ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 }; +ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 }; +ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 }; +ITEMLIST it_users = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 }; + +COMPSPEC *pcomp_curcs; +const char *pcomp_curcmd; +const char *pcomp_curtxt; + +#ifdef DEBUG +/* Debugging code */ +static void +#if defined (PREFER_STDARG) +debug_printf (const char *format, ...) +#else +debug_printf (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + if (progcomp_debug == 0) + return; + + SH_VA_START (args, format); + + fprintf (stdout, "DEBUG: "); + vfprintf (stdout, format, args); + fprintf (stdout, "\n"); + + rl_on_new_line (); + + va_end (args); +} +#endif + +/* Functions to manage the item lists */ + +void +set_itemlist_dirty (it) + ITEMLIST *it; +{ + it->flags |= LIST_DIRTY; +} + +void +initialize_itemlist (itp) + ITEMLIST *itp; +{ + (*itp->list_getter) (itp); + itp->flags |= LIST_INITIALIZED; + itp->flags &= ~LIST_DIRTY; +} + +void +clean_itemlist (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = itp->slist; + if (sl) + { + if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0) + strvec_flush (sl->list); + if ((itp->flags & LIST_DONTFREE) == 0) + free (sl->list); + free (sl); + } + itp->slist = (STRINGLIST *)NULL; + itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY); +} + + +static int +shouldexp_filterpat (s) + char *s; +{ + register char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} + +/* Replace any instance of `&' in PAT with TEXT. Backslash may be used to + quote a `&' and inhibit substitution. Returns a new string. This just + calls stringlib.c:strcreplace(). */ +static char * +preproc_filterpat (pat, text) + char *pat; + const char *text; +{ + char *ret; + + ret = strcreplace (pat, '&', text, 1); + return ret; +} + +/* Remove any match of FILTERPAT from SL. A `&' in FILTERPAT is replaced by + TEXT. A leading `!' in FILTERPAT negates the pattern; in this case + any member of SL->list that does *not* match will be removed. This returns + a new STRINGLIST with the matching members of SL *copied*. Any + non-matching members of SL->list are *freed*. */ +STRINGLIST * +filter_stringlist (sl, filterpat, text) + STRINGLIST *sl; + char *filterpat; + const char *text; +{ + int i, m, not; + STRINGLIST *ret; + char *npat, *t; + + if (sl == 0 || sl->list == 0 || sl->list_len == 0) + return sl; + + npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; + +#if defined (EXTENDED_GLOB) + not = (npat[0] == '!' && (extended_glob == 0 || npat[1] != '(')); /*)*/ +#else + not = (npat[0] == '!'); +#endif + t = not ? npat + 1 : npat; + + ret = strlist_create (sl->list_size); + for (i = 0; i < sl->list_len; i++) + { + m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG | FNMATCH_IGNCASE); + if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH)) + free (sl->list[i]); + else + ret->list[ret->list_len++] = sl->list[i]; + } + + ret->list[ret->list_len] = (char *)NULL; + if (npat != filterpat) + free (npat); + + return ret; +} + +/* Turn an array of strings returned by rl_completion_matches into a STRINGLIST. + This understands how rl_completion_matches sets matches[0] (the lcd of the + strings in the list, unless it's the only match). */ +STRINGLIST * +completions_to_stringlist (matches) + char **matches; +{ + STRINGLIST *sl; + int mlen, i, n; + + mlen = (matches == 0) ? 0 : strvec_len (matches); + sl = strlist_create (mlen + 1); + + if (matches == 0 || matches[0] == 0) + return sl; + + if (matches[1] == 0) + { + sl->list[0] = STRDUP (matches[0]); + sl->list[sl->list_len = 1] = (char *)NULL; + return sl; + } + + for (i = 1, n = 0; i < mlen; i++, n++) + sl->list[n] = STRDUP (matches[i]); + sl->list_len = n; + sl->list[n] = (char *)NULL; + + return sl; +} + +/* Functions to manage the various ITEMLISTs that we populate internally. + The caller is responsible for setting ITP->flags correctly. */ + +static int +it_init_aliases (itp) + ITEMLIST *itp; +{ +#ifdef ALIAS + alias_t **alias_list; + register int i, n; + STRINGLIST *sl; + + alias_list = all_aliases (); + if (alias_list == 0) + { + itp->slist = (STRINGLIST *)NULL; + return 0; + } + for (n = 0; alias_list[n]; n++) + ; + sl = strlist_create (n+1); + for (i = 0; i < n; i++) + sl->list[i] = STRDUP (alias_list[i]->name); + sl->list[n] = (char *)NULL; + sl->list_size = sl->list_len = n; + itp->slist = sl; +#else + itp->slist = (STRINGLIST *)NULL; +#endif + free (alias_list); + return 1; +} + +static void +init_itemlist_from_varlist (itp, svfunc) + ITEMLIST *itp; + SVFUNC *svfunc; +{ + SHELL_VAR **vlist; + STRINGLIST *sl; + register int i, n; + + vlist = (*svfunc) (); + if (vlist == 0) + { + itp->slist = (STRINGLIST *)NULL; + return; + } + for (n = 0; vlist[n]; n++) + ; + sl = strlist_create (n+1); + for (i = 0; i < n; i++) + sl->list[i] = savestring (vlist[i]->name); + sl->list[sl->list_len = n] = (char *)NULL; + itp->slist = sl; +} + +static int +it_init_arrayvars (itp) + ITEMLIST *itp; +{ +#if defined (ARRAY_VARS) + init_itemlist_from_varlist (itp, all_array_variables); + return 1; +#else + return 0; +#endif +} + +static int +it_init_bindings (itp) + ITEMLIST *itp; +{ + char **blist; + STRINGLIST *sl; + + /* rl_funmap_names allocates blist, but not its members */ + blist = (char **)rl_funmap_names (); /* XXX fix const later */ + sl = strlist_create (0); + sl->list = blist; + sl->list_size = 0; + sl->list_len = strvec_len (sl->list); + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + + return 0; +} + +static int +it_init_builtins (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + if (shell_builtins[i].function) + sl->list[n++] = shell_builtins[i].name; + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_enabled (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + { + if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED)) + sl->list[n++] = shell_builtins[i].name; + } + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_disabled (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + { + if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) + sl->list[n++] = shell_builtins[i].name; + } + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_exported (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_exported_variables); + return 0; +} + +static int +it_init_functions (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_visible_functions); + return 0; +} + +/* Like it_init_builtins, but includes everything the help builtin looks at, + not just builtins with an active implementing function. */ +static int +it_init_helptopics (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + sl->list[n++] = shell_builtins[i].name; + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_hostnames (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_hostname_list (); + sl->list_len = sl->list ? strvec_len (sl->list) : 0; + sl->list_size = sl->list_len; + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE; + return 0; +} + +static int +it_init_joblist (itp, jstate) + ITEMLIST *itp; + int jstate; +{ +#if defined (JOB_CONTROL) + STRINGLIST *sl; + register int i; + register PROCESS *p; + char *s, *t; + JOB *j; + JOB_STATE ws; /* wanted state */ + + ws = JNONE; + if (jstate == 0) + ws = JRUNNING; + else if (jstate == 1) + ws = JSTOPPED; + + sl = strlist_create (js.j_jobslots); + for (i = js.j_jobslots - 1; i >= 0; i--) + { + j = get_job_by_jid (i); + if (j == 0) + continue; + p = j->pipe; + if (jstate == -1 || JOBSTATE(i) == ws) + { + s = savestring (p->command); + t = strpbrk (s, " \t\n"); + if (t) + *t = '\0'; + sl->list[sl->list_len++] = s; + } + } + itp->slist = sl; +#else + itp->slist = (STRINGLIST *)NULL; +#endif + return 0; +} + +static int +it_init_jobs (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, -1)); +} + +static int +it_init_running (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, 0)); +} + +static int +it_init_stopped (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, 1)); +} + +static int +it_init_keywords (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + for (n = 0; word_token_alist[n].word; n++) + ; + sl = strlist_create (n); + for (i = 0; i < n; i++) + sl->list[i] = word_token_alist[i].word; + sl->list[sl->list_len = i] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_signals (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = signal_names; + sl->list_len = strvec_len (sl->list); + itp->flags |= LIST_DONTFREE; + itp->slist = sl; + return 0; +} + +static int +it_init_variables (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_visible_variables); + return 0; +} + +static int +it_init_setopts (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_minus_o_opts (); + sl->list_len = strvec_len (sl->list); + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS; + return 0; +} + +static int +it_init_shopts (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_shopt_options (); + sl->list_len = strvec_len (sl->list); + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS; + return 0; +} + +/* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist + as the list of possibilities. If the itemlist has been marked dirty or + it should be regenerated every time, destroy the old STRINGLIST and make a + new one before trying the match. TEXT is dequoted before attempting a + match. */ +static STRINGLIST * +gen_matches_from_itemlist (itp, text) + ITEMLIST *itp; + const char *text; +{ + STRINGLIST *ret, *sl; + int tlen, i, n; + char *ntxt; + + if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) || + (itp->flags & LIST_INITIALIZED) == 0) + { + if (itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) + clean_itemlist (itp); + if ((itp->flags & LIST_INITIALIZED) == 0) + initialize_itemlist (itp); + } + if (itp->slist == 0) + return ((STRINGLIST *)NULL); + ret = strlist_create (itp->slist->list_len+1); + sl = itp->slist; + + ntxt = bash_dequote_text (text); + tlen = STRLEN (ntxt); + + for (i = n = 0; i < sl->list_len; i++) + { + if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen)) + ret->list[n++] = STRDUP (sl->list[i]); + } + ret->list[ret->list_len = n] = (char *)NULL; + + FREE (ntxt); + return ret; +} + +/* A wrapper for rl_filename_completion_function that dequotes the filename + before attempting completions. */ +static char * +pcomp_filename_completion_function (text, state) + const char *text; + int state; +{ + static char *dfn; /* dequoted filename */ + int qc; + int iscompgen, iscompleting; + + if (state == 0) + { + FREE (dfn); + /* remove backslashes quoting special characters in filenames. */ + /* There are roughly three paths we can follow to get here: + 1. complete -f + 2. compgen -f "$word" from a completion function + 3. compgen -f "$word" from the command line + They all need to be handled. + + In the first two cases, readline will run the filename dequoting + function in rl_filename_completion_function if it found a filename + quoting character in the word to be completed + (rl_completion_found_quote). We run the dequoting function here + if we're running compgen, we're not completing, and the + rl_filename_completion_function won't dequote the filename + (rl_completion_found_quote == 0). */ + iscompgen = this_shell_builtin == compgen_builtin; + iscompleting = RL_ISSTATE (RL_STATE_COMPLETING); + if (iscompgen && iscompleting == 0 && rl_completion_found_quote == 0 + && rl_filename_dequoting_function) + { + /* Use rl_completion_quote_character because any single or + double quotes have been removed by the time TEXT makes it + here, and we don't want to remove backslashes inside + quoted strings. */ + dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character); + } + /* Intended to solve a mismatched assumption by bash-completion. If + the text to be completed is empty, but bash-completion turns it into + a quoted string ('') assuming that this code will dequote it before + calling readline, do the dequoting. */ + else if (iscompgen && iscompleting && + pcomp_curtxt && *pcomp_curtxt == 0 && + text && (*text == '\'' || *text == '"') && text[1] == text[0] && text[2] == 0 && + rl_filename_dequoting_function) + dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character); + /* Another mismatched assumption by bash-completion. If compgen is being + run as part of bash-completion, and the argument to compgen is not + the same as the word originally passed to the programmable completion + code, dequote the argument if it has quote characters. It's an + attempt to detect when bash-completion is quoting its filename + argument before calling compgen. */ + /* We could check whether gen_shell_function_matches is in the call + stack by checking whether the gen-shell-function-matches tag is in + the unwind-protect stack, but there's no function to do that yet. + We could simply check whether we're executing in a function by + checking variable_context, and may end up doing that. */ + else if (iscompgen && iscompleting && rl_filename_dequoting_function && + pcomp_curtxt && text && + STREQ (pcomp_curtxt, text) == 0 && + variable_context && + sh_contains_quotes (text)) /* guess */ + dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character); + else + dfn = savestring (text); + } + + return (rl_filename_completion_function (dfn, state)); +} + +#define GEN_COMPS(bmap, flag, it, text, glist, tlist) \ + do { \ + if (bmap & flag) \ + { \ + tlist = gen_matches_from_itemlist (it, text); \ + if (tlist) \ + { \ + glist = strlist_append (glist, tlist); \ + strlist_dispose (tlist); \ + } \ + } \ + } while (0) + +#define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \ + do { \ + if (bmap & flag) \ + { \ + cmatches = rl_completion_matches (text, func); \ + tlist = completions_to_stringlist (cmatches); \ + glist = strlist_append (glist, tlist); \ + strvec_dispose (cmatches); \ + strlist_dispose (tlist); \ + } \ + } while (0) + +/* Functions to generate lists of matches from the actions member of CS. */ + +static STRINGLIST * +gen_action_completions (cs, text) + COMPSPEC *cs; + const char *text; +{ + STRINGLIST *ret, *tmatches; + char **cmatches; /* from rl_completion_matches ... */ + unsigned long flags; + int t; + + ret = tmatches = (STRINGLIST *)NULL; + flags = cs->actions; + + GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches); + GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches); + GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches); + GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches); + GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches); + GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches); + GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches); + GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches); + GEN_COMPS (flags, CA_HELPTOPIC, &it_helptopics, text, ret, tmatches); + GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches); + GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches); + GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches); + GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches); + GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches); + GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches); + GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches); + GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches); + GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches); + + GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches); + + /* And lastly, the special case for directories */ + if (flags & CA_DIRECTORY) + { + t = rl_filename_completion_desired; + rl_completion_mark_symlink_dirs = 1; /* override user preference */ + cmatches = bash_directory_completion_matches (text); + /* If we did not want filename completion before this, and there are + no matches, turn off rl_filename_completion_desired so whatever + matches we get are not treated as filenames (it gets turned on by + rl_filename_completion_function unconditionally). */ + if (t == 0 && cmatches == 0 && rl_filename_completion_desired == 1) + rl_filename_completion_desired = 0; + tmatches = completions_to_stringlist (cmatches); + ret = strlist_append (ret, tmatches); + strvec_dispose (cmatches); + strlist_dispose (tmatches); + } + + return ret; +} + +/* Generate a list of matches for CS->globpat. Unresolved: should this use + TEXT as a match prefix, or just go without? Currently, the code does not + use TEXT, just globs CS->globpat and returns the results. If we do decide + to use TEXT, we should call quote_string_for_globbing before the call to + glob_filename. */ +static STRINGLIST * +gen_globpat_matches (cs, text) + COMPSPEC *cs; + const char *text; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = glob_filename (cs->globpat, 0); + if (GLOB_FAILED (sl->list)) + sl->list = (char **)NULL; + if (sl->list) + sl->list_len = sl->list_size = strvec_len (sl->list); + return sl; +} + +/* Perform the shell word expansions on CS->words and return the results. + Again, this ignores TEXT. */ +static STRINGLIST * +gen_wordlist_matches (cs, text) + COMPSPEC *cs; + const char *text; +{ + WORD_LIST *l, *l2; + STRINGLIST *sl; + int nw, tlen; + char *ntxt; /* dequoted TEXT to use in comparisons */ + + if (cs->words == 0 || cs->words[0] == '\0') + return ((STRINGLIST *)NULL); + + /* This used to be a simple expand_string(cs->words, 0), but that won't + do -- there's no way to split a simple list into individual words + that way, since the shell semantics say that word splitting is done + only on the results of expansion. split_at_delims also handles embedded + quoted strings and preserves the quotes for the expand_words_shellexp + function call that follows. */ + /* XXX - this is where this function spends most of its time */ + l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, 0, (int *)NULL, (int *)NULL); + if (l == 0) + return ((STRINGLIST *)NULL); + /* This will jump back to the top level if the expansion fails... */ + l2 = expand_words_shellexp (l); + dispose_words (l); + + nw = list_length (l2); + sl = strlist_create (nw + 1); + + ntxt = bash_dequote_text (text); + tlen = STRLEN (ntxt); + + for (nw = 0, l = l2; l; l = l->next) + { + if (tlen == 0 || STREQN (l->word->word, ntxt, tlen)) + sl->list[nw++] = STRDUP (l->word->word); + } + sl->list[sl->list_len = nw] = (char *)NULL; + + dispose_words (l2); + FREE (ntxt); + return sl; +} + +#ifdef ARRAY_VARS + +static SHELL_VAR * +bind_comp_words (lwords) + WORD_LIST *lwords; +{ + SHELL_VAR *v; + + v = find_variable ("COMP_WORDS"); + if (v == 0) + v = make_new_array_variable ("COMP_WORDS"); + if (readonly_p (v)) + VUNSETATTR (v, att_readonly); + if (array_p (v) == 0) + v = convert_var_to_array (v); + v = assign_array_var_from_word_list (v, lwords, 0); + + VUNSETATTR (v, att_invisible); + return v; +} +#endif /* ARRAY_VARS */ + +static void +bind_compfunc_variables (line, ind, lwords, cw, exported) + char *line; + int ind; + WORD_LIST *lwords; + int cw, exported; +{ + char ibuf[INT_STRLEN_BOUND(int) + 1]; + char *value; + SHELL_VAR *v; + size_t llen; + int c; + + /* Set the variables that the function expects while it executes. Maybe + these should be in the function environment (temporary_env). */ + v = bind_variable ("COMP_LINE", line, 0); + if (v && exported) + VSETATTR(v, att_exported); + + /* Post bash-4.2: COMP_POINT is characters instead of bytes. */ + c = line[ind]; + line[ind] = '\0'; + llen = MB_STRLEN (line); + line[ind] = c; + value = inttostr (llen, ibuf, sizeof(ibuf)); + v = bind_int_variable ("COMP_POINT", value); + if (v && exported) + VSETATTR(v, att_exported); + + value = inttostr (rl_completion_type, ibuf, sizeof (ibuf)); + v = bind_int_variable ("COMP_TYPE", value); + if (v && exported) + VSETATTR(v, att_exported); + + value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf)); + v = bind_int_variable ("COMP_KEY", value); + if (v && exported) + VSETATTR(v, att_exported); + + /* Since array variables can't be exported, we don't bother making the + array of words. */ + if (exported == 0) + { +#ifdef ARRAY_VARS + v = bind_comp_words (lwords); + value = inttostr (cw, ibuf, sizeof(ibuf)); + bind_int_variable ("COMP_CWORD", value); +#endif + } + else + array_needs_making = 1; +} + +static void +unbind_compfunc_variables (exported) + int exported; +{ + unbind_variable ("COMP_LINE"); + unbind_variable ("COMP_POINT"); + unbind_variable ("COMP_TYPE"); + unbind_variable ("COMP_KEY"); +#ifdef ARRAY_VARS + unbind_variable ("COMP_WORDS"); + unbind_variable ("COMP_CWORD"); +#endif + if (exported) + array_needs_making = 1; +} + +/* Build the list of words to pass to a function or external command + as arguments. When the function or command is invoked, + + $0 == function or command being invoked + $1 == command name + $2 == word to be completed (possibly null) + $3 == previous word + + Functions can access all of the words in the current command line + with the COMP_WORDS array. External commands cannot; they have to + make do with the COMP_LINE and COMP_POINT variables. */ + +static WORD_LIST * +build_arg_list (cmd, cname, text, lwords, ind) + char *cmd; + const char *cname; + const char *text; + WORD_LIST *lwords; + int ind; +{ + WORD_LIST *ret, *cl, *l; + WORD_DESC *w; + int i; + + ret = (WORD_LIST *)NULL; + w = make_word (cmd); + ret = make_word_list (w, (WORD_LIST *)NULL); /* $0 */ + + w = make_word (cname); /* $1 */ + cl = ret->next = make_word_list (w, (WORD_LIST *)NULL); + + w = make_word (text); + cl->next = make_word_list (w, (WORD_LIST *)NULL); /* $2 */ + cl = cl->next; + + /* Search lwords for current word */ + for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++) + ; + w = (l && l->word) ? copy_word (l->word) : make_word (""); + cl->next = make_word_list (w, (WORD_LIST *)NULL); + + return ret; +} + +/* Build a command string with + $0 == cs->funcname (function to execute for completion list) + $1 == command name (command being completed) + $2 = word to be completed (possibly null) + $3 = previous word + and run in the current shell. The function should put its completion + list into the array variable COMPREPLY. We build a STRINGLIST + from the results and return it. + + Since the shell function should return its list of matches in an array + variable, this does nothing if arrays are not compiled into the shell. */ + +static STRINGLIST * +gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp) + COMPSPEC *cs; + const char *cmd; + const char *text; + char *line; + int ind; + WORD_LIST *lwords; + int nw, cw; + int *foundp; +{ + char *funcname; + STRINGLIST *sl; + SHELL_VAR *f, *v; + WORD_LIST *cmdlist; + int fval, found; + sh_parser_state_t ps; + sh_parser_state_t * restrict pps; +#if defined (ARRAY_VARS) + ARRAY *a; +#endif + + found = 0; + if (foundp) + *foundp = found; + + funcname = cs->funcname; + f = find_function (funcname); + if (f == 0) + { + internal_error (_("completion: function `%s' not found"), funcname); + rl_ding (); + rl_on_new_line (); + return ((STRINGLIST *)NULL); + } + +#if !defined (ARRAY_VARS) + return ((STRINGLIST *)NULL); +#else + + /* We pass cw - 1 because command_line_to_word_list returns indices that are + 1-based, while bash arrays are 0-based. */ + bind_compfunc_variables (line, ind, lwords, cw - 1, 0); + + cmdlist = build_arg_list (funcname, cmd, text, lwords, cw); + + pps = &ps; + save_parser_state (pps); + begin_unwind_frame ("gen-shell-function-matches"); + add_unwind_protect (restore_parser_state, (char *)pps); + add_unwind_protect (dispose_words, (char *)cmdlist); + add_unwind_protect (unbind_compfunc_variables, (char *)0); + + fval = execute_shell_function (f, cmdlist); + + discard_unwind_frame ("gen-shell-function-matches"); + restore_parser_state (pps); + + found = fval != EX_NOTFOUND; + if (fval == EX_RETRYFAIL) + found |= PCOMP_RETRYFAIL; + if (foundp) + *foundp = found; + + /* Now clean up and destroy everything. */ + dispose_words (cmdlist); + unbind_compfunc_variables (0); + + /* The list of completions is returned in the array variable COMPREPLY. */ + v = find_variable ("COMPREPLY"); + if (v == 0) + return ((STRINGLIST *)NULL); + if (array_p (v) == 0) + v = convert_var_to_array (v); + + VUNSETATTR (v, att_invisible); + + a = array_cell (v); + if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a)) + sl = (STRINGLIST *)NULL; + else + { + /* XXX - should we filter the list of completions so only those matching + TEXT are returned? Right now, we do not. */ + sl = strlist_create (0); + sl->list = array_to_argv (a); + sl->list_len = sl->list_size = array_num_elements (a); + } + + /* XXX - should we unbind COMPREPLY here? */ + unbind_variable ("COMPREPLY"); + + return (sl); +#endif +} + +/* Build a command string with + $0 == cs->command (command to execute for completion list) + $1 == command name (command being completed) + $2 == word to be completed (possibly null) + $3 == previous word + and run in with command substitution. Parse the results, one word + per line, with backslashes allowed to escape newlines. Build a + STRINGLIST from the results and return it. */ + +static STRINGLIST * +gen_command_matches (cs, cmd, text, line, ind, lwords, nw, cw) + COMPSPEC *cs; + const char *cmd; + const char *text; + char *line; + int ind; + WORD_LIST *lwords; + int nw, cw; +{ + char *csbuf, *cscmd, *t; + int cmdlen, cmdsize, n, ws, we; + WORD_LIST *cmdlist, *cl; + WORD_DESC *tw; + STRINGLIST *sl; + + bind_compfunc_variables (line, ind, lwords, cw, 1); + cmdlist = build_arg_list (cs->command, cmd, text, lwords, cw); + + /* Estimate the size needed for the buffer. */ + n = strlen (cs->command); + cmdsize = n + 1; + for (cl = cmdlist->next; cl; cl = cl->next) + cmdsize += STRLEN (cl->word->word) + 3; + cmdsize += 2; + + /* allocate the string for the command and fill it in. */ + cscmd = (char *)xmalloc (cmdsize + 1); + + strcpy (cscmd, cs->command); /* $0 */ + cmdlen = n; + cscmd[cmdlen++] = ' '; + for (cl = cmdlist->next; cl; cl = cl->next) /* $1, $2, $3, ... */ + { + t = sh_single_quote (cl->word->word ? cl->word->word : ""); + n = strlen (t); + RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64); + strcpy (cscmd + cmdlen, t); + cmdlen += n; + if (cl->next) + cscmd[cmdlen++] = ' '; + free (t); + } + cscmd[cmdlen] = '\0'; + + tw = command_substitute (cscmd, 0); + csbuf = tw ? tw->word : (char *)NULL; + if (tw) + dispose_word_desc (tw); + + /* Now clean up and destroy everything. */ + dispose_words (cmdlist); + free (cscmd); + unbind_compfunc_variables (1); + + if (csbuf == 0 || *csbuf == '\0') + { + FREE (csbuf); + return ((STRINGLIST *)NULL); + } + + /* Now break CSBUF up at newlines, with backslash allowed to escape a + newline, and put the individual words into a STRINGLIST. */ + sl = strlist_create (16); + for (ws = 0; csbuf[ws]; ) + { + we = ws; + while (csbuf[we] && csbuf[we] != '\n') + { + if (csbuf[we] == '\\' && csbuf[we+1] == '\n') + we++; + we++; + } + t = substring (csbuf, ws, we); + if (sl->list_len >= sl->list_size - 1) + strlist_resize (sl, sl->list_size + 16); + sl->list[sl->list_len++] = t; + while (csbuf[we] == '\n') we++; + ws = we; + } + sl->list[sl->list_len] = (char *)NULL; + + free (csbuf); + return (sl); +} + +static WORD_LIST * +command_line_to_word_list (line, llen, sentinel, nwp, cwp) + char *line; + int llen, sentinel, *nwp, *cwp; +{ + WORD_LIST *ret; + char *delims; + +#if 0 + delims = "()<>;&| \t\n"; /* shell metacharacters break words */ +#else + delims = rl_completer_word_break_characters; +#endif + ret = split_at_delims (line, llen, delims, sentinel, SD_NOQUOTEDELIM, nwp, cwp); + return (ret); +} + +/* Evaluate COMPSPEC *cs and return all matches for WORD. */ + +STRINGLIST * +gen_compspec_completions (cs, cmd, word, start, end, foundp) + COMPSPEC *cs; + const char *cmd; + const char *word; + int start, end; + int *foundp; +{ + STRINGLIST *ret, *tmatches; + char *line; + int llen, nw, cw, found, foundf; + WORD_LIST *lwords; + WORD_DESC *lw; + COMPSPEC *tcs; + + found = 1; + +#ifdef DEBUG + debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end); + debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs); +#endif + ret = gen_action_completions (cs, word); +#ifdef DEBUG + if (ret && progcomp_debug) + { + debug_printf ("gen_action_completions (%p, %s) -->", cs, word); + strlist_print (ret, "\t"); + rl_on_new_line (); + } +#endif + + /* Now we start generating completions based on the other members of CS. */ + if (cs->globpat) + { + tmatches = gen_globpat_matches (cs, word); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + rl_filename_completion_desired = 1; + } + } + + if (cs->words) + { + tmatches = gen_wordlist_matches (cs, word); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + lwords = (WORD_LIST *)NULL; + line = (char *)NULL; + if (cs->command || cs->funcname) + { + /* If we have a command or function to execute, we need to first break + the command line into individual words, find the number of words, + and find the word in the list containing the word to be completed. */ + line = substring (rl_line_buffer, start, end); + llen = end - start; + +#ifdef DEBUG + debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)", + line, llen, rl_point - start, &nw, &cw); +#endif + lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw); + /* If we skipped a NULL word at the beginning of the line, add it back */ + if (lwords && lwords->word && cmd[0] == 0 && lwords->word->word[0] != 0) + { + lw = make_bare_word (cmd); + lwords = make_word_list (lw, lwords); + nw++; + cw++; + } +#ifdef DEBUG + if (lwords == 0 && llen > 0) + debug_printf ("ERROR: command_line_to_word_list returns NULL"); + else if (progcomp_debug) + { + debug_printf ("command_line_to_word_list -->"); + printf ("\t"); + print_word_list (lwords, "!"); + printf ("\n"); + fflush(stdout); + rl_on_new_line (); + } +#endif + } + + if (cs->funcname) + { + foundf = 0; + tmatches = gen_shell_function_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw, &foundf); + if (foundf != 0) + found = foundf; + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_shell_function_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + if (cs->command) + { + tmatches = gen_command_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_command_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + if (cs->command || cs->funcname) + { + if (lwords) + dispose_words (lwords); + FREE (line); + } + + if (foundp) + *foundp = found; + + if (found == 0 || (found & PCOMP_RETRYFAIL)) + { + strlist_dispose (ret); + return NULL; + } + + if (cs->filterpat) + { + tmatches = filter_stringlist (ret, cs->filterpat, word); +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + if (ret && ret != tmatches) + { + FREE (ret->list); + free (ret); + } + ret = tmatches; + } + + if (cs->prefix || cs->suffix) + ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix); + + /* If no matches have been generated and the user has specified that + directory completion should be done as a default, call + gen_action_completions again to generate a list of matching directory + names. */ + if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES)) + { + tcs = compspec_create (); + tcs->actions = CA_DIRECTORY; + FREE (ret); + ret = gen_action_completions (tcs, word); + compspec_dispose (tcs); + } + else if (cs->options & COPT_PLUSDIRS) + { + tcs = compspec_create (); + tcs->actions = CA_DIRECTORY; + tmatches = gen_action_completions (tcs, word); + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + compspec_dispose (tcs); + } + + return (ret); +} + +void +pcomp_set_readline_variables (flags, nval) + int flags, nval; +{ + /* If the user specified that the compspec returns filenames, make + sure that readline knows it. */ + if (flags & COPT_FILENAMES) + rl_filename_completion_desired = nval; + /* If the user doesn't want a space appended, tell readline. */ + if (flags & COPT_NOSPACE) + rl_completion_suppress_append = nval; + /* The value here is inverted, since the default is on and the `noquote' + option is supposed to turn it off */ + if (flags & COPT_NOQUOTE) + rl_filename_quoting_desired = 1 - nval; +} + +/* Set or unset FLAGS in the options word of the current compspec. + SET_OR_UNSET is 1 for setting, 0 for unsetting. */ +void +pcomp_set_compspec_options (cs, flags, set_or_unset) + COMPSPEC *cs; + int flags, set_or_unset; +{ + if (cs == 0 && ((cs = pcomp_curcs) == 0)) + return; + if (set_or_unset) + cs->options |= flags; + else + cs->options &= ~flags; +} + +static STRINGLIST * +gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs) + const char *ocmd; + const char *cmd; + const char *word; + int start, end; + int *foundp, *retryp; + COMPSPEC **lastcs; +{ + COMPSPEC *cs, *oldcs; + const char *oldcmd, *oldtxt; + STRINGLIST *ret; + + cs = progcomp_search (ocmd); + + if (cs == 0 || cs == *lastcs) + { +#if 0 + if (foundp) + *foundp = 0; +#endif + return (NULL); + } + + if (*lastcs) + compspec_dispose (*lastcs); + cs->refcount++; /* XXX */ + *lastcs = cs; + + cs = compspec_copy (cs); + + oldcs = pcomp_curcs; + oldcmd = pcomp_curcmd; + oldtxt = pcomp_curtxt; + + pcomp_curcs = cs; + pcomp_curcmd = cmd; + pcomp_curtxt = word; + + ret = gen_compspec_completions (cs, cmd, word, start, end, foundp); + + pcomp_curcs = oldcs; + pcomp_curcmd = oldcmd; + pcomp_curtxt = oldtxt; + + /* We need to conditionally handle setting *retryp here */ + if (retryp) + *retryp = foundp && (*foundp & PCOMP_RETRYFAIL); + + if (foundp) + { + *foundp &= ~PCOMP_RETRYFAIL; + *foundp |= cs->options; + } + + compspec_dispose (cs); + return ret; +} + +/* The driver function for the programmable completion code. Returns a list + of matches for WORD, which is an argument to command CMD. START and END + bound the command currently being completed in rl_line_buffer. */ +char ** +programmable_completions (cmd, word, start, end, foundp) + const char *cmd; + const char *word; + int start, end, *foundp; +{ + COMPSPEC *cs, *lastcs; + STRINGLIST *ret; + char **rmatches, *t; + int found, retry, count; + + lastcs = 0; + found = count = 0; + + do + { + retry = 0; + + /* We look at the basename of CMD if the full command does not have + an associated COMPSPEC. */ + ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs); + if (found == 0) + { + t = strrchr (cmd, '/'); + if (t && *(++t)) + ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs); + } + + if (found == 0) + ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs); + + count++; + + if (count > 32) + { + internal_warning ("programmable_completion: %s: possible retry loop", cmd); + break; + } + } + while (retry); + + if (ret) + { + rmatches = ret->list; + free (ret); + } + else + rmatches = (char **)NULL; + + if (foundp) + *foundp = found; + + if (lastcs) /* XXX - should be while? */ + compspec_dispose (lastcs); + + return (rmatches); +} + +#endif /* PROGRAMMABLE_COMPLETION */ diff --git a/pcomplete.h b/pcomplete.h index 67f6393f8..0514245a6 100644 --- a/pcomplete.h +++ b/pcomplete.h @@ -75,6 +75,7 @@ typedef struct compspec { #define COPT_NOSPACE (1<<5) #define COPT_BASHDEFAULT (1<<6) #define COPT_PLUSDIRS (1<<7) +#define COPT_NOSORT (1<<8) /* List of items is used by the code that implements the programmable completions. */ diff --git a/pcomplete.h~ b/pcomplete.h~ new file mode 100644 index 000000000..67f6393f8 --- /dev/null +++ b/pcomplete.h~ @@ -0,0 +1,164 @@ +/* pcomplete.h - structure definitions and other stuff for programmable + completion. */ + +/* Copyright (C) 1999-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 . +*/ + +#if !defined (_PCOMPLETE_H_) +# define _PCOMPLETE_H_ + +#include "stdc.h" +#include "hashlib.h" + +typedef struct compspec { + int refcount; + unsigned long actions; + unsigned long options; + char *globpat; + char *words; + char *prefix; + char *suffix; + char *funcname; + char *command; + char *lcommand; + char *filterpat; +} COMPSPEC; + +/* Values for COMPSPEC actions. These are things the shell knows how to + build internally. */ +#define CA_ALIAS (1<<0) +#define CA_ARRAYVAR (1<<1) +#define CA_BINDING (1<<2) +#define CA_BUILTIN (1<<3) +#define CA_COMMAND (1<<4) +#define CA_DIRECTORY (1<<5) +#define CA_DISABLED (1<<6) +#define CA_ENABLED (1<<7) +#define CA_EXPORT (1<<8) +#define CA_FILE (1<<9) +#define CA_FUNCTION (1<<10) +#define CA_GROUP (1<<11) +#define CA_HELPTOPIC (1<<12) +#define CA_HOSTNAME (1<<13) +#define CA_JOB (1<<14) +#define CA_KEYWORD (1<<15) +#define CA_RUNNING (1<<16) +#define CA_SERVICE (1<<17) +#define CA_SETOPT (1<<18) +#define CA_SHOPT (1<<19) +#define CA_SIGNAL (1<<20) +#define CA_STOPPED (1<<21) +#define CA_USER (1<<22) +#define CA_VARIABLE (1<<23) + +/* Values for COMPSPEC options field. */ +#define COPT_RESERVED (1<<0) /* reserved for other use */ +#define COPT_DEFAULT (1<<1) +#define COPT_FILENAMES (1<<2) +#define COPT_DIRNAMES (1<<3) +#define COPT_NOQUOTE (1<<4) +#define COPT_NOSPACE (1<<5) +#define COPT_BASHDEFAULT (1<<6) +#define COPT_PLUSDIRS (1<<7) + +/* List of items is used by the code that implements the programmable + completions. */ +typedef struct _list_of_items { + int flags; + int (*list_getter) __P((struct _list_of_items *)); /* function to call to get the list */ + + STRINGLIST *slist; + + /* These may or may not be used. */ + STRINGLIST *genlist; /* for handing to the completion code one item at a time */ + int genindex; /* index of item last handed to completion code */ + +} ITEMLIST; + +/* Values for ITEMLIST -> flags */ +#define LIST_DYNAMIC 0x001 +#define LIST_DIRTY 0x002 +#define LIST_INITIALIZED 0x004 +#define LIST_MUSTSORT 0x008 +#define LIST_DONTFREE 0x010 +#define LIST_DONTFREEMEMBERS 0x020 + +#define EMPTYCMD "_EmptycmD_" +#define DEFAULTCMD "_DefaultCmD_" + +extern HASH_TABLE *prog_completes; +extern int prog_completion_enabled; + +/* Not all of these are used yet. */ +extern ITEMLIST it_aliases; +extern ITEMLIST it_arrayvars; +extern ITEMLIST it_bindings; +extern ITEMLIST it_builtins; +extern ITEMLIST it_commands; +extern ITEMLIST it_directories; +extern ITEMLIST it_disabled; +extern ITEMLIST it_enabled; +extern ITEMLIST it_exports; +extern ITEMLIST it_files; +extern ITEMLIST it_functions; +extern ITEMLIST it_groups; +extern ITEMLIST it_helptopics; +extern ITEMLIST it_hostnames; +extern ITEMLIST it_jobs; +extern ITEMLIST it_keywords; +extern ITEMLIST it_running; +extern ITEMLIST it_services; +extern ITEMLIST it_setopts; +extern ITEMLIST it_shopts; +extern ITEMLIST it_signals; +extern ITEMLIST it_stopped; +extern ITEMLIST it_users; +extern ITEMLIST it_variables; + +extern COMPSPEC *pcomp_curcs; +extern const char *pcomp_curcmd; + +/* Functions from pcomplib.c */ +extern COMPSPEC *compspec_create __P((void)); +extern void compspec_dispose __P((COMPSPEC *)); +extern COMPSPEC *compspec_copy __P((COMPSPEC *)); + +extern void progcomp_create __P((void)); +extern void progcomp_flush __P((void)); +extern void progcomp_dispose __P((void)); + +extern int progcomp_size __P((void)); + +extern int progcomp_insert __P((char *, COMPSPEC *)); +extern int progcomp_remove __P((char *)); + +extern COMPSPEC *progcomp_search __P((const char *)); + +extern void progcomp_walk __P((hash_wfunc *)); + +/* Functions from pcomplete.c */ +extern void set_itemlist_dirty __P((ITEMLIST *)); + +extern STRINGLIST *completions_to_stringlist __P((char **)); + +extern STRINGLIST *gen_compspec_completions __P((COMPSPEC *, const char *, const char *, int, int, int *)); +extern char **programmable_completions __P((const char *, const char *, int, int, int *)); + +extern void pcomp_set_readline_variables __P((int, int)); +extern void pcomp_set_compspec_options __P((COMPSPEC *, int, int)); +#endif /* _PCOMPLETE_H_ */ diff --git a/po/._fr.po b/po/._fr.po index d0dd7297f8100321b875616ac1774737681ba57f..d55c439848905fa84cc211764b3298988b2b09bd 100644 GIT binary patch delta 13 Uc-m`FXi%6C#dPu7#+W7i03`kelmGw# delta 13 Uc-m`FXi%6C#kBXz#+W7i03>_`egFUf diff --git a/redir.c b/redir.c index a0b7f24e6..2765a5547 100644 --- a/redir.c +++ b/redir.c @@ -674,7 +674,10 @@ redir_open (filename, flags, mode, ri) fd = open (filename, flags, mode); e = errno; if (fd < 0 && e == EINTR) - QUIT; + { + QUIT; + run_pending_traps (); + } errno = e; } while (fd < 0 && errno == EINTR); diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 72ec06a2c..3efcf32d6 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/bash/bash-current +BUILD_DIR=/usr/local/build/chet/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig new file mode 100644 index 000000000..c1f1e1991 --- /dev/null +++ b/tests/misc/regress/log.orig @@ -0,0 +1,50 @@ +:; ./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 new file mode 100644 index 000000000..4b3bf2b82 --- /dev/null +++ b/tests/misc/regress/shx.orig @@ -0,0 +1,10 @@ +#! /bin/sh +for cmd in sh bash ash ksh zsh +do + echo + echo $cmd: + for demo in shx? + do + $cmd $demo + done +done -- 2.47.2