From: Chet Ramey Date: Tue, 27 Jan 2015 16:12:02 +0000 (-0500) Subject: bash-20150123 remove leftover and stray files X-Git-Tag: bash-4.4-alpha~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6d7fc2d32d1cb231196b5e3a913ab198736278b1;p=thirdparty%2Fbash.git bash-20150123 remove leftover and stray files --- diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ deleted file mode 100644 index 817082eaa..000000000 --- a/CWRU/CWRU.chlog~ +++ /dev/null @@ -1,7926 +0,0 @@ - 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 - -lib/readline/readline.h - - rl_vi_yank_pop: extern declaration - - 1/21 - ---- -lib/sh/shquote.c - - sh_backslash_quote: change to understand and handle multibyte - characters, using is_basic, COPY_CHAR_P. See - https://bugzilla.redhat.com/show_bug.cgi?id=1184320 for original - report - - 1/23 - ---- -include/posixjmp.h - - use setjmp_sigs instead of redefined setjmp, it fails on Cygwin. - Report from Eric Blake - -builtins/wait.def,shell.c - - use setjmp_sigs instead of setjmp call, since setjmp no longer - redefined to something known - -include/chartypes.h, lib/readline/chardefs.h - - make sure all ctype.h macros are called with unsigned char args, - casting to make sure diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old deleted file mode 100644 index 1707ab10c..000000000 --- a/CWRU/POSIX.NOTES.old +++ /dev/null @@ -1,82 +0,0 @@ -Starting bash with the `--posix' command-line option or executing -`set -o posix' while bash is running will cause bash to conform more -closely to the Posix.2 standard by changing the behavior to match that -specified by Posix.2 in areas where the bash default differs. - -The following list is what's changed when `posix mode' is in effect: - -1. When a command in the hash table no longer exists, bash will re-search - $PATH to find the new location. This is also available with - `shopt -s checkhash'. - -2. The >& redirection does not redirect stdout and stderr. - -3. The message printed by the job control code and builtins when a job - exits with a non-zero status is `Done(status)'. - -4. Reserved words may not be aliased. - -5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and - `!!' -> `!' are enabled, and parameter expansion is performed on - the value regardless of the setting of the `promptvars' option. - -6. Interactive comments are enabled by default. (Note that bash has - them on by default anyway.) - -7. The Posix.2 startup files are executed ($ENV) rather than the normal - bash files. - -8. Tilde expansion is only performed on assignments preceding a command - name, rather than on all assignment statements on the line. - -9. The default history file is ~/.sh_history (default value of $HISTFILE). - -10. The output of `kill -l' prints all the signal names on a single line, - separated by spaces. - -11. Non-interactive shells exit if `file' in `. file' is not found. - -12. Redirection operators do not perform pathname expansion on the word - in the redirection unless the shell is interactive - -13. Function names must be valid shell identifiers. That is, they may not - contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal name - causes a fatal syntax error in non-interactive shells. - -14. Posix.2 `special' builtins are found before shell functions during command - lookup. - -15. If a Posix.2 special builtin returns an error status, a non-interactive - shell exits. The fatal errors are those listed in the POSIX.2 standard, - and include things like passing incorrect options, redirection errors, - variable assignment errors for assignments preceding the command name, - and so on. - -16. The environment passed to executed commands is not sorted. Neither is - the output of `set'. This is not strictly Posix.2 behavior, but sh - does it this way. Ksh does not. It's not necessary to sort the - environment; no program should rely on it being sorted. - -17. If the `cd' builtin finds a directory to change to using $CDPATH, the - value it assigns to $PWD does not contain any symbolic links, as if - `cd -P' had been executed. - -18. A non-interactive shell exits with an error status if a variable - assignment error occurs when no command name follows the assignment - statements. A variable assignment error occurs, for example, when - trying to assign a value to a read-only variable. - -19. A non-interactive shell exits with an error status if the iteration - variable in a for statement or the selection variable in a select - statement is a read-only variable. - -20. Process substitution is not available. - -21. Assignment statements preceding POSIX.2 `special' builtins persist in - the shell environment after the builtin completes. - -There is other Posix.2 behavior that bash does not implement. Specifically: - -1. Assignment statements affect the execution environment of all builtins, - not just special ones. diff --git a/CWRU/old/set.def.save b/CWRU/old/set.def.save deleted file mode 100644 index 87b78d7cc..000000000 --- a/CWRU/old/set.def.save +++ /dev/null @@ -1,544 +0,0 @@ -This file is set.def, from which is created set.c. -It implements the "set" and "unset" builtins in Bash. - -Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 1, or (at your option) any later -version. - -Bash is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with Bash; see the file COPYING. If not, write to the Free Software -Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -$PRODUCES set.c - -#include -#include "../shell.h" -#include "../flags.h" - -#include "bashgetopt.h" - -extern int interactive; -extern int noclobber, posixly_correct; -#if defined (READLINE) -extern int rl_editing_mode, no_line_editing; -#endif /* READLINE */ - -$BUILTIN set -$FUNCTION set_builtin -$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...] - -a Mark variables which are modified or created for export. - -b Notify of job termination immediately. - -e Exit immediately if a command exits with a non-zero status. - -f Disable file name generation (globbing). - -h Locate and remember function commands as functions are - defined. Function commands are normally looked up when - the function is executed. - -i Force the shell to be an "interactive" one. Interactive shells - always read `~/.bashrc' on startup. - -k All keyword arguments are placed in the environment for a - command, not just those that precede the command name. - -m Job control is enabled. - -n Read commands but do not execute them. - -o option-name - Set the variable corresponding to option-name: - allexport same as -a - braceexpand same as -B -#if defined (READLINE) - emacs use an emacs-style line editing interface -#endif /* READLINE */ - errexit same as -e - histexpand same as -H - ignoreeof the shell will not exit upon reading EOF - interactive-comments - allow comments to appear in interactive commands - monitor same as -m - noclobber disallow redirection to existing files - noexec same as -n - noglob same as -f - nohash same as -d - notify save as -b - nounset same as -u - physical same as -P - posix change the behavior of bash where the default - operation differs from the 1003.2 standard to - match the standard - privileged same as -p - verbose same as -v -#if defined (READLINE) - vi use a vi-style line editing interface -#endif /* READLINE */ - xtrace same as -x - -p Turned on whenever the real and effective user ids do not match. - Disables processing of the $ENV file and importing of shell - functions. Turning this option off causes the effective uid and - gid to be set to the real uid and gid. - -t Exit after reading and executing one command. - -u Treat unset variables as an error when substituting. - -v Print shell input lines as they are read. - -x Print commands and their arguments as they are executed. - -l Save and restore the binding of the NAME in a FOR command. - -d Disable the hashing of commands that are looked up for execution. - Normally, commands are remembered in a hash table, and once - found, do not have to be looked up again. -#if defined (BRACE_EXPANSION) - -B the shell will perform brace expansion -#endif /* BRACE_EXPANSION */ -#if defined (BANG_HISTORY) - -H Enable ! style history substitution. This flag is on - by default. -#endif /* BANG_HISTORY */ - -C If set, disallow existing regular files to be overwritten - by redirection of output. - -P If set, do not follow symbolic links when executing commands - such as cd which change the current directory. - -Using + rather than - causes these flags to be turned off. The -flags can also be used upon invocation of the shell. The current -set of flags may be found in $-. The remaining n ARGs are positional -parameters and are assigned, in order, to $1, $2, .. $n. If no -ARGs are given, all shell variables are printed. -$END - -/* An a-list used to match long options for set -o to the corresponding - option letter. */ -struct { - char *name; - int letter; -} o_options[] = { - { "allexport", 'a' }, -#if defined (BRACE_EXPANSION) - { "braceexpand",'B' }, -#endif - { "errexit", 'e' }, - { "histexpand", 'H' }, - { "monitor", 'm' }, - { "noexec", 'n' }, - { "noglob", 'f' }, - { "nohash", 'd' }, -#if defined (JOB_CONTROL) - { "notify", 'b' }, -#endif /* JOB_CONTROL */ - {"nounset", 'u' }, - {"physical", 'P' }, - {"privileged", 'p' }, - {"verbose", 'v' }, - {"xtrace", 'x' }, - {(char *)NULL, 0}, -}; - -#define MINUS_O_FORMAT "%-15s\t%s\n" - -void -list_minus_o_opts () -{ - register int i; - char *on = "on", *off = "off"; - - printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off); - - if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF")) - printf (MINUS_O_FORMAT, "ignoreeof", on); - else - printf (MINUS_O_FORMAT, "ignoreeof", off); - - printf (MINUS_O_FORMAT, "interactive-comments", - interactive_comments ? on : off); - - printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off); - -#if defined (READLINE) - if (no_line_editing) - { - printf (MINUS_O_FORMAT, "emacs", off); - printf (MINUS_O_FORMAT, "vi", off); - } - else - { - /* Magic. This code `knows' how readline handles rl_editing_mode. */ - printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off); - printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off); - } -#endif /* READLINE */ - - for (i = 0; o_options[i].name; i++) - { - int *on_or_off, zero = 0; - - on_or_off = find_flag (o_options[i].letter); - if (on_or_off == FLAG_UNKNOWN) - on_or_off = &zero; - printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off); - } -} - -set_minus_o_option (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - int option_char = -1; - - if (STREQ (option_name, "noclobber")) - { - if (on_or_off == FLAG_ON) - bind_variable ("noclobber", ""); - else - unbind_variable ("noclobber"); - stupidly_hack_special_variables ("noclobber"); - } - else if (STREQ (option_name, "ignoreeof")) - { - unbind_variable ("ignoreeof"); - unbind_variable ("IGNOREEOF"); - if (on_or_off == FLAG_ON) - bind_variable ("IGNOREEOF", "10"); - stupidly_hack_special_variables ("IGNOREEOF"); - } - -#if defined (READLINE) - else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi"))) - { - if (on_or_off == FLAG_ON) - { - rl_variable_bind ("editing-mode", option_name); - - if (interactive) - with_input_from_stdin (); - no_line_editing = 0; - } - else - { - int isemacs = (rl_editing_mode == 1); - if ((isemacs && STREQ (option_name, "emacs")) || - (!isemacs && STREQ (option_name, "vi"))) - { - if (interactive) - with_input_from_stream (stdin, "stdin"); - no_line_editing = 1; - } - else - builtin_error ("not in %s editing mode", option_name); - } - } -#endif /* READLINE */ - else if (STREQ (option_name, "interactive-comments")) - interactive_comments = (on_or_off == FLAG_ON); - else if (STREQ (option_name, "posix")) - { - posixly_correct = (on_or_off == FLAG_ON); - unbind_variable ("POSIXLY_CORRECT"); - unbind_variable ("POSIX_PEDANTIC"); - if (on_or_off == FLAG_ON) - { - bind_variable ("POSIXLY_CORRECT", ""); - stupidly_hack_special_variables ("POSIXLY_CORRECT"); - } - } - else - { - register int i; - for (i = 0; o_options[i].name; i++) - { - if (STREQ (option_name, o_options[i].name)) - { - option_char = o_options[i].letter; - break; - } - } - if (option_char == -1) - { - builtin_error ("%s: unknown option name", option_name); - return (EXECUTION_FAILURE); - } - if (change_flag (option_char, on_or_off) == FLAG_ERROR) - { - bad_option (option_name); - return (EXECUTION_FAILURE); - } - } - return (EXECUTION_SUCCESS); -} - -/* Set some flags from the word values in the input list. If LIST is empty, - then print out the values of the variables instead. If LIST contains - non-flags, then set $1 - $9 to the successive words of LIST. */ -set_builtin (list) - WORD_LIST *list; -{ - int on_or_off, flag_name, force_assignment = 0; - - if (!list) - { - SHELL_VAR **vars; - - vars = all_shell_variables (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - vars = all_shell_functions (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - return (EXECUTION_SUCCESS); - } - - /* Check validity of flag arguments. */ - if (*list->word->word == '-' || *list->word->word == '+') - { - register char *arg; - WORD_LIST *save_list = list; - - while (list && (arg = list->word->word)) - { - char c; - - if (arg[0] != '-' && arg[0] != '+') - break; - - /* `-' or `--' signifies end of flag arguments. */ - if (arg[0] == '-' && - (!arg[1] || (arg[1] == '-' && !arg[2]))) - break; - - while (c = *++arg) - { - if (find_flag (c) == FLAG_UNKNOWN && c != 'o') - { - char s[2]; - s[0] = c; s[1] = '\0'; - bad_option (s); - if (c == '?') - builtin_usage (); - return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - } - list = list->next; - } - list = save_list; - } - - /* Do the set command. While the list consists of words starting with - '-' or '+' treat them as flags, otherwise, start assigning them to - $1 ... $n. */ - while (list) - { - char *string = list->word->word; - - /* If the argument is `--' or `-' then signal the end of the list - and remember the remaining arguments. */ - if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2]))) - { - list = list->next; - - /* `set --' unsets the positional parameters. */ - if (string[1] == '-') - force_assignment = 1; - - /* Until told differently, the old shell behaviour of - `set - [arg ...]' being equivalent to `set +xv [arg ...]' - stands. Posix.2 says the behaviour is marked as obsolescent. */ - else - { - change_flag ('x', '+'); - change_flag ('v', '+'); - } - - break; - } - - if ((on_or_off = *string) && - (on_or_off == '-' || on_or_off == '+')) - { - int i = 1; - while (flag_name = string[i++]) - { - if (flag_name == '?') - { - builtin_usage (); - return (EXECUTION_SUCCESS); - } - else if (flag_name == 'o') /* -+o option-name */ - { - char *option_name; - WORD_LIST *opt; - - opt = list->next; - - if (!opt) - { - list_minus_o_opts (); - continue; - } - - option_name = opt->word->word; - - if (!option_name || !*option_name || (*option_name == '-')) - { - list_minus_o_opts (); - continue; - } - list = list->next; /* Skip over option name. */ - - if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS) - return (EXECUTION_FAILURE); - } - else - { - if (change_flag (flag_name, on_or_off) == FLAG_ERROR) - { - char opt[3]; - opt[0] = on_or_off; - opt[1] = flag_name; - opt[2] = '\0'; - bad_option (opt); - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - } - } - else - { - break; - } - list = list->next; - } - - /* Assigning $1 ... $n */ - if (list || force_assignment) - remember_args (list, 1); - return (EXECUTION_SUCCESS); -} - -$BUILTIN unset -$FUNCTION unset_builtin -$SHORT_DOC unset [-f] [-v] [name ...] -For each NAME, remove the corresponding variable or function. Given -the `-v', unset will only act on variables. Given the `-f' flag, -unset will only act on functions. With neither flag, unset first -tries to unset a variable, and if that fails, then tries to unset a -function. Some variables (such as PATH and IFS) cannot be unset; also -see readonly. -$END - -#define NEXT_VARIABLE() any_failed++; list = list->next; continue; - -unset_builtin (list) - WORD_LIST *list; -{ - int unset_function, unset_variable, unset_array, opt, any_failed; - char *name; - - unset_function = unset_variable = unset_array = any_failed = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "fv")) != -1) - { - switch (opt) - { - case 'f': - unset_function = 1; - break; - case 'v': - unset_variable = 1; - break; - default: - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - - list = loptend; - - if (unset_function && unset_variable) - { - builtin_error ("cannot simultaneously unset a function and a variable"); - return (EXECUTION_FAILURE); - } - - while (list) - { - SHELL_VAR *var; - int tem; -#if defined (ARRAY_VARS) - char *t; -#endif - - name = list->word->word; - -#if defined (ARRAY_VARS) - if (!unset_function && valid_array_reference (name)) - { - t = strchr (name, '['); - *t++ = '\0'; - unset_array++; - } -#endif - - var = unset_function ? find_function (name) : find_variable (name); - - if (var && !unset_function && non_unsettable_p (var)) - { - builtin_error ("%s: cannot unset", name); - NEXT_VARIABLE (); - } - - /* Posix.2 says that unsetting readonly variables is an error. */ - if (var && readonly_p (var)) - { - builtin_error ("%s: cannot unset: readonly %s", - name, unset_function ? "function" : "variable"); - NEXT_VARIABLE (); - } - - /* Unless the -f option is supplied, the name refers to a variable. */ -#if defined (ARRAY_VARS) - if (var && unset_array) - { - if (array_p (var) == 0) - { - builtin_error ("%s: not an array variable", name); - NEXT_VARIABLE (); - } - else - tem = unbind_array_element (var, t); - } - else -#endif /* ARRAY_VARS */ - tem = makunbound (name, unset_function ? shell_functions : shell_variables); - - /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v - is specified, the name refers to a variable; if a variable by - that name does not exist, a function by that name, if any, - shall be unset.'' */ - if ((tem == -1) && !unset_function && !unset_variable) - tem = makunbound (name, shell_functions); - - if (tem == -1) - any_failed++; - else if (!unset_function) - stupidly_hack_special_variables (name); - - list = list->next; - } - - if (any_failed) - return (EXECUTION_FAILURE); - else - return (EXECUTION_SUCCESS); -} diff --git a/CWRU/save/unwind_prot.h.save b/CWRU/save/unwind_prot.h.save deleted file mode 100644 index 998fd72b6..000000000 --- a/CWRU/save/unwind_prot.h.save +++ /dev/null @@ -1,50 +0,0 @@ -/* unwind_prot.h - Macros and functions for hacking unwind protection. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#if !defined (_UNWIND_PROT_H) -#define _UNWIND_PROT_H - -/* Run a function without interrupts. */ -extern void begin_unwind_frame (); -extern void discard_unwind_frame (); -extern void run_unwind_frame (); -extern void add_unwind_protect (); -extern void remove_unwind_protect (); -extern void run_unwind_protects (); -extern void unwind_protect_var (); - -/* Define for people who like their code to look a certain way. */ -#define end_unwind_frame() - -/* How to protect an integer. */ -#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int)) - -/* How to protect a pointer to a string. */ -#define unwind_protect_string(X) \ - unwind_protect_var ((int *)&(X), (X), sizeof (char *)) - -/* How to protect any old pointer. */ -#define unwind_protect_pointer(X) unwind_protect_string (X) - -/* How to protect the contents of a jmp_buf. */ -#define unwind_protect_jmp_buf(X) \ - unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t)) - -#endif /* _UNWIND_PROT_H */ diff --git a/bashline.c~ b/bashline.c~ deleted file mode 100644 index 79ad03068..000000000 --- a/bashline.c~ +++ /dev/null @@ -1,4280 +0,0 @@ -/* 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/common.c~ b/builtins/common.c~ deleted file mode 100644 index cfa14215a..000000000 --- a/builtins/common.c~ +++ /dev/null @@ -1,918 +0,0 @@ -/* common.c - utility functions for all builtins */ - -/* Copyright (C) 1987-2010 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include -#include "../bashtypes.h" -#include "posixstat.h" -#include - -#include - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#define NEED_FPURGE_DECL - -#include "../shell.h" -#include "maxpath.h" -#include "../flags.h" -#include "../jobs.h" -#include "../builtins.h" -#include "../input.h" -#include "../execute_cmd.h" -#include "../trap.h" -#include "bashgetopt.h" -#include "common.h" -#include "builtext.h" -#include - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int indirection_level, subshell_environment; -extern int line_number; -extern int last_command_exit_value; -extern int trap_saved_exit_value; -extern int running_trap; -extern int posixly_correct; -extern char *this_command_name, *shell_name; -extern const char * const bash_getcwd_errstr; - -/* Used by some builtins and the mainline code. */ -sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL; -sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL; - -/* **************************************************************** */ -/* */ -/* Error reporting, usage, and option processing */ -/* */ -/* **************************************************************** */ - -/* This is a lot like report_error (), but it is for shell builtins - instead of shell control structures, and it won't ever exit the - shell. */ - -static void -builtin_error_prolog () -{ - char *name; - - name = get_name_for_error (); - fprintf (stderr, "%s: ", name); - - if (interactive_shell == 0) - fprintf (stderr, _("line %d: "), executing_line_number ()); - - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); -} - -void -#if defined (PREFER_STDARG) -builtin_error (const char *format, ...) -#else -builtin_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - builtin_error_prolog (); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} - -void -#if defined (PREFER_STDARG) -builtin_warning (const char *format, ...) -#else -builtin_warning (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - builtin_error_prolog (); - fprintf (stderr, _("warning: ")); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} - -/* Print a usage summary for the currently-executing builtin command. */ -void -builtin_usage () -{ - if (this_command_name && *this_command_name) - fprintf (stderr, _("%s: usage: "), this_command_name); - fprintf (stderr, "%s\n", _(current_builtin->short_doc)); - fflush (stderr); -} - -/* Return if LIST is NULL else barf and jump to top_level. Used by some - builtins that do not accept arguments. */ -void -no_args (list) - WORD_LIST *list; -{ - if (list) - { - builtin_error (_("too many arguments")); - top_level_cleanup (); - jump_to_top_level (DISCARD); - } -} - -/* Check that no options were given to the currently-executing builtin, - and return 0 if there were options. */ -int -no_options (list) - WORD_LIST *list; -{ - int opt; - - reset_internal_getopt (); - if ((opt = internal_getopt (list, "")) != -1) - { - if (opt == GETOPT_HELP) - { - builtin_help (); - return (2); - } - builtin_usage (); - return (1); - } - return (0); -} - -void -sh_needarg (s) - char *s; -{ - builtin_error (_("%s: option requires an argument"), s); -} - -void -sh_neednumarg (s) - char *s; -{ - builtin_error (_("%s: numeric argument required"), s); -} - -void -sh_notfound (s) - char *s; -{ - builtin_error (_("%s: not found"), s); -} - -/* Function called when one of the builtin commands detects an invalid - option. */ -void -sh_invalidopt (s) - char *s; -{ - builtin_error (_("%s: invalid option"), s); -} - -void -sh_invalidoptname (s) - char *s; -{ - builtin_error (_("%s: invalid option name"), s); -} - -void -sh_invalidid (s) - char *s; -{ - builtin_error (_("`%s': not a valid identifier"), s); -} - -void -sh_invalidnum (s) - char *s; -{ - char *msg; - - if (*s == '0' && isdigit (s[1])) - msg = _("invalid octal number"); - else if (*s == '0' && s[1] == 'x') - msg = _("invalid hex number"); - else - msg = _("invalid number"); - builtin_error ("%s: %s", s, msg); -} - -void -sh_invalidsig (s) - char *s; -{ - builtin_error (_("%s: invalid signal specification"), s); -} - -void -sh_badpid (s) - char *s; -{ - builtin_error (_("`%s': not a pid or valid job spec"), s); -} - -void -sh_readonly (s) - const char *s; -{ - builtin_error (_("%s: readonly variable"), s); -} - -void -sh_erange (s, desc) - char *s, *desc; -{ - if (s) - builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument")); - else - builtin_error (_("%s out of range"), desc ? desc : _("argument")); -} - -#if defined (JOB_CONTROL) -void -sh_badjob (s) - char *s; -{ - builtin_error (_("%s: no such job"), s); -} - -void -sh_nojobs (s) - char *s; -{ - if (s) - builtin_error (_("%s: no job control"), s); - else - builtin_error (_("no job control")); -} -#endif - -#if defined (RESTRICTED_SHELL) -void -sh_restricted (s) - char *s; -{ - if (s) - builtin_error (_("%s: restricted"), s); - else - builtin_error (_("restricted")); -} -#endif - -void -sh_notbuiltin (s) - char *s; -{ - builtin_error (_("%s: not a shell builtin"), s); -} - -void -sh_wrerror () -{ -#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE) - if (errno != EPIPE) -#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */ - builtin_error (_("write error: %s"), strerror (errno)); -} - -void -sh_ttyerror (set) - int set; -{ - if (set) - builtin_error (_("error setting terminal attributes: %s"), strerror (errno)); - else - builtin_error (_("error getting terminal attributes: %s"), strerror (errno)); -} - -int -sh_chkwrite (s) - int s; -{ - fflush (stdout); - if (ferror (stdout)) - { - sh_wrerror (); - fpurge (stdout); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - return (s); -} - -/* **************************************************************** */ -/* */ -/* Shell positional parameter manipulation */ -/* */ -/* **************************************************************** */ - -/* Convert a WORD_LIST into a C-style argv. Return the number of elements - in the list in *IP, if IP is non-null. A convenience function for - loadable builtins; also used by `test'. */ -char ** -make_builtin_argv (list, ip) - WORD_LIST *list; - int *ip; -{ - char **argv; - - argv = strvec_from_word_list (list, 0, 1, ip); - argv[0] = this_command_name; - return argv; -} - -/* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is - non-zero, then discard whatever the existing arguments are, else - only discard the ones that are to be replaced. */ -void -remember_args (list, destructive) - WORD_LIST *list; - int destructive; -{ - register int i; - - for (i = 1; i < 10; i++) - { - if ((destructive || list) && dollar_vars[i]) - { - free (dollar_vars[i]); - dollar_vars[i] = (char *)NULL; - } - - if (list) - { - dollar_vars[i] = savestring (list->word->word); - list = list->next; - } - } - - /* If arguments remain, assign them to REST_OF_ARGS. - Note that copy_word_list (NULL) returns NULL, and - that dispose_words (NULL) does nothing. */ - if (destructive || list) - { - dispose_words (rest_of_args); - rest_of_args = copy_word_list (list); - } - - if (destructive) - set_dollar_vars_changed (); - - invalidate_cached_quoted_dollar_at (); -} - -static int changed_dollar_vars; - -/* Have the dollar variables been reset to new values since we last - checked? */ -int -dollar_vars_changed () -{ - return (changed_dollar_vars); -} - -void -set_dollar_vars_unchanged () -{ - changed_dollar_vars = 0; -} - -void -set_dollar_vars_changed () -{ - if (variable_context) - changed_dollar_vars |= ARGS_FUNC; - else if (this_shell_builtin == set_builtin) - changed_dollar_vars |= ARGS_SETBLTIN; - else - changed_dollar_vars |= ARGS_INVOC; -} - -/* **************************************************************** */ -/* */ -/* Validating numeric input and arguments */ -/* */ -/* **************************************************************** */ - -/* Read a numeric arg for this_command_name, the name of the shell builtin - that wants it. LIST is the word list that the arg is to come from. - Accept only the numeric argument; report an error if other arguments - follow. If FATAL is 1, call throw_to_top_level, which exits the - shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the - current command; if FATAL is 0, return an indication of an invalid - number by setting *NUMOK == 0 and return -1. */ -int -get_numeric_arg (list, fatal, count) - WORD_LIST *list; - int fatal; - intmax_t *count; -{ - char *arg; - - if (count) - *count = 1; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list) - { - arg = list->word->word; - if (arg == 0 || (legal_number (arg, count) == 0)) - { - sh_neednumarg (list->word->word ? list->word->word : "`'"); - if (fatal == 0) - return 0; - else if (fatal == 1) /* fatal == 1; abort */ - throw_to_top_level (); - else /* fatal == 2; discard current command */ - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - no_args (list->next); - } - - return (1); -} - -/* Get an eight-bit status value from LIST */ -int -get_exitstat (list) - WORD_LIST *list; -{ - int status; - intmax_t sval; - char *arg; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list == 0) - { - /* If we're not running the DEBUG trap, the return builtin, when not - given any arguments, uses the value of $? before the trap ran. If - given an argument, return uses it. This means that the trap can't - change $?. The DEBUG trap gets to change $?, though, since that is - part of its reason for existing, and because the extended debug mode - does things with the return value. */ - if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1) - return (trap_saved_exit_value); - return (last_command_exit_value); - } - - arg = list->word->word; - if (arg == 0 || legal_number (arg, &sval) == 0) - { - sh_neednumarg (list->word->word ? list->word->word : "`'"); - return EX_BADUSAGE; - } - no_args (list->next); - - status = sval & 255; - return status; -} - -/* Return the octal number parsed from STRING, or -1 to indicate - that the string contained a bad number. */ -int -read_octal (string) - char *string; -{ - int result, digits; - - result = digits = 0; - while (*string && ISOCTAL (*string)) - { - digits++; - result = (result * 8) + (*string++ - '0'); - if (result > 0777) - return -1; - } - - if (digits == 0 || *string) - result = -1; - - return (result); -} - -/* **************************************************************** */ -/* */ -/* Manipulating the current working directory */ -/* */ -/* **************************************************************** */ - -/* Return a consed string which is the current working directory. - FOR_WHOM is the name of the caller for error printing. */ -char *the_current_working_directory = (char *)NULL; - -char * -get_working_directory (for_whom) - char *for_whom; -{ - if (no_symbolic_links) - { - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - } - - if (the_current_working_directory == 0) - { -#if defined (GETCWD_BROKEN) - the_current_working_directory = getcwd (0, PATH_MAX); -#else - the_current_working_directory = getcwd (0, 0); -#endif - if (the_current_working_directory == 0) - { - fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"), - (for_whom && *for_whom) ? for_whom : get_name_for_error (), - _(bash_getcwd_errstr), strerror (errno)); - return (char *)NULL; - } - } - - return (savestring (the_current_working_directory)); -} - -/* Make NAME our internal idea of the current working directory. */ -void -set_working_directory (name) - char *name; -{ - FREE (the_current_working_directory); - the_current_working_directory = savestring (name); -} - -/* **************************************************************** */ -/* */ -/* Job control support functions */ -/* */ -/* **************************************************************** */ - -#if defined (JOB_CONTROL) -int -get_job_by_name (name, flags) - const char *name; - int flags; -{ - register int i, wl, cl, match, job; - register PROCESS *p; - register JOB *j; - - job = NO_JOB; - wl = strlen (name); - for (i = js.j_jobslots - 1; i >= 0; i--) - { - j = get_job_by_jid (i); - if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED)) - continue; - - p = j->pipe; - do - { - if (flags & JM_EXACT) - { - cl = strlen (p->command); - match = STREQN (p->command, name, cl); - } - else if (flags & JM_SUBSTRING) - match = strcasestr (p->command, name) != (char *)0; - else - match = STREQN (p->command, name, wl); - - if (match == 0) - { - p = p->next; - continue; - } - else if (flags & JM_FIRSTMATCH) - return i; /* return first match */ - else if (job != NO_JOB) - { - if (this_shell_builtin) - builtin_error (_("%s: ambiguous job spec"), name); - else - internal_error (_("%s: ambiguous job spec"), name); - return (DUP_JOB); - } - else - job = i; - } - while (p != j->pipe); - } - - return (job); -} - -/* Return the job spec found in LIST. */ -int -get_job_spec (list) - WORD_LIST *list; -{ - register char *word; - int job, jflags; - - if (list == 0) - return (js.j_current); - - word = list->word->word; - - if (*word == '\0') - return (NO_JOB); - - if (*word == '%') - word++; - - if (DIGIT (*word) && all_digits (word)) - { - job = atoi (word); - return (job > js.j_jobslots ? NO_JOB : job - 1); - } - - jflags = 0; - switch (*word) - { - case 0: - case '%': - case '+': - return (js.j_current); - - case '-': - return (js.j_previous); - - case '?': /* Substring search requested. */ - jflags |= JM_SUBSTRING; - word++; - /* FALLTHROUGH */ - - default: - return get_job_by_name (word, jflags); - } -} -#endif /* JOB_CONTROL */ - -/* - * NOTE: `kill' calls this function with forcecols == 0 - */ -int -display_signal_list (list, forcecols) - WORD_LIST *list; - int forcecols; -{ - register int i, column; - char *name; - int result, signum, dflags; - intmax_t lsignum; - - result = EXECUTION_SUCCESS; - if (!list) - { - for (i = 1, column = 0; i < NSIG; i++) - { - name = signal_name (i); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - continue; - - if (posixly_correct && !forcecols) - { - /* This is for the kill builtin. POSIX.2 says the signal names - are displayed without the `SIG' prefix. */ - if (STREQN (name, "SIG", 3)) - name += 3; - printf ("%s%s", name, (i == NSIG - 1) ? "" : " "); - } - else - { - printf ("%2d) %s", i, name); - - if (++column < 5) - printf ("\t"); - else - { - printf ("\n"); - column = 0; - } - } - } - - if ((posixly_correct && !forcecols) || column != 0) - printf ("\n"); - return result; - } - - /* List individual signal names or numbers. */ - while (list) - { - if (legal_number (list->word->word, &lsignum)) - { - /* This is specified by Posix.2 so that exit statuses can be - mapped into signal numbers. */ - if (lsignum > 128) - lsignum -= 128; - if (lsignum < 0 || lsignum >= NSIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - - signum = lsignum; - name = signal_name (signum); - if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7)) - { - list = list->next; - continue; - } -#if defined (JOB_CONTROL) - /* POSIX.2 says that `kill -l signum' prints the signal name without - the `SIG' prefix. */ - printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name); -#else - printf ("%s\n", name); -#endif - } - else - { - dflags = DSIG_NOCASE; - if (posixly_correct == 0 || this_shell_builtin != kill_builtin) - dflags |= DSIG_SIGPREFIX; - signum = decode_signal (list->word->word, dflags); - if (signum == NO_SIG) - { - sh_invalidsig (list->word->word); - result = EXECUTION_FAILURE; - list = list->next; - continue; - } - printf ("%d\n", signum); - } - list = list->next; - } - return (result); -} - -/* **************************************************************** */ -/* */ -/* Finding builtin commands and their functions */ -/* */ -/* **************************************************************** */ - -/* Perform a binary search and return the address of the builtin function - whose name is NAME. If the function couldn't be found, or the builtin - is disabled or has no function associated with it, return NULL. - Return the address of the builtin. - DISABLED_OKAY means find it even if the builtin is disabled. */ -struct builtin * -builtin_address_internal (name, disabled_okay) - char *name; - int disabled_okay; -{ - int hi, lo, mid, j; - - hi = num_shell_builtins - 1; - lo = 0; - - while (lo <= hi) - { - mid = (lo + hi) / 2; - - j = shell_builtins[mid].name[0] - name[0]; - - if (j == 0) - j = strcmp (shell_builtins[mid].name, name); - - if (j == 0) - { - /* It must have a function pointer. It must be enabled, or we - must have explicitly allowed disabled functions to be found, - and it must not have been deleted. */ - if (shell_builtins[mid].function && - ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) && - ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay)) - return (&shell_builtins[mid]); - else - return ((struct builtin *)NULL); - } - if (j > 0) - hi = mid - 1; - else - lo = mid + 1; - } - return ((struct builtin *)NULL); -} - -/* Return the pointer to the function implementing builtin command NAME. */ -sh_builtin_func_t * -find_shell_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the address of builtin with NAME, whether it is enabled or not. */ -sh_builtin_func_t * -builtin_address (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 1); - return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL); -} - -/* Return the function implementing the builtin NAME, but only if it is a - POSIX.2 special builtin. */ -sh_builtin_func_t * -find_special_builtin (name) - char *name; -{ - current_builtin = builtin_address_internal (name, 0); - return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ? - current_builtin->function : - (sh_builtin_func_t *)NULL); -} - -static int -shell_builtin_compare (sbp1, sbp2) - struct builtin *sbp1, *sbp2; -{ - int result; - - if ((result = sbp1->name[0] - sbp2->name[0]) == 0) - result = strcmp (sbp1->name, sbp2->name); - - return (result); -} - -/* Sort the table of shell builtins so that the binary search will work - in find_shell_builtin. */ -void -initialize_shell_builtins () -{ - qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin), - (QSFUNC *)shell_builtin_compare); -} - -#if !defined (HELP_BUILTIN) -void -builtin_help () -{ - printf ("%s: %s\n", this_command_name, _("help not available in this version")); -} -#endif diff --git a/builtins/complete.def~ b/builtins/complete.def~ deleted file mode 100644 index 0a292ac7a..000000000 --- a/builtins/complete.def~ +++ /dev/null @@ -1,874 +0,0 @@ -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/umask.def~ b/builtins/umask.def~ deleted file mode 100644 index d9aa04183..000000000 --- a/builtins/umask.def~ +++ /dev/null @@ -1,312 +0,0 @@ -This file is umask.def, from which is created umask.c. -It implements the builtin "umask" in Bash. - -Copyright (C) 1987-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES umask.c - -$BUILTIN umask -$FUNCTION umask_builtin -$SHORT_DOC umask [-p] [-S] [mode] -Display or set file mode mask. - -Sets the user file-creation mask to MODE. If MODE is omitted, prints -the current value of the mask. - -If MODE begins with a digit, it is interpreted as an octal number; -otherwise it is a symbolic mode string like that accepted by chmod(1). - -Options: - -p if MODE is omitted, output in a form that may be reused as input - -S makes the output symbolic; otherwise an octal number is output - -Exit Status: -Returns success unless MODE is invalid or an invalid option is given. -$END - -#include - -#include "../bashtypes.h" -#include "filecntl.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -#include -#endif - -#include -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "posixstat.h" -#include "common.h" -#include "bashgetopt.h" - -/* **************************************************************** */ -/* */ -/* UMASK Builtin and Helpers */ -/* */ -/* **************************************************************** */ - -static void print_symbolic_umask __P((mode_t)); -static int symbolic_umask __P((WORD_LIST *)); - -/* Set or display the mask used by the system when creating files. Flag - of -S means display the umask in a symbolic mode. */ -int -umask_builtin (list) - WORD_LIST *list; -{ - int print_symbolically, opt, umask_value, pflag; - mode_t umask_arg; - - print_symbolically = pflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "Sp")) != -1) - { - switch (opt) - { - case 'S': - print_symbolically++; - break; - case 'p': - pflag++; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (list) - { - if (DIGIT (*list->word->word)) - { - umask_value = read_octal (list->word->word); - - /* Note that other shells just let you set the umask to zero - by specifying a number out of range. This is a problem - with those shells. We don't change the umask if the input - is lousy. */ - if (umask_value == -1) - { - sh_erange (list->word->word, _("octal number")); - return (EXECUTION_FAILURE); - } - } - else - { - umask_value = symbolic_umask (list); - if (umask_value == -1) - return (EXECUTION_FAILURE); - } - umask_arg = (mode_t)umask_value; - umask (umask_arg); - if (print_symbolically) - print_symbolic_umask (umask_arg); - } - else /* Display the UMASK for this user. */ - { - umask_arg = umask (022); - umask (umask_arg); - - if (pflag) - printf ("umask%s ", (print_symbolically ? " -S" : "")); - if (print_symbolically) - print_symbolic_umask (umask_arg); - else - printf ("%04lo\n", (unsigned long)umask_arg); - } - - return (sh_chkwrite (EXECUTION_SUCCESS)); -} - -/* Print the umask in a symbolic form. In the output, a letter is - printed if the corresponding bit is clear in the umask. */ -static void -print_symbolic_umask (um) - mode_t um; -{ - char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ - int i; - - i = 0; - if ((um & S_IRUSR) == 0) - ubits[i++] = 'r'; - if ((um & S_IWUSR) == 0) - ubits[i++] = 'w'; - if ((um & S_IXUSR) == 0) - ubits[i++] = 'x'; - ubits[i] = '\0'; - - i = 0; - if ((um & S_IRGRP) == 0) - gbits[i++] = 'r'; - if ((um & S_IWGRP) == 0) - gbits[i++] = 'w'; - if ((um & S_IXGRP) == 0) - gbits[i++] = 'x'; - gbits[i] = '\0'; - - i = 0; - if ((um & S_IROTH) == 0) - obits[i++] = 'r'; - if ((um & S_IWOTH) == 0) - obits[i++] = 'w'; - if ((um & S_IXOTH) == 0) - obits[i++] = 'x'; - obits[i] = '\0'; - - printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits); -} - -int -parse_symbolic_mode (mode, initial_bits) - char *mode; - int initial_bits; -{ - int who, op, perm, bits, c; - char *s; - - for (s = mode, bits = initial_bits;;) - { - who = op = perm = 0; - - /* Parse the `who' portion of the symbolic mode clause. */ - while (member (*s, "agou")) - { - switch (c = *s++) - { - case 'u': - who |= S_IRWXU; - continue; - case 'g': - who |= S_IRWXG; - continue; - case 'o': - who |= S_IRWXO; - continue; - case 'a': - who |= S_IRWXU | S_IRWXG | S_IRWXO; - continue; - default: - break; - } - } - - /* The operation is now sitting in *s. */ - op = *s++; - switch (op) - { - case '+': - case '-': - case '=': - break; - default: - builtin_error (_("`%c': invalid symbolic mode operator"), op); - return (-1); - } - - /* Parse out the `perm' section of the symbolic mode clause. */ - while (member (*s, "rwx")) - { - c = *s++; - - switch (c) - { - case 'r': - perm |= S_IRUGO; - break; - case 'w': - perm |= S_IWUGO; - break; - case 'x': - perm |= S_IXUGO; - break; - } - } - - /* Now perform the operation or return an error for a - bad permission string. */ - if (!*s || *s == ',') - { - if (who) - perm &= who; - - switch (op) - { - case '+': - bits |= perm; - break; - case '-': - bits &= ~perm; - break; - case '=': - if (who == 0) - who = S_IRWXU | S_IRWXG | S_IRWXO; - bits &= ~who; - bits |= perm; - break; - - /* No other values are possible. */ - } - - if (*s == '\0') - break; - else - s++; /* skip past ',' */ - } - else - { - builtin_error (_("`%c': invalid symbolic mode character"), *s); - return (-1); - } - } - - return (bits); -} - -/* Set the umask from a symbolic mode string similar to that accepted - by chmod. If the -S argument is given, then print the umask in a - symbolic form. */ -static int -symbolic_umask (list) - WORD_LIST *list; -{ - int um, bits; - - /* Get the initial umask. Don't change it yet. */ - um = umask (022); - umask (um); - - /* All work is done with the complement of the umask -- it's - more intuitive and easier to deal with. It is complemented - again before being returned. */ - bits = parse_symbolic_mode (list->word->word, ~um & 0777); - if (bits == -1) - return (-1); - - um = ~bits & 0777; - return (um); -} diff --git a/builtins/wait.def~ b/builtins/wait.def~ deleted file mode 100644 index 2de7bfb6e..000000000 --- a/builtins/wait.def~ +++ /dev/null @@ -1,218 +0,0 @@ -This file is wait.def, from which is created wait.c. -It implements the builtin "wait" in Bash. - -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 . - -$BUILTIN wait -$FUNCTION wait_builtin -$DEPENDS_ON JOB_CONTROL -$PRODUCES wait.c -$SHORT_DOC wait [-n] [id ...] -Wait for job completion and return exit status. - -Waits for each process identified by an ID, which may be a process ID or a -job specification, and reports its termination status. If ID is not -given, waits for all currently active child processes, and the return -status is zero. If ID is a a job specification, waits for all processes -in that job's pipeline. - -If the -n option is supplied, waits for the next job to terminate and -returns its exit status. - -Exit Status: -Returns the status of the last ID; fails if ID is invalid or an invalid -option is given. -$END - -$BUILTIN wait -$FUNCTION wait_builtin -$DEPENDS_ON !JOB_CONTROL -$SHORT_DOC wait [pid ...] -Wait for process completion and return exit status. - -Waits for each process specified by a PID and reports its termination status. -If PID is not given, waits for all currently active child processes, -and the return status is zero. PID must be a process ID. - -Exit Status: -Returns the status of the last PID; fails if PID is invalid or an invalid -option is given. -$END - -#include - -#include "../bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#include "../bashansi.h" - -#include "../shell.h" -#include "../jobs.h" -#include "common.h" -#include "bashgetopt.h" - -extern int wait_signal_received; -extern int last_command_exit_signal; - -procenv_t wait_intr_buf; - -/* Wait for the pid in LIST to stop or die. If no arguments are given, then - wait for all of the active background processes of the shell and return - 0. If a list of pids or job specs are given, return the exit status of - the last one waited for. */ - -#define WAIT_RETURN(s) \ - do \ - { \ - interrupt_immediately = old_interrupt_immediately;\ - wait_signal_received = 0; \ - return (s);\ - } \ - while (0) - -int -wait_builtin (list) - WORD_LIST *list; -{ - int status, code, opt, nflag; - volatile int old_interrupt_immediately; - - USE_VAR(list); - - nflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "n")) != -1) - { - switch (opt) - { -#if defined (JOB_CONTROL) - case 'n': - nflag = 1; - break; -#endif - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - old_interrupt_immediately = interrupt_immediately; -#if 0 - interrupt_immediately++; -#endif - - /* POSIX.2 says: When the shell is waiting (by means of the wait utility) - for asynchronous commands to complete, the reception of a signal for - which a trap has been set shall cause the wait utility to return - immediately with an exit status greater than 128, after which the trap - associated with the signal shall be taken. - - We handle SIGINT here; it's the only one that needs to be treated - specially (I think), since it's handled specially in {no,}jobs.c. */ - code = setjmp_sigs (wait_intr_buf); - if (code) - { - last_command_exit_signal = wait_signal_received; - status = 128 + wait_signal_received; - WAIT_RETURN (status); - } - - /* We support jobs or pids. - wait [pid-or-job ...] */ - -#if defined (JOB_CONTROL) - if (nflag) - { - status = wait_for_any_job (); - if (status < 0) - status = 127; - WAIT_RETURN (status); - } -#endif - - /* But wait without any arguments means to wait for all of the shell's - currently active background processes. */ - if (list == 0) - { - wait_for_background_pids (); - WAIT_RETURN (EXECUTION_SUCCESS); - } - - status = EXECUTION_SUCCESS; - while (list) - { - pid_t pid; - char *w; - intmax_t pid_value; - - w = list->word->word; - if (DIGIT (*w)) - { - if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value) - { - pid = (pid_t)pid_value; - status = wait_for_single_pid (pid); - } - else - { - sh_badpid (w); - WAIT_RETURN (EXECUTION_FAILURE); - } - } -#if defined (JOB_CONTROL) - else if (*w && *w == '%') - /* Must be a job spec. Check it out. */ - { - int job; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - job = get_job_spec (list); - - if (INVALID_JOB (job)) - { - if (job != DUP_JOB) - sh_badjob (list->word->word); - UNBLOCK_CHILD (oset); - status = 127; /* As per Posix.2, section 4.70.2 */ - list = list->next; - continue; - } - - /* Job spec used. Wait for the last pid in the pipeline. */ - UNBLOCK_CHILD (oset); - status = wait_for_job (job); - } -#endif /* JOB_CONTROL */ - else - { - sh_badpid (w); - status = EXECUTION_FAILURE; - } - list = list->next; - } - - WAIT_RETURN (status); -} diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old deleted file mode 100644 index 640390fbf..000000000 --- a/cross-build/cygwin32.cache.old +++ /dev/null @@ -1,42 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests for CYGWIN32 so they don't need to be done when cross-compiling. - -# AC_FUNC_GETPGRP should also define GETPGRP_VOID -ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} -# AC_FUNC_SETVBUF_REVERSED should not define anything else -ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} -# on CYGWIN32, system calls do not restart -ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} -bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} - -# these may be necessary, but they are currently commented out -#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} -ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} -ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} -ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} -ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} - -bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} -bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} -bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} -bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} -bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} -bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} -bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} -bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} -bash_cv_printf_declared=${bash_cv_printf_declared='yes'} -bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} -bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} -bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} -bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} -bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} -bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} -bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} -bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} - -bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} -bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} - -ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} - -# end of cross-build/cygwin32.cache diff --git a/doc/FAQ.orig b/doc/FAQ.orig deleted file mode 100644 index 1cff3c8ef..000000000 --- a/doc/FAQ.orig +++ /dev/null @@ -1,1745 +0,0 @@ -This is the Bash FAQ, version 3.24, for Bash version 2.05b. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet@po.cwru.edu. - -This document is available for anonymous FTP with the URL - -ftp://ftp.cwru.edu/pub/bash/FAQ - -The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html - ----------- -Contents: - -Section A: The Basics - -A1) What is it? -A2) What's the latest version? -A3) Where can I get it? -A4) On what machines will bash run? -A5) Will bash run on operating systems other than Unix? -A6) How can I build bash with gcc? -A7) How can I make bash my login shell? -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? -A9) What's the `POSIX 1003.2 standard'? -A10) What is the bash `posix mode'? - -Section B: The latest version - -B1) What's new in version 2.05b? -B2) Are there any user-visible incompatibilities between bash-2.05b and - bash-1.14.7? - -Section C: Differences from other Unix shells - -C1) How does bash differ from sh, the Bourne shell? -C2) How does bash differ from the Korn shell, version ksh88? -C3) Which new features in ksh-93 are not in bash, and which are? - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? -D2) Why doesn't bash treat brace expansions exactly like csh? -D3) Why doesn't bash have csh variable modifiers? -D4) How can I make my csh aliases work when I convert to bash? -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -Section E: Why does bash do certain things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? -E2) Why does bash sometimes say `Broken pipe'? -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? -E4) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? -E5) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? -E6) Why doesn't a while or for loop get suspended when I type ^Z? -E7) What about empty for loops in Makefiles? -E8) Why does the arithmetic evaluation code complain about `08'? -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? -E10) Why does `cd //' leave $PWD as `//'? -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? -G5) How do I get the current directory into my prompt? -G6) How can I rename "*.foo" to "*.bar"? -G7) How can I translate a filename from uppercase to lowercase? -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? -H2) What kind of bash documentation is there? -H3) What's coming in future versions? -H4) What's on the bash `wish list'? -H5) When will the next release appear? - ----------- -Section A: The Basics - -A1) What is it? - -Bash is a Unix command interpreter (shell). It is an implementation of -the Posix 1003.2 shell standard, and resembles the Korn and System V -shells. - -Bash contains a number of enhancements over those shells, both -for interactive use and shell programming. Features geared -toward interactive use include command line editing, command -history, job control, aliases, and prompt expansion. Programming -features include additional variable expansions, shell -arithmetic, and a number of variables and options to control -shell behavior. - -Bash was originally written by Brian Fox of the Free Software -Foundation. The current developer and maintainer is Chet Ramey -of Case Western Reserve University. - -A2) What's the latest version? - -The latest version is 2.05b, first made available on Wednesday, 17 -July, 2002. - -A3) Where can I get it? - -Bash is the GNU project's shell, and so is available from the -master GNU archive site, ftp.gnu.org, and its mirrors. The -latest version is also available for FTP from ftp.cwru.edu. -The following URLs tell how to get version 2.05b: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz - -A4) On what machines will bash run? - -Bash has been ported to nearly every version of UNIX. All you -should have to do to build it on a machine for which a port -exists is to type `configure' and then `make'. The build process -will attempt to discover the version of UNIX you have and tailor -itself accordingly, using a script created by GNU autoconf. - -More information appears in the file `INSTALL' in the distribution. - -The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html) -explains how to obtain binary versions of bash for most of the major -commercial Unix systems. - -A5) Will bash run on operating systems other than Unix? - -Configuration specifics for Unix-like systems such as QNX and -LynxOS are included in the distribution. Bash-2.05 and later -versions should compile and run on Minix 2.0 (patches were -contributed), but I don't believe anyone has built bash-2.x on -earlier Minix versions yet. - -Bash has been ported to versions of Windows implementing the Win32 -programming interface. This includes Windows 95 and Windows NT. -The port was done by Cygnus Solutions as part of their CYGWIN -project. For more information about the project, look at the URLs - -http://www.cygwin.com/ -http://sourceware.cygnus.com/cygwin - -Cygnus originally ported bash-1.14.7, and that port was part of their -early GNU-Win32 (the original name) releases. Cygnus has also done a -port of bash-2.05 to the CYGWIN environment, and it is available as -part of their current release. - -Bash-2.05b should require no local Cygnus changes to build and run under -CYGWIN. - -The Cygnus port works only on Intel machines. There is a port of bash -(I don't know which version) to the alpha/NT environment available from - -ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz - -DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part -of the DJGPP project. For more information on the project, see - -http://www.delorie.com/djgpp/ - -I have been told that the original DJGPP port was done by Daisuke Aoyama. - -Mark Elbrecht has sent me notice that bash-2.04 -is available for DJGPP V2. The files are available as: - -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation -ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source - -Mark has begun to work with bash-2.05, but I don't know the status. - -Ports of bash-1.12 and bash-2.0 are available for OS/2 from - -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip -ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip - -I haven't looked at either, but the second appears to be a binary-only -distribution. Beware. - -I have received word that Bash (I'm not sure which version, but I -believe that it's at least bash-2.02.1) is the standard shell on -BeOS. - -A6) How can I build bash with gcc? - -Bash configures to use gcc by default if it is available. Read the -file INSTALL in the distribution for more information. - -A7) How can I make bash my login shell? - -Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s' or `passwd -e'. If one of these works for -you, that's all you need. Note that many systems require the full -pathname to a shell to appear in /etc/shells before you can make it -your login shell. For this, you may need the assistance of your -friendly local system administrator. - -If you cannot do this, you can still use bash as your login shell, but -you need to perform some tricks. The basic idea is to add a command -to your login shell's startup file to replace your login shell with -bash. - -For example, if your login shell is csh or tcsh, and you have installed -bash in /usr/gnu/bin/bash, add the following line to ~/.login: - - if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login - -(the `--login' tells bash that it is a login shell). - -It's not a good idea to put this command into ~/.cshrc, because every -csh you run without the `-f' option, even ones started to run csh scripts, -reads that file. If you must put the command in ~/.cshrc, use something -like - - if ( $?prompt ) exec /usr/gnu/bin/bash --login - -to ensure that bash is exec'd only when the csh is interactive. - -If your login shell is sh or ksh, you have to do two things. - -First, create an empty file in your home directory named `.bash_profile'. -The existence of this file will prevent the exec'd bash from trying to -read ~/.profile, and re-execing itself over and over again. ~/.bash_profile -is the first file bash tries to read initialization commands from when -it is invoked as a login shell. - -Next, add a line similar to the above to ~/.profile: - - [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \ - exec /usr/gnu/bin/bash --login - -This will cause login shells to replace themselves with bash running as -a login shell. Once you have this working, you can copy your initialization -code from ~/.profile to ~/.bash_profile. - -I have received word that the recipe supplied above is insufficient for -machines running CDE. CDE has a maze of twisty little startup files, all -slightly different. - -If you cannot change your login shell in the password file to bash, you -will have to (apparently) live with CDE using the shell in the password -file to run its startup scripts. If you have changed your shell to bash, -there is code in the CDE startup files (on Solaris, at least) that attempts -to do the right thing. It is, however, often broken, and may require that -you use the $BASH_ENV trick described below. - -`dtterm' claims to use $SHELL as the default program to start, so if you -can change $SHELL in the CDE startup files, you should be able to use bash -in your terminal windows. - -Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program -to read your login shell's startup files. You may be able to use bash for -the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as -well, but I have not tried this. - -You can use the above `exec' recipe to start bash when not logging in with -CDE by testing the value of the DT variable: - - if [ -n "$DT" ]; then - [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login - fi - -If CDE starts its shells non-interactively during login, the login shell -startup files (~/.profile, ~/.bash_profile) will not be sourced at login. -To get around this problem, append a line similar to the following to your -~/.dtprofile: - - BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV - -and add the following line to the beginning of ~/.bash_profile: - - unset BASH_ENV - -A8) I just changed my login shell to bash, and now I can't FTP into my - machine. Why not? - -You must add the full pathname to bash to the file /etc/shells. As -noted in the answer to the previous question, many systems require -this before you can make bash your login shell. - -Most versions of ftpd use this file to prohibit `special' users -such as `uucp' and `news' from using FTP. - -A9) What's the `POSIX 1003.2 standard'? - -POSIX is a name originally coined by Richard Stallman for a -family of open system standards based on UNIX. There are a -number of aspects of UNIX under consideration for -standardization, from the basic system services at the system -call and C library level to applications and tools to system -administration and management. Each area of standardization is -assigned to a working group in the 1003 series. - -The POSIX Shell and Utilities standard has been developed by IEEE -Working Group 1003.2 (POSIX.2). It concentrates on the command -interpreter interface and utility programs commonly executed from -the command line or by other programs. An initial version of the -standard has been approved and published by the IEEE, and work is -currently underway to update it. - -Bash is concerned with the aspects of the shell's behavior -defined by POSIX.2. The shell command language has of course -been standardized, including the basic flow control and program -execution constructs, I/O redirection and pipelining, argument -handling, variable expansion, and quoting. - -The `special' builtins, which must be implemented as part of the -shell to provide the desired functionality, are specified as -being part of the shell; examples of these are `eval' and -`export'. Other utilities appear in the sections of POSIX.2 not -devoted to the shell which are commonly (and in some cases must -be) implemented as builtin commands, such as `read' and `test'. -POSIX.2 also specifies aspects of the shell's interactive -behavior as part of the UPE, including job control and command -line editing. Only vi-style line editing commands have been -standardized; emacs editing commands were left out due to -objections. - -The Open Group has made an older version of its Single Unix -Specification (version 2), which is very similar to POSIX.2, -available on the web at - -http://www.opengroup.org/onlinepubs/007908799/ - -The Single Unix Specification, version 3, is available on the web at - -http://www.opengroup.org/onlinepubs/007904975/ - -A10) What is the bash `posix mode'? - -Although bash is an implementation of the POSIX.2 shell -specification, there are areas where the bash default behavior -differs from that spec. The bash `posix mode' changes the bash -behavior in these areas so that it obeys the spec more closely. - -Posix mode is entered by starting bash with the --posix or -'-o posix' option or executing `set -o posix' after bash is running. - -The specific aspects of bash which change when posix mode is -active are listed in the file POSIX in the bash distribution. -They are also listed in a section in the Bash Reference Manual -(from which that file is generated). - -Section B: The latest version - -B1) What's new in version 2.05b? - -The raison d'etre for bash-2.05b is to make a second intermediate -release containing the first of the new features to be available -in bash-3.0 and get feedback on those features before proceeding. -The major new feature is multibyte character support in both Bash -and Readline. - -Bash-2.05b contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-2.05b -distribution): - -o support for multibyte characters has been added to both bash and readline - -o the DEBUG trap is now run *before* simple commands, ((...)) commands, - [[...]] conditional commands, and for ((...)) loops - -o the shell now performs arithmetic in the largest integer size the machine - supports (intmax_t) - -o there is a new \D{...} prompt expansion; passes the `...' to strftime(3) - and inserts the result into the expanded prompt - -o there is a new `here-string' redirection operator: <<< word - -o when displaying variables, function attributes and definitions are shown - separately, allowing them to be re-used as input (attempting to re-use - the old output would result in syntax errors). - -o `read' has a new `-u fd' option to read from a specified file descriptor - -o the bash debugger in examples/bashdb has been modified to work with the - new DEBUG trap semantics, the command set has been made more gdb-like, - and the changes to $LINENO make debugging functions work better - -o the expansion of $LINENO inside a shell function is only relative to the - function start if the shell is interactive -- if the shell is running a - script, $LINENO expands to the line number in the script. This is as - POSIX-2001 requires - - -A short feature history dating from Bash-2.0: - -Bash-2.05a introduced the following new features: - -o The `printf' builtin has undergone major work - -o There is a new read-only `shopt' option: login_shell, which is set by - login shells and unset otherwise - -o New `\A' prompt string escape sequence; expanding to time in 24-hour - HH:MM format - -o New `-A group/-g' option to complete and compgen; goes group name - completion - -o New [+-]O invocation option to set and unset `shopt' options at startup - -o ksh-like `ERR' trap - -o `for' loops now allow empty word lists after the `in' reserved word - -o new `hard' and `soft' arguments for the `ulimit' builtin - -o Readline can be configured to place the user at the same point on the line - when retrieving commands from the history list - -o Readline can be configured to skip `hidden' files (filenames with a leading - `.' on Unix) when performing completion - -Bash-2.05 introduced the following new features: - -o This version has once again reverted to using locales and strcoll(3) when - processing pattern matching bracket expressions, as POSIX requires. -o Added a new `--init-file' invocation argument as a synonym for `--rcfile', - per the new GNU coding standards. -o The /dev/tcp and /dev/udp redirections now accept service names as well as - port numbers. -o `complete' and `compgen' now take a `-o value' option, which controls some - of the aspects of that compspec. Valid values are: - - default - perform bash default completion if programmable - completion produces no matches - dirnames - perform directory name completion if programmable - completion produces no matches - filenames - tell readline that the compspec produces filenames, - so it can do things like append slashes to - directory names and suppress trailing spaces -o A new loadable builtin, realpath, which canonicalizes and expands symlinks - in pathname arguments. -o When `set' is called without options, it prints function defintions in a - way that allows them to be reused as input. This affects `declare' and - `declare -p' as well. This only happens when the shell is not in POSIX - mode, since POSIX.2 forbids this behavior. - -Bash-2.04 introduced the following new features: - -o Programmable word completion with the new `complete' and `compgen' builtins; - examples are provided in examples/complete/complete-examples -o `history' has a new `-d' option to delete a history entry -o `bind' has a new `-x' option to bind key sequences to shell commands -o The prompt expansion code has new `\j' and `\l' escape sequences -o The `no_empty_cmd_completion' shell option, if enabled, inhibits - command completion when TAB is typed on an empty line -o `help' has a new `-s' option to print a usage synopsis -o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma) -o New ksh93-style arithmetic for command: - for ((expr1 ; expr2; expr3 )); do list; done -o `read' has new options: `-t', `-n', `-d', `-s' -o The redirection code handles several filenames specially: /dev/fd/N, - /dev/stdin, /dev/stdout, /dev/stderr -o The redirection code now recognizes /dev/tcp/HOST/PORT and - /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively, - to the specified port on the specified host -o The ${!prefix*} expansion has been implemented -o A new FUNCNAME variable, which expands to the name of a currently-executing - function -o The GROUPS variable is no longer readonly -o A new shopt `xpg_echo' variable, to control the behavior of echo with - respect to backslash-escape sequences at runtime -o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned - -The version of Readline released with Bash-2.04, Readline-4.1, had several -new features as well: - -o Parentheses matching is always compiled into readline, and controllable - with the new `blink-matching-paren' variable -o The history-search-forward and history-search-backward functions now leave - point at the end of the line when the search string is empty, like - reverse-search-history, and forward-search-history -o A new function for applications: rl_on_new_line_with_prompt() -o New variables for applications: rl_already_prompted, and rl_gnu_readline_p - - -Bash-2.03 had very few new features, in keeping with the convention -that odd-numbered releases provide mainly bug fixes. A number of new -features were added to Readline, mostly at the request of the Cygnus -folks. - -A new shopt option, `restricted_shell', so that startup files can test - whether or not the shell was started in restricted mode -Filename generation is now performed on the words between ( and ) in - compound array assignments (this is really a bug fix) -OLDPWD is now auto-exported, as POSIX.2 requires -ENV and BASH_ENV are read-only variables in a restricted shell -Bash may now be linked against an already-installed Readline library, - as long as the Readline library is version 4 or newer -All shells begun with the `--login' option will source the login shell - startup files, even if the shell is not interactive - -There were lots of changes to the version of the Readline library released -along with Bash-2.03. For a complete list of the changes, read the file -CHANGES in the Bash-2.03 distribution. - -Bash-2.02 contained the following new features: - -a new version of malloc (based on the old GNU malloc code in previous - bash versions) that is more page-oriented, more conservative - with memory usage, does not `orphan' large blocks when they - are freed, is usable on 64-bit machines, and has allocation - checking turned on unconditionally -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -the ksh [[...]] extended conditional command -the ksh egrep-style extended pattern matching operators -a new `printf' builtin -the ksh-like $(, &>, >|, <<<, [n]<&word-, [n]>&word- - prompt string special char translation and variable expansion - auto-export of variables in initial environment - command search finds functions before builtins - bash return builtin will exit a file sourced with `.' - builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t. - export -n/-f/-p/name=value, pwd -L/-P, - read -e/-p/-a/-t/-n/-d/-s/-u, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -m/-p/-u, - type -a/-p/-t/-f/-P, suspend -f, kill -n, - test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S - bash reads ~/.bashrc for interactive shells, $ENV for non-interactive - bash restricted shell mode is more extensive - bash allows functions and variables with the same name - brace expansion - tilde expansion - arithmetic expansion with $((...)) and `let' builtin - the `[[...]]' extended conditional command - process substitution - aliases and alias/unalias builtins - local variables in functions and `local' builtin - readline and command-line editing with programmable completion - command history and history/fc builtins - csh-like history expansion - other new bash builtins: bind, command, compgen, complete, builtin, - declare/typeset, dirs, enable, fc, help, - history, logout, popd, pushd, disown, shopt, - printf - exported functions - filename generation when using output redirection (command >a*) - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - variable assignments preceding commands affect only that command, - even for builtins and functions - posix mode - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - -Things sh has that bash does not: - uses variable SHACCT to do shell accounting - includes `stop' builtin (bash can use alias stop='kill -s STOP') - `newgrp' builtin - turns on job control if called as `jsh' - $TIMEOUT (like bash $TMOUT) - `^' is a synonym for `|' - new SVR4.2 sh builtins: mldmode, priv - -Implementation differences: - redirection to/from compound commands causes sh to create a subshell - bash does not allow unbalanced quotes; sh silently inserts them at EOF - bash does not mess with signal 11 - sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100 - bash splits only the results of expansions on IFS, using POSIX.2 - field splitting rules; sh splits all words on IFS - sh does not allow MAILCHECK to be unset (?) - sh does not allow traps on SIGALRM or SIGCHLD - bash allows multiple option arguments when invoked (e.g. -x -v); - sh allows only a single option argument (`sh -x -v' attempts - to open a file named `-v', and, on SunOS 4.1.4, dumps core. - On Solaris 2.4 and earlier versions, sh goes into an infinite - loop.) - sh exits a script if any builtin fails; bash exits only if one of - the POSIX.2 `special' builtins fails - -C2) How does bash differ from the Korn shell, version ksh88? - -Things bash has or uses that ksh88 does not: - long invocation options - [-+]O invocation option - -l invocation option - `!' reserved word - arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done - arithmetic in largest machine-supported size (intmax_t) - posix mode and posix conformance - command hashing - tilde expansion for assignment statements that look like $PATH - process substitution with named pipes if /dev/fd is not available - the ${!param} indirect parameter expansion operator - the ${!param*} prefix expansion operator - the ${param:offset[:length]} parameter substring operator - the ${param/pat[/string]} parameter pattern substitution operator - variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL, - TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, - HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND, - IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK, - PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE, - GROUPS, FUNCNAME, histchars, auto_resume - prompt expansion with backslash escapes and command substitution - redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word- - more extensive and extensible editing and programmable completion - builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable, - exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history, - jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd, - read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p, - set -o braceexpand/-o histexpand/-o interactive-comments/ - -o notify/-o physical/-o posix/-o hashall/-o onecmd/ - -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type, - typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt, - disown, printf, complete, compgen - `!' csh-style history expansion - POSIX.2-style globbing character classes - POSIX.2-style globbing equivalence classes - POSIX.2-style globbing collating symbols - egrep-like extended pattern matching operators - case-insensitive pattern matching and globbing - `**' arithmetic operator to do exponentiation - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr - arrays of unlimited size - TMOUT is default timeout for `read' and `select' - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (|&, >&p, <&p) - weirdly-scoped functions - typeset +f to list all function names without definitions - text of command history kept in a file, not memory - builtins: alias -x, cd old new, fc -e -, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence - using environment to pass attributes of exported variables - arithmetic evaluation done on arguments to some builtins - reads .profile from $PWD when invoked as login shell - -Implementation differences: - ksh runs last command of a pipeline in parent shell context - bash has brace expansion by default (ksh88 compile-time option) - bash has fixed startup file for all interactive shells; ksh reads $ENV - bash has exported functions - bash command search finds functions before builtins - bash waits for all commands in pipeline to exit before returning status - emacs-mode editing has some slightly different key bindings - -C3) Which new features in ksh-93 are not in bash, and which are? - -New things in ksh-93 not in bash-2.05b: - associative arrays - floating point arithmetic and variables - math library functions - ${!name[sub]} name of subscript for associative array - `.' is allowed in variable names to create a hierarchical namespace - more extensive compound assignment syntax - discipline functions - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - KEYBD trap - variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version, - .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT - backreferences in pattern matching (\N) - `&' operator in pattern lists for matching - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - exit statuses between 0 and 255 - set -o pipefail - `+=' variable assignment operator - FPATH and PATH mixing - getopts -a - -I invocation option - DEBUG trap now executed before each simple command, instead of after - printf %H, %P, %T, %Z modifiers, output base for %d - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - -New things in ksh-93 present in bash-2.05b: - [n]<&word- and [n]>&word- redirections (combination dup and close) - for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command - ?:, ++, --, `expr1 , expr2' arithmetic operators - expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]}, - ${!param*} - compound array assignment - the `!' reserved word - loadable builtins -- but ksh uses `builtin' while bash uses `enable' - `command', `builtin', `disown' builtins - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - set -o notify/-C - changes to kill builtin - read -A (bash uses read -a) - read -t/-d - trap -p - exec -c/-a - `.' restores the positional parameters when it completes - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion - ENV processed only for interactive shells - -Section D: Why does bash do some things differently than other Unix shells? - -D1) Why does bash run a different version of `command' than - `which command' says it will? - -On many systems, `which' is actually a csh script that assumes -you're running csh. In tcsh, `which' and its cousin `where' -are builtins. On other Unix systems, `which' is a perl script -that uses the PATH environment variable. - -The csh script version reads the csh startup files from your -home directory and uses those to determine which `command' will -be invoked. Since bash doesn't use any of those startup files, -there's a good chance that your bash environment differs from -your csh environment. The bash `type' builtin does everything -`which' does, and will report correct results for the running -shell. If you're really wedded to the name `which', try adding -the following function definition to your .bashrc: - - which() - { - builtin type "$@" - } - -If you're moving from tcsh and would like to bring `where' along -as well, use this function: - - where() - { - builtin type -a "$@" - } - -D2) Why doesn't bash treat brace expansions exactly like csh? - -The only difference between bash and csh brace expansion is that -bash requires a brace expression to contain at least one unquoted -comma if it is to be expanded. Any brace-surrounded word not -containing an unquoted comma is left unchanged by the brace -expansion code. This affords the greatest degree of sh -compatibility. - -Bash, ksh, zsh, and pd-ksh all implement brace expansion this way. - -D3) Why doesn't bash have csh variable modifiers? - -Posix has specified a more powerful, albeit somewhat more cryptic, -mechanism cribbed from ksh, and bash implements it. - -${parameter%word} - Remove smallest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the suffix matched by the pattern deleted. - - x=file.c - echo ${x%.c}.o - -->file.o - -${parameter%%word} - - Remove largest suffix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the suffix matched by the pattern deleted. - - x=posix/src/std - echo ${x%%/*} - -->posix - -${parameter#word} - Remove smallest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - smallest portion of the prefix matched by the pattern deleted. - - x=$HOME/src/cmd - echo ${x#$HOME} - -->/src/cmd - -${parameter##word} - Remove largest prefix pattern. The WORD is expanded to produce - a pattern. It then expands to the value of PARAMETER, with the - largest portion of the prefix matched by the pattern deleted. - - x=/one/two/three - echo ${x##*/} - -->three - - -Given - a=/a/b/c/d - b=b.xxx - - csh bash result - --- ---- ------ - $a:h ${a%/*} /a/b/c - $a:t ${a##*/} d - $b:r ${b%.*} b - $b:e ${b##*.} xxx - - -D4) How can I make my csh aliases work when I convert to bash? - -Bash uses a different syntax to support aliases than csh does. -The details can be found in the documentation. We have provided -a shell script which does most of the work of conversion for you; -this script can be found in ./examples/misc/aliasconv.sh. Here is -how you use it: - -Start csh in the normal way for you. (e.g., `csh') - -Pipe the output of `alias' through `aliasconv.sh', saving the -results into `bash_aliases': - - alias | bash aliasconv.sh >bash_aliases - -Edit `bash_aliases', carefully reading through any created -functions. You will need to change the names of some csh specific -variables to the bash equivalents. The script converts $cwd to -$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt -to $PS1. You may also have to add quotes to avoid unwanted -expansion. - -For example, the csh alias: - - alias cd 'cd \!*; echo $cwd' - -is converted to the bash function: - - cd () { command cd "$@"; echo $PWD ; } - -The only thing that needs to be done is to quote $PWD: - - cd () { command cd "$@"; echo "$PWD" ; } - -Merge the edited file into your ~/.bashrc. - -There is an additional, more ambitious, script in -examples/misc/cshtobash that attempts to convert your entire csh -environment to its bash equivalent. This script can be run as -simply `cshtobash' to convert your normal interactive -environment, or as `cshtobash ~/.login' to convert your login -environment. - -D5) How can I pipe standard output and standard error from one command to - another, like csh does with `|&'? - -Use - command 2>&1 | command2 - -The key is to remember that piping is performed before redirection, so -file descriptor 1 points to the pipe when it is duplicated onto file -descriptor 2. - -D6) Now that I've converted from ksh to bash, are there equivalents to - ksh features like autoloaded functions and the `whence' command? - -There are features in ksh-88 and ksh-93 that do not have direct bash -equivalents. Most, however, can be emulated with very little trouble. - -ksh-88 feature Bash equivalent --------------- --------------- -compiled-in aliases set up aliases in .bashrc; some ksh aliases are - bash builtins (hash, history, type) -coprocesses named pipe pairs (one for read, one for write) -typeset +f declare -F -cd, print, whence function substitutes in examples/functions/kshenv -autoloaded functions examples/functions/autoload is the same as typeset -fu -read var?prompt read -p prompt var - -ksh-93 feature Bash equivalent --------------- --------------- -sleep, getconf Bash has loadable versions in examples/loadables -${.sh.version} $BASH_VERSION -print -f printf -hist alias hist=fc -$HISTEDIT $FCEDIT - -Section E: How can I get bash to do certain things, and why does bash do - things the way it does? - -E1) Why is the bash builtin `test' slightly different from /bin/test? - -The specific example used here is [ ! x -o x ], which is false. - -Bash's builtin `test' implements the Posix.2 spec, which can be -summarized as follows (the wording is due to David Korn): - -Here is the set of rules for processing test arguments. - - 0 Args: False - 1 Arg: True iff argument is not null. - 2 Args: If first arg is !, True iff second argument is null. - If first argument is unary, then true if unary test is true - Otherwise error. - 3 Args: If second argument is a binary operator, do binary test of $1 $3 - If first argument is !, negate two argument test of $2 $3 - If first argument is `(' and third argument is `)', do the - one-argument test of the second argument. - Otherwise error. - 4 Args: If first argument is !, negate three argument test of $2 $3 $4. - Otherwise unspecified - 5 or more Args: unspecified. (Historical shells would use their - current algorithm). - -The operators -a and -o are considered binary operators for the purpose -of the 3 Arg case. - -As you can see, the test becomes (not (x or x)), which is false. - -E2) Why does bash sometimes say `Broken pipe'? - -If a sequence of commands appears in a pipeline, and one of the -reading commands finishes before the writer has finished, the -writer receives a SIGPIPE signal. Many other shells special-case -SIGPIPE as an exit status in the pipeline and do not report it. -For example, in: - - ps -aux | head - -`head' can finish before `ps' writes all of its output, and ps -will try to write on a pipe without a reader. In that case, bash -will print `Broken pipe' to stderr when ps is killed by a -SIGPIPE. - -You can build a version of bash that will not report SIGPIPE errors -by uncommenting the definition of DONT_REPORT_SIGPIPE in the file -config-top.h. - -E3) When I have terminal escape sequences in my prompt, why does bash - wrap lines at the wrong column? - -Readline, the line editing library that bash uses, does not know -that the terminal escape sequences do not take up space on the -screen. The redisplay code assumes, unless told otherwise, that -each character in the prompt is a `printable' character that -takes up one character position on the screen. - -You can use the bash prompt expansion facility (see the PROMPTING -section in the manual page) to tell readline that sequences of -characters in the prompt strings take up no screen space. - -Use the \[ escape to begin a sequence of non-printing characters, -and the \] escape to signal the end of such a sequence. - -E4) If I pipe the output of a command into `read variable', why doesn't - the output show up in $variable when the read command finishes? - -This has to do with the parent-child relationship between Unix -processes. It affects all commands run in pipelines, not just -simple calls to `read'. For example, piping a command's output -into a `while' loop that repeatedly calls `read' will result in -the same behavior. - -Each element of a pipeline runs in a separate process, a child of -the shell running the pipeline. A subprocess cannot affect its -parent's environment. When the `read' command sets the variable -to the input, that variable is set only in the subshell, not the -parent shell. When the subshell exits, the value of the variable -is lost. - -Many pipelines that end with `read variable' can be converted -into command substitutions, which will capture the output of -a specified command. The output can then be assigned to a -variable: - - grep ^gnu /usr/lib/news/active | wc -l | read ngroup - -can be converted into - - ngroup=$(grep ^gnu /usr/lib/news/active | wc -l) - -This does not, unfortunately, work to split the text among -multiple variables, as read does when given multiple variable -arguments. If you need to do this, you can either use the -command substitution above to read the output into a variable -and chop up the variable using the bash pattern removal -expansion operators or use some variant of the following -approach. - -Say /usr/local/bin/ipaddr is the following shell script: - -#! /bin/sh -host `hostname` | awk '/address/ {print $NF}' - -Instead of using - - /usr/local/bin/ipaddr | read A B C D - -to break the local machine's IP address into separate octets, use - - OIFS="$IFS" - IFS=. - set -- $(/usr/local/bin/ipaddr) - IFS="$OIFS" - A="$1" B="$2" C="$3" D="$4" - -Beware, however, that this will change the shell's positional -parameters. If you need them, you should save them before doing -this. - -This is the general approach -- in most cases you will not need to -set $IFS to a different value. - -Some other user-supplied alternatives include: - -read A B C D << HERE - $(IFS=.; echo $(/usr/local/bin/ipaddr)) -HERE - -and, where process substitution is available, - -read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr)) - -E5) I have a bunch of shell scripts that use backslash-escaped characters - in arguments to `echo'. Bash doesn't interpret these characters. Why - not, and how can I make it understand them? - -This is the behavior of echo on most Unix System V machines. - -The bash builtin `echo' is modeled after the 9th Edition -Research Unix version of `echo'. It does not interpret -backslash-escaped characters in its argument strings by default; -it requires the use of the -e option to enable the -interpretation. The System V echo provides no way to disable the -special characters; the bash echo has a -E option to disable -them. - -There is a configuration option that will make bash behave like -the System V echo and interpret things like `\t' by default. Run -configure with the --enable-xpg-echo-default option to turn this -on. Be aware that this will cause some of the tests run when you -type `make tests' to fail. - -There is a shell option, `xpg_echo', settable with `shopt', that will -change the behavior of echo at runtime. Enabling this option turns -on expansion of backslash-escape sequences. - -E6) Why doesn't a while or for loop get suspended when I type ^Z? - -This is a consequence of how job control works on Unix. The only -thing that can be suspended is the process group. This is a single -command or pipeline of commands that the shell forks and executes. - -When you run a while or for loop, the only thing that the shell forks -and executes are any commands in the while loop test and commands in -the loop bodies. These, therefore, are the only things that can be -suspended when you type ^Z. - -If you want to be able to stop the entire loop, you need to put it -within parentheses, which will force the loop into a subshell that -may be stopped (and subsequently restarted) as a single unit. - -E7) What about empty for loops in Makefiles? - -It's fairly common to see constructs like this in automatically-generated -Makefiles: - -SUBDIRS = @SUBDIRS@ - - ... - -subdirs-clean: - for d in ${SUBDIRS}; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -When SUBDIRS is empty, this results in a command like this being passed to -bash: - - for d in ; do - ( cd $d && ${MAKE} ${MFLAGS} clean ) - done - -In versions of bash before bash-2.05a, this was a syntax error. If the -reserved word `in' was present, a word must follow it before the semicolon -or newline. The language in the manual page referring to the list of words -being empty referred to the list after it is expanded. These versions of -bash required that there be at least one word following the `in' when the -construct was parsed. - -The idiomatic Makefile solution is something like: - -SUBDIRS = @SUBDIRS@ - -subdirs-clean: - subdirs=$SUBDIRS ; for d in $$subdirs; do \ - ( cd $$d && ${MAKE} ${MFLAGS} clean ) \ - done - -The latest drafts of the updated POSIX standard have changed this: the -word list is no longer required. Bash versions 2.05a and later accept -the new syntax. - -E8) Why does the arithmetic evaluation code complain about `08'? - -The bash arithmetic evaluation code (used for `let', $(()), (()), and in -other places), interprets a leading `0' in numeric constants as denoting -an octal number, and a leading `0x' as denoting hexadecimal. This is -in accordance with the POSIX.2 spec, section 2.9.2.1, which states that -arithmetic constants should be handled as signed long integers as defined -by the ANSI/ISO C standard. - -The POSIX.2 interpretation committee has confirmed this: - -http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html - -E9) Why does the pattern matching expression [A-Z]* match files beginning - with every letter except `z'? - -Bash-2.03, Bash-2.05 and later versions honor the current locale setting -when processing ranges within pattern matching bracket expressions ([A-Z]). -This is what POSIX.2 and SUSv3/XPG6 specify. - -The behavior of the matcher in bash-2.05 and later versions depends on the -current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will -result in the traditional behavior ([A-Z] matches all uppercase ASCII -characters). Many other locales, including the en_US locale (the default -on many US versions of Linux) collate the upper and lower case letters like -this: - - AaBb...Zz - -which means that [A-Z] matches every letter except `z'. Others collate like - - aAbBcC...zZ - -which means that [A-Z] matches every letter except `a'. - -The portable way to specify upper case letters is [:upper:] instead of -A-Z; lower case may be specified as [:lower:] instead of a-z. - -Look at the manual pages for setlocale(3), strcoll(3), and, if it is -present, locale(1). If you have locale(1), you can use it to find -your current locale information even if you do not have any of the -LC_ variables set. - -My advice is to put - - export LC_COLLATE=C - -into /etc/profile and inspect any shell scripts run from cron for -constructs like [A-Z]. This will prevent things like - - rm [A-Z]* - -from removing every file in the current directory except those beginning -with `z' and still allow individual users to change the collation order. -Users may put the above command into their own profiles as well, of course. - -E10) Why does `cd //' leave $PWD as `//'? - -POSIX.2, in its description of `cd', says that *three* or more leading -slashes may be replaced with a single slash when canonicalizing the -current working directory. - -This is, I presume, for historical compatibility. Certain versions of -Unix, and early network file systems, used paths of the form -//hostname/path to access `path' on server `hostname'. - -E11) If I resize my xterm while another program is running, why doesn't bash - notice the change? - -This is another issue that deals with job control. - -The kernel maintains a notion of a current terminal process group. Members -of this process group (processes whose process group ID is equal to the -current terminal process group ID) receive terminal-generated signals like -SIGWINCH. (For more details, see the JOB CONTROL section of the bash -man page.) - -If a terminal is resized, the kernel sends SIGWINCH to each member of -the terminal's current process group (the `foreground' process group). - -When bash is running with job control enabled, each pipeline (which may be -a single command) is run in its own process group, different from bash's -process group. This foreground process group receives the SIGWINCH; bash -does not. Bash has no way of knowing that the terminal has been resized. - -There is a `checkwinsize' option, settable with the `shopt' builtin, that -will cause bash to check the window size and adjust its idea of the -terminal's dimensions each time a process stops or exits and returns control -of the terminal to bash. Enable it with `shopt -s checkwinsize'. - -Section F: Things to watch out for on certain Unix versions - -F1) Why can't I use command line editing in my `cmdtool'? - -The problem is `cmdtool' and bash fighting over the input. When -scrolling is enabled in a cmdtool window, cmdtool puts the tty in -`raw mode' to permit command-line editing using the mouse for -applications that cannot do it themselves. As a result, bash and -cmdtool each try to read keyboard input immediately, with neither -getting enough of it to be useful. - -This mode also causes cmdtool to not implement many of the -terminal functions and control sequences appearing in the -`sun-cmd' termcap entry. For a more complete explanation, see -that file examples/suncmd.termcap in the bash distribution. - -`xterm' is a better choice, and gets along with bash much more -smoothly. - -If you must use cmdtool, you can use the termcap description in -examples/suncmd.termcap. Set the TERMCAP variable to the terminal -description contained in that file, i.e. - -TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:' - -Then export TERMCAP and start a new cmdtool window from that shell. -The bash command-line editing should behave better in the new -cmdtool. If this works, you can put the assignment to TERMCAP -in your bashrc file. - -F2) I built bash on Solaris 2. Why do globbing expansions and filename - completion chop off the first few characters of each filename? - -This is the consequence of building bash on SunOS 5 and linking -with the libraries in /usr/ucblib, but using the definitions -and structures from files in /usr/include. - -The actual conflict is between the dirent structure in -/usr/include/dirent.h and the struct returned by the version of -`readdir' in libucb.a (a 4.3-BSD style `struct direct'). - -Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH -when configuring and building bash. This will ensure that you -use /usr/ccs/bin/cc or acc instead of /usr/ucb/cc and that you -link with libc before libucb. - -If you have installed the Sun C compiler, you may also need to -put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before -/usr/ucb. - -F3) Why does bash dump core after I interrupt username completion or - `~user' tilde expansion on a machine running NIS? - -This is a famous and long-standing bug in the SunOS YP (sorry, NIS) -client library, which is part of libc. - -The YP library code keeps static state -- a pointer into the data -returned from the server. When YP initializes itself (setpwent), -it looks at this pointer and calls free on it if it's non-null. -So far, so good. - -If one of the YP functions is interrupted during getpwent (the -exact function is interpretwithsave()), and returns NULL, the -pointer is freed without being reset to NULL, and the function -returns. The next time getpwent is called, it sees that this -pointer is non-null, calls free, and the bash free() blows up -because it's being asked to free freed memory. - -The traditional Unix mallocs allow memory to be freed multiple -times; that's probably why this has never been fixed. You can -run configure with the `--without-gnu-malloc' option to use -the C library malloc and avoid the problem. - -F4) I'm running SVR4.2. Why is the line erased every time I type `@'? - -The `@' character is the default `line kill' character in most -versions of System V, including SVR4.2. You can change this -character to whatever you want using `stty'. For example, to -change the line kill character to control-u, type - - stty kill ^U - -where the `^' and `U' can be two separate characters. - -F5) Why does bash report syntax errors when my C News scripts use a - redirection before a subshell command? - -The actual command in question is something like - - < file ( command ) - -According to the grammar given in the POSIX.2 standard, this construct -is, in fact, a syntax error. Redirections may only precede `simple -commands'. A subshell construct such as the above is one of the shell's -`compound commands'. A redirection may only follow a compound command. - -This affects the mechanical transformation of commands that use `cat' -to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on -comp.unix.shell). While most commands of the form - - cat file | command - -can be converted to `< file command', shell control structures such as -loops and subshells require `command < file'. - -The file CWRU/sh-redir-hack in the bash-2.05a distribution is an -(unofficial) patch to parse.y that will modify the grammar to -support this construct. It will not apply with `patch'; you must -modify parse.y by hand. Note that if you apply this, you must -recompile with -DREDIRECTION_HACK. This introduces a large -number of reduce/reduce conflicts into the shell grammar. - -F6) Why can't I use vi-mode editing on Red Hat Linux 6.1? - -The short answer is that Red Hat screwed up. - -The long answer is that they shipped an /etc/inputrc that only works -for emacs mode editing, and then screwed all the vi users by setting -INPUTRC to /etc/inputrc in /etc/profile. - -The short fix is to do one of the following: remove or rename -/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile, -but make sure you export it if you do), remove the assignment to -INPUTRC from /etc/profile, add - - set keymap emacs - -to the beginning of /etc/inputrc, or bracket the key bindings in -/etc/inputrc with these lines - - $if mode=emacs - [...] - $endif - -F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on - HP/UX 11.x? - -HP/UX's support for long double is imperfect at best. - -GCC will support it without problems, but the HP C library functions -like strtold(3) and printf(3) don't actually work with long doubles. -HP implemented a `long_double' type as a 4-element array of 32-bit -ints, and that is what the library functions use. The ANSI C -`long double' type is a 128-bit floating point scalar. - -The easiest fix, until HP fixes things up, is to edit the generated -config.h and #undef the HAVE_LONG_DOUBLE line. After doing that, -the compilation should complete successfully. - -Section G: How can I get bash to do certain common things? - -G1) How can I get bash to read and display eight-bit characters? - -This is a process requiring several steps. - -First, you must ensure that the `physical' data path is a full eight -bits. For xterms, for example, the `vt100' resources `eightBitInput' -and `eightBitOutput' should be set to `true'. - -Once you have set up an eight-bit path, you must tell the kernel and -tty driver to leave the eighth bit of characters alone when processing -keyboard input. Use `stty' to do this: - - stty cs8 -istrip -parenb - -For old BSD-style systems, you can use - - stty pass8 - -You may also need - - stty even odd - -Finally, you need to tell readline that you will be inputting and -displaying eight-bit characters. You use readline variables to do -this. These variables can be set in your .inputrc or using the bash -`bind' builtin. Here's an example using `bind': - - bash$ bind 'set convert-meta off' - bash$ bind 'set meta-flag on' - bash$ bind 'set output-meta on' - -The `set' commands between the single quotes may also be placed -in ~/.inputrc. - -G2) How do I write a function `x' to replace builtin command `x', but - still invoke the command from within the function? - -This is why the `command' and `builtin' builtins exist. The -`command' builtin executes the command supplied as its first -argument, skipping over any function defined with that name. The -`builtin' builtin executes the builtin command given as its first -argument directly. - -For example, to write a function to replace `cd' that writes the -hostname and current directory to an xterm title bar, use -something like the following: - - cd() - { - builtin cd "$@" && xtitle "$HOST: $PWD" - } - -This could also be written using `command' instead of `builtin'; -the version above is marginally more efficient. - -G3) How can I find the value of a shell variable whose name is the value - of another shell variable? - -Versions of Bash newer than Bash-2.0 support this directly. You can use - - ${!var} - -For example, the following sequence of commands will echo `z': - - var1=var2 - var2=z - echo ${!var1} - -For sh compatibility, use the `eval' builtin. The important -thing to remember is that `eval' expands the arguments you give -it again, so you need to quote the parts of the arguments that -you want `eval' to act on. - -For example, this expression prints the value of the last positional -parameter: - - eval echo \"\$\{$#\}\" - -The expansion of the quoted portions of this expression will be -deferred until `eval' runs, while the `$#' will be expanded -before `eval' is executed. In versions of bash later than bash-2.0, - - echo ${!#} - -does the same thing. - -This is not the same thing as ksh93 `nameref' variables, though the syntax -is similar. I may add namerefs in a future bash version. - -G4) How can I make the bash `time' reserved word print timing output that - looks like the output from my system's /usr/bin/time? - -The bash command timing code looks for a variable `TIMEFORMAT' and -uses its value as a format string to decide how to display the -timing statistics. - -The value of TIMEFORMAT is a string with `%' escapes expanded in a -fashion similar in spirit to printf(3). The manual page explains -the meanings of the escape sequences in the format string. - -If TIMEFORMAT is not set, bash acts as if the following assignment had -been performed: - - TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS' - -The POSIX.2 default time format (used by `time -p command') is - - TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S' - -The BSD /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys' - -The System V /usr/bin/time format can be emulated with: - - TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S' - -The ksh format can be emulated with: - - TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS' - -G5) How do I get the current directory into my prompt? - -Bash provides a number of backslash-escape sequences which are expanded -when the prompt string (PS1 or PS2) is displayed. The full list is in -the manual page. - -The \w expansion gives the full pathname of the current directory, with -a tilde (`~') substituted for the current value of $HOME. The \W -expansion gives the basename of the current directory. To put the full -pathname of the current directory into the path without any tilde -subsitution, use $PWD. Here are some examples: - - PS1='\w$ ' # current directory with tilde - PS1='\W$ ' # basename of current directory - PS1='$PWD$ ' # full pathname of current directory - -The single quotes are important in the final example to prevent $PWD from -being expanded when the assignment to PS1 is performed. - -G6) How can I rename "*.foo" to "*.bar"? - -Use the pattern removal functionality described in D3. The following `for' -loop will do the trick: - - for f in *.foo; do - mv $f ${f%foo}bar - done - -G7) How can I translate a filename from uppercase to lowercase? - -The script examples/functions/lowercase, originally written by John DuBois, -will do the trick. The converse is left as an exercise. - -G8) How can I write a filename expansion (globbing) pattern that will match - all files in the current directory except "." and ".."? - -You must have set the `extglob' shell option using `shopt -s extglob' to use -this: - - echo .!(.|) * - -A solution that works without extended globbing is given in the Unix Shell -FAQ, posted periodically to comp.unix.shell. - -Section H: Where do I go from here? - -H1) How do I report bugs in bash, and where should I look for fixes and - advice? - -Use the `bashbug' script to report bugs. It is built and -installed at the same time as bash. It provides a standard -template for reporting a problem and automatically includes -information about your configuration and build environment. - -`bashbug' sends its reports to bug-bash@gnu.org, which -is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug. - -Bug fixes, answers to questions, and announcements of new releases -are all posted to gnu.bash.bug. Discussions concerning bash features -and problems also take place there. - -To reach the bash maintainers directly, send mail to -bash-maintainers@gnu.org. - -H2) What kind of bash documentation is there? - -First, look in the doc directory in the bash distribution. It should -contain at least the following files: - -bash.1 an extensive, thorough Unix-style manual page -builtins.1 a manual page covering just bash builtin commands -bashref.texi a reference manual in GNU tex`info format -bashref.info an info version of the reference manual -FAQ this file -article.ms text of an article written for The Linux Journal -readline.3 a man page describing readline - -Postscript, HTML, and ASCII files created from the above source are -available in the documentation distribution. - -There is additional documentation available for anonymous FTP from host -ftp.cwru.edu in the `pub/bash' directory. - -Cameron Newham and Bill Rosenblatt have written a book on bash, published -by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn -Shell book. The title is ``Learning the Bash Shell'', and the ISBN number -is 1-56592-147-X. Look for it in fine bookstores near you. This book -covers bash-1.14, but has an appendix describing some of the new features -in bash-2.0. - -A second edition of this book is available, published in January, 1998. -The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores -or on the web. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers -bash-2.0 and is available from most online bookstores (see -http://www.network-theory.co.uk/bash/manual/ for details). The publisher -will donate $1 to the Free Software Foundation for each copy sold. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -a better bash debugger (a minimally-tested version is included with bash-2.05b) -associative arrays -co-processes, but with a new-style syntax that looks like function declaration - -H4) What's on the bash `wish list' for future versions? - -These are features that may or may not appear in a future version of bash. - -breaking some of the shell functionality into embeddable libraries -a module system like zsh's, using dynamic loading like builtins -better internationalization using GNU `gettext' -date-stamped command history -a bash programmer's guide with a chapter on creating loadable builtins -a better loadable interface to perl with access to the shell builtins and - variables (contributions gratefully accepted) -ksh93-like `nameref' variables -ksh93-like `+=' variable assignment operator -ksh93-like `xx.yy' variables (including some of the .sh.* variables) and - associated disipline functions -Some of the new ksh93 pattern matching operators, like backreferencing - -H5) When will the next release appear? - -The next version will appear sometime in 2002. Never make predictions. - - -This document is Copyright 1995-2003 by Chester Ramey. - -Permission is hereby granted, without written agreement and -without license or royalty fees, to use, copy, and distribute -this document for any purpose, provided that the above copyright -notice appears in all copies of this document and that the -contents of this document remain unaltered. diff --git a/doc/aosa-bash.pdf.old b/doc/aosa-bash.pdf.old deleted file mode 100644 index 006a76776..000000000 Binary files a/doc/aosa-bash.pdf.old and /dev/null differ diff --git a/doc/bash.1~ b/doc/bash.1~ deleted file mode 100644 index ccc4b6ba4..000000000 --- a/doc/bash.1~ +++ /dev/null @@ -1,10482 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Case Western Reserve University -.\" chet.ramey@case.edu -.\" -.\" Last Change: Thu Jan 1 14:40:18 EST 2015 -.\" -.\" bash_builtins, strip all but Built-Ins section -.if \n(zZ=1 .ig zZ -.if \n(zY=1 .ig zY -.TH BASH 1 "2015 January 1" "GNU Bash 4.4" -.\" -.\" There's some problem with having a `@' -.\" in a tagged paragraph with the BSD man macros. -.\" It has to do with `@' appearing in the }1 macro. -.\" This is a problem on 4.3 BSD and Ultrix, but Sun -.\" appears to have fixed it. -.\" If you're seeing the characters -.\" `@u-3p' appearing before the lines reading -.\" `possible-hostname-completions -.\" and `complete-hostname' down in READLINE, -.\" then uncomment this redefinition. -.\" -.de }1 -.ds ]X \&\\*(]B\\ -.nr )E 0 -.if !"\\$1"" .nr )I \\$1n -.}f -.ll \\n(LLu -.in \\n()Ru+\\n(INu+\\n()Iu -.ti \\n(INu -.ie !\\n()Iu+\\n()Ru-\w\\*(]Xu-3p \{\\*(]X -.br\} -.el \\*(]X\h|\\n()Iu+\\n()Ru\c -.}f -.. -.\" -.\" File Name macro. This used to be `.PN', for Path Name, -.\" but Sun doesn't seem to like that very much. -.\" -.de FN -\fI\|\\$1\|\fP -.. -.SH NAME -bash \- GNU Bourne-Again SHell -.SH SYNOPSIS -.B bash -[options] -[command_string | file] -.SH COPYRIGHT -.if n Bash is Copyright (C) 1989-2015 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989-2015 by the Free Software Foundation, Inc. -.SH DESCRIPTION -.B Bash -is an \fBsh\fR-compatible command language interpreter that -executes commands read from the standard input or from a file. -.B Bash -also incorporates useful features from the \fIKorn\fP and \fIC\fP -shells (\fBksh\fP and \fBcsh\fP). -.PP -.B Bash -is intended to be a conformant implementation of the -Shell and Utilities portion of the IEEE POSIX specification -(IEEE Standard 1003.1). -.B Bash -can be configured to be POSIX-conformant by default. -.SH OPTIONS -All of the single-character shell options documented in the -description of the \fBset\fR builtin command can be used as options -when the shell is invoked. -In addition, \fBbash\fR -interprets the following options when it is invoked: -.PP -.PD 0 -.TP 10 -.B \-c -If the -.B \-c -option is present, then commands are read from the first non-option argument -.IR command_string . -If there are arguments after the -.IR command_string , -the first argument is assigned to -.B $0 -and any remaining arguments are assigned to the positional parameters. -The assignment to -.B $0 -sets the name of the shell, which is used in warning and error messages. -.TP -.B \-i -If the -.B \-i -option is present, the shell is -.IR interactive . -.TP -.B \-l -Make -.B bash -act as if it had been invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-r -If the -.B \-r -option is present, the shell becomes -.I restricted -(see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-s -If the -.B \-s -option is present, or if no arguments remain after option -processing, then commands are read from the standard input. -This option allows the positional parameters to be set -when invoking an interactive shell. -.TP -.B \-D -A list of all double-quoted strings preceded by \fB$\fP -is printed on the standard output. -These are the strings that -are subject to language translation when the current locale -is not \fBC\fP or \fBPOSIX\fP. -This implies the \fB\-n\fP option; no commands will be executed. -.TP -.B [\-+]O [\fIshopt_option\fP] -\fIshopt_option\fP is one of the shell options accepted by the -\fBshopt\fP builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -If \fIshopt_option\fP is present, \fB\-O\fP sets the value of that option; -\fB+O\fP unsets it. -If \fIshopt_option\fP is not supplied, the names and values of the shell -options accepted by \fBshopt\fP are printed on the standard output. -If the invocation option is \fB+O\fP, the output is displayed in a format -that may be reused as input. -.TP -.B \-\- -A -.B \-\- -signals the end of options and disables further option processing. -Any arguments after the -.B \-\- -are treated as filenames and arguments. An argument of -.B \- -is equivalent to \fB\-\-\fP. -.PD -.PP -.B Bash -also interprets a number of multi-character options. -These options must appear on the command line before the -single-character options to be recognized. -.PP -.PD 0 -.TP -.B \-\-debugger -Arrange for the debugger profile to be executed before the shell -starts. -Turns on extended debugging mode (see the description of the -.B extdebug -option to the -.B shopt -builtin below). -.TP -.B \-\-dump\-po\-strings -Equivalent to \fB\-D\fP, but the output is in the GNU \fIgettext\fP -\fBpo\fP (portable object) file format. -.TP -.B \-\-dump\-strings -Equivalent to \fB\-D\fP. -.TP -.B \-\-help -Display a usage message on standard output and exit successfully. -.TP -\fB\-\-init\-file\fP \fIfile\fP -.PD 0 -.TP -\fB\-\-rcfile\fP \fIfile\fP -.PD -Execute commands from -.I file -instead of the standard personal initialization file -.I ~/.bashrc -if the shell is interactive (see -.SM -.B INVOCATION -below). -.TP -.B \-\-login -Equivalent to \fB\-l\fP. -.TP -.B \-\-noediting -Do not use the GNU -.B readline -library to read command lines when the shell is interactive. -.TP -.B \-\-noprofile -Do not read either the system-wide startup file -.FN /etc/profile -or any of the personal initialization files -.IR ~/.bash_profile , -.IR ~/.bash_login , -or -.IR ~/.profile . -By default, -.B bash -reads these files when it is invoked as a login shell (see -.SM -.B INVOCATION -below). -.TP -.B \-\-norc -Do not read and execute the personal initialization file -.I ~/.bashrc -if the shell is interactive. -This option is on by default if the shell is invoked as -.BR sh . -.TP -.B \-\-posix -Change the behavior of \fBbash\fP where the default operation differs -from the POSIX standard to match the standard (\fIposix mode\fP). -See -.SM -.B "SEE ALSO" -below for a reference to a document that details how posix mode affects -bash's behavior. -.TP -.B \-\-restricted -The shell becomes restricted (see -.SM -.B "RESTRICTED SHELL" -below). -.TP -.B \-\-verbose -Equivalent to \fB\-v\fP. -.TP -.B \-\-version -Show version information for this instance of -.B bash -on the standard output and exit successfully. -.PD -.SH ARGUMENTS -If arguments remain after option processing, and neither the -.B \-c -nor the -.B \-s -option has been supplied, the first argument is assumed to -be the name of a file containing shell commands. -If -.B bash -is invoked in this fashion, -.B $0 -is set to the name of the file, and the positional parameters -are set to the remaining arguments. -.B Bash -reads and executes commands from this file, then exits. -\fBBash\fP's exit status is the exit status of the last command -executed in the script. -If no commands are executed, the exit status is 0. -An attempt is first made to open the file in the current directory, and, -if no file is found, then the shell searches the directories in -.SM -.B PATH -for the script. -.SH INVOCATION -A \fIlogin shell\fP is one whose first character of argument zero is a -.BR \- , -or one started with the -.B \-\-login -option. -.PP -An \fIinteractive\fP shell is one started without non-option arguments -and without the -.B \-c -option -whose standard input and error are -both connected to terminals (as determined by -.IR isatty (3)), -or one started with the -.B \-i -option. -.SM -.B PS1 -is set and -.B $\- -includes -.B i -if -.B bash -is interactive, -allowing a shell script or a startup file to test this state. -.PP -The following paragraphs describe how -.B bash -executes its startup files. -If any of the files exist but cannot be read, -.B bash -reports an error. -Tildes are expanded in filenames as described below under -.B "Tilde Expansion" -in the -.SM -.B EXPANSION -section. -.PP -When -.B bash -is invoked as an interactive login shell, or as a non-interactive shell -with the \fB\-\-login\fP option, it first reads and -executes commands from the file \fI/etc/profile\fP, if that -file exists. -After reading that file, it looks for \fI~/.bash_profile\fP, -\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads -and executes commands from the first one that exists and is readable. -The -.B \-\-noprofile -option may be used when the shell is started to inhibit this behavior. -.PP -When a login shell exits, -.B bash -reads and executes commands from the file \fI~/.bash_logout\fP, if it -exists. -.PP -When an interactive shell that is not a login shell is started, -.B bash -reads and executes commands from \fI~/.bashrc\fP, if that file exists. -This may be inhibited by using the -.B \-\-norc -option. -The \fB\-\-rcfile\fP \fIfile\fP option will force -.B bash -to read and execute commands from \fIfile\fP instead of \fI~/.bashrc\fP. -.PP -When -.B bash -is started non-interactively, to run a shell script, for example, it -looks for the variable -.SM -.B BASH_ENV -in the environment, expands its value if it appears there, and uses the -expanded value as the name of a file to read and execute. -.B Bash -behaves as if the following command were executed: -.sp .5 -.RS -.if t \f(CWif [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\fP -.if n if [ \-n "$BASH_ENV" ]; then . "$BASH_ENV"; fi -.RE -.sp .5 -but the value of the -.SM -.B PATH -variable is not used to search for the filename. -.PP -If -.B bash -is invoked with the name -.BR sh , -it tries to mimic the startup behavior of historical versions of -.B sh -as closely as possible, -while conforming to the POSIX standard as well. -When invoked as an interactive login shell, or a non-interactive -shell with the \fB\-\-login\fP option, it first attempts to -read and execute commands from -.I /etc/profile -and -.IR ~/.profile , -in that order. -The -.B \-\-noprofile -option may be used to inhibit this behavior. -When invoked as an interactive shell with the name -.BR sh , -.B bash -looks for the variable -.SM -.BR ENV , -expands its value if it is defined, and uses the -expanded value as the name of a file to read and execute. -Since a shell invoked as -.B sh -does not attempt to read and execute commands from any other startup -files, the -.B \-\-rcfile -option has no effect. -A non-interactive shell invoked with the name -.B sh -does not attempt to read any other startup files. -When invoked as -.BR sh , -.B bash -enters -.I posix -mode after the startup files are read. -.PP -When -.B bash -is started in -.I posix -mode, as with the -.B \-\-posix -command line option, it follows the POSIX standard for startup files. -In this mode, interactive shells expand the -.SM -.B ENV -variable and commands are read and executed from the file -whose name is the expanded value. -No other startup files are read. -.PP -.B Bash -attempts to determine when it is being run with its standard input -connected to a network connection, as when executed by the remote shell -daemon, usually \fIrshd\fP, or the secure shell daemon \fIsshd\fP. -If -.B bash -determines it is being run in this fashion, it reads and executes -commands from \fI~/.bashrc\fP, if that file exists and is readable. -It will not do this if invoked as \fBsh\fP. -The -.B \-\-norc -option may be used to inhibit this behavior, and the -.B \-\-rcfile -option may be used to force another file to be read, but neither -\fIrshd\fP nor \fIsshd\fP generally invoke the shell with those options -or allow them to be specified. -.PP -If the shell is started with the effective user (group) id not equal to the -real user (group) id, and the \fB\-p\fP option is not supplied, no startup -files are read, shell functions are not inherited from the environment, the -.SM -.BR SHELLOPTS , -.SM -.BR BASHOPTS , -.SM -.BR CDPATH , -and -.SM -.B GLOBIGNORE -variables, if they appear in the environment, are ignored, -and the effective user id is set to the real user id. -If the \fB\-p\fP option is supplied at invocation, the startup behavior is -the same, but the effective user id is not reset. -.SH DEFINITIONS -.PP -The following definitions are used throughout the rest of this -document. -.PD 0 -.TP -.B blank -A space or tab. -.TP -.B word -A sequence of characters considered as a single unit by the shell. -Also known as a -.BR token . -.TP -.B name -A -.I word -consisting only of alphanumeric characters and underscores, and -beginning with an alphabetic character or an underscore. Also -referred to as an -.BR identifier . -.TP -.B metacharacter -A character that, when unquoted, separates words. One of the following: -.br -.RS -.PP -.if t \fB| & ; ( ) < > space tab\fP -.if n \fB| & ; ( ) < > space tab\fP -.RE -.PP -.TP -.B control operator -A \fItoken\fP that performs a control function. It is one of the following -symbols: -.RS -.PP -.if t \fB|| & && ; ;; ( ) | |& \fP -.if n \fB|| & && ; ;; ( ) | |& \fP -.RE -.PD -.SH "RESERVED WORDS" -\fIReserved words\fP are words that have a special meaning to the shell. -The following words are recognized as reserved when unquoted and either -the first word of a simple command (see -.SM -.B SHELL GRAMMAR -below) or the third word of a -.B case -or -.B for -command: -.if t .RS -.PP -.B -.if n ! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t ! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]] -.if t .RE -.SH "SHELL GRAMMAR" -.SS Simple Commands -.PP -A \fIsimple command\fP is a sequence of optional variable assignments -followed by \fBblank\fP-separated words and redirections, and -terminated by a \fIcontrol operator\fP. The first word -specifies the command to be executed, and is passed as argument zero. -The remaining words are passed as arguments to the invoked command. -.PP -The return value of a \fIsimple command\fP is its exit status, or -128+\fIn\^\fP if the command is terminated by signal -.IR n . -.SS Pipelines -.PP -A \fIpipeline\fP is a sequence of one or more commands separated by -one of the control operators -.B | -or \fB|&\fP. -The format for a pipeline is: -.RS -.PP -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ] -.RE -.PP -The standard output of -.I command -is connected via a pipe to the standard input of -.IR command2 . -This connection is performed before any redirections specified by the -command (see -.SM -.B REDIRECTION -below). -If \fB|&\fP is used, \fIcommand\fP's standard 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~ deleted file mode 100644 index a666278cc..000000000 --- a/doc/version.texi~ +++ /dev/null @@ -1,11 +0,0 @@ -@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 deleted file mode 100644 index f6208f5cc..000000000 --- a/examples/loadables/Makefile.in.save +++ /dev/null @@ -1,238 +0,0 @@ -# -# Simple makefile for the sample loadable builtins -# -# Copyright (C) 1996 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -@SET_MAKE@ -CC = @CC@ -RM = rm -f - -SHELL = @MAKE_SHELL@ - -host_os = @host_os@ -host_cpu = @host_cpu@ -host_vendor = @host_vendor@ - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -CPPFLAGS = @CPPFLAGS@ - -BASHINCDIR = ${topdir}/include - -LIBBUILD = ${BUILD_DIR}/lib - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_INC = @INTL_INC@ -LIBINTL_H = @LIBINTL_H@ - -CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) - -# -# These values are generated for configure by ${topdir}/support/shobj-conf. -# If your system is not supported by that script, but includes facilities for -# dynamic loading of shared objects, please update the script and send the -# changes to bash-maintainers@gnu.org. -# -SHOBJ_CC = @SHOBJ_CC@ -SHOBJ_CFLAGS = @SHOBJ_CFLAGS@ -SHOBJ_LD = @SHOBJ_LD@ -SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ -SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@ -SHOBJ_LIBS = @SHOBJ_LIBS@ -SHOBJ_STATUS = @SHOBJ_STATUS@ - -INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ - -I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \ - -I$(BUILD_DIR)/builtins $(INTL_INC) - -.c.o: - $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $< - - -ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ - tty pathchk tee head mkdir rmdir printenv id whoami \ - uname sync push ln unlink cut realpath getconf strftime -OTHERPROG = necho hello cat - -all: $(SHOBJ_STATUS) - -supported: $(ALLPROG) -others: $(OTHERPROG) - -unsupported: - @echo "Your system (${host_os}) is not supported by the" - @echo "${topdir}/support/shobj-conf script." - @echo "If your operating system provides facilities for dynamic" - @echo "loading of shared objects using the dlopen(3) interface," - @echo "please update the script and re-run configure. - @echo "Please send the changes you made to bash-maintainers@gnu.org" - @echo "for inclusion in future bash releases." - -everything: supported others - -print: print.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS) - -necho: necho.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS) - -getconf: getconf.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS) - -hello: hello.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS) - -truefalse: truefalse.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS) - -sleep: sleep.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS) - -finfo: finfo.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS) - -cat: cat.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS) - -logname: logname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS) - -basename: basename.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS) - -dirname: dirname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS) - -tty: tty.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS) - -pathchk: pathchk.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS) - -tee: tee.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS) - -mkdir: mkdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS) - -rmdir: rmdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS) - -head: head.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS) - -printenv: printenv.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS) - -id: id.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS) - -whoami: whoami.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS) - -uname: uname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS) - -sync: sync.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS) - -push: push.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS) - -ln: ln.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS) - -unlink: unlink.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS) - -cut: cut.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS) - -realpath: realpath.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) - -strftime: strftime.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS) - -# pushd is a special case. We use the same source that the builtin version -# uses, with special compilation options. -# -pushd.c: ${topdir}/builtins/pushd.def - $(RM) $@ - ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def - -pushd.o: pushd.c - $(RM) $@ - $(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $< - -pushd: pushd.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS) - -clean: - $(RM) $(ALLPROG) $(OTHERPROG) *.o - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -mostlyclean: clean - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -distclean maintainer-clean: clean - $(RM) Makefile pushd.c - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -print.o: print.c -truefalse.o: truefalse.c -sleep.o: sleep.c -finfo.o: finfo.c -logname.o: logname.c -basename.o: basename.c -dirname.o: dirname.c -tty.o: tty.c -pathchk.o: pathchk.c -tee.o: tee.c -head.o: head.c -rmdir.o: rmdir.c -necho.o: necho.c -getconf.o: getconf.c -hello.o: hello.c -cat.o: cat.c -printenv.o: printenv.c -id.o: id.c -whoami.o: whoami.c -uname.o: uname.c -sync.o: sync.c -push.o: push.c -mkdir.o: mkdir.c -realpath.o: realpath.c -strftime.o: strftime.c diff --git a/include/chartypes.h~ b/include/chartypes.h~ deleted file mode 100644 index 66553f642..000000000 --- a/include/chartypes.h~ +++ /dev/null @@ -1,113 +0,0 @@ -/* chartypes.h -- extend ctype.h */ - -/* Copyright (C) 2001 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#ifndef _SH_CHARTYPES_H -#define _SH_CHARTYPES_H - -#include - -/* Jim Meyering writes: - - "... Some ctype macros are valid only for character codes that - isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when - using /bin/cc or gcc but without giving an ansi option). So, all - ctype uses should be through macros like ISPRINT... If - STDC_HEADERS is defined, then autoconf has verified that the ctype - macros don't need to be guarded with references to isascii. ... - Defining IN_CTYPE_DOMAIN to 1 should let any compiler worth its salt - eliminate the && through constant folding." - Solaris defines some of these symbols so we must undefine them first. */ - -#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII) -# define IN_CTYPE_DOMAIN(c) 1 -#else -# define IN_CTYPE_DOMAIN(c) isascii(c) -#endif - -#if !defined (isspace) && !defined (HAVE_ISSPACE) -# define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f') -#endif - -#if !defined (isprint) && !defined (HAVE_ISPRINT) -# define isprint(c) (isalpha(c) || isdigit(c) || ispunct(c)) -#endif - -#if defined (isblank) || defined (HAVE_ISBLANK) -# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) -#else -# define ISBLANK(c) ((c) == ' ' || (c) == '\t') -#endif - -#if defined (isgraph) || defined (HAVE_ISGRAPH) -# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) -#else -# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) -#endif - -#if !defined (isxdigit) && !defined (HAVE_ISXDIGIT) -# define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) -#endif - -#undef ISPRINT - -#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint ((unsigned char)c)) -#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit ((unsigned char)c)) -#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum ((unsigned char)c)) -#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha ((unsigned char)c)) -#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl ((unsigned char)c)) -#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower ((unsigned char)c)) -#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct ((unsigned char)c)) -#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace ((unsigned char)c)) -#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper ((unsigned char)c)) -#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit ((unsigned char)c)) - -#define ISLETTER(c) (ISALPHA(c)) - -#define DIGIT(c) ((c) >= '0' && (c) <= '9') - -#define ISWORD(c) (ISLETTER(c) || DIGIT(c) || ((c) == '_')) - -#define HEXVALUE(c) \ - (((c) >= 'a' && (c) <= 'f') \ - ? (c)-'a'+10 \ - : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') - -#ifndef ISOCTAL -# define ISOCTAL(c) ((c) >= '0' && (c) <= '7') -#endif -#define OCTVALUE(c) ((c) - '0') - -#define TODIGIT(c) ((c) - '0') -#define TOCHAR(c) ((c) + '0') - -#define TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c)) -#define TOUPPER(c) (ISLOWER(c) ? toupper(c) : (c)) - -#ifndef TOCTRL - /* letter to control char -- ASCII. The TOUPPER is in there so \ce and - \cE will map to the same character in $'...' expansions. */ -# define TOCTRL(x) (TOUPPER(x) & 037) -#endif -#ifndef UNCTRL - /* control char to letter -- ASCII */ -# define UNCTRL(x) (TOUPPER(x) ^ 0x40) -#endif - -#endif /* _SH_CHARTYPES_H */ diff --git a/include/posixjmp.h~ b/include/posixjmp.h~ deleted file mode 100644 index 8f8b45e71..000000000 --- a/include/posixjmp.h~ +++ /dev/null @@ -1,42 +0,0 @@ -/* posixjmp.h -- wrapper for setjmp.h with changes for POSIX systems. */ - -/* Copyright (C) 1987,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 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 . -*/ - -#ifndef _POSIXJMP_H_ -#define _POSIXJMP_H_ - -#include - -/* This *must* be included *after* config.h */ - -#if defined (HAVE_POSIX_SIGSETJMP) -# define procenv_t sigjmp_buf -# if !defined (__OPENNT) -# define setjmp_nosigs(x) sigsetjmp((x), 0) -# define setjmp_sigs(x) sigsetjmp((x), 1) -# undef longjmp -# define longjmp(x, n) siglongjmp((x), (n)) -# endif /* !__OPENNT */ -#else -# define procenv_t jmp_buf -# define setjmp_nosigs setjmp -# define setjmp_sigs setjmp -#endif - -#endif /* _POSIXJMP_H_ */ diff --git a/jobs.c~ b/jobs.c~ deleted file mode 100644 index 56444e89d..000000000 --- a/jobs.c~ +++ /dev/null @@ -1,4545 +0,0 @@ -/* jobs.c - functions that make children, remember them, and handle their termination. */ - -/* This file works with both POSIX and BSD systems. It implements job - control. */ - -/* Copyright (C) 1989-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/bind.c~ b/lib/readline/bind.c~ deleted file mode 100644 index 8de2067bc..000000000 --- a/lib/readline/bind.c~ +++ /dev/null @@ -1,2586 +0,0 @@ -/* bind.c -- key binding and startup file support for the readline library. */ - -/* Copyright (C) 1987-2012 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (__TANDEM) -# include -#endif - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include "posixstat.h" - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - -/* Variables exported by this file. */ -Keymap rl_binding_keymap; - -static int _rl_skip_to_delim PARAMS((char *, int, int)); - -static char *_rl_read_file PARAMS((char *, size_t *)); -static void _rl_init_file_error PARAMS((const char *)); -static int _rl_read_init_file PARAMS((const char *, int)); -static int glean_key_from_name PARAMS((char *)); - -static int find_boolean_var PARAMS((const char *)); -static int find_string_var PARAMS((const char *)); - -static char *_rl_get_string_variable_value PARAMS((const char *)); -static int substring_member_of_array PARAMS((const char *, const char * const *)); - -static int currently_reading_init_file; - -/* used only in this file */ -static int _rl_prefer_visible_bell = 1; - -/* **************************************************************** */ -/* */ -/* Binding keys */ -/* */ -/* **************************************************************** */ - -/* rl_add_defun (char *name, rl_command_func_t *function, int key) - Add NAME to the list of named functions. Make FUNCTION be the function - that gets called. If KEY is not -1, then bind it. */ -int -rl_add_defun (name, function, key) - const char *name; - rl_command_func_t *function; - int key; -{ - if (key != -1) - rl_bind_key (key, function); - rl_add_funmap_entry (name, function); - return 0; -} - -/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ -int -rl_bind_key (key, function) - int key; - rl_command_func_t *function; -{ - if (key < 0) - return (key); - - if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) - { - if (_rl_keymap[ESC].type == ISKMAP) - { - Keymap escmap; - - escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); - key = UNMETA (key); - escmap[key].type = ISFUNC; - escmap[key].function = function; - return (0); - } - return (key); - } - - _rl_keymap[key].type = ISFUNC; - _rl_keymap[key].function = function; - rl_binding_keymap = _rl_keymap; - return (0); -} - -/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid - KEY. */ -int -rl_bind_key_in_map (key, function, map) - int key; - rl_command_func_t *function; - Keymap map; -{ - int result; - Keymap oldmap; - - oldmap = _rl_keymap; - _rl_keymap = map; - result = rl_bind_key (key, function); - _rl_keymap = oldmap; - return (result); -} - -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right - now, this is always used to attempt to bind the arrow keys, hence the - check for rl_vi_movement_mode. */ -int -rl_bind_key_if_unbound_in_map (key, default_func, kmap) - int key; - rl_command_func_t *default_func; - Keymap kmap; -{ - char keyseq[2]; - - keyseq[0] = (unsigned char)key; - keyseq[1] = '\0'; - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap)); -} - -int -rl_bind_key_if_unbound (key, default_func) - int key; - rl_command_func_t *default_func; -{ - char keyseq[2]; - - keyseq[0] = (unsigned char)key; - keyseq[1] = '\0'; - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); -} - -/* Make KEY do nothing in the currently selected keymap. - Returns non-zero in case of error. */ -int -rl_unbind_key (key) - int key; -{ - return (rl_bind_key (key, (rl_command_func_t *)NULL)); -} - -/* Make KEY do nothing in MAP. - Returns non-zero in case of error. */ -int -rl_unbind_key_in_map (key, map) - int key; - Keymap map; -{ - return (rl_bind_key_in_map (key, (rl_command_func_t *)NULL, map)); -} - -/* Unbind all keys bound to FUNCTION in MAP. */ -int -rl_unbind_function_in_map (func, map) - rl_command_func_t *func; - Keymap map; -{ - register int i, rval; - - for (i = rval = 0; i < KEYMAP_SIZE; i++) - { - if (map[i].type == ISFUNC && map[i].function == func) - { - map[i].function = (rl_command_func_t *)NULL; - rval = 1; - } - } - return rval; -} - -int -rl_unbind_command_in_map (command, map) - const char *command; - Keymap map; -{ - rl_command_func_t *func; - - func = rl_named_function (command); - if (func == 0) - return 0; - return (rl_unbind_function_in_map (func, map)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION, starting in the current keymap. This makes new - keymaps as necessary. */ -int -rl_bind_keyseq (keyseq, function) - const char *keyseq; - rl_command_func_t *function; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION. This makes new keymaps as necessary. The initial - place to do bindings is in MAP. */ -int -rl_bind_keyseq_in_map (keyseq, function, map) - const char *keyseq; - rl_command_func_t *function; - Keymap map; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); -} - -/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */ -int -rl_set_key (keyseq, function, map) - const char *keyseq; - rl_command_func_t *function; - Keymap map; -{ - return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); -} - -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right - now, this is always used to attempt to bind the arrow keys, hence the - check for rl_vi_movement_mode. */ -int -rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap) - const char *keyseq; - rl_command_func_t *default_func; - Keymap kmap; -{ - rl_command_func_t *func; - - if (keyseq) - { - func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL); -#if defined (VI_MODE) - if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) -#else - if (!func || func == rl_do_lowercase_version) -#endif - return (rl_bind_keyseq_in_map (keyseq, default_func, kmap)); - else - return 1; - } - return 0; -} - -int -rl_bind_keyseq_if_unbound (keyseq, default_func) - const char *keyseq; - rl_command_func_t *default_func; -{ - return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the string of characters MACRO. This makes new keymaps as - necessary. The initial place to do bindings is in MAP. */ -int -rl_macro_bind (keyseq, macro, map) - const char *keyseq, *macro; - Keymap map; -{ - char *macro_keys; - int macro_keys_len; - - macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); - - if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) - { - xfree (macro_keys); - return -1; - } - rl_generic_bind (ISMACR, keyseq, macro_keys, map); - return 0; -} - -/* Bind the key sequence represented by the string KEYSEQ to - the arbitrary pointer DATA. TYPE says what kind of data is - pointed to by DATA, right now this can be a function (ISFUNC), - a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps - as necessary. The initial place to do bindings is in MAP. */ -int -rl_generic_bind (type, keyseq, data, map) - int type; - const char *keyseq; - char *data; - Keymap map; -{ - char *keys; - int keys_len; - register int i; - KEYMAP_ENTRY k; - - k.function = 0; - - /* If no keys to bind to, exit right away. */ - if (keyseq == 0 || *keyseq == 0) - { - if (type == ISMACR) - xfree (data); - return -1; - } - - keys = (char *)xmalloc (1 + (2 * strlen (keyseq))); - - /* Translate the ASCII representation of KEYSEQ into an array of - characters. Stuff the characters into KEYS, and the length of - KEYS into KEYS_LEN. */ - if (rl_translate_keyseq (keyseq, keys, &keys_len)) - { - xfree (keys); - return -1; - } - - /* Bind keys, making new keymaps as necessary. */ - for (i = 0; i < keys_len; i++) - { - unsigned char uc = keys[i]; - int ic; - - ic = uc; - if (ic < 0 || ic >= KEYMAP_SIZE) - { - xfree (keys); - return -1; - } - - if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) - { - ic = UNMETA (ic); - if (map[ESC].type == ISKMAP) - map = FUNCTION_TO_KEYMAP (map, ESC); - } - - if ((i + 1) < keys_len) - { - if (map[ic].type != ISKMAP) - { - /* We allow subsequences of keys. If a keymap is being - created that will `shadow' an existing function or macro - key binding, we save that keybinding into the ANYOTHERKEY - index in the new map. The dispatch code will look there - to find the function to execute if the subsequence is not - matched. ANYOTHERKEY was chosen to be greater than - UCHAR_MAX. */ - k = map[ic]; - - map[ic].type = ISKMAP; - map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); - } - map = FUNCTION_TO_KEYMAP (map, ic); - /* The dispatch code will return this function if no matching - key sequence is found in the keymap. This (with a little - help from the dispatch code in readline.c) allows `a' to be - mapped to something, `abc' to be mapped to something else, - and the function bound to `a' to be executed when the user - types `abx', leaving `bx' in the input queue. */ - if (k.function && ((k.type == ISFUNC && k.function != rl_do_lowercase_version) || k.type == ISMACR)) - { - map[ANYOTHERKEY] = k; - k.function = 0; - } - } - else - { - if (map[ic].type == ISMACR) - xfree ((char *)map[ic].function); - else if (map[ic].type == ISKMAP) - { - map = FUNCTION_TO_KEYMAP (map, ic); - ic = ANYOTHERKEY; - /* If we're trying to override a keymap with a null function - (e.g., trying to unbind it), we can't use a null pointer - here because that's indistinguishable from having not been - overridden. We use a special bindable function that does - nothing. */ - if (type == ISFUNC && data == 0) - data = (char *)_rl_null_function; - } - - map[ic].function = KEYMAP_TO_FUNCTION (data); - map[ic].type = type; - } - - rl_binding_keymap = map; - } - xfree (keys); - return 0; -} - -/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY, - an array of characters. LEN gets the final length of ARRAY. Return - non-zero if there was an error parsing SEQ. */ -int -rl_translate_keyseq (seq, array, len) - const char *seq; - char *array; - int *len; -{ - register int i, c, l, temp; - - for (i = l = 0; c = seq[i]; i++) - { - if (c == '\\') - { - c = seq[++i]; - - if (c == 0) - break; - - /* Handle \C- and \M- prefixes. */ - if ((c == 'C' || c == 'M') && seq[i + 1] == '-') - { - /* Handle special case of backwards define. */ - if (strncmp (&seq[i], "C-\\M-", 5) == 0) - { - array[l++] = ESC; /* ESC is meta-prefix */ - i += 5; - array[l++] = CTRL (_rl_to_upper (seq[i])); - if (seq[i] == '\0') - i--; - } - else if (c == 'M') - { - i++; /* seq[i] == '-' */ - /* XXX - obey convert-meta setting */ - if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP) - array[l++] = ESC; /* ESC is meta-prefix */ - else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-') - { - i += 4; - temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - array[l++] = META (temp); - } - else - { - /* This doesn't yet handle things like \M-\a, which may - or may not have any reasonable meaning. You're - probably better off using straight octal or hex. */ - i++; - array[l++] = META (seq[i]); - } - } - else if (c == 'C') - { - i += 2; - /* Special hack for C-?... */ - array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - } - continue; - } - - /* Translate other backslash-escaped characters. These are the - same escape sequences that bash's `echo' and `printf' builtins - handle, with the addition of \d -> RUBOUT. A backslash - preceding a character that is not special is stripped. */ - switch (c) - { - case 'a': - array[l++] = '\007'; - break; - case 'b': - array[l++] = '\b'; - break; - case 'd': - array[l++] = RUBOUT; /* readline-specific */ - break; - case 'e': - array[l++] = ESC; - break; - case 'f': - array[l++] = '\f'; - break; - case 'n': - array[l++] = NEWLINE; - break; - case 'r': - array[l++] = RETURN; - break; - case 't': - array[l++] = TAB; - break; - case 'v': - array[l++] = 0x0B; - break; - case '\\': - array[l++] = '\\'; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - i++; - for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++) - c = (c * 8) + OCTVALUE (seq[i]); - i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; - break; - case 'x': - i++; - for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++) - c = (c * 16) + HEXVALUE (seq[i]); - if (temp == 2) - c = 'x'; - i--; /* auto-increment in for loop */ - array[l++] = c & largest_char; - break; - default: /* backslashes before non-special chars just add the char */ - array[l++] = c; - break; /* the backslash is stripped */ - } - continue; - } - - array[l++] = c; - } - - *len = l; - array[l] = '\0'; - return (0); -} - -static int -_rl_isescape (c) - int c; -{ - switch (c) - { - case '\007': - case '\b': - case '\f': - case '\n': - case '\r': - case TAB: - case 0x0b: return (1); - default: return (0); - } -} - -static int -_rl_escchar (c) - int c; -{ - switch (c) - { - case '\007': return ('a'); - case '\b': return ('b'); - case '\f': return ('f'); - case '\n': return ('n'); - case '\r': return ('r'); - case TAB: return ('t'); - case 0x0b: return ('v'); - default: return (c); - } -} - -char * -rl_untranslate_keyseq (seq) - int seq; -{ - static char kseq[16]; - int i, c; - - i = 0; - c = seq; - if (META_CHAR (c)) - { - kseq[i++] = '\\'; - kseq[i++] = 'M'; - kseq[i++] = '-'; - c = UNMETA (c); - } - else if (c == ESC) - { - kseq[i++] = '\\'; - c = 'e'; - } - else if (CTRL_CHAR (c)) - { - kseq[i++] = '\\'; - kseq[i++] = 'C'; - kseq[i++] = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - else if (c == RUBOUT) - { - kseq[i++] = '\\'; - kseq[i++] = 'C'; - kseq[i++] = '-'; - c = '?'; - } - - if (c == ESC) - { - kseq[i++] = '\\'; - c = 'e'; - } - else if (c == '\\' || c == '"') - { - kseq[i++] = '\\'; - } - - kseq[i++] = (unsigned char) c; - kseq[i] = '\0'; - return kseq; -} - -char * -_rl_untranslate_macro_value (seq, use_escapes) - char *seq; - int use_escapes; -{ - char *ret, *r, *s; - int c; - - r = ret = (char *)xmalloc (7 * strlen (seq) + 1); - for (s = seq; *s; s++) - { - c = *s; - if (META_CHAR (c)) - { - *r++ = '\\'; - *r++ = 'M'; - *r++ = '-'; - c = UNMETA (c); - } - else if (c == ESC) - { - *r++ = '\\'; - c = 'e'; - } - else if (CTRL_CHAR (c)) - { - *r++ = '\\'; - if (use_escapes && _rl_isescape (c)) - c = _rl_escchar (c); - else - { - *r++ = 'C'; - *r++ = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - } - else if (c == RUBOUT) - { - *r++ = '\\'; - *r++ = 'C'; - *r++ = '-'; - c = '?'; - } - - if (c == ESC) - { - *r++ = '\\'; - c = 'e'; - } - else if (c == '\\' || c == '"') - *r++ = '\\'; - - *r++ = (unsigned char)c; - } - *r = '\0'; - return ret; -} - -/* Return a pointer to the function that STRING represents. - If STRING doesn't have a matching function, then a NULL pointer - is returned. */ -rl_command_func_t * -rl_named_function (string) - const char *string; -{ - register int i; - - rl_initialize_funmap (); - - for (i = 0; funmap[i]; i++) - if (_rl_stricmp (funmap[i]->name, string) == 0) - return (funmap[i]->function); - return ((rl_command_func_t *)NULL); -} - -/* Return the function (or macro) definition which would be invoked via - KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is - used. TYPE, if non-NULL, is a pointer to an int which will receive the - type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap), - or ISMACR (macro). */ -rl_command_func_t * -rl_function_of_keyseq (keyseq, map, type) - const char *keyseq; - Keymap map; - int *type; -{ - register int i; - - if (map == 0) - map = _rl_keymap; - - for (i = 0; keyseq && keyseq[i]; i++) - { - unsigned char ic = keyseq[i]; - - if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) - { - if (map[ESC].type == ISKMAP) - { - map = FUNCTION_TO_KEYMAP (map, ESC); - ic = UNMETA (ic); - } - /* XXX - should we just return NULL here, since this obviously - doesn't match? */ - else - { - if (type) - *type = map[ESC].type; - - return (map[ESC].function); - } - } - - if (map[ic].type == ISKMAP) - { - /* If this is the last key in the key sequence, return the - map. */ - if (keyseq[i + 1] == '\0') - { - if (type) - *type = ISKMAP; - - return (map[ic].function); - } - else - map = FUNCTION_TO_KEYMAP (map, ic); - } - /* If we're not at the end of the key sequence, and the current key - is bound to something other than a keymap, then the entire key - sequence is not bound. */ - else if (map[ic].type != ISKMAP && keyseq[i+1]) - return ((rl_command_func_t *)NULL); - else /* map[ic].type != ISKMAP && keyseq[i+1] == 0 */ - { - if (type) - *type = map[ic].type; - - return (map[ic].function); - } - } - return ((rl_command_func_t *) NULL); -} - -/* The last key bindings file read. */ -static char *last_readline_init_file = (char *)NULL; - -/* The file we're currently reading key bindings from. */ -static const char *current_readline_init_file; -static int current_readline_init_include_level; -static int current_readline_init_lineno; - -/* Read FILENAME into a locally-allocated buffer and return the buffer. - The size of the buffer is returned in *SIZEP. Returns NULL if any - errors were encountered. */ -static char * -_rl_read_file (filename, sizep) - char *filename; - size_t *sizep; -{ - struct stat finfo; - size_t file_size; - char *buffer; - int i, file; - - if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0) - return ((char *)NULL); - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - if (file >= 0) - close (file); -#if defined (EFBIG) - errno = EFBIG; -#endif - return ((char *)NULL); - } - - /* Read the file into BUFFER. */ - buffer = (char *)xmalloc (file_size + 1); - i = read (file, buffer, file_size); - close (file); - - if (i < 0) - { - xfree (buffer); - return ((char *)NULL); - } - - RL_CHECK_SIGNALS (); - - buffer[i] = '\0'; - if (sizep) - *sizep = i; - - return (buffer); -} - -/* Re-read the current keybindings file. */ -int -rl_re_read_init_file (count, ignore) - int count, ignore; -{ - int r; - r = rl_read_init_file ((const char *)NULL); - rl_set_keymap_from_edit_mode (); - return r; -} - -/* Do key bindings from a file. If FILENAME is NULL it defaults - to the first non-null filename from this list: - 1. the filename used for the previous call - 2. the value of the shell variable `INPUTRC' - 3. ~/.inputrc - 4. /etc/inputrc - If the file existed and could be opened and read, 0 is returned, - otherwise errno is returned. */ -int -rl_read_init_file (filename) - const char *filename; -{ - /* Default the filename. */ - if (filename == 0) - filename = last_readline_init_file; - if (filename == 0) - filename = sh_get_env_value ("INPUTRC"); - if (filename == 0 || *filename == 0) - { - filename = DEFAULT_INPUTRC; - /* Try to read DEFAULT_INPUTRC; fall back to SYS_INPUTRC on failure */ - if (_rl_read_init_file (filename, 0) == 0) - return 0; - filename = SYS_INPUTRC; - } - -#if defined (__MSDOS__) - if (_rl_read_init_file (filename, 0) == 0) - return 0; - filename = "~/_inputrc"; -#endif - return (_rl_read_init_file (filename, 0)); -} - -static int -_rl_read_init_file (filename, include_level) - const char *filename; - int include_level; -{ - register int i; - char *buffer, *openname, *line, *end; - size_t file_size; - - current_readline_init_file = filename; - current_readline_init_include_level = include_level; - - openname = tilde_expand (filename); - buffer = _rl_read_file (openname, &file_size); - xfree (openname); - - RL_CHECK_SIGNALS (); - if (buffer == 0) - return (errno); - - if (include_level == 0 && filename != last_readline_init_file) - { - FREE (last_readline_init_file); - last_readline_init_file = savestring (filename); - } - - currently_reading_init_file = 1; - - /* Loop over the lines in the file. Lines that start with `#' are - comments; all other lines are commands for readline initialization. */ - current_readline_init_lineno = 1; - line = buffer; - end = buffer + file_size; - while (line < end) - { - /* Find the end of this line. */ - for (i = 0; line + i != end && line[i] != '\n'; i++); - -#if defined (__CYGWIN__) - /* ``Be liberal in what you accept.'' */ - if (line[i] == '\n' && line[i-1] == '\r') - line[i - 1] = '\0'; -#endif - - /* Mark end of line. */ - line[i] = '\0'; - - /* Skip leading whitespace. */ - while (*line && whitespace (*line)) - { - line++; - i--; - } - - /* If the line is not a comment, then parse it. */ - if (*line && *line != '#') - rl_parse_and_bind (line); - - /* Move to the next line. */ - line += i + 1; - current_readline_init_lineno++; - } - - xfree (buffer); - currently_reading_init_file = 0; - return (0); -} - -static void -_rl_init_file_error (msg) - const char *msg; -{ - if (currently_reading_init_file) - _rl_errmsg ("%s: line %d: %s\n", current_readline_init_file, - current_readline_init_lineno, msg); - else - _rl_errmsg ("%s", msg); -} - -/* **************************************************************** */ -/* */ -/* Parser Directives */ -/* */ -/* **************************************************************** */ - -typedef int _rl_parser_func_t PARAMS((char *)); - -/* Things that mean `Control'. */ -const char * const _rl_possible_control_prefixes[] = { - "Control-", "C-", "CTRL-", (const char *)NULL -}; - -const char * const _rl_possible_meta_prefixes[] = { - "Meta", "M-", (const char *)NULL -}; - -/* Conditionals. */ - -/* Calling programs set this to have their argv[0]. */ -const char *rl_readline_name = "other"; - -/* Stack of previous values of parsing_conditionalized_out. */ -static unsigned char *if_stack = (unsigned char *)NULL; -static int if_stack_depth; -static int if_stack_size; - -/* Push _rl_parsing_conditionalized_out, and set parser state based - on ARGS. */ -static int -parser_if (args) - char *args; -{ - register int i; - - /* Push parser state. */ - if (if_stack_depth + 1 >= if_stack_size) - { - if (!if_stack) - if_stack = (unsigned char *)xmalloc (if_stack_size = 20); - else - if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); - } - if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out; - - /* If parsing is turned off, then nothing can turn it back on except - for finding the matching endif. In that case, return right now. */ - if (_rl_parsing_conditionalized_out) - return 0; - - /* Isolate first argument. */ - for (i = 0; args[i] && !whitespace (args[i]); i++); - - if (args[i]) - args[i++] = '\0'; - - /* Handle "$if term=foo" and "$if mode=emacs" constructs. If this - isn't term=foo, or mode=emacs, then check to see if the first - word in ARGS is the same as the value stored in rl_readline_name. */ - if (rl_terminal_name && _rl_strnicmp (args, "term=", 5) == 0) - { - char *tem, *tname; - - /* Terminals like "aaa-60" are equivalent to "aaa". */ - tname = savestring (rl_terminal_name); - tem = strchr (tname, '-'); - if (tem) - *tem = '\0'; - - /* Test the `long' and `short' forms of the terminal name so that - if someone has a `sun-cmd' and does not want to have bindings - that will be executed if the terminal is a `sun', they can put - `$if term=sun-cmd' into their .inputrc. */ - _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && - _rl_stricmp (args + 5, rl_terminal_name); - xfree (tname); - } -#if defined (VI_MODE) - else if (_rl_strnicmp (args, "mode=", 5) == 0) - { - int mode; - - if (_rl_stricmp (args + 5, "emacs") == 0) - mode = emacs_mode; - else if (_rl_stricmp (args + 5, "vi") == 0) - mode = vi_mode; - else - mode = no_mode; - - _rl_parsing_conditionalized_out = mode != rl_editing_mode; - } -#endif /* VI_MODE */ - /* Check to see if the first word in ARGS is the same as the - value stored in rl_readline_name. */ - else if (_rl_stricmp (args, rl_readline_name) == 0) - _rl_parsing_conditionalized_out = 0; - else - _rl_parsing_conditionalized_out = 1; - return 0; -} - -/* Invert the current parser state if there is anything on the stack. */ -static int -parser_else (args) - char *args; -{ - register int i; - - if (if_stack_depth == 0) - { - _rl_init_file_error ("$else found without matching $if"); - return 0; - } - -#if 0 - /* Check the previous (n - 1) levels of the stack to make sure that - we haven't previously turned off parsing. */ - for (i = 0; i < if_stack_depth - 1; i++) -#else - /* Check the previous (n) levels of the stack to make sure that - we haven't previously turned off parsing. */ - for (i = 0; i < if_stack_depth; i++) -#endif - if (if_stack[i] == 1) - return 0; - - /* Invert the state of parsing if at top level. */ - _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out; - return 0; -} - -/* Terminate a conditional, popping the value of - _rl_parsing_conditionalized_out from the stack. */ -static int -parser_endif (args) - char *args; -{ - if (if_stack_depth) - _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; - else - _rl_init_file_error ("$endif without matching $if"); - return 0; -} - -static int -parser_include (args) - char *args; -{ - const char *old_init_file; - char *e; - int old_line_number, old_include_level, r; - - if (_rl_parsing_conditionalized_out) - return (0); - - old_init_file = current_readline_init_file; - old_line_number = current_readline_init_lineno; - old_include_level = current_readline_init_include_level; - - e = strchr (args, '\n'); - if (e) - *e = '\0'; - r = _rl_read_init_file ((const char *)args, old_include_level + 1); - - current_readline_init_file = old_init_file; - current_readline_init_lineno = old_line_number; - current_readline_init_include_level = old_include_level; - - return r; -} - -/* Associate textual names with actual functions. */ -static const struct { - const char * const name; - _rl_parser_func_t *function; -} parser_directives [] = { - { "if", parser_if }, - { "endif", parser_endif }, - { "else", parser_else }, - { "include", parser_include }, - { (char *)0x0, (_rl_parser_func_t *)0x0 } -}; - -/* Handle a parser directive. STATEMENT is the line of the directive - without any leading `$'. */ -static int -handle_parser_directive (statement) - char *statement; -{ - register int i; - char *directive, *args; - - /* Isolate the actual directive. */ - - /* Skip whitespace. */ - for (i = 0; whitespace (statement[i]); i++); - - directive = &statement[i]; - - for (; statement[i] && !whitespace (statement[i]); i++); - - if (statement[i]) - statement[i++] = '\0'; - - for (; statement[i] && whitespace (statement[i]); i++); - - args = &statement[i]; - - /* Lookup the command, and act on it. */ - for (i = 0; parser_directives[i].name; i++) - if (_rl_stricmp (directive, parser_directives[i].name) == 0) - { - (*parser_directives[i].function) (args); - return (0); - } - - /* display an error message about the unknown parser directive */ - _rl_init_file_error ("unknown parser directive"); - return (1); -} - -/* Start at STRING[START] and look for DELIM. Return I where STRING[I] == - DELIM or STRING[I] == 0. DELIM is usually a double quote. */ -static int -_rl_skip_to_delim (string, start, delim) - char *string; - int start, delim; -{ - int i, c, passc; - - for (i = start,passc = 0; c = string[i]; i++) - { - if (passc) - { - passc = 0; - if (c == 0) - break; - continue; - } - - if (c == '\\') - { - passc = 1; - continue; - } - - if (c == delim) - break; - } - - return i; -} - -/* Read the binding command from STRING and perform it. - A key binding command looks like: Keyname: function-name\0, - a variable binding command looks like: set variable value. - A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ -int -rl_parse_and_bind (string) - char *string; -{ - char *funname, *kname; - register int c, i; - int key, equivalency; - - while (string && whitespace (*string)) - string++; - - if (string == 0 || *string == 0 || *string == '#') - return 0; - - /* If this is a parser directive, act on it. */ - if (*string == '$') - { - handle_parser_directive (&string[1]); - return 0; - } - - /* If we aren't supposed to be parsing right now, then we're done. */ - if (_rl_parsing_conditionalized_out) - return 0; - - i = 0; - /* If this keyname is a complex key expression surrounded by quotes, - advance to after the matching close quote. This code allows the - backslash to quote characters in the key expression. */ - if (*string == '"') - { - i = _rl_skip_to_delim (string, 1, '"'); - - /* If we didn't find a closing quote, abort the line. */ - if (string[i] == '\0') - { - _rl_init_file_error ("no closing `\"' in key binding"); - return 1; - } - else - i++; /* skip past closing double quote */ - } - - /* Advance to the colon (:) or whitespace which separates the two objects. */ - for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); - - equivalency = (c == ':' && string[i + 1] == '='); - - /* Mark the end of the command (or keyname). */ - if (string[i]) - string[i++] = '\0'; - - /* If doing assignment, skip the '=' sign as well. */ - if (equivalency) - string[i++] = '\0'; - - /* If this is a command to set a variable, then do that. */ - if (_rl_stricmp (string, "set") == 0) - { - char *var, *value, *e; - int s; - - var = string + i; - /* Make VAR point to start of variable name. */ - while (*var && whitespace (*var)) var++; - - /* Make VALUE point to start of value string. */ - value = var; - while (*value && whitespace (*value) == 0) value++; - if (*value) - *value++ = '\0'; - while (*value && whitespace (*value)) value++; - - /* Strip trailing whitespace from values of boolean variables. */ - if (find_boolean_var (var) >= 0) - { - /* remove trailing whitespace */ -remove_trailing: - e = value + strlen (value) - 1; - while (e >= value && whitespace (*e)) - e--; - e++; /* skip back to whitespace or EOS */ - - if (*e && e >= value) - *e = '\0'; - } - else if ((i = find_string_var (var)) >= 0) - { - /* Allow quoted strings in variable values */ - if (*value == '"') - { - i = _rl_skip_to_delim (value, 1, *value); - value[i] = '\0'; - value++; /* skip past the quote */ - } - else - goto remove_trailing; - } - - rl_variable_bind (var, value); - return 0; - } - - /* Skip any whitespace between keyname and funname. */ - for (; string[i] && whitespace (string[i]); i++); - funname = &string[i]; - - /* Now isolate funname. - For straight function names just look for whitespace, since - that will signify the end of the string. But this could be a - macro definition. In that case, the string is quoted, so skip - to the matching delimiter. We allow the backslash to quote the - delimiter characters in the macro body. */ - /* This code exists to allow whitespace in macro expansions, which - would otherwise be gobbled up by the next `for' loop.*/ - /* XXX - it may be desirable to allow backslash quoting only if " is - the quoted string delimiter, like the shell. */ - if (*funname == '\'' || *funname == '"') - { - i = _rl_skip_to_delim (string, i+1, *funname); - if (string[i]) - i++; - } - - /* Advance to the end of the string. */ - for (; string[i] && whitespace (string[i]) == 0; i++); - - /* No extra whitespace at the end of the string. */ - string[i] = '\0'; - - /* Handle equivalency bindings here. Make the left-hand side be exactly - whatever the right-hand evaluates to, including keymaps. */ - if (equivalency) - { - return 0; - } - - /* If this is a new-style key-binding, then do the binding with - rl_bind_keyseq (). Otherwise, let the older code deal with it. */ - if (*string == '"') - { - char *seq; - register int j, k, passc; - - seq = (char *)xmalloc (1 + strlen (string)); - for (j = 1, k = passc = 0; string[j]; j++) - { - /* Allow backslash to quote characters, but leave them in place. - This allows a string to end with a backslash quoting another - backslash, or with a backslash quoting a double quote. The - backslashes are left in place for rl_translate_keyseq (). */ - if (passc || (string[j] == '\\')) - { - seq[k++] = string[j]; - passc = !passc; - continue; - } - - if (string[j] == '"') - break; - - seq[k++] = string[j]; - } - seq[k] = '\0'; - - /* Binding macro? */ - if (*funname == '\'' || *funname == '"') - { - j = strlen (funname); - - /* Remove the delimiting quotes from each end of FUNNAME. */ - if (j && funname[j - 1] == *funname) - funname[j - 1] = '\0'; - - rl_macro_bind (seq, &funname[1], _rl_keymap); - } - else - rl_bind_keyseq (seq, rl_named_function (funname)); - - xfree (seq); - return 0; - } - - /* Get the actual character we want to deal with. */ - kname = strrchr (string, '-'); - if (kname == 0) - kname = string; - else - kname++; - - key = glean_key_from_name (kname); - - /* Add in control and meta bits. */ - if (substring_member_of_array (string, _rl_possible_control_prefixes)) - key = CTRL (_rl_to_upper (key)); - - if (substring_member_of_array (string, _rl_possible_meta_prefixes)) - key = META (key); - - /* Temporary. Handle old-style keyname with macro-binding. */ - if (*funname == '\'' || *funname == '"') - { - char useq[2]; - int fl = strlen (funname); - - useq[0] = key; useq[1] = '\0'; - if (fl && funname[fl - 1] == *funname) - funname[fl - 1] = '\0'; - - rl_macro_bind (useq, &funname[1], _rl_keymap); - } -#if defined (PREFIX_META_HACK) - /* Ugly, but working hack to keep prefix-meta around. */ - else if (_rl_stricmp (funname, "prefix-meta") == 0) - { - char seq[2]; - - seq[0] = key; - seq[1] = '\0'; - rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap); - } -#endif /* PREFIX_META_HACK */ - else - rl_bind_key (key, rl_named_function (funname)); - return 0; -} - -/* Simple structure for boolean readline variables (i.e., those that can - have one of two values; either "On" or 1 for truth, or "Off" or 0 for - false. */ - -#define V_SPECIAL 0x1 - -static const struct { - const char * const name; - int *value; - int flags; -} boolean_varlist [] = { - { "bind-tty-special-chars", &_rl_bind_stty_chars, 0 }, - { "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL }, - { "byte-oriented", &rl_byte_oriented, 0 }, -#if defined (COLOR_SUPPORT) - { "colored-completion-prefix",&_rl_colored_completion_prefix, 0 }, - { "colored-stats", &_rl_colored_stats, 0 }, -#endif - { "completion-ignore-case", &_rl_completion_case_fold, 0 }, - { "completion-map-case", &_rl_completion_case_map, 0 }, - { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, - { "disable-completion", &rl_inhibit_completion, 0 }, - { "echo-control-characters", &_rl_echo_control_chars, 0 }, - { "enable-bracketed-paste", &_rl_enable_bracketed_paste, 0 }, - { "enable-keypad", &_rl_enable_keypad, 0 }, - { "enable-meta-key", &_rl_enable_meta, 0 }, - { "expand-tilde", &rl_complete_with_tilde_expansion, 0 }, - { "history-preserve-point", &_rl_history_preserve_point, 0 }, - { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode, 0 }, - { "input-meta", &_rl_meta_flag, 0 }, - { "mark-directories", &_rl_complete_mark_directories, 0 }, - { "mark-modified-lines", &_rl_mark_modified_lines, 0 }, - { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 }, - { "match-hidden-files", &_rl_match_hidden_files, 0 }, - { "menu-complete-display-prefix", &_rl_menu_complete_prefix_first, 0 }, - { "meta-flag", &_rl_meta_flag, 0 }, - { "output-meta", &_rl_output_meta_chars, 0 }, - { "page-completions", &_rl_page_completions, 0 }, - { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, - { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, - { "revert-all-at-newline", &_rl_revert_all_at_newline, 0 }, - { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, - { "show-all-if-unmodified", &_rl_complete_show_unmodified, 0 }, - { "show-mode-in-prompt", &_rl_show_mode_in_prompt, 0 }, - { "skip-completed-text", &_rl_skip_completed_text, 0 }, -#if defined (VISIBLE_STATS) - { "visible-stats", &rl_visible_stats, 0 }, -#endif /* VISIBLE_STATS */ - { (char *)NULL, (int *)NULL, 0 } -}; - -static int -find_boolean_var (name) - const char *name; -{ - register int i; - - for (i = 0; boolean_varlist[i].name; i++) - if (_rl_stricmp (name, boolean_varlist[i].name) == 0) - return i; - return -1; -} - -/* Hooks for handling special boolean variables, where a - function needs to be called or another variable needs - to be changed when they're changed. */ -static void -hack_special_boolean_var (i) - int i; -{ - const char *name; - - name = boolean_varlist[i].name; - - if (_rl_stricmp (name, "blink-matching-paren") == 0) - _rl_enable_paren_matching (rl_blink_matching_paren); - else if (_rl_stricmp (name, "prefer-visible-bell") == 0) - { - if (_rl_prefer_visible_bell) - _rl_bell_preference = VISIBLE_BELL; - else - _rl_bell_preference = AUDIBLE_BELL; - } - else if (_rl_stricmp (name, "show-mode-in-prompt") == 0) - _rl_reset_prompt (); -} - -typedef int _rl_sv_func_t PARAMS((const char *)); - -/* These *must* correspond to the array indices for the appropriate - string variable. (Though they're not used right now.) */ -#define V_BELLSTYLE 0 -#define V_COMBEGIN 1 -#define V_EDITMODE 2 -#define V_ISRCHTERM 3 -#define V_KEYMAP 4 - -#define V_STRING 1 -#define V_INT 2 - -/* Forward declarations */ -static int sv_bell_style PARAMS((const char *)); -static int sv_combegin PARAMS((const char *)); -static int sv_dispprefix PARAMS((const char *)); -static int sv_compquery PARAMS((const char *)); -static int sv_compwidth PARAMS((const char *)); -static int sv_editmode PARAMS((const char *)); -static int sv_emacs_modestr PARAMS((const char *)); -static int sv_histsize PARAMS((const char *)); -static int sv_isrchterm PARAMS((const char *)); -static int sv_keymap PARAMS((const char *)); -static int sv_seqtimeout PARAMS((const char *)); -static int sv_viins_modestr PARAMS((const char *)); -static int sv_vicmd_modestr PARAMS((const char *)); - -static const struct { - const char * const name; - int flags; - _rl_sv_func_t *set_func; -} string_varlist[] = { - { "bell-style", V_STRING, sv_bell_style }, - { "comment-begin", V_STRING, sv_combegin }, - { "completion-display-width", V_INT, sv_compwidth }, - { "completion-prefix-display-length", V_INT, sv_dispprefix }, - { "completion-query-items", V_INT, sv_compquery }, - { "editing-mode", V_STRING, sv_editmode }, - { "emacs-mode-string", V_STRING, sv_emacs_modestr }, - { "history-size", V_INT, sv_histsize }, - { "isearch-terminators", V_STRING, sv_isrchterm }, - { "keymap", V_STRING, sv_keymap }, - { "keyseq-timeout", V_INT, sv_seqtimeout }, - { "vi-cmd-mode-string", V_STRING, sv_vicmd_modestr }, - { "vi-ins-mode-string", V_STRING, sv_viins_modestr }, - { (char *)NULL, 0, (_rl_sv_func_t *)0 } -}; - -static int -find_string_var (name) - const char *name; -{ - register int i; - - for (i = 0; string_varlist[i].name; i++) - if (_rl_stricmp (name, string_varlist[i].name) == 0) - return i; - return -1; -} - -/* A boolean value that can appear in a `set variable' command is true if - the value is null or empty, `on' (case-insensitive), or "1". Any other - values result in 0 (false). */ -static int -bool_to_int (value) - const char *value; -{ - return (value == 0 || *value == '\0' || - (_rl_stricmp (value, "on") == 0) || - (value[0] == '1' && value[1] == '\0')); -} - -char * -rl_variable_value (name) - const char *name; -{ - register int i; - - /* Check for simple variables first. */ - i = find_boolean_var (name); - if (i >= 0) - return (*boolean_varlist[i].value ? "on" : "off"); - - i = find_string_var (name); - if (i >= 0) - return (_rl_get_string_variable_value (string_varlist[i].name)); - - /* Unknown variable names return NULL. */ - return 0; -} - -int -rl_variable_bind (name, value) - const char *name, *value; -{ - register int i; - int v; - - /* Check for simple variables first. */ - i = find_boolean_var (name); - if (i >= 0) - { - *boolean_varlist[i].value = bool_to_int (value); - if (boolean_varlist[i].flags & V_SPECIAL) - hack_special_boolean_var (i); - return 0; - } - - i = find_string_var (name); - - /* For the time being, unknown variable names or string names without a - handler function are simply ignored. */ - if (i < 0 || string_varlist[i].set_func == 0) - return 0; - - v = (*string_varlist[i].set_func) (value); - return v; -} - -static int -sv_editmode (value) - const char *value; -{ - if (_rl_strnicmp (value, "vi", 2) == 0) - { -#if defined (VI_MODE) - _rl_keymap = vi_insertion_keymap; - rl_editing_mode = vi_mode; -#endif /* VI_MODE */ - return 0; - } - else if (_rl_strnicmp (value, "emacs", 5) == 0) - { - _rl_keymap = emacs_standard_keymap; - rl_editing_mode = emacs_mode; - return 0; - } - return 1; -} - -static int -sv_combegin (value) - const char *value; -{ - if (value && *value) - { - FREE (_rl_comment_begin); - _rl_comment_begin = savestring (value); - return 0; - } - return 1; -} - -static int -sv_dispprefix (value) - const char *value; -{ - int nval = 0; - - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - _rl_completion_prefix_display_length = nval; - return 0; -} - -static int -sv_compquery (value) - const char *value; -{ - int nval = 100; - - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - rl_completion_query_items = nval; - return 0; -} - -static int -sv_compwidth (value) - const char *value; -{ - int nval = -1; - - if (value && *value) - nval = atoi (value); - - _rl_completion_columns = nval; - return 0; -} - -static int -sv_histsize (value) - const char *value; -{ - int nval; - - nval = 500; - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - { - unstifle_history (); - return 0; - } - } - stifle_history (nval); - return 0; -} - -static int -sv_keymap (value) - const char *value; -{ - Keymap kmap; - - kmap = rl_get_keymap_by_name (value); - if (kmap) - { - rl_set_keymap (kmap); - return 0; - } - return 1; -} - -static int -sv_seqtimeout (value) - const char *value; -{ - int nval; - - nval = 0; - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - _rl_keyseq_timeout = nval; - return 0; -} - -static int -sv_bell_style (value) - const char *value; -{ - if (value == 0 || *value == '\0') - _rl_bell_preference = AUDIBLE_BELL; - else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0) - _rl_bell_preference = NO_BELL; - else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0) - _rl_bell_preference = AUDIBLE_BELL; - else if (_rl_stricmp (value, "visible") == 0) - _rl_bell_preference = VISIBLE_BELL; - else - return 1; - return 0; -} - -static int -sv_isrchterm (value) - const char *value; -{ - int beg, end, delim; - char *v; - - if (value == 0) - return 1; - - /* Isolate the value and translate it into a character string. */ - v = savestring (value); - FREE (_rl_isearch_terminators); - if (v[0] == '"' || v[0] == '\'') - { - delim = v[0]; - for (beg = end = 1; v[end] && v[end] != delim; end++) - ; - } - else - { - for (beg = end = 0; whitespace (v[end]) == 0; end++) - ; - } - - v[end] = '\0'; - - /* The value starts at v + beg. Translate it into a character string. */ - _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1); - rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end); - _rl_isearch_terminators[end] = '\0'; - - xfree (v); - return 0; -} - -extern char *_rl_emacs_mode_str; - -static int -sv_emacs_modestr (value) - const char *value; -{ - if (value && *value) - { - FREE (_rl_emacs_mode_str); - _rl_emacs_mode_str = (char *)xmalloc (2 * strlen (value) + 1); - rl_translate_keyseq (value, _rl_emacs_mode_str, &_rl_emacs_modestr_len); - _rl_emacs_mode_str[_rl_emacs_modestr_len] = '\0'; - return 0; - } - else if (value) - { - FREE (_rl_emacs_mode_str); - _rl_emacs_mode_str = (char *)xmalloc (1); - _rl_emacs_mode_str[_rl_emacs_modestr_len = 0] = '\0'; - return 0; - } - else if (value == 0) - { - FREE (_rl_emacs_mode_str); - _rl_emacs_mode_str = 0; /* prompt_modestr does the right thing */ - _rl_emacs_modestr_len = 0; - return 0; - } - return 1; -} - -static int -sv_viins_modestr (value) - const char *value; -{ - if (value && *value) - { - FREE (_rl_vi_ins_mode_str); - _rl_vi_ins_mode_str = (char *)xmalloc (2 * strlen (value) + 1); - rl_translate_keyseq (value, _rl_vi_ins_mode_str, &_rl_vi_ins_modestr_len); - _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len] = '\0'; - return 0; - } - else if (value) - { - FREE (_rl_vi_ins_mode_str); - _rl_vi_ins_mode_str = (char *)xmalloc (1); - _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len = 0] = '\0'; - return 0; - } - else if (value == 0) - { - FREE (_rl_vi_ins_mode_str); - _rl_vi_ins_mode_str = 0; /* prompt_modestr does the right thing */ - _rl_vi_ins_modestr_len = 0; - return 0; - } - return 1; -} - -static int -sv_vicmd_modestr (value) - const char *value; -{ - if (value && *value) - { - FREE (_rl_vi_cmd_mode_str); - _rl_vi_cmd_mode_str = (char *)xmalloc (2 * strlen (value) + 1); - rl_translate_keyseq (value, _rl_vi_cmd_mode_str, &_rl_vi_cmd_modestr_len); - _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len] = '\0'; - return 0; - } - else if (value) - { - FREE (_rl_vi_cmd_mode_str); - _rl_vi_cmd_mode_str = (char *)xmalloc (1); - _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len = 0] = '\0'; - return 0; - } - else if (value == 0) - { - FREE (_rl_vi_cmd_mode_str); - _rl_vi_cmd_mode_str = 0; /* prompt_modestr does the right thing */ - _rl_vi_cmd_modestr_len = 0; - return 0; - } - return 1; -} - -/* Return the character which matches NAME. - For example, `Space' returns ' '. */ - -typedef struct { - const char * const name; - int value; -} assoc_list; - -static const assoc_list name_key_alist[] = { - { "DEL", 0x7f }, - { "ESC", '\033' }, - { "Escape", '\033' }, - { "LFD", '\n' }, - { "Newline", '\n' }, - { "RET", '\r' }, - { "Return", '\r' }, - { "Rubout", 0x7f }, - { "SPC", ' ' }, - { "Space", ' ' }, - { "Tab", 0x09 }, - { (char *)0x0, 0 } -}; - -static int -glean_key_from_name (name) - char *name; -{ - register int i; - - for (i = 0; name_key_alist[i].name; i++) - if (_rl_stricmp (name, name_key_alist[i].name) == 0) - return (name_key_alist[i].value); - - return (*(unsigned char *)name); /* XXX was return (*name) */ -} - -/* Auxiliary functions to manage keymaps. */ -static const struct { - const char * const name; - Keymap map; -} keymap_names[] = { - { "emacs", emacs_standard_keymap }, - { "emacs-standard", emacs_standard_keymap }, - { "emacs-meta", emacs_meta_keymap }, - { "emacs-ctlx", emacs_ctlx_keymap }, -#if defined (VI_MODE) - { "vi", vi_movement_keymap }, - { "vi-move", vi_movement_keymap }, - { "vi-command", vi_movement_keymap }, - { "vi-insert", vi_insertion_keymap }, -#endif /* VI_MODE */ - { (char *)0x0, (Keymap)0x0 } -}; - -Keymap -rl_get_keymap_by_name (name) - const char *name; -{ - register int i; - - for (i = 0; keymap_names[i].name; i++) - if (_rl_stricmp (name, keymap_names[i].name) == 0) - return (keymap_names[i].map); - return ((Keymap) NULL); -} - -char * -rl_get_keymap_name (map) - Keymap map; -{ - register int i; - for (i = 0; keymap_names[i].name; i++) - if (map == keymap_names[i].map) - return ((char *)keymap_names[i].name); - return ((char *)NULL); -} - -void -rl_set_keymap (map) - Keymap map; -{ - if (map) - _rl_keymap = map; -} - -Keymap -rl_get_keymap () -{ - return (_rl_keymap); -} - -void -rl_set_keymap_from_edit_mode () -{ - if (rl_editing_mode == emacs_mode) - _rl_keymap = emacs_standard_keymap; -#if defined (VI_MODE) - else if (rl_editing_mode == vi_mode) - _rl_keymap = vi_insertion_keymap; -#endif /* VI_MODE */ -} - -char * -rl_get_keymap_name_from_edit_mode () -{ - if (rl_editing_mode == emacs_mode) - return "emacs"; -#if defined (VI_MODE) - else if (rl_editing_mode == vi_mode) - return "vi"; -#endif /* VI_MODE */ - else - return "none"; -} - -/* **************************************************************** */ -/* */ -/* Key Binding and Function Information */ -/* */ -/* **************************************************************** */ - -/* Each of the following functions produces information about the - state of keybindings and functions known to Readline. The info - is always printed to rl_outstream, and in such a way that it can - be read back in (i.e., passed to rl_parse_and_bind ()). */ - -/* Print the names of functions known to Readline. */ -void -rl_list_funmap_names () -{ - register int i; - const char **funmap_names; - - funmap_names = rl_funmap_names (); - - if (!funmap_names) - return; - - for (i = 0; funmap_names[i]; i++) - fprintf (rl_outstream, "%s\n", funmap_names[i]); - - xfree (funmap_names); -} - -static char * -_rl_get_keyname (key) - int key; -{ - char *keyname; - int i, c; - - keyname = (char *)xmalloc (8); - - c = key; - /* Since this is going to be used to write out keysequence-function - pairs for possible inclusion in an inputrc file, we don't want to - do any special meta processing on KEY. */ - -#if 1 - /* XXX - Experimental */ - /* We might want to do this, but the old version of the code did not. */ - - /* If this is an escape character, we don't want to do any more processing. - Just add the special ESC key sequence and return. */ - if (c == ESC) - { - keyname[0] = '\\'; - keyname[1] = 'e'; - keyname[2] = '\0'; - return keyname; - } -#endif - - /* RUBOUT is translated directly into \C-? */ - if (key == RUBOUT) - { - keyname[0] = '\\'; - keyname[1] = 'C'; - keyname[2] = '-'; - keyname[3] = '?'; - keyname[4] = '\0'; - return keyname; - } - - i = 0; - /* Now add special prefixes needed for control characters. This can - potentially change C. */ - if (CTRL_CHAR (c)) - { - keyname[i++] = '\\'; - keyname[i++] = 'C'; - keyname[i++] = '-'; - c = _rl_to_lower (UNCTRL (c)); - } - - /* XXX experimental code. Turn the characters that are not ASCII or - ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237). - This changes C. */ - if (c >= 128 && c <= 159) - { - keyname[i++] = '\\'; - keyname[i++] = '2'; - c -= 128; - keyname[i++] = (c / 8) + '0'; - c = (c % 8) + '0'; - } - - /* Now, if the character needs to be quoted with a backslash, do that. */ - if (c == '\\' || c == '"') - keyname[i++] = '\\'; - - /* Now add the key, terminate the string, and return it. */ - keyname[i++] = (char) c; - keyname[i] = '\0'; - - return keyname; -} - -/* Return a NULL terminated array of strings which represent the key - sequences that are used to invoke FUNCTION in MAP. */ -char ** -rl_invoking_keyseqs_in_map (function, map) - rl_command_func_t *function; - Keymap map; -{ - register int key; - char **result; - int result_index, result_size; - - result = (char **)NULL; - result_index = result_size = 0; - - for (key = 0; key < KEYMAP_SIZE; key++) - { - switch (map[key].type) - { - case ISMACR: - /* Macros match, if, and only if, the pointers are identical. - Thus, they are treated exactly like functions in here. */ - case ISFUNC: - /* If the function in the keymap is the one we are looking for, - then add the current KEY to the list of invoking keys. */ - if (map[key].function == function) - { - char *keyname; - - keyname = _rl_get_keyname (key); - - if (result_index + 2 > result_size) - { - result_size += 10; - result = (char **)xrealloc (result, result_size * sizeof (char *)); - } - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; - } - break; - - case ISKMAP: - { - char **seqs; - register int i; - - /* Find the list of keyseqs in this map which have FUNCTION as - their target. Add the key sequences found to RESULT. */ - if (map[key].function) - seqs = - rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); - else - break; - - if (seqs == 0) - break; - - for (i = 0; seqs[i]; i++) - { - char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); - - if (key == ESC) - { - /* If ESC is the meta prefix and we're converting chars - with the eighth bit set to ESC-prefixed sequences, then - we can use \M-. Otherwise we need to use the sequence - for ESC. */ - if (_rl_convert_meta_chars_to_ascii && map[ESC].type == ISKMAP) - sprintf (keyname, "\\M-"); - else - sprintf (keyname, "\\e"); - } - else if (CTRL_CHAR (key)) - sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } - else - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } - - strcat (keyname, seqs[i]); - xfree (seqs[i]); - - if (result_index + 2 > result_size) - { - result_size += 10; - result = (char **)xrealloc (result, result_size * sizeof (char *)); - } - - result[result_index++] = keyname; - result[result_index] = (char *)NULL; - } - - xfree (seqs); - } - break; - } - } - return (result); -} - -/* Return a NULL terminated array of strings which represent the key - sequences that can be used to invoke FUNCTION using the current keymap. */ -char ** -rl_invoking_keyseqs (function) - rl_command_func_t *function; -{ - return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); -} - -/* Print all of the functions and their bindings to rl_outstream. If - PRINT_READABLY is non-zero, then print the output in such a way - that it can be read back in. */ -void -rl_function_dumper (print_readably) - int print_readably; -{ - register int i; - const char **names; - const char *name; - - names = rl_funmap_names (); - - fprintf (rl_outstream, "\n"); - - for (i = 0; name = names[i]; i++) - { - rl_command_func_t *function; - char **invokers; - - function = rl_named_function (name); - invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap); - - if (print_readably) - { - if (!invokers) - fprintf (rl_outstream, "# %s (not bound)\n", name); - else - { - register int j; - - for (j = 0; invokers[j]; j++) - { - fprintf (rl_outstream, "\"%s\": %s\n", - invokers[j], name); - xfree (invokers[j]); - } - - xfree (invokers); - } - } - else - { - if (!invokers) - fprintf (rl_outstream, "%s is not bound to any keys\n", - name); - else - { - register int j; - - fprintf (rl_outstream, "%s can be found on ", name); - - for (j = 0; invokers[j] && j < 5; j++) - { - fprintf (rl_outstream, "\"%s\"%s", invokers[j], - invokers[j + 1] ? ", " : ".\n"); - } - - if (j == 5 && invokers[j]) - fprintf (rl_outstream, "...\n"); - - for (j = 0; invokers[j]; j++) - xfree (invokers[j]); - - xfree (invokers); - } - } - } - - xfree (names); -} - -/* Print all of the current functions and their bindings to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_functions (count, key) - int count, key; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_function_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -static void -_rl_macro_dumper_internal (print_readably, map, prefix) - int print_readably; - Keymap map; - char *prefix; -{ - register int key; - char *keyname, *out; - int prefix_len; - - for (key = 0; key < KEYMAP_SIZE; key++) - { - switch (map[key].type) - { - case ISMACR: - keyname = _rl_get_keyname (key); - out = _rl_untranslate_macro_value ((char *)map[key].function, 0); - - if (print_readably) - fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", - keyname, - out ? out : ""); - else - fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "", - keyname, - out ? out : ""); - xfree (keyname); - xfree (out); - break; - case ISFUNC: - break; - case ISKMAP: - prefix_len = prefix ? strlen (prefix) : 0; - if (key == ESC) - { - keyname = (char *)xmalloc (3 + prefix_len); - if (prefix) - strcpy (keyname, prefix); - keyname[prefix_len] = '\\'; - keyname[prefix_len + 1] = 'e'; - keyname[prefix_len + 2] = '\0'; - } - else - { - keyname = _rl_get_keyname (key); - if (prefix) - { - out = (char *)xmalloc (strlen (keyname) + prefix_len + 1); - strcpy (out, prefix); - strcpy (out + prefix_len, keyname); - xfree (keyname); - keyname = out; - } - } - - _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); - xfree (keyname); - break; - } - } -} - -void -rl_macro_dumper (print_readably) - int print_readably; -{ - _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL); -} - -int -rl_dump_macros (count, key) - int count, key; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_macro_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -static char * -_rl_get_string_variable_value (name) - const char *name; -{ - static char numbuf[32]; - char *ret; - - if (_rl_stricmp (name, "bell-style") == 0) - { - switch (_rl_bell_preference) - { - case NO_BELL: - return "none"; - case VISIBLE_BELL: - return "visible"; - case AUDIBLE_BELL: - default: - return "audible"; - } - } - else if (_rl_stricmp (name, "comment-begin") == 0) - return (_rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); - else if (_rl_stricmp (name, "completion-display-width") == 0) - { - sprintf (numbuf, "%d", _rl_completion_columns); - return (numbuf); - } - else if (_rl_stricmp (name, "completion-prefix-display-length") == 0) - { - sprintf (numbuf, "%d", _rl_completion_prefix_display_length); - return (numbuf); - } - else if (_rl_stricmp (name, "completion-query-items") == 0) - { - sprintf (numbuf, "%d", rl_completion_query_items); - return (numbuf); - } - else if (_rl_stricmp (name, "editing-mode") == 0) - return (rl_get_keymap_name_from_edit_mode ()); - else if (_rl_stricmp (name, "history-size") == 0) - { - sprintf (numbuf, "%d", history_is_stifled() ? history_max_entries : 0); - return (numbuf); - } - else if (_rl_stricmp (name, "isearch-terminators") == 0) - { - if (_rl_isearch_terminators == 0) - return 0; - ret = _rl_untranslate_macro_value (_rl_isearch_terminators, 0); - if (ret) - { - strncpy (numbuf, ret, sizeof (numbuf) - 1); - xfree (ret); - numbuf[sizeof(numbuf) - 1] = '\0'; - } - else - numbuf[0] = '\0'; - return numbuf; - } - else if (_rl_stricmp (name, "keymap") == 0) - { - ret = rl_get_keymap_name (_rl_keymap); - if (ret == 0) - ret = rl_get_keymap_name_from_edit_mode (); - return (ret ? ret : "none"); - } - else if (_rl_stricmp (name, "keyseq-timeout") == 0) - { - sprintf (numbuf, "%d", _rl_keyseq_timeout); - return (numbuf); - } - else if (_rl_stricmp (name, "emacs-mode-string") == 0) - return (_rl_emacs_mode_str ? _rl_emacs_mode_str : RL_EMACS_MODESTR_DEFAULT); - else if (_rl_stricmp (name, "vi-cmd-mode-string") == 0) - return (_rl_emacs_mode_str ? _rl_emacs_mode_str : RL_VI_CMD_MODESTR_DEFAULT); - else if (_rl_stricmp (name, "vi-ins-mode-string") == 0) - return (_rl_emacs_mode_str ? _rl_emacs_mode_str : RL_VI_INS_MODESTR_DEFAULT); - else - return (0); -} - -void -rl_variable_dumper (print_readably) - int print_readably; -{ - int i; - char *v; - - for (i = 0; boolean_varlist[i].name; i++) - { - if (print_readably) - fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name, - *boolean_varlist[i].value ? "on" : "off"); - else - fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name, - *boolean_varlist[i].value ? "on" : "off"); - } - - for (i = 0; string_varlist[i].name; i++) - { - v = _rl_get_string_variable_value (string_varlist[i].name); - if (v == 0) /* _rl_isearch_terminators can be NULL */ - continue; - if (print_readably) - fprintf (rl_outstream, "set %s %s\n", string_varlist[i].name, v); - else - fprintf (rl_outstream, "%s is set to `%s'\n", string_varlist[i].name, v); - } -} - -/* Print all of the current variables and their values to - rl_outstream. If an explicit argument is given, then print - the output in such a way that it can be read back in. */ -int -rl_dump_variables (count, key) - int count, key; -{ - if (rl_dispatching) - fprintf (rl_outstream, "\r\n"); - rl_variable_dumper (rl_explicit_arg); - rl_on_new_line (); - return (0); -} - -/* Return non-zero if any members of ARRAY are a substring in STRING. */ -static int -substring_member_of_array (string, array) - const char *string; - const char * const *array; -{ - while (*array) - { - if (_rl_strindex (string, *array)) - return (1); - array++; - } - return (0); -} diff --git a/lib/readline/chardefs.h~ b/lib/readline/chardefs.h~ deleted file mode 100644 index 1fa1b089d..000000000 --- a/lib/readline/chardefs.h~ +++ /dev/null @@ -1,164 +0,0 @@ -/* chardefs.h -- Character definitions for readline. */ - -/* Copyright (C) 1994-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#ifndef _CHARDEFS_H_ -#define _CHARDEFS_H_ - -#include - -#if defined (HAVE_CONFIG_H) -# if defined (HAVE_STRING_H) -# if ! defined (STDC_HEADERS) && defined (HAVE_MEMORY_H) -# include -# endif -# include -# endif /* HAVE_STRING_H */ -# if defined (HAVE_STRINGS_H) -# include -# endif /* HAVE_STRINGS_H */ -#else -# include -#endif /* !HAVE_CONFIG_H */ - -#ifndef whitespace -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif - -#ifdef CTRL -# undef CTRL -#endif -#ifdef UNCTRL -# undef UNCTRL -#endif - -/* Some character stuff. */ -#define control_character_threshold 0x020 /* Smaller than this is control. */ -#define control_character_mask 0x1f /* 0x20 - 1 */ -#define meta_character_threshold 0x07f /* Larger than this is Meta. */ -#define control_character_bit 0x40 /* 0x000000, must be off. */ -#define meta_character_bit 0x080 /* x0000000, must be on. */ -#define largest_char 255 /* Largest character value. */ - -#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0)) -#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char) - -#define CTRL(c) ((c) & control_character_mask) -#define META(c) ((c) | meta_character_bit) - -#define UNMETA(c) ((c) & (~meta_character_bit)) -#define UNCTRL(c) _rl_to_upper(((c)|control_character_bit)) - -#if defined STDC_HEADERS || (!defined (isascii) && !defined (HAVE_ISASCII)) -# define IN_CTYPE_DOMAIN(c) 1 -#else -# define IN_CTYPE_DOMAIN(c) isascii(c) -#endif - -#if !defined (isxdigit) && !defined (HAVE_ISXDIGIT) && !defined (__cplusplus) -# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) -#endif - -#if defined (CTYPE_NON_ASCII) -# define NON_NEGATIVE(c) 1 -#else -# define NON_NEGATIVE(c) ((unsigned char)(c) == (c)) -#endif - -/* Some systems define these; we want our definitions. */ -#undef ISPRINT - -/* Beware: these only work with single-byte ASCII characters. */ - -#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) -#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) -#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) -#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) -#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) -#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) -#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) - -#define _rl_lowercase_p(c) (NON_NEGATIVE(c) && ISLOWER(c)) -#define _rl_uppercase_p(c) (NON_NEGATIVE(c) && ISUPPER(c)) -#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') - -#define _rl_pure_alphabetic(c) (NON_NEGATIVE(c) && ISALPHA(c)) -#define ALPHABETIC(c) (NON_NEGATIVE(c) && ISALNUM(c)) - -#ifndef _rl_to_upper -# define _rl_to_upper(c) (_rl_lowercase_p(c) ? toupper((unsigned char)c) : (c)) -# define _rl_to_lower(c) (_rl_uppercase_p(c) ? tolower((unsigned char)c) : (c)) -#endif - -#ifndef _rl_digit_value -# define _rl_digit_value(x) ((x) - '0') -#endif - -#ifndef _rl_isident -# define _rl_isident(c) (ISALNUM(c) || (c) == '_') -#endif - -#ifndef ISOCTAL -# define ISOCTAL(c) ((c) >= '0' && (c) <= '7') -#endif -#define OCTVALUE(c) ((c) - '0') - -#define HEXVALUE(c) \ - (((c) >= 'a' && (c) <= 'f') \ - ? (c)-'a'+10 \ - : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') - -#ifndef NEWLINE -#define NEWLINE '\n' -#endif - -#ifndef RETURN -#define RETURN CTRL('M') -#endif - -#ifndef RUBOUT -#define RUBOUT 0x7f -#endif - -#ifndef TAB -#define TAB '\t' -#endif - -#ifdef ABORT_CHAR -#undef ABORT_CHAR -#endif -#define ABORT_CHAR CTRL('G') - -#ifdef PAGE -#undef PAGE -#endif -#define PAGE CTRL('L') - -#ifdef SPACE -#undef SPACE -#endif -#define SPACE ' ' /* XXX - was 0x20 */ - -#ifdef ESC -#undef ESC -#endif -#define ESC CTRL('[') - -#endif /* _CHARDEFS_H_ */ diff --git a/lib/readline/doc/Makefile.old b/lib/readline/doc/Makefile.old deleted file mode 100644 index 58d4dd762..000000000 --- a/lib/readline/doc/Makefile.old +++ /dev/null @@ -1,76 +0,0 @@ -# This makefile for Readline library documentation is in -*- text -*- mode. -# Emacs likes it that way. -RM = rm -f - -MAKEINFO = makeinfo -TEXI2DVI = texi2dvi -TEXI2HTML = texi2html -QUIETPS = #set this to -q to shut up dvips -DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky - -INSTALL_DATA = cp -infodir = /usr/local/info - -RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo -HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo - -DVIOBJ = readline.dvi history.dvi -INFOOBJ = readline.info history.info -PSOBJ = readline.ps history.ps -HTMLOBJ = readline.html history.html - -all: info dvi html ps -nodvi: info html - -readline.dvi: $(RLSRC) - $(TEXI2DVI) rlman.texinfo - mv rlman.dvi readline.dvi - -readline.info: $(RLSRC) - $(MAKEINFO) --no-split -o $@ rlman.texinfo - -history.dvi: ${HISTSRC} - $(TEXI2DVI) hist.texinfo - mv hist.dvi history.dvi - -history.info: ${HISTSRC} - $(MAKEINFO) --no-split -o $@ hist.texinfo - -readline.ps: readline.dvi - $(RM) $@ - $(DVIPS) readline.dvi - -history.ps: history.dvi - $(RM) $@ - $(DVIPS) history.dvi - -readline.html: ${RLSRC} - $(TEXI2HTML) rlman.texinfo - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html - $(RM) rlman.html rlman_toc.html - -history.html: ${HISTSRC} - $(TEXI2HTML) hist.texinfo - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html - $(RM) hist.html hist_toc.html - -info: $(INFOOBJ) -dvi: $(DVIOBJ) -ps: $(PSOBJ) -html: $(HTMLOBJ) - -clean: - $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core - -distclean: clean -mostlyclean: clean - -maintainer-clean: clean - $(RM) *.dvi *.info *.info-* *.ps *.html - -install: info - ${INSTALL_DATA} readline.info $(infodir)/readline.info - ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/doc/rluser.texi~ b/lib/readline/doc/rluser.texi~ deleted file mode 100644 index 3b48b9bfb..000000000 --- a/lib/readline/doc/rluser.texi~ +++ /dev/null @@ -1,2301 +0,0 @@ -@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~ deleted file mode 100644 index 7e04b67da..000000000 --- a/lib/readline/funmap.c~ +++ /dev/null @@ -1,267 +0,0 @@ -/* 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/histfile.c~ b/lib/readline/histfile.c~ deleted file mode 100644 index 8341c2087..000000000 --- a/lib/readline/histfile.c~ +++ /dev/null @@ -1,650 +0,0 @@ -/* histfile.c - functions to manipulate the history file. */ - -/* Copyright (C) 1989-2010 Free Software Foundation, Inc. - - This file contains the GNU History Library (History), a set of - routines for managing the text of previously typed lines. - - History 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. - - History 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 History. If not, see . -*/ - -/* The goal is to make the implementation transparent, so that you - don't have to know what data types are used, just what functions - you can call. I think I have done that. */ - -#define READLINE_LIBRARY - -#if defined (__TANDEM) -# include -#endif - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#include -#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#include - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#if defined (__EMX__) -# undef HAVE_MMAP -#endif - -#ifdef HISTORY_USE_MMAP -# include - -# ifdef MAP_FILE -# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) -# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) -# else -# define MAP_RFLAGS MAP_PRIVATE -# define MAP_WFLAGS MAP_SHARED -# endif - -# ifndef MAP_FAILED -# define MAP_FAILED ((void *)-1) -# endif - -#endif /* HISTORY_USE_MMAP */ - -/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment - on win 95/98/nt), we want to open files with O_BINARY mode so that there - is no \n -> \r\n conversion performed. On other systems, we don't want to - mess around with O_BINARY at all, so we ensure that it's defined to 0. */ -#if defined (__EMX__) || defined (__CYGWIN__) -# ifndef O_BINARY -# define O_BINARY 0 -# endif -#else /* !__EMX__ && !__CYGWIN__ */ -# undef O_BINARY -# define O_BINARY 0 -#endif /* !__EMX__ && !__CYGWIN__ */ - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include "history.h" -#include "histlib.h" - -#include "rlshell.h" -#include "xmalloc.h" - -/* If non-zero, we write timestamps to the history file in history_do_write() */ -int history_write_timestamps = 0; - -/* Immediately after a call to read_history() or read_history_range(), this - will return the number of lines just read from the history file in that - call. */ -int history_lines_read_from_file = 0; - -/* Immediately after a call to write_history() or history_do_write(), this - will return the number of lines just written to the history file in that - call. This also works with history_truncate_file. */ -int history_lines_written_to_file = 0; - -/* Does S look like the beginning of a history timestamp entry? Placeholder - for more extensive tests. */ -#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) ) - -/* Return the string that should be used in the place of this - filename. This only matters when you don't specify the - filename to read_history (), or write_history (). */ -static char * -history_filename (filename) - const char *filename; -{ - char *return_val; - const char *home; - int home_len; - - return_val = filename ? savestring (filename) : (char *)NULL; - - if (return_val) - return (return_val); - - home = sh_get_env_value ("HOME"); -#if defined (_WIN32) - if (home == 0) - home = sh_get_env_value ("APPDATA"); -#endif - - if (home == 0) - return (NULL); - else - home_len = strlen (home); - - return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ - strcpy (return_val, home); - return_val[home_len] = '/'; -#if defined (__MSDOS__) - strcpy (return_val + home_len + 1, "_history"); -#else - strcpy (return_val + home_len + 1, ".history"); -#endif - - return (return_val); -} - -static char * -history_backupfile (filename) - const char *filename; -{ - char *ret; - size_t len; - - len = strlen (filename); - ret = xmalloc (len + 2); - strcpy (ret, filename); - ret[len] = '-'; - ret[len+1] = '\0'; - return ret; -} - -/* Add the contents of FILENAME to the history list, a line at a time. - If FILENAME is NULL, then read from ~/.history. Returns 0 if - successful, or errno if not. */ -int -read_history (filename) - const char *filename; -{ - return (read_history_range (filename, 0, -1)); -} - -/* Read a range of lines from FILENAME, adding them to the history list. - Start reading at the FROM'th line and end at the TO'th. If FROM - is zero, start at the beginning. If TO is less than FROM, read - until the end of the file. If FILENAME is NULL, then read from - ~/.history. Returns 0 if successful, or errno if not. */ -int -read_history_range (filename, from, to) - const char *filename; - int from, to; -{ - register char *line_start, *line_end, *p; - char *input, *buffer, *bufend, *last_ts; - int file, current_line, chars_read; - struct stat finfo; - size_t file_size; -#if defined (EFBIG) - int overflow_errno = EFBIG; -#elif defined (EOVERFLOW) - int overflow_errno = EOVERFLOW; -#else - int overflow_errno = EIO; -#endif - - history_lines_read_from_file = 0; - - buffer = last_ts = (char *)NULL; - input = history_filename (filename); - file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1; - - if ((file < 0) || (fstat (file, &finfo) == -1)) - goto error_and_exit; - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - errno = overflow_errno; - goto error_and_exit; - } - -#ifdef HISTORY_USE_MMAP - /* We map read/write and private so we can change newlines to NULs without - affecting the underlying object. */ - buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); - if ((void *)buffer == MAP_FAILED) - { - errno = overflow_errno; - goto error_and_exit; - } - chars_read = file_size; -#else - buffer = (char *)malloc (file_size + 1); - if (buffer == 0) - { - errno = overflow_errno; - goto error_and_exit; - } - - chars_read = read (file, buffer, file_size); -#endif - if (chars_read < 0) - { - error_and_exit: - if (errno != 0) - chars_read = errno; - else - chars_read = EIO; - if (file >= 0) - close (file); - - FREE (input); -#ifndef HISTORY_USE_MMAP - FREE (buffer); -#endif - - return (chars_read); - } - - close (file); - - /* Set TO to larger than end of file if negative. */ - if (to < 0) - to = chars_read; - - /* Start at beginning of file, work to end. */ - bufend = buffer + chars_read; - current_line = 0; - - /* Skip lines until we are at FROM. */ - for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) - if (*line_end == '\n') - { - p = line_end + 1; - /* If we see something we think is a timestamp, continue with this - line. We should check more extensively here... */ - if (HIST_TIMESTAMP_START(p) == 0) - current_line++; - line_start = p; - } - - /* If there are lines left to gobble, then gobble them now. */ - for (line_end = line_start; line_end < bufend; line_end++) - if (*line_end == '\n') - { - /* Change to allow Windows-like \r\n end of line delimiter. */ - if (line_end > line_start && line_end[-1] == '\r') - line_end[-1] = '\0'; - else - *line_end = '\0'; - - if (*line_start) - { - if (HIST_TIMESTAMP_START(line_start) == 0) - { - add_history (line_start); - if (last_ts) - { - add_history_time (last_ts); - last_ts = NULL; - } - } - else - { - last_ts = line_start; - current_line--; - } - } - - current_line++; - - if (current_line >= to) - break; - - line_start = line_end + 1; - } - - history_lines_read_from_file = current_line; - - FREE (input); -#ifndef HISTORY_USE_MMAP - FREE (buffer); -#else - munmap (buffer, file_size); -#endif - - return (0); -} - -/* Truncate the history file FNAME, leaving only LINES trailing lines. - If FNAME is NULL, then use ~/.history. Returns 0 on success, errno - on failure. */ -int -history_truncate_file (fname, lines) - const char *fname; - int lines; -{ - char *buffer, *filename, *bakname, *bp, *bp1; /* bp1 == bp+1 */ - int file, chars_read, rv, orig_lines, exists; - struct stat finfo; - size_t file_size; - - history_lines_written_to_file = 0; - - buffer = (char *)NULL; - filename = history_filename (fname); - bakname = 0; - file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1; - rv = exists = 0; - - /* Don't try to truncate non-regular files. */ - if (file == -1 || fstat (file, &finfo) == -1) - { - rv = errno; - if (file != -1) - close (file); - goto truncate_exit; - } - exists = 1; - - if (S_ISREG (finfo.st_mode) == 0) - { - close (file); -#ifdef EFTYPE - rv = EFTYPE; -#else - rv = EINVAL; -#endif - goto truncate_exit; - } - - file_size = (size_t)finfo.st_size; - - /* check for overflow on very large files */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - close (file); -#if defined (EFBIG) - rv = errno = EFBIG; -#elif defined (EOVERFLOW) - rv = errno = EOVERFLOW; -#else - rv = errno = EINVAL; -#endif - goto truncate_exit; - } - - buffer = (char *)malloc (file_size + 1); - if (buffer == 0) - { - rv = errno; - close (file); - goto truncate_exit; - } - - chars_read = read (file, buffer, file_size); - close (file); - - if (chars_read <= 0) - { - rv = (chars_read < 0) ? errno : 0; - goto truncate_exit; - } - - orig_lines = lines; - /* Count backwards from the end of buffer until we have passed - LINES lines. bp1 is set funny initially. But since bp[1] can't - be a comment character (since it's off the end) and *bp can't be - both a newline and the history comment character, it should be OK. */ - for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) - { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) - lines--; - bp1 = bp; - } - - /* If this is the first line, then the file contains exactly the - number of lines we want to truncate to, so we don't need to do - anything. It's the first line if we don't find a newline between - the current value of i and 0. Otherwise, write from the start of - this line until the end of the buffer. */ - for ( ; bp > buffer; bp--) - { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) - { - bp++; - break; - } - bp1 = bp; - } - - /* Write only if there are more lines in the file than we want to - truncate to. */ - if (bp <= buffer) - { - rv = 0; - /* No-op if LINES == 0 at this point */ - history_lines_written_to_file = orig_lines - lines; - goto truncate_exit; - } - - bakname = history_backupfile (filename); - if (filename && bakname) - rename (filename, bakname); - - if ((file = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1) - { - if (write (file, bp, chars_read - (bp - buffer)) < 0) - rv = errno; - -#if defined (__BEOS__) - /* BeOS ignores O_TRUNC. */ - ftruncate (file, chars_read - (bp - buffer)); -#endif - - if (close (file) < 0 && rv == 0) - rv = errno; - } - else - rv = errno; - - truncate_exit: - FREE (buffer); - - history_lines_written_to_file = orig_lines - lines; - - if (rv != 0 && filename && bakname) - rename (bakname, filename); - else if (rv == 0 && bakname) - unlink (bakname); - - /* Make sure the new filename is owned by the same user as the old. If one - user is running this, it's a no-op. If the shell is running after sudo - with a shared history file, we don't want to leave the history file - owned by root. */ - if (rv == 0 && exists) - chown (filename, finfo.st_uid, finfo.st_gid); - - xfree (filename); - FREE (bakname); - - return rv; -} - -/* Workhorse function for writing history. Writes the last NELEMENT entries - from the history list to FILENAME. OVERWRITE is non-zero if you - wish to replace FILENAME with the entries. */ -static int -history_do_write (filename, nelements, overwrite) - const char *filename; - int nelements, overwrite; -{ - register int i; - char *output, *bakname; - int file, mode, rv, exists; - struct stat finfo; -#ifdef HISTORY_USE_MMAP - size_t cursize; - - history_lines_written_to_file = 0; - - mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; -#else - mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; -#endif - output = history_filename (filename); - bakname = (overwrite && output) ? history_backupfile (output) : 0; - exists = output ? (stat (output, &finfo) == 0) : 0; - - if (output && bakname) - rename (output, bakname); - - file = output ? open (output, mode, 0600) : -1; - rv = 0; - - if (file == -1) - { - rv = errno; - if (output && bakname) - rename (bakname, output); - FREE (output); - FREE (bakname); - return (rv); - } - -#ifdef HISTORY_USE_MMAP - cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); -#endif - - if (nelements > history_length) - nelements = history_length; - - /* Build a buffer of all the lines to write, and write them in one syscall. - Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ - { - HIST_ENTRY **the_history; /* local */ - register int j; - int buffer_size; - char *buffer; - - the_history = history_list (); - /* Calculate the total number of bytes to write. */ - for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) -#if 0 - buffer_size += 2 + HISTENT_BYTES (the_history[i]); -#else - { - if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) - buffer_size += strlen (the_history[i]->timestamp) + 1; - buffer_size += strlen (the_history[i]->line) + 1; - } -#endif - - /* Allocate the buffer, and fill it. */ -#ifdef HISTORY_USE_MMAP - if (ftruncate (file, buffer_size+cursize) == -1) - goto mmap_error; - buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); - if ((void *)buffer == MAP_FAILED) - { -mmap_error: - rv = errno; - close (file); - if (output && bakname) - rename (bakname, output); - FREE (output); - FREE (bakname); - return rv; - } -#else - buffer = (char *)malloc (buffer_size); - if (buffer == 0) - { - rv = errno; - close (file); - if (output && bakname) - rename (bakname, output); - FREE (output); - FREE (bakname); - return rv; - } -#endif - - for (j = 0, i = history_length - nelements; i < history_length; i++) - { - if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) - { - strcpy (buffer + j, the_history[i]->timestamp); - j += strlen (the_history[i]->timestamp); - buffer[j++] = '\n'; - } - strcpy (buffer + j, the_history[i]->line); - j += strlen (the_history[i]->line); - buffer[j++] = '\n'; - } - -#ifdef HISTORY_USE_MMAP - if (msync (buffer, buffer_size, MS_ASYNC) != 0 || munmap (buffer, buffer_size) != 0) - rv = errno; -#else - if (write (file, buffer, buffer_size) < 0) - rv = errno; - xfree (buffer); -#endif - } - - history_lines_written_to_file = nelements; - - if (close (file) < 0 && rv == 0) - rv = errno; - - if (rv != 0 && output && bakname) - rename (bakname, output); - else if (rv == 0 && bakname) - unlink (bakname); - - /* Make sure the new filename is owned by the same user as the old. If one - user is running this, it's a no-op. If the shell is running after sudo - with a shared history file, we don't want to leave the history file - owned by root. */ - if (rv == 0 && exists) - chown (output, finfo.st_uid, finfo.st_gid); - - FREE (output); - FREE (bakname); - - return (rv); -} - -/* Append NELEMENT entries to FILENAME. The entries appended are from - the end of the list minus NELEMENTs up to the end of the list. */ -int -append_history (nelements, filename) - int nelements; - const char *filename; -{ - return (history_do_write (filename, nelements, HISTORY_APPEND)); -} - -/* Overwrite FILENAME with the current history. If FILENAME is NULL, - then write the history list to ~/.history. Values returned - are as in read_history ().*/ -int -write_history (filename) - const char *filename; -{ - return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); -} diff --git a/lib/readline/kill.c~ b/lib/readline/kill.c~ deleted file mode 100644 index d4012da30..000000000 --- a/lib/readline/kill.c~ +++ /dev/null @@ -1,744 +0,0 @@ -/* 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.c~ b/lib/readline/readline.c~ deleted file mode 100644 index 6d2e36b97..000000000 --- a/lib/readline/readline.c~ +++ /dev/null @@ -1,1426 +0,0 @@ -/* readline.c -- a general facility for reading lines of input - with emacs style editing and completion. */ - -/* 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 . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include "posixstat.h" -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include -#include "posixjmp.h" -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (__EMX__) -# define INCL_DOSPROCESS -# include -#endif /* __EMX__ */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -#ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "5.1" -#endif - -#ifndef RL_READLINE_VERSION -# define RL_READLINE_VERSION 0x0501 -#endif - -extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); - -#if defined (COLOR_SUPPORT) -extern void _rl_parse_colors PARAMS((void)); /* XXX */ -#endif - - -/* Forward declarations used in this file. */ -static char *readline_internal PARAMS((void)); -static void readline_initialize_everything PARAMS((void)); - -static void bind_arrow_keys_internal PARAMS((Keymap)); -static void bind_arrow_keys PARAMS((void)); - -static void bind_bracketed_paste_prefix PARAMS((void)); - -static void readline_default_bindings PARAMS((void)); -static void reset_default_bindings PARAMS((void)); - -static int _rl_subseq_result PARAMS((int, Keymap, int, int)); -static int _rl_subseq_getchar PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Line editing input utility */ -/* */ -/* **************************************************************** */ - -const char *rl_library_version = RL_LIBRARY_VERSION; - -int rl_readline_version = RL_READLINE_VERSION; - -/* True if this is `real' readline as opposed to some stub substitute. */ -int rl_gnu_readline_p = 1; - -/* A pointer to the keymap that is currently in use. - By default, it is the standard emacs keymap. */ -Keymap _rl_keymap = emacs_standard_keymap; - -/* The current style of editing. */ -int rl_editing_mode = emacs_mode; - -/* The current insert mode: input (the default) or overwrite */ -int rl_insert_mode = RL_IM_DEFAULT; - -/* Non-zero if we called this function from _rl_dispatch(). It's present - so functions can find out whether they were called from a key binding - or directly from an application. */ -int rl_dispatching; - -/* Non-zero if the previous command was a kill command. */ -int _rl_last_command_was_kill = 0; - -/* The current value of the numeric argument specified by the user. */ -int rl_numeric_arg = 1; - -/* Non-zero if an argument was typed. */ -int rl_explicit_arg = 0; - -/* Temporary value used while generating the argument. */ -int rl_arg_sign = 1; - -/* Non-zero means we have been called at least once before. */ -static int rl_initialized; - -#if 0 -/* If non-zero, this program is running in an EMACS buffer. */ -static int running_in_emacs; -#endif - -/* Flags word encapsulating the current readline state. */ -int rl_readline_state = RL_STATE_NONE; - -/* The current offset in the current input line. */ -int rl_point; - -/* Mark in the current input line. */ -int rl_mark; - -/* Length of the current input line. */ -int rl_end; - -/* Make this non-zero to return the current input_line. */ -int rl_done; - -/* The last function executed by readline. */ -rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; - -/* Top level environment for readline_internal (). */ -procenv_t _rl_top_level; - -/* The streams we interact with. */ -FILE *_rl_in_stream, *_rl_out_stream; - -/* The names of the streams that we do input and output to. */ -FILE *rl_instream = (FILE *)NULL; -FILE *rl_outstream = (FILE *)NULL; - -/* Non-zero means echo characters as they are read. Defaults to no echo; - set to 1 if there is a controlling terminal, we can get its attributes, - and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings - for the code that sets it. */ -int _rl_echoing_p = 0; - -/* Current prompt. */ -char *rl_prompt = (char *)NULL; -int rl_visible_prompt_length = 0; - -/* Set to non-zero by calling application if it has already printed rl_prompt - and does not want readline to do it the first time. */ -int rl_already_prompted = 0; - -/* The number of characters read in order to type this complete command. */ -int rl_key_sequence_length = 0; - -/* If non-zero, then this is the address of a function to call just - before readline_internal_setup () prints the first prompt. */ -rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; - -/* If non-zero, this is the address of a function to call just before - readline_internal_setup () returns and readline_internal starts - reading input characters. */ -rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; - -/* What we use internally. You should always refer to RL_LINE_BUFFER. */ -static char *the_line; - -/* The character that can generate an EOF. Really read from - the terminal driver... just defaulted here. */ -int _rl_eof_char = CTRL ('D'); - -/* Non-zero makes this the next keystroke to read. */ -int rl_pending_input = 0; - -/* Pointer to a useful terminal name. */ -const char *rl_terminal_name = (const char *)NULL; - -/* Non-zero means to always use horizontal scrolling in line display. */ -int _rl_horizontal_scroll_mode = 0; - -/* Non-zero means to display an asterisk at the starts of history lines - which have been modified. */ -int _rl_mark_modified_lines = 0; - -/* The style of `bell' notification preferred. This can be set to NO_BELL, - AUDIBLE_BELL, or VISIBLE_BELL. */ -int _rl_bell_preference = AUDIBLE_BELL; - -/* String inserted into the line by rl_insert_comment (). */ -char *_rl_comment_begin; - -/* Keymap holding the function currently being executed. */ -Keymap rl_executing_keymap; - -/* Keymap we're currently using to dispatch. */ -Keymap _rl_dispatching_keymap; - -/* Non-zero means to erase entire line, including prompt, on empty input lines. */ -int rl_erase_empty_line = 0; - -/* Non-zero means to read only this many characters rather than up to a - character bound to accept-line. */ -int rl_num_chars_to_read; - -/* Line buffer and maintenance. */ -char *rl_line_buffer = (char *)NULL; -int rl_line_buffer_len = 0; - -/* Key sequence `contexts' */ -_rl_keyseq_cxt *_rl_kscxt = 0; - -int rl_executing_key; -char *rl_executing_keyseq = 0; -int _rl_executing_keyseq_size = 0; - -/* Timeout (specified in milliseconds) when reading characters making up an - ambiguous multiple-key sequence */ -int _rl_keyseq_timeout = 500; - -#define RESIZE_KEYSEQ_BUFFER() \ - do \ - { \ - if (rl_key_sequence_length + 2 >= _rl_executing_keyseq_size) \ - { \ - _rl_executing_keyseq_size += 16; \ - rl_executing_keyseq = xrealloc (rl_executing_keyseq, _rl_executing_keyseq_size); \ - } \ - } \ - while (0); - -/* Forward declarations used by the display, termcap, and history code. */ - -/* **************************************************************** */ -/* */ -/* `Forward' declarations */ -/* */ -/* **************************************************************** */ - -/* Non-zero means do not parse any lines other than comments and - parser directives. */ -unsigned char _rl_parsing_conditionalized_out = 0; - -/* Non-zero means to convert characters with the meta bit set to - escape-prefixed characters so we can indirect through - emacs_meta_keymap or vi_escape_keymap. */ -int _rl_convert_meta_chars_to_ascii = 1; - -/* Non-zero means to output characters with the meta bit set directly - rather than as a meta-prefixed escape sequence. */ -int _rl_output_meta_chars = 0; - -/* Non-zero means to look at the termios special characters and bind - them to equivalent readline functions at startup. */ -int _rl_bind_stty_chars = 1; - -/* Non-zero means to go through the history list at every newline (or - whenever rl_done is set and readline returns) and revert each line to - its initial state. */ -int _rl_revert_all_at_newline = 0; - -/* Non-zero means to honor the termios ECHOCTL bit and echo control - characters corresponding to keyboard-generated signals. */ -int _rl_echo_control_chars = 1; - -/* Non-zero means to prefix the displayed prompt with a character indicating - the editing mode: @ for emacs, : for vi-command, + for vi-insert. */ -int _rl_show_mode_in_prompt = 0; - -/* Non-zero means to attempt to put the terminal in `bracketed paste mode', - where it will prefix pasted text with an escape sequence and send - another to mark the end of the paste. */ -int _rl_enable_bracketed_paste = 0; - -/* **************************************************************** */ -/* */ -/* Top Level Functions */ -/* */ -/* **************************************************************** */ - -/* Non-zero means treat 0200 bit in terminal input as Meta bit. */ -int _rl_meta_flag = 0; /* Forward declaration */ - -/* Set up the prompt and expand it. Called from readline() and - rl_callback_handler_install (). */ -int -rl_set_prompt (prompt) - const char *prompt; -{ - FREE (rl_prompt); - rl_prompt = prompt ? savestring (prompt) : (char *)NULL; - rl_display_prompt = rl_prompt ? rl_prompt : ""; - - rl_visible_prompt_length = rl_expand_prompt (rl_prompt); - return 0; -} - -/* Read a line of input. Prompt with PROMPT. An empty PROMPT means - none. A return value of NULL means that EOF was encountered. */ -char * -readline (prompt) - const char *prompt; -{ - char *value; -#if 0 - int in_callback; -#endif - - /* If we are at EOF return a NULL string. */ - if (rl_pending_input == EOF) - { - rl_clear_pending_input (); - return ((char *)NULL); - } - -#if 0 - /* If readline() is called after installing a callback handler, temporarily - turn off the callback state to avoid ensuing messiness. Patch supplied - by the gdb folks. XXX -- disabled. This can be fooled and readline - left in a strange state by a poorly-timed longjmp. */ - if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK)) - RL_UNSETSTATE (RL_STATE_CALLBACK); -#endif - - rl_set_prompt (prompt); - - rl_initialize (); - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - -#if defined (HANDLE_SIGNALS) - rl_set_signals (); -#endif - - value = readline_internal (); - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - -#if 0 - if (in_callback) - RL_SETSTATE (RL_STATE_CALLBACK); -#endif - -#if HAVE_DECL_AUDIT_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT) - if (value) - _rl_audit_tty (value); -#endif - - return (value); -} - -#if defined (READLINE_CALLBACKS) -# define STATIC_CALLBACK -#else -# define STATIC_CALLBACK static -#endif - -STATIC_CALLBACK void -readline_internal_setup () -{ - char *nprompt; - - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - /* Enable the meta key only for the duration of readline(), if this - terminal has one and the terminal has been initialized */ - if (_rl_enable_meta & RL_ISSTATE (RL_STATE_TERMPREPPED)) - _rl_enable_meta_key (); - - if (rl_startup_hook) - (*rl_startup_hook) (); - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (1, 'i'); /* don't want to reset last */ -#endif /* VI_MODE */ - - /* If we're not echoing, we still want to at least print a prompt, because - rl_redisplay will not do it for us. If the calling application has a - custom redisplay function, though, let that function handle it. */ - if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay) - { - if (rl_prompt && rl_already_prompted == 0) - { - nprompt = _rl_strip_prompt (rl_prompt); - fprintf (_rl_out_stream, "%s", nprompt); - fflush (_rl_out_stream); - xfree (nprompt); - } - } - else - { - if (rl_prompt && rl_already_prompted) - rl_on_new_line_with_prompt (); - else - rl_on_new_line (); - (*rl_redisplay_function) (); - } - - if (rl_pre_input_hook) - (*rl_pre_input_hook) (); - - RL_CHECK_SIGNALS (); -} - -STATIC_CALLBACK char * -readline_internal_teardown (eof) - int eof; -{ - char *temp; - HIST_ENTRY *entry; - - RL_CHECK_SIGNALS (); - - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - entry = current_history (); - - if (entry && rl_undo_list) - { - temp = savestring (the_line); - rl_revert_line (1, 0); - entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); - _rl_free_history_entry (entry); - - strcpy (the_line, temp); - xfree (temp); - } - - if (_rl_revert_all_at_newline) - _rl_revert_all_lines (); - - /* At any rate, it is highly likely that this line has an undo list. Get - rid of it now. */ - if (rl_undo_list) - rl_free_undo_list (); - - /* Disable the meta key, if this terminal has one and we were told to use it. - The check whether or not we sent the enable string is in - _rl_disable_meta_key(); the flag is set in _rl_enable_meta_key */ - _rl_disable_meta_key (); - - /* Restore normal cursor, if available. */ - _rl_set_insert_mode (RL_IM_INSERT, 0); - - return (eof ? (char *)NULL : savestring (the_line)); -} - -void -_rl_internal_char_cleanup () -{ -#if defined (VI_MODE) - /* In vi mode, when you exit insert mode, the cursor moves back - over the previous character. We explicitly check for that here. */ - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) - rl_vi_check (); -#endif /* VI_MODE */ - - if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - rl_newline (1, '\n'); - } - - if (rl_done == 0) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - /* If the application writer has told us to erase the entire line if - the only character typed was something bound to rl_newline, do so. */ - if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && - rl_point == 0 && rl_end == 0) - _rl_erase_entire_line (); -} - -STATIC_CALLBACK int -#if defined (READLINE_CALLBACKS) -readline_internal_char () -#else -readline_internal_charloop () -#endif -{ - static int lastc, eof_found; - int c, code, lk; - - lastc = EOF; - eof_found = 0; - -#if !defined (READLINE_CALLBACKS) - while (rl_done == 0) - { -#endif - lk = _rl_last_command_was_kill; - -#if defined (HAVE_POSIX_SIGSETJMP) - code = sigsetjmp (_rl_top_level, 0); -#else - code = setjmp (_rl_top_level); -#endif - - if (code) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - /* If we get here, we're not being called from something dispatched - from _rl_callback_read_char(), which sets up its own value of - _rl_top_level (saving and restoring the old, of course), so - we can just return here. */ - if (RL_ISSTATE (RL_STATE_CALLBACK)) - return (0); - } - - if (rl_pending_input == 0) - { - /* Then initialize the argument and number of keys read. */ - _rl_reset_argument (); - rl_key_sequence_length = 0; - rl_executing_keyseq[0] = 0; - } - - RL_SETSTATE(RL_STATE_READCMD); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_READCMD); - - /* look at input.c:rl_getc() for the circumstances under which this will - be returned; punt immediately on read error without converting it to - a newline; assume that rl_read_key has already called the signal - handler. */ - if (c == READERR) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - /* EOF typed to a non-blank line is ^D the first time, EOF the second - time in a row. This won't return any partial line read from the tty. - If we want to change this, to force any existing line to be returned - when read(2) reads EOF, for example, this is the place to change. */ - if (c == EOF && rl_end) - { - if (RL_SIG_RECEIVED ()) - { - RL_CHECK_SIGNALS (); - if (rl_signal_event_hook) - (*rl_signal_event_hook) (); /* XXX */ - } - - /* XXX - reading two consecutive EOFs returns EOF */ - if (RL_ISSTATE (RL_STATE_TERMPREPPED)) - { - if (lastc == _rl_eof_char || lastc == EOF) - rl_end = 0; - else - c = _rl_eof_char; - } - else - c = NEWLINE; - } - - /* The character _rl_eof_char typed to blank line, and not as the - previous character is interpreted as EOF. This doesn't work when - READLINE_CALLBACKS is defined, so hitting a series of ^Ds will - erase all the chars on the line and then return EOF. */ - if (((c == _rl_eof_char && lastc != c) || c == EOF) && rl_end == 0) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - lastc = c; - _rl_dispatch ((unsigned char)c, _rl_keymap); - RL_CHECK_SIGNALS (); - - /* If there was no change in _rl_last_command_was_kill, then no kill - has taken place. Note that if input is pending we are reading - a prefix command, so nothing has changed yet. */ - if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) - _rl_last_command_was_kill = 0; - - _rl_internal_char_cleanup (); - -#if defined (READLINE_CALLBACKS) - return 0; -#else - } - - return (eof_found); -#endif -} - -#if defined (READLINE_CALLBACKS) -static int -readline_internal_charloop () -{ - int eof = 1; - - while (rl_done == 0) - eof = readline_internal_char (); - return (eof); -} -#endif /* READLINE_CALLBACKS */ - -/* Read a line of input from the global rl_instream, doing output on - the global rl_outstream. - If rl_prompt is non-null, then that is our prompt. */ -static char * -readline_internal () -{ - int eof; - - readline_internal_setup (); - eof = readline_internal_charloop (); - return (readline_internal_teardown (eof)); -} - -void -_rl_init_line_state () -{ - rl_point = rl_end = rl_mark = 0; - the_line = rl_line_buffer; - the_line[0] = 0; -} - -void -_rl_set_the_line () -{ - the_line = rl_line_buffer; -} - -#if defined (READLINE_CALLBACKS) -_rl_keyseq_cxt * -_rl_keyseq_cxt_alloc () -{ - _rl_keyseq_cxt *cxt; - - cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); - - cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; - - cxt->okey = 0; - cxt->ocxt = _rl_kscxt; - cxt->childval = 42; /* sentinel value */ - - return cxt; -} - -void -_rl_keyseq_cxt_dispose (cxt) - _rl_keyseq_cxt *cxt; -{ - xfree (cxt); -} - -void -_rl_keyseq_chain_dispose () -{ - _rl_keyseq_cxt *cxt; - - while (_rl_kscxt) - { - cxt = _rl_kscxt; - _rl_kscxt = _rl_kscxt->ocxt; - _rl_keyseq_cxt_dispose (cxt); - } -} -#endif - -static int -_rl_subseq_getchar (key) - int key; -{ - int k; - - if (key == ESC) - RL_SETSTATE(RL_STATE_METANEXT); - RL_SETSTATE(RL_STATE_MOREINPUT); - k = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (key == ESC) - RL_UNSETSTATE(RL_STATE_METANEXT); - - return k; -} - -#if defined (READLINE_CALLBACKS) -int -_rl_dispatch_callback (cxt) - _rl_keyseq_cxt *cxt; -{ - int nkey, r; - - /* For now */ - /* The first time this context is used, we want to read input and dispatch - on it. When traversing the chain of contexts back `up', we want to use - the value from the next context down. We're simulating recursion using - a chain of contexts. */ - if ((cxt->flags & KSEQ_DISPATCHED) == 0) - { - nkey = _rl_subseq_getchar (cxt->okey); - if (nkey < 0) - { - _rl_abort_internal (); - return -1; - } - r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); - cxt->flags |= KSEQ_DISPATCHED; - } - else - r = cxt->childval; - - /* For now */ - if (r != -3) /* don't do this if we indicate there will be other matches */ - r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ)); - - RL_CHECK_SIGNALS (); - /* We only treat values < 0 specially to simulate recursion. */ - if (r >= 0 || (r == -1 && (cxt->flags & KSEQ_SUBSEQ) == 0)) /* success! or failure! */ - { - _rl_keyseq_chain_dispose (); - RL_UNSETSTATE (RL_STATE_MULTIKEY); - return r; - } - - if (r != -3) /* magic value that says we added to the chain */ - _rl_kscxt = cxt->ocxt; - if (_rl_kscxt) - _rl_kscxt->childval = r; - if (r != -3) - _rl_keyseq_cxt_dispose (cxt); - - return r; -} -#endif /* READLINE_CALLBACKS */ - -/* Do the command associated with KEY in MAP. - If the associated command is really a keymap, then read - another key, and dispatch into that map. */ -int -_rl_dispatch (key, map) - register int key; - Keymap map; -{ - _rl_dispatching_keymap = map; - return _rl_dispatch_subseq (key, map, 0); -} - -int -_rl_dispatch_subseq (key, map, got_subseq) - register int key; - Keymap map; - int got_subseq; -{ - int r, newkey; - char *macro; - rl_command_func_t *func; -#if defined (READLINE_CALLBACKS) - _rl_keyseq_cxt *cxt; -#endif - - if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) - { - if (map[ESC].type == ISKMAP) - { - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (ESC); - RESIZE_KEYSEQ_BUFFER (); - rl_executing_keyseq[rl_key_sequence_length++] = ESC; - map = FUNCTION_TO_KEYMAP (map, ESC); - key = UNMETA (key); - return (_rl_dispatch (key, map)); - } - else - rl_ding (); - return 0; - } - - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (key); - - r = 0; - switch (map[key].type) - { - case ISFUNC: - func = map[key].function; - if (func) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - /* Should we do anything special if key == ANYOTHERKEY? */ - return (_rl_dispatch (_rl_to_lower (key), map)); - - rl_executing_keymap = map; - rl_executing_key = key; - - RESIZE_KEYSEQ_BUFFER(); - rl_executing_keyseq[rl_key_sequence_length++] = key; - rl_executing_keyseq[rl_key_sequence_length] = '\0'; - - rl_dispatching = 1; - RL_SETSTATE(RL_STATE_DISPATCHING); - r = (*func) (rl_numeric_arg * rl_arg_sign, key); - RL_UNSETSTATE(RL_STATE_DISPATCHING); - rl_dispatching = 0; - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. Otherwise, - remember the last command executed in this variable. */ - if (rl_pending_input == 0 && map[key].function != rl_digit_argument) - rl_last_func = map[key].function; - - RL_CHECK_SIGNALS (); - } - else if (map[ANYOTHERKEY].function) - { - /* OK, there's no function bound in this map, but there is a - shadow function that was overridden when the current keymap - was created. Return -2 to note that. */ - if (RL_ISSTATE (RL_STATE_MACROINPUT)) - _rl_prev_macro_key (); - else - _rl_unget_char (key); - return -2; - } - else if (got_subseq) - { - /* Return -1 to note that we're in a subsequence, but we don't - have a matching key, nor was one overridden. This means - we need to back up the recursion chain and find the last - subsequence that is bound to a function. */ - if (RL_ISSTATE (RL_STATE_MACROINPUT)) - _rl_prev_macro_key (); - else - _rl_unget_char (key); - return -1; - } - else - { -#if defined (READLINE_CALLBACKS) - RL_UNSETSTATE (RL_STATE_MULTIKEY); - _rl_keyseq_chain_dispose (); -#endif - _rl_abort_internal (); - return -1; - } - break; - - case ISKMAP: - if (map[key].function != 0) - { -#if defined (VI_MODE) - /* The only way this test will be true is if a subsequence has been - bound starting with ESC, generally the arrow keys. What we do is - check whether there's input in the queue, which there generally - will be if an arrow key has been pressed, and, if there's not, - just dispatch to (what we assume is) rl_vi_movement_mode right - away. This is essentially an input test with a zero timeout (by - default) or a timeout determined by the value of `keyseq-timeout' */ - /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued - takes microseconds, so multiply by 1000 */ - if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap - && _rl_input_queued ((_rl_keyseq_timeout > 0) ? _rl_keyseq_timeout*1000 : 0) == 0) - return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); -#endif - - RESIZE_KEYSEQ_BUFFER (); - rl_executing_keyseq[rl_key_sequence_length++] = key; - _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key); - - /* Allocate new context here. Use linked contexts (linked through - cxt->ocxt) to simulate recursion */ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - /* Return 0 only the first time, to indicate success to - _rl_callback_read_char. The rest of the time, we're called - from _rl_dispatch_callback, so we return -3 to indicate - special handling is necessary. */ - r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0; - cxt = _rl_keyseq_cxt_alloc (); - - if (got_subseq) - cxt->flags |= KSEQ_SUBSEQ; - cxt->okey = key; - cxt->oldmap = map; - cxt->dmap = _rl_dispatching_keymap; - cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function; - - RL_SETSTATE (RL_STATE_MULTIKEY); - _rl_kscxt = cxt; - - return r; /* don't indicate immediate success */ - } -#endif - - /* Tentative inter-character timeout for potential multi-key - sequences? If no input within timeout, abort sequence and - act as if we got non-matching input. */ - /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued - takes microseconds, so multiply by 1000 */ - if (_rl_keyseq_timeout > 0 && - (RL_ISSTATE (RL_STATE_INPUTPENDING|RL_STATE_MACROINPUT) == 0) && - _rl_pushed_input_available () == 0 && - _rl_dispatching_keymap[ANYOTHERKEY].function && - _rl_input_queued (_rl_keyseq_timeout*1000) == 0) - return (_rl_subseq_result (-2, map, key, got_subseq)); - - newkey = _rl_subseq_getchar (key); - if (newkey < 0) - { - _rl_abort_internal (); - return -1; - } - - r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function); - return _rl_subseq_result (r, map, key, got_subseq); - } - else - { - _rl_abort_internal (); /* XXX */ - return -1; - } - break; - - case ISMACR: - if (map[key].function != 0) - { - rl_executing_keyseq[rl_key_sequence_length] = '\0'; - macro = savestring ((char *)map[key].function); - _rl_with_macro_input (macro); - return 0; - } - break; - } -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && - key != ANYOTHERKEY && - _rl_dispatching_keymap == vi_movement_keymap && - _rl_vi_textmod_command (key)) - _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); -#endif - - return (r); -} - -static int -_rl_subseq_result (r, map, key, got_subseq) - int r; - Keymap map; - int key, got_subseq; -{ - Keymap m; - int type, nt; - rl_command_func_t *func, *nf; - - if (r == -2) - /* We didn't match anything, and the keymap we're indexed into - shadowed a function previously bound to that prefix. Call - the function. The recursive call to _rl_dispatch_subseq has - already taken care of pushing any necessary input back onto - the input queue with _rl_unget_char. */ - { - m = _rl_dispatching_keymap; - type = m[ANYOTHERKEY].type; - func = m[ANYOTHERKEY].function; - if (type == ISFUNC && func == rl_do_lowercase_version) - r = _rl_dispatch (_rl_to_lower (key), map); - else if (type == ISFUNC && func == rl_insert) - { - /* If the function that was shadowed was self-insert, we - somehow need a keymap with map[key].func == self-insert. - Let's use this one. */ - nt = m[key].type; - nf = m[key].function; - - m[key].type = type; - m[key].function = func; - r = _rl_dispatch (key, m); - m[key].type = nt; - m[key].function = nf; - } - else - r = _rl_dispatch (ANYOTHERKEY, m); - } - else if (r && map[ANYOTHERKEY].function) - { - /* We didn't match (r is probably -1), so return something to - tell the caller that it should try ANYOTHERKEY for an - overridden function. */ - if (RL_ISSTATE (RL_STATE_MACROINPUT)) - _rl_prev_macro_key (); - else - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -2; - } - else if (r && got_subseq) - { - /* OK, back up the chain. */ - if (RL_ISSTATE (RL_STATE_MACROINPUT)) - _rl_prev_macro_key (); - else - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -1; - } - - return r; -} - -/* **************************************************************** */ -/* */ -/* Initializations */ -/* */ -/* **************************************************************** */ - -/* Initialize readline (and terminal if not already). */ -int -rl_initialize () -{ - /* If we have never been called before, initialize the - terminal and data structures. */ - if (!rl_initialized) - { - RL_SETSTATE(RL_STATE_INITIALIZING); - readline_initialize_everything (); - RL_UNSETSTATE(RL_STATE_INITIALIZING); - rl_initialized++; - RL_SETSTATE(RL_STATE_INITIALIZED); - } - - /* Initialize the current line information. */ - _rl_init_line_state (); - - /* We aren't done yet. We haven't even gotten started yet! */ - rl_done = 0; - RL_UNSETSTATE(RL_STATE_DONE); - - /* Tell the history routines what is going on. */ - _rl_start_using_history (); - - /* Make the display buffer match the state of the line. */ - rl_reset_line_state (); - - /* No such function typed yet. */ - rl_last_func = (rl_command_func_t *)NULL; - - /* Parsing of key-bindings begins in an enabled state. */ - _rl_parsing_conditionalized_out = 0; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - _rl_vi_initialize_line (); -#endif - - /* Each line starts in insert mode (the default). */ - _rl_set_insert_mode (RL_IM_DEFAULT, 1); - - return 0; -} - -#if 0 -#if defined (__EMX__) -static void -_emx_build_environ () -{ - TIB *tibp; - PIB *pibp; - char *t, **tp; - int c; - - DosGetInfoBlocks (&tibp, &pibp); - t = pibp->pib_pchenv; - for (c = 1; *t; c++) - t += strlen (t) + 1; - tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *)); - t = pibp->pib_pchenv; - while (*t) - { - *tp++ = t; - t += strlen (t) + 1; - } - *tp = 0; -} -#endif /* __EMX__ */ -#endif - -/* Initialize the entire state of the world. */ -static void -readline_initialize_everything () -{ -#if 0 -#if defined (__EMX__) - if (environ == 0) - _emx_build_environ (); -#endif -#endif - -#if 0 - /* Find out if we are running in Emacs -- UNUSED. */ - running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; -#endif - - /* Set up input and output if they are not already set up. */ - if (!rl_instream) - rl_instream = stdin; - - if (!rl_outstream) - rl_outstream = stdout; - - /* Bind _rl_in_stream and _rl_out_stream immediately. These values - may change, but they may also be used before readline_internal () - is called. */ - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - /* Allocate data structures. */ - if (rl_line_buffer == 0) - rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - - /* Initialize the terminal interface. */ - if (rl_terminal_name == 0) - rl_terminal_name = sh_get_env_value ("TERM"); - _rl_init_terminal_io (rl_terminal_name); - - /* Bind tty characters to readline functions. */ - readline_default_bindings (); - - /* Initialize the function names. */ - rl_initialize_funmap (); - - /* Decide whether we should automatically go into eight-bit mode. */ - _rl_init_eightbit (); - - /* Read in the init file. */ - rl_read_init_file ((char *)NULL); - - /* XXX */ - if (_rl_horizontal_scroll_mode && _rl_term_autowrap) - { - _rl_screenwidth--; - _rl_screenchars -= _rl_screenheight; - } - - /* Override the effect of any `set keymap' assignments in the - inputrc file. */ - rl_set_keymap_from_edit_mode (); - - /* Try to bind a common arrow key prefix, if not already bound. */ - bind_arrow_keys (); - - /* Bind the bracketed paste prefix assuming that the user will enable - it on terminals that support it. */ - bind_bracketed_paste_prefix (); - - /* If the completion parser's default word break characters haven't - been set yet, then do so now. */ - if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; - -#if defined (COLOR_SUPPORT) - if (_rl_colored_stats || _rl_colored_completion_prefix) - _rl_parse_colors (); -#endif - - rl_executing_keyseq = malloc (_rl_executing_keyseq_size = 16); - if (rl_executing_keyseq) - rl_executing_keyseq[0] = '\0'; -} - -/* If this system allows us to look at the values of the regular - input editing characters, then bind them to their readline - equivalents, iff the characters are not bound to keymaps. */ -static void -readline_default_bindings () -{ - if (_rl_bind_stty_chars) - rl_tty_set_default_bindings (_rl_keymap); -} - -/* Reset the default bindings for the terminal special characters we're - interested in back to rl_insert and read the new ones. */ -static void -reset_default_bindings () -{ - if (_rl_bind_stty_chars) - { - rl_tty_unset_default_bindings (_rl_keymap); - rl_tty_set_default_bindings (_rl_keymap); - } -} - -/* Bind some common arrow key sequences in MAP. */ -static void -bind_arrow_keys_internal (map) - Keymap map; -{ - Keymap xkeymap; - - xkeymap = _rl_keymap; - _rl_keymap = map; - -#if defined (__MSDOS__) - rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); -#endif - - rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); - - rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); - -#if defined (__MINGW32__) - rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\340M", rl_forward_char); - rl_bind_keyseq_if_unbound ("\340K", rl_backward_char); - rl_bind_keyseq_if_unbound ("\340G", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\340O", rl_end_of_line); - rl_bind_keyseq_if_unbound ("\340S", rl_delete); - rl_bind_keyseq_if_unbound ("\340R", rl_overwrite_mode); - - /* These may or may not work because of the embedded NUL. */ - rl_bind_keyseq_if_unbound ("\\000H", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\\000P", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\\000M", rl_forward_char); - rl_bind_keyseq_if_unbound ("\\000K", rl_backward_char); - rl_bind_keyseq_if_unbound ("\\000G", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\\000O", rl_end_of_line); - rl_bind_keyseq_if_unbound ("\\000S", rl_delete); - rl_bind_keyseq_if_unbound ("\\000R", rl_overwrite_mode); -#endif - - _rl_keymap = xkeymap; -} - -/* Try and bind the common arrow key prefixes after giving termcap and - the inputrc file a chance to bind them and create `real' keymaps - for the arrow key prefix. */ -static void -bind_arrow_keys () -{ - bind_arrow_keys_internal (emacs_standard_keymap); - -#if defined (VI_MODE) - bind_arrow_keys_internal (vi_movement_keymap); - /* Unbind vi_movement_keymap[ESC] to allow users to repeatedly hit ESC - in vi command mode while still allowing the arrow keys to work. */ - if (vi_movement_keymap[ESC].type == ISKMAP) - rl_bind_keyseq_in_map ("\033", (rl_command_func_t *)NULL, vi_movement_keymap); - bind_arrow_keys_internal (vi_insertion_keymap); -#endif -} - -static void -bind_bracketed_paste_prefix () -{ - Keymap xkeymap; - - xkeymap = _rl_keymap; - - _rl_keymap = emacs_standard_keymap; - rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_bracketed_paste_begin); - - _rl_keymap = vi_insertion_keymap; - rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_bracketed_paste_begin); - - _rl_keymap = xkeymap; -} - -/* **************************************************************** */ -/* */ -/* Saving and Restoring Readline's state */ -/* */ -/* **************************************************************** */ - -int -rl_save_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - sp->point = rl_point; - sp->end = rl_end; - sp->mark = rl_mark; - sp->buffer = rl_line_buffer; - sp->buflen = rl_line_buffer_len; - sp->ul = rl_undo_list; - sp->prompt = rl_prompt; - - sp->rlstate = rl_readline_state; - sp->done = rl_done; - sp->kmap = _rl_keymap; - - sp->lastfunc = rl_last_func; - sp->insmode = rl_insert_mode; - sp->edmode = rl_editing_mode; - sp->kseq = rl_executing_keyseq; - sp->kseqlen = rl_key_sequence_length; - sp->inf = rl_instream; - sp->outf = rl_outstream; - sp->pendingin = rl_pending_input; - sp->macro = rl_executing_macro; - - sp->catchsigs = rl_catch_signals; - sp->catchsigwinch = rl_catch_sigwinch; - - sp->entryfunc = rl_completion_entry_function; - sp->menuentryfunc = rl_menu_completion_entry_function; - sp->ignorefunc = rl_ignore_some_completions_function; - sp->attemptfunc = rl_attempted_completion_function; - sp->wordbreakchars = rl_completer_word_break_characters; - - return (0); -} - -int -rl_restore_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - rl_point = sp->point; - rl_end = sp->end; - rl_mark = sp->mark; - the_line = rl_line_buffer = sp->buffer; - rl_line_buffer_len = sp->buflen; - rl_undo_list = sp->ul; - rl_prompt = sp->prompt; - - rl_readline_state = sp->rlstate; - rl_done = sp->done; - _rl_keymap = sp->kmap; - - rl_last_func = sp->lastfunc; - rl_insert_mode = sp->insmode; - rl_editing_mode = sp->edmode; - rl_executing_keyseq = sp->kseq; - rl_key_sequence_length = sp->kseqlen; - rl_instream = sp->inf; - rl_outstream = sp->outf; - rl_pending_input = sp->pendingin; - rl_executing_macro = sp->macro; - - rl_catch_signals = sp->catchsigs; - rl_catch_sigwinch = sp->catchsigwinch; - - rl_completion_entry_function = sp->entryfunc; - rl_menu_completion_entry_function = sp->menuentryfunc; - rl_ignore_some_completions_function = sp->ignorefunc; - rl_attempted_completion_function = sp->attemptfunc; - rl_completer_word_break_characters = sp->wordbreakchars; - - return (0); -} diff --git a/lib/readline/readline.h~ b/lib/readline/readline.h~ deleted file mode 100644 index 5c7ffb007..000000000 --- a/lib/readline/readline.h~ +++ /dev/null @@ -1,933 +0,0 @@ -/* 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/rlmbutil.h~ b/lib/readline/rlmbutil.h~ deleted file mode 100644 index 06d85ab37..000000000 --- a/lib/readline/rlmbutil.h~ +++ /dev/null @@ -1,163 +0,0 @@ -/* rlmbutil.h -- utility functions for multibyte characters. */ - -/* Copyright (C) 2001-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#if !defined (_RL_MBUTIL_H_) -#define _RL_MBUTIL_H_ - -#include "rlstdc.h" - -/************************************************/ -/* check multibyte capability for I18N code */ -/************************************************/ - -/* For platforms which support the ISO C amendement 1 functionality we - support user defined character classes. */ - /* Solaris 2.5 has a bug: must be included before . */ -#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) && defined (HAVE_LOCALE_H) -# include -# include -# if defined (HAVE_ISWCTYPE) && \ - defined (HAVE_ISWLOWER) && \ - defined (HAVE_ISWUPPER) && \ - defined (HAVE_MBSRTOWCS) && \ - defined (HAVE_MBRTOWC) && \ - defined (HAVE_MBRLEN) && \ - defined (HAVE_TOWLOWER) && \ - defined (HAVE_TOWUPPER) && \ - defined (HAVE_WCHAR_T) && \ - defined (HAVE_WCWIDTH) - /* system is supposed to support XPG5 */ -# define HANDLE_MULTIBYTE 1 -# endif -#endif - -/* If we don't want multibyte chars even on a system that supports them, let - the configuring user turn multibyte support off. */ -#if defined (NO_MULTIBYTE_SUPPORT) -# undef HANDLE_MULTIBYTE -#endif - -/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ -#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) -# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) -# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) -# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) -# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) -# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) -# define mbstate_t int -#endif - -/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to - handle multibyte chars (some systems define MB_LEN_MAX as 1) */ -#ifdef HANDLE_MULTIBYTE -# include -# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) -# undef MB_LEN_MAX -# endif -# if !defined (MB_LEN_MAX) -# define MB_LEN_MAX 16 -# endif -#endif - -/************************************************/ -/* end of multibyte capability checks for I18N */ -/************************************************/ - -/* - * Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar: - * - * MB_FIND_ANY find any multibyte character - * MB_FIND_NONZERO find a non-zero-width multibyte character - */ - -#define MB_FIND_ANY 0x00 -#define MB_FIND_NONZERO 0x01 - -extern int _rl_find_prev_mbchar PARAMS((char *, int, int)); -extern int _rl_find_next_mbchar PARAMS((char *, int, int, int)); - -#ifdef HANDLE_MULTIBYTE - -extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *)); -extern int _rl_get_char_len PARAMS((char *, mbstate_t *)); -extern int _rl_adjust_point PARAMS((char *, int, mbstate_t *)); - -extern int _rl_read_mbchar PARAMS((char *, int)); -extern int _rl_read_mbstring PARAMS((int, char *, int)); - -extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int)); - -extern wchar_t _rl_char_value PARAMS((char *, int)); -extern int _rl_walphabetic PARAMS((wchar_t)); - -#define _rl_to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc)) -#define _rl_to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc)) - -#define MB_NEXTCHAR(b,s,c,f) \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) \ - ? _rl_find_next_mbchar ((b), (s), (c), (f)) \ - : ((s) + (c))) -#define MB_PREVCHAR(b,s,f) \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) \ - ? _rl_find_prev_mbchar ((b), (s), (f)) \ - : ((s) - 1)) - -#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2) -#define MB_NULLWCH(x) ((x) == 0) - -/* Unicode combining characters range from U+0300 to U+036F */ -#define UNICODE_COMBINING_CHAR(x) ((x) >= 768 && (x) <= 879) - -#if defined (WCWIDTH_BROKEN) -# define WCWIDTH(wc) ((_rl_utf8locale && UNICODE_COMBINING_CHAR(wc)) ? 0 : wcwidth(wc)) -#else -# define WCWIDTH(wc) wcwidth(wc) -#endif - -#else /* !HANDLE_MULTIBYTE */ - -#undef MB_LEN_MAX -#undef MB_CUR_MAX - -#define MB_LEN_MAX 1 -#define MB_CUR_MAX 1 - -#define _rl_find_prev_mbchar(b, i, f) (((i) == 0) ? (i) : ((i) - 1)) -#define _rl_find_next_mbchar(b, i1, i2, f) ((i1) + (i2)) - -#define _rl_char_value(buf,ind) ((buf)[(ind)]) - -#define _rl_walphabetic(c) (rl_alphabetic (c)) - -#define _rl_to_wupper(c) (_rl_to_upper (c)) -#define _rl_to_wlower(c) (_rl_to_lower (c)) - -#define MB_NEXTCHAR(b,s,c,f) ((s) + (c)) -#define MB_PREVCHAR(b,s,f) ((s) - 1) - -#define MB_INVALIDCH(x) (0) -#define MB_NULLWCH(x) (0) - -#endif /* !HANDLE_MULTIBYTE */ - -extern int rl_byte_oriented; - -#endif /* _RL_MBUTIL_H_ */ diff --git a/lib/readline/signals.c~ b/lib/readline/signals.c~ deleted file mode 100644 index 2dd34af23..000000000 --- a/lib/readline/signals.c~ +++ /dev/null @@ -1,709 +0,0 @@ -/* signals.c -- signal handling support for readline. */ - -/* Copyright (C) 1987-2011 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include /* Just for NULL. Yuck. */ -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" - -#if defined (HANDLE_SIGNALS) - -#if !defined (RETSIGTYPE) -# if defined (VOID_SIGHANDLER) -# define RETSIGTYPE void -# else -# define RETSIGTYPE int -# endif /* !VOID_SIGHANDLER */ -#endif /* !RETSIGTYPE */ - -#if defined (VOID_SIGHANDLER) -# define SIGHANDLER_RETURN return -#else -# define SIGHANDLER_RETURN return (0) -#endif - -/* This typedef is equivalent to the one for Function; it allows us - to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef RETSIGTYPE SigHandler (); - -#if defined (HAVE_POSIX_SIGNALS) -typedef struct sigaction sighandler_cxt; -# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) -#else -typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt; -# define sigemptyset(m) -#endif /* !HAVE_POSIX_SIGNALS */ - -#ifndef SA_RESTART -# define SA_RESTART 0 -#endif - -static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); -static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); -static void rl_maybe_restore_sighandler PARAMS((int, sighandler_cxt *)); - -static RETSIGTYPE rl_signal_handler PARAMS((int)); -static RETSIGTYPE _rl_handle_signal PARAMS((int)); - -/* Exported variables for use by applications. */ - -/* If non-zero, readline will install its own signal handlers for - SIGINT, SIGTERM, SIGHUP, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ -int rl_catch_signals = 1; - -/* If non-zero, readline will install a signal handler for SIGWINCH. */ -#ifdef SIGWINCH -int rl_catch_sigwinch = 1; -#else -int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */ -#endif - -/* Private variables. */ -int _rl_interrupt_immediately = 0; -int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including everywhere */ - -/* If non-zero, print characters corresponding to received signals as long as - the user has indicated his desire to do so (_rl_echo_control_chars). */ -int _rl_echoctl = 0; - -int _rl_intr_char = 0; -int _rl_quit_char = 0; -int _rl_susp_char = 0; - -static int signals_set_flag; -static int sigwinch_set_flag; - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ - -static sighandler_cxt old_int, old_term, old_hup, old_alrm, old_quit; -#if defined (SIGTSTP) -static sighandler_cxt old_tstp, old_ttou, old_ttin; -#endif -#if defined (SIGWINCH) -static sighandler_cxt old_winch; -#endif - -_rl_sigcleanup_func_t *_rl_sigcleanup; -void *_rl_sigcleanarg; - -/* Readline signal handler functions. */ - -/* Called from RL_CHECK_SIGNALS() macro */ -RETSIGTYPE -_rl_signal_handler (sig) - int sig; -{ - _rl_caught_signal = 0; /* XXX */ - -#if defined (SIGWINCH) - if (sig == SIGWINCH) - { - rl_resize_terminal (); - /* 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/text.c~ b/lib/readline/text.c~ deleted file mode 100644 index bb496d5fd..000000000 --- a/lib/readline/text.c~ +++ /dev/null @@ -1,1705 +0,0 @@ -/* text.c -- text handling commands for readline. */ - -/* 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 (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (__EMX__) -# define INCL_DOSPROCESS -# include -#endif /* __EMX__ */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -/* Forward declarations. */ -static int rl_change_case PARAMS((int, int)); -static int _rl_char_search PARAMS((int, int, int)); - -#if defined (READLINE_CALLBACKS) -static int _rl_insert_next_callback PARAMS((_rl_callback_generic_arg *)); -static int _rl_char_search_callback PARAMS((_rl_callback_generic_arg *)); -#endif - -/* The largest chunk of text that can be inserted in one call to - rl_insert_text. Text blocks larger than this are divided. */ -#define TEXT_COUNT_MAX 1024 - -/* **************************************************************** */ -/* */ -/* Insert and Delete */ -/* */ -/* **************************************************************** */ - -/* Insert a string of text into the line at point. This is the only - way that you should do insertion. _rl_insert_char () calls this - function. Returns the number of characters inserted. */ -int -rl_insert_text (string) - const char *string; -{ - register int i, l; - - l = (string && *string) ? strlen (string) : 0; - if (l == 0) - return 0; - - if (rl_end + l >= rl_line_buffer_len) - rl_extend_line_buffer (rl_end + l); - - for (i = rl_end; i >= rl_point; i--) - rl_line_buffer[i + l] = rl_line_buffer[i]; - strncpy (rl_line_buffer + rl_point, string, l); - - /* Remember how to undo this if we aren't undoing something. */ - if (_rl_doing_an_undo == 0) - { - /* If possible and desirable, concatenate the undos. */ - if ((l == 1) && - rl_undo_list && - (rl_undo_list->what == UNDO_INSERT) && - (rl_undo_list->end == rl_point) && - (rl_undo_list->end - rl_undo_list->start < 20)) - rl_undo_list->end++; - else - rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); - } - rl_point += l; - rl_end += l; - rl_line_buffer[rl_end] = '\0'; - return l; -} - -/* Delete the string between FROM and TO. FROM is inclusive, TO is not. - Returns the number of characters deleted. */ -int -rl_delete_text (from, to) - int from, to; -{ - register char *text; - register int diff, i; - - /* Fix it if the caller is confused. */ - if (from > to) - SWAP (from, to); - - /* fix boundaries */ - if (to > rl_end) - { - to = rl_end; - if (from > to) - from = to; - } - if (from < 0) - from = 0; - - text = rl_copy_text (from, to); - - /* Some versions of strncpy() can't handle overlapping arguments. */ - diff = to - from; - for (i = from; i < rl_end - diff; i++) - rl_line_buffer[i] = rl_line_buffer[i + diff]; - - /* Remember how to undo this delete. */ - if (_rl_doing_an_undo == 0) - rl_add_undo (UNDO_DELETE, from, to, text); - else - xfree (text); - - rl_end -= diff; - rl_line_buffer[rl_end] = '\0'; - return (diff); -} - -/* Fix up point so that it is within the line boundaries after killing - text. If FIX_MARK_TOO is non-zero, the mark is forced within line - boundaries also. */ - -#define _RL_FIX_POINT(x) \ - do { \ - if (x > rl_end) \ - x = rl_end; \ - else if (x < 0) \ - x = 0; \ - } while (0) - -void -_rl_fix_point (fix_mark_too) - int fix_mark_too; -{ - _RL_FIX_POINT (rl_point); - if (fix_mark_too) - _RL_FIX_POINT (rl_mark); -} -#undef _RL_FIX_POINT - -/* Replace the contents of the line buffer between START and END with - TEXT. The operation is undoable. To replace the entire line in an - undoable mode, use _rl_replace_text(text, 0, rl_end); */ -int -_rl_replace_text (text, start, end) - const char *text; - int start, end; -{ - int n; - - n = 0; - rl_begin_undo_group (); - if (start <= end) - rl_delete_text (start, end + 1); - rl_point = start; - if (*text) - n = rl_insert_text (text); - rl_end_undo_group (); - - return n; -} - -/* Replace the current line buffer contents with TEXT. If CLEAR_UNDO is - non-zero, we free the current undo list. */ -void -rl_replace_line (text, clear_undo) - const char *text; - int clear_undo; -{ - int len; - - len = strlen (text); - if (len >= rl_line_buffer_len) - rl_extend_line_buffer (len); - strcpy (rl_line_buffer, text); - rl_end = len; - - if (clear_undo) - rl_free_undo_list (); - - _rl_fix_point (1); -} - -/* **************************************************************** */ -/* */ -/* Readline character functions */ -/* */ -/* **************************************************************** */ - -/* This is not a gap editor, just a stupid line input routine. No hair - is involved in writing any of the functions, and none should be. */ - -/* Note that: - - rl_end is the place in the string that we would place '\0'; - i.e., it is always safe to place '\0' there. - - rl_point is the place in the string where the cursor is. Sometimes - this is the same as rl_end. - - Any command that is called interactively receives two arguments. - The first is a count: the numeric arg passed to this command. - The second is the key which invoked this command. -*/ - -/* **************************************************************** */ -/* */ -/* Movement Commands */ -/* */ -/* **************************************************************** */ - -/* Note that if you `optimize' the display for these functions, you cannot - use said functions in other functions which do not do optimizing display. - I.e., you will have to update the data base for rl_redisplay, and you - might as well let rl_redisplay do that job. */ - -/* Move forward COUNT bytes. */ -int -rl_forward_byte (count, key) - int count, key; -{ - if (count < 0) - return (rl_backward_byte (-count, key)); - - if (count > 0) - { - int end, lend; - - end = rl_point + count; -#if defined (VI_MODE) - lend = rl_end > 0 ? rl_end - (VI_COMMAND_MODE()) : rl_end; -#else - lend = rl_end; -#endif - - if (end > lend) - { - rl_point = lend; - rl_ding (); - } - else - rl_point = end; - } - - if (rl_end < 0) - rl_end = 0; - - return 0; -} - -int -_rl_forward_char_internal (count) - int count; -{ - int point; - -#if defined (HANDLE_MULTIBYTE) - point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - -#if defined (VI_MODE) - if (point >= rl_end && VI_COMMAND_MODE()) - point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO); -#endif - - if (rl_end < 0) - rl_end = 0; -#else - point = rl_point + count; - if (point > rl_end) - point = rl_end; -#endif - - return (point); -} - -#if defined (HANDLE_MULTIBYTE) -/* Move forward COUNT characters. */ -int -rl_forward_char (count, key) - int count, key; -{ - int point; - - if (MB_CUR_MAX == 1 || rl_byte_oriented) - return (rl_forward_byte (count, key)); - - if (count < 0) - return (rl_backward_char (-count, key)); - - if (count > 0) - { - if (rl_point == rl_end && EMACS_MODE()) - { - rl_ding (); - return 0; - } - - point = _rl_forward_char_internal (count); - - if (rl_point == point) - rl_ding (); - - rl_point = point; - } - - return 0; -} -#else /* !HANDLE_MULTIBYTE */ -int -rl_forward_char (count, key) - int count, key; -{ - return (rl_forward_byte (count, key)); -} -#endif /* !HANDLE_MULTIBYTE */ - -/* Backwards compatibility. */ -int -rl_forward (count, key) - int count, key; -{ - return (rl_forward_char (count, key)); -} - -/* Move backward COUNT bytes. */ -int -rl_backward_byte (count, key) - int count, key; -{ - if (count < 0) - return (rl_forward_byte (-count, key)); - - if (count > 0) - { - if (rl_point < count) - { - rl_point = 0; - rl_ding (); - } - else - rl_point -= count; - } - - if (rl_point < 0) - rl_point = 0; - - return 0; -} - -#if defined (HANDLE_MULTIBYTE) -/* Move backward COUNT characters. */ -int -rl_backward_char (count, key) - int count, key; -{ - int point; - - if (MB_CUR_MAX == 1 || rl_byte_oriented) - return (rl_backward_byte (count, key)); - - if (count < 0) - return (rl_forward_char (-count, key)); - - if (count > 0) - { - point = rl_point; - - while (count > 0 && point > 0) - { - point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO); - count--; - } - if (count > 0) - { - rl_point = 0; - rl_ding (); - } - else - rl_point = point; - } - - return 0; -} -#else -int -rl_backward_char (count, key) - int count, key; -{ - return (rl_backward_byte (count, key)); -} -#endif - -/* Backwards compatibility. */ -int -rl_backward (count, key) - int count, key; -{ - return (rl_backward_char (count, key)); -} - -/* Move to the beginning of the line. */ -int -rl_beg_of_line (count, key) - int count, key; -{ - rl_point = 0; - return 0; -} - -/* Move to the end of the line. */ -int -rl_end_of_line (count, key) - int count, key; -{ - rl_point = rl_end; - return 0; -} - -/* Move forward a word. We do what Emacs does. Handles multibyte chars. */ -int -rl_forward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - return (rl_backward_word (-count, key)); - - while (count) - { - if (rl_point == rl_end) - return 0; - - /* If we are not in a word, move forward until we are in one. - Then, move forward until we hit a non-alphabetic character. */ - c = _rl_char_value (rl_line_buffer, rl_point); - - if (_rl_walphabetic (c) == 0) - { - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - while (rl_point < rl_end) - { - c = _rl_char_value (rl_line_buffer, rl_point); - if (_rl_walphabetic (c)) - break; - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - } - } - - if (rl_point == rl_end) - return 0; - - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - while (rl_point < rl_end) - { - c = _rl_char_value (rl_line_buffer, rl_point); - if (_rl_walphabetic (c) == 0) - break; - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - } - - --count; - } - - return 0; -} - -/* Move backward a word. We do what Emacs does. Handles multibyte chars. */ -int -rl_backward_word (count, key) - int count, key; -{ - int c, p; - - if (count < 0) - return (rl_forward_word (-count, key)); - - while (count) - { - if (rl_point == 0) - return 0; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - - if (_rl_walphabetic (c) == 0) - { - rl_point = p; - while (rl_point > 0) - { - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - if (_rl_walphabetic (c)) - break; - rl_point = p; - } - } - - while (rl_point) - { - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - if (_rl_walphabetic (c) == 0) - break; - else - rl_point = p; - } - - --count; - } - - return 0; -} - -/* Clear the current line. Numeric argument to C-l does this. */ -int -rl_refresh_line (ignore1, ignore2) - int ignore1, ignore2; -{ - int curr_line; - - curr_line = _rl_current_display_line (); - - _rl_move_vert (curr_line); - _rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */ - - _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ - - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -/* C-l typed to a line without quoting clears the screen, and then reprints - the prompt and the current input line. Given a numeric arg, redraw only - the current line. */ -int -rl_clear_screen (count, key) - int count, key; -{ - if (rl_explicit_arg) - { - rl_refresh_line (count, key); - return 0; - } - - _rl_clear_screen (); /* calls termcap function to clear screen */ - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -int -rl_skip_csi_sequence (count, key) - int count, key; -{ - int ch; - - RL_SETSTATE (RL_STATE_MOREINPUT); - do - ch = rl_read_key (); - while (ch >= 0x20 && ch < 0x40); - RL_UNSETSTATE (RL_STATE_MOREINPUT); - - return 0; -} - -int -rl_arrow_keys (count, c) - int count, c; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - switch (_rl_to_upper (ch)) - { - case 'A': - rl_get_previous_history (count, ch); - break; - - case 'B': - rl_get_next_history (count, ch); - break; - - case 'C': - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_forward_char (count, ch); - else - rl_forward_byte (count, ch); - break; - - case 'D': - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_backward_char (count, ch); - else - rl_backward_byte (count, ch); - break; - - default: - rl_ding (); - } - - return 0; -} - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -#ifdef HANDLE_MULTIBYTE -static char pending_bytes[MB_LEN_MAX]; -static int pending_bytes_length = 0; -static mbstate_t ps = {0}; -#endif - -/* Insert the character C at the current location, moving point forward. - If C introduces a multibyte sequence, we read the whole sequence and - then insert the multibyte char into the line buffer. */ -int -_rl_insert_char (count, c) - int count, c; -{ - register int i; - char *string; -#ifdef HANDLE_MULTIBYTE - int string_size; - char incoming[MB_LEN_MAX + 1]; - int incoming_length = 0; - mbstate_t ps_back; - static int stored_count = 0; -#endif - - if (count <= 0) - return 0; - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - incoming[0] = c; - incoming[1] = '\0'; - incoming_length = 1; - } - else - { - wchar_t wc; - size_t ret; - - if (stored_count <= 0) - stored_count = count; - else - count = stored_count; - - ps_back = ps; - pending_bytes[pending_bytes_length++] = c; - ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps); - - if (ret == (size_t)-2) - { - /* Bytes too short to compose character, try to wait for next byte. - Restore the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - ps = ps_back; - return 1; - } - else if (ret == (size_t)-1) - { - /* Invalid byte sequence for the current locale. Treat first byte - as a single character. */ - incoming[0] = pending_bytes[0]; - incoming[1] = '\0'; - incoming_length = 1; - pending_bytes_length--; - memmove (pending_bytes, pending_bytes + 1, pending_bytes_length); - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (ret == (size_t)0) - { - incoming[0] = '\0'; - incoming_length = 0; - pending_bytes_length--; - /* Clear the state of the byte sequence, because in this case the - effect of mbstate is undefined. */ - memset (&ps, 0, sizeof (mbstate_t)); - } - else - { - /* We successfully read a single multibyte character. */ - memcpy (incoming, pending_bytes, pending_bytes_length); - incoming[pending_bytes_length] = '\0'; - incoming_length = pending_bytes_length; - pending_bytes_length = 0; - } - } -#endif /* HANDLE_MULTIBYTE */ - - /* If we can optimize, then do it. But don't let people crash - readline because of extra large arguments. */ - if (count > 1 && count <= TEXT_COUNT_MAX) - { -#if defined (HANDLE_MULTIBYTE) - string_size = count * incoming_length; - string = (char *)xmalloc (1 + string_size); - - i = 0; - while (i < string_size) - { - strncpy (string + i, incoming, incoming_length); - i += incoming_length; - } - incoming_length = 0; - stored_count = 0; -#else /* !HANDLE_MULTIBYTE */ - string = (char *)xmalloc (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; -#endif /* !HANDLE_MULTIBYTE */ - - string[i] = '\0'; - rl_insert_text (string); - xfree (string); - - return 0; - } - - if (count > TEXT_COUNT_MAX) - { - int decreaser; -#if defined (HANDLE_MULTIBYTE) - string_size = incoming_length * TEXT_COUNT_MAX; - string = (char *)xmalloc (1 + string_size); - - i = 0; - while (i < string_size) - { - strncpy (string + i, incoming, incoming_length); - i += incoming_length; - } - - while (count) - { - decreaser = (count > TEXT_COUNT_MAX) ? TEXT_COUNT_MAX : count; - string[decreaser*incoming_length] = '\0'; - rl_insert_text (string); - count -= decreaser; - } - - xfree (string); - incoming_length = 0; - stored_count = 0; -#else /* !HANDLE_MULTIBYTE */ - char str[TEXT_COUNT_MAX+1]; - - for (i = 0; i < TEXT_COUNT_MAX; i++) - str[i] = c; - - while (count) - { - decreaser = (count > TEXT_COUNT_MAX ? TEXT_COUNT_MAX : count); - str[decreaser] = '\0'; - rl_insert_text (str); - count -= decreaser; - } -#endif /* !HANDLE_MULTIBYTE */ - - return 0; - } - - if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - /* We are inserting a single character. - If there is pending input, then make a string of all of the - pending characters that are bound to rl_insert, and insert - them all. Don't do this if we're current reading input from - a macro. */ - if ((RL_ISSTATE (RL_STATE_MACROINPUT) == 0) && _rl_pushed_input_available ()) - _rl_insert_typein (c); - else - { - /* Inserting a single character. */ - char str[2]; - - str[1] = '\0'; - str[0] = c; - rl_insert_text (str); - } - } -#if defined (HANDLE_MULTIBYTE) - else - { - rl_insert_text (incoming); - stored_count = 0; - } -#endif - - return 0; -} - -/* Overwrite the character at point (or next COUNT characters) with C. - If C introduces a multibyte character sequence, read the entire sequence - before starting the overwrite loop. */ -int -_rl_overwrite_char (count, c) - int count, c; -{ - int i; -#if defined (HANDLE_MULTIBYTE) - char mbkey[MB_LEN_MAX]; - int k; - - /* Read an entire multibyte character sequence to insert COUNT times. */ - if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) - k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX); -#endif - - rl_begin_undo_group (); - - for (i = 0; i < count; i++) - { -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_insert_text (mbkey); - else -#endif - _rl_insert_char (1, c); - - if (rl_point < rl_end) - rl_delete (1, c); - } - - rl_end_undo_group (); - - return 0; -} - -int -rl_insert (count, c) - int count, c; -{ - return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c) - : _rl_overwrite_char (count, c)); -} - -/* Insert the next typed character verbatim. */ -static int -_rl_insert_next (count) - int count; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - return 1; - - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (c); - -#if defined (HANDLE_SIGNALS) - if (RL_ISSTATE (RL_STATE_CALLBACK) == 0) - _rl_restore_tty_signals (); -#endif - - return (_rl_insert_char (count, c)); -} - -#if defined (READLINE_CALLBACKS) -static int -_rl_insert_next_callback (data) - _rl_callback_generic_arg *data; -{ - int count; - - count = data->count; - - /* Deregister function, let rl_callback_read_char deallocate data */ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return _rl_insert_next (count); -} -#endif - -int -rl_quoted_insert (count, key) - int count, key; -{ - /* Let's see...should the callback interface futz with signal handling? */ -#if defined (HANDLE_SIGNALS) - if (RL_ISSTATE (RL_STATE_CALLBACK) == 0) - _rl_disable_tty_signals (); -#endif - -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_func = _rl_insert_next_callback; - return (0); - } -#endif - - return _rl_insert_next (count); -} - -/* Insert a tab character. */ -int -rl_tab_insert (count, key) - int count, key; -{ - return (_rl_insert_char (count, '\t')); -} - -/* What to do when a NEWLINE is pressed. We accept the whole line. - KEY is the key that invoked this command. I guess it could have - meaning in the future. */ -int -rl_newline (count, key) - int count, key; -{ - rl_done = 1; - - if (_rl_history_preserve_point) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - RL_SETSTATE(RL_STATE_DONE); - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - { - _rl_vi_done_inserting (); - if (_rl_vi_textmod_command (_rl_vi_last_command) == 0) /* XXX */ - _rl_vi_reset_last (); - } -#endif /* VI_MODE */ - - /* If we've been asked to erase empty lines, suppress the final update, - since _rl_update_final calls rl_crlf(). */ - if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) - return 0; - - if (_rl_echoing_p) - _rl_update_final (); - return 0; -} - -/* What to do for some uppercase characters, like meta characters, - and some characters appearing in emacs_ctlx_keymap. This function - is just a stub, you bind keys to it and the code in _rl_dispatch () - is special cased. */ -int -rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; -{ - return 0; -} - -/* This is different from what vi does, so the code's not shared. Emacs - rubout in overwrite mode has one oddity: it replaces a control - character that's displayed as two characters (^X) with two spaces. */ -int -_rl_overwrite_rubout (count, key) - int count, key; -{ - int opoint; - int i, l; - - if (rl_point == 0) - { - rl_ding (); - return 1; - } - - opoint = rl_point; - - /* L == number of spaces to insert */ - for (i = l = 0; i < count; i++) - { - rl_backward_char (1, key); - l += rl_character_len (rl_line_buffer[rl_point], rl_point); /* not exactly right */ - } - - rl_begin_undo_group (); - - if (count > 1 || rl_explicit_arg) - rl_kill_text (opoint, rl_point); - else - rl_delete_text (opoint, rl_point); - - /* Emacs puts point at the beginning of the sequence of spaces. */ - if (rl_point < rl_end) - { - opoint = rl_point; - _rl_insert_char (l, ' '); - rl_point = opoint; - } - - rl_end_undo_group (); - - return 0; -} - -/* Rubout the character behind point. */ -int -rl_rubout (count, key) - int count, key; -{ - if (count < 0) - return (rl_delete (-count, key)); - - if (!rl_point) - { - rl_ding (); - return 1; - } - - if (rl_insert_mode == RL_IM_OVERWRITE) - return (_rl_overwrite_rubout (count, key)); - - return (_rl_rubout_char (count, key)); -} - -int -_rl_rubout_char (count, key) - int count, key; -{ - int orig_point; - unsigned char c; - - /* Duplicated code because this is called from other parts of the library. */ - if (count < 0) - return (rl_delete (-count, key)); - - if (rl_point == 0) - { - rl_ding (); - return 1; - } - - orig_point = rl_point; - if (count > 1 || rl_explicit_arg) - { - rl_backward_char (count, key); - rl_kill_text (orig_point, rl_point); - } - else if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - c = rl_line_buffer[--rl_point]; - rl_delete_text (rl_point, orig_point); - /* The erase-at-end-of-line hack is of questionable merit now. */ - if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos) - { - int l; - l = rl_character_len (c, rl_point); - _rl_erase_at_end_of_line (l); - } - } - else - { - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - rl_delete_text (rl_point, orig_point); - } - - return 0; -} - -/* Delete the character under the cursor. Given a numeric argument, - kill that many characters instead. */ -int -rl_delete (count, key) - int count, key; -{ - int xpoint; - - if (count < 0) - return (_rl_rubout_char (-count, key)); - - if (rl_point == rl_end) - { - rl_ding (); - return 1; - } - - if (count > 1 || rl_explicit_arg) - { - xpoint = rl_point; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_forward_char (count, key); - else - rl_forward_byte (count, key); - - rl_kill_text (xpoint, rl_point); - rl_point = xpoint; - } - else - { - xpoint = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - rl_delete_text (rl_point, xpoint); - } - return 0; -} - -/* Delete the character under the cursor, unless the insertion - point is at the end of the line, in which case the character - behind the cursor is deleted. COUNT is obeyed and may be used - to delete forward or backward that many characters. */ -int -rl_rubout_or_delete (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (_rl_rubout_char (count, key)); - else - return (rl_delete (count, key)); -} - -/* Delete all spaces and tabs around point. */ -int -rl_delete_horizontal_space (count, ignore) - int count, ignore; -{ - int start; - - while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) - rl_point--; - - start = rl_point; - - while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) - rl_point++; - - if (start != rl_point) - { - rl_delete_text (start, rl_point); - rl_point = start; - } - - if (rl_point < 0) - rl_point = 0; - - return 0; -} - -/* Like the tcsh editing function delete-char-or-list. The eof character - is caught before this is invoked, so this really does the same thing as - delete-char-or-list-or-eof, as long as it's bound to the eof character. */ -int -rl_delete_or_show_completions (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_possible_completions (count, key)); - else - return (rl_delete (count, key)); -} - -#ifndef RL_COMMENT_BEGIN_DEFAULT -#define RL_COMMENT_BEGIN_DEFAULT "#" -#endif - -/* Turn the current line into a comment in shell history. - A K*rn shell style function. */ -int -rl_insert_comment (count, key) - int count, key; -{ - char *rl_comment_text; - int rl_comment_len; - - rl_beg_of_line (1, key); - rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT; - - if (rl_explicit_arg == 0) - rl_insert_text (rl_comment_text); - else - { - rl_comment_len = strlen (rl_comment_text); - if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len)) - rl_delete_text (rl_point, rl_point + rl_comment_len); - else - rl_insert_text (rl_comment_text); - } - - (*rl_redisplay_function) (); - rl_newline (1, '\n'); - - return (0); -} - -/* **************************************************************** */ -/* */ -/* Changing Case */ -/* */ -/* **************************************************************** */ - -/* The three kinds of things that we know how to do. */ -#define UpCase 1 -#define DownCase 2 -#define CapCase 3 - -/* Uppercase the word at point. */ -int -rl_upcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, UpCase)); -} - -/* Lowercase the word at point. */ -int -rl_downcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, DownCase)); -} - -/* Upcase the first letter, downcase the rest. */ -int -rl_capitalize_word (count, key) - int count, key; -{ - return (rl_change_case (count, CapCase)); -} - -/* The meaty function. - Change the case of COUNT words, performing OP on them. - OP is one of UpCase, DownCase, or CapCase. - If a negative argument is given, leave point where it started, - otherwise, leave it where it moves to. */ -static int -rl_change_case (count, op) - int count, op; -{ - int start, next, end; - int inword, c, nc, nop; -#if defined (HANDLE_MULTIBYTE) - wchar_t wc, nwc; - char mb[MB_LEN_MAX+1]; - int mlen; - size_t m; - mbstate_t mps; -#endif - - start = rl_point; - rl_forward_word (count, 0); - end = rl_point; - - if (op != UpCase && op != DownCase && op != CapCase) - { - rl_ding (); - return 1; - } - - if (count < 0) - SWAP (start, end); - -#if defined (HANDLE_MULTIBYTE) - memset (&mps, 0, sizeof (mbstate_t)); -#endif - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - inword = 0; - while (start < end) - { - c = _rl_char_value (rl_line_buffer, start); - /* This assumes that the upper and lower case versions are the same width. */ - next = MB_NEXTCHAR (rl_line_buffer, start, 1, MB_FIND_NONZERO); - - if (_rl_walphabetic (c) == 0) - { - inword = 0; - start = next; - continue; - } - - if (op == CapCase) - { - nop = inword ? DownCase : UpCase; - inword = 1; - } - else - nop = op; - if (MB_CUR_MAX == 1 || rl_byte_oriented || isascii ((unsigned char)c)) - { - nc = (nop == UpCase) ? _rl_to_upper (c) : _rl_to_lower (c); - rl_line_buffer[start] = nc; - } -#if defined (HANDLE_MULTIBYTE) - else - { - m = mbrtowc (&wc, rl_line_buffer + start, end - start, &mps); - if (MB_INVALIDCH (m)) - wc = (wchar_t)rl_line_buffer[start]; - else if (MB_NULLWCH (m)) - wc = L'\0'; - nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc); - if (nwc != wc) /* just skip unchanged characters */ - { - mlen = wcrtomb (mb, nwc, &mps); - if (mlen > 0) - mb[mlen] = '\0'; - /* Assume the same width */ - strncpy (rl_line_buffer + start, mb, mlen); - } - } -#endif - - start = next; - } - - rl_point = end; - return 0; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. If point is at the end of the line, - transpose the two words before point. */ -int -rl_transpose_words (count, key) - int count, key; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) - return 0; - - /* Find the two words. */ - rl_forward_word (count, key); - w2_end = rl_point; - rl_backward_word (1, key); - w2_beg = rl_point; - rl_backward_word (count, key); - w1_beg = rl_point; - rl_forward_word (1, key); - w1_end = rl_point; - - /* Do some check to make sure that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - rl_ding (); - rl_point = orig_point; - return 1; - } - - /* Get the text of the words. */ - word1 = rl_copy_text (w1_beg, w1_end); - word2 = rl_copy_text (w2_beg, w2_end); - - /* We are about to do many insertions and deletions. Remember them - as one operation. */ - rl_begin_undo_group (); - - /* Do the stuff at word2 first, so that we don't have to worry - about word1 moving. */ - rl_point = w2_beg; - rl_delete_text (w2_beg, w2_end); - rl_insert_text (word1); - - rl_point = w1_beg; - rl_delete_text (w1_beg, w1_end); - rl_insert_text (word2); - - /* This is exactly correct since the text before this point has not - changed in length. */ - rl_point = w2_end; - - /* I think that does it. */ - rl_end_undo_group (); - xfree (word1); - xfree (word2); - - return 0; -} - -/* Transpose the characters at point. If point is at the end of the line, - then transpose the characters before point. */ -int -rl_transpose_chars (count, key) - int count, key; -{ -#if defined (HANDLE_MULTIBYTE) - char *dummy; - int i; -#else - char dummy[2]; -#endif - int char_length, prev_point; - - if (count == 0) - return 0; - - if (!rl_point || rl_end < 2) - { - rl_ding (); - return 1; - } - - rl_begin_undo_group (); - - if (rl_point == rl_end) - { - rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - count = 1; - } - - prev_point = rl_point; - rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - -#if defined (HANDLE_MULTIBYTE) - char_length = prev_point - rl_point; - dummy = (char *)xmalloc (char_length + 1); - for (i = 0; i < char_length; i++) - dummy[i] = rl_line_buffer[rl_point + i]; - dummy[i] = '\0'; -#else - dummy[0] = rl_line_buffer[rl_point]; - dummy[char_length = 1] = '\0'; -#endif - - rl_delete_text (rl_point, rl_point + char_length); - - rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - - _rl_fix_point (0); - rl_insert_text (dummy); - rl_end_undo_group (); - -#if defined (HANDLE_MULTIBYTE) - xfree (dummy); -#endif - - return 0; -} - -/* **************************************************************** */ -/* */ -/* Character Searching */ -/* */ -/* **************************************************************** */ - -int -#if defined (HANDLE_MULTIBYTE) -_rl_char_search_internal (count, dir, smbchar, len) - int count, dir; - char *smbchar; - int len; -#else -_rl_char_search_internal (count, dir, schar) - int count, dir, schar; -#endif -{ - int pos, inc; -#if defined (HANDLE_MULTIBYTE) - int prepos; -#endif - - if (dir == 0) - return 1; - - pos = rl_point; - inc = (dir < 0) ? -1 : 1; - while (count) - { - if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) - { - rl_ding (); - return 1; - } - -#if defined (HANDLE_MULTIBYTE) - pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) - : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); -#else - pos += inc; -#endif - do - { -#if defined (HANDLE_MULTIBYTE) - if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len)) -#else - if (rl_line_buffer[pos] == schar) -#endif - { - count--; - if (dir < 0) - rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) - : pos; - else - rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY) - : pos; - break; - } -#if defined (HANDLE_MULTIBYTE) - prepos = pos; -#endif - } -#if defined (HANDLE_MULTIBYTE) - while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos - : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos); -#else - while ((dir < 0) ? pos-- : ++pos < rl_end); -#endif - } - return (0); -} - -/* Search COUNT times for a character read from the current input stream. - FDIR is the direction to search if COUNT is non-negative; otherwise - the search goes in BDIR. So much is dependent on HANDLE_MULTIBYTE - that there are two separate versions of this function. */ -#if defined (HANDLE_MULTIBYTE) -static int -_rl_char_search (count, fdir, bdir) - int count, fdir, bdir; -{ - char mbchar[MB_LEN_MAX]; - int mb_len; - - mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX); - - if (mb_len <= 0) - return 1; - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, mbchar, mb_len)); - else - return (_rl_char_search_internal (count, fdir, mbchar, mb_len)); -} -#else /* !HANDLE_MULTIBYTE */ -static int -_rl_char_search (count, fdir, bdir) - int count, fdir, bdir; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - return 1; - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, c)); - else - return (_rl_char_search_internal (count, fdir, c)); -} -#endif /* !HANDLE_MULTIBYTE */ - -#if defined (READLINE_CALLBACKS) -static int -_rl_char_search_callback (data) - _rl_callback_generic_arg *data; -{ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return (_rl_char_search (data->count, data->i1, data->i2)); -} -#endif - -int -rl_char_search (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_data->i1 = FFIND; - _rl_callback_data->i2 = BFIND; - _rl_callback_func = _rl_char_search_callback; - return (0); - } -#endif - - return (_rl_char_search (count, FFIND, BFIND)); -} - -int -rl_backward_char_search (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_data->i1 = BFIND; - _rl_callback_data->i2 = FFIND; - _rl_callback_func = _rl_char_search_callback; - return (0); - } -#endif - - return (_rl_char_search (count, BFIND, FFIND)); -} - -/* **************************************************************** */ -/* */ -/* The Mark and the Region. */ -/* */ -/* **************************************************************** */ - -/* Set the mark at POSITION. */ -int -_rl_set_mark_at_pos (position) - int position; -{ - if (position > rl_end) - return 1; - - rl_mark = position; - return 0; -} - -/* A bindable command to set the mark. */ -int -rl_set_mark (count, key) - int count, key; -{ - return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); -} - -/* Exchange the position of mark and point. */ -int -rl_exchange_point_and_mark (count, key) - int count, key; -{ - if (rl_mark > rl_end) - rl_mark = -1; - - if (rl_mark == -1) - { - rl_ding (); - return 1; - } - else - SWAP (rl_point, rl_mark); - - return 0; -} diff --git a/lib/readline/vi_mode.c~ b/lib/readline/vi_mode.c~ deleted file mode 100644 index 0802aaa36..000000000 --- a/lib/readline/vi_mode.c~ +++ /dev/null @@ -1,2217 +0,0 @@ -/* 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/lib/sh/casemod.c~ b/lib/sh/casemod.c~ deleted file mode 100644 index 183864199..000000000 --- a/lib/sh/casemod.c~ +++ /dev/null @@ -1,270 +0,0 @@ -/* casemod.c -- functions to change case of strings */ - -/* Copyright (C) 2008,2009,2015 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define _to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc)) -#define _to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc)) - -#if !defined (HANDLE_MULTIBYTE) -# define cval(s, i) ((s)[(i)]) -# define iswalnum(c) (isalnum(c)) -# define TOGGLE(x) (ISUPPER (x) ? tolower ((unsigned char)x) : (TOUPPER (x))) -#else -# define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x))) -#endif - -/* These must agree with the defines in externs.h */ -#define CASE_NOOP 0x0000 -#define CASE_LOWER 0x0001 -#define CASE_UPPER 0x0002 -#define CASE_CAPITALIZE 0x0004 -#define CASE_UNCAP 0x0008 -#define CASE_TOGGLE 0x0010 -#define CASE_TOGGLEALL 0x0020 -#define CASE_UPFIRST 0x0040 -#define CASE_LOWFIRST 0x0080 - -#define CASE_USEWORDS 0x1000 /* modify behavior to act on words in passed string */ - -extern char *substring __P((char *, int, int)); - -#ifndef UCHAR_MAX -# define UCHAR_MAX TYPE_MAXIMUM(unsigned char) -#endif - -#if defined (HANDLE_MULTIBYTE) -static wchar_t -cval (s, i) - char *s; - int i; -{ - size_t tmp; - wchar_t wc; - int l; - mbstate_t mps; - - if (MB_CUR_MAX == 1 || is_basic (s[i])) - return ((wchar_t)s[i]); - l = strlen (s); - if (i >= (l - 1)) - return ((wchar_t)s[i]); - memset (&mps, 0, sizeof (mbstate_t)); - tmp = mbrtowc (&wc, s + i, l - i, &mps); - if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp)) - return ((wchar_t)s[i]); - return wc; -} -#endif - -/* Modify the case of characters in STRING matching PAT based on the value of - FLAGS. If PAT is null, modify the case of each character */ -char * -sh_modcase (string, pat, flags) - const char *string; - char *pat; - int flags; -{ - int start, next, end, retind; - int inword, c, nc, nop, match, usewords; - char *ret, *s; - wchar_t wc; -#if defined (HANDLE_MULTIBYTE) - wchar_t nwc; - char mb[MB_LEN_MAX+1]; - int mlen; - size_t m; - mbstate_t state; -#endif - - if (string == 0 || *string == 0) - { - ret = (char *)xmalloc (1); - ret[0] = '\0'; - return ret; - } - -#if defined (HANDLE_MULTIBYTE) - memset (&state, 0, sizeof (mbstate_t)); -#endif - - start = 0; - end = strlen (string); - - ret = (char *)xmalloc (2*end + 1); - retind = 0; - - /* See if we are supposed to split on alphanumerics and operate on each word */ - usewords = (flags & CASE_USEWORDS); - flags &= ~CASE_USEWORDS; - - inword = 0; - while (start < end) - { - wc = cval (string, start); - - if (iswalnum (wc) == 0) - inword = 0; - - if (pat) - { - next = start; - ADVANCE_CHAR (string, end, next); - s = substring (string, start, next); - match = strmatch (pat, s, FNM_EXTMATCH) != FNM_NOMATCH; - free (s); - if (match == 0) - { - /* copy unmatched portion */ - memcpy (ret + retind, string + start, next - start); - retind += next - start; - start = next; - inword = 1; - continue; - } - } - - /* XXX - for now, the toggling operators work on the individual - words in the string, breaking on alphanumerics. Should I - leave the capitalization operators to do that also? */ - if (flags == CASE_CAPITALIZE) - { - if (usewords) - nop = inword ? CASE_LOWER : CASE_UPPER; - else - nop = (start > 0) ? CASE_LOWER : CASE_UPPER; - inword = 1; - } - else if (flags == CASE_UNCAP) - { - if (usewords) - nop = inword ? CASE_UPPER : CASE_LOWER; - else - nop = (start > 0) ? CASE_UPPER : CASE_LOWER; - inword = 1; - } - else if (flags == CASE_UPFIRST) - { - if (usewords) - nop = inword ? CASE_NOOP : CASE_UPPER; - else - nop = (start > 0) ? CASE_NOOP : CASE_UPPER; - inword = 1; - } - else if (flags == CASE_LOWFIRST) - { - if (usewords) - nop = inword ? CASE_NOOP : CASE_LOWER; - else - nop = (start > 0) ? CASE_NOOP : CASE_LOWER; - inword = 1; - } - else if (flags == CASE_TOGGLE) - { - nop = inword ? CASE_NOOP : CASE_TOGGLE; - inword = 1; - } - else - nop = flags; - - /* Can't short-circuit, some locales have multibyte upper and lower - case equivalents of single-byte ascii characters (e.g., Turkish) */ - if (MB_CUR_MAX == 1) - { -singlebyte: - switch (nop) - { - default: - case CASE_NOOP: nc = wc; break; - case CASE_UPPER: nc = TOUPPER (wc); break; - case CASE_LOWER: nc = TOLOWER (wc); break; - case CASE_TOGGLEALL: - case CASE_TOGGLE: nc = TOGGLE (wc); break; - } - ret[retind++] = nc; - } -#if defined (HANDLE_MULTIBYTE) - else - { - m = mbrtowc (&wc, string + start, end - start, &state); -if (m == 1) - itrace("sh_modcase: mbrtowc returns 1 for single byte char"); - if (MB_INVALIDCH (m) || m == 1) - { - wc = (unsigned char)string[start]; - goto singlebyte; - } - else if (MB_NULLWCH (m)) - wc = L'\0'; - switch (nop) - { - default: - case CASE_NOOP: nwc = wc; break; - case CASE_UPPER: nwc = _to_wupper (wc); break; - case CASE_LOWER: nwc = _to_wlower (wc); break; - case CASE_TOGGLEALL: - case CASE_TOGGLE: nwc = TOGGLE (wc); break; - } - - /* We don't have to convert `wide' characters that are in the - unsigned char range back to single-byte `multibyte' characters. */ - if ((int)nwc <= UCHAR_MAX && is_basic ((int)nwc)) - ret[retind++] = nwc; - else - { - mlen = wcrtomb (mb, nwc, &state); - if (mlen > 0) - mb[mlen] = '\0'; - /* Don't assume the same width */ - strncpy (ret + retind, mb, mlen); - retind += mlen; - } - } -#endif - - ADVANCE_CHAR (string, end, start); - } - - ret[retind] = '\0'; - return ret; -} diff --git a/locale.c~ b/locale.c~ deleted file mode 100644 index 8dabc7d2c..000000000 --- a/locale.c~ +++ /dev/null @@ -1,563 +0,0 @@ -/* locale.c - Miscellaneous internationalization functions. */ - -/* Copyright (C) 1996-2009,2012 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if HAVE_LANGINFO_CODESET -# include -#endif - -#include "bashintl.h" -#include "bashansi.h" -#include -#include "chartypes.h" -#include - -#include "shell.h" -#include "input.h" /* For bash_input */ - -#ifndef errno -extern int errno; -#endif - -int locale_utf8locale; /* unused for now */ -int locale_mb_cur_max; /* value of MB_CUR_MAX for current locale (LC_CTYPE) */ - -extern int dump_translatable_strings, dump_po_strings; - -/* The current locale when the program begins */ -static char *default_locale; - -/* The current domain for textdomain(3). */ -static char *default_domain; -static char *default_dir; - -/* tracks the value of LC_ALL; used to override values for other locale - categories */ -static char *lc_all; - -/* tracks the value of LC_ALL; used to provide defaults for locale - categories */ -static char *lang; - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. */ -static int reset_locale_vars __P((void)); - -static void locale_setblanks __P((void)); -static int locale_isutf8 __P((char *)); - -/* Set the value of default_locale and make the current locale the - system default locale. This should be called very early in main(). */ -void -set_default_locale () -{ -#if defined (HAVE_SETLOCALE) - default_locale = setlocale (LC_ALL, ""); - if (default_locale) - default_locale = savestring (default_locale); -#endif /* HAVE_SETLOCALE */ - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - locale_mb_cur_max = MB_CUR_MAX; -} - -/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and - LC_TIME if they are not specified in the environment, but LC_ALL is. This - should be called from main() after parsing the environment. */ -void -set_default_locale_vars () -{ - char *val; - -#if defined (HAVE_SETLOCALE) - -# if defined (LC_CTYPE) - val = get_string_value ("LC_CTYPE"); - if (val == 0 && lc_all && *lc_all) - { - setlocale (LC_CTYPE, lc_all); - locale_setblanks (); - locale_mb_cur_max = MB_CUR_MAX; - u32reset (); - } -# endif - -# if defined (LC_COLLATE) - val = get_string_value ("LC_COLLATE"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_COLLATE, lc_all); -# endif /* LC_COLLATE */ - -# if defined (LC_MESSAGES) - val = get_string_value ("LC_MESSAGES"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_MESSAGES, lc_all); -# endif /* LC_MESSAGES */ - -# if defined (LC_NUMERIC) - val = get_string_value ("LC_NUMERIC"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_NUMERIC, lc_all); -# endif /* LC_NUMERIC */ - -# if defined (LC_TIME) - val = get_string_value ("LC_TIME"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_TIME, lc_all); -# endif /* LC_TIME */ - -#endif /* HAVE_SETLOCALE */ - - val = get_string_value ("TEXTDOMAIN"); - if (val && *val) - { - FREE (default_domain); - default_domain = savestring (val); - if (default_dir && *default_dir) - bindtextdomain (default_domain, default_dir); - } - - val = get_string_value ("TEXTDOMAINDIR"); - if (val && *val) - { - FREE (default_dir); - default_dir = savestring (val); - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - } -} - -/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1 - if successful, 0 otherwise. */ -int -set_locale_var (var, value) - char *var, *value; -{ - int r; - char *x; - - x = ""; - errno = 0; - if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */ - { - FREE (default_domain); - default_domain = value ? savestring (value) : (char *)NULL; - if (default_dir && *default_dir) - bindtextdomain (default_domain, default_dir); - return (1); - } - else if (var[0] == 'T') /* TEXTDOMAINDIR */ - { - FREE (default_dir); - default_dir = value ? savestring (value) : (char *)NULL; - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - return (1); - } - - /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */ - - else if (var[3] == 'A') /* LC_ALL */ - { - FREE (lc_all); - if (value) - lc_all = savestring (value); - else - { - lc_all = (char *)xmalloc (1); - lc_all[0] = '\0'; - } -#if defined (HAVE_SETLOCALE) - r = *lc_all ? ((x = setlocale (LC_ALL, lc_all)) != 0) : reset_locale_vars (); - if (x == 0) - { - if (errno == 0) - internal_warning(_("setlocale: LC_ALL: cannot change locale (%s)"), lc_all); - else - internal_warning(_("setlocale: LC_ALL: cannot change locale (%s): %s"), lc_all, strerror (errno)); - } - locale_setblanks (); - locale_mb_cur_max = MB_CUR_MAX; - u32reset (); - return r; -#else - return (1); -#endif - } - -#if defined (HAVE_SETLOCALE) - else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */ - { -# if defined (LC_CTYPE) - if (lc_all == 0 || *lc_all == '\0') - { - x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); - locale_setblanks (); - locale_mb_cur_max = MB_CUR_MAX; - u32reset (); - } -# endif - } - else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */ - { -# if defined (LC_COLLATE) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); -# endif /* LC_COLLATE */ - } - else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */ - { -# if defined (LC_MESSAGES) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); -# endif /* LC_MESSAGES */ - } - else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */ - { -# if defined (LC_NUMERIC) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); -# endif /* LC_NUMERIC */ - } - else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */ - { -# if defined (LC_TIME) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_TIME, get_locale_var ("LC_TIME")); -# endif /* LC_TIME */ - } -#endif /* HAVE_SETLOCALE */ - - if (x == 0) - { - if (errno == 0) - internal_warning(_("setlocale: %s: cannot change locale (%s)"), var, get_locale_var (var)); - else - internal_warning(_("setlocale: %s: cannot change locale (%s): %s"), var, get_locale_var (var), strerror (errno)); - } - - return (x != 0); -} - -/* Called when LANG is assigned a value. Tracks value in `lang'. Calls - reset_locale_vars() to reset any default values if LC_ALL is unset or - null. */ -int -set_lang (var, value) - char *var, *value; -{ - FREE (lang); - if (value) - lang = savestring (value); - else - { - lang = (char *)xmalloc (1); - lang[0] = '\0'; - } - - return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0); -} - -/* Set default values for LANG and LC_ALL. Default values for all other - locale-related variables depend on these. */ -void -set_default_lang () -{ - char *v; - - v = get_string_value ("LC_ALL"); - set_locale_var ("LC_ALL", v); - - v = get_string_value ("LANG"); - set_lang ("LANG", v); -} - -/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE). - The precedence is as POSIX.2 specifies: LC_ALL has precedence over - the specific locale variables, and LANG, if set, is used as the default. */ -char * -get_locale_var (var) - char *var; -{ - char *locale; - - locale = lc_all; - - if (locale == 0 || *locale == 0) - locale = get_string_value (var); /* XXX - mem leak? */ - if (locale == 0 || *locale == 0) - locale = lang; - if (locale == 0 || *locale == 0) -#if 0 - locale = default_locale; /* system-dependent; not really portable. should it be "C"? */ -#else - locale = ""; -#endif - return (locale); -} - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS - IF LC_ALL HAS BEEN ASSIGNED A VALUE. */ -static int -reset_locale_vars () -{ - char *t; -#if defined (HAVE_SETLOCALE) - if (lang == 0 || *lang == '\0') - maybe_make_export_env (); /* trust that this will change environment for setlocale */ - if (setlocale (LC_ALL, lang ? lang : "") == 0) - return 0; - -# if defined (LC_CTYPE) - t = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); -# endif -# if defined (LC_COLLATE) - t = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); -# endif -# if defined (LC_MESSAGES) - t = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); -# endif -# if defined (LC_NUMERIC) - t = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); -# endif -# if defined (LC_TIME) - t = setlocale (LC_TIME, get_locale_var ("LC_TIME")); -# endif - - locale_setblanks (); - locale_mb_cur_max = MB_CUR_MAX; - u32reset (); - -#endif - return 1; -} - -/* Translate the contents of STRING, a $"..." quoted string, according - to the current locale. In the `C' or `POSIX' locale, or if gettext() - is not available, the passed string is returned unchanged. The - length of the translated string is returned in LENP, if non-null. */ -char * -localetrans (string, len, lenp) - char *string; - int len, *lenp; -{ - char *locale, *t; - char *translated; - int tlen; - - /* Don't try to translate null strings. */ - if (string == 0 || *string == 0) - { - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - locale = get_locale_var ("LC_MESSAGES"); - - /* If we don't have setlocale() or the current locale is `C' or `POSIX', - just return the string. If we don't have gettext(), there's no use - doing anything else. */ - if (locale == 0 || locale[0] == '\0' || - (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX")) - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - return (t); - } - - /* Now try to translate it. */ - if (default_domain && *default_domain) - translated = dgettext (default_domain, string); - else - translated = string; - - if (translated == string) /* gettext returns its argument if untranslatable */ - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - } - else - { - tlen = strlen (translated); - t = (char *)xmalloc (tlen + 1); - strcpy (t, translated); - if (lenp) - *lenp = tlen; - } - return (t); -} - -/* Change a bash string into a string suitable for inclusion in a `po' file. - This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */ -char * -mk_msgstr (string, foundnlp) - char *string; - int *foundnlp; -{ - register int c, len; - char *result, *r, *s; - - for (len = 0, s = string; s && *s; s++) - { - len++; - if (*s == '"' || *s == '\\') - len++; - else if (*s == '\n') - len += 5; - } - - r = result = (char *)xmalloc (len + 3); - *r++ = '"'; - - for (s = string; s && (c = *s); s++) - { - if (c == '\n') /* -> \n"" */ - { - *r++ = '\\'; - *r++ = 'n'; - *r++ = '"'; - *r++ = '\n'; - *r++ = '"'; - if (foundnlp) - *foundnlp = 1; - continue; - } - if (c == '"' || c == '\\') - *r++ = '\\'; - *r++ = c; - } - - *r++ = '"'; - *r++ = '\0'; - - return result; -} - -/* $"..." -- Translate the portion of STRING between START and END - according to current locale using gettext (if available) and return - the result. The caller will take care of leaving the quotes intact. - The string will be left without the leading `$' by the caller. - If translation is performed, the translated string will be double-quoted - by the caller. The length of the translated string is returned in LENP, - if non-null. */ -char * -localeexpand (string, start, end, lineno, lenp) - char *string; - int start, end, lineno, *lenp; -{ - int len, tlen, foundnl; - char *temp, *t, *t2; - - temp = (char *)xmalloc (end - start + 1); - for (tlen = 0, len = start; len < end; ) - temp[tlen++] = string[len++]; - temp[tlen] = '\0'; - - /* If we're just dumping translatable strings, don't do anything with the - string itself, but if we're dumping in `po' file format, convert it into - a form more palatable to gettext(3) and friends by quoting `"' and `\' - with backslashes and converting into `\n""'. If we find a - newline in TEMP, we first output a `msgid ""' line and then the - translated string; otherwise we output the `msgid' and translated - string all on one line. */ - if (dump_translatable_strings) - { - if (dump_po_strings) - { - foundnl = 0; - t = mk_msgstr (temp, &foundnl); - t2 = foundnl ? "\"\"\n" : ""; - - printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n", - yy_input_name (), lineno, t2, t); - free (t); - } - else - printf ("\"%s\"\n", temp); - - if (lenp) - *lenp = tlen; - return (temp); - } - else if (*temp) - { - t = localetrans (temp, tlen, &len); - free (temp); - if (lenp) - *lenp = len; - return (t); - } - else - { - if (lenp) - *lenp = 0; - return (temp); - } -} - -/* Set every character in the character class to be a shell break - character for the lexical analyzer when the locale changes. */ -static void -locale_setblanks () -{ - int x; - - for (x = 0; x < sh_syntabsiz; x++) - { - if (isblank (x)) - sh_syntaxtab[x] |= CSHBRK|CBLANK; - else if (member (x, shell_break_chars)) - { - sh_syntaxtab[x] |= CSHBRK; - sh_syntaxtab[x] &= ~CBLANK; - } - else - sh_syntaxtab[x] &= ~(CSHBRK|CBLANK); - } -} - -static int -locale_isutf8 (lspec) - char *lspec; -{ - char *cp; - -#if HAVE_LANGINFO_CODESET - cp = nl_langinfo (CODESET); - return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8")); -#else - /* Take a shot */ - return (strstr (lspec, "UTF-8") || strstr (lspec, "utf8")); -#endif -} diff --git a/pcomplete.c~ b/pcomplete.c~ deleted file mode 100644 index 85d3cc50a..000000000 --- a/pcomplete.c~ +++ /dev/null @@ -1,1667 +0,0 @@ -/* 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~ deleted file mode 100644 index 67f6393f8..000000000 --- a/pcomplete.h~ +++ /dev/null @@ -1,164 +0,0 @@ -/* 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/shell.c~ b/shell.c~ deleted file mode 100644 index 4883dcf84..000000000 --- a/shell.c~ +++ /dev/null @@ -1,1925 +0,0 @@ -/* shell.c -- GNU's idea of the POSIX shell specification. */ - -/* Copyright (C) 1987-2012 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* - Birthdate: - Sunday, January 10th, 1988. - Initial author: Brian Fox -*/ -#define INSTALL_DEBUG_MODE - -#include "config.h" - -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#include "posixtime.h" -#include "bashansi.h" -#include -#include -#include -#include "filecntl.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" - -#define NEED_SH_SETLINEBUF_DECL /* used in externs.h */ - -#include "shell.h" -#include "flags.h" -#include "trap.h" -#include "mailcheck.h" -#include "builtins.h" -#include "builtins/common.h" - -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif /* JOB_CONTROL */ - -#include "input.h" -#include "execute_cmd.h" -#include "findcmd.h" - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include -#endif - -#if defined (READLINE) -# include -# include "bashline.h" -#endif - -#include -#include - -#if defined (__OPENNT) -# include -#endif - -#if !defined (HAVE_GETPW_DECLS) -extern struct passwd *getpwuid (); -#endif /* !HAVE_GETPW_DECLS */ - -#if !defined (errno) -extern int errno; -#endif - -#if defined (NO_MAIN_ENV_ARG) -extern char **environ; /* used if no third argument to main() */ -#endif - -extern char *dist_version, *release_status; -extern int patch_level, build_version; -extern int shell_level; -extern int subshell_environment; -extern int running_in_background; -extern int last_command_exit_value; -extern int line_number; -extern int expand_aliases; -extern int array_needs_making; -extern int gnu_error_format; -extern char *primary_prompt, *secondary_prompt; -extern char *this_command_name; - -/* Non-zero means that this shell has already been run; i.e. you should - call shell_reinitialize () if you need to start afresh. */ -int shell_initialized = 0; - -COMMAND *global_command = (COMMAND *)NULL; - -/* Information about the current user. */ -struct user_info current_user = -{ - (uid_t)-1, (uid_t)-1, (gid_t)-1, (gid_t)-1, - (char *)NULL, (char *)NULL, (char *)NULL -}; - -/* The current host's name. */ -char *current_host_name = (char *)NULL; - -/* Non-zero means that this shell is a login shell. - Specifically: - 0 = not login shell. - 1 = login shell from getty (or equivalent fake out) - -1 = login shell from "--login" (or -l) flag. - -2 = both from getty, and from flag. - */ -int login_shell = 0; - -/* Non-zero means that at this moment, the shell is interactive. In - general, this means that the shell is at this moment reading input - from the keyboard. */ -int interactive = 0; - -/* Non-zero means that the shell was started as an interactive shell. */ -int interactive_shell = 0; - -/* Non-zero means to send a SIGHUP to all jobs when an interactive login - shell exits. */ -int hup_on_exit = 0; - -/* Non-zero means to list status of running and stopped jobs at shell exit */ -int check_jobs_at_exit = 0; - -/* Non-zero means to change to a directory name supplied as a command name */ -int autocd = 0; - -/* Tells what state the shell was in when it started: - 0 = non-interactive shell script - 1 = interactive - 2 = -c command - 3 = wordexp evaluation - This is a superset of the information provided by interactive_shell. -*/ -int startup_state = 0; - -/* Special debugging helper. */ -int debugging_login_shell = 0; - -/* The environment that the shell passes to other commands. */ -char **shell_environment; - -/* Non-zero when we are executing a top-level command. */ -int executing = 0; - -/* The number of commands executed so far. */ -int current_command_number = 1; - -/* Non-zero is the recursion depth for commands. */ -int indirection_level = 0; - -/* The name of this shell, as taken from argv[0]. */ -char *shell_name = (char *)NULL; - -/* time in seconds when the shell was started */ -time_t shell_start_time; - -/* Are we running in an emacs shell window? */ -int running_under_emacs; - -/* Do we have /dev/fd? */ -#ifdef HAVE_DEV_FD -int have_devfd = HAVE_DEV_FD; -#else -int have_devfd = 0; -#endif - -/* The name of the .(shell)rc file. */ -static char *bashrc_file = DEFAULT_BASHRC; - -/* Non-zero means to act more like the Bourne shell on startup. */ -static int act_like_sh; - -/* Non-zero if this shell is being run by `su'. */ -static int su_shell; - -/* Non-zero if we have already expanded and sourced $ENV. */ -static int sourced_env; - -/* Is this shell running setuid? */ -static int running_setuid; - -/* Values for the long-winded argument names. */ -static int debugging; /* Do debugging things. */ -static int no_rc; /* Don't execute ~/.bashrc */ -static int no_profile; /* Don't execute .profile */ -static int do_version; /* Display interesting version info. */ -static int make_login_shell; /* Make this shell be a `-bash' shell. */ -static int want_initial_help; /* --help option */ - -int debugging_mode = 0; /* In debugging mode with --debugger */ -#if defined (READLINE) -int no_line_editing = 0; /* non-zero -> don't do fancy line editing. */ -#else -int no_line_editing = 1; /* can't have line editing without readline */ -#endif -int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ -int dump_po_strings; /* Dump strings in $"..." in po format */ -int wordexp_only = 0; /* Do word expansion only */ -int protected_mode = 0; /* No command substitution with --wordexp */ - -#if defined (STRICT_POSIX) -int posixly_correct = 1; /* Non-zero means posix.2 superset. */ -#else -int posixly_correct = 0; /* Non-zero means posix.2 superset. */ -#endif - -/* Some long-winded argument names. These are obviously new. */ -#define Int 1 -#define Charp 2 -static const struct { - const char *name; - int type; - int *int_value; - char **char_value; -} long_args[] = { - { "debug", Int, &debugging, (char **)0x0 }, -#if defined (DEBUGGER) - { "debugger", Int, &debugging_mode, (char **)0x0 }, -#endif - { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 }, - { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, - { "help", Int, &want_initial_help, (char **)0x0 }, - { "init-file", Charp, (int *)0x0, &bashrc_file }, - { "login", Int, &make_login_shell, (char **)0x0 }, - { "noediting", Int, &no_line_editing, (char **)0x0 }, - { "noprofile", Int, &no_profile, (char **)0x0 }, - { "norc", Int, &no_rc, (char **)0x0 }, - { "posix", Int, &posixly_correct, (char **)0x0 }, -#if defined (WORDEXP_OPTION) - { "protected", Int, &protected_mode, (char **)0x0 }, -#endif - { "rcfile", Charp, (int *)0x0, &bashrc_file }, -#if defined (RESTRICTED_SHELL) - { "restricted", Int, &restricted, (char **)0x0 }, -#endif - { "verbose", Int, &echo_input_at_read, (char **)0x0 }, - { "version", Int, &do_version, (char **)0x0 }, -#if defined (WORDEXP_OPTION) - { "wordexp", Int, &wordexp_only, (char **)0x0 }, -#endif - { (char *)0x0, Int, (int *)0x0, (char **)0x0 } -}; - -/* These are extern so execute_simple_command can set them, and then - longjmp back to main to execute a shell script, instead of calling - main () again and resulting in indefinite, possibly fatal, stack - growth. */ -procenv_t subshell_top_level; -int subshell_argc; -char **subshell_argv; -char **subshell_envp; - -char *exec_argv0; - -#if defined (BUFFERED_INPUT) -/* The file descriptor from which the shell is reading input. */ -int default_buffered_input = -1; -#endif - -/* The following two variables are not static so they can show up in $-. */ -int read_from_stdin; /* -s flag supplied */ -int want_pending_command; /* -c flag supplied */ - -/* This variable is not static so it can be bound to $BASH_EXECUTION_STRING */ -char *command_execution_string; /* argument to -c option */ - -int malloc_trace_at_exit = 0; - -static int shell_reinitialized = 0; - -static FILE *default_input; - -static STRING_INT_ALIST *shopt_alist; -static int shopt_ind = 0, shopt_len = 0; - -static int parse_long_options __P((char **, int, int)); -static int parse_shell_options __P((char **, int, int)); -static int bind_args __P((char **, int, int, int)); - -static void start_debugger __P((void)); - -static void add_shopt_to_alist __P((char *, int)); -static void run_shopt_alist __P((void)); - -static void execute_env_file __P((char *)); -static void run_startup_files __P((void)); -static int open_shell_script __P((char *)); -static void set_bash_input __P((void)); -static int run_one_command __P((char *)); -#if defined (WORDEXP_OPTION) -static int run_wordexp __P((char *)); -#endif - -static int uidget __P((void)); - -static void init_interactive __P((void)); -static void init_noninteractive __P((void)); -static void init_interactive_script __P((void)); - -static void set_shell_name __P((char *)); -static void shell_initialize __P((void)); -static void shell_reinitialize __P((void)); - -static void show_shell_usage __P((FILE *, int)); - -#ifdef __CYGWIN__ -static void -_cygwin32_check_tmp () -{ - struct stat sb; - - if (stat ("/tmp", &sb) < 0) - internal_warning (_("could not find /tmp, please create!")); - else - { - if (S_ISDIR (sb.st_mode) == 0) - internal_warning (_("/tmp must be a valid directory name")); - } -} -#endif /* __CYGWIN__ */ - -#if defined (NO_MAIN_ENV_ARG) -/* systems without third argument to main() */ -int -main (argc, argv) - int argc; - char **argv; -#else /* !NO_MAIN_ENV_ARG */ -int -main (argc, argv, env) - int argc; - char **argv, **env; -#endif /* !NO_MAIN_ENV_ARG */ -{ - register int i; - int code, old_errexit_flag; -#if defined (RESTRICTED_SHELL) - int saverst; -#endif - volatile int locally_skip_execution; - volatile int arg_index, top_level_arg_index; -#ifdef __OPENNT - char **env; - - env = environ; -#endif /* __OPENNT */ - - USE_VAR(argc); - USE_VAR(argv); - USE_VAR(env); - USE_VAR(code); - USE_VAR(old_errexit_flag); -#if defined (RESTRICTED_SHELL) - USE_VAR(saverst); -#endif - - /* Catch early SIGINTs. */ - code = setjmp_nosigs (top_level); - if (code) - exit (2); - - xtrace_init (); - -#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# if 1 - malloc_set_register (1); -# endif -#endif - - check_dev_tty (); - -#ifdef __CYGWIN__ - _cygwin32_check_tmp (); -#endif /* __CYGWIN__ */ - - /* Wait forever if we are debugging a login shell. */ - while (debugging_login_shell) sleep (3); - - set_default_locale (); - - running_setuid = uidget (); - - if (getenv ("POSIXLY_CORRECT") || getenv ("POSIX_PEDANTIC")) - posixly_correct = 1; - -#if defined (USE_GNU_MALLOC_LIBRARY) - mcheck (programming_error, (void (*) ())0); -#endif /* USE_GNU_MALLOC_LIBRARY */ - - if (setjmp_sigs (subshell_top_level)) - { - argc = subshell_argc; - argv = subshell_argv; - env = subshell_envp; - sourced_env = 0; - } - - shell_reinitialized = 0; - - /* Initialize `local' variables for all `invocations' of main (). */ - arg_index = 1; - if (arg_index > argc) - arg_index = argc; - command_execution_string = (char *)NULL; - want_pending_command = locally_skip_execution = read_from_stdin = 0; - default_input = stdin; -#if defined (BUFFERED_INPUT) - default_buffered_input = -1; -#endif - - /* Fix for the `infinite process creation' bug when running shell scripts - from startup files on System V. */ - login_shell = make_login_shell = 0; - - /* If this shell has already been run, then reinitialize it to a - vanilla state. */ - if (shell_initialized || shell_name) - { - /* Make sure that we do not infinitely recurse as a login shell. */ - if (*shell_name == '-') - shell_name++; - - shell_reinitialize (); - if (setjmp_nosigs (top_level)) - exit (2); - } - - shell_environment = env; - set_shell_name (argv[0]); - shell_start_time = NOW; /* NOW now defined in general.h */ - - /* Parse argument flags from the input line. */ - - /* Find full word arguments first. */ - arg_index = parse_long_options (argv, arg_index, argc); - - if (want_initial_help) - { - show_shell_usage (stdout, 1); - exit (EXECUTION_SUCCESS); - } - - if (do_version) - { - show_shell_version (1); - exit (EXECUTION_SUCCESS); - } - - /* All done with full word options; do standard shell option parsing.*/ - this_command_name = shell_name; /* for error reporting */ - arg_index = parse_shell_options (argv, arg_index, argc); - - /* If user supplied the "--login" (or -l) flag, then set and invert - LOGIN_SHELL. */ - if (make_login_shell) - { - login_shell++; - login_shell = -login_shell; - } - - set_login_shell ("login_shell", login_shell != 0); - - if (dump_po_strings) - dump_translatable_strings = 1; - - if (dump_translatable_strings) - read_but_dont_execute = 1; - - if (running_setuid && privileged_mode == 0) - disable_priv_mode (); - - /* Need to get the argument to a -c option processed in the - above loop. The next arg is a command to execute, and the - following args are $0...$n respectively. */ - if (want_pending_command) - { - command_execution_string = argv[arg_index]; - if (command_execution_string == 0) - { - report_error (_("%s: option requires an argument"), "-c"); - exit (EX_BADUSAGE); - } - arg_index++; - } - this_command_name = (char *)NULL; - - cmd_init(); /* initialize the command object caches */ - - /* First, let the outside world know about our interactive status. - A shell is interactive if the `-i' flag was given, or if all of - the following conditions are met: - no -c command - no arguments remaining or the -s flag given - standard input is a terminal - standard error is a terminal - Refer to Posix.2, the description of the `sh' utility. */ - - if (forced_interactive || /* -i flag */ - (!command_execution_string && /* No -c command and ... */ - wordexp_only == 0 && /* No --wordexp and ... */ - ((arg_index == argc) || /* no remaining args or... */ - read_from_stdin) && /* -s flag with args, and */ - isatty (fileno (stdin)) && /* Input is a terminal and */ - isatty (fileno (stderr)))) /* error output is a terminal. */ - init_interactive (); - else - init_noninteractive (); - - /* - * Some systems have the bad habit of starting login shells with lots of open - * file descriptors. For instance, most systems that have picked up the - * pre-4.0 Sun YP code leave a file descriptor open each time you call one - * of the getpw* functions, and it's set to be open across execs. That - * means one for login, one for xterm, one for shelltool, etc. There are - * also systems that open persistent FDs to other agents or files as part - * of process startup; these need to be set to be close-on-exec. - */ - if (login_shell && interactive_shell) - { - for (i = 3; i < 20; i++) - SET_CLOSE_ON_EXEC (i); - } - - /* If we're in a strict Posix.2 mode, turn on interactive comments, - alias expansion in non-interactive shells, and other Posix.2 things. */ - if (posixly_correct) - { - bind_variable ("POSIXLY_CORRECT", "y", 0); - sv_strict_posix ("POSIXLY_CORRECT"); - } - - /* Now we run the shopt_alist and process the options. */ - if (shopt_alist) - run_shopt_alist (); - - /* From here on in, the shell must be a normal functioning shell. - Variables from the environment are expected to be set, etc. */ - shell_initialize (); - - set_default_lang (); - set_default_locale_vars (); - - /* - * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) - * M-x shell -> TERM=dumb EMACS=t (no line editing) - * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) - */ - if (interactive_shell) - { - char *term, *emacs; - - term = get_string_value ("TERM"); - emacs = get_string_value ("EMACS"); - - /* Not sure any emacs terminal emulator sets TERM=emacs any more */ - no_line_editing |= term && (STREQ (term, "emacs")); - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); - - /* running_under_emacs == 2 for `eterm' */ - running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); - running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term"); - - if (running_under_emacs) - gnu_error_format = 1; - } - - top_level_arg_index = arg_index; - old_errexit_flag = exit_immediately_on_error; - - /* Give this shell a place to longjmp to before executing the - startup files. This allows users to press C-c to abort the - lengthy startup. */ - code = setjmp_sigs (top_level); - if (code) - { - if (code == EXITPROG || code == ERREXIT) - exit_shell (last_command_exit_value); - else - { -#if defined (JOB_CONTROL) - /* Reset job control, since run_startup_files turned it off. */ - set_job_control (interactive_shell); -#endif - /* Reset value of `set -e', since it's turned off before running - the startup files. */ - exit_immediately_on_error += old_errexit_flag; - locally_skip_execution++; - } - } - - arg_index = top_level_arg_index; - - /* Execute the start-up scripts. */ - - if (interactive_shell == 0) - { - unbind_variable ("PS1"); - unbind_variable ("PS2"); - interactive = 0; -#if 0 - /* This has already been done by init_noninteractive */ - expand_aliases = posixly_correct; -#endif - } - else - { - change_flag ('i', FLAG_ON); - interactive = 1; - } - -#if defined (RESTRICTED_SHELL) - /* Set restricted_shell based on whether the basename of $0 indicates that - the shell should be restricted or if the `-r' option was supplied at - startup. */ - restricted_shell = shell_is_restricted (shell_name); - - /* If the `-r' option is supplied at invocation, make sure that the shell - is not in restricted mode when running the startup files. */ - saverst = restricted; - restricted = 0; -#endif - - /* The startup files are run with `set -e' temporarily disabled. */ - if (locally_skip_execution == 0 && running_setuid == 0) - { - old_errexit_flag = exit_immediately_on_error; - exit_immediately_on_error = 0; - - run_startup_files (); - exit_immediately_on_error += old_errexit_flag; - } - - /* If we are invoked as `sh', turn on Posix mode. */ - if (act_like_sh) - { - bind_variable ("POSIXLY_CORRECT", "y", 0); - sv_strict_posix ("POSIXLY_CORRECT"); - } - -#if defined (RESTRICTED_SHELL) - /* Turn on the restrictions after executing the startup files. This - means that `bash -r' or `set -r' invoked from a startup file will - turn on the restrictions after the startup files are executed. */ - restricted = saverst || restricted; - if (shell_reinitialized == 0) - maybe_make_restricted (shell_name); -#endif /* RESTRICTED_SHELL */ - -#if defined (WORDEXP_OPTION) - if (wordexp_only) - { - startup_state = 3; - last_command_exit_value = run_wordexp (argv[arg_index]); - exit_shell (last_command_exit_value); - } -#endif - - if (command_execution_string) - { - arg_index = bind_args (argv, arg_index, argc, 0); - startup_state = 2; - - if (debugging_mode) - start_debugger (); - -#if defined (ONESHOT) - executing = 1; - run_one_command (command_execution_string); - exit_shell (last_command_exit_value); -#else /* ONESHOT */ - with_input_from_string (command_execution_string, "-c"); - goto read_and_execute; -#endif /* !ONESHOT */ - } - - /* Get possible input filename and set up default_buffered_input or - default_input as appropriate. */ - if (arg_index != argc && read_from_stdin == 0) - { - open_shell_script (argv[arg_index]); - arg_index++; - } - else if (interactive == 0) - /* In this mode, bash is reading a script from stdin, which is a - pipe or redirected file. */ -#if defined (BUFFERED_INPUT) - default_buffered_input = fileno (stdin); /* == 0 */ -#else - setbuf (default_input, (char *)NULL); -#endif /* !BUFFERED_INPUT */ - - set_bash_input (); - - /* Bind remaining args to $1 ... $n */ - arg_index = bind_args (argv, arg_index, argc, 1); - - if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (dollar_vars[1] || interactive_shell == 0)) - start_debugger (); - - /* Do the things that should be done only for interactive shells. */ - if (interactive_shell) - { - /* Set up for checking for presence of mail. */ - reset_mail_timer (); - init_mail_dates (); - -#if defined (HISTORY) - /* Initialize the interactive history stuff. */ - bash_initialize_history (); - /* Don't load the history from the history file if we've already - saved some lines in this session (e.g., by putting `history -s xx' - into one of the startup files). */ - if (shell_initialized == 0 && history_lines_this_session == 0) - load_history (); -#endif /* HISTORY */ - - /* Initialize terminal state for interactive shells after the - .bash_profile and .bashrc are interpreted. */ - get_tty_state (); - } - -#if !defined (ONESHOT) - read_and_execute: -#endif /* !ONESHOT */ - - shell_initialized = 1; - - /* Read commands until exit condition. */ - reader_loop (); - exit_shell (last_command_exit_value); -} - -static int -parse_long_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index, longarg, i; - char *arg_string; - - arg_index = arg_start; - while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && - (*arg_string == '-')) - { - longarg = 0; - - /* Make --login equivalent to -login. */ - if (arg_string[1] == '-' && arg_string[2]) - { - longarg = 1; - arg_string++; - } - - for (i = 0; long_args[i].name; i++) - { - if (STREQ (arg_string + 1, long_args[i].name)) - { - if (long_args[i].type == Int) - *long_args[i].int_value = 1; - else if (argv[++arg_index] == 0) - { - report_error (_("%s: option requires an argument"), long_args[i].name); - exit (EX_BADUSAGE); - } - else - *long_args[i].char_value = argv[arg_index]; - - break; - } - } - if (long_args[i].name == 0) - { - if (longarg) - { - report_error (_("%s: invalid option"), argv[arg_index]); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - break; /* No such argument. Maybe flag arg. */ - } - - arg_index++; - } - - return (arg_index); -} - -static int -parse_shell_options (argv, arg_start, arg_end) - char **argv; - int arg_start, arg_end; -{ - int arg_index; - int arg_character, on_or_off, next_arg, i; - char *o_option, *arg_string; - - arg_index = arg_start; - while (arg_index != arg_end && (arg_string = argv[arg_index]) && - (*arg_string == '-' || *arg_string == '+')) - { - /* There are flag arguments, so parse them. */ - next_arg = arg_index + 1; - - /* A single `-' signals the end of options. From the 4.3 BSD sh. - An option `--' means the same thing; this is the standard - getopt(3) meaning. */ - if (arg_string[0] == '-' && - (arg_string[1] == '\0' || - (arg_string[1] == '-' && arg_string[2] == '\0'))) - return (next_arg); - - i = 1; - on_or_off = arg_string[0]; - while (arg_character = arg_string[i++]) - { - switch (arg_character) - { - case 'c': - want_pending_command = 1; - break; - - case 'l': - make_login_shell = 1; - break; - - case 's': - read_from_stdin = 1; - break; - - case 'o': - o_option = argv[next_arg]; - if (o_option == 0) - { - list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); - break; - } - if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - next_arg++; - break; - - case 'O': - /* Since some of these can be overridden by the normal - interactive/non-interactive shell initialization or - initializing posix mode, we save the options and process - them after initialization. */ - o_option = argv[next_arg]; - if (o_option == 0) - { - shopt_listopt (o_option, (on_or_off == '-') ? 0 : 1); - break; - } - add_shopt_to_alist (o_option, on_or_off); - next_arg++; - break; - - case 'D': - dump_translatable_strings = 1; - break; - - default: - if (change_flag (arg_character, on_or_off) == FLAG_ERROR) - { - report_error (_("%c%c: invalid option"), on_or_off, arg_character); - show_shell_usage (stderr, 0); - exit (EX_BADUSAGE); - } - } - } - /* Can't do just a simple increment anymore -- what about - "bash -abouo emacs ignoreeof -hP"? */ - arg_index = next_arg; - } - - return (arg_index); -} - -/* Exit the shell with status S. */ -void -exit_shell (s) - int s; -{ - fflush (stdout); /* XXX */ - fflush (stderr); - - /* Clean up the terminal if we are in a state where it's been modified. */ -#if defined (READLINE) - if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function) - (*rl_deprep_term_function) (); -#endif - if (read_tty_modified ()) - read_tty_cleanup (); - - /* Do trap[0] if defined. Allow it to override the exit status - passed to us. */ - if (signal_is_trapped (0)) - s = run_exit_trap (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - -#if defined (HISTORY) - if (remember_on_history) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (COPROCESS_SUPPORT) - coproc_flush (); -#endif - -#if defined (JOB_CONTROL) - /* If the user has run `shopt -s huponexit', hangup all jobs when we exit - an interactive login shell. ksh does this unconditionally. */ - if (interactive_shell && login_shell && hup_on_exit) - hangup_all_jobs (); - - /* If this shell is interactive, or job control is active, terminate all - stopped jobs and restore the original terminal process group. Don't do - this if we're in a subshell and calling exit_shell after, for example, - a failed word expansion. We want to do this even if the shell is not - interactive because we set the terminal's process group when job control - is enabled regardless of the interactive status. */ - if (subshell_environment == 0) - end_job_control (); -#endif /* JOB_CONTROL */ - - /* Always return the exit status of the last command to our parent. */ - sh_exit (s); -} - -/* A wrapper for exit that (optionally) can do other things, like malloc - statistics tracing. */ -void -sh_exit (s) - int s; -{ -#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC) - if (malloc_trace_at_exit) - trace_malloc_stats (get_name_for_error (), (char *)NULL); -#endif - - exit (s); -} - -/* Exit a subshell, which includes calling the exit trap. We don't want to - do any more cleanup, since a subshell is created as an exact copy of its - parent. */ -void -subshell_exit (s) - int s; -{ - fflush (stdout); - fflush (stderr); - - /* Do trap[0] if defined. Allow it to override the exit status - passed to us. */ - if (signal_is_trapped (0)) - s = run_exit_trap (); - - sh_exit (s); -} - -/* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey - the Posix.2 startup file rules: $ENV is expanded, and if the file it - names exists, that file is sourced. The Posix.2 rules are in effect - for interactive shells only. (section 4.56.5.3) */ - -/* Execute ~/.bashrc for most shells. Never execute it if - ACT_LIKE_SH is set, or if NO_RC is set. - - If the executable file "/usr/gnu/src/bash/foo" contains: - - #!/usr/gnu/bin/bash - echo hello - - then: - - COMMAND EXECUTE BASHRC - -------------------------------- - bash -c foo NO - bash foo NO - foo NO - rsh machine ls YES (for rsh, which calls `bash -c') - rsh machine foo YES (for shell started by rsh) NO (for foo!) - echo ls | bash NO - login NO - bash YES -*/ - -static void -execute_env_file (env_file) - char *env_file; -{ - char *fn; - - if (env_file && *env_file) - { - fn = expand_string_unsplit_to_string (env_file, Q_DOUBLE_QUOTES); - if (fn && *fn) - maybe_execute_file (fn, 1); - FREE (fn); - } -} - -static void -run_startup_files () -{ -#if defined (JOB_CONTROL) - int old_job_control; -#endif - int sourced_login, run_by_ssh; - - /* get the rshd/sshd case out of the way first. */ - if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && - act_like_sh == 0 && command_execution_string) - { -#ifdef SSH_SOURCE_BASHRC - run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) || - (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); -#else - run_by_ssh = 0; -#endif - - /* If we were run by sshd or we think we were run by rshd, execute - ~/.bashrc if we are a top-level shell. */ - if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - return; - } - } - -#if defined (JOB_CONTROL) - /* Startup files should be run without job control enabled. */ - old_job_control = interactive_shell ? set_job_control (0) : 0; -#endif - - sourced_login = 0; - - /* A shell begun with the --login (or -l) flag that is not in posix mode - runs the login shell startup files, no matter whether or not it is - interactive. If NON_INTERACTIVE_LOGIN_SHELLS is defined, run the - startup files if argv[0][0] == '-' as well. */ -#if defined (NON_INTERACTIVE_LOGIN_SHELLS) - if (login_shell && posixly_correct == 0) -#else - if (login_shell < 0 && posixly_correct == 0) -#endif - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - - sourced_login = 1; - } - - /* A non-interactive shell not named `sh' and not in posix mode reads and - executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd' - and `-su' as the name of the shell, we want to read the startup files. - No other non-interactive shells read any startup files. */ - if (interactive_shell == 0 && !(su_shell && login_shell)) - { - if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 && - sourced_env++ == 0) - execute_env_file (get_string_value ("BASH_ENV")); - return; - } - - /* Interactive shell or `-su' shell. */ - if (posixly_correct == 0) /* bash, sh */ - { - if (login_shell && sourced_login++ == 0) - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - - /* Execute /etc/profile and one of the personal login shell - initialization files. */ - if (no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); - - if (act_like_sh) /* sh */ - maybe_execute_file ("~/.profile", 1); - else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && - (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ - maybe_execute_file ("~/.profile", 1); - } - } - - /* bash */ - if (act_like_sh == 0 && no_rc == 0) - { -#ifdef SYS_BASHRC -# if defined (__OPENNT) - maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1); -# else - maybe_execute_file (SYS_BASHRC, 1); -# endif -#endif - maybe_execute_file (bashrc_file, 1); - } - /* sh */ - else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - else /* bash --posix, sh --posix */ - { - /* bash and sh */ - if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0) - execute_env_file (get_string_value ("ENV")); - } - -#if defined (JOB_CONTROL) - set_job_control (old_job_control); -#endif -} - -#if defined (RESTRICTED_SHELL) -/* Return 1 if the shell should be a restricted one based on NAME or the - value of `restricted'. Don't actually do anything, just return a - boolean value. */ -int -shell_is_restricted (name) - char *name; -{ - char *temp; - - if (restricted) - return 1; - temp = base_pathname (name); - if (*temp == '-') - temp++; - return (STREQ (temp, RESTRICTED_SHELL_NAME)); -} - -/* Perhaps make this shell a `restricted' one, based on NAME. If the - basename of NAME is "rbash", then this shell is restricted. The - name of the restricted shell is a configurable option, see config.h. - In a restricted shell, PATH, SHELL, ENV, and BASH_ENV are read-only - and non-unsettable. - Do this also if `restricted' is already set to 1; maybe the shell was - started with -r. */ -int -maybe_make_restricted (name) - char *name; -{ - char *temp; - - temp = base_pathname (name); - if (*temp == '-') - temp++; - if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) - { - set_var_read_only ("PATH"); - set_var_read_only ("SHELL"); - set_var_read_only ("ENV"); - set_var_read_only ("BASH_ENV"); - restricted = 1; - } - return (restricted); -} -#endif /* RESTRICTED_SHELL */ - -/* Fetch the current set of uids and gids and return 1 if we're running - setuid or setgid. */ -static int -uidget () -{ - uid_t u; - - u = getuid (); - if (current_user.uid != u) - { - FREE (current_user.user_name); - FREE (current_user.shell); - FREE (current_user.home_dir); - current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL; - } - current_user.uid = u; - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); - - /* See whether or not we are running setuid or setgid. */ - return (current_user.uid != current_user.euid) || - (current_user.gid != current_user.egid); -} - -void -disable_priv_mode () -{ - int e; - - if (setuid (current_user.uid) < 0) - { - e = errno; - sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid); -#if defined (EXIT_ON_SETUID_FAILURE) - if (e == EAGAIN) - exit (e); -#endif - } - if (setgid (current_user.gid) < 0) - sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid); - - current_user.euid = current_user.uid; - current_user.egid = current_user.gid; -} - -#if defined (WORDEXP_OPTION) -static int -run_wordexp (words) - char *words; -{ - int code, nw, nb; - WORD_LIST *wl, *tl, *result; - - code = setjmp_nosigs (top_level); - - if (code != NOT_JUMPED) - { - switch (code) - { - /* Some kind of throw to top_level has occurred. */ - case FORCE_EOF: - return last_command_exit_value = 127; - case ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_wordexp", CMDERR_BADJUMP, code, 0); - } - } - - /* Run it through the parser to get a list of words and expand them */ - if (words && *words) - { - with_input_from_string (words, "--wordexp"); - if (parse_command () != 0) - return (126); - if (global_command == 0) - { - printf ("0\n0\n"); - return (0); - } - if (global_command->type != cm_simple) - return (126); - wl = global_command->value.Simple->words; - if (protected_mode) - for (tl = wl; tl; tl = tl->next) - tl->word->flags |= W_NOCOMSUB|W_NOPROCSUB; - result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0; - } - else - result = (WORD_LIST *)0; - - last_command_exit_value = 0; - - if (result == 0) - { - printf ("0\n0\n"); - return (0); - } - - /* Count up the number of words and bytes, and print them. Don't count - the trailing NUL byte. */ - for (nw = nb = 0, wl = result; wl; wl = wl->next) - { - nw++; - nb += strlen (wl->word->word); - } - printf ("%u\n%u\n", nw, nb); - /* Print each word on a separate line. This will have to be changed when - the interface to glibc is completed. */ - for (wl = result; wl; wl = wl->next) - printf ("%s\n", wl->word->word); - - return (0); -} -#endif - -#if defined (ONESHOT) -/* Run one command, given as the argument to the -c option. Tell - parse_and_execute not to fork for a simple command. */ -static int -run_one_command (command) - char *command; -{ - int code; - - code = setjmp_nosigs (top_level); - - if (code != NOT_JUMPED) - { -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - switch (code) - { - /* Some kind of throw to top_level has occurred. */ - case FORCE_EOF: - return last_command_exit_value = 127; - case ERREXIT: - case EXITPROG: - return last_command_exit_value; - case DISCARD: - return last_command_exit_value = 1; - default: - command_error ("run_one_command", CMDERR_BADJUMP, code, 0); - } - } - return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST)); -} -#endif /* ONESHOT */ - -static int -bind_args (argv, arg_start, arg_end, start_index) - char **argv; - int arg_start, arg_end, start_index; -{ - register int i; - WORD_LIST *args; - - for (i = arg_start, args = (WORD_LIST *)NULL; i < arg_end; i++) - args = make_word_list (make_word (argv[i]), args); - if (args) - { - args = REVERSE_LIST (args, WORD_LIST *); - if (start_index == 0) /* bind to $0...$n for sh -c command */ - { - /* Posix.2 4.56.3 says that the first argument after sh -c command - becomes $0, and the rest of the arguments become $1...$n */ - shell_name = savestring (args->word->word); - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (args->word->word); - remember_args (args->next, 1); - push_args (args->next); /* BASH_ARGV and BASH_ARGC */ - } - else /* bind to $1...$n for shell script */ - { - remember_args (args, 1); - push_args (args); /* BASH_ARGV and BASH_ARGC */ - } - - dispose_words (args); - } - - return (i); -} - -void -unbind_args () -{ - remember_args ((WORD_LIST *)NULL, 1); - pop_args (); /* Reset BASH_ARGV and BASH_ARGC */ -} - -static void -start_debugger () -{ -#if defined (DEBUGGER) && defined (DEBUGGER_START_FILE) - int old_errexit; - int r; - - old_errexit = exit_immediately_on_error; - exit_immediately_on_error = 0; - - r = force_execute_file (DEBUGGER_START_FILE, 1); - if (r < 0) - { - internal_warning ("cannot start debugger; debugging mode disabled"); - debugging_mode = function_trace_mode = 0; - } - else - function_trace_mode = 1; - - exit_immediately_on_error += old_errexit; -#endif -} - -static int -open_shell_script (script_name) - char *script_name; -{ - int fd, e, fd_is_tty; - char *filename, *path_filename, *t; - char sample[80]; - int sample_len; - struct stat sb; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; -#endif - - filename = savestring (script_name); - - fd = open (filename, O_RDONLY); - if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) - { - e = errno; - /* If it's not in the current directory, try looking through PATH - for it. */ - path_filename = find_path_file (script_name); - if (path_filename) - { - free (filename); - filename = path_filename; - fd = open (filename, O_RDONLY); - } - else - errno = e; - } - - if (fd < 0) - { - e = errno; - file_error (filename); - exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); - } - - free (dollar_vars[0]); - dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (script_name); - if (exec_argv0) - { - free (exec_argv0); - exec_argv0 = (char *)NULL; - } - -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); - - array_push (bash_source_a, filename); - if (bash_lineno_a) - { - t = itos (executing_line_number ()); - array_push (bash_lineno_a, t); - free (t); - } - array_push (funcname_a, "main"); -#endif - -#ifdef HAVE_DEV_FD - fd_is_tty = isatty (fd); -#else - fd_is_tty = 0; -#endif - - /* Only do this with non-tty file descriptors we can seek on. */ - if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) - { - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), - and report an error and exit if it is. */ - sample_len = read (fd, sample, sizeof (sample)); - if (sample_len < 0) - { - e = errno; - if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode)) - internal_error (_("%s: is a directory"), filename); - else - { - errno = e; - file_error (filename); - } - exit (EX_NOEXEC); - } - else if (sample_len > 0 && (check_binary_file (sample, sample_len))) - { - internal_error (_("%s: cannot execute binary file"), filename); - exit (EX_BINARY_FILE); - } - /* Now rewind the file back to the beginning. */ - lseek (fd, 0L, 0); - } - - /* Open the script. But try to move the file descriptor to a randomly - large one, in the hopes that any descriptors used by the script will - not match with ours. */ - fd = move_to_high_fd (fd, 1, -1); - -#if defined (BUFFERED_INPUT) - default_buffered_input = fd; - SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ - default_input = fdopen (fd, "r"); - - if (default_input == 0) - { - file_error (filename); - exit (EX_NOTFOUND); - } - - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); -#endif /* !BUFFERED_INPUT */ - - /* Just about the only way for this code to be executed is if something - like `bash -i /dev/stdin' is executed. */ - if (interactive_shell && fd_is_tty) - { - dup2 (fd, 0); - close (fd); - fd = 0; -#if defined (BUFFERED_INPUT) - default_buffered_input = 0; -#else - fclose (default_input); - default_input = stdin; -#endif - } - else if (forced_interactive && fd_is_tty == 0) - /* But if a script is called with something like `bash -i scriptname', - we need to do a non-interactive setup here, since we didn't do it - before. */ - init_interactive_script (); - - free (filename); - return (fd); -} - -/* Initialize the input routines for the parser. */ -static void -set_bash_input () -{ - /* Make sure the fd from which we are reading input is not in - no-delay mode. */ -#if defined (BUFFERED_INPUT) - if (interactive == 0) - sh_unset_nodelay_mode (default_buffered_input); - else -#endif /* !BUFFERED_INPUT */ - sh_unset_nodelay_mode (fileno (stdin)); - - /* with_input_from_stdin really means `with_input_from_readline' */ - if (interactive && no_line_editing == 0) - with_input_from_stdin (); -#if defined (BUFFERED_INPUT) - else if (interactive == 0) - with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); -#endif /* BUFFERED_INPUT */ - else - with_input_from_stream (default_input, dollar_vars[0]); -} - -/* Close the current shell script input source and forget about it. This is - extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO - is non-zero, we close default_buffered_input even if it's the standard - input (fd 0). */ -void -unset_bash_input (check_zero) - int check_zero; -{ -#if defined (BUFFERED_INPUT) - if ((check_zero && default_buffered_input >= 0) || - (check_zero == 0 && default_buffered_input > 0)) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - bash_input.type = st_none; /* XXX */ - } -#else /* !BUFFERED_INPUT */ - if (default_input) - { - fclose (default_input); - default_input = (FILE *)NULL; - } -#endif /* !BUFFERED_INPUT */ -} - - -#if !defined (PROGRAM) -# define PROGRAM "bash" -#endif - -static void -set_shell_name (argv0) - char *argv0; -{ - /* Here's a hack. If the name of this shell is "sh", then don't do - any startup files; just try to be more like /bin/sh. */ - shell_name = argv0 ? base_pathname (argv0) : PROGRAM; - - if (argv0 && *argv0 == '-') - { - if (*shell_name == '-') - shell_name++; - login_shell = 1; - } - - if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') - act_like_sh++; - if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') - su_shell++; - - shell_name = argv0 ? argv0 : PROGRAM; - FREE (dollar_vars[0]); - dollar_vars[0] = savestring (shell_name); - - /* A program may start an interactive shell with - "execl ("/bin/bash", "-", NULL)". - If so, default the name of this shell to our name. */ - if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) - shell_name = PROGRAM; -} - -static void -init_interactive () -{ - expand_aliases = interactive_shell = startup_state = 1; - interactive = 1; -} - -static void -init_noninteractive () -{ -#if defined (HISTORY) - bash_history_reinit (0); -#endif /* HISTORY */ - interactive_shell = startup_state = interactive = 0; - expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */ - no_line_editing = 1; -#if defined (JOB_CONTROL) - /* Even if the shell is not interactive, enable job control if the -i or - -m option is supplied at startup. */ - set_job_control (forced_interactive||jobs_m_flag); -#endif /* JOB_CONTROL */ -} - -static void -init_interactive_script () -{ - init_noninteractive (); - expand_aliases = interactive_shell = startup_state = 1; -} - -void -get_current_user_info () -{ - struct passwd *entry; - - /* Don't fetch this more than once. */ - if (current_user.user_name == 0) - { -#if defined (__TANDEM) - entry = getpwnam (getlogin ()); -#else - entry = getpwuid (current_user.uid); -#endif - if (entry) - { - current_user.user_name = savestring (entry->pw_name); - current_user.shell = (entry->pw_shell && entry->pw_shell[0]) - ? savestring (entry->pw_shell) - : savestring ("/bin/sh"); - current_user.home_dir = savestring (entry->pw_dir); - } - else - { - current_user.user_name = _("I have no name!"); - current_user.user_name = savestring (current_user.user_name); - current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring ("/"); - } - endpwent (); - } -} - -/* Do whatever is necessary to initialize the shell. - Put new initializations in here. */ -static void -shell_initialize () -{ - char hostname[256]; - int should_be_restricted; - - /* Line buffer output for stderr and stdout. */ - if (shell_initialized == 0) - { - sh_setlinebuf (stderr); - sh_setlinebuf (stdout); - } - - /* Sort the array of shell builtins so that the binary search in - find_shell_builtin () works correctly. */ - initialize_shell_builtins (); - - /* Initialize the trap signal handlers before installing our own - signal handlers. traps.c:restore_original_signals () is responsible - for restoring the original default signal handlers. That function - is called when we make a new child. */ - initialize_traps (); - initialize_signals (0); - - /* It's highly unlikely that this will change. */ - if (current_host_name == 0) - { - /* Initialize current_host_name. */ - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; - else - current_host_name = savestring (hostname); - } - - /* Initialize the stuff in current_user that comes from the password - file. We don't need to do this right away if the shell is not - interactive. */ - if (interactive_shell) - get_current_user_info (); - - /* Initialize our interface to the tilde expander. */ - tilde_initialize (); - -#if defined (RESTRICTED_SHELL) - should_be_restricted = shell_is_restricted (shell_name); -#endif - - /* Initialize internal and environment variables. Don't import shell - functions from the environment if we are running in privileged or - restricted mode or if the shell is running setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_variables (shell_environment, privileged_mode||restricted||should_be_restricted||running_setuid); -#else - initialize_shell_variables (shell_environment, privileged_mode||running_setuid); -#endif - - /* Initialize the data structures for storing and running jobs. */ - initialize_job_control (jobs_m_flag); - - /* Initialize input streams to null. */ - initialize_bash_input (); - - initialize_flags (); - - /* Initialize the shell options. Don't import the shell options - from the environment variables $SHELLOPTS or $BASHOPTS if we are - running in privileged or restricted mode or if the shell is running - setuid. */ -#if defined (RESTRICTED_SHELL) - initialize_shell_options (privileged_mode||restricted||should_be_restricted||running_setuid); - initialize_bashopts (privileged_mode||restricted||should_be_restricted||running_setuid); -#else - initialize_shell_options (privileged_mode||running_setuid); - initialize_bashopts (privileged_mode||running_setuid); -#endif -} - -/* Function called by main () when it appears that the shell has already - had some initialization performed. This is supposed to reset the world - back to a pristine state, as if we had been exec'ed. */ -static void -shell_reinitialize () -{ - /* The default shell prompts. */ - primary_prompt = PPROMPT; - secondary_prompt = SPROMPT; - - /* Things that get 1. */ - current_command_number = 1; - - /* We have decided that the ~/.bashrc file should not be executed - for the invocation of each shell script. If the variable $ENV - (or $BASH_ENV) is set, its value is used as the name of a file - to source. */ - no_rc = no_profile = 1; - - /* Things that get 0. */ - login_shell = make_login_shell = interactive = executing = 0; - debugging = do_version = line_number = last_command_exit_value = 0; - forced_interactive = interactive_shell = 0; - subshell_environment = running_in_background = 0; - expand_aliases = 0; - - /* XXX - should we set jobs_m_flag to 0 here? */ - -#if defined (HISTORY) - bash_history_reinit (0); -#endif /* HISTORY */ - -#if defined (RESTRICTED_SHELL) - restricted = 0; -#endif /* RESTRICTED_SHELL */ - - /* Ensure that the default startup file is used. (Except that we don't - execute this file for reinitialized shells). */ - bashrc_file = DEFAULT_BASHRC; - - /* Delete all variables and functions. They will be reinitialized when - the environment is parsed. */ - delete_all_contexts (shell_variables); - delete_all_variables (shell_functions); - - reinit_special_variables (); - -#if defined (READLINE) - bashline_reinitialize (); -#endif - - shell_reinitialized = 1; -} - -static void -show_shell_usage (fp, extra) - FILE *fp; - int extra; -{ - int i; - char *set_opts, *s, *t; - - if (extra) - fprintf (fp, _("GNU bash, version %s-(%s)\n"), shell_version_string (), MACHTYPE); - fprintf (fp, _("Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n"), - shell_name, shell_name); - fputs (_("GNU long options:\n"), fp); - for (i = 0; long_args[i].name; i++) - fprintf (fp, "\t--%s\n", long_args[i].name); - - fputs (_("Shell options:\n"), fp); - fputs (_("\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n"), fp); - - for (i = 0, set_opts = 0; shell_builtins[i].name; i++) - if (STREQ (shell_builtins[i].name, "set")) - set_opts = savestring (shell_builtins[i].short_doc); - if (set_opts) - { - s = strchr (set_opts, '['); - if (s == 0) - s = set_opts; - while (*++s == '-') - ; - t = strchr (s, ']'); - if (t) - *t = '\0'; - fprintf (fp, _("\t-%s or -o option\n"), s); - free (set_opts); - } - - if (extra) - { - fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name); - fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name); - fprintf (fp, _("Use the `bashbug' command to report bugs.\n")); - } -} - -static void -add_shopt_to_alist (opt, on_or_off) - char *opt; - int on_or_off; -{ - if (shopt_ind >= shopt_len) - { - shopt_len += 8; - shopt_alist = (STRING_INT_ALIST *)xrealloc (shopt_alist, shopt_len * sizeof (shopt_alist[0])); - } - shopt_alist[shopt_ind].word = opt; - shopt_alist[shopt_ind].token = on_or_off; - shopt_ind++; -} - -static void -run_shopt_alist () -{ - register int i; - - for (i = 0; i < shopt_ind; i++) - if (shopt_setopt (shopt_alist[i].word, (shopt_alist[i].token == '-')) != EXECUTION_SUCCESS) - exit (EX_BADUSAGE); - free (shopt_alist); - shopt_alist = 0; - shopt_ind = shopt_len = 0; -} diff --git a/tests/RUN-ONE-TEST~ b/tests/RUN-ONE-TEST~ deleted file mode 100755 index 3efcf32d6..000000000 --- a/tests/RUN-ONE-TEST~ +++ /dev/null @@ -1,9 +0,0 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current -THIS_SH=$BUILD_DIR/bash -PATH=$PATH:$BUILD_DIR - -export THIS_SH PATH - -rm -f /tmp/xx - -/bin/sh "$@" diff --git a/tests/misc/regress/log.orig b/tests/misc/regress/log.orig deleted file mode 100644 index c1f1e1991..000000000 --- a/tests/misc/regress/log.orig +++ /dev/null @@ -1,50 +0,0 @@ -:; ./shx - -sh: -<&$fd ok -nlbq Mon Aug 3 02:45:00 EDT 1992 -bang geoff -quote 712824302 -setbq defmsgid=<1992Aug3.024502.6176@host> -bgwait sleep done... wait 6187 - - -bash: -<&$fd ok -nlbq Mon Aug 3 02:45:09 EDT 1992 -bang geoff -quote 712824311 -setbq defmsgid=<1992Aug3.024512.6212@host> -bgwait sleep done... wait 6223 - - -ash: -<&$fd shx1: 4: Syntax error: Bad fd number -nlbq Mon Aug 3 02:45:19 EDT 1992 -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.` echo 024521 -bgwait sleep done... wait 6241 - - -ksh: -<&$fd ok -nlbq ./shx: 6248 Memory fault - core dumped -bang geoff -quote getdate: `"now"' not a valid date - -setbq defmsgid=<1992Aug3.024530.6257@host> -bgwait no such job: 6265 -wait 6265 -sleep done... - -zsh: -<&$fd ok -nlbq Mon Aug 3 02:45:36 EDT 1992 -bang shx3: event not found: /s/ [4] -quote 712824337 -setbq defmsgid=<..6290@host> -bgwait shx7: unmatched " [9] -sleep done... -:; diff --git a/tests/misc/regress/shx.orig b/tests/misc/regress/shx.orig deleted file mode 100644 index 4b3bf2b82..000000000 --- a/tests/misc/regress/shx.orig +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh -for cmd in sh bash ash ksh zsh -do - echo - echo $cmd: - for demo in shx? - do - $cmd $demo - done -done diff --git a/variables.c~ b/variables.c~ deleted file mode 100644 index 54b116714..000000000 --- a/variables.c~ +++ /dev/null @@ -1,5453 +0,0 @@ -/* variables.c -- Functions for hacking shell variables. */ - -/* Copyright (C) 1987-2015 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 "posixstat.h" -#include "posixtime.h" - -#if defined (__QNX__) -# if defined (__QNXNTO__) -# include -# else -# include -# endif /* !__QNXNTO__ */ -#endif /* __QNX__ */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#include "bashansi.h" -#include "bashintl.h" - -#define NEED_XTRACE_SET_DECL - -#include "shell.h" -#include "flags.h" -#include "execute_cmd.h" -#include "findcmd.h" -#include "mailcheck.h" -#include "input.h" -#include "hashcmd.h" -#include "pathexp.h" -#include "alias.h" -#include "jobs.h" - -#include "version.h" - -#include "builtins/getopt.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#if defined (READLINE) -# include "bashline.h" -# include -#else -# include -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include -#endif /* HISTORY */ - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ - -#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') - -#define BASHFUNC_PREFIX "BASH_FUNC_" -#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */ -#define BASHFUNC_SUFFIX "%%" -#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */ - -/* flags for find_variable_internal */ - -#define FV_FORCETEMPENV 0x01 -#define FV_SKIPINVISIBLE 0x02 - -extern char **environ; - -/* Variables used here and defined in other files. */ -extern int posixly_correct; -extern int line_number, line_number_base; -extern int subshell_environment, indirection_level, subshell_level; -extern int build_version, patch_level; -extern int expanding_redir; -extern int last_command_exit_value; -extern char *dist_version, *release_status; -extern char *shell_name; -extern char *primary_prompt, *secondary_prompt; -extern char *current_host_name; -extern sh_builtin_func_t *this_shell_builtin; -extern SHELL_VAR *this_shell_function; -extern char *the_printed_command_except_trap; -extern char *this_command_name; -extern char *command_execution_string; -extern time_t shell_start_time; -extern int assigning_in_environment; -extern int executing_builtin; -extern int funcnest_max; - -#if defined (READLINE) -extern int no_line_editing; -extern int perform_hostname_completion; -#endif - -/* The list of shell variables that the user has created at the global - scope, or that came from the environment. */ -VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL; - -/* The current list of shell variables, including function scopes */ -VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL; - -/* The list of shell functions that the user has created, or that came from - the environment. */ -HASH_TABLE *shell_functions = (HASH_TABLE *)NULL; - -#if defined (DEBUGGER) -/* The table of shell function definitions that the user defined or that - came from the environment. */ -HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; -#endif - -/* The current variable context. This is really a count of how deep into - executing functions we are. */ -int variable_context = 0; - -/* The set of shell assignments which are made only in the environment - for a single command. */ -HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; - -/* Set to non-zero if an assignment error occurs while putting variables - into the temporary environment. */ -int tempenv_assign_error; - -/* Some funky variables which are known about specially. Here is where - "$*", "$1", and all the cruft is kept. */ -char *dollar_vars[10]; -WORD_LIST *rest_of_args = (WORD_LIST *)NULL; - -/* The value of $$. */ -pid_t dollar_dollar_pid; - -/* Non-zero means that we have to remake EXPORT_ENV. */ -int array_needs_making = 1; - -/* The number of times BASH has been executed. This is set - by initialize_variables (). */ -int shell_level = 0; - -/* An array which is passed to commands as their environment. It is - manufactured from the union of the initial environment and the - shell variables that are marked for export. */ -char **export_env = (char **)NULL; -static int export_env_index; -static int export_env_size; - -#if defined (READLINE) -static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ -#endif - -static HASH_TABLE *last_table_searched; /* hash_lookup sets this */ - -/* Some forward declarations. */ -static void create_variable_tables __P((void)); - -static void set_machine_vars __P((void)); -static void set_home_var __P((void)); -static void set_shell_var __P((void)); -static char *get_bash_name __P((void)); -static void initialize_shell_level __P((void)); -static void uidset __P((void)); -#if defined (ARRAY_VARS) -static void make_vers_array __P((void)); -#endif - -static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); -#if defined (ARRAY_VARS) -static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); -#endif -static SHELL_VAR *get_self __P((SHELL_VAR *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); -static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int)); -#endif - -static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_seconds __P((SHELL_VAR *)); -static SHELL_VAR *init_seconds_var __P((void)); - -static int brand __P((void)); -static void sbrand __P((unsigned long)); /* set bash random number generator. */ -static void seedrand __P((void)); /* seed generator randomly */ -static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_random __P((SHELL_VAR *)); - -static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_lineno __P((SHELL_VAR *)); - -static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_subshell __P((SHELL_VAR *)); - -static SHELL_VAR *get_bashpid __P((SHELL_VAR *)); - -#if defined (HISTORY) -static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); -#endif - -#if defined (READLINE) -static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *)); -static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *)); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); -#endif - -#if defined (ARRAY_VARS) -static SHELL_VAR *get_groupset __P((SHELL_VAR *)); - -static SHELL_VAR *build_hashcmd __P((SHELL_VAR *)); -static SHELL_VAR *get_hashcmd __P((SHELL_VAR *)); -static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *)); -# if defined (ALIAS) -static SHELL_VAR *build_aliasvar __P((SHELL_VAR *)); -static SHELL_VAR *get_aliasvar __P((SHELL_VAR *)); -static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *)); -# endif -#endif - -static SHELL_VAR *get_funcname __P((SHELL_VAR *)); -static SHELL_VAR *init_funcname_var __P((void)); - -static void initialize_dynamic_variables __P((void)); - -static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *)); -static SHELL_VAR *new_shell_variable __P((const char *)); -static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *)); -static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int)); - -static void dispose_variable_value __P((SHELL_VAR *)); -static void free_variable_hash_data __P((PTR_T)); - -static VARLIST *vlist_alloc __P((int)); -static VARLIST *vlist_realloc __P((VARLIST *, int)); -static void vlist_add __P((VARLIST *, SHELL_VAR *, int)); - -static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int)); - -static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **)); - -static SHELL_VAR **vapply __P((sh_var_map_func_t *)); -static SHELL_VAR **fapply __P((sh_var_map_func_t *)); - -static int visible_var __P((SHELL_VAR *)); -static int visible_and_exported __P((SHELL_VAR *)); -static int export_environment_candidate __P((SHELL_VAR *)); -static int local_and_exported __P((SHELL_VAR *)); -static int variable_in_context __P((SHELL_VAR *)); -#if defined (ARRAY_VARS) -static int visible_array_vars __P((SHELL_VAR *)); -#endif - -static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *)); -static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); -static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); - -static SHELL_VAR *bind_tempenv_variable __P((const char *, char *)); -static void push_temp_var __P((PTR_T)); -static void propagate_temp_var __P((PTR_T)); -static void dispose_temporary_env __P((sh_free_func_t *)); - -static inline char *mk_env_string __P((const char *, const char *, int)); -static char **make_env_array_from_var_list __P((SHELL_VAR **)); -static char **make_var_export_array __P((VAR_CONTEXT *)); -static char **make_func_export_array __P((void)); -static void add_temp_array_to_env __P((char **, int, int)); - -static int n_shell_variables __P((void)); -static int set_context __P((SHELL_VAR *)); - -static void push_func_var __P((PTR_T)); -static void push_exported_var __P((PTR_T)); - -static inline int find_special_var __P((const char *)); - -static void -create_variable_tables () -{ - if (shell_variables == 0) - { - shell_variables = global_variables = new_var_context ((char *)NULL, 0); - shell_variables->scope = 0; - shell_variables->table = hash_create (0); - } - - if (shell_functions == 0) - shell_functions = hash_create (0); - -#if defined (DEBUGGER) - if (shell_function_defs == 0) - shell_function_defs = hash_create (0); -#endif -} - -/* Initialize the shell variables from the current environment. - If PRIVMODE is nonzero, don't import functions from ENV or - parse $SHELLOPTS. */ -void -initialize_shell_variables (env, privmode) - char **env; - int privmode; -{ - char *name, *string, *temp_string; - int c, char_index, string_index, string_length, ro; - SHELL_VAR *temp_var; - - create_variable_tables (); - - for (string_index = 0; string = env[string_index++]; ) - { - char_index = 0; - name = string; - while ((c = *string++) && c != '=') - ; - if (string[-1] == '=') - char_index = string - name - 1; - - /* If there are weird things in the environment, like `=xxx' or a - string without an `=', just skip them. */ - if (char_index == 0) - continue; - - /* ASSERT(name[char_index] == '=') */ - name[char_index] = '\0'; - /* Now, name = env variable name, string = env variable value, and - char_index == strlen (name) */ - - temp_var = (SHELL_VAR *)NULL; - -#if defined (FUNCTION_IMPORT) - /* If exported function, define it now. Don't import functions from - the environment in privileged mode. */ - if (privmode == 0 && read_but_dont_execute == 0 && - STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) && - STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) && - STREQN ("() {", string, 4)) - { - size_t namelen; - char *tname; /* desired imported function name */ - - namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN; - - tname = name + BASHFUNC_PREFLEN; /* start of func name */ - tname[namelen] = '\0'; /* now tname == func name */ - - string_length = strlen (string); - temp_string = (char *)xmalloc (namelen + string_length + 2); - - memcpy (temp_string, tname, namelen); - temp_string[namelen] = ' '; - memcpy (temp_string + namelen + 1, string, string_length + 1); - - /* Don't import function names that are invalid identifiers from the - environment in posix mode, though we still allow them to be defined as - shell variables. */ - if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) - parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); - else - free (temp_string); /* parse_and_execute does this */ - - if (temp_var = find_function (tname)) - { - VSETATTR (temp_var, (att_exported|att_imported)); - array_needs_making = 1; - } - else - { - if (temp_var = bind_variable (name, string, 0)) - { - VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); - array_needs_making = 1; - } - last_command_exit_value = 1; - report_error (_("error importing function definition for `%s'"), tname); - } - - /* Restore original suffix */ - tname[namelen] = BASHFUNC_SUFFIX[0]; - } -#endif /* FUNCTION_IMPORT */ -#if defined (ARRAY_VARS) -# if ARRAY_EXPORT - /* Array variables may not yet be exported. */ - else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') - { - string_length = 1; - temp_string = extract_array_assignment_list (string, &string_length); - temp_var = assign_array_from_string (name, temp_string); - FREE (temp_string); - VSETATTR (temp_var, (att_exported | att_imported)); - array_needs_making = 1; - } -# endif /* ARRAY_EXPORT */ -#endif - else - { - ro = 0; - if (posixly_correct && STREQ (name, "SHELLOPTS")) - { - temp_var = find_variable ("SHELLOPTS"); - ro = temp_var && readonly_p (temp_var); - if (temp_var) - VUNSETATTR (temp_var, att_readonly); - } - temp_var = bind_variable (name, string, 0); - if (temp_var) - { - if (legal_identifier (name)) - VSETATTR (temp_var, (att_exported | att_imported)); - else - VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); - if (ro) - VSETATTR (temp_var, att_readonly); - array_needs_making = 1; - } - } - - name[char_index] = '='; - /* temp_var can be NULL if it was an exported function with a syntax - error (a different bug, but it still shouldn't dump core). */ - if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ - { - CACHE_IMPORTSTR (temp_var, name); - } - } - - set_pwd (); - - /* Set up initial value of $_ */ - temp_var = set_if_not ("_", dollar_vars[0]); - - /* Remember this pid. */ - dollar_dollar_pid = getpid (); - - /* Now make our own defaults in case the vars that we think are - important are missing. */ - temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE); -#if 0 - set_auto_export (temp_var); /* XXX */ -#endif - - temp_var = set_if_not ("TERM", "dumb"); -#if 0 - set_auto_export (temp_var); /* XXX */ -#endif - -#if defined (__QNX__) - /* set node id -- don't import it from the environment */ - { - char node_name[22]; -# if defined (__QNXNTO__) - netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); -# else - qnx_nidtostr (getnid (), node_name, sizeof (node_name)); -# endif - temp_var = bind_variable ("NODE", node_name, 0); - set_auto_export (temp_var); - } -#endif - - /* set up the prompts. */ - if (interactive_shell) - { -#if defined (PROMPT_STRING_DECODE) - set_if_not ("PS1", primary_prompt); -#else - if (current_user.uid == -1) - get_current_user_info (); - set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt); -#endif - set_if_not ("PS2", secondary_prompt); - } - set_if_not ("PS4", "+ "); - - /* Don't allow IFS to be imported from the environment. */ - temp_var = bind_variable ("IFS", " \t\n", 0); - setifs (temp_var); - - /* Magic machine types. Pretty convenient. */ - set_machine_vars (); - - /* Default MAILCHECK for interactive shells. Defer the creation of a - default MAILPATH until the startup files are read, because MAIL - names a mail file if MAILPATH is not set, and we should provide a - default only if neither is set. */ - if (interactive_shell) - { - temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); - VSETATTR (temp_var, att_integer); - } - - /* Do some things with shell level. */ - initialize_shell_level (); - - set_ppid (); - - /* Initialize the `getopts' stuff. */ - temp_var = bind_variable ("OPTIND", "1", 0); - VSETATTR (temp_var, att_integer); - getopts_reset (0); - bind_variable ("OPTERR", "1", 0); - sh_opterr = 1; - - if (login_shell == 1 && posixly_correct == 0) - set_home_var (); - - /* Get the full pathname to THIS shell, and set the BASH variable - to it. */ - name = get_bash_name (); - temp_var = bind_variable ("BASH", name, 0); - free (name); - - /* Make the exported environment variable SHELL be the user's login - shell. Note that the `tset' command looks at this variable - to determine what style of commands to output; if it ends in "csh", - then C-shell commands are output, else Bourne shell commands. */ - set_shell_var (); - - /* Make a variable called BASH_VERSION which contains the version info. */ - bind_variable ("BASH_VERSION", shell_version_string (), 0); -#if defined (ARRAY_VARS) - make_vers_array (); -#endif - - if (command_execution_string) - bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0); - - /* Find out if we're supposed to be in Posix.2 mode via an - environment variable. */ - temp_var = find_variable ("POSIXLY_CORRECT"); - if (!temp_var) - temp_var = find_variable ("POSIX_PEDANTIC"); - if (temp_var && imported_p (temp_var)) - sv_strict_posix (temp_var->name); - -#if defined (HISTORY) - /* Set history variables to defaults, and then do whatever we would - do if the variable had just been set. Do this only in the case - that we are remembering commands on the history list. */ - if (remember_on_history) - { - name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0); - - set_if_not ("HISTFILE", name); - free (name); - } -#endif /* HISTORY */ - - /* Seed the random number generator. */ - seedrand (); - - /* Handle some "special" variables that we may have inherited from a - parent shell. */ - if (interactive_shell) - { - temp_var = find_variable ("IGNOREEOF"); - if (!temp_var) - temp_var = find_variable ("ignoreeof"); - if (temp_var && imported_p (temp_var)) - sv_ignoreeof (temp_var->name); - } - -#if defined (HISTORY) - if (interactive_shell && remember_on_history) - { - sv_history_control ("HISTCONTROL"); - sv_histignore ("HISTIGNORE"); - sv_histtimefmt ("HISTTIMEFORMAT"); - } -#endif /* HISTORY */ - -#if defined (READLINE) && defined (STRICT_POSIX) - /* POSIXLY_CORRECT will only be 1 here if the shell was compiled - -DSTRICT_POSIX */ - if (interactive_shell && posixly_correct && no_line_editing == 0) - rl_prefer_env_winsize = 1; -#endif /* READLINE && STRICT_POSIX */ - - /* - * 24 October 2001 - * - * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT - * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in - * isnetconn() to avoid running the startup files more often than wanted. - * That will, of course, only work if the user's login shell is bash, so - * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined - * in config-top.h. - */ -#if 0 - temp_var = find_variable ("SSH_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } - temp_var = find_variable ("SSH2_CLIENT"); - if (temp_var && imported_p (temp_var)) - { - VUNSETATTR (temp_var, att_exported); - array_needs_making = 1; - } -#endif - - /* Get the user's real and effective user ids. */ - uidset (); - - temp_var = find_variable ("BASH_XTRACEFD"); - if (temp_var && imported_p (temp_var)) - sv_xtracefd (temp_var->name); - - /* Initialize the dynamic variables, and seed their values. */ - initialize_dynamic_variables (); -} - -/* **************************************************************** */ -/* */ -/* Setting values for special shell variables */ -/* */ -/* **************************************************************** */ - -static void -set_machine_vars () -{ - SHELL_VAR *temp_var; - - temp_var = set_if_not ("HOSTTYPE", HOSTTYPE); - temp_var = set_if_not ("OSTYPE", OSTYPE); - temp_var = set_if_not ("MACHTYPE", MACHTYPE); - - temp_var = set_if_not ("HOSTNAME", current_host_name); -} - -/* Set $HOME to the information in the password file if we didn't get - it from the environment. */ - -/* This function is not static so the tilde and readline libraries can - use it. */ -char * -sh_get_home_dir () -{ - if (current_user.home_dir == 0) - get_current_user_info (); - return current_user.home_dir; -} - -static void -set_home_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("HOME"); - if (temp_var == 0) - temp_var = bind_variable ("HOME", sh_get_home_dir (), 0); -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -/* Set $SHELL to the user's login shell if it is not already set. Call - get_current_user_info if we haven't already fetched the shell. */ -static void -set_shell_var () -{ - SHELL_VAR *temp_var; - - temp_var = find_variable ("SHELL"); - if (temp_var == 0) - { - if (current_user.shell == 0) - get_current_user_info (); - temp_var = bind_variable ("SHELL", current_user.shell, 0); - } -#if 0 - VSETATTR (temp_var, att_exported); -#endif -} - -static char * -get_bash_name () -{ - char *name; - - if ((login_shell == 1) && RELPATH(shell_name)) - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - else if (ABSPATH(shell_name)) - name = savestring (shell_name); - else if (shell_name[0] == '.' && shell_name[1] == '/') - { - /* Fast path for common case. */ - char *cdir; - int len; - - cdir = get_string_value ("PWD"); - if (cdir) - { - len = strlen (cdir); - name = (char *)xmalloc (len + strlen (shell_name) + 1); - strcpy (name, cdir); - strcpy (name + len, shell_name + 1); - } - else - name = savestring (shell_name); - } - else - { - char *tname; - int s; - - tname = find_user_command (shell_name); - - if (tname == 0) - { - /* Try the current directory. If there is not an executable - there, just punt and use the login shell. */ - s = file_status (shell_name); - if (s & FS_EXECABLE) - { - tname = make_absolute (shell_name, get_string_value ("PWD")); - if (*shell_name == '.') - { - name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - if (name == 0) - name = tname; - else - free (tname); - } - else - name = tname; - } - else - { - if (current_user.shell == 0) - get_current_user_info (); - name = savestring (current_user.shell); - } - } - else - { - name = full_pathname (tname); - free (tname); - } - } - - return (name); -} - -void -adjust_shell_level (change) - int change; -{ - char new_level[5], *old_SHLVL; - intmax_t old_level; - SHELL_VAR *temp_var; - - old_SHLVL = get_string_value ("SHLVL"); - if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0) - old_level = 0; - - shell_level = old_level + change; - if (shell_level < 0) - shell_level = 0; - else if (shell_level > 1000) - { - internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); - shell_level = 1; - } - - /* We don't need the full generality of itos here. */ - if (shell_level < 10) - { - new_level[0] = shell_level + '0'; - new_level[1] = '\0'; - } - else if (shell_level < 100) - { - new_level[0] = (shell_level / 10) + '0'; - new_level[1] = (shell_level % 10) + '0'; - new_level[2] = '\0'; - } - else if (shell_level < 1000) - { - new_level[0] = (shell_level / 100) + '0'; - old_level = shell_level % 100; - new_level[1] = (old_level / 10) + '0'; - new_level[2] = (old_level % 10) + '0'; - new_level[3] = '\0'; - } - - temp_var = bind_variable ("SHLVL", new_level, 0); - set_auto_export (temp_var); -} - -static void -initialize_shell_level () -{ - adjust_shell_level (1); -} - -/* If we got PWD from the environment, update our idea of the current - working directory. In any case, make sure that PWD exists before - checking it. It is possible for getcwd () to fail on shell startup, - and in that case, PWD would be undefined. If this is an interactive - login shell, see if $HOME is the current working directory, and if - that's not the same string as $PWD, set PWD=$HOME. */ - -void -set_pwd () -{ - SHELL_VAR *temp_var, *home_var; - char *temp_string, *home_string; - - home_var = find_variable ("HOME"); - home_string = home_var ? value_cell (home_var) : (char *)NULL; - - temp_var = find_variable ("PWD"); - if (temp_var && imported_p (temp_var) && - (temp_string = value_cell (temp_var)) && - same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - set_working_directory (temp_string); - else if (home_string && interactive_shell && login_shell && - same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - { - set_working_directory (home_string); - temp_var = bind_variable ("PWD", home_string, 0); - set_auto_export (temp_var); - } - else - { - temp_string = get_working_directory ("shell-init"); - if (temp_string) - { - temp_var = bind_variable ("PWD", temp_string, 0); - set_auto_export (temp_var); - free (temp_string); - } - } - - /* According to the Single Unix Specification, v2, $OLDPWD is an - `environment variable' and therefore should be auto-exported. - Make a dummy invisible variable for OLDPWD, and mark it as exported. */ - temp_var = bind_variable ("OLDPWD", (char *)NULL, 0); - VSETATTR (temp_var, (att_exported | att_invisible)); -} - -/* Make a variable $PPID, which holds the pid of the shell's parent. */ -void -set_ppid () -{ - char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name; - SHELL_VAR *temp_var; - - name = inttostr (getppid (), namebuf, sizeof(namebuf)); - temp_var = find_variable ("PPID"); - if (temp_var) - VUNSETATTR (temp_var, (att_readonly | att_exported)); - temp_var = bind_variable ("PPID", name, 0); - VSETATTR (temp_var, (att_readonly | att_integer)); -} - -static void -uidset () -{ - char buff[INT_STRLEN_BOUND(uid_t) + 1], *b; - register SHELL_VAR *v; - - b = inttostr (current_user.uid, buff, sizeof (buff)); - v = find_variable ("UID"); - if (v == 0) - { - v = bind_variable ("UID", b, 0); - VSETATTR (v, (att_readonly | att_integer)); - } - - if (current_user.euid != current_user.uid) - b = inttostr (current_user.euid, buff, sizeof (buff)); - - v = find_variable ("EUID"); - if (v == 0) - { - v = bind_variable ("EUID", b, 0); - VSETATTR (v, (att_readonly | att_integer)); - } -} - -#if defined (ARRAY_VARS) -static void -make_vers_array () -{ - SHELL_VAR *vv; - ARRAY *av; - char *s, d[32], b[INT_STRLEN_BOUND(int) + 1]; - - unbind_variable ("BASH_VERSINFO"); - - vv = make_new_array_variable ("BASH_VERSINFO"); - av = array_cell (vv); - strcpy (d, dist_version); - s = strchr (d, '.'); - if (s) - *s++ = '\0'; - array_insert (av, 0, d); - array_insert (av, 1, s); - s = inttostr (patch_level, b, sizeof (b)); - array_insert (av, 2, s); - s = inttostr (build_version, b, sizeof (b)); - array_insert (av, 3, s); - array_insert (av, 4, release_status); - array_insert (av, 5, MACHTYPE); - - VSETATTR (vv, att_readonly); -} -#endif /* ARRAY_VARS */ - -/* Set the environment variables $LINES and $COLUMNS in response to - a window size change. */ -void -sh_set_lines_and_columns (lines, cols) - int lines, cols; -{ - char val[INT_STRLEN_BOUND(int) + 1], *v; - -#if defined (READLINE) - /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ - if (winsize_assignment) - return; -#endif - - v = inttostr (lines, val, sizeof (val)); - bind_variable ("LINES", v, 0); - - v = inttostr (cols, val, sizeof (val)); - bind_variable ("COLUMNS", v, 0); -} - -/* **************************************************************** */ -/* */ -/* Printing variables and values */ -/* */ -/* **************************************************************** */ - -/* Print LIST (a list of shell variables) to stdout in such a way that - they can be read back in. */ -void -print_var_list (list) - register SHELL_VAR **list; -{ - register int i; - register SHELL_VAR *var; - - for (i = 0; list && (var = list[i]); i++) - if (invisible_p (var) == 0) - print_assignment (var); -} - -/* Print LIST (a list of shell functions) to stdout in such a way that - they can be read back in. */ -void -print_func_list (list) - register SHELL_VAR **list; -{ - register int i; - register SHELL_VAR *var; - - for (i = 0; list && (var = list[i]); i++) - { - printf ("%s ", var->name); - print_var_function (var); - printf ("\n"); - } -} - -/* Print the value of a single SHELL_VAR. No newline is - output, but the variable is printed in such a way that - it can be read back in. */ -void -print_assignment (var) - SHELL_VAR *var; -{ - if (var_isset (var) == 0) - return; - - if (function_p (var)) - { - printf ("%s", var->name); - print_var_function (var); - printf ("\n"); - } -#if defined (ARRAY_VARS) - else if (array_p (var)) - print_array_assignment (var, 0); - else if (assoc_p (var)) - print_assoc_assignment (var, 0); -#endif /* ARRAY_VARS */ - else - { - printf ("%s=", var->name); - print_var_value (var, 1); - printf ("\n"); - } -} - -/* Print the value cell of VAR, a shell variable. Do not print - the name, nor leading/trailing newline. If QUOTE is non-zero, - and the value contains shell metacharacters, quote the value - in such a way that it can be read back in. */ -void -print_var_value (var, quote) - SHELL_VAR *var; - int quote; -{ - char *t; - - if (var_isset (var) == 0) - return; - - if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var))) - { - t = ansic_quote (value_cell (var), 0, (int *)0); - printf ("%s", t); - free (t); - } - else if (quote && sh_contains_shell_metas (value_cell (var))) - { - t = sh_single_quote (value_cell (var)); - printf ("%s", t); - free (t); - } - else - printf ("%s", value_cell (var)); -} - -/* Print the function cell of VAR, a shell variable. Do not - print the name, nor leading/trailing newline. */ -void -print_var_function (var) - SHELL_VAR *var; -{ - char *x; - - if (function_p (var) && var_isset (var)) - { - x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); - printf ("%s", x); - } -} - -/* **************************************************************** */ -/* */ -/* Dynamic Variables */ -/* */ -/* **************************************************************** */ - -/* DYNAMIC VARIABLES - - These are variables whose values are generated anew each time they are - referenced. These are implemented using a pair of function pointers - in the struct variable: assign_func, which is called from bind_variable - and, if arrays are compiled into the shell, some of the functions in - arrayfunc.c, and dynamic_value, which is called from find_variable. - - assign_func is called from bind_variable_internal, if - bind_variable_internal discovers that the variable being assigned to - has such a function. The function is called as - SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind) - and the (SHELL_VAR *)temp is returned as the value of bind_variable. It - is usually ENTRY (self). IND is an index for an array variable, and - unused otherwise. - - dynamic_value is called from find_variable_internal to return a `new' - value for the specified dynamic varible. If this function is NULL, - the variable is treated as a `normal' shell variable. If it is not, - however, then this function is called like this: - tempvar = (*(var->dynamic_value)) (var); - - Sometimes `tempvar' will replace the value of `var'. Other times, the - shell will simply use the string value. Pretty object-oriented, huh? - - Be warned, though: if you `unset' a special variable, it loses its - special meaning, even if you subsequently set it. - - The special assignment code would probably have been better put in - subst.c: do_assignment_internal, in the same style as - stupidly_hack_special_variables, but I wanted the changes as - localized as possible. */ - -#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ - do \ - { \ - v = bind_variable (var, (val), 0); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_array_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_assoc_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -static SHELL_VAR * -null_assign (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - return (self); -} - -#if defined (ARRAY_VARS) -static SHELL_VAR * -null_array_assign (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - return (self); -} -#endif - -/* Degenerate `dynamic_value' function; just returns what's passed without - manipulation. */ -static SHELL_VAR * -get_self (self) - SHELL_VAR *self; -{ - return (self); -} - -#if defined (ARRAY_VARS) -/* A generic dynamic array variable initializer. Initialize array variable - NAME with dynamic value function GETFUNC and assignment function SETFUNC. */ -static SHELL_VAR * -init_dynamic_array_var (name, getfunc, setfunc, attrs) - char *name; - sh_var_value_func_t *getfunc; - sh_var_assign_func_t *setfunc; - int attrs; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v) - return (v); - INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc); - if (attrs) - VSETATTR (v, attrs); - return v; -} - -static SHELL_VAR * -init_dynamic_assoc_var (name, getfunc, setfunc, attrs) - char *name; - sh_var_value_func_t *getfunc; - sh_var_assign_func_t *setfunc; - int attrs; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v) - return (v); - INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc); - if (attrs) - VSETATTR (v, attrs); - return v; -} -#endif - -/* The value of $SECONDS. This is the number of seconds since shell - invocation, or, the number of seconds since the last assignment + the - value of the last assignment. */ -static intmax_t seconds_value_assigned; - -static SHELL_VAR * -assign_seconds (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - if (legal_number (value, &seconds_value_assigned) == 0) - seconds_value_assigned = 0; - shell_start_time = NOW; - return (self); -} - -static SHELL_VAR * -get_seconds (var) - SHELL_VAR *var; -{ - time_t time_since_start; - char *p; - - time_since_start = NOW - shell_start_time; - p = itos(seconds_value_assigned + time_since_start); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -init_seconds_var () -{ - SHELL_VAR *v; - - v = find_variable ("SECONDS"); - if (v) - { - if (legal_number (value_cell(v), &seconds_value_assigned) == 0) - seconds_value_assigned = 0; - } - INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds); - return v; -} - -/* The random number seed. You can change this by setting RANDOM. */ -static unsigned long rseed = 1; -static int last_random_value; -static int seeded_subshell = 0; - -/* A linear congruential random number generator based on the example - one in the ANSI C standard. This one isn't very good, but a more - complicated one is overkill. */ - -/* Returns a pseudo-random number between 0 and 32767. */ -static int -brand () -{ - /* From "Random number generators: good ones are hard to find", - Park and Miller, Communications of the ACM, vol. 31, no. 10, - October 1988, p. 1195. filtered through FreeBSD */ - long h, l; - - /* Can't seed with 0. */ - if (rseed == 0) - rseed = 123459876; - h = rseed / 127773; - l = rseed % 127773; - rseed = 16807 * l - 2836 * h; -#if 0 - if (rseed < 0) - rseed += 0x7fffffff; -#endif - return ((unsigned int)(rseed & 32767)); /* was % 32768 */ -} - -/* Set the random number generator seed to SEED. */ -static void -sbrand (seed) - unsigned long seed; -{ - rseed = seed; - last_random_value = 0; -} - -static void -seedrand () -{ - struct timeval tv; - - gettimeofday (&tv, NULL); - sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ()); -} - -static SHELL_VAR * -assign_random (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - sbrand (strtoul (value, (char **)NULL, 10)); - if (subshell_environment) - seeded_subshell = getpid (); - return (self); -} - -int -get_random_number () -{ - int rv, pid; - - /* Reset for command and process substitution. */ - pid = getpid (); - if (subshell_environment && seeded_subshell != pid) - { - seedrand (); - seeded_subshell = pid; - } - - do - rv = brand (); - while (rv == last_random_value); - return rv; -} - -static SHELL_VAR * -get_random (var) - SHELL_VAR *var; -{ - int rv; - char *p; - - rv = get_random_number (); - last_random_value = rv; - p = itos (rv); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_lineno (var, value, unused, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - line_number = line_number_base = new_value; - return var; -} - -/* Function which returns the current line number. */ -static SHELL_VAR * -get_lineno (var) - SHELL_VAR *var; -{ - char *p; - int ln; - - ln = executing_line_number (); - p = itos (ln); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -assign_subshell (var, value, unused, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - intmax_t new_value; - - if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0) - new_value = 0; - subshell_level = new_value; - return var; -} - -static SHELL_VAR * -get_subshell (var) - SHELL_VAR *var; -{ - char *p; - - p = itos (subshell_level); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bashpid (var) - SHELL_VAR *var; -{ - int pid; - char *p; - - pid = getpid (); - p = itos (pid); - - FREE (value_cell (var)); - VSETATTR (var, att_integer|att_readonly); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bash_command (var) - SHELL_VAR *var; -{ - char *p; - - if (the_printed_command_except_trap) - p = savestring (the_printed_command_except_trap); - else - { - p = (char *)xmalloc (1); - p[0] = '\0'; - } - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} - -#if defined (HISTORY) -static SHELL_VAR * -get_histcmd (var) - SHELL_VAR *var; -{ - char *p; - - p = itos (history_number ()); - FREE (value_cell (var)); - var_setvalue (var, p); - return (var); -} -#endif - -#if defined (READLINE) -/* When this function returns, VAR->value points to malloced memory. */ -static SHELL_VAR * -get_comp_wordbreaks (var) - SHELL_VAR *var; -{ - /* If we don't have anything yet, assign a default value. */ - if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0) - enable_hostname_completion (perform_hostname_completion); - - FREE (value_cell (var)); - var_setvalue (var, savestring (rl_completer_word_break_characters)); - - return (var); -} - -/* When this function returns, rl_completer_word_break_characters points to - malloced memory. */ -static SHELL_VAR * -assign_comp_wordbreaks (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - if (rl_completer_word_break_characters && - rl_completer_word_break_characters != rl_basic_word_break_characters) - free (rl_completer_word_break_characters); - - rl_completer_word_break_characters = savestring (value); - return self; -} -#endif /* READLINE */ - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR * -assign_dirstack (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - set_dirstack_element (ind, 1, value); - return self; -} - -static SHELL_VAR * -get_dirstack (self) - SHELL_VAR *self; -{ - ARRAY *a; - WORD_LIST *l; - - l = get_directory_stack (0); - a = array_from_word_list (l); - array_dispose (array_cell (self)); - dispose_words (l); - var_setarray (self, a); - return self; -} -#endif /* PUSHD AND POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) -/* We don't want to initialize the group set with a call to getgroups() - unless we're asked to, but we only want to do it once. */ -static SHELL_VAR * -get_groupset (self) - SHELL_VAR *self; -{ - register int i; - int ng; - ARRAY *a; - static char **group_set = (char **)NULL; - - if (group_set == 0) - { - group_set = get_group_list (&ng); - a = array_cell (self); - for (i = 0; i < ng; i++) - array_insert (a, i, group_set[i]); - } - return (self); -} - -static SHELL_VAR * -build_hashcmd (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (hashed_filenames->nbuckets); - for (i = 0; i < hashed_filenames->nbuckets; i++) - { - for (item = hash_items (i, hashed_filenames); item; item = item->next) - { - k = savestring (item->key); - v = pathdata(item)->path; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_hashcmd (self) - SHELL_VAR *self; -{ - build_hashcmd (self); - return (self); -} - -static SHELL_VAR * -assign_hashcmd (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - phash_insert (key, value, 0, 0); - return (build_hashcmd (self)); -} - -#if defined (ALIAS) -static SHELL_VAR * -build_aliasvar (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (aliases == 0 || HASH_ENTRIES (aliases) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (aliases->nbuckets); - for (i = 0; i < aliases->nbuckets; i++) - { - for (item = hash_items (i, aliases); item; item = item->next) - { - k = savestring (item->key); - v = ((alias_t *)(item->data))->value; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_aliasvar (self) - SHELL_VAR *self; -{ - build_aliasvar (self); - return (self); -} - -static SHELL_VAR * -assign_aliasvar (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - add_alias (key, value); - return (build_aliasvar (self)); -} -#endif /* ALIAS */ - -#endif /* ARRAY_VARS */ - -/* If ARRAY_VARS is not defined, this just returns the name of any - currently-executing function. If we have arrays, it's a call stack. */ -static SHELL_VAR * -get_funcname (self) - SHELL_VAR *self; -{ -#if ! defined (ARRAY_VARS) - char *t; - if (variable_context && this_shell_function) - { - FREE (value_cell (self)); - t = savestring (this_shell_function->name); - var_setvalue (self, t); - } -#endif - return (self); -} - -void -make_funcname_visible (on_or_off) - int on_or_off; -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v == 0 || v->dynamic_value == 0) - return; - - if (on_or_off) - VUNSETATTR (v, att_invisible); - else - VSETATTR (v, att_invisible); -} - -static SHELL_VAR * -init_funcname_var () -{ - SHELL_VAR *v; - - v = find_variable ("FUNCNAME"); - if (v) - return v; -#if defined (ARRAY_VARS) - INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign); -#else - INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign); -#endif - VSETATTR (v, att_invisible|att_noassign); - return v; -} - -static void -initialize_dynamic_variables () -{ - SHELL_VAR *v; - - v = init_seconds_var (); - - INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL); - INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell); - - INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random); - VSETATTR (v, att_integer); - INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); - VSETATTR (v, att_integer); - - INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign); - VSETATTR (v, att_integer|att_readonly); - -#if defined (HISTORY) - INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); - VSETATTR (v, att_integer); -#endif - -#if defined (READLINE) - INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) - v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0); -#endif /* PUSHD_AND_POPD && ARRAY_VARS */ - -#if defined (ARRAY_VARS) - v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); - -# if defined (DEBUGGER) - v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset); -# endif /* DEBUGGER */ - v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); - - v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); -# if defined (ALIAS) - v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); -# endif -#endif - - v = init_funcname_var (); -} - -/* **************************************************************** */ -/* */ -/* Retrieving variables and values */ -/* */ -/* **************************************************************** */ - -/* How to get a pointer to the shell variable or function named NAME. - HASHED_VARS is a pointer to the hash table containing the list - of interest (either variables or functions). */ - -static SHELL_VAR * -hash_lookup (name, hashed_vars) - const char *name; - HASH_TABLE *hashed_vars; -{ - BUCKET_CONTENTS *bucket; - - bucket = hash_search (name, hashed_vars, 0); - /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that - table. */ - if (bucket) - last_table_searched = hashed_vars; - return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL); -} - -SHELL_VAR * -var_lookup (name, vcontext) - const char *name; - VAR_CONTEXT *vcontext; -{ - VAR_CONTEXT *vc; - SHELL_VAR *v; - - v = (SHELL_VAR *)NULL; - for (vc = vcontext; vc; vc = vc->down) - if (v = hash_lookup (name, vc->table)) - break; - - return v; -} - -/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero, - then also search the temporarily built list of exported variables. - The lookup order is: - temporary_env - shell_variables list -*/ - -SHELL_VAR * -find_variable_internal (name, flags) - const char *name; - int flags; -{ - SHELL_VAR *var; - int search_tempenv, force_tempenv; - VAR_CONTEXT *vc; - - var = (SHELL_VAR *)NULL; - - force_tempenv = (flags & FV_FORCETEMPENV); - - /* If explicitly requested, first look in the temporary environment for - the variable. This allows constructs such as "foo=x eval 'echo $foo'" - to get the `exported' value of $foo. This happens if we are executing - a function or builtin, or if we are looking up a variable in a - "subshell environment". */ - search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment); - - if (search_tempenv && temporary_env) - var = hash_lookup (name, temporary_env); - - if (var == 0) - { - if ((flags & FV_SKIPINVISIBLE) == 0) - var = var_lookup (name, shell_variables); - else - { - /* essentially var_lookup expanded inline so we can check for - att_invisible */ - for (vc = shell_variables; vc; vc = vc->down) - { - var = hash_lookup (name, vc->table); - if (var && invisible_p (var)) - var = 0; - if (var) - break; - } - } - } - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -/* Look up and resolve the chain of nameref variables starting at V all the - way to NULL or non-nameref. */ -SHELL_VAR * -find_variable_nameref (v) - SHELL_VAR *v; -{ - int level, flags; - char *newname; - SHELL_VAR *orig, *oldv; - - level = 0; - orig = v; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)0); - oldv = v; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (newname, flags); - if (v == orig || v == oldv) - { - internal_warning (_("%s: circular name reference"), orig->name); - return ((SHELL_VAR *)0); - } - } - return v; -} - -/* Resolve the chain of nameref variables for NAME. XXX - could change later */ -SHELL_VAR * -find_variable_last_nameref (name) - const char *name; -{ - SHELL_VAR *v, *nv; - char *newname; - int level, flags; - - nv = v = find_variable_noref (name); - level = 0; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)0); - nv = v; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (newname, flags); - } - return nv; -} - -/* Resolve the chain of nameref variables for NAME. XXX - could change later */ -SHELL_VAR * -find_global_variable_last_nameref (name) - const char *name; -{ - SHELL_VAR *v, *nv; - char *newname; - int level; - - nv = v = find_global_variable_noref (name); - level = 0; - while (v && nameref_p (v)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)0); /* error message here? */ - newname = nameref_cell (v); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)0); - nv = v; - v = find_global_variable_noref (newname); - } - return nv; -} - -static SHELL_VAR * -find_nameref_at_context (v, vc) - SHELL_VAR *v; - VAR_CONTEXT *vc; -{ - SHELL_VAR *nv, *nv2; - VAR_CONTEXT *nvc; - char *newname; - int level; - - nv = v; - level = 1; - while (nv && nameref_p (nv)) - { - level++; - if (level > NAMEREF_MAX) - return ((SHELL_VAR *)NULL); - newname = nameref_cell (nv); - if (newname == 0 || *newname == '\0') - return ((SHELL_VAR *)NULL); - nv2 = hash_lookup (newname, vc->table); - if (nv2 == 0) - break; - nv = nv2; - } - return nv; -} - -/* Do nameref resolution from the VC, which is the local context for some - function or builtin, `up' the chain to the global variables context. If - NVCP is not NULL, return the variable context where we finally ended the - nameref resolution (so the bind_variable_internal can use the correct - variable context and hash table). */ -static SHELL_VAR * -find_variable_nameref_context (v, vc, nvcp) - SHELL_VAR *v; - VAR_CONTEXT *vc; - VAR_CONTEXT **nvcp; -{ - SHELL_VAR *nv, *nv2; - VAR_CONTEXT *nvc; - - /* Look starting at the current context all the way `up' */ - for (nv = v, nvc = vc; nvc; nvc = nvc->down) - { - nv2 = find_nameref_at_context (nv, nvc); - if (nv2 == 0) - continue; - nv = nv2; - if (*nvcp) - *nvcp = nvc; - if (nameref_p (nv) == 0) - break; - } - return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv); -} - -/* Do nameref resolution from the VC, which is the local context for some - function or builtin, `up' the chain to the global variables context. If - NVCP is not NULL, return the variable context where we finally ended the - nameref resolution (so the bind_variable_internal can use the correct - variable context and hash table). */ -static SHELL_VAR * -find_variable_last_nameref_context (v, vc, nvcp) - SHELL_VAR *v; - VAR_CONTEXT *vc; - VAR_CONTEXT **nvcp; -{ - SHELL_VAR *nv, *nv2; - VAR_CONTEXT *nvc; - - /* Look starting at the current context all the way `up' */ - for (nv = v, nvc = vc; nvc; nvc = nvc->down) - { - nv2 = find_nameref_at_context (nv, nvc); - if (nv2 == 0) - continue; - nv = nv2; - if (*nvcp) - *nvcp = nvc; - } - return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL); -} - -/* Find a variable, forcing a search of the temporary environment first */ -SHELL_VAR * -find_variable_tempenv (name) - const char *name; -{ - SHELL_VAR *var; - - var = find_variable_internal (name, FV_FORCETEMPENV); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - return (var); -} - -/* Find a variable, not forcing a search of the temporary environment first */ -SHELL_VAR * -find_variable_notempenv (name) - const char *name; -{ - SHELL_VAR *var; - - var = find_variable_internal (name, 0); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - return (var); -} - -SHELL_VAR * -find_global_variable (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, global_variables); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -SHELL_VAR * -find_global_variable_noref (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, global_variables); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -SHELL_VAR * -find_shell_variable (name) - const char *name; -{ - SHELL_VAR *var; - - var = var_lookup (name, shell_variables); - if (var && nameref_p (var)) - var = find_variable_nameref (var); - - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var); -} - -/* Look up the variable entry named NAME. Returns the entry or NULL. */ -SHELL_VAR * -find_variable (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -/* Find the first instance of NAME in the variable context chain; return first - one found without att_invisible set; return 0 if no non-invisible instances - found. */ -SHELL_VAR * -find_variable_no_invisible (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = FV_SKIPINVISIBLE; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -/* Find the first instance of NAME in the variable context chain; return first - one found even if att_invisible set. */ -SHELL_VAR * -find_variable_for_assignment (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - last_table_searched = 0; - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - if (v && nameref_p (v)) - v = find_variable_nameref (v); - return v; -} - -SHELL_VAR * -find_variable_noref (name) - const char *name; -{ - SHELL_VAR *v; - int flags; - - flags = 0; - if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) - flags |= FV_FORCETEMPENV; - v = find_variable_internal (name, flags); - return v; -} - -/* Look up the function entry whose name matches STRING. - Returns the entry or NULL. */ -SHELL_VAR * -find_function (name) - const char *name; -{ - return (hash_lookup (name, shell_functions)); -} - -/* Find the function definition for the shell function named NAME. Returns - the entry or NULL. */ -FUNCTION_DEF * -find_function_def (name) - const char *name; -{ -#if defined (DEBUGGER) - return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); -#else - return ((FUNCTION_DEF *)0); -#endif -} - -/* Return the value of VAR. VAR is assumed to have been the result of a - lookup without any subscript, if arrays are compiled into the shell. */ -char * -get_variable_value (var) - SHELL_VAR *var; -{ - if (var == 0) - return ((char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (var)) - return (array_reference (array_cell (var), 0)); - else if (assoc_p (var)) - return (assoc_reference (assoc_cell (var), "0")); -#endif - else - return (value_cell (var)); -} - -/* Return the string value of a variable. Return NULL if the variable - doesn't exist. Don't cons a new string. This is a potential memory - leak if the variable is found in the temporary environment. Since - functions and variables have separate name spaces, returns NULL if - var_name is a shell function only. */ -char * -get_string_value (var_name) - const char *var_name; -{ - SHELL_VAR *var; - - var = find_variable (var_name); - return ((var) ? get_variable_value (var) : (char *)NULL); -} - -/* This is present for use by the tilde and readline libraries. */ -char * -sh_get_env_value (v) - const char *v; -{ - return get_string_value (v); -} - -/* **************************************************************** */ -/* */ -/* Creating and setting variables */ -/* */ -/* **************************************************************** */ - -/* Set NAME to VALUE if NAME has no value. */ -SHELL_VAR * -set_if_not (name, value) - char *name, *value; -{ - SHELL_VAR *v; - - if (shell_variables == 0) - create_variable_tables (); - - v = find_variable (name); - if (v == 0) - v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); - return (v); -} - -/* Create a local variable referenced by NAME. */ -SHELL_VAR * -make_local_variable (name) - const char *name; -{ - SHELL_VAR *new_var, *old_var; - VAR_CONTEXT *vc; - int was_tmpvar; - char *tmp_value; - - /* local foo; local foo; is a no-op. */ - old_var = find_variable (name); - if (old_var && local_p (old_var) && old_var->context == variable_context) - return (old_var); - - was_tmpvar = old_var && tempvar_p (old_var); - /* If we're making a local variable in a shell function, the temporary env - has already been merged into the function's variable context stack. We - can assume that a temporary var in the same context appears in the same - VAR_CONTEXT and can safely be returned without creating a new variable - (which results in duplicate names in the same VAR_CONTEXT->table */ - /* We can't just test tmpvar_p because variables in the temporary env given - to a shell function appear in the function's local variable VAR_CONTEXT - but retain their tempvar attribute. We want temporary variables that are - found in temporary_env, hence the test for last_table_searched, which is - set in hash_lookup and only (so far) checked here. */ - if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env) - { - VUNSETATTR (old_var, att_invisible); /* XXX */ - return (old_var); - } - if (was_tmpvar) - tmp_value = value_cell (old_var); - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("make_local_variable: no function context at current scope")); - return ((SHELL_VAR *)NULL); - } - else if (vc->table == 0) - vc->table = hash_create (TEMPENV_HASH_BUCKETS); - - /* Since this is called only from the local/declare/typeset code, we can - call builtin_error here without worry (of course, it will also work - for anything that sets this_command_name). Variables with the `noassign' - attribute may not be made local. The test against old_var's context - level is to disallow local copies of readonly global variables (since I - believe that this could be a security hole). Readonly copies of calling - function local variables are OK. */ - if (old_var && (noassign_p (old_var) || - (readonly_p (old_var) && old_var->context == 0))) - { - if (readonly_p (old_var)) - sh_readonly (name); - else if (noassign_p (old_var)) - builtin_error (_("%s: variable may not be assigned value"), name); -#if 0 - /* Let noassign variables through with a warning */ - if (readonly_p (old_var)) -#endif - return ((SHELL_VAR *)NULL); - } - - if (old_var == 0) - new_var = make_new_variable (name, vc->table); - else - { - new_var = make_new_variable (name, vc->table); - - /* If we found this variable in one of the temporary environments, - inherit its value. Watch to see if this causes problems with - things like `x=4 local x'. XXX - see above for temporary env - variables with the same context level as variable_context */ - /* XXX - we should only do this if the variable is not an array. */ - if (was_tmpvar) - var_setvalue (new_var, savestring (tmp_value)); - - new_var->attributes = exported_p (old_var) ? att_exported : 0; - } - - vc->flags |= VC_HASLOCAL; - - new_var->context = variable_context; - VSETATTR (new_var, att_local); - - if (ifsname (name)) - setifs (new_var); - - if (was_tmpvar == 0 && no_invisible_vars == 0) - VSETATTR (new_var, att_invisible); /* XXX */ - return (new_var); -} - -/* Create a new shell variable with name NAME. */ -static SHELL_VAR * -new_shell_variable (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - - entry->name = savestring (name); - var_setvalue (entry, (char *)NULL); - CLEAR_EXPORTSTR (entry); - - entry->dynamic_value = (sh_var_value_func_t *)NULL; - entry->assign_func = (sh_var_assign_func_t *)NULL; - - entry->attributes = 0; - - /* Always assume variables are to be made at toplevel! - make_local_variable has the responsibility of changing the - variable context. */ - entry->context = 0; - - return (entry); -} - -/* Create a new shell variable with name NAME and add it to the hash table - TABLE. */ -static SHELL_VAR * -make_new_variable (name, table) - const char *name; - HASH_TABLE *table; -{ - SHELL_VAR *entry; - BUCKET_CONTENTS *elt; - - entry = new_shell_variable (name); - - /* Make sure we have a shell_variables hash table to add to. */ - if (shell_variables == 0) - create_variable_tables (); - - elt = hash_insert (savestring (name), table, HASH_NOSRCH); - elt->data = (PTR_T)entry; - - return entry; -} - -#if defined (ARRAY_VARS) -SHELL_VAR * -make_new_array_variable (name) - char *name; -{ - SHELL_VAR *entry; - ARRAY *array; - - entry = make_new_variable (name, global_variables->table); - array = array_create (); - - var_setarray (entry, array); - VSETATTR (entry, att_array); - return entry; -} - -SHELL_VAR * -make_local_array_variable (name, assoc_ok) - char *name; - int assoc_ok; -{ - SHELL_VAR *var; - ARRAY *array; - - var = make_local_variable (name); - if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) - return var; - - array = array_create (); - - dispose_variable_value (var); - var_setarray (var, array); - VSETATTR (var, att_array); - return var; -} - -SHELL_VAR * -make_new_assoc_variable (name) - char *name; -{ - SHELL_VAR *entry; - HASH_TABLE *hash; - - entry = make_new_variable (name, global_variables->table); - hash = assoc_create (0); - - var_setassoc (entry, hash); - VSETATTR (entry, att_assoc); - return entry; -} - -SHELL_VAR * -make_local_assoc_variable (name) - char *name; -{ - SHELL_VAR *var; - HASH_TABLE *hash; - - var = make_local_variable (name); - if (var == 0 || assoc_p (var)) - return var; - - dispose_variable_value (var); - hash = assoc_create (0); - - var_setassoc (var, hash); - VSETATTR (var, att_assoc); - return var; -} -#endif - -char * -make_variable_value (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - char *retval, *oval; - intmax_t lval, rval; - int expok, olen, op; - - /* If this variable has had its type set to integer (via `declare -i'), - then do expression evaluation on it and store the result. The - functions in expr.c (evalexp()) and bind_int_variable() are responsible - for turning off the integer flag if they don't want further - evaluation done. */ - if (integer_p (var)) - { - if (flags & ASS_APPEND) - { - oval = value_cell (var); - lval = evalexp (oval, &expok); /* ksh93 seems to do this */ - if (expok == 0) - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - rval = evalexp (value, &expok); - if (expok == 0) - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - /* This can be fooled if the variable's value changes while evaluating - `rval'. We can change it if we move the evaluation of lval to here. */ - if (flags & ASS_APPEND) - rval += lval; - retval = itos (rval); - } -#if defined (CASEMOD_ATTRS) - else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var)) - { - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - op = capcase_p (var) ? CASE_CAPITALIZE - : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); - oval = sh_modcase (retval, (char *)0, op); - free (retval); - retval = oval; - } -#endif /* CASEMOD_ATTRS */ - else if (value) - { - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - } - else - retval = (char *)NULL; - - return retval; -} - -/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the - temporary environment (but usually is not). */ -static SHELL_VAR * -bind_variable_internal (name, value, table, hflags, aflags) - const char *name; - char *value; - HASH_TABLE *table; - int hflags, aflags; -{ - char *newval; - SHELL_VAR *entry; - - entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table); - /* Follow the nameref chain here if this is the global variables table */ - if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table) - { - entry = find_global_variable (entry->name); - /* Let's see if we have a nameref referencing a variable that hasn't yet - been created. */ - if (entry == 0) - entry = find_variable_last_nameref (name); /* XXX */ - if (entry == 0) /* just in case */ - return (entry); - } - - /* The first clause handles `declare -n ref; ref=x;' */ - if (entry && invisible_p (entry) && nameref_p (entry)) - goto assign_value; - else if (entry && nameref_p (entry)) - { - newval = nameref_cell (entry); -#if defined (ARRAY_VARS) - /* declare -n foo=x[2] */ - if (valid_array_reference (newval)) - /* XXX - should it be aflags? */ - entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags); - else -#endif - { - entry = make_new_variable (newval, table); - var_setvalue (entry, make_variable_value (entry, value, 0)); - } - } - else if (entry == 0) - { - entry = make_new_variable (name, table); - var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */ - } - else if (entry->assign_func) /* array vars have assign functions now */ - { - INVALIDATE_EXPORTSTR (entry); - newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; - if (assoc_p (entry)) - entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0")); - else if (array_p (entry)) - entry = (*(entry->assign_func)) (entry, newval, 0, 0); - else - entry = (*(entry->assign_func)) (entry, newval, -1, 0); - if (newval != value) - free (newval); - return (entry); - } - else - { -assign_value: - if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - - /* Variables which are bound are visible. */ - VUNSETATTR (entry, att_invisible); - -#if defined (ARRAY_VARS) - if (assoc_p (entry) || array_p (entry)) - newval = make_array_variable_value (entry, 0, "0", value, aflags); - else -#endif - - newval = make_variable_value (entry, value, aflags); /* XXX */ - - /* Invalidate any cached export string */ - INVALIDATE_EXPORTSTR (entry); - -#if defined (ARRAY_VARS) - /* XXX -- this bears looking at again -- XXX */ - /* If an existing array variable x is being assigned to with x=b or - `read x' or something of that nature, silently convert it to - x[0]=b or `read x[0]'. */ - if (assoc_p (entry)) - { - assoc_insert (assoc_cell (entry), savestring ("0"), newval); - free (newval); - } - else if (array_p (entry)) - { - array_insert (array_cell (entry), 0, newval); - free (newval); - } - else -#endif - { - FREE (value_cell (entry)); - var_setvalue (entry, newval); - } - } - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - if (exported_p (entry)) - array_needs_making = 1; - - return (entry); -} - -/* Bind a variable NAME to VALUE. This conses up the name - and value strings. If we have a temporary environment, we bind there - first, then we bind into shell_variables. */ - -SHELL_VAR * -bind_variable (name, value, flags) - const char *name; - char *value; - int flags; -{ - SHELL_VAR *v, *nv; - VAR_CONTEXT *vc, *nvc; - int level; - - if (shell_variables == 0) - create_variable_tables (); - - /* If we have a temporary environment, look there first for the variable, - and, if found, modify the value there before modifying it in the - shell_variables table. This allows sourced scripts to modify values - given to them in a temporary environment while modifying the variable - value that the caller sees. */ - if (temporary_env && value) /* XXX - can value be null here? */ - bind_tempenv_variable (name, value); - - /* XXX -- handle local variables here. */ - for (vc = shell_variables; vc; vc = vc->down) - { - if (vc_isfuncenv (vc) || vc_isbltnenv (vc)) - { - v = hash_lookup (name, vc->table); - nvc = vc; - if (v && nameref_p (v)) - { - nv = find_variable_nameref_context (v, vc, &nvc); - if (nv == 0) - { - nv = find_variable_last_nameref_context (v, vc, &nvc); - if (nv && nameref_p (nv)) - { - /* If this nameref variable doesn't have a value yet, - set the value. Otherwise, assign using the value as - normal. */ - if (nameref_cell (nv) == 0) - return (bind_variable_internal (nv->name, value, nvc->table, 0, flags)); -#if defined (ARRAY_VARS) - else if (valid_array_reference (nameref_cell (nv))) - return (assign_array_element (nameref_cell (nv), value, flags)); - else -#endif - return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags)); - } - else - v = nv; - } - else - v = nv; - } - if (v) - return (bind_variable_internal (v->name, value, nvc->table, 0, flags)); - } - } - /* bind_variable_internal will handle nameref resolution in this case */ - return (bind_variable_internal (name, value, global_variables->table, 0, flags)); -} - -SHELL_VAR * -bind_global_variable (name, value, flags) - const char *name; - char *value; - int flags; -{ - SHELL_VAR *v, *nv; - VAR_CONTEXT *vc, *nvc; - int level; - - if (shell_variables == 0) - create_variable_tables (); - - /* bind_variable_internal will handle nameref resolution in this case */ - return (bind_variable_internal (name, value, global_variables->table, 0, flags)); -} - -/* Make VAR, a simple shell variable, have value VALUE. Once assigned a - value, variables are no longer invisible. This is a duplicate of part - of the internals of bind_variable. If the variable is exported, or - all modified variables should be exported, mark the variable for export - and note that the export environment needs to be recreated. */ -SHELL_VAR * -bind_variable_value (var, value, aflags) - SHELL_VAR *var; - char *value; - int aflags; -{ - char *t; - int invis; - - invis = invisible_p (var); - VUNSETATTR (var, att_invisible); - - if (var->assign_func) - { - /* If we're appending, we need the old value, so use - make_variable_value */ - t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; - (*(var->assign_func)) (var, t, -1, 0); - if (t != value && t) - free (t); - } - else - { - t = make_variable_value (var, value, aflags); -#if defined (ARRAY_VARS) - if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0))) -#else - if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0)) -#endif - { - free (t); - if (invis) - VSETATTR (var, att_invisible); /* XXX */ - return ((SHELL_VAR *)NULL); - } - FREE (value_cell (var)); - var_setvalue (var, t); - } - - INVALIDATE_EXPORTSTR (var); - - if (mark_modified_vars) - VSETATTR (var, att_exported); - - if (exported_p (var)) - array_needs_making = 1; - - return (var); -} - -/* Bind/create a shell variable with the name LHS to the RHS. - This creates or modifies a variable such that it is an integer. - - This used to be in expr.c, but it is here so that all of the - variable binding stuff is localized. Since we don't want any - recursive evaluation from bind_variable() (possible without this code, - since bind_variable() calls the evaluator for variables with the integer - attribute set), we temporarily turn off the integer attribute for each - variable we set here, then turn it back on after binding as necessary. */ - -SHELL_VAR * -bind_int_variable (lhs, rhs) - char *lhs, *rhs; -{ - register SHELL_VAR *v; - int isint, isarr, implicitarray; - - isint = isarr = implicitarray = 0; -#if defined (ARRAY_VARS) - if (valid_array_reference (lhs)) - { - isarr = 1; - v = array_variable_part (lhs, (char **)0, (int *)0); - } - else -#endif - v = find_variable (lhs); - - if (v) - { - isint = integer_p (v); - VUNSETATTR (v, att_integer); -#if defined (ARRAY_VARS) - if (array_p (v) && isarr == 0) - implicitarray = 1; -#endif - } - -#if defined (ARRAY_VARS) - if (isarr) - v = assign_array_element (lhs, rhs, 0); - else if (implicitarray) - v = bind_array_variable (lhs, 0, rhs, 0); - else -#endif - v = bind_variable (lhs, rhs, 0); - - if (v && isint) - VSETATTR (v, att_integer); - - VUNSETATTR (v, att_invisible); - - return (v); -} - -SHELL_VAR * -bind_var_to_int (var, val) - char *var; - intmax_t val; -{ - char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p; - - p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0); - return (bind_int_variable (var, p)); -} - -/* Do a function binding to a variable. You pass the name and - the command to bind to. This conses the name and command. */ -SHELL_VAR * -bind_function (name, value) - const char *name; - COMMAND *value; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry == 0) - { - BUCKET_CONTENTS *elt; - - elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH); - entry = new_shell_variable (name); - elt->data = (PTR_T)entry; - } - else - INVALIDATE_EXPORTSTR (entry); - - if (var_isset (entry)) - dispose_command (function_cell (entry)); - - if (value) - var_setfunc (entry, copy_command (value)); - else - var_setfunc (entry, 0); - - VSETATTR (entry, att_function); - - if (mark_modified_vars) - VSETATTR (entry, att_exported); - - VUNSETATTR (entry, att_invisible); /* Just to be sure */ - - if (exported_p (entry)) - array_needs_making = 1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - return (entry); -} - -#if defined (DEBUGGER) -/* Bind a function definition, which includes source file and line number - information in addition to the command, into the FUNCTION_DEF hash table.*/ -void -bind_function_def (name, value) - const char *name; - FUNCTION_DEF *value; -{ - FUNCTION_DEF *entry; - BUCKET_CONTENTS *elt; - COMMAND *cmd; - - entry = find_function_def (name); - if (entry) - { - dispose_function_def_contents (entry); - entry = copy_function_def_contents (value, entry); - } - else - { - cmd = value->command; - value->command = 0; - entry = copy_function_def (value); - value->command = cmd; - - elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH); - elt->data = (PTR_T *)entry; - } -} -#endif /* DEBUGGER */ - -/* Add STRING, which is of the form foo=bar, to the temporary environment - HASH_TABLE (temporary_env). The functions in execute_cmd.c are - responsible for moving the main temporary env to one of the other - temporary environments. The expansion code in subst.c calls this. */ -int -assign_in_env (word, flags) - WORD_DESC *word; - int flags; -{ - int offset, aflags; - char *name, *temp, *value; - SHELL_VAR *var; - const char *string; - - string = word->word; - - aflags = 0; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - name[offset] = 0; - - /* don't ignore the `+' when assigning temporary environment */ - if (name[offset - 1] == '+') - { - name[offset - 1] = '\0'; - aflags |= ASS_APPEND; - } - - var = find_variable (name); - if (var && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - err_readonly (name); - free (name); - return (0); - } - - temp = name + offset + 1; - value = expand_assignment_string_to_string (temp, 0); - - if (var && (aflags & ASS_APPEND)) - { - temp = make_variable_value (var, value, aflags); - FREE (value); - value = temp; - } - } - - if (temporary_env == 0) - temporary_env = hash_create (TEMPENV_HASH_BUCKETS); - - var = hash_lookup (name, temporary_env); - if (var == 0) - var = make_new_variable (name, temporary_env); - else - FREE (value_cell (var)); - - if (value == 0) - { - value = (char *)xmalloc (1); /* like do_assignment_internal */ - value[0] = '\0'; - } - - var_setvalue (var, value); - var->attributes |= (att_exported|att_tempvar); - var->context = variable_context; /* XXX */ - - INVALIDATE_EXPORTSTR (var); - var->exportstr = mk_env_string (name, value, 0); - - array_needs_making = 1; - - if (flags) - stupidly_hack_special_variables (name); - - if (echo_command_at_execute) - /* The Korn shell prints the `+ ' in front of assignment statements, - so we do too. */ - xtrace_print_assignment (name, value, 0, 1); - - free (name); - return 1; -} - -/* **************************************************************** */ -/* */ -/* Copying variables */ -/* */ -/* **************************************************************** */ - -#ifdef INCLUDE_UNUSED -/* Copy VAR to a new data structure and return that structure. */ -SHELL_VAR * -copy_variable (var) - SHELL_VAR *var; -{ - SHELL_VAR *copy = (SHELL_VAR *)NULL; - - if (var) - { - copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - - copy->attributes = var->attributes; - copy->name = savestring (var->name); - - if (function_p (var)) - var_setfunc (copy, copy_command (function_cell (var))); -#if defined (ARRAY_VARS) - else if (array_p (var)) - var_setarray (copy, array_copy (array_cell (var))); - else if (assoc_p (var)) - var_setassoc (copy, assoc_copy (assoc_cell (var))); -#endif - else if (nameref_cell (var)) /* XXX - nameref */ - var_setref (copy, savestring (nameref_cell (var))); - else if (value_cell (var)) /* XXX - nameref */ - var_setvalue (copy, savestring (value_cell (var))); - else - var_setvalue (copy, (char *)NULL); - - copy->dynamic_value = var->dynamic_value; - copy->assign_func = var->assign_func; - - copy->exportstr = COPY_EXPORTSTR (var); - - copy->context = var->context; - } - return (copy); -} -#endif - -/* **************************************************************** */ -/* */ -/* Deleting and unsetting variables */ -/* */ -/* **************************************************************** */ - -/* Dispose of the information attached to VAR. */ -static void -dispose_variable_value (var) - SHELL_VAR *var; -{ - if (function_p (var)) - dispose_command (function_cell (var)); -#if defined (ARRAY_VARS) - else if (array_p (var)) - array_dispose (array_cell (var)); - else if (assoc_p (var)) - assoc_dispose (assoc_cell (var)); -#endif - else if (nameref_p (var)) - FREE (nameref_cell (var)); - else - FREE (value_cell (var)); -} - -void -dispose_variable (var) - SHELL_VAR *var; -{ - if (var == 0) - return; - - if (nofree_p (var) == 0) - dispose_variable_value (var); - - FREE_EXPORTSTR (var); - - free (var->name); - - if (exported_p (var)) - array_needs_making = 1; - - free (var); -} - -/* Unset the shell variable referenced by NAME. Unsetting a nameref variable - unsets the variable it resolves to but leaves the nameref alone. */ -int -unbind_variable (name) - const char *name; -{ - SHELL_VAR *v, *nv; - int r; - - v = var_lookup (name, shell_variables); - nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL; - - r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables); - return r; -} - -/* Unbind NAME, where NAME is assumed to be a nameref variable */ -int -unbind_nameref (name) - const char *name; -{ - SHELL_VAR *v; - - v = var_lookup (name, shell_variables); - if (v && nameref_p (v)) - return makunbound (name, shell_variables); - return 0; -} - -/* Unset the shell function named NAME. */ -int -unbind_func (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - SHELL_VAR *func; - - elt = hash_remove (name, shell_functions, 0); - - if (elt == 0) - return -1; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_functions); -#endif - - func = (SHELL_VAR *)elt->data; - if (func) - { - if (exported_p (func)) - array_needs_making++; - dispose_variable (func); - } - - free (elt->key); - free (elt); - - return 0; -} - -#if defined (DEBUGGER) -int -unbind_function_def (name) - const char *name; -{ - BUCKET_CONTENTS *elt; - FUNCTION_DEF *funcdef; - - elt = hash_remove (name, shell_function_defs, 0); - - if (elt == 0) - return -1; - - funcdef = (FUNCTION_DEF *)elt->data; - if (funcdef) - dispose_function_def (funcdef); - - free (elt->key); - free (elt); - - return 0; -} -#endif /* DEBUGGER */ - -int -delete_var (name, vc) - const char *name; - VAR_CONTEXT *vc; -{ - BUCKET_CONTENTS *elt; - SHELL_VAR *old_var; - VAR_CONTEXT *v; - - for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) - if (elt = hash_remove (name, v->table, 0)) - break; - - if (elt == 0) - return (-1); - - old_var = (SHELL_VAR *)elt->data; - free (elt->key); - free (elt); - - dispose_variable (old_var); - return (0); -} - -/* Make the variable associated with NAME go away. HASH_LIST is the - hash table from which this variable should be deleted (either - shell_variables or shell_functions). - Returns non-zero if the variable couldn't be found. */ -int -makunbound (name, vc) - const char *name; - VAR_CONTEXT *vc; -{ - BUCKET_CONTENTS *elt, *new_elt; - SHELL_VAR *old_var; - VAR_CONTEXT *v; - char *t; - - for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down) - if (elt = hash_remove (name, v->table, 0)) - break; - - if (elt == 0) - return (-1); - - old_var = (SHELL_VAR *)elt->data; - - if (old_var && exported_p (old_var)) - array_needs_making++; - - /* If we're unsetting a local variable and we're still executing inside - the function, just mark the variable as invisible. The function - eventually called by pop_var_context() will clean it up later. This - must be done so that if the variable is subsequently assigned a new - value inside the function, the `local' attribute is still present. - We also need to add it back into the correct hash table. */ - if (old_var && local_p (old_var) && variable_context == old_var->context) - { - if (nofree_p (old_var)) - var_setvalue (old_var, (char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (old_var)) - array_dispose (array_cell (old_var)); - else if (assoc_p (old_var)) - assoc_dispose (assoc_cell (old_var)); -#endif - else if (nameref_p (old_var)) - FREE (nameref_cell (old_var)); - else - FREE (value_cell (old_var)); - /* Reset the attributes. Preserve the export attribute if the variable - came from a temporary environment. Make sure it stays local, and - make it invisible. */ - old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0; - VSETATTR (old_var, att_local); - VSETATTR (old_var, att_invisible); - var_setvalue (old_var, (char *)NULL); - INVALIDATE_EXPORTSTR (old_var); - - new_elt = hash_insert (savestring (old_var->name), v->table, 0); - new_elt->data = (PTR_T)old_var; - stupidly_hack_special_variables (old_var->name); - - free (elt->key); - free (elt); - return (0); - } - - /* Have to save a copy of name here, because it might refer to - old_var->name. If so, stupidly_hack_special_variables will - reference freed memory. */ - t = savestring (name); - - free (elt->key); - free (elt); - - dispose_variable (old_var); - stupidly_hack_special_variables (t); - free (t); - - return (0); -} - -/* Get rid of all of the variables in the current context. */ -void -kill_all_local_variables () -{ - VAR_CONTEXT *vc; - - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - if (vc == 0) - return; /* XXX */ - - if (vc->table && vc_haslocals (vc)) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - vc->table = (HASH_TABLE *)NULL; -} - -static void -free_variable_hash_data (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - dispose_variable (var); -} - -/* Delete the entire contents of the hash table. */ -void -delete_all_variables (hashed_vars) - HASH_TABLE *hashed_vars; -{ - hash_flush (hashed_vars, free_variable_hash_data); -} - -/* **************************************************************** */ -/* */ -/* Setting variable attributes */ -/* */ -/* **************************************************************** */ - -#define FIND_OR_MAKE_VARIABLE(name, entry) \ - do \ - { \ - entry = find_variable (name); \ - if (!entry) \ - { \ - entry = bind_variable (name, "", 0); \ - if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \ - } \ - } \ - while (0) - -/* Make the variable associated with NAME be readonly. - If NAME does not exist yet, create it. */ -void -set_var_read_only (name) - char *name; -{ - SHELL_VAR *entry; - - FIND_OR_MAKE_VARIABLE (name, entry); - VSETATTR (entry, att_readonly); -} - -#ifdef INCLUDE_UNUSED -/* Make the function associated with NAME be readonly. - If NAME does not exist, we just punt, like auto_export code below. */ -void -set_func_read_only (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - VSETATTR (entry, att_readonly); -} - -/* Make the variable associated with NAME be auto-exported. - If NAME does not exist yet, create it. */ -void -set_var_auto_export (name) - char *name; -{ - SHELL_VAR *entry; - - FIND_OR_MAKE_VARIABLE (name, entry); - set_auto_export (entry); -} - -/* Make the function associated with NAME be auto-exported. */ -void -set_func_auto_export (name) - const char *name; -{ - SHELL_VAR *entry; - - entry = find_function (name); - if (entry) - set_auto_export (entry); -} -#endif - -/* **************************************************************** */ -/* */ -/* Creating lists of variables */ -/* */ -/* **************************************************************** */ - -static VARLIST * -vlist_alloc (nentries) - int nentries; -{ - VARLIST *vlist; - - vlist = (VARLIST *)xmalloc (sizeof (VARLIST)); - vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *)); - vlist->list_size = nentries; - vlist->list_len = 0; - vlist->list[0] = (SHELL_VAR *)NULL; - - return vlist; -} - -static VARLIST * -vlist_realloc (vlist, n) - VARLIST *vlist; - int n; -{ - if (vlist == 0) - return (vlist = vlist_alloc (n)); - if (n > vlist->list_size) - { - vlist->list_size = n; - vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *)); - } - return vlist; -} - -static void -vlist_add (vlist, var, flags) - VARLIST *vlist; - SHELL_VAR *var; - int flags; -{ - register int i; - - for (i = 0; i < vlist->list_len; i++) - if (STREQ (var->name, vlist->list[i]->name)) - break; - if (i < vlist->list_len) - return; - - if (i >= vlist->list_size) - vlist = vlist_realloc (vlist, vlist->list_size + 16); - - vlist->list[vlist->list_len++] = var; - vlist->list[vlist->list_len] = (SHELL_VAR *)NULL; -} - -/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the - variables for which FUNCTION returns a non-zero value. A NULL value - for FUNCTION means to use all variables. */ -SHELL_VAR ** -map_over (function, vc) - sh_var_map_func_t *function; - VAR_CONTEXT *vc; -{ - VAR_CONTEXT *v; - VARLIST *vlist; - SHELL_VAR **ret; - int nentries; - - for (nentries = 0, v = vc; v; v = v->down) - nentries += HASH_ENTRIES (v->table); - - if (nentries == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (nentries); - - for (v = vc; v; v = v->down) - flatten (v->table, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -SHELL_VAR ** -map_over_funcs (function) - sh_var_map_func_t *function; -{ - VARLIST *vlist; - SHELL_VAR **ret; - - if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0) - return ((SHELL_VAR **)NULL); - - vlist = vlist_alloc (HASH_ENTRIES (shell_functions)); - - flatten (shell_functions, function, vlist, 0); - - ret = vlist->list; - free (vlist); - return ret; -} - -/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those - elements for which FUNC succeeds to VLIST->list. FLAGS is reserved - for future use. Only unique names are added to VLIST. If FUNC is - NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is - NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST - and FUNC are both NULL, nothing happens. */ -static void -flatten (var_hash_table, func, vlist, flags) - HASH_TABLE *var_hash_table; - sh_var_map_func_t *func; - VARLIST *vlist; - int flags; -{ - register int i; - register BUCKET_CONTENTS *tlist; - int r; - SHELL_VAR *var; - - if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0)) - return; - - for (i = 0; i < var_hash_table->nbuckets; i++) - { - for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next) - { - var = (SHELL_VAR *)tlist->data; - - r = func ? (*func) (var) : 1; - if (r && vlist) - vlist_add (vlist, var, flags); - } - } -} - -void -sort_variables (array) - SHELL_VAR **array; -{ - qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp); -} - -static int -qsort_var_comp (var1, var2) - SHELL_VAR **var1, **var2; -{ - int result; - - if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0) - result = strcmp ((*var1)->name, (*var2)->name); - - return (result); -} - -/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -vapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over (func, shell_variables); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for - which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */ -static SHELL_VAR ** -fapply (func) - sh_var_map_func_t *func; -{ - SHELL_VAR **list; - - list = map_over_funcs (func); - if (list /* && posixly_correct */) - sort_variables (list); - return (list); -} - -/* Create a NULL terminated array of all the shell variables. */ -SHELL_VAR ** -all_shell_variables () -{ - return (vapply ((sh_var_map_func_t *)NULL)); -} - -/* Create a NULL terminated array of all the shell functions. */ -SHELL_VAR ** -all_shell_functions () -{ - return (fapply ((sh_var_map_func_t *)NULL)); -} - -static int -visible_var (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0); -} - -SHELL_VAR ** -all_visible_functions () -{ - return (fapply (visible_var)); -} - -SHELL_VAR ** -all_visible_variables () -{ - return (vapply (visible_var)); -} - -/* Return non-zero if the variable VAR is visible and exported. Array - variables cannot be exported. */ -static int -visible_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && exported_p (var)); -} - -/* Candidate variables for the export environment are either valid variables - with the export attribute or invalid variables inherited from the initial - environment and simply passed through. */ -static int -export_environment_candidate (var) - SHELL_VAR *var; -{ - return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var))); -} - -/* Return non-zero if VAR is a local variable in the current context and - is exported. */ -static int -local_and_exported (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var)); -} - -SHELL_VAR ** -all_exported_variables () -{ - return (vapply (visible_and_exported)); -} - -SHELL_VAR ** -local_exported_variables () -{ - return (vapply (local_and_exported)); -} - -static int -variable_in_context (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); -} - -SHELL_VAR ** -all_local_variables () -{ - VARLIST *vlist; - SHELL_VAR **ret; - VAR_CONTEXT *vc; - - vc = shell_variables; - for (vc = shell_variables; vc; vc = vc->down) - if (vc_isfuncenv (vc) && vc->scope == variable_context) - break; - - if (vc == 0) - { - internal_error (_("all_local_variables: no function context at current scope")); - return (SHELL_VAR **)NULL; - } - if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0) - return (SHELL_VAR **)NULL; - - vlist = vlist_alloc (HASH_ENTRIES (vc->table)); - - flatten (vc->table, variable_in_context, vlist, 0); - - ret = vlist->list; - free (vlist); - if (ret) - sort_variables (ret); - return ret; -} - -#if defined (ARRAY_VARS) -/* Return non-zero if the variable VAR is visible and an array. */ -static int -visible_array_vars (var) - SHELL_VAR *var; -{ - return (invisible_p (var) == 0 && array_p (var)); -} - -SHELL_VAR ** -all_array_variables () -{ - return (vapply (visible_array_vars)); -} -#endif /* ARRAY_VARS */ - -char ** -all_variables_matching_prefix (prefix) - const char *prefix; -{ - SHELL_VAR **varlist; - char **rlist; - int vind, rind, plen; - - plen = STRLEN (prefix); - varlist = all_visible_variables (); - for (vind = 0; varlist && varlist[vind]; vind++) - ; - if (varlist == 0 || vind == 0) - return ((char **)NULL); - rlist = strvec_create (vind + 1); - for (vind = rind = 0; varlist[vind]; vind++) - { - if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen)) - rlist[rind++] = savestring (varlist[vind]->name); - } - rlist[rind] = (char *)0; - free (varlist); - - return rlist; -} - -/* **************************************************************** */ -/* */ -/* Managing temporary variable scopes */ -/* */ -/* **************************************************************** */ - -/* Make variable NAME have VALUE in the temporary environment. */ -static SHELL_VAR * -bind_tempenv_variable (name, value) - const char *name; - char *value; -{ - SHELL_VAR *var; - - var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL; - - if (var) - { - FREE (value_cell (var)); - var_setvalue (var, savestring (value)); - INVALIDATE_EXPORTSTR (var); - } - - return (var); -} - -/* Find a variable in the temporary environment that is named NAME. - Return the SHELL_VAR *, or NULL if not found. */ -SHELL_VAR * -find_tempenv_variable (name) - const char *name; -{ - return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL); -} - -char **tempvar_list; -int tvlist_ind; - -/* Push the variable described by (SHELL_VAR *)DATA down to the next - variable context from the temporary environment. */ -static void -push_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - HASH_TABLE *binding_table; - - var = (SHELL_VAR *)data; - - binding_table = shell_variables->table; - if (binding_table == 0) - { - if (shell_variables == global_variables) - /* shouldn't happen */ - binding_table = shell_variables->table = global_variables->table = hash_create (0); - else - binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS); - } - - v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE); - - /* XXX - should we set the context here? It shouldn't matter because of how - assign_in_env works, but might want to check. */ - if (binding_table == global_variables->table) /* XXX */ - var->attributes &= ~(att_tempvar|att_propagate); - else - { - var->attributes |= att_propagate; - if (binding_table == shell_variables->table) - shell_variables->flags |= VC_HASTMPVAR; - } - v->attributes |= var->attributes; - - if (find_special_var (var->name) >= 0) - tempvar_list[tvlist_ind++] = savestring (var->name); - - dispose_variable (var); -} - -static void -propagate_temp_var (data) - PTR_T data; -{ - SHELL_VAR *var; - - var = (SHELL_VAR *)data; - if (tempvar_p (var) && (var->attributes & att_propagate)) - push_temp_var (data); - else - { - if (find_special_var (var->name) >= 0) - tempvar_list[tvlist_ind++] = savestring (var->name); - dispose_variable (var); - } -} - -/* Free the storage used in the hash table for temporary - environment variables. PUSHF is a function to be called - to free each hash table entry. It takes care of pushing variables - to previous scopes if appropriate. PUSHF stores names of variables - that require special handling (e.g., IFS) on tempvar_list, so this - function can call stupidly_hack_special_variables on all the - variables in the list when the temporary hash table is destroyed. */ -static void -dispose_temporary_env (pushf) - sh_free_func_t *pushf; -{ - int i; - - tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); - tempvar_list[tvlist_ind = 0] = 0; - - hash_flush (temporary_env, pushf); - hash_dispose (temporary_env); - temporary_env = (HASH_TABLE *)NULL; - - tempvar_list[tvlist_ind] = 0; - - array_needs_making = 1; - -#if 0 - sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */ -#endif - for (i = 0; i < tvlist_ind; i++) - stupidly_hack_special_variables (tempvar_list[i]); - - strvec_dispose (tempvar_list); - tempvar_list = 0; - tvlist_ind = 0; -} - -void -dispose_used_env_vars () -{ - if (temporary_env) - { - dispose_temporary_env (propagate_temp_var); - maybe_make_export_env (); - } -} - -/* Take all of the shell variables in the temporary environment HASH_TABLE - and make shell variables from them at the current variable context. */ -void -merge_temporary_env () -{ - if (temporary_env) - dispose_temporary_env (push_temp_var); -} - -void -flush_temporary_env () -{ - if (temporary_env) - { - hash_flush (temporary_env, free_variable_hash_data); - hash_dispose (temporary_env); - temporary_env = (HASH_TABLE *)NULL; - } -} - -/* **************************************************************** */ -/* */ -/* Creating and manipulating the environment */ -/* */ -/* **************************************************************** */ - -static inline char * -mk_env_string (name, value, isfunc) - const char *name, *value; - int isfunc; -{ - size_t name_len, value_len; - char *p, *q; - - name_len = strlen (name); - value_len = STRLEN (value); - - /* If we are exporting a shell function, construct the encoded function - name. */ - if (isfunc && value) - { - p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2); - q = p; - memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN); - q += BASHFUNC_PREFLEN; - memcpy (q, name, name_len); - q += name_len; - memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN); - q += BASHFUNC_SUFFLEN; - } - else - { - p = (char *)xmalloc (2 + name_len + value_len); - memcpy (p, name, name_len); - q = p + name_len; - } - - q[0] = '='; - if (value && *value) - memcpy (q + 1, value, value_len + 1); - else - q[1] = '\0'; - - return (p); -} - -#ifdef DEBUG -/* Debugging */ -static int -valid_exportstr (v) - SHELL_VAR *v; -{ - char *s; - - s = v->exportstr; - if (s == 0) - { - internal_error (_("%s has null exportstr"), v->name); - return (0); - } - if (legal_variable_starter ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - for (s = v->exportstr + 1; s && *s; s++) - { - if (*s == '=') - break; - if (legal_variable_char ((unsigned char)*s) == 0) - { - internal_error (_("invalid character %d in exportstr for %s"), *s, v->name); - return (0); - } - } - if (*s != '=') - { - internal_error (_("no `=' in exportstr for %s"), v->name); - return (0); - } - return (1); -} -#endif - -static char ** -make_env_array_from_var_list (vars) - SHELL_VAR **vars; -{ - register int i, list_index; - register SHELL_VAR *var; - char **list, *value; - - list = strvec_create ((1 + strvec_len ((char **)vars))); - -#define USE_EXPORTSTR (value == var->exportstr) - - for (i = 0, list_index = 0; var = vars[i]; i++) - { -#if defined (__CYGWIN__) - /* We don't use the exportstr stuff on Cygwin at all. */ - INVALIDATE_EXPORTSTR (var); -#endif - if (var->exportstr) - value = var->exportstr; - else if (function_p (var)) - value = named_function_string ((char *)NULL, function_cell (var), 0); -#if defined (ARRAY_VARS) - else if (array_p (var)) -# if ARRAY_EXPORT - value = array_to_assignment_string (array_cell (var)); -# else - continue; /* XXX array vars cannot yet be exported */ -# endif /* ARRAY_EXPORT */ - else if (assoc_p (var)) -# if 0 - value = assoc_to_assignment_string (assoc_cell (var)); -# else - continue; /* XXX associative array vars cannot yet be exported */ -# endif -#endif - else - value = value_cell (var); - - if (value) - { - /* Gee, I'd like to get away with not using savestring() if we're - using the cached exportstr... */ - list[list_index] = USE_EXPORTSTR ? savestring (value) - : mk_env_string (var->name, value, function_p (var)); - - if (USE_EXPORTSTR == 0) - SAVE_EXPORTSTR (var, list[list_index]); - - list_index++; -#undef USE_EXPORTSTR - -#if 0 /* not yet */ -#if defined (ARRAY_VARS) - if (array_p (var) || assoc_p (var)) - free (value); -#endif -#endif - } - } - - list[list_index] = (char *)NULL; - return (list); -} - -/* Make an array of assignment statements from the hash table - HASHED_VARS which contains SHELL_VARs. Only visible, exported - variables are eligible. */ -static char ** -make_var_export_array (vcxt) - VAR_CONTEXT *vcxt; -{ - char **list; - SHELL_VAR **vars; - -#if 0 - vars = map_over (visible_and_exported, vcxt); -#else - vars = map_over (export_environment_candidate, vcxt); -#endif - - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -static char ** -make_func_export_array () -{ - char **list; - SHELL_VAR **vars; - - vars = map_over_funcs (visible_and_exported); - if (vars == 0) - return (char **)NULL; - - list = make_env_array_from_var_list (vars); - - free (vars); - return (list); -} - -/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */ -#define add_to_export_env(envstr,do_alloc) \ -do \ - { \ - if (export_env_index >= (export_env_size - 1)) \ - { \ - export_env_size += 16; \ - export_env = strvec_resize (export_env, export_env_size); \ - environ = export_env; \ - } \ - export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \ - export_env[export_env_index] = (char *)NULL; \ - } while (0) - -/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the - array with the same left-hand side. Return the new EXPORT_ENV. */ -char ** -add_or_supercede_exported_var (assign, do_alloc) - char *assign; - int do_alloc; -{ - register int i; - int equal_offset; - - equal_offset = assignment (assign, 0); - if (equal_offset == 0) - return (export_env); - - /* If this is a function, then only supersede the function definition. - We do this by including the `=() {' in the comparison, like - initialize_shell_variables does. */ - if (assign[equal_offset + 1] == '(' && - strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */ - equal_offset += 4; - - for (i = 0; i < export_env_index; i++) - { - if (STREQN (assign, export_env[i], equal_offset + 1)) - { - free (export_env[i]); - export_env[i] = do_alloc ? savestring (assign) : assign; - return (export_env); - } - } - add_to_export_env (assign, do_alloc); - return (export_env); -} - -static void -add_temp_array_to_env (temp_array, do_alloc, do_supercede) - char **temp_array; - int do_alloc, do_supercede; -{ - register int i; - - if (temp_array == 0) - return; - - for (i = 0; temp_array[i]; i++) - { - if (do_supercede) - export_env = add_or_supercede_exported_var (temp_array[i], do_alloc); - else - add_to_export_env (temp_array[i], do_alloc); - } - - free (temp_array); -} - -/* Make the environment array for the command about to be executed, if the - array needs making. Otherwise, do nothing. If a shell action could - change the array that commands receive for their environment, then the - code should `array_needs_making++'. - - The order to add to the array is: - temporary_env - list of var contexts whose head is shell_variables - shell_functions - - This is the shell variable lookup order. We add only new variable - names at each step, which allows local variables and variables in - the temporary environments to shadow variables in the global (or - any previous) scope. -*/ - -static int -n_shell_variables () -{ - VAR_CONTEXT *vc; - int n; - - for (n = 0, vc = shell_variables; vc; vc = vc->down) - n += HASH_ENTRIES (vc->table); - return n; -} - -int -chkexport (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v && exported_p (v)) - { - array_needs_making = 1; - maybe_make_export_env (); - return 1; - } - return 0; -} - -void -maybe_make_export_env () -{ - register char **temp_array; - int new_size; - VAR_CONTEXT *tcxt; - - if (array_needs_making) - { - if (export_env) - strvec_flush (export_env); - - /* Make a guess based on how many shell variables and functions we - have. Since there will always be array variables, and array - variables are not (yet) exported, this will always be big enough - for the exported variables and functions. */ - new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 + - HASH_ENTRIES (temporary_env); - if (new_size > export_env_size) - { - export_env_size = new_size; - export_env = strvec_resize (export_env, export_env_size); - environ = export_env; - } - export_env[export_env_index = 0] = (char *)NULL; - - /* Make a dummy variable context from the temporary_env, stick it on - the front of shell_variables, call make_var_export_array on the - whole thing to flatten it, and convert the list of SHELL_VAR *s - to the form needed by the environment. */ - if (temporary_env) - { - tcxt = new_var_context ((char *)NULL, 0); - tcxt->table = temporary_env; - tcxt->down = shell_variables; - } - else - tcxt = shell_variables; - - temp_array = make_var_export_array (tcxt); - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - if (tcxt != shell_variables) - free (tcxt); - -#if defined (RESTRICTED_SHELL) - /* Restricted shells may not export shell functions. */ - temp_array = restricted ? (char **)0 : make_func_export_array (); -#else - temp_array = make_func_export_array (); -#endif - if (temp_array) - add_temp_array_to_env (temp_array, 0, 0); - - array_needs_making = 0; - } -} - -/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so - we will need to remake the exported environment every time we - change directories. `_' is always put into the environment for - every external command, so without special treatment it will always - cause the environment to be remade. - - If there is no other reason to make the exported environment, we can - just update the variables in place and mark the exported environment - as no longer needing a remake. */ -void -update_export_env_inplace (env_prefix, preflen, value) - char *env_prefix; - int preflen; - char *value; -{ - char *evar; - - evar = (char *)xmalloc (STRLEN (value) + preflen + 1); - strcpy (evar, env_prefix); - if (value) - strcpy (evar + preflen, value); - export_env = add_or_supercede_exported_var (evar, 0); -} - -/* We always put _ in the environment as the name of this command. */ -void -put_command_name_into_env (command_name) - char *command_name; -{ - update_export_env_inplace ("_=", 2, command_name); -} - -/* **************************************************************** */ -/* */ -/* Managing variable contexts */ -/* */ -/* **************************************************************** */ - -/* Allocate and return a new variable context with NAME and FLAGS. - NAME can be NULL. */ - -VAR_CONTEXT * -new_var_context (name, flags) - char *name; - int flags; -{ - VAR_CONTEXT *vc; - - vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT)); - vc->name = name ? savestring (name) : (char *)NULL; - vc->scope = variable_context; - vc->flags = flags; - - vc->up = vc->down = (VAR_CONTEXT *)NULL; - vc->table = (HASH_TABLE *)NULL; - - return vc; -} - -/* Free a variable context and its data, including the hash table. Dispose - all of the variables. */ -void -dispose_var_context (vc) - VAR_CONTEXT *vc; -{ - FREE (vc->name); - - if (vc->table) - { - delete_all_variables (vc->table); - hash_dispose (vc->table); - } - - free (vc); -} - -/* Set VAR's scope level to the current variable context. */ -static int -set_context (var) - SHELL_VAR *var; -{ - return (var->context = variable_context); -} - -/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of - temporary variables, and push it onto shell_variables. This is - for shell functions. */ -VAR_CONTEXT * -push_var_context (name, flags, tempvars) - char *name; - int flags; - HASH_TABLE *tempvars; -{ - VAR_CONTEXT *vc; - - vc = new_var_context (name, flags); - vc->table = tempvars; - if (tempvars) - { - /* Have to do this because the temp environment was created before - variable_context was incremented. */ - flatten (tempvars, set_context, (VARLIST *)NULL, 0); - vc->flags |= VC_HASTMPVAR; - } - vc->down = shell_variables; - shell_variables->up = vc; - - return (shell_variables = vc); -} - -static void -push_func_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - - var = (SHELL_VAR *)data; - - if (local_p (var) && STREQ (var->name, "-")) - set_current_options (value_cell (var)); - else if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate))) - { - /* Make sure we have a hash table to store the variable in while it is - being propagated down to the global variables table. Create one if - we have to */ - if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0) - shell_variables->table = hash_create (0); - /* XXX - should we set v->context here? */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); - if (shell_variables == global_variables) - var->attributes &= ~(att_tempvar|att_propagate); - else - shell_variables->flags |= VC_HASTMPVAR; - v->attributes |= var->attributes; - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - - dispose_variable (var); -} - -/* Pop the top context off of VCXT and dispose of it, returning the rest of - the stack. */ -void -pop_var_context () -{ - VAR_CONTEXT *ret, *vcxt; - - vcxt = shell_variables; - if (vc_isfuncenv (vcxt) == 0) - { - internal_error (_("pop_var_context: head of shell_variables not a function context")); - return; - } - - if (ret = vcxt->down) - { - ret->up = (VAR_CONTEXT *)NULL; - shell_variables = ret; - if (vcxt->table) - hash_flush (vcxt->table, push_func_var); - dispose_var_context (vcxt); - } - else - internal_error (_("pop_var_context: no global_variables context")); -} - -/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and - all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */ -void -delete_all_contexts (vcxt) - VAR_CONTEXT *vcxt; -{ - VAR_CONTEXT *v, *t; - - for (v = vcxt; v != global_variables; v = t) - { - t = v->down; - dispose_var_context (v); - } - - delete_all_variables (global_variables->table); - shell_variables = global_variables; -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping temporary variable scopes */ -/* */ -/* **************************************************************** */ - -VAR_CONTEXT * -push_scope (flags, tmpvars) - int flags; - HASH_TABLE *tmpvars; -{ - return (push_var_context ((char *)NULL, flags, tmpvars)); -} - -static void -push_exported_var (data) - PTR_T data; -{ - SHELL_VAR *var, *v; - - var = (SHELL_VAR *)data; - - /* If a temp var had its export attribute set, or it's marked to be - propagated, bind it in the previous scope before disposing it. */ - /* XXX - This isn't exactly right, because all tempenv variables have the - export attribute set. */ -#if 0 - if (exported_p (var) || (var->attributes & att_propagate)) -#else - if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) -#endif - { - var->attributes &= ~att_tempvar; /* XXX */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); - if (shell_variables == global_variables) - var->attributes &= ~att_propagate; - v->attributes |= var->attributes; - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - - dispose_variable (var); -} - -void -pop_scope (is_special) - int is_special; -{ - VAR_CONTEXT *vcxt, *ret; - - vcxt = shell_variables; - if (vc_istempscope (vcxt) == 0) - { - internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); - return; - } - - ret = vcxt->down; - if (ret) - ret->up = (VAR_CONTEXT *)NULL; - - shell_variables = ret; - - /* Now we can take care of merging variables in VCXT into set of scopes - whose head is RET (shell_variables). */ - FREE (vcxt->name); - if (vcxt->table) - { - if (is_special) - hash_flush (vcxt->table, push_func_var); - else - hash_flush (vcxt->table, push_exported_var); - hash_dispose (vcxt->table); - } - free (vcxt); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* **************************************************************** */ -/* */ -/* Pushing and Popping function contexts */ -/* */ -/* **************************************************************** */ - -static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; -static int dollar_arg_stack_slots; -static int dollar_arg_stack_index; - -/* XXX - should always be followed by remember_args () */ -void -push_context (name, is_subshell, tempvars) - char *name; /* function name */ - int is_subshell; - HASH_TABLE *tempvars; -{ - if (is_subshell == 0) - push_dollar_vars (); - variable_context++; - push_var_context (name, VC_FUNCENV, tempvars); -} - -/* Only called when subshell == 0, so we don't need to check, and can - unconditionally pop the dollar vars off the stack. */ -void -pop_context () -{ - pop_dollar_vars (); - variable_context--; - pop_var_context (); - - sv_ifs ("IFS"); /* XXX here for now */ -} - -/* Save the existing positional parameters on a stack. */ -void -push_dollar_vars () -{ - if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) - { - dollar_arg_stack = (WORD_LIST **) - xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) - * sizeof (WORD_LIST *)); - } - dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args (); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; -} - -/* Restore the positional parameters from our stack. */ -void -pop_dollar_vars () -{ - if (!dollar_arg_stack || dollar_arg_stack_index == 0) - return; - - remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); - dispose_words (dollar_arg_stack[dollar_arg_stack_index]); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; - set_dollar_vars_unchanged (); -} - -void -dispose_saved_dollar_vars () -{ - if (!dollar_arg_stack || dollar_arg_stack_index == 0) - return; - - dispose_words (dollar_arg_stack[dollar_arg_stack_index]); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; -} - -/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */ - -void -push_args (list) - WORD_LIST *list; -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bash_argv_v, *bash_argc_v; - ARRAY *bash_argv_a, *bash_argc_a; - WORD_LIST *l; - arrayind_t i; - char *t; - - GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); - GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); - - for (l = list, i = 0; l; l = l->next, i++) - array_push (bash_argv_a, l->word->word); - - t = itos (i); - array_push (bash_argc_a, t); - free (t); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC - array and use that value as the count of elements to remove from - BASH_ARGV. */ -void -pop_args () -{ -#if defined (ARRAY_VARS) && defined (DEBUGGER) - SHELL_VAR *bash_argv_v, *bash_argc_v; - ARRAY *bash_argv_a, *bash_argc_a; - ARRAY_ELEMENT *ce; - intmax_t i; - - GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); - GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); - - ce = array_shift (bash_argc_a, 1, 0); - if (ce == 0 || legal_number (element_value (ce), &i) == 0) - i = 0; - - for ( ; i > 0; i--) - array_pop (bash_argv_a); - array_dispose_element (ce); -#endif /* ARRAY_VARS && DEBUGGER */ -} - -/************************************************* - * * - * Functions to manage special variables * - * * - *************************************************/ - -/* Extern declarations for variables this code has to manage. */ -extern int eof_encountered, eof_encountered_limit, ignoreeof; - -#if defined (READLINE) -extern int hostname_list_initialized; -#endif - -/* An alist of name.function for each special variable. Most of the - functions don't do much, and in fact, this would be faster with a - switch statement, but by the end of this file, I am sick of switch - statements. */ - -#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 - -/* This table will be sorted with qsort() the first time it's accessed. */ -struct name_and_function { - char *name; - sh_sv_func_t *function; -}; - -static struct name_and_function special_vars[] = { - { "BASH_COMPAT", sv_shcompat }, - { "BASH_XTRACEFD", sv_xtracefd }, - -#if defined (JOB_CONTROL) - { "CHILD_MAX", sv_childmax }, -#endif - -#if defined (READLINE) -# if defined (STRICT_POSIX) - { "COLUMNS", sv_winsize }, -# endif - { "COMP_WORDBREAKS", sv_comp_wordbreaks }, -#endif - - { "FUNCNEST", sv_funcnest }, - - { "GLOBIGNORE", sv_globignore }, - -#if defined (HISTORY) - { "HISTCONTROL", sv_history_control }, - { "HISTFILESIZE", sv_histsize }, - { "HISTIGNORE", sv_histignore }, - { "HISTSIZE", sv_histsize }, - { "HISTTIMEFORMAT", sv_histtimefmt }, -#endif - -#if defined (__CYGWIN__) - { "HOME", sv_home }, -#endif - -#if defined (READLINE) - { "HOSTFILE", sv_hostfile }, -#endif - - { "IFS", sv_ifs }, - { "IGNOREEOF", sv_ignoreeof }, - - { "LANG", sv_locale }, - { "LC_ALL", sv_locale }, - { "LC_COLLATE", sv_locale }, - { "LC_CTYPE", sv_locale }, - { "LC_MESSAGES", sv_locale }, - { "LC_NUMERIC", sv_locale }, - { "LC_TIME", sv_locale }, - -#if defined (READLINE) && defined (STRICT_POSIX) - { "LINES", sv_winsize }, -#endif - - { "MAIL", sv_mail }, - { "MAILCHECK", sv_mail }, - { "MAILPATH", sv_mail }, - - { "OPTERR", sv_opterr }, - { "OPTIND", sv_optind }, - - { "PATH", sv_path }, - { "POSIXLY_CORRECT", sv_strict_posix }, - -#if defined (READLINE) - { "TERM", sv_terminal }, - { "TERMCAP", sv_terminal }, - { "TERMINFO", sv_terminal }, -#endif /* READLINE */ - - { "TEXTDOMAIN", sv_locale }, - { "TEXTDOMAINDIR", sv_locale }, - -#if defined (HAVE_TZSET) - { "TZ", sv_tz }, -#endif - -#if defined (HISTORY) && defined (BANG_HISTORY) - { "histchars", sv_histchars }, -#endif /* HISTORY && BANG_HISTORY */ - - { "ignoreeof", sv_ignoreeof }, - - { (char *)0, (sh_sv_func_t *)0 } -}; - -#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1) - -static int -sv_compare (sv1, sv2) - struct name_and_function *sv1, *sv2; -{ - int r; - - if ((r = sv1->name[0] - sv2->name[0]) == 0) - r = strcmp (sv1->name, sv2->name); - return r; -} - -static inline int -find_special_var (name) - const char *name; -{ - register int i, r; - - for (i = 0; special_vars[i].name; i++) - { - r = special_vars[i].name[0] - name[0]; - if (r == 0) - r = strcmp (special_vars[i].name, name); - if (r == 0) - return i; - else if (r > 0) - /* Can't match any of rest of elements in sorted list. Take this out - if it causes problems in certain environments. */ - break; - } - return -1; -} - -/* The variable in NAME has just had its state changed. Check to see if it - is one of the special ones where something special happens. */ -void -stupidly_hack_special_variables (name) - char *name; -{ - static int sv_sorted = 0; - int i; - - if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */ - { - qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]), - (QSFUNC *)sv_compare); - sv_sorted = 1; - } - - i = find_special_var (name); - if (i != -1) - (*(special_vars[i].function)) (name); -} - -/* Special variables that need hooks to be run when they are unset as part - of shell reinitialization should have their sv_ functions run here. */ -void -reinit_special_variables () -{ -#if defined (READLINE) - sv_comp_wordbreaks ("COMP_WORDBREAKS"); -#endif - sv_globignore ("GLOBIGNORE"); - sv_opterr ("OPTERR"); -} - -void -sv_ifs (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable ("IFS"); - setifs (v); -} - -/* What to do just after the PATH variable has changed. */ -void -sv_path (name) - char *name; -{ - /* hash -r */ - phash_flush (); -} - -/* What to do just after one of the MAILxxxx variables has changed. NAME - is the name of the variable. This is called with NAME set to one of - MAIL, MAILCHECK, or MAILPATH. */ -void -sv_mail (name) - char *name; -{ - /* If the time interval for checking the files has changed, then - reset the mail timer. Otherwise, one of the pathname vars - to the users mailbox has changed, so rebuild the array of - filenames. */ - if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ - reset_mail_timer (); - else - { - free_mail_files (); - remember_mail_dates (); - } -} - -void -sv_funcnest (name) - char *name; -{ - SHELL_VAR *v; - intmax_t num; - - v = find_variable (name); - if (v == 0) - funcnest_max = 0; - else if (legal_number (value_cell (v), &num) == 0) - funcnest_max = 0; - else - funcnest_max = num; -} - -/* What to do when GLOBIGNORE changes. */ -void -sv_globignore (name) - char *name; -{ - if (privileged_mode == 0) - setup_glob_ignore (name); -} - -#if defined (READLINE) -void -sv_comp_wordbreaks (name) - char *name; -{ - SHELL_VAR *sv; - - sv = find_variable (name); - if (sv == 0) - reset_completer_word_break_chars (); -} - -/* What to do just after one of the TERMxxx variables has changed. - If we are an interactive shell, then try to reset the terminal - information in readline. */ -void -sv_terminal (name) - char *name; -{ - if (interactive_shell && no_line_editing == 0) - rl_reset_terminal (get_string_value ("TERM")); -} - -void -sv_hostfile (name) - char *name; -{ - SHELL_VAR *v; - - v = find_variable (name); - if (v == 0) - clear_hostname_list (); - else - hostname_list_initialized = 0; -} - -#if defined (STRICT_POSIX) -/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values - found in the initial environment) to override the terminal size reported by - the kernel. */ -void -sv_winsize (name) - char *name; -{ - SHELL_VAR *v; - intmax_t xd; - int d; - - if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) - return; - - v = find_variable (name); - if (v == 0 || var_isnull (v)) - rl_reset_screen_size (); - else - { - if (legal_number (value_cell (v), &xd) == 0) - return; - winsize_assignment = 1; - d = xd; /* truncate */ - if (name[0] == 'L') /* LINES */ - rl_set_screen_size (d, -1); - else /* COLUMNS */ - rl_set_screen_size (-1, d); - winsize_assignment = 0; - } -} -#endif /* STRICT_POSIX */ -#endif /* READLINE */ - -/* Update the value of HOME in the export environment so tilde expansion will - work on cygwin. */ -#if defined (__CYGWIN__) -sv_home (name) - char *name; -{ - array_needs_making = 1; - maybe_make_export_env (); -} -#endif - -#if defined (HISTORY) -/* What to do after the HISTSIZE or HISTFILESIZE variables change. - If there is a value for this HISTSIZE (and it is numeric), then stifle - the history. Otherwise, if there is NO value for this variable, - unstifle the history. If name is HISTFILESIZE, and its value is - numeric, truncate the history file to hold no more than that many - lines. */ -void -sv_histsize (name) - char *name; -{ - char *temp; - intmax_t num; - int hmax; - - temp = get_string_value (name); - - if (temp && *temp) - { - if (legal_number (temp, &num)) - { - hmax = num; - if (hmax < 0 && name[4] == 'S') - unstifle_history (); /* unstifle history if HISTSIZE < 0 */ - else if (name[4] == 'S') - { - stifle_history (hmax); - hmax = where_history (); - if (history_lines_this_session > hmax) - history_lines_this_session = hmax; - } - else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */ - { - history_truncate_file (get_string_value ("HISTFILE"), hmax); - /* If we just shrank the history file to fewer lines than we've - already read, make sure we adjust our idea of how many lines - we have read from the file. */ - if (hmax < history_lines_in_file) - history_lines_in_file = hmax; - } - } - } - else if (name[4] == 'S') - unstifle_history (); -} - -/* What to do after the HISTIGNORE variable changes. */ -void -sv_histignore (name) - char *name; -{ - setup_history_ignore (name); -} - -/* What to do after the HISTCONTROL variable changes. */ -void -sv_history_control (name) - char *name; -{ - char *temp; - char *val; - int tptr; - - history_control = 0; - temp = get_string_value (name); - - if (temp == 0 || *temp == 0) - return; - - tptr = 0; - while (val = extract_colon_unit (temp, &tptr)) - { - if (STREQ (val, "ignorespace")) - history_control |= HC_IGNSPACE; - else if (STREQ (val, "ignoredups")) - history_control |= HC_IGNDUPS; - else if (STREQ (val, "ignoreboth")) - history_control |= HC_IGNBOTH; - else if (STREQ (val, "erasedups")) - history_control |= HC_ERASEDUPS; - - free (val); - } -} - -#if defined (BANG_HISTORY) -/* Setting/unsetting of the history expansion character. */ -void -sv_histchars (name) - char *name; -{ - char *temp; - - temp = get_string_value (name); - if (temp) - { - history_expansion_char = *temp; - if (temp[0] && temp[1]) - { - history_subst_char = temp[1]; - if (temp[2]) - history_comment_char = temp[2]; - } - } - else - { - history_expansion_char = '!'; - history_subst_char = '^'; - history_comment_char = '#'; - } -} -#endif /* BANG_HISTORY */ - -void -sv_histtimefmt (name) - char *name; -{ - SHELL_VAR *v; - - if (v = find_variable (name)) - { - if (history_comment_char == 0) - history_comment_char = '#'; - } - history_write_timestamps = (v != 0); -} -#endif /* HISTORY */ - -#if defined (HAVE_TZSET) -void -sv_tz (name) - char *name; -{ - if (chkexport (name)) - tzset (); -} -#endif - -/* If the variable exists, then the value of it can be the number - of times we actually ignore the EOF. The default is small, - (smaller than csh, anyway). */ -void -sv_ignoreeof (name) - char *name; -{ - SHELL_VAR *tmp_var; - char *temp; - - eof_encountered = 0; - - tmp_var = find_variable (name); - ignoreeof = tmp_var != 0; - temp = tmp_var ? value_cell (tmp_var) : (char *)NULL; - if (temp) - eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10; - set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */ -} - -void -sv_optind (name) - char *name; -{ - SHELL_VAR *var; - char *tt; - int s; - - var = find_variable ("OPTIND"); - tt = var ? get_variable_value (var) : (char *)NULL; - - /* Assume that if var->context < variable_context and variable_context > 0 - then we are restoring the variables's previous state while returning - from a function. */ - if (tt && *tt) - { - s = atoi (tt); - - /* According to POSIX, setting OPTIND=1 resets the internal state - of getopt (). */ - if (s < 0 || s == 1) - s = 0; - } - else - s = 0; - getopts_reset (s); -} - -void -sv_opterr (name) - char *name; -{ - char *tt; - - tt = get_string_value ("OPTERR"); - sh_opterr = (tt && *tt) ? atoi (tt) : 1; -} - -void -sv_strict_posix (name) - char *name; -{ - SET_INT_VAR (name, posixly_correct); - posix_initialize (posixly_correct); -#if defined (READLINE) - if (interactive_shell) - posix_readline_initialize (posixly_correct); -#endif /* READLINE */ - set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */ -} - -void -sv_locale (name) - char *name; -{ - char *v; - int r; - - v = get_string_value (name); - if (name[0] == 'L' && name[1] == 'A') /* LANG */ - r = set_lang (name, v); - else - r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */ - -#if 1 - if (r == 0 && posixly_correct) - last_command_exit_value = 1; -#endif -} - -#if defined (ARRAY_VARS) -void -set_pipestatus_array (ps, nproc) - int *ps; - int nproc; -{ - SHELL_VAR *v; - ARRAY *a; - ARRAY_ELEMENT *ae; - register int i; - char *t, tbuf[INT_STRLEN_BOUND(int) + 1]; - - v = find_variable ("PIPESTATUS"); - if (v == 0) - v = make_new_array_variable ("PIPESTATUS"); - if (array_p (v) == 0) - return; /* Do nothing if not an array variable. */ - a = array_cell (v); - - if (a == 0 || array_num_elements (a) == 0) - { - for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */ - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - return; - } - - /* Fast case */ - if (array_num_elements (a) == nproc && nproc == 1) - { - ae = element_forw (a->head); - free (element_value (ae)); - ae->value = itos (ps[0]); - } - else if (array_num_elements (a) <= nproc) - { - /* modify in array_num_elements members in place, then add */ - ae = a->head; - for (i = 0; i < array_num_elements (a); i++) - { - ae = element_forw (ae); - free (element_value (ae)); - ae->value = itos (ps[i]); - } - /* add any more */ - for ( ; i < nproc; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } - else - { - /* deleting elements. it's faster to rebuild the array. */ - array_flush (a); - for (i = 0; ps[i] != -1; i++) - { - t = inttostr (ps[i], tbuf, sizeof (tbuf)); - array_insert (a, i, t); - } - } -} - -ARRAY * -save_pipestatus_array () -{ - SHELL_VAR *v; - ARRAY *a, *a2; - - v = find_variable ("PIPESTATUS"); - if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) - return ((ARRAY *)NULL); - - a = array_cell (v); - a2 = array_copy (array_cell (v)); - - return a2; -} - -void -restore_pipestatus_array (a) - ARRAY *a; -{ - SHELL_VAR *v; - ARRAY *a2; - - v = find_variable ("PIPESTATUS"); - /* XXX - should we still assign even if existing value is NULL? */ - if (v == 0 || array_p (v) == 0 || array_cell (v) == 0) - return; - - a2 = array_cell (v); - var_setarray (v, a); - - array_dispose (a2); -} -#endif - -void -set_pipestatus_from_exit (s) - int s; -{ -#if defined (ARRAY_VARS) - static int v[2] = { 0, -1 }; - - v[0] = s; - set_pipestatus_array (v, 1); -#endif -} - -void -sv_xtracefd (name) - char *name; -{ - SHELL_VAR *v; - char *t, *e; - int fd; - FILE *fp; - - v = find_variable (name); - if (v == 0) - { - xtrace_reset (); - return; - } - - t = value_cell (v); - if (t == 0 || *t == 0) - xtrace_reset (); - else - { - fd = (int)strtol (t, &e, 10); - if (e != t && *e == '\0' && sh_validfd (fd)) - { - fp = fdopen (fd, "w"); - if (fp == 0) - internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v)); - else - xtrace_set (fd, fp); - } - else - internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v)); - } -} - -#define MIN_COMPAT_LEVEL 31 - -void -sv_shcompat (name) - char *name; -{ - SHELL_VAR *v; - char *val; - int tens, ones, compatval; - - v = find_variable (name); - if (v == 0) - { - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - val = value_cell (v); - if (val == 0 || *val == '\0') - { - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - /* Handle decimal-like compatibility version specifications: 4.2 */ - if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0) - { - tens = val[0] - '0'; - ones = val[2] - '0'; - compatval = tens*10 + ones; - } - /* Handle integer-like compatibility version specifications: 42 */ - else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0) - { - tens = val[0] - '0'; - ones = val[1] - '0'; - compatval = tens*10 + ones; - } - else - { -compat_error: - internal_error (_("%s: %s: compatibility value out of range"), name, val); - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - set_compatibility_opts (); - return; - } - - if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL) - goto compat_error; - - shell_compatibility_level = compatval; - set_compatibility_opts (); -} - -#if defined (JOB_CONTROL) -void -sv_childmax (name) - char *name; -{ - char *tt; - int s; - - tt = get_string_value (name); - s = (tt && *tt) ? atoi (tt) : 0; - set_maxchild (s); -} -#endif