+++ /dev/null
- 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 <dearvoid@gmail.com>
-
- 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 <jue@jue.li>
-
-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
- <dearvoid@gmail.com>
-
-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 <dearvoid@gmail.com>
-
-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
- <vapier@gentoo.org>
-
- 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 <dennistwilliamson@gmail.com>
-
-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 <jojo@schmitz-digital.de>
-
-support/shobj-conf
- - add a stanza for nsk on the Tandem from Joachim Schmitz
- <jojo@schmitz-digital.de>
-
-{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
- <jojo@schmitz-digital.de>
-
- 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 <foutrelis@gmail.com>
-
- 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 <mfwitten@gmail.com>
-
-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
- <nathanael@gnat.ca> and Matthias Klose <doko@debian.org>
-
-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 <mfwitten@gmail.com>
- - 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 <mfwitten@gmail.com>
- - 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 <mfwitten@gmail.com>
- - 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 <mfwitten@gmail.com>
-
-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 <andres.p@zoho.com>
-
- 3/4
- ---
-lib/readline/bind.c
- - add a missing free of `names' in rl_function_dumper. Bug report
- and fix from Michael Snyder <msnyder@vmware.com>
-
- 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 <micah@cowan.name>
-
- 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 <torvalds@linux-foundation.org>, bug report originally
- from Oleg Nesterov <oleg@redhat.com>
-
- 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 <cfajohnson@gmail.com>
-
-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 <rrakus@redhat.com>
-
- 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 <werner@suse.de>
- - 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 <sam@liddicott.com>
-
- 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 <blue3waters@gmail.com>
-
- 3/26
- ----
-lib/readline/rltypedefs.h
- - remove old Function/VFunction/CPFunction/CPPFunction typedefs as
- suggested by Tom Tromey <tromey@redhat.com>
-
-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
- <tromey@redhat.com>
-
- 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 <dennistwilliamson@gmail.com>
-
-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 <h.bekel@googlemail.com>
-
- 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 <mfwitten@gmail.com>
-
-lib/readline/display.c
- - include <pc.h> 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 <pc.h> 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 <eliz@gnu.org>
-
- 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 <arbogast.cedric@gmail.com>
-
- 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 <mdinger.bugzilla@gmail.com>
-
-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 <dearvoid@gmail.com>
-
- 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 <rrakus@redhat.com>
-
- 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
- <piuma@piumalab.org>
-
- 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." <skunk@iSKUNK.ORG>
-
- 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
- <johan.hattne@utsouthwestern.edu>
-
- 5/2
- ---
-doc/{bash.1,bashref.texi}
- - add forward reference to `Pattern Matching' from `Pathname
- Expansion', suggested by Greg Wooledge <wooledg@eeg.ccf.org>
-
- 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 \<CTLESC> 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 <sbohrer@rgmadvisors.com>
-
- 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 <rrakus@redhat.com>
-
- 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 <rbyshko@gmail.com>
-
- 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 <marten.wikstrom@keystream.se>
-
- 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 <arbogast.cedric@gmail.com>
-
- 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 <mlichvar@redhat.com>
-
-builtins/help.def
- - help_builtin: change strncmp to strcmp so that `help read' no longer
- matches `readonly'. Suggested by Clark Wang <dearvoid@gmail.com>
-
-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 <samuel.thibault@gnu.org>
-
-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
- <d.l.tDecontes@free.fr>
-
- 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
- <keithw@mit.edu>
-
-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
- <cubranic@stat.ubc.ca>
-
- 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 <eblake@redhat.com>
-
- 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
- <kulkarniniraj14@gmail.com>
-
-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
- <mark.herbert@gmail.com>
-
-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
- <qiaomuf@gentoo.org>
-
- 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 <jrnieder@gmail.com>
-
-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
- <curtis@greenkey.net>
-
- 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 <lrhorer@satx.rr.com>
-
-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 <ville.skytta@iki.fi>
-
-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 <rsantos@grupopie.com>
-
-include/shmbutil.h
- - use locale_mb_cur_max instead of MB_CUR_MAX in ADVANCE_CHAR and
- similar macros
-
-lib/glob/smatch.c
- - rangecmp,rangecmp_wc: change to take an additional argument, which
- forces the use of strcoll/wscoll when non-zero. If it's 0, a new
- variable `glob_asciirange' controls whether or not we use strcoll/
- wscoll. If it's non-zero, we use straight C-locale-like ordering.
- Suggested by Aharon Robbins <arnold@skeeve.com>
-
- 6/30
- ----
-execute_cmd.c
- - execute_pipeline: make sure the lastpipe code is protected by
- #ifdef JOB_CONTROL. Fixes problem reported by Thomas Cort
- <tcort@minix3.org>
-
- 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 <jan.ktratochvil@redhat.com> 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 <arnold@skeeve.com>
-
- 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 <dearvoid@gmail.com>
- - _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
- <jan.kratochvil@redhat.com>
-
-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 <ralph@inputplus.co.uk>
-
- 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
- <mlichvar@redhat.com>
-
-builtins/printf.def
- - getint: if garglist == 0, return whatever getintmax returns (0).
- Fixes bug reported by Ralph Coredroy <ralph@inputplus.co.uk>
-
- 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 <gmargo@pacbell.net>
-
- 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
- <lhunath@lyndir.com>
-
- 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 <bash@tlinx.org>.
- 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
- <ohnobinki@ohnopublishing.net> -- 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 <vince.sheffer@apisphere.com>
-
-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 <rrakus@redhat.com>
-
- 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
- <rrakus@redhat.com>
-
- 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 <diegoaugustomolina@gmail.com>
-
- 9/19
- ----
-expr.c
- - exppower: replace the simple exponentiation algorithm with an
- implementation of exponentiation by squaring. Inspired by report
- from Nicolas ARGYROU <nargy@yahoo.com>
-
-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 <backuppc-users@whitleymott.net>
-
-doc/{bash.1,bashref.texi},lib/readline/doc/{hsuser,rluser}.texi
- - minor editorial changes inspired by suggestions from
- Roger Zauner <rogerx.oss@gmail.com>
-
- 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
- <bensberg@justemail.net>
- - 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 <daysleeper@centrum.cz>
-
- 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
- <bugs@kayari.org>
- - 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 <pto@linuxbog.dk> and Patrick Pfeifer
- <patrick@pfeifer.de>
- - 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 <patrick@pfeifer.de>
-
-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 <dearvoid@gmail.com>
-
-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 <davidparks21@yahoo.com>
-
- 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 <jreiser@bitwagon.com>
- 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 <vapier@gentoo.org> 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 <vapier@gentoo.org> 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 <Len.Giambrone@intersystems.com>
-
- 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
- <wooledg@eeg.ccf.org>
-
- 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 <lolilolicon@gmail.com>
-
- 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 <michael@kalisz.homelinux.net>
-
- 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 <jaak.ristioja@cyber.ee>
- - 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 <ormaaj@gmail.com>
-
- 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 <vapier@gentoo.org>
-
- 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
- <jens.schmidt35@arcor.de>
-
-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 <jan.ktratochvil@redhat.com> 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
- <stephane_chazelas@yahoo.fr>
-
-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 <eggert@cs.ucla.edu>
-
- 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 <schwab@linux-m68k.org>
-
-builtins/read.def
- - skip over NUL bytes in input, as most modern shells seem to. Bug
- report by Matthew Story <matt@tablethotels.com>
-
-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
- <pierre.gaston@gmail.com>
-
-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
- <g.clare@opengroup.org> 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 <yanegomi@gmail.com>
- - 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
- <yanegomi@gmail.com>
- - 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 <yanegomi@gmail.com>
- - 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
- <panyongzhi@gmail.com>
-
- 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 <panyongzhi@gmail.com>
- - 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
- <dearvoid@gmail.com>
-
- 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 <hanzl@noel.feld.cvut.cz>
-
- 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
- <kazikcz@gmail.com>
-
- 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 <dethrophes@motd005>
-
-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 <raphael.droz+floss@gmail.com>
- - 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
- <ormaaj@gmail.com>
-
-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 <pengyu.ut@gmail.com>
-
- 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
- <bill@ycc.com>
-
- 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 <p@draigbrady.com>
- - 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
- <raphael.droz+floss@gmail.com>
-
-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 <sungpae@gmail.com>
-
- 1/18
- ----
-
-{configure,config.h}.in
- - new check: check for AUDIT_USER_TTY defined in <linux/audit.h>,
- 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 <mlichvar@redhat.com>
-
- 1/21
- ----
-
-lib/readline/readline.c:
- - _rl_dispatch_subseq: add an inter-character timeout for multi-char
- key sequences. Suggested by <rogerx.oss@gmail.com>. 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 <ormaaj@gmail.com>
-
-
- 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
- <pierre.muller@ics-cnrs.unistra.fr>
-
-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 <bash@tlinx.org>
-
- 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 <james_avera@yahoo.com>
-
- 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 <rogerx.oss@gmail.com>
- - _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
- <rogerx.oss@gmail.com>
-
- 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 <schwab@linux-m68k.org>
-
-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
- <Ewan.Mellor@eu.citrix.com>
-
-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
- <ormaaj@gmail.com>
-
-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 <ormaaj@gmail.com>
-
- 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 <dethrophes@web.de>
-
-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 <dethrophes@web.de>
- - 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 <dethrophes@web.de>
-
- 2/21
- ----
-doc/{bash,builtins}.1
- - minor changes from Bjarni Ingi Gislason <bjarniig@rhi.hi.is>
-
-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 <derflob@derflob.de>
-
- 2/22
- ----
-lib/sh/shquote.c
- - sh_backslash_quote: quote tilde in places where it would be
- expanded. From a report from John Kearney <dethrophes@web.de>
-
- 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 <rdkehn@yahoo.com>
-
- 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 <dethrophes@web.de>
- - u32toutf16: function to convert unsigned 32-bit value (unicode) to
- UTF-16. From John Kearney <dethrophes@web.de>
- - 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 <dethrophes@web.de>
- - 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 <sar@nec-labs.com>
-
- 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 <ormaaj@gmail.com>
-
-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 <sami.pietila@gmail.com>
-
- 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
- <werner@suse.de> 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
- <fabrizio.ge@tiscali.it>
- - 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 <fabrizio.ge@tiscali.it>
-
-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
- <siddhesh@redhat.com>
-
-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 <medgar123@gmail.com>
-
-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 <jurij.mihelic@fri.uni-lj.si>
-
- 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 <bill@ycc.com>
-
- 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
- <rogerx.oss@gmail.com>; this prompted by report from Barry Downes
- <barry.downes@gmail.com>
-
-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
- <wooledg@eeg.ccf.org>
-
- 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 <stdbool.h> 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 <petr.sumbera@sun.com>
-
- 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 <petr.sumbera@sun.com>
- - 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 <arnold@skeeve.com>
-
- 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 <vapier@gentoo.org>,
- fix from Andreas Schwab <schwab@linux-m68k.org>
-
-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 <wooledg@eeg.ccf.org>
-
- 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 <RKuhlmann@orga-systems.com>
- - 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 <ormaaj@gmail.com>
-
-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 <ormaaj@gmail.com>
-
- 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 <ormaaj@gmail.com>
-
- 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 <backuppc-users@whitleymott.net> and
- supplemented by Dan Douglas <ormaaj@gmail.com>
-
-doc/{bash.1,bashref.texi}
- - changes to the description of substring expansion inspired by
- suggestions from Bill Gradwohl <bill@ycc.com>
-
-doc/bashref.texi
- - added substring expansion examples inspired by suggestions from
- Bill Gradwohl <bill@ycc.com>
-
-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 <stddef.h>. Fix from
- John E. Malmberg <wb8tyw@qsl.net>
-
- 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
- <levertond@googlemail.com>
-
- 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
- <scotty.mcmillan@gmail.com>
- - 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" <dave_br@gmx.com>
-
- 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 <bash@tlinx.org>
-
-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 <schweikh@schweikhardt.net>
-
- 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
- <nshyrokovskiy@gmail.com>
-
- 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 <ormaaj@gmail.com>
-
- 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 <wb8tyw@qsl.net>
-
- 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
- <svdb@stack.nl>, fix from Andreas Schwab <schwab@linux-m68k.org>
- - 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 <max@quendi.de>
-
- 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 <dennistwilliamson@gmail.com>
-
- 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 <dennistwilliamson@gmail.com>, fix from
- Andreas Schwab <schwab@linux-m68k.org>
- - 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 <rainer.blome@gmx.de>
-
-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 <pengyu.ut@gmail.com>
-
- 7/24
- ----
-configure.in
- - interix: define RECYCLES_PIDS. Based on a report from Michael
- Haubenwallner <michael.haubenwallner@salomon.at>
-
- 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
- <michael.haubenwallner@salomon.at>
-
-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 <michael.haubenwallner@salomon.at>
-
-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
- <michael.haubenwallner@salomon.at>
-
- 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 <lhunath@lyndir.com>
-
-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
- <lhunath@lyndir.com>
-
-{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 <sys/param.h> 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 <clark.wang@oracle.com>
-
- 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
- <dearvoid@gmail.com>
-
-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 <techlivezheng@gmail.com>
-
- 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 <ormaaj@gmail.com>
-
- 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 <armandsl@gmail.com>
-
-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 <vapier@gentoo.org>
-
- 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 <soltys@ziu.info>
-
-doc/bashref.texi
- - some small formatting changes from Karl Berry <karl@freefriends.org>
-
- 8/27
- ----
-lib/readline/doc/{history,rlman,rluserman}.texi
- - some small formatting changes from Karl Berry <karl@freefriends.org>
-
-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 <dennistwilliamson@gmail.com>
- and Chris F. A. Johnson <chris@cfajohnson.com>
-
-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 <stefano.lattarini@gmail.com>
-
-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}<file
-
-redir.c
- - redir_varassign: bind_var_to_int already handles array assignments,
- so don't need to do anything more for things like {a[i]}<file
- - redir_varvalue: changes to allow references to {a[i]} when
- performing redirections using valid_array_reference and
- get_array_value. Adds functionality requested most recently by
- <unknown@vmw-les.eng.vmware.com>
-
-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 <mkoskar@gmail.com> and most recently by Jordan Michael
- Ziegler <jziegler@bnl.gov>
-
-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
- <pierre.gaston@gmail.com>
-
- 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 <ormaaj@gmail.com>
-
- 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 <gerd.hofmann.nbg@googlemail.com>
-
-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 <vermaelen.wouter@gmail.com>
-
-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 <ormaaj@gmail.com>
-
- 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 <benoit.vaugon@gmail.com>
-
- 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 <rrakus@redhat.com>
-
-configure.ac
- - HP NonStop (*-nsk*): compile --without-bash-malloc. Change from
- Joachim Schmitz <jojo@schmitz-digital.de>
-
- 9/16
- ----
-subst.c,execute_cmd.c,lib/glob/sm_loop.c,lib/sh/shquote.c
- - minor code cleanups from Joachim Schmitz <jojo@schmitz-digital.de>
-
-lib/readline/colors.h
- - workaround for HP NonStop compiler issue with <stdbool.h> from
- Joachim Schmitz <jojo@schmitz-digital.de>
-
- 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 <dualbus@gmail.com>
-
-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 <info@skeena.net>
-
- 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 <pclouds@gmail.c
-
- 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
+++ /dev/null
-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.
+++ /dev/null
-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 <stdio.h>
-#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);
-}
+++ /dev/null
-/* 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 */
+++ /dev/null
-This file is help.def, from which is created help.c.
-It implements the builtin "help" in Bash.
-
-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 <http://www.gnu.org/licenses/>.
-
-$PRODUCES help.c
-
-$BUILTIN help
-$FUNCTION help_builtin
-$DEPENDS_ON HELP_BUILTIN
-$SHORT_DOC help [-dms] [pattern ...]
-Display information about builtin commands.
-
-Displays brief summaries of builtin commands. If PATTERN is
-specified, gives detailed help on all commands matching PATTERN,
-otherwise the list of help topics is printed.
-
-Options:
- -d output short description for each topic
- -m display usage in pseudo-manpage format
- -s output only a short usage synopsis for each topic matching
- PATTERN
-
-Arguments:
- PATTERN Pattern specifiying a help topic
-
-Exit Status:
-Returns success unless PATTERN is not found or an invalid option is given.
-$END
-
-#include <config.h>
-
-#if defined (HELP_BUILTIN)
-#include <stdio.h>
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include <errno.h>
-
-#include <filecntl.h>
-
-#include "../bashintl.h"
-
-#include "../shell.h"
-#include "../builtins.h"
-#include "../pathexp.h"
-#include "common.h"
-#include "bashgetopt.h"
-
-#include <glob/strmatch.h>
-#include <glob/glob.h>
-
-#ifndef errno
-extern int errno;
-#endif
-
-extern const char * const bash_copyright;
-extern const char * const bash_license;
-
-static void show_builtin_command_help __P((void));
-static int open_helpfile __P((char *));
-static void show_desc __P((char *, int));
-static void show_manpage __P((char *, int));
-static void show_longdoc __P((int));
-
-/* Print out a list of the known functions in the shell, and what they do.
- If LIST is supplied, print out the list which matches for each pattern
- specified. */
-int
-help_builtin (list)
- WORD_LIST *list;
-{
- register int i;
- char *pattern, *name;
- int plen, match_found, sflag, dflag, mflag;
-
- dflag = sflag = mflag = 0;
- reset_internal_getopt ();
- while ((i = internal_getopt (list, "dms")) != -1)
- {
- switch (i)
- {
- case 'd':
- dflag = 1;
- break;
- case 'm':
- mflag = 1;
- break;
- case 's':
- sflag = 1;
- break;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
-
- if (list == 0)
- {
- show_shell_version (0);
- show_builtin_command_help ();
- return (EXECUTION_SUCCESS);
- }
-
- /* We should consider making `help bash' do something. */
-
- if (glob_pattern_p (list->word->word))
- {
- printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
- print_word_list (list, ", ");
- printf ("'\n\n");
- }
-
- for (match_found = 0, pattern = ""; list; list = list->next)
- {
- pattern = list->word->word;
- plen = strlen (pattern);
-
- for (i = 0; name = shell_builtins[i].name; i++)
- {
- QUIT;
- if ((strcmp (pattern, name) == 0) ||
- (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH))
- {
- match_found++;
- if (dflag)
- {
- show_desc (name, i);
- continue;
- }
- else if (mflag)
- {
- show_manpage (name, i);
- continue;
- }
-
- printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
-
- if (sflag == 0)
- show_longdoc (i);
- }
- }
- }
-
- if (match_found == 0)
- {
- builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
- return (EXECUTION_FAILURE);
- }
-
- fflush (stdout);
- return (EXECUTION_SUCCESS);
-}
-
-static int
-open_helpfile (name)
- char *name;
-{
- int fd;
-
- fd = open (name, O_RDONLY);
- if (fd == -1)
- {
- builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
- return -1;
- }
- return fd;
-}
-
-/* By convention, enforced by mkbuiltins.c, if separate help files are being
- used, the long_doc array contains one string -- the full pathname of the
- help file for this builtin. */
-static void
-show_longdoc (i)
- int i;
-{
- register int j;
- char * const *doc;
- int fd;
-
- doc = shell_builtins[i].long_doc;
-
- if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
- {
- fd = open_helpfile (doc[0]);
- if (fd < 0)
- return;
- zcatfd (fd, 1, doc[0]);
- close (fd);
- }
- else if (doc)
- for (j = 0; doc[j]; j++)
- printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
-}
-
-static void
-show_desc (name, i)
- char *name;
- int i;
-{
- register int j;
- char **doc, *line;
- int fd, usefile;
-
- doc = (char **)shell_builtins[i].long_doc;
-
- usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
- if (usefile)
- {
- fd = open_helpfile (doc[0]);
- if (fd < 0)
- return;
- zmapfd (fd, &line, doc[0]);
- close (fd);
- }
- else
- line = doc ? doc[0] : (char *)NULL;
-
- printf ("%s - ", name);
- for (j = 0; line && line[j]; j++)
- {
- putchar (line[j]);
- if (line[j] == '\n')
- break;
- }
-
- fflush (stdout);
-
- if (usefile)
- free (line);
-}
-
-/* Print builtin help in pseudo-manpage format. */
-static void
-show_manpage (name, i)
- char *name;
- int i;
-{
- register int j;
- char **doc, *line;
- int fd, usefile;
-
- doc = (char **)shell_builtins[i].long_doc;
-
- usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
- if (usefile)
- {
- fd = open_helpfile (doc[0]);
- if (fd < 0)
- return;
- zmapfd (fd, &line, doc[0]);
- close (fd);
- }
- else
- line = doc ? _(doc[0]) : (char *)NULL;
-
- /* NAME */
- printf ("NAME\n");
- printf ("%*s%s - ", BASE_INDENT, " ", name);
- for (j = 0; line && line[j]; j++)
- {
- putchar (line[j]);
- if (line[j] == '\n')
- break;
- }
- printf ("\n");
-
- /* SYNOPSIS */
- printf ("SYNOPSIS\n");
- printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
-
- /* DESCRIPTION */
- printf ("DESCRIPTION\n");
- if (usefile == 0)
- {
- for (j = 0; doc[j]; j++)
- printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
- }
- else
- {
- for (j = 0; line && line[j]; j++)
- {
- putchar (line[j]);
- if (line[j] == '\n')
- printf ("%*s", BASE_INDENT, " ");
- }
- }
- putchar ('\n');
-
- /* SEE ALSO */
- printf ("SEE ALSO\n");
- printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
-
- /* IMPLEMENTATION */
- printf ("IMPLEMENTATION\n");
- printf ("%*s", BASE_INDENT, " ");
- show_shell_version (0);
- printf ("%*s", BASE_INDENT, " ");
- printf ("%s\n", _(bash_copyright));
- printf ("%*s", BASE_INDENT, " ");
- printf ("%s\n", _(bash_license));
-
- fflush (stdout);
- if (usefile)
- free (line);
-}
-
-static void
-dispcolumn (i, buf, bufsize, width, height)
- int i;
- char *buf;
- size_t bufsize;
- int width, height;
-{
- int j;
- int displen;
- char *helpdoc;
-
- /* first column */
- helpdoc = _(shell_builtins[i].short_doc);
-
- buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
- strncpy (buf + 1, helpdoc, width - 2);
- buf[width - 2] = '>'; /* indicate truncation */
- buf[width - 1] = '\0';
- printf ("%s", buf);
- if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
- {
- printf ("\n");
- return;
- }
-
- displen = strlen (buf);
- /* two spaces */
- for (j = displen; j < width; j++)
- putc (' ', stdout);
-
- /* second column */
- helpdoc = _(shell_builtins[i+height].short_doc);
-
- buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
- strncpy (buf + 1, helpdoc, width - 3);
- buf[width - 3] = '>'; /* indicate truncation */
- buf[width - 2] = '\0';
-
- printf ("%s\n", buf);
-}
-
-static void
-wdispcolumn (i, buf, bufsize, width, height)
- int i;
- char *buf;
- size_t bufsize;
- int width, height;
-{
- int j;
- int displen;
- char *helpdoc;
- wchar_t *wcstr;
- size_t slen;
- int wclen;
-
- /* first column */
- helpdoc = _(shell_builtins[i].short_doc);
-
- wcstr = 0;
- slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
- if (slen == -1)
- {
- dispcolumn (i, buf, bufsize, width, height);
- return;
- }
-
- /* No bigger than the passed max width */
- if (slen >= width)
- slen = width - 1;
- wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
- mbstowcs (wcstr+1, helpdoc, slen + 1);
-
- displen = wcsnwidth (wcstr+1, slen, width - 2);
-
- wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
-
- wcstr[width - 2] = L'>'; /* indicate truncation */
- wcstr[width - 1] = L'\0';
- printf ("%ls", wcstr);
- if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
- {
- printf ("\n");
- return;
- }
-
- /* two spaces */
- for (j = displen; j < width; j++)
- putc (' ', stdout);
-
- /* second column */
- helpdoc = _(shell_builtins[i+height].short_doc);
- slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
- if (slen == -1)
- {
- /* for now */
- printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
- return;
- }
-
- /* Reuse wcstr since it is already width wide chars long */
- if (slen >= width)
- slen = width - 1;
- mbstowcs (wcstr+1, helpdoc, slen + 1);
-
- displen = wcsnwidth (wcstr+1, slen, width - 3);
-
- wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
-
- wcstr[width - 3] = L'>'; /* indicate truncation */
- wcstr[width - 2] = L'\0';
- printf ("%ls\n", wcstr);
-
- free (wcstr);
-}
-
-static void
-show_builtin_command_help ()
-{
- int i, j;
- int height, width;
- char *t, blurb[128];
-
- printf (
-_("These shell commands are defined internally. Type `help' to see this list.\n\
-Type `help name' to find out more about the function `name'.\n\
-Use `info bash' to find out more about the shell in general.\n\
-Use `man -k' or `info' to find out more about commands not in this list.\n\
-\n\
-A star (*) next to a name means that the command is disabled.\n\
-\n"));
-
- t = get_string_value ("COLUMNS");
- width = (t && *t) ? atoi (t) : 80;
- if (width <= 0)
- width = 80;
-
- width /= 2;
- if (width > sizeof (blurb))
- width = sizeof (blurb);
- if (width <= 3)
- width = 40;
- height = (num_shell_builtins + 1) / 2; /* number of rows */
-
- for (i = 0; i < height; i++)
- {
- QUIT;
-
- wdispcolumn (i, blurb, sizeof (blurb), width, height);
- }
-}
-#endif /* HELP_BUILTIN */
+++ /dev/null
-# 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
+++ /dev/null
-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 <snowball3@bigfoot.com> 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 $(<filename) command substitution, which is equivalent to
- $(cat filename)
-new tilde prefixes that expand to directories from the directory stack
-new `**' arithmetic operator to do exponentiation
-case-insensitive globbing (filename expansion)
-menu completion a la tcsh
-`magic-space' history expansion function like tcsh
-the readline inputrc `language' has a new file inclusion directive ($include)
-
-Bash-2.01 contained only a few new features:
-
-new `GROUPS' builtin array variable containing the user's group list
-new bindable readline commands: history-and-alias-expand-line and
- alias-expand-line
-
-Bash-2.0 contained extensive changes and new features from bash-1.14.7.
-Here's a short list:
-
-new `time' reserved word to time pipelines, shell builtins, and
- shell functions
-one-dimensional arrays with a new compound assignment statement,
- appropriate expansion constructs and modifications to some
- of the builtins (read, declare, etc.) to use them
-new quoting syntaxes for ANSI-C string expansion and locale-specific
- string translation
-new expansions to do substring extraction, pattern replacement, and
- indirect variable expansion
-new builtins: `disown' and `shopt'
-new variables: HISTIGNORE, SHELLOPTS, PIPESTATUS, DIRSTACK, GLOBIGNORE,
- MACHTYPE, BASH_VERSINFO
-special handling of many unused or redundant variables removed
- (e.g., $notify, $glob_dot_filenames, $no_exit_on_failed_exec)
-dynamic loading of new builtin commands; many loadable examples provided
-new prompt expansions: \a, \e, \n, \H, \T, \@, \v, \V
-history and aliases available in shell scripts
-new readline variables: enable-keypad, mark-directories, input-meta,
- visible-stats, disable-completion, comment-begin
-new readline commands to manipulate the mark and operate on the region
-new readline emacs mode commands and bindings for ksh-88 compatibility
-updated and extended builtins
-new DEBUG trap
-expanded (and now documented) restricted shell mode
-
-implementation stuff:
-autoconf-based configuration
-nearly all of the bugs reported since version 1.14 have been fixed
-most builtins converted to use builtin `getopt' for consistency
-most builtins use -p option to display output in a reusable form
- (for consistency)
-grammar tighter and smaller (66 reduce-reduce conflicts gone)
-lots of code now smaller and faster
-test suite greatly expanded
-
-B2) Are there any user-visible incompatibilities between bash-2.05b and
- bash-1.14.7?
-
-There are a few incompatibilities between version 1.14.7 and version 2.05b.
-They are detailed in the file COMPAT in the bash distribution. That file
-is not meant to be all-encompassing; send mail to bash-maintainers@gnu.org
-if if you find something that's not mentioned there.
-
-Section C: Differences from other Unix shells
-
-C1) How does bash differ from sh, the Bourne shell?
-
-This is a non-comprehensive list of features that differentiate bash
-from the SVR4.2 shell. The bash manual page explains these more
-completely.
-
-Things bash has that sh does not:
- long invocation options
- [+-]O invocation option
- -l invocation option
- `!' reserved word to invert pipeline return value
- `time' reserved word to time pipelines and shell builtins
- the `function' reserved word
- the `select' compound command and reserved word
- arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done
- new $'...' and $"..." quoting
- the $(...) form of command substitution
- the $(<filename) form of command substitution, equivalent to
- $(cat filename)
- the ${#param} parameter value length operator
- 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
- expansions to perform substring removal (${p%[%]w}, ${p#[#]w})
- expansion of positional parameters beyond $9 with ${num}
- variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, REPLY,
- TIMEFORMAT, PPID, PWD, OLDPWD, SHLVL, RANDOM, SECONDS,
- LINENO, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, HOSTNAME,
- ENV, PS3, PS4, DIRSTACK, PIPESTATUS, HISTSIZE, HISTFILE,
- HISTFILESIZE, HISTCONTROL, HISTIGNORE, GLOBIGNORE, GROUPS,
- PROMPT_COMMAND, FCEDIT, FIGNORE, IGNOREEOF, INPUTRC,
- SHELLOPTS, OPTERR, HOSTFILE, TMOUT, FUNCNAME, histchars,
- auto_resume
- DEBUG trap
- ERR trap
- variable arrays with new compound assignment syntax
- redirections: <>, &>, >|, <<<, [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.
+++ /dev/null
-#
-# 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
+++ /dev/null
-#!/bin/bash
-# ash -- "Adventure shell"
-# last edit: 86/04/21 D A Gwyn
-# SCCS ID: @(#)ash.sh 1.4
-
-OPATH=$PATH
-
-ask()
-{
- echo -n "$@" '[y/n] '
- read ans
-
- case "$ans" in
- y*|Y*)
- return 0
- ;;
- *)
- return 1
- ;;
- esac
-}
-
-CAT=${PAGER:-more}
-
-ash_inst()
-{
- cat <<- EOF
-
- Instructions for the Adventure shell
-
- Welcome to the Adventure shell! In this exploration of the UNIX file
- system, I will act as your eyes and hands. As you move around, I will
- describe whatever is visible and will carry out your commands. The
- general form of a command is
- Verb Object Extra_stuff.
- Most commands pay no attention to the "Extra_stuff", and many do not
- need an "Object". A typical command is
- get all
- which picks up all files in the current "room" (directory). You can
- find out what you are carrying by typing the command
- inventory
- The command "help" results in a full description of all commands that I
- understand. To quit the Adventure shell, type
- quit
-
- There are UNIX monsters lurking in the background. These are also
- known as "commands with arguments".
-
- Good luck!
- EOF
-}
-
-ash_help()
-{
-echo "I understand the following commands (synonyms in parentheses):"
-echo ""
-
-echo "change OBJECT to NEW_NAME changes the name of the object"
-echo "clone OBJECT as NEW_NAME duplicates the object"
-echo "drop OBJECTS leaves the objects in the room"
-echo "enter (go) PASSAGE takes the labeled passage"
-echo "examine OBJECTS describes the objects in detail"
-echo "feed OBJECT to MONSTER stuffs the object into a UNIX monster"
-echo "get (take) OBJECTS picks up the specified objects"
-echo "gripe (bug) report a problem with the Adventure shell"
-echo "help prints this summary"
-echo "inventory (i) tells what you are carrying"
-echo "kill (destroy) OBJECTS destroys the objects"
-echo "look (l) describes the room, including hidden objects"
-echo "open (read) OBJECT shows the contents of an object"
-echo "quit (exit) leaves the Adventure shell"
-echo "resurrect OBJECTS attempts to restore dead objects"
-echo "steal OBJECT from MONSTER obtains the object from a UNIX monster"
-echo "throw OBJECT at daemon feeds the object to the printer daemon"
-echo "up takes the overhead passage"
-echo "wake MONSTER awakens a UNIX monster"
-echo "where (w) tells you where you are"
-echo "xyzzy moves you to your home"
-}
-
-MAINT=chet@ins.cwru.edu
-
-PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin:.
-export PATH
-
-trap 'echo Ouch!' 2 3
-#trap '' 18 # disable Berkeley job control
-
-ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
-ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; }
-ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }
-
-# enable history, bang history expansion, and emacs editing
-set -o history
-set -o histexpand
-set -o emacs
-
-cd
-LIM=.limbo # $HOME/$LIM contains "destroyed" objects
-mkdir $LIM >&- 2>&-
-KNAP=.knapsack # $HOME/$KNAP contains objects being "carried"
-if [ ! -d $KNAP ]
-then mkdir $KNAP >&- 2>&-
- if [ $? = 0 ]
- then echo 'You found a discarded empty knapsack.'
- else echo 'You have no knapsack to carry things in.'
- exit 1
- fi
-else echo 'One moment while I peek in your old knapsack...'
-fi
-
-kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\``
-
-if ask 'Welcome to the Adventure shell! Do you need instructions?'
-then
- ash_inst
- echo -n 'Type a newline to continue: '
- read
-fi
-
-wiz=false
-cha=false
-prev=$LIM
-while :
-do room=`pwd`
- if [ $room != $prev ]
- then if [ $room = $HOME ]
- then echo 'You are in your own home.'
- else echo "You have entered $room."
- fi
- exs=
- obs=
- hexs=
- hobs=
- f=false
- for i in `ls -a`
- do case $i in
- .|..) ;;
- .*) if [ -f $i ]
- then hobs="$hobs $i"
- elif [ -d $i ]
- then hexs="$hexs $i"
- else f=true
- fi
- ;;
- *) if [ -f $i ]
- then obs="$obs $i"
- elif [ -d $i ]
- then exs="$exs $i"
- else f=true
- fi
- ;;
- esac
- done
- if [ "$obs" ]
- then echo 'This room contains:'
- ash_pr $obs
- else echo 'The room looks empty.'
- fi
- if [ "$exs" ]
- then echo 'There are exits labeled:'
- ash_pr $exs
- echo 'as well as a passage overhead.'
- else echo 'There is a passage overhead.'
- fi
- if sh -c $f
- then echo 'There are shadowy figures in the corner.'
- fi
- prev=$room
- fi
-
- read -e -p '-advsh> ' verb obj x # prompt is '-advsh> '
- if [ $? != 0 ]
- then verb=quit # EOF
- fi
-
- case $verb in
- change) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then set -- $x
- case "$1" in
- to) if [ "$2" ]
- then if [ -f $2 ]
- then echo "You must destroy $2 first."
- set --
- fi
- if [ "$2" ]
- then if mv $obj $2 >&- 2>&-
- then echo "The $obj shimmers and turns into $2."
- obs=`ash_rm "$2 $obs" "$obj"`
- else echo "There is a cloud of smoke but the $obj is unchanged."
- fi
- fi
- else echo 'To what?'
- fi
- ;;
- *) echo "Change $obj to what?"
- ;;
- esac
- else if ash_lk "$kn" "$obj"
- then echo 'You must drop it first.'
- else echo "I see no $obj here."
- fi
- fi
- else echo 'Change what?'
- fi
- ;;
- clone) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then if [ ! -r $obj ]
- then echo "The $obj does not wish to be cloned."
- else set -- $x
- case "$1" in
- as) if [ "$2" ]
- then if [ -f $2 ]
- then echo "You must destroy $2 first."
- else if cp $obj $2 >&- 2>&-
- then echo "Poof! When the smoke clears, you see the new $2."
- obs="$obs $2"
- else echo 'You hear a dull thud but no clone appears.'
- fi
- fi
- else echo 'As what?'
- fi
- ;;
- *) echo "Clone $obj as what?"
- ;;
- esac
- fi
- else if ash_lk "$kn" "$obj"
- then echo 'You must drop it first.'
- else echo "I see no $obj here."
- fi
- fi
- else echo 'Clone what?'
- fi
- ;;
- drop) if [ "$obj" ]
- then for it in $obj $x
- do if ash_lk "$kn" "$it"
- then if [ -w $it ]
- then echo "You must destroy $it first."
- else if mv $HOME/$KNAP/$it $it >&- 2>&-
- then echo "$it: dropped."
- kn=`ash_rm "$kn" "$it"`
- obs=`echo $it $obs`
- else echo "The $it is caught in your knapsack."
- fi
- fi
- else echo "You're not carrying the $it!"
- fi
- done
- else echo 'Drop what?'
- fi
- ;;
- enter|go) if [ "$obj" ]
- then if [ $obj != up ]
- then if ash_lk "$exs $hexs" "$obj"
- then if [ -x $obj ]
- then if cd $obj
- then echo 'You squeeze through the passage.'
- else echo "You can't go that direction."
- fi
- else echo 'An invisible force blocks your way.'
- fi
- else echo 'I see no such passage.'
- fi
- else if cd ..
- then echo 'You struggle upwards.'
- else echo "You can't reach that high."
- fi
- fi
- else echo 'Which passage?'
- fi
- ;;
- examine) if [ "$obj" ]
- then if [ $obj = all ]
- then $obj=`echo $obs $exs`
- x=
- fi
- for it in $obj $x
- do if ash_lk "$obs $hobs $exs $hexs" "$it"
- then echo "Upon close inspection of the $it, you see:"
- ls -ld $it 2>&-
- if [ $? != 0 ]
- then echo "-- when you look directly at the $it, it vanishes."
- fi
- else if ash_lk "$kn" "$it"
- then echo 'You must drop it first.'
- else echo "I see no $it here."
- fi
- fi
- done
- else echo 'Examine what?'
- fi
- ;;
- feed) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then set -- $x
- case "$1" in
- to) if [ "$2" ]
- then shift
- if PATH=$OPATH $* <$obj 2>&-
- then echo "The $1 monster devours your $obj."
- if rm -f $obj >&- 2>&-
- then obs=`ash_rm "$obs" "$obj"`
- else echo 'But he spits it back up.'
- fi
- else echo "The $1 monster holds his nose in disdain."
- fi
- else echo 'To what?'
- fi
- ;;
- *) echo "Feed $obj to what?"
- ;;
- esac
- else if ash_lk "$kn" "$obj"
- then echo 'You must drop it first.'
- else echo "I see no $obj here."
- fi
- fi
- else echo 'Feed what?'
- fi
- ;;
- get|take) if [ "$obj" ]
- then if [ $obj = all ]
- then obj="$obs"
- x=
- fi
- for it in $obj $x
- do if ash_lk "$obs $hobs" "$it"
- then if ash_lk "$kn" "$it"
- then echo 'You already have one.'
- else if mv $it $HOME/$KNAP/$it >&- 2>&-
- then echo "$it: taken."
- kn="$it $kn"
- obs=`ash_rm "$obs" "$it"`
- else echo "The $it is too heavy."
- fi
- fi
- else echo "I see no $it here."
- fi
- done
- else echo 'Get what?'
- fi
- ;;
- gripe|bug) echo 'Please describe the problem and your situation at the time it failed.\nEnd the bug report with a line containing just a Ctrl-D.'
- cat | mail $MAINT -s 'ash bug'
- echo 'Thank you!'
- ;;
- help) ash_help
- ;;
- inventory|i) if [ "$kn" ]
- then echo 'Your knapsack contains:'
- ash_pr $kn
- else echo 'You are poverty-stricken.'
- fi
- ;;
- kill|destroy) if [ "$obj" ]
- then if [ $obj = all ]
- then x=
- if ask "Do you really want to attempt to $verb them all?"
- then obj=`echo $obs`
- else echo 'Chicken!'
- obj=
- fi
- fi
- for it in $obj $x
- do if ash_lk "$obs $hobs" "$it"
- then if mv $it $HOME/$LIM <&- >&- 2>&-
- then if [ $verb = kill ]
- then echo "The $it cannot defend himself; he dies."
- else echo "You have destroyed the $it; it vanishes."
- fi
- obs=`ash_rm "$obs" "$it"`
- else if [ $verb = kill ]
- then echo "Your feeble blows are no match for the $it."
- else echo "The $it is indestructible."
- fi
- fi
- else if ash_lk "$kn" "$it"
- then echo "You must drop the $it first."
- found=false
- else echo "I see no $it here."
- fi
- fi
- done
- else echo 'Kill what?'
- fi
- ;;
- look|l) obs=`echo $obs $hobs`
- hobs=
- if [ "$obs" ]
- then echo 'The room contains:'
- ash_pr $obs
- else echo 'The room is empty.'
- fi
- exs=`echo $exs $hexs`
- hexs=
- if [ "$exs" ]
- then echo 'There are exits plainly labeled:'
- ash_pr $exs
- echo 'and a passage directly overhead.'
- else echo 'The only exit is directly overhead.'
- fi
- ;;
- magic) if [ "$obj" = mode ]
- then if sh -c $cha
- then echo 'You had your chance and you blew it.'
- else if ask 'Are you a wizard?'
- then echo -n 'Prove it! Say the magic word: '
- read obj
- if [ "$obj" = armadillo ]
- then echo 'Yes, master!!'
- wiz=true
- else echo "Homie says: I don't think so"
- cha=true
- fi
- else echo "I didn't think so."
- fi
- fi
- else echo 'Nice try.'
- fi
- ;;
- open|read) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then if [ -r $obj ]
- then if [ -s $obj ]
- then echo "Opening the $obj reveals:"
- $CAT < $obj
- if [ $? != 0 ]
- then echo '-- oops, you lost the contents!'
- fi
- else echo "There is nothing inside the $obj."
- fi
- else echo "You do not have the proper tools to open the $obj."
- fi
- else if ash_lk "$kn" "$obj"
- then echo 'You must drop it first.'
- found=false
- else echo "I see no $obj here."
- fi
- fi
- else echo 'Open what?'
- fi
- ;;
- quit|exit) if ask 'Do you really want to quit now?'
- then if [ "$kn" ]
- then echo 'The contents of your knapsack will still be there next time.'
- fi
- rm -rf $HOME/$LIM
- echo 'See you later!'
- exit 0
- fi
- ;;
- resurrect) if [ "$obj" ]
- then for it in $obj $x
- do if ash_lk "$obs $hobs" "$it"
- then echo "The $it is already alive and well."
- else if mv $HOME/$LIM/$it $it <&- >&- 2>&-
- then echo "The $it staggers to his feet."
- obs=`echo $it $obs`
- else echo "There are sparks but no $it appears."
- fi
- fi
- done
- else echo 'Resurrect what?'
- fi
- ;;
- steal) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then echo 'There is already one here.'
- else set -- $x
- case "$1" in
- from) if [ "$2" ]
- then shift
- if PATH=$OPATH $* >$obj 2>&-
- then echo "The $1 monster drops the $obj."
- obs=`echo $obj $obs`
- else echo "The $1 monster runs away as you approach."
- rm -f $obj >&- 2>&-
- fi
- else echo 'From what?'
- fi
- ;;
- *) echo "Steal $obj from what?"
- ;;
- esac
- fi
- else echo 'Steal what?'
- fi
- ;;
- throw) if [ "$obj" ]
- then if ash_lk "$obs $hobs" "$obj"
- then set -- $x
- case "$1" in
- at) case "$2" in
- daemon) if sh -c "lpr -r $obj"
- then echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket."
- obs=`ash_rm "$obs" "$obj"`
- else echo "The daemon is nowhere to be found."
- fi
- ;;
- *) echo 'At what?'
- ;;
- esac
- ;;
- *) echo "Throw $obj at what?"
- ;;
- esac
- else if ash_lk "$kn" "$obj"
- then echo 'It is in your knapsack.'
- found=false
- else echo "I see no $obj here."
- fi
- fi
- else echo 'Throw what?'
- fi
- ;;
- u|up) if cd ..
- then echo 'You pull yourself up a level.'
- else echo "You can't reach that high."
- fi
- ;;
- wake) if [ "$obj" ]
- then echo "You awaken the $obj monster:"
- PATH=$OPATH $obj $x
- echo 'The monster slithers back into the darkness.'
- else echo 'Wake what?'
- fi
- ;;
- w|where) echo "You are in $room."
- ;;
- xyzzy) if cd
- then echo 'A strange feeling comes over you.'
- else echo 'Your spell fizzles out.'
- fi
- ;;
- *) if [ "$verb" ]
- then if sh -c $wiz
- then PATH=$OPATH $verb $obj $x
- else echo "I don't know how to \"$verb\"."
- echo 'Type "help" for assistance.'
- fi
- else echo 'Say something!'
- fi
- ;;
- esac
-done
+++ /dev/null
-/* execute_cmd.c -- Execute a COMMAND structure. */
-
-/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "config.h"
-
-#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
- #pragma alloca
-#endif /* _AIX && RISC6000 && !__GNUC__ */
-
-#include <stdio.h>
-#include "chartypes.h"
-#include "bashtypes.h"
-#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif
-#include "filecntl.h"
-#include "posixstat.h"
-#include <signal.h>
-#if defined (HAVE_SYS_PARAM_H)
-# include <sys/param.h>
-#endif
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "posixtime.h"
-
-#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE)
-# include <sys/resource.h>
-#endif
-
-#if defined (HAVE_SYS_TIMES_H) && defined (HAVE_TIMES)
-# include <sys/times.h>
-#endif
-
-#include <errno.h>
-
-#if !defined (errno)
-extern int errno;
-#endif
-
-#define NEED_FPURGE_DECL
-
-#include "bashansi.h"
-#include "bashintl.h"
-
-#include "memalloc.h"
-#include "shell.h"
-#include <y.tab.h> /* use <...> so we pick it up from the build directory */
-#include "flags.h"
-#include "builtins.h"
-#include "hashlib.h"
-#include "jobs.h"
-#include "execute_cmd.h"
-#include "findcmd.h"
-#include "redir.h"
-#include "trap.h"
-#include "pathexp.h"
-#include "hashcmd.h"
-
-#if defined (COND_COMMAND)
-# include "test.h"
-#endif
-
-#include "builtins/common.h"
-#include "builtins/builtext.h" /* list of builtins */
-
-#include <glob/strmatch.h>
-#include <tilde/tilde.h>
-
-#if defined (BUFFERED_INPUT)
-# include "input.h"
-#endif
-
-#if defined (ALIAS)
-# include "alias.h"
-#endif
-
-#if defined (HISTORY)
-# include "bashhist.h"
-#endif
-
-extern int dollar_dollar_pid;
-extern int posixly_correct;
-extern int expand_aliases;
-extern int autocd;
-extern int breaking, continuing, loop_level;
-extern int parse_and_execute_level, running_trap, sourcelevel;
-extern int command_string_index, line_number;
-extern int dot_found_in_search;
-extern int already_making_children;
-extern int tempenv_assign_error;
-extern char *the_printed_command, *shell_name;
-extern pid_t last_command_subst_pid;
-extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
-extern char **subshell_argv, **subshell_envp;
-extern int subshell_argc;
-extern time_t shell_start_time;
-#if 0
-extern char *glob_argv_flags;
-#endif
-
-extern int job_control; /* XXX */
-
-extern int close __P((int));
-
-/* Static functions defined and used in this file. */
-static void close_pipes __P((int, int));
-static void do_piping __P((int, int));
-static void bind_lastarg __P((char *));
-static int shell_control_structure __P((enum command_type));
-static void cleanup_redirects __P((REDIRECT *));
-
-#if defined (JOB_CONTROL)
-static int restore_signal_mask __P((sigset_t *));
-#endif
-
-static void async_redirect_stdin __P((void));
-
-static int builtin_status __P((int));
-
-static int execute_for_command __P((FOR_COM *));
-#if defined (SELECT_COMMAND)
-static int displen __P((const char *));
-static int print_index_and_element __P((int, int, WORD_LIST *));
-static void indent __P((int, int));
-static void print_select_list __P((WORD_LIST *, int, int, int));
-static char *select_query __P((WORD_LIST *, int, char *, int));
-static int execute_select_command __P((SELECT_COM *));
-#endif
-#if defined (DPAREN_ARITHMETIC)
-static int execute_arith_command __P((ARITH_COM *));
-#endif
-#if defined (COND_COMMAND)
-static int execute_cond_node __P((COND_COM *));
-static int execute_cond_command __P((COND_COM *));
-#endif
-#if defined (COMMAND_TIMING)
-static int mkfmt __P((char *, int, int, time_t, int));
-static void print_formatted_time __P((FILE *, char *,
- time_t, int, time_t, int,
- time_t, int, int));
-static int time_command __P((COMMAND *, int, int, int, struct fd_bitmap *));
-#endif
-#if defined (ARITH_FOR_COMMAND)
-static intmax_t eval_arith_for_expr __P((WORD_LIST *, int *));
-static int execute_arith_for_command __P((ARITH_FOR_COM *));
-#endif
-static int execute_case_command __P((CASE_COM *));
-static int execute_while_command __P((WHILE_COM *));
-static int execute_until_command __P((WHILE_COM *));
-static int execute_while_or_until __P((WHILE_COM *, int));
-static int execute_if_command __P((IF_COM *));
-static int execute_null_command __P((REDIRECT *, int, int, int));
-static void fix_assignment_words __P((WORD_LIST *));
-static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *));
-static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int));
-static int execute_function __P((SHELL_VAR *, WORD_LIST *, int, struct fd_bitmap *, int, int));
-static int execute_builtin_or_function __P((WORD_LIST *, sh_builtin_func_t *,
- SHELL_VAR *,
- REDIRECT *, struct fd_bitmap *, int));
-static void execute_subshell_builtin_or_function __P((WORD_LIST *, REDIRECT *,
- sh_builtin_func_t *,
- SHELL_VAR *,
- int, int, int,
- struct fd_bitmap *,
- int));
-static int execute_disk_command __P((WORD_LIST *, REDIRECT *, char *,
- int, int, int, struct fd_bitmap *, int));
-
-static char *getinterp __P((char *, int, int *));
-static void initialize_subshell __P((void));
-static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *));
-#if defined (COPROCESS_SUPPORT)
-static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *));
-#endif
-
-static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *));
-
-static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *));
-
-static int execute_intern_function __P((WORD_DESC *, FUNCTION_DEF *));
-
-/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global
- so that reader_loop can set it to zero before executing a command. */
-int stdin_redir;
-
-/* The name of the command that is currently being executed.
- `test' needs this, for example. */
-char *this_command_name;
-
-/* The printed representation of the currently-executing command (same as
- the_printed_command), except when a trap is being executed. Useful for
- a debugger to know where exactly the program is currently executing. */
-char *the_printed_command_except_trap;
-
-/* For catching RETURN in a function. */
-int return_catch_flag;
-int return_catch_value;
-procenv_t return_catch;
-
-/* The value returned by the last synchronous command. */
-int last_command_exit_value;
-
-/* Whether or not the last command (corresponding to last_command_exit_value)
- was terminated by a signal, and, if so, which one. */
-int last_command_exit_signal;
-
-/* The list of redirections to perform which will undo the redirections
- that I made in the shell. */
-REDIRECT *redirection_undo_list = (REDIRECT *)NULL;
-
-/* The list of redirections to perform which will undo the internal
- redirections performed by the `exec' builtin. These are redirections
- that must be undone even when exec discards redirection_undo_list. */
-REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL;
-
-/* When greater than zero, value is the `level' of builtins we are
- currently executing (e.g. `eval echo a' would have it set to 2). */
-int executing_builtin = 0;
-
-/* Non-zero if we are executing a command list (a;b;c, etc.) */
-int executing_list = 0;
-
-/* Non-zero if failing commands in a command substitution should not exit the
- shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to
- commands run in command substitutions by parse_and_execute. */
-int comsub_ignore_return = 0;
-
-/* Non-zero if we have just forked and are currently running in a subshell
- environment. */
-int subshell_environment;
-
-/* Count of nested subshells, like SHLVL. Available via $BASH_SUBSHELL */
-int subshell_level = 0;
-
-/* Currently-executing shell function. */
-SHELL_VAR *this_shell_function;
-
-/* If non-zero, matches in case and [[ ... ]] are case-insensitive */
-int match_ignore_case = 0;
-
-int executing_command_builtin = 0;
-
-struct stat SB; /* used for debugging */
-
-static int special_builtin_failed;
-
-static COMMAND *currently_executing_command;
-
-/* The line number that the currently executing function starts on. */
-static int function_line_number;
-
-/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line
- number containing the function name. Used by executing_line_number to
- report the correct line number. Kind of a hack. */
-static int showing_function_line;
-
-/* $LINENO ($BASH_LINENO) for use by an ERR trap. Global so parse_and_execute
- can save and restore it. */
-int line_number_for_err_trap;
-
-/* A sort of function nesting level counter */
-int funcnest = 0;
-int funcnest_max = 0; /* XXX - bash-4.2 */
-
-int lastpipe_opt = 0;
-
-struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL;
-
-#define FD_BITMAP_DEFAULT_SIZE 32
-
-/* Functions to allocate and deallocate the structures used to pass
- information from the shell to its children about file descriptors
- to close. */
-struct fd_bitmap *
-new_fd_bitmap (size)
- int size;
-{
- struct fd_bitmap *ret;
-
- ret = (struct fd_bitmap *)xmalloc (sizeof (struct fd_bitmap));
-
- ret->size = size;
-
- if (size)
- {
- ret->bitmap = (char *)xmalloc (size);
- memset (ret->bitmap, '\0', size);
- }
- else
- ret->bitmap = (char *)NULL;
- return (ret);
-}
-
-void
-dispose_fd_bitmap (fdbp)
- struct fd_bitmap *fdbp;
-{
- FREE (fdbp->bitmap);
- free (fdbp);
-}
-
-void
-close_fd_bitmap (fdbp)
- struct fd_bitmap *fdbp;
-{
- register int i;
-
- if (fdbp)
- {
- for (i = 0; i < fdbp->size; i++)
- if (fdbp->bitmap[i])
- {
- close (i);
- fdbp->bitmap[i] = 0;
- }
- }
-}
-
-/* Return the line number of the currently executing command. */
-int
-executing_line_number ()
-{
- if (executing && showing_function_line == 0 &&
- (variable_context == 0 || interactive_shell == 0) &&
- currently_executing_command)
- {
-#if defined (COND_COMMAND)
- if (currently_executing_command->type == cm_cond)
- return currently_executing_command->value.Cond->line;
-#endif
-#if defined (DPAREN_ARITHMETIC)
- else if (currently_executing_command->type == cm_arith)
- return currently_executing_command->value.Arith->line;
-#endif
-#if defined (ARITH_FOR_COMMAND)
- else if (currently_executing_command->type == cm_arith_for)
- return currently_executing_command->value.ArithFor->line;
-#endif
-
- return line_number;
- }
- else
- return line_number;
-}
-
-/* Execute the command passed in COMMAND. COMMAND is exactly what
- read_command () places into GLOBAL_COMMAND. See "command.h" for the
- details of the command structure.
-
- EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible
- return values. Executing a command with nothing in it returns
- EXECUTION_SUCCESS. */
-int
-execute_command (command)
- COMMAND *command;
-{
- struct fd_bitmap *bitmap;
- int result;
-
- current_fds_to_close = (struct fd_bitmap *)NULL;
- bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE);
- begin_unwind_frame ("execute-command");
- add_unwind_protect (dispose_fd_bitmap, (char *)bitmap);
-
- /* Just do the command, but not asynchronously. */
- result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap);
-
- dispose_fd_bitmap (bitmap);
- discard_unwind_frame ("execute-command");
-
-#if defined (PROCESS_SUBSTITUTION)
- /* don't unlink fifos if we're in a shell function; wait until the function
- returns. */
- if (variable_context == 0)
- unlink_fifo_list ();
-#endif /* PROCESS_SUBSTITUTION */
-
- QUIT;
- return (result);
-}
-
-/* Return 1 if TYPE is a shell control structure type. */
-static int
-shell_control_structure (type)
- enum command_type type;
-{
- switch (type)
- {
-#if defined (ARITH_FOR_COMMAND)
- case cm_arith_for:
-#endif
-#if defined (SELECT_COMMAND)
- case cm_select:
-#endif
-#if defined (DPAREN_ARITHMETIC)
- case cm_arith:
-#endif
-#if defined (COND_COMMAND)
- case cm_cond:
-#endif
- case cm_case:
- case cm_while:
- case cm_until:
- case cm_if:
- case cm_for:
- case cm_group:
- case cm_function_def:
- return (1);
-
- default:
- return (0);
- }
-}
-
-/* A function to use to unwind_protect the redirection undo list
- for loops. */
-static void
-cleanup_redirects (list)
- REDIRECT *list;
-{
- do_redirections (list, RX_ACTIVE);
- dispose_redirects (list);
-}
-
-#if 0
-/* Function to unwind_protect the redirections for functions and builtins. */
-static void
-cleanup_func_redirects (list)
- REDIRECT *list;
-{
- do_redirections (list, RX_ACTIVE);
-}
-#endif
-
-void
-dispose_exec_redirects ()
-{
- if (exec_redirection_undo_list)
- {
- dispose_redirects (exec_redirection_undo_list);
- exec_redirection_undo_list = (REDIRECT *)NULL;
- }
-}
-
-#if defined (JOB_CONTROL)
-/* A function to restore the signal mask to its proper value when the shell
- is interrupted or errors occur while creating a pipeline. */
-static int
-restore_signal_mask (set)
- sigset_t *set;
-{
- return (sigprocmask (SIG_SETMASK, set, (sigset_t *)NULL));
-}
-#endif /* JOB_CONTROL */
-
-#ifdef DEBUG
-/* A debugging function that can be called from gdb, for instance. */
-void
-open_files ()
-{
- register int i;
- int f, fd_table_size;
-
- fd_table_size = getdtablesize ();
-
- fprintf (stderr, "pid %ld open files:", (long)getpid ());
- for (i = 3; i < fd_table_size; i++)
- {
- if ((f = fcntl (i, F_GETFD, 0)) != -1)
- fprintf (stderr, " %d (%s)", i, f ? "close" : "open");
- }
- fprintf (stderr, "\n");
-}
-#endif
-
-static void
-async_redirect_stdin ()
-{
- int fd;
-
- fd = open ("/dev/null", O_RDONLY);
- if (fd > 0)
- {
- dup2 (fd, 0);
- close (fd);
- }
- else if (fd < 0)
- internal_error (_("cannot redirect standard input from /dev/null: %s"), strerror (errno));
-}
-
-#define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0)
-
-/* Execute the command passed in COMMAND, perhaps doing it asynchrounously.
- COMMAND is exactly what read_command () places into GLOBAL_COMMAND.
- ASYNCHROUNOUS, if non-zero, says to do this command in the background.
- PIPE_IN and PIPE_OUT are file descriptors saying where input comes
- from and where it goes. They can have the value of NO_PIPE, which means
- I/O is stdin/stdout.
- FDS_TO_CLOSE is a list of file descriptors to close once the child has
- been forked. This list often contains the unusable sides of pipes, etc.
-
- EXECUTION_SUCCESS or EXECUTION_FAILURE are the only possible
- return values. Executing a command with nothing in it returns
- EXECUTION_SUCCESS. */
-int
-execute_command_internal (command, asynchronous, pipe_in, pipe_out,
- fds_to_close)
- COMMAND *command;
- int asynchronous;
- int pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- int exec_result, user_subshell, invert, ignore_return, was_error_trap;
- REDIRECT *my_undo_list, *exec_undo_list;
- volatile int last_pid;
- volatile int save_line_number;
-#if defined (PROCESS_SUBSTITUTION)
- volatile int ofifo, nfifo, osize, saved_fifo;
- volatile char *ofifo_list;
-#endif
-
- if (breaking || continuing)
- return (last_command_exit_value);
- if (command == 0 || read_but_dont_execute)
- return (EXECUTION_SUCCESS);
-
- QUIT;
- run_pending_traps ();
-
-#if 0
- if (running_trap == 0)
-#endif
- currently_executing_command = command;
-
- invert = (command->flags & CMD_INVERT_RETURN) != 0;
-
- /* If we're inverting the return value and `set -e' has been executed,
- we don't want a failing command to inadvertently cause the shell
- to exit. */
- if (exit_immediately_on_error && invert) /* XXX */
- command->flags |= CMD_IGNORE_RETURN; /* XXX */
-
- exec_result = EXECUTION_SUCCESS;
-
- /* If a command was being explicitly run in a subshell, or if it is
- a shell control-structure, and it has a pipe, then we do the command
- in a subshell. */
- if (command->type == cm_subshell && (command->flags & CMD_NO_FORK))
- return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close));
-
-#if defined (COPROCESS_SUPPORT)
- if (command->type == cm_coproc)
- return (execute_coproc (command, pipe_in, pipe_out, fds_to_close));
-#endif
-
- user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0);
-
- if (command->type == cm_subshell ||
- (command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) ||
- (shell_control_structure (command->type) &&
- (pipe_out != NO_PIPE || pipe_in != NO_PIPE || asynchronous)))
- {
- pid_t paren_pid;
- int s;
-
- /* Fork a subshell, turn off the subshell bit, turn off job
- control and call execute_command () on the command again. */
- line_number_for_err_trap = line_number;
- paren_pid = make_child (savestring (make_command_string (command)),
- asynchronous);
-
- if (user_subshell && signal_is_trapped (ERROR_TRAP) &&
- signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- if (paren_pid == 0)
- {
- /* We want to run the exit trap for forced {} subshells, and we
- want to note this before execute_in_subshell modifies the
- COMMAND struct. Need to keep in mind that execute_in_subshell
- runs the exit trap for () subshells itself. */
- s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous;
-
- last_command_exit_value = execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close);
- if (s)
- subshell_exit (last_command_exit_value);
- else
- exit (last_command_exit_value);
- /* NOTREACHED */
- }
- else
- {
- close_pipes (pipe_in, pipe_out);
-
-#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
- if (variable_context == 0) /* wait until shell function completes */
- unlink_fifo_list ();
-#endif
- /* If we are part of a pipeline, and not the end of the pipeline,
- then we should simply return and let the last command in the
- pipe be waited for. If we are not in a pipeline, or are the
- last command in the pipeline, then we wait for the subshell
- and return its exit status as usual. */
- if (pipe_out != NO_PIPE)
- return (EXECUTION_SUCCESS);
-
- stop_pipeline (asynchronous, (COMMAND *)NULL);
-
- if (asynchronous == 0)
- {
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- invert = (command->flags & CMD_INVERT_RETURN) != 0;
- ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
-
- exec_result = wait_for (paren_pid);
-
- /* If we have to, invert the return value. */
- if (invert)
- exec_result = ((exec_result == EXECUTION_SUCCESS)
- ? EXECUTION_FAILURE
- : EXECUTION_SUCCESS);
-
- last_command_exit_value = exec_result;
- if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
- {
- save_line_number = line_number;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
- {
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- return (last_command_exit_value);
- }
- else
- {
- DESCRIBE_PID (paren_pid);
-
- run_pending_traps ();
-
- return (EXECUTION_SUCCESS);
- }
- }
- }
-
-#if defined (COMMAND_TIMING)
- if (command->flags & CMD_TIME_PIPELINE)
- {
- if (asynchronous)
- {
- command->flags |= CMD_FORCE_SUBSHELL;
- exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close);
- }
- else
- {
- exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close);
-#if 0
- if (running_trap == 0)
-#endif
- currently_executing_command = (COMMAND *)NULL;
- }
- return (exec_result);
- }
-#endif /* COMMAND_TIMING */
-
- if (shell_control_structure (command->type) && command->redirects)
- stdin_redir = stdin_redirects (command->redirects);
-
-#if defined (PROCESS_SUBSTITUTION)
- if (variable_context != 0)
- {
- ofifo = num_fifos ();
- ofifo_list = copy_fifo_list ((int *)&osize);
- saved_fifo = 1;
- }
- else
- saved_fifo = 0;
-#endif
-
- /* Handle WHILE FOR CASE etc. with redirections. (Also '&' input
- redirection.) */
- if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 0)
- {
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
- dispose_exec_redirects ();
-#if defined (PROCESS_SUBSTITUTION)
- if (saved_fifo)
- free ((void *)ofifo_list);
-#endif
- return (last_command_exit_value = EXECUTION_FAILURE);
- }
-
- if (redirection_undo_list)
- {
- /* XXX - why copy here? */
- my_undo_list = (REDIRECT *)copy_redirects (redirection_undo_list);
- dispose_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
- }
- else
- my_undo_list = (REDIRECT *)NULL;
-
- if (exec_redirection_undo_list)
- {
- /* XXX - why copy here? */
- exec_undo_list = (REDIRECT *)copy_redirects (exec_redirection_undo_list);
- dispose_redirects (exec_redirection_undo_list);
- exec_redirection_undo_list = (REDIRECT *)NULL;
- }
- else
- exec_undo_list = (REDIRECT *)NULL;
-
- if (my_undo_list || exec_undo_list)
- begin_unwind_frame ("loop_redirections");
-
- if (my_undo_list)
- add_unwind_protect ((Function *)cleanup_redirects, my_undo_list);
-
- if (exec_undo_list)
- add_unwind_protect ((Function *)dispose_redirects, exec_undo_list);
-
- ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
-
- QUIT;
-
- switch (command->type)
- {
- case cm_simple:
- {
- save_line_number = line_number;
- /* We can't rely on variables retaining their values across a
- call to execute_simple_command if a longjmp occurs as the
- result of a `return' builtin. This is true for sure with gcc. */
-#if defined (RECYCLES_PIDS)
- last_made_pid = NO_PID;
-#endif
- last_pid = last_made_pid;
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
-
- if (ignore_return && command->value.Simple)
- command->value.Simple->flags |= CMD_IGNORE_RETURN;
- if (command->flags & CMD_STDIN_REDIR)
- command->value.Simple->flags |= CMD_STDIN_REDIR;
-
- line_number_for_err_trap = line_number = command->value.Simple->line;
- exec_result =
- execute_simple_command (command->value.Simple, pipe_in, pipe_out,
- asynchronous, fds_to_close);
- line_number = save_line_number;
-
- /* The temporary environment should be used for only the simple
- command immediately following its definition. */
- dispose_used_env_vars ();
-
-#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA)
- /* Reclaim memory allocated with alloca () on machines which
- may be using the alloca emulation code. */
- (void) alloca (0);
-#endif /* (ultrix && mips) || C_ALLOCA */
-
- /* If we forked to do the command, then we must wait_for ()
- the child. */
-
- /* XXX - this is something to watch out for if there are problems
- when the shell is compiled without job control. Don't worry about
- whether or not last_made_pid == last_pid; already_making_children
- tells us whether or not there are unwaited-for children to wait
- for and reap. */
- if (already_making_children && pipe_out == NO_PIPE)
- {
- stop_pipeline (asynchronous, (COMMAND *)NULL);
-
- if (asynchronous)
- {
- DESCRIBE_PID (last_made_pid);
- }
- else
-#if !defined (JOB_CONTROL)
- /* Do not wait for asynchronous processes started from
- startup files. */
- if (last_made_pid != last_asynchronous_pid)
-#endif
- /* When executing a shell function that executes other
- commands, this causes the last simple command in
- the function to be waited for twice. This also causes
- subshells forked to execute builtin commands (e.g., in
- pipelines) to be waited for twice. */
- exec_result = wait_for (last_made_pid);
- }
- }
-
- /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles
- only the failure of a simple command. */
- if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (ignore_return == 0 && invert == 0 &&
- ((posixly_correct && interactive == 0 && special_builtin_failed) ||
- (exit_immediately_on_error && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS)))
- {
- last_command_exit_value = exec_result;
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- break;
-
- case cm_for:
- if (ignore_return)
- command->value.For->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_for_command (command->value.For);
- break;
-
-#if defined (ARITH_FOR_COMMAND)
- case cm_arith_for:
- if (ignore_return)
- command->value.ArithFor->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_arith_for_command (command->value.ArithFor);
- break;
-#endif
-
-#if defined (SELECT_COMMAND)
- case cm_select:
- if (ignore_return)
- command->value.Select->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_select_command (command->value.Select);
- break;
-#endif
-
- case cm_case:
- if (ignore_return)
- command->value.Case->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_case_command (command->value.Case);
- break;
-
- case cm_while:
- if (ignore_return)
- command->value.While->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_while_command (command->value.While);
- break;
-
- case cm_until:
- if (ignore_return)
- command->value.While->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_until_command (command->value.While);
- break;
-
- case cm_if:
- if (ignore_return)
- command->value.If->flags |= CMD_IGNORE_RETURN;
- exec_result = execute_if_command (command->value.If);
- break;
-
- case cm_group:
-
- /* This code can be executed from either of two paths: an explicit
- '{}' command, or via a function call. If we are executed via a
- function call, we have already taken care of the function being
- executed in the background (down there in execute_simple_command ()),
- and this command should *not* be marked as asynchronous. If we
- are executing a regular '{}' group command, and asynchronous == 1,
- we must want to execute the whole command in the background, so we
- need a subshell, and we want the stuff executed in that subshell
- (this group command) to be executed in the foreground of that
- subshell (i.e. there will not be *another* subshell forked).
-
- What we do is to force a subshell if asynchronous, and then call
- execute_command_internal again with asynchronous still set to 1,
- but with the original group command, so the printed command will
- look right.
-
- The code above that handles forking off subshells will note that
- both subshell and async are on, and turn off async in the child
- after forking the subshell (but leave async set in the parent, so
- the normal call to describe_pid is made). This turning off
- async is *crucial*; if it is not done, this will fall into an
- infinite loop of executions through this spot in subshell after
- subshell until the process limit is exhausted. */
-
- if (asynchronous)
- {
- command->flags |= CMD_FORCE_SUBSHELL;
- exec_result =
- execute_command_internal (command, 1, pipe_in, pipe_out,
- fds_to_close);
- }
- else
- {
- if (ignore_return && command->value.Group->command)
- command->value.Group->command->flags |= CMD_IGNORE_RETURN;
- exec_result =
- execute_command_internal (command->value.Group->command,
- asynchronous, pipe_in, pipe_out,
- fds_to_close);
- }
- break;
-
- case cm_connection:
- exec_result = execute_connection (command, asynchronous,
- pipe_in, pipe_out, fds_to_close);
- break;
-
-#if defined (DPAREN_ARITHMETIC)
- case cm_arith:
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- if (ignore_return)
- command->value.Arith->flags |= CMD_IGNORE_RETURN;
- line_number_for_err_trap = save_line_number = line_number;
- exec_result = execute_arith_command (command->value.Arith);
- line_number = save_line_number;
-
- if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- save_line_number = line_number;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- break;
-#endif
-
-#if defined (COND_COMMAND)
- case cm_cond:
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- if (ignore_return)
- command->value.Cond->flags |= CMD_IGNORE_RETURN;
-
- line_number_for_err_trap = save_line_number = line_number;
- exec_result = execute_cond_command (command->value.Cond);
- line_number = save_line_number;
-
- if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- save_line_number = line_number;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- break;
-#endif
-
- case cm_function_def:
- exec_result = execute_intern_function (command->value.Function_def->name,
- command->value.Function_def);
- break;
-
- default:
- command_error ("execute_command", CMDERR_BADTYPE, command->type, 0);
- }
-
- if (my_undo_list)
- {
- do_redirections (my_undo_list, RX_ACTIVE);
- dispose_redirects (my_undo_list);
- }
-
- if (exec_undo_list)
- dispose_redirects (exec_undo_list);
-
- if (my_undo_list || exec_undo_list)
- discard_unwind_frame ("loop_redirections");
-
-#if defined (PROCESS_SUBSTITUTION)
- if (saved_fifo)
- {
- nfifo = num_fifos ();
- if (nfifo > ofifo)
- close_new_fifos ((char *)ofifo_list, osize);
- free ((void *)ofifo_list);
- }
-#endif
-
- /* Invert the return value if we have to */
- if (invert)
- exec_result = (exec_result == EXECUTION_SUCCESS)
- ? EXECUTION_FAILURE
- : EXECUTION_SUCCESS;
-
-#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND)
- /* This is where we set PIPESTATUS from the exit status of the appropriate
- compound commands (the ones that look enough like simple commands to
- cause confusion). We might be able to optimize by not doing this if
- subshell_environment != 0. */
- switch (command->type)
- {
-# if defined (DPAREN_ARITHMETIC)
- case cm_arith:
-# endif
-# if defined (COND_COMMAND)
- case cm_cond:
-# endif
- set_pipestatus_from_exit (exec_result);
- break;
- }
-#endif
-
- last_command_exit_value = exec_result;
- run_pending_traps ();
-#if 0
- if (running_trap == 0)
-#endif
- currently_executing_command = (COMMAND *)NULL;
-
- return (last_command_exit_value);
-}
-
-#if defined (COMMAND_TIMING)
-
-#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-extern struct timeval *difftimeval __P((struct timeval *, struct timeval *, struct timeval *));
-extern struct timeval *addtimeval __P((struct timeval *, struct timeval *, struct timeval *));
-extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeval *));
-#endif
-
-#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S"
-#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS"
-
-static const int precs[] = { 0, 100, 10, 1 };
-
-/* Expand one `%'-prefixed escape sequence from a time format string. */
-static int
-mkfmt (buf, prec, lng, sec, sec_fraction)
- char *buf;
- int prec, lng;
- time_t sec;
- int sec_fraction;
-{
- time_t min;
- char abuf[INT_STRLEN_BOUND(time_t) + 1];
- int ind, aind;
-
- ind = 0;
- abuf[sizeof(abuf) - 1] = '\0';
-
- /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */
- if (lng)
- {
- min = sec / 60;
- sec %= 60;
- aind = sizeof(abuf) - 2;
- do
- abuf[aind--] = (min % 10) + '0';
- while (min /= 10);
- aind++;
- while (abuf[aind])
- buf[ind++] = abuf[aind++];
- buf[ind++] = 'm';
- }
-
- /* Now add the seconds. */
- aind = sizeof (abuf) - 2;
- do
- abuf[aind--] = (sec % 10) + '0';
- while (sec /= 10);
- aind++;
- while (abuf[aind])
- buf[ind++] = abuf[aind++];
-
- /* We want to add a decimal point and PREC places after it if PREC is
- nonzero. PREC is not greater than 3. SEC_FRACTION is between 0
- and 999. */
- if (prec != 0)
- {
- buf[ind++] = '.';
- for (aind = 1; aind <= prec; aind++)
- {
- buf[ind++] = (sec_fraction / precs[aind]) + '0';
- sec_fraction %= precs[aind];
- }
- }
-
- if (lng)
- buf[ind++] = 's';
- buf[ind] = '\0';
-
- return (ind);
-}
-
-/* Interpret the format string FORMAT, interpolating the following escape
- sequences:
- %[prec][l][RUS]
-
- where the optional `prec' is a precision, meaning the number of
- characters after the decimal point, the optional `l' means to format
- using minutes and seconds (MMmNN[.FF]s), like the `times' builtin',
- and the last character is one of
-
- R number of seconds of `real' time
- U number of seconds of `user' time
- S number of seconds of `system' time
-
- An occurrence of `%%' in the format string is translated to a `%'. The
- result is printed to FP, a pointer to a FILE. The other variables are
- the seconds and thousandths of a second of real, user, and system time,
- resectively. */
-static void
-print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu)
- FILE *fp;
- char *format;
- time_t rs;
- int rsf;
- time_t us;
- int usf;
- time_t ss;
- int ssf, cpu;
-{
- int prec, lng, len;
- char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")];
- time_t sum;
- int sum_frac;
- int sindex, ssize;
-
- len = strlen (format);
- ssize = (len + 64) - (len % 64);
- str = (char *)xmalloc (ssize);
- sindex = 0;
-
- for (s = format; *s; s++)
- {
- if (*s != '%' || s[1] == '\0')
- {
- RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64);
- str[sindex++] = *s;
- }
- else if (s[1] == '%')
- {
- s++;
- RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64);
- str[sindex++] = *s;
- }
- else if (s[1] == 'P')
- {
- s++;
-#if 0
- /* clamp CPU usage at 100% */
- if (cpu > 10000)
- cpu = 10000;
-#endif
- sum = cpu / 100;
- sum_frac = (cpu % 100) * 10;
- len = mkfmt (ts, 2, 0, sum, sum_frac);
- RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64);
- strcpy (str + sindex, ts);
- sindex += len;
- }
- else
- {
- prec = 3; /* default is three places past the decimal point. */
- lng = 0; /* default is to not use minutes or append `s' */
- s++;
- if (DIGIT (*s)) /* `precision' */
- {
- prec = *s++ - '0';
- if (prec > 3) prec = 3;
- }
- if (*s == 'l') /* `length extender' */
- {
- lng = 1;
- s++;
- }
- if (*s == 'R' || *s == 'E')
- len = mkfmt (ts, prec, lng, rs, rsf);
- else if (*s == 'U')
- len = mkfmt (ts, prec, lng, us, usf);
- else if (*s == 'S')
- len = mkfmt (ts, prec, lng, ss, ssf);
- else
- {
- internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s);
- free (str);
- return;
- }
- RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64);
- strcpy (str + sindex, ts);
- sindex += len;
- }
- }
-
- str[sindex] = '\0';
- fprintf (fp, "%s\n", str);
- fflush (fp);
-
- free (str);
-}
-
-static int
-time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
- COMMAND *command;
- int asynchronous, pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- int rv, posix_time, old_flags, nullcmd;
- time_t rs, us, ss;
- int rsf, usf, ssf;
- int cpu;
- char *time_format;
-
-#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
- struct timeval real, user, sys;
- struct timeval before, after;
-# if defined (HAVE_STRUCT_TIMEZONE)
- struct timezone dtz; /* posix doesn't define this */
-# endif
- struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */
-#else
-# if defined (HAVE_TIMES)
- clock_t tbefore, tafter, real, user, sys;
- struct tms before, after;
-# endif
-#endif
-
-#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-# if defined (HAVE_STRUCT_TIMEZONE)
- gettimeofday (&before, &dtz);
-# else
- gettimeofday (&before, (void *)NULL);
-# endif /* !HAVE_STRUCT_TIMEZONE */
- getrusage (RUSAGE_SELF, &selfb);
- getrusage (RUSAGE_CHILDREN, &kidsb);
-#else
-# if defined (HAVE_TIMES)
- tbefore = times (&before);
-# endif
-#endif
-
- posix_time = command && (command->flags & CMD_TIME_POSIX);
-
- nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
- if (posixly_correct && nullcmd)
- {
-#if defined (HAVE_GETRUSAGE)
- selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0;
- selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0;
- before.tv_sec = shell_start_time;
- before.tv_usec = 0;
-#else
- before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0;
- tbefore = shell_start_time;
-#endif
- }
-
- old_flags = command->flags;
- command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX);
- rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
- command->flags = old_flags;
-
- rs = us = ss = 0;
- rsf = usf = ssf = cpu = 0;
-
-#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-# if defined (HAVE_STRUCT_TIMEZONE)
- gettimeofday (&after, &dtz);
-# else
- gettimeofday (&after, (void *)NULL);
-# endif /* !HAVE_STRUCT_TIMEZONE */
- getrusage (RUSAGE_SELF, &selfa);
- getrusage (RUSAGE_CHILDREN, &kidsa);
-
- difftimeval (&real, &before, &after);
- timeval_to_secs (&real, &rs, &rsf);
-
- addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime),
- difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime));
- timeval_to_secs (&user, &us, &usf);
-
- addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime),
- difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime));
- timeval_to_secs (&sys, &ss, &ssf);
-
- cpu = timeval_to_cpu (&real, &user, &sys);
-#else
-# if defined (HAVE_TIMES)
- tafter = times (&after);
-
- real = tafter - tbefore;
- clock_t_to_secs (real, &rs, &rsf);
-
- user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime);
- clock_t_to_secs (user, &us, &usf);
-
- sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime);
- clock_t_to_secs (sys, &ss, &ssf);
-
- cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real;
-
-# else
- rs = us = ss = 0;
- rsf = usf = ssf = cpu = 0;
-# endif
-#endif
-
- if (posix_time)
- time_format = POSIX_TIMEFORMAT;
- else if ((time_format = get_string_value ("TIMEFORMAT")) == 0)
- {
- if (posixly_correct && nullcmd)
- time_format = "user\t%2lU\nsys\t%2lS";
- else
- time_format = BASH_TIMEFORMAT;
- }
- if (time_format && *time_format)
- print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu);
-
- return rv;
-}
-#endif /* COMMAND_TIMING */
-
-/* Execute a command that's supposed to be in a subshell. This must be
- called after make_child and we must be running in the child process.
- The caller will return or exit() immediately with the value this returns. */
-static int
-execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
- COMMAND *command;
- int asynchronous;
- int pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- int user_subshell, return_code, function_value, should_redir_stdin, invert;
- int ois, user_coproc;
- int result;
- volatile COMMAND *tcom;
-
- USE_VAR(user_subshell);
- USE_VAR(user_coproc);
- USE_VAR(invert);
- USE_VAR(tcom);
- USE_VAR(asynchronous);
-
- subshell_level++;
- should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) &&
- pipe_in == NO_PIPE &&
- stdin_redirects (command->redirects) == 0);
-
- invert = (command->flags & CMD_INVERT_RETURN) != 0;
- user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0);
- user_coproc = command->type == cm_coproc;
-
- command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN);
-
- /* If a command is asynchronous in a subshell (like ( foo ) & or
- the special case of an asynchronous GROUP command where the
- the subshell bit is turned on down in case cm_group: below),
- turn off `asynchronous', so that two subshells aren't spawned.
- XXX - asynchronous used to be set to 0 in this block, but that
- means that setup_async_signals was never run. Now it's set to
- 0 after subshell_environment is set appropriately and setup_async_signals
- is run.
-
- This seems semantically correct to me. For example,
- ( foo ) & seems to say ``do the command `foo' in a subshell
- environment, but don't wait for that subshell to finish'',
- and "{ foo ; bar ; } &" seems to me to be like functions or
- builtins in the background, which executed in a subshell
- environment. I just don't see the need to fork two subshells. */
-
- /* Don't fork again, we are already in a subshell. A `doubly
- async' shell is not interactive, however. */
- if (asynchronous)
- {
-#if defined (JOB_CONTROL)
- /* If a construct like ( exec xxx yyy ) & is given while job
- control is active, we want to prevent exec from putting the
- subshell back into the original process group, carefully
- undoing all the work we just did in make_child. */
- original_pgrp = -1;
-#endif /* JOB_CONTROL */
- ois = interactive_shell;
- interactive_shell = 0;
- /* This test is to prevent alias expansion by interactive shells that
- run `(command) &' but to allow scripts that have enabled alias
- expansion with `shopt -s expand_alias' to continue to expand
- aliases. */
- if (ois != interactive_shell)
- expand_aliases = 0;
- }
-
- /* Subshells are neither login nor interactive. */
- login_shell = interactive = 0;
-
- if (user_subshell)
- subshell_environment = SUBSHELL_PAREN;
- else
- {
- subshell_environment = 0; /* XXX */
- if (asynchronous)
- subshell_environment |= SUBSHELL_ASYNC;
- if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
- subshell_environment |= SUBSHELL_PIPE;
- if (user_coproc)
- subshell_environment |= SUBSHELL_COPROC;
- }
-
- reset_terminating_signals (); /* in sig.c */
- /* Cancel traps, in trap.c. */
- /* Reset the signal handlers in the child, but don't free the
- trap strings. Set a flag noting that we have to free the
- trap strings if we run trap to change a signal disposition. */
- reset_signal_handlers ();
- subshell_environment |= SUBSHELL_RESETTRAP;
-
- /* Make sure restore_original_signals doesn't undo the work done by
- make_child to ensure that asynchronous children are immune to SIGINT
- and SIGQUIT. Turn off asynchronous to make sure more subshells are
- not spawned. */
- if (asynchronous)
- {
- setup_async_signals ();
- asynchronous = 0;
- }
-
-#if defined (JOB_CONTROL)
- set_sigchld_handler ();
-#endif /* JOB_CONTROL */
-
- set_sigint_handler ();
-
-#if defined (JOB_CONTROL)
- /* Delete all traces that there were any jobs running. This is
- only for subshells. */
- without_job_control ();
-#endif /* JOB_CONTROL */
-
- if (fds_to_close)
- close_fd_bitmap (fds_to_close);
-
- do_piping (pipe_in, pipe_out);
-
-#if defined (COPROCESS_SUPPORT)
- coproc_closeall ();
-#endif
-
- /* If this is a user subshell, set a flag if stdin was redirected.
- This is used later to decide whether to redirect fd 0 to
- /dev/null for async commands in the subshell. This adds more
- sh compatibility, but I'm not sure it's the right thing to do. */
- if (user_subshell)
- {
- stdin_redir = stdin_redirects (command->redirects);
- restore_default_signal (0);
- }
-
- /* If this is an asynchronous command (command &), we want to
- redirect the standard input from /dev/null in the absence of
- any specific redirection involving stdin. */
- if (should_redir_stdin && stdin_redir == 0)
- async_redirect_stdin ();
-
- /* Do redirections, then dispose of them before recursive call. */
- if (command->redirects)
- {
- if (do_redirections (command->redirects, RX_ACTIVE) != 0)
- exit (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
-
- dispose_redirects (command->redirects);
- command->redirects = (REDIRECT *)NULL;
- }
-
- if (command->type == cm_subshell)
- tcom = command->value.Subshell->command;
- else if (user_coproc)
- tcom = command->value.Coproc->command;
- else
- tcom = command;
-
- if (command->flags & CMD_TIME_PIPELINE)
- tcom->flags |= CMD_TIME_PIPELINE;
- if (command->flags & CMD_TIME_POSIX)
- tcom->flags |= CMD_TIME_POSIX;
-
- /* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */
- if ((command->flags & CMD_IGNORE_RETURN) && tcom != command)
- tcom->flags |= CMD_IGNORE_RETURN;
-
- /* If this is a simple command, tell execute_disk_command that it
- might be able to get away without forking and simply exec.
- This means things like ( sleep 10 ) will only cause one fork.
- If we're timing the command or inverting its return value, however,
- we cannot do this optimization. */
- if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) &&
- ((tcom->flags & CMD_TIME_PIPELINE) == 0) &&
- ((tcom->flags & CMD_INVERT_RETURN) == 0))
- {
- tcom->flags |= CMD_NO_FORK;
- if (tcom->type == cm_simple)
- tcom->value.Simple->flags |= CMD_NO_FORK;
- }
-
- invert = (tcom->flags & CMD_INVERT_RETURN) != 0;
- tcom->flags &= ~CMD_INVERT_RETURN;
-
- result = setjmp (top_level);
-
- /* If we're inside a function while executing this subshell, we
- need to handle a possible `return'. */
- function_value = 0;
- if (return_catch_flag)
- function_value = setjmp (return_catch);
-
- /* If we're going to exit the shell, we don't want to invert the return
- status. */
- if (result == EXITPROG)
- invert = 0, return_code = last_command_exit_value;
- else if (result)
- return_code = EXECUTION_FAILURE;
- else if (function_value)
- return_code = return_catch_value;
- else
- return_code = execute_command_internal ((COMMAND *)tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
-
- /* If we are asked to, invert the return value. */
- if (invert)
- return_code = (return_code == EXECUTION_SUCCESS) ? EXECUTION_FAILURE
- : EXECUTION_SUCCESS;
-
- /* If we were explicitly placed in a subshell with (), we need
- to do the `shell cleanup' things, such as running traps[0]. */
- if (user_subshell && signal_is_trapped (0))
- {
- last_command_exit_value = return_code;
- return_code = run_exit_trap ();
- }
-
- subshell_level--;
- return (return_code);
- /* NOTREACHED */
-}
-
-#if defined (COPROCESS_SUPPORT)
-#define COPROC_MAX 16
-
-typedef struct cpelement
- {
- struct cpelement *next;
- struct coproc *coproc;
- }
-cpelement_t;
-
-typedef struct cplist
- {
- struct cpelement *head;
- struct cpelement *tail;
- int ncoproc;
- }
-cplist_t;
-
-static struct cpelement *cpe_alloc __P((struct coproc *));
-static void cpe_dispose __P((struct cpelement *));
-static struct cpelement *cpl_add __P((struct coproc *));
-static struct cpelement *cpl_delete __P((pid_t));
-static void cpl_reap __P((void));
-static void cpl_flush __P((void));
-static void cpl_closeall __P((void));
-static struct cpelement *cpl_search __P((pid_t));
-static struct cpelement *cpl_searchbyname __P((const char *));
-static void cpl_prune __P((void));
-
-static void coproc_free __P((struct coproc *));
-
-/* Will go away when there is fully-implemented support for multiple coprocs. */
-Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 };
-
-cplist_t coproc_list = {0, 0, 0};
-
-/* Functions to manage the list of coprocs */
-
-static struct cpelement *
-cpe_alloc (cp)
- Coproc *cp;
-{
- struct cpelement *cpe;
-
- cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement));
- cpe->coproc = cp;
- cpe->next = (struct cpelement *)0;
- return cpe;
-}
-
-static void
-cpe_dispose (cpe)
- struct cpelement *cpe;
-{
- free (cpe);
-}
-
-static struct cpelement *
-cpl_add (cp)
- Coproc *cp;
-{
- struct cpelement *cpe;
-
- cpe = cpe_alloc (cp);
-
- if (coproc_list.head == 0)
- {
- coproc_list.head = coproc_list.tail = cpe;
- coproc_list.ncoproc = 0; /* just to make sure */
- }
- else
- {
- coproc_list.tail->next = cpe;
- coproc_list.tail = cpe;
- }
- coproc_list.ncoproc++;
-
- return cpe;
-}
-
-static struct cpelement *
-cpl_delete (pid)
- pid_t pid;
-{
- struct cpelement *prev, *p;
-
- for (prev = p = coproc_list.head; p; prev = p, p = p->next)
- if (p->coproc->c_pid == pid)
- {
- prev->next = p->next; /* remove from list */
- break;
- }
-
- if (p == 0)
- return 0; /* not found */
-
-#if defined (DEBUG)
- itrace("cpl_delete: deleting %d", pid);
-#endif
-
- /* Housekeeping in the border cases. */
- if (p == coproc_list.head)
- coproc_list.head = coproc_list.head->next;
- else if (p == coproc_list.tail)
- coproc_list.tail = prev;
-
- coproc_list.ncoproc--;
- if (coproc_list.ncoproc == 0)
- coproc_list.head = coproc_list.tail = 0;
- else if (coproc_list.ncoproc == 1)
- coproc_list.tail = coproc_list.head; /* just to make sure */
-
- return (p);
-}
-
-static void
-cpl_reap ()
-{
- struct cpelement *p, *next, *nh, *nt;
-
- /* Build a new list by removing dead coprocs and fix up the coproc_list
- pointers when done. */
- nh = nt = next = (struct cpelement *)0;
- for (p = coproc_list.head; p; p = next)
- {
- next = p->next;
- if (p->coproc->c_flags & COPROC_DEAD)
- {
- coproc_list.ncoproc--; /* keep running count, fix up pointers later */
-
-#if defined (DEBUG)
- itrace("cpl_reap: deleting %d", p->coproc->c_pid);
-#endif
-
- coproc_dispose (p->coproc);
- cpe_dispose (p);
- }
- else if (nh == 0)
- nh = nt = p;
- else
- {
- nt->next = p;
- nt = nt->next;
- }
- }
-
- if (coproc_list.ncoproc == 0)
- coproc_list.head = coproc_list.tail = 0;
- else
- {
- if (nt)
- nt->next = 0;
- coproc_list.head = nh;
- coproc_list.tail = nt;
- if (coproc_list.ncoproc == 1)
- coproc_list.tail = coproc_list.head; /* just to make sure */
- }
-}
-
-/* Clear out the list of saved statuses */
-static void
-cpl_flush ()
-{
- struct cpelement *cpe, *p;
-
- for (cpe = coproc_list.head; cpe; )
- {
- p = cpe;
- cpe = cpe->next;
-
- coproc_dispose (p->coproc);
- cpe_dispose (p);
- }
-
- coproc_list.head = coproc_list.tail = 0;
- coproc_list.ncoproc = 0;
-}
-
-static void
-cpl_closeall ()
-{
- struct cpelement *cpe;
-
- for (cpe = coproc_list.head; cpe; cpe = cpe->next)
- coproc_close (cpe->coproc);
-}
-
-static void
-cpl_fdchk (fd)
- int fd;
-{
- struct cpelement *cpe;
-
- for (cpe = coproc_list.head; cpe; cpe = cpe->next)
- coproc_checkfd (cpe->coproc, fd);
-}
-
-/* Search for PID in the list of coprocs; return the cpelement struct if
- found. If not found, return NULL. */
-static struct cpelement *
-cpl_search (pid)
- pid_t pid;
-{
- struct cpelement *cpe;
-
- for (cpe = coproc_list.head ; cpe; cpe = cpe->next)
- if (cpe->coproc->c_pid == pid)
- return cpe;
- return (struct cpelement *)NULL;
-}
-
-/* Search for the coproc named NAME in the list of coprocs; return the
- cpelement struct if found. If not found, return NULL. */
-static struct cpelement *
-cpl_searchbyname (name)
- const char *name;
-{
- struct cpelement *cp;
-
- for (cp = coproc_list.head ; cp; cp = cp->next)
- if (STREQ (cp->coproc->c_name, name))
- return cp;
- return (struct cpelement *)NULL;
-}
-
-#if 0
-static void
-cpl_prune ()
-{
- struct cpelement *cp;
-
- while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX)
- {
- cp = coproc_list.head;
- coproc_list.head = coproc_list.head->next;
- coproc_dispose (cp->coproc);
- cpe_dispose (cp);
- coproc_list.ncoproc--;
- }
-}
-#endif
-
-/* These currently use a single global "shell coproc" but are written in a
- way to not preclude additional coprocs later (using the list management
- package above). */
-
-struct coproc *
-getcoprocbypid (pid)
- pid_t pid;
-{
-#if MULTIPLE_COPROCS
- struct cpelement *p;
-
- p = cpl_search (pid);
- return (p ? p->coproc : 0);
-#else
- return (pid == sh_coproc.c_pid ? &sh_coproc : 0);
-#endif
-}
-
-struct coproc *
-getcoprocbyname (name)
- const char *name;
-{
-#if MULTIPLE_COPROCS
- struct cpelement *p;
-
- p = cpl_searchbyname (name);
- return (p ? p->coproc : 0);
-#else
- return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0);
-#endif
-}
-
-void
-coproc_init (cp)
- struct coproc *cp;
-{
- cp->c_name = 0;
- cp->c_pid = NO_PID;
- cp->c_rfd = cp->c_wfd = -1;
- cp->c_rsave = cp->c_wsave = -1;
- cp->c_flags = cp->c_status = 0;
-}
-
-struct coproc *
-coproc_alloc (name, pid)
- char *name;
- pid_t pid;
-{
- struct coproc *cp;
-
-#if MULTIPLE_COPROCS
- cp = (struct coproc *)xmalloc (sizeof (struct coproc));
-#else
- cp = &sh_coproc;
-#endif
- coproc_init (cp);
-
- cp->c_name = savestring (name);
- cp->c_pid = pid;
-
-#if MULTIPLE_COPROCS
- cpl_add (cp);
-#endif
-
- return (cp);
-}
-
-static void
-coproc_free (cp)
- struct coproc *cp;
-{
- free (cp);
-}
-
-void
-coproc_dispose (cp)
- struct coproc *cp;
-{
- if (cp == 0)
- return;
-
- coproc_unsetvars (cp);
- FREE (cp->c_name);
- coproc_close (cp);
-#if MULTIPLE_COPROCS
- coproc_free (cp);
-#else
- coproc_init (cp);
-#endif
-}
-
-/* Placeholder for now. Will require changes for multiple coprocs */
-void
-coproc_flush ()
-{
-#if MULTIPLE_COPROCS
- cpl_flush ();
-#else
- coproc_dispose (&sh_coproc);
-#endif
-}
-
-void
-coproc_close (cp)
- struct coproc *cp;
-{
- if (cp->c_rfd >= 0)
- {
- close (cp->c_rfd);
- cp->c_rfd = -1;
- }
- if (cp->c_wfd >= 0)
- {
- close (cp->c_wfd);
- cp->c_wfd = -1;
- }
- cp->c_rsave = cp->c_wsave = -1;
-}
-
-void
-coproc_closeall ()
-{
-#if MULTIPLE_COPROCS
- cpl_closeall ();
-#else
- coproc_close (&sh_coproc); /* XXX - will require changes for multiple coprocs */
-#endif
-}
-
-void
-coproc_reap ()
-{
-#if MULTIPLE_COPROCS
- cpl_reap ();
-#else
- struct coproc *cp;
-
- cp = &sh_coproc; /* XXX - will require changes for multiple coprocs */
- if (cp && (cp->c_flags & COPROC_DEAD))
- coproc_dispose (cp);
-#endif
-}
-
-void
-coproc_rclose (cp, fd)
- struct coproc *cp;
- int fd;
-{
- if (cp->c_rfd >= 0 && cp->c_rfd == fd)
- {
- close (cp->c_rfd);
- cp->c_rfd = -1;
- }
-}
-
-void
-coproc_wclose (cp, fd)
- struct coproc *cp;
- int fd;
-{
- if (cp->c_wfd >= 0 && cp->c_wfd == fd)
- {
- close (cp->c_wfd);
- cp->c_wfd = -1;
- }
-}
-
-void
-coproc_checkfd (cp, fd)
- struct coproc *cp;
- int fd;
-{
- int update;
-
- update = 0;
- if (cp->c_rfd >= 0 && cp->c_rfd == fd)
- update = cp->c_rfd = -1;
- if (cp->c_wfd >= 0 && cp->c_wfd == fd)
- update = cp->c_wfd = -1;
- if (update)
- coproc_setvars (cp);
-}
-
-void
-coproc_fdchk (fd)
- int fd;
-{
-#if MULTIPLE_COPROCS
- cpl_fdchk (fd);
-#else
- coproc_checkfd (&sh_coproc, fd);
-#endif
-}
-
-void
-coproc_fdclose (cp, fd)
- struct coproc *cp;
- int fd;
-{
- coproc_rclose (cp, fd);
- coproc_wclose (cp, fd);
- coproc_setvars (cp);
-}
-
-void
-coproc_fdsave (cp)
- struct coproc *cp;
-{
- cp->c_rsave = cp->c_rfd;
- cp->c_wsave = cp->c_wfd;
-}
-
-void
-coproc_fdrestore (cp)
- struct coproc *cp;
-{
- cp->c_rfd = cp->c_rsave;
- cp->c_wfd = cp->c_wsave;
-}
-
-void
-coproc_pidchk (pid, status)
- pid_t pid;
-{
- struct coproc *cp;
-
-#if MULTIPLE_COPROCS
- struct cpelement *cpe;
-
- cpe = cpl_delete (pid);
- cp = cpe ? cpe->coproc : 0;
-#else
- cp = getcoprocbypid (pid);
-#endif
- if (cp)
- {
-#if 0
- itrace("coproc_pidchk: pid %d has died", pid);
-#endif
- cp->c_status = status;
- cp->c_flags |= COPROC_DEAD;
- cp->c_flags &= ~COPROC_RUNNING;
-#if MULTIPLE_COPROCS
- coproc_dispose (cp);
-#else
- coproc_unsetvars (cp);
-#endif
- }
-}
-
-void
-coproc_setvars (cp)
- struct coproc *cp;
-{
- SHELL_VAR *v;
- char *namevar, *t;
- int l;
-#if defined (ARRAY_VARS)
- arrayind_t ind;
-#endif
-
- if (cp->c_name == 0)
- return;
-
- l = strlen (cp->c_name);
- namevar = xmalloc (l + 16);
-
-#if defined (ARRAY_VARS)
- v = find_variable (cp->c_name);
- if (v == 0)
- v = make_new_array_variable (cp->c_name);
- if (array_p (v) == 0)
- v = convert_var_to_array (v);
-
- t = itos (cp->c_rfd);
- ind = 0;
- v = bind_array_variable (cp->c_name, ind, t, 0);
- free (t);
-
- t = itos (cp->c_wfd);
- ind = 1;
- bind_array_variable (cp->c_name, ind, t, 0);
- free (t);
-#else
- sprintf (namevar, "%s_READ", cp->c_name);
- t = itos (cp->c_rfd);
- bind_variable (namevar, t, 0);
- free (t);
- sprintf (namevar, "%s_WRITE", cp->c_name);
- t = itos (cp->c_wfd);
- bind_variable (namevar, t, 0);
- free (t);
-#endif
-
- sprintf (namevar, "%s_PID", cp->c_name);
- t = itos (cp->c_pid);
- bind_variable (namevar, t, 0);
- free (t);
-
- free (namevar);
-}
-
-void
-coproc_unsetvars (cp)
- struct coproc *cp;
-{
- int l;
- char *namevar;
-
- if (cp->c_name == 0)
- return;
-
- l = strlen (cp->c_name);
- namevar = xmalloc (l + 16);
-
- sprintf (namevar, "%s_PID", cp->c_name);
- unbind_variable (namevar);
-
-#if defined (ARRAY_VARS)
- unbind_variable (cp->c_name);
-#else
- sprintf (namevar, "%s_READ", cp->c_name);
- unbind_variable (namevar);
- sprintf (namevar, "%s_WRITE", cp->c_name);
- unbind_variable (namevar);
-#endif
-
- free (namevar);
-}
-
-static int
-execute_coproc (command, pipe_in, pipe_out, fds_to_close)
- COMMAND *command;
- int pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- int rpipe[2], wpipe[2], estat;
- pid_t coproc_pid;
- Coproc *cp;
- char *tcmd;
-
- /* XXX -- can be removed after changes to handle multiple coprocs */
-#if !MULTIPLE_COPROCS
- if (sh_coproc.c_pid != NO_PID)
- internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name);
- coproc_init (&sh_coproc);
-#endif
-
- command_string_index = 0;
- tcmd = make_command_string (command);
-
- sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */
- sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */
-
- coproc_pid = make_child (savestring (tcmd), 1);
- if (coproc_pid == 0)
- {
- close (rpipe[0]);
- close (wpipe[1]);
-
- estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close);
-
- fflush (stdout);
- fflush (stderr);
-
- exit (estat);
- }
-
- close (rpipe[1]);
- close (wpipe[0]);
-
- cp = coproc_alloc (command->value.Coproc->name, coproc_pid);
- cp->c_rfd = rpipe[0];
- cp->c_wfd = wpipe[1];
-
- SET_CLOSE_ON_EXEC (cp->c_rfd);
- SET_CLOSE_ON_EXEC (cp->c_wfd);
-
- coproc_setvars (cp);
-
-#if 0
- itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command);
-#endif
-
- close_pipes (pipe_in, pipe_out);
-#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
- unlink_fifo_list ();
-#endif
- stop_pipeline (1, (COMMAND *)NULL);
- DESCRIBE_PID (coproc_pid);
- run_pending_traps ();
-
- return (EXECUTION_SUCCESS);
-}
-#endif
-
-static void
-restore_stdin (s)
- int s;
-{
- dup2 (s, 0);
- close (s);
-}
-
-/* Catch-all cleanup function for lastpipe code for unwind-protects */
-static void
-lastpipe_cleanup (s)
- int s;
-{
- unfreeze_jobs_list ();
-}
-
-static int
-execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
- COMMAND *command;
- int asynchronous, pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result;
- int lstdin, lastpipe_flag, lastpipe_jid;
- COMMAND *cmd;
- struct fd_bitmap *fd_bitmap;
- pid_t lastpid;
-
-#if defined (JOB_CONTROL)
- sigset_t set, oset;
- BLOCK_CHILD (set, oset);
-#endif /* JOB_CONTROL */
-
- ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
-
- prev = pipe_in;
- cmd = command;
-
- while (cmd && cmd->type == cm_connection &&
- cmd->value.Connection && cmd->value.Connection->connector == '|')
- {
- /* Make a pipeline between the two commands. */
- if (pipe (fildes) < 0)
- {
- sys_error (_("pipe error"));
-#if defined (JOB_CONTROL)
- terminate_current_pipeline ();
- kill_current_pipeline ();
- UNBLOCK_CHILD (oset);
-#endif /* JOB_CONTROL */
- last_command_exit_value = EXECUTION_FAILURE;
- /* The unwind-protects installed below will take care
- of closing all of the open file descriptors. */
- throw_to_top_level ();
- return (EXECUTION_FAILURE); /* XXX */
- }
-
- /* Here is a problem: with the new file close-on-exec
- code, the read end of the pipe (fildes[0]) stays open
- in the first process, so that process will never get a
- SIGPIPE. There is no way to signal the first process
- that it should close fildes[0] after forking, so it
- remains open. No SIGPIPE is ever sent because there
- is still a file descriptor open for reading connected
- to the pipe. We take care of that here. This passes
- around a bitmap of file descriptors that must be
- closed after making a child process in execute_simple_command. */
-
- /* We need fd_bitmap to be at least as big as fildes[0].
- If fildes[0] is less than fds_to_close->size, then
- use fds_to_close->size. */
- new_bitmap_size = (fildes[0] < fds_to_close->size)
- ? fds_to_close->size
- : fildes[0] + 8;
-
- fd_bitmap = new_fd_bitmap (new_bitmap_size);
-
- /* Now copy the old information into the new bitmap. */
- xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size);
-
- /* And mark the pipe file descriptors to be closed. */
- fd_bitmap->bitmap[fildes[0]] = 1;
-
- /* In case there are pipe or out-of-processes errors, we
- want all these file descriptors to be closed when
- unwind-protects are run, and the storage used for the
- bitmaps freed up. */
- begin_unwind_frame ("pipe-file-descriptors");
- add_unwind_protect (dispose_fd_bitmap, fd_bitmap);
- add_unwind_protect (close_fd_bitmap, fd_bitmap);
- if (prev >= 0)
- add_unwind_protect (close, prev);
- dummyfd = fildes[1];
- add_unwind_protect (close, dummyfd);
-
-#if defined (JOB_CONTROL)
- add_unwind_protect (restore_signal_mask, &oset);
-#endif /* JOB_CONTROL */
-
- if (ignore_return && cmd->value.Connection->first)
- cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN;
- execute_command_internal (cmd->value.Connection->first, asynchronous,
- prev, fildes[1], fd_bitmap);
-
- if (prev >= 0)
- close (prev);
-
- prev = fildes[0];
- close (fildes[1]);
-
- dispose_fd_bitmap (fd_bitmap);
- discard_unwind_frame ("pipe-file-descriptors");
-
- cmd = cmd->value.Connection->second;
- }
-
- lastpid = last_made_pid;
-
- /* Now execute the rightmost command in the pipeline. */
- if (ignore_return && cmd)
- cmd->flags |= CMD_IGNORE_RETURN;
-
- lastpipe_flag = 0;
-
- begin_unwind_frame ("lastpipe-exec");
- lstdin = -1;
- /* If the `lastpipe' option is set with shopt, and job control is not
- enabled, execute the last element of non-async pipelines in the
- current shell environment. */
- if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0)
- {
- lstdin = move_to_high_fd (0, 1, -1);
- if (lstdin > 0)
- {
- do_piping (prev, pipe_out);
- prev = NO_PIPE;
- add_unwind_protect (restore_stdin, lstdin);
- lastpipe_flag = 1;
- freeze_jobs_list ();
- lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */
- add_unwind_protect (lastpipe_cleanup, lastpipe_jid);
- }
- if (cmd)
- cmd->flags |= CMD_LASTPIPE;
- }
- if (prev >= 0)
- add_unwind_protect (close, prev);
-
- exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close);
-
- if (lstdin > 0)
- restore_stdin (lstdin);
-
- if (prev >= 0)
- close (prev);
-
-#if defined (JOB_CONTROL)
- UNBLOCK_CHILD (oset);
-#endif
-
- QUIT;
-
- if (lastpipe_flag)
- {
-#if defined (JOB_CONTROL)
- append_process (savestring (the_printed_command), dollar_dollar_pid, exec_result, lastpipe_jid);
-#endif
- lstdin = wait_for (lastpid);
-#if defined (JOB_CONTROL)
- exec_result = job_exit_status (lastpipe_jid);
-#endif
- unfreeze_jobs_list ();
- }
-
- discard_unwind_frame ("lastpipe-exec");
-
- return (exec_result);
-}
-
-static int
-execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
- COMMAND *command;
- int asynchronous, pipe_in, pipe_out;
- struct fd_bitmap *fds_to_close;
-{
- COMMAND *tc, *second;
- int ignore_return, exec_result, was_error_trap, invert;
- volatile int save_line_number;
-
- ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
-
- switch (command->value.Connection->connector)
- {
- /* Do the first command asynchronously. */
- case '&':
- tc = command->value.Connection->first;
- if (tc == 0)
- return (EXECUTION_SUCCESS);
-
- if (ignore_return)
- tc->flags |= CMD_IGNORE_RETURN;
- tc->flags |= CMD_AMPERSAND;
-
- /* If this shell was compiled without job control support,
- if we are currently in a subshell via `( xxx )', or if job
- control is not active then the standard input for an
- asynchronous command is forced to /dev/null. */
-#if defined (JOB_CONTROL)
- if ((subshell_environment || !job_control) && !stdin_redir)
-#else
- if (!stdin_redir)
-#endif /* JOB_CONTROL */
- tc->flags |= CMD_STDIN_REDIR;
-
- exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close);
- QUIT;
-
- if (tc->flags & CMD_STDIN_REDIR)
- tc->flags &= ~CMD_STDIN_REDIR;
-
- second = command->value.Connection->second;
- if (second)
- {
- if (ignore_return)
- second->flags |= CMD_IGNORE_RETURN;
-
- exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close);
- }
-
- break;
-
- /* Just call execute command on both sides. */
- case ';':
- if (ignore_return)
- {
- if (command->value.Connection->first)
- command->value.Connection->first->flags |= CMD_IGNORE_RETURN;
- if (command->value.Connection->second)
- command->value.Connection->second->flags |= CMD_IGNORE_RETURN;
- }
- executing_list++;
- QUIT;
- execute_command (command->value.Connection->first);
- QUIT;
- exec_result = execute_command_internal (command->value.Connection->second,
- asynchronous, pipe_in, pipe_out,
- fds_to_close);
- executing_list--;
- break;
-
- case '|':
- was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
- invert = (command->flags & CMD_INVERT_RETURN) != 0;
- ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
-
- line_number_for_err_trap = line_number;
- exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close);
-
- if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- save_line_number = line_number;
- line_number = line_number_for_err_trap;
- run_error_trap ();
- line_number = save_line_number;
- }
-
- if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
- {
- last_command_exit_value = exec_result;
- run_pending_traps ();
- jump_to_top_level (ERREXIT);
- }
-
- break;
-
- case AND_AND:
- case OR_OR:
- if (asynchronous)
- {
- /* If we have something like `a && b &' or `a || b &', run the
- && or || stuff in a subshell. Force a subshell and just call
- execute_command_internal again. Leave asynchronous on
- so that we get a report from the parent shell about the
- background job. */
- command->flags |= CMD_FORCE_SUBSHELL;
- exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close);
- break;
- }
-
- /* Execute the first command. If the result of that is successful
- and the connector is AND_AND, or the result is not successful
- and the connector is OR_OR, then execute the second command,
- otherwise return. */
-
- executing_list++;
- if (command->value.Connection->first)
- command->value.Connection->first->flags |= CMD_IGNORE_RETURN;
-
- exec_result = execute_command (command->value.Connection->first);
- QUIT;
- if (((command->value.Connection->connector == AND_AND) &&
- (exec_result == EXECUTION_SUCCESS)) ||
- ((command->value.Connection->connector == OR_OR) &&
- (exec_result != EXECUTION_SUCCESS)))
- {
- if (ignore_return && command->value.Connection->second)
- command->value.Connection->second->flags |= CMD_IGNORE_RETURN;
-
- exec_result = execute_command (command->value.Connection->second);
- }
- executing_list--;
- break;
-
- default:
- command_error ("execute_connection", CMDERR_BADCONN, command->value.Connection->connector, 0);
- jump_to_top_level (DISCARD);
- exec_result = EXECUTION_FAILURE;
- }
-
- return exec_result;
-}
-
-#define REAP() \
- do \
- { \
- if (!interactive_shell) \
- reap_dead_jobs (); \
- } \
- while (0)
-
-/* Execute a FOR command. The syntax is: FOR word_desc IN word_list;
- DO command; DONE */
-static int
-execute_for_command (for_command)
- FOR_COM *for_command;
-{
- register WORD_LIST *releaser, *list;
- SHELL_VAR *v;
- char *identifier;
- int retval, save_line_number;
-#if 0
- SHELL_VAR *old_value = (SHELL_VAR *)NULL; /* Remember the old value of x. */
-#endif
-
- save_line_number = line_number;
- if (check_identifier (for_command->name, 1) == 0)
- {
- if (posixly_correct && interactive_shell == 0)
- {
- last_command_exit_value = EX_BADUSAGE;
- jump_to_top_level (ERREXIT);
- }
- return (EXECUTION_FAILURE);
- }
-
- loop_level++;
- identifier = for_command->name->word;
-
- list = releaser = expand_words_no_vars (for_command->map_list);
-
- begin_unwind_frame ("for");
- add_unwind_protect (dispose_words, releaser);
-
-#if 0
- if (lexical_scoping)
- {
- old_value = copy_variable (find_variable (identifier));
- if (old_value)
- add_unwind_protect (dispose_variable, old_value);
- }
-#endif
-
- if (for_command->flags & CMD_IGNORE_RETURN)
- for_command->action->flags |= CMD_IGNORE_RETURN;
-
- for (retval = EXECUTION_SUCCESS; list; list = list->next)
- {
- QUIT;
-
- line_number = for_command->line;
-
- /* Remember what this command looks like, for debugger. */
- command_string_index = 0;
- print_for_command_head (for_command);
-
- if (echo_command_at_execute)
- xtrace_print_for_command_head (for_command);
-
- /* Save this command unless it's a trap command and we're not running
- a debug trap. */
- if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- retval = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && retval != EXECUTION_SUCCESS)
- continue;
-#endif
-
- this_command_name = (char *)NULL;
- /* XXX - special ksh93 for command index variable handling */
- v = find_variable_last_nameref (identifier);
- if (v && nameref_p (v))
- {
- v = bind_variable_value (v, list->word->word, 0);
- }
- else
- v = bind_variable (identifier, list->word->word, 0);
- if (readonly_p (v) || noassign_p (v))
- {
- line_number = save_line_number;
- if (readonly_p (v) && interactive_shell == 0 && posixly_correct)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (FORCE_EOF);
- }
- else
- {
- dispose_words (releaser);
- discard_unwind_frame ("for");
- loop_level--;
- return (EXECUTION_FAILURE);
- }
- }
- retval = execute_command (for_command->action);
- REAP ();
- QUIT;
-
- if (breaking)
- {
- breaking--;
- break;
- }
-
- if (continuing)
- {
- continuing--;
- if (continuing)
- break;
- }
- }
-
- loop_level--;
- line_number = save_line_number;
-
-#if 0
- if (lexical_scoping)
- {
- if (!old_value)
- unbind_variable (identifier);
- else
- {
- SHELL_VAR *new_value;
-
- new_value = bind_variable (identifier, value_cell(old_value), 0);
- new_value->attributes = old_value->attributes;
- dispose_variable (old_value);
- }
- }
-#endif
-
- dispose_words (releaser);
- discard_unwind_frame ("for");
- return (retval);
-}
-
-#if defined (ARITH_FOR_COMMAND)
-/* Execute an arithmetic for command. The syntax is
-
- for (( init ; step ; test ))
- do
- body
- done
-
- The execution should be exactly equivalent to
-
- eval \(\( init \)\)
- while eval \(\( test \)\) ; do
- body;
- eval \(\( step \)\)
- done
-*/
-static intmax_t
-eval_arith_for_expr (l, okp)
- WORD_LIST *l;
- int *okp;
-{
- WORD_LIST *new;
- intmax_t expresult;
- int r;
-
- new = expand_words_no_vars (l);
- if (new)
- {
- if (echo_command_at_execute)
- xtrace_print_arith_cmd (new);
- this_command_name = "(("; /* )) for expression error messages */
-
- command_string_index = 0;
- print_arith_command (new);
- if (signal_in_progress (DEBUG_TRAP) == 0)
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- r = run_debug_trap ();
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
-#if defined (DEBUGGER)
- if (debugging_mode == 0 || r == EXECUTION_SUCCESS)
- expresult = evalexp (new->word->word, okp);
- else
- {
- expresult = 0;
- if (okp)
- *okp = 1;
- }
-#else
- expresult = evalexp (new->word->word, okp);
-#endif
- dispose_words (new);
- }
- else
- {
- expresult = 0;
- if (okp)
- *okp = 1;
- }
- return (expresult);
-}
-
-static int
-execute_arith_for_command (arith_for_command)
- ARITH_FOR_COM *arith_for_command;
-{
- intmax_t expresult;
- int expok, body_status, arith_lineno, save_lineno;
-
- body_status = EXECUTION_SUCCESS;
- loop_level++;
- save_lineno = line_number;
-
- if (arith_for_command->flags & CMD_IGNORE_RETURN)
- arith_for_command->action->flags |= CMD_IGNORE_RETURN;
-
- this_command_name = "(("; /* )) for expression error messages */
-
- /* save the starting line number of the command so we can reset
- line_number before executing each expression -- for $LINENO
- and the DEBUG trap. */
- line_number = arith_lineno = arith_for_command->line;
- if (variable_context && interactive_shell)
- line_number -= function_line_number;
-
- /* Evaluate the initialization expression. */
- expresult = eval_arith_for_expr (arith_for_command->init, &expok);
- if (expok == 0)
- {
- line_number = save_lineno;
- return (EXECUTION_FAILURE);
- }
-
- while (1)
- {
- /* Evaluate the test expression. */
- line_number = arith_lineno;
- expresult = eval_arith_for_expr (arith_for_command->test, &expok);
- line_number = save_lineno;
-
- if (expok == 0)
- {
- body_status = EXECUTION_FAILURE;
- break;
- }
- REAP ();
- if (expresult == 0)
- break;
-
- /* Execute the body of the arithmetic for command. */
- QUIT;
- body_status = execute_command (arith_for_command->action);
- QUIT;
-
- /* Handle any `break' or `continue' commands executed by the body. */
- if (breaking)
- {
- breaking--;
- break;
- }
-
- if (continuing)
- {
- continuing--;
- if (continuing)
- break;
- }
-
- /* Evaluate the step expression. */
- line_number = arith_lineno;
- expresult = eval_arith_for_expr (arith_for_command->step, &expok);
- line_number = save_lineno;
-
- if (expok == 0)
- {
- body_status = EXECUTION_FAILURE;
- break;
- }
- }
-
- loop_level--;
- line_number = save_lineno;
-
- return (body_status);
-}
-#endif
-
-#if defined (SELECT_COMMAND)
-static int LINES, COLS, tabsize;
-
-#define RP_SPACE ") "
-#define RP_SPACE_LEN 2
-
-/* XXX - does not handle numbers > 1000000 at all. */
-#define NUMBER_LEN(s) \
-((s < 10) ? 1 \
- : ((s < 100) ? 2 \
- : ((s < 1000) ? 3 \
- : ((s < 10000) ? 4 \
- : ((s < 100000) ? 5 \
- : 6)))))
-
-static int
-displen (s)
- const char *s;
-{
-#if defined (HANDLE_MULTIBYTE)
- wchar_t *wcstr;
- size_t slen;
- int wclen;
-
- wcstr = 0;
- slen = mbstowcs (wcstr, s, 0);
- if (slen == -1)
- slen = 0;
- wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1));
- mbstowcs (wcstr, s, slen + 1);
- wclen = wcswidth (wcstr, slen);
- free (wcstr);
- return (wclen < 0 ? STRLEN(s) : wclen);
-#else
- return (STRLEN (s));
-#endif
-}
-
-static int
-print_index_and_element (len, ind, list)
- int len, ind;
- WORD_LIST *list;
-{
- register WORD_LIST *l;
- register int i;
-
- if (list == 0)
- return (0);
- for (i = ind, l = list; l && --i; l = l->next)
- ;
- if (l == 0) /* don't think this can happen */
- return (0);
- fprintf (stderr, "%*d%s%s", len, ind, RP_SPACE, l->word->word);
- return (displen (l->word->word));
-}
-
-static void
-indent (from, to)
- int from, to;
-{
- while (from < to)
- {
- if ((to / tabsize) > (from / tabsize))
- {
- putc ('\t', stderr);
- from += tabsize - from % tabsize;
- }
- else
- {
- putc (' ', stderr);
- from++;
- }
- }
-}
-
-static void
-print_select_list (list, list_len, max_elem_len, indices_len)
- WORD_LIST *list;
- int list_len, max_elem_len, indices_len;
-{
- int ind, row, elem_len, pos, cols, rows;
- int first_column_indices_len, other_indices_len;
-
- if (list == 0)
- {
- putc ('\n', stderr);
- return;
- }
-
- cols = max_elem_len ? COLS / max_elem_len : 1;
- if (cols == 0)
- cols = 1;
- rows = list_len ? list_len / cols + (list_len % cols != 0) : 1;
- cols = list_len ? list_len / rows + (list_len % rows != 0) : 1;
-
- if (rows == 1)
- {
- rows = cols;
- cols = 1;
- }
-
- first_column_indices_len = NUMBER_LEN (rows);
- other_indices_len = indices_len;
-
- for (row = 0; row < rows; row++)
- {
- ind = row;
- pos = 0;
- while (1)
- {
- indices_len = (pos == 0) ? first_column_indices_len : other_indices_len;
- elem_len = print_index_and_element (indices_len, ind + 1, list);
- elem_len += indices_len + RP_SPACE_LEN;
- ind += rows;
- if (ind >= list_len)
- break;
- indent (pos + elem_len, pos + max_elem_len);
- pos += max_elem_len;
- }
- putc ('\n', stderr);
- }
-}
-
-/* Print the elements of LIST, one per line, preceded by an index from 1 to
- LIST_LEN. Then display PROMPT and wait for the user to enter a number.
- If the number is between 1 and LIST_LEN, return that selection. If EOF
- is read, return a null string. If a blank line is entered, or an invalid
- number is entered, the loop is executed again. */
-static char *
-select_query (list, list_len, prompt, print_menu)
- WORD_LIST *list;
- int list_len;
- char *prompt;
- int print_menu;
-{
- int max_elem_len, indices_len, len;
- intmax_t reply;
- WORD_LIST *l;
- char *repl_string, *t;
-
-#if 0
- t = get_string_value ("LINES");
- LINES = (t && *t) ? atoi (t) : 24;
-#endif
- t = get_string_value ("COLUMNS");
- COLS = (t && *t) ? atoi (t) : 80;
-
-#if 0
- t = get_string_value ("TABSIZE");
- tabsize = (t && *t) ? atoi (t) : 8;
- if (tabsize <= 0)
- tabsize = 8;
-#else
- tabsize = 8;
-#endif
-
- max_elem_len = 0;
- for (l = list; l; l = l->next)
- {
- len = displen (l->word->word);
- if (len > max_elem_len)
- max_elem_len = len;
- }
- indices_len = NUMBER_LEN (list_len);
- max_elem_len += indices_len + RP_SPACE_LEN + 2;
-
- while (1)
- {
- if (print_menu)
- print_select_list (list, list_len, max_elem_len, indices_len);
- fprintf (stderr, "%s", prompt);
- fflush (stderr);
- QUIT;
-
- if (read_builtin ((WORD_LIST *)NULL) != EXECUTION_SUCCESS)
- {
- putchar ('\n');
- return ((char *)NULL);
- }
- repl_string = get_string_value ("REPLY");
- if (*repl_string == 0)
- {
- print_menu = 1;
- continue;
- }
- if (legal_number (repl_string, &reply) == 0)
- return "";
- if (reply < 1 || reply > list_len)
- return "";
-
- for (l = list; l && --reply; l = l->next)
- ;
- return (l->word->word); /* XXX - can't be null? */
- }
-}
-
-/* Execute a SELECT command. The syntax is:
- SELECT word IN list DO command_list DONE
- Only `break' or `return' in command_list will terminate
- the command. */
-static int
-execute_select_command (select_command)
- SELECT_COM *select_command;
-{
- WORD_LIST *releaser, *list;
- SHELL_VAR *v;
- char *identifier, *ps3_prompt, *selection;
- int retval, list_len, show_menu, save_line_number;
-
- if (check_identifier (select_command->name, 1) == 0)
- return (EXECUTION_FAILURE);
-
- save_line_number = line_number;
- line_number = select_command->line;
-
- command_string_index = 0;
- print_select_command_head (select_command);
-
- if (echo_command_at_execute)
- xtrace_print_select_command_head (select_command);
-
-#if 0
- if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
-#else
- if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
-#endif
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- retval = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && retval != EXECUTION_SUCCESS)
- return (EXECUTION_SUCCESS);
-#endif
-
- loop_level++;
- identifier = select_command->name->word;
-
- /* command and arithmetic substitution, parameter and variable expansion,
- word splitting, pathname expansion, and quote removal. */
- list = releaser = expand_words_no_vars (select_command->map_list);
- list_len = list_length (list);
- if (list == 0 || list_len == 0)
- {
- if (list)
- dispose_words (list);
- line_number = save_line_number;
- return (EXECUTION_SUCCESS);
- }
-
- begin_unwind_frame ("select");
- add_unwind_protect (dispose_words, releaser);
-
- if (select_command->flags & CMD_IGNORE_RETURN)
- select_command->action->flags |= CMD_IGNORE_RETURN;
-
- retval = EXECUTION_SUCCESS;
- show_menu = 1;
-
- while (1)
- {
- line_number = select_command->line;
- ps3_prompt = get_string_value ("PS3");
- if (ps3_prompt == 0)
- ps3_prompt = "#? ";
-
- QUIT;
- selection = select_query (list, list_len, ps3_prompt, show_menu);
- QUIT;
- if (selection == 0)
- {
- /* select_query returns EXECUTION_FAILURE if the read builtin
- fails, so we want to return failure in this case. */
- retval = EXECUTION_FAILURE;
- break;
- }
-
- v = bind_variable (identifier, selection, 0);
- if (readonly_p (v) || noassign_p (v))
- {
- if (readonly_p (v) && interactive_shell == 0 && posixly_correct)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (FORCE_EOF);
- }
- else
- {
- dispose_words (releaser);
- discard_unwind_frame ("select");
- loop_level--;
- line_number = save_line_number;
- return (EXECUTION_FAILURE);
- }
- }
-
- retval = execute_command (select_command->action);
-
- REAP ();
- QUIT;
-
- if (breaking)
- {
- breaking--;
- break;
- }
-
- if (continuing)
- {
- continuing--;
- if (continuing)
- break;
- }
-
-#if defined (KSH_COMPATIBLE_SELECT)
- show_menu = 0;
- selection = get_string_value ("REPLY");
- if (selection && *selection == '\0')
- show_menu = 1;
-#endif
- }
-
- loop_level--;
- line_number = save_line_number;
-
- dispose_words (releaser);
- discard_unwind_frame ("select");
- return (retval);
-}
-#endif /* SELECT_COMMAND */
-
-/* Execute a CASE command. The syntax is: CASE word_desc IN pattern_list ESAC.
- The pattern_list is a linked list of pattern clauses; each clause contains
- some patterns to compare word_desc against, and an associated command to
- execute. */
-static int
-execute_case_command (case_command)
- CASE_COM *case_command;
-{
- register WORD_LIST *list;
- WORD_LIST *wlist, *es;
- PATTERN_LIST *clauses;
- char *word, *pattern;
- int retval, match, ignore_return, save_line_number;
-
- save_line_number = line_number;
- line_number = case_command->line;
-
- command_string_index = 0;
- print_case_command_head (case_command);
-
- if (echo_command_at_execute)
- xtrace_print_case_command_head (case_command);
-
-#if 0
- if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
-#else
- if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
-#endif
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- retval = run_debug_trap();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && retval != EXECUTION_SUCCESS)
- {
- line_number = save_line_number;
- return (EXECUTION_SUCCESS);
- }
-#endif
-
- wlist = expand_word_unsplit (case_command->word, 0);
- word = wlist ? string_list (wlist) : savestring ("");
- dispose_words (wlist);
-
- retval = EXECUTION_SUCCESS;
- ignore_return = case_command->flags & CMD_IGNORE_RETURN;
-
- begin_unwind_frame ("case");
- add_unwind_protect ((Function *)xfree, word);
-
-#define EXIT_CASE() goto exit_case_command
-
- for (clauses = case_command->clauses; clauses; clauses = clauses->next)
- {
- QUIT;
- for (list = clauses->patterns; list; list = list->next)
- {
- es = expand_word_leave_quoted (list->word, 0);
-
- if (es && es->word && es->word->word && *(es->word->word))
- pattern = quote_string_for_globbing (es->word->word, QGLOB_CVTNULL);
- else
- {
- pattern = (char *)xmalloc (1);
- pattern[0] = '\0';
- }
-
- /* Since the pattern does not undergo quote removal (as per
- Posix.2, section 3.9.4.3), the strmatch () call must be able
- to recognize backslashes as escape characters. */
- match = strmatch (pattern, word, FNMATCH_EXTFLAG|FNMATCH_IGNCASE) != FNM_NOMATCH;
- free (pattern);
-
- dispose_words (es);
-
- if (match)
- {
- do
- {
- if (clauses->action && ignore_return)
- clauses->action->flags |= CMD_IGNORE_RETURN;
- retval = execute_command (clauses->action);
- }
- while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next));
- if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0)
- EXIT_CASE ();
- else
- break;
- }
-
- QUIT;
- }
- }
-
-exit_case_command:
- free (word);
- discard_unwind_frame ("case");
- line_number = save_line_number;
- return (retval);
-}
-
-#define CMD_WHILE 0
-#define CMD_UNTIL 1
-
-/* The WHILE command. Syntax: WHILE test DO action; DONE.
- Repeatedly execute action while executing test produces
- EXECUTION_SUCCESS. */
-static int
-execute_while_command (while_command)
- WHILE_COM *while_command;
-{
- return (execute_while_or_until (while_command, CMD_WHILE));
-}
-
-/* UNTIL is just like WHILE except that the test result is negated. */
-static int
-execute_until_command (while_command)
- WHILE_COM *while_command;
-{
- return (execute_while_or_until (while_command, CMD_UNTIL));
-}
-
-/* The body for both while and until. The only difference between the
- two is that the test value is treated differently. TYPE is
- CMD_WHILE or CMD_UNTIL. The return value for both commands should
- be EXECUTION_SUCCESS if no commands in the body are executed, and
- the status of the last command executed in the body otherwise. */
-static int
-execute_while_or_until (while_command, type)
- WHILE_COM *while_command;
- int type;
-{
- int return_value, body_status;
-
- body_status = EXECUTION_SUCCESS;
- loop_level++;
-
- while_command->test->flags |= CMD_IGNORE_RETURN;
- if (while_command->flags & CMD_IGNORE_RETURN)
- while_command->action->flags |= CMD_IGNORE_RETURN;
-
- while (1)
- {
- return_value = execute_command (while_command->test);
- REAP ();
-
- /* Need to handle `break' in the test when we would break out of the
- loop. The job control code will set `breaking' to loop_level
- when a job in a loop is stopped with SIGTSTP. If the stopped job
- is in the loop test, `breaking' will not be reset unless we do
- this, and the shell will cease to execute commands. */
- if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS)
- {
- if (breaking)
- breaking--;
- break;
- }
- if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS)
- {
- if (breaking)
- breaking--;
- break;
- }
-
- QUIT;
- body_status = execute_command (while_command->action);
- QUIT;
-
- if (breaking)
- {
- breaking--;
- break;
- }
-
- if (continuing)
- {
- continuing--;
- if (continuing)
- break;
- }
- }
- loop_level--;
-
- return (body_status);
-}
-
-/* IF test THEN command [ELSE command].
- IF also allows ELIF in the place of ELSE IF, but
- the parser makes *that* stupidity transparent. */
-static int
-execute_if_command (if_command)
- IF_COM *if_command;
-{
- int return_value, save_line_number;
-
- save_line_number = line_number;
- if_command->test->flags |= CMD_IGNORE_RETURN;
- return_value = execute_command (if_command->test);
- line_number = save_line_number;
-
- if (return_value == EXECUTION_SUCCESS)
- {
- QUIT;
-
- if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN))
- if_command->true_case->flags |= CMD_IGNORE_RETURN;
-
- return (execute_command (if_command->true_case));
- }
- else
- {
- QUIT;
-
- if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN))
- if_command->false_case->flags |= CMD_IGNORE_RETURN;
-
- return (execute_command (if_command->false_case));
- }
-}
-
-#if defined (DPAREN_ARITHMETIC)
-static int
-execute_arith_command (arith_command)
- ARITH_COM *arith_command;
-{
- int expok, save_line_number, retval;
- intmax_t expresult;
- WORD_LIST *new;
- char *exp;
-
- expresult = 0;
-
- save_line_number = line_number;
- this_command_name = "(("; /* )) */
- line_number = arith_command->line;
- /* If we're in a function, update the line number information. */
- if (variable_context && interactive_shell)
- line_number -= function_line_number;
-
- command_string_index = 0;
- print_arith_command (arith_command->exp);
-
- if (signal_in_progress (DEBUG_TRAP) == 0)
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- /* Run the debug trap before each arithmetic command, but do it after we
- update the line number information and before we expand the various
- words in the expression. */
- retval = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && retval != EXECUTION_SUCCESS)
- {
- line_number = save_line_number;
- return (EXECUTION_SUCCESS);
- }
-#endif
-
- new = expand_words_no_vars (arith_command->exp);
-
- /* If we're tracing, make a new word list with `((' at the front and `))'
- at the back and print it. */
- if (echo_command_at_execute)
- xtrace_print_arith_cmd (new);
-
- if (new)
- {
- exp = new->next ? string_list (new) : new->word->word;
- expresult = evalexp (exp, &expok);
- line_number = save_line_number;
- if (exp != new->word->word)
- free (exp);
- dispose_words (new);
- }
- else
- {
- expresult = 0;
- expok = 1;
- }
-
- if (expok == 0)
- return (EXECUTION_FAILURE);
-
- return (expresult == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
-}
-#endif /* DPAREN_ARITHMETIC */
-
-#if defined (COND_COMMAND)
-
-static char * const nullstr = "";
-
-/* XXX - can COND ever be NULL when this is called? */
-static int
-execute_cond_node (cond)
- COND_COM *cond;
-{
- int result, invert, patmatch, rmatch, mflags, ignore;
- char *arg1, *arg2;
-
- invert = (cond->flags & CMD_INVERT_RETURN);
- ignore = (cond->flags & CMD_IGNORE_RETURN);
- if (ignore)
- {
- if (cond->left)
- cond->left->flags |= CMD_IGNORE_RETURN;
- if (cond->right)
- cond->right->flags |= CMD_IGNORE_RETURN;
- }
-
- if (cond->type == COND_EXPR)
- result = execute_cond_node (cond->left);
- else if (cond->type == COND_OR)
- {
- result = execute_cond_node (cond->left);
- if (result != EXECUTION_SUCCESS)
- result = execute_cond_node (cond->right);
- }
- else if (cond->type == COND_AND)
- {
- result = execute_cond_node (cond->left);
- if (result == EXECUTION_SUCCESS)
- result = execute_cond_node (cond->right);
- }
- else if (cond->type == COND_UNARY)
- {
- if (ignore)
- comsub_ignore_return++;
- arg1 = cond_expand_word (cond->left->op, 0);
- if (ignore)
- comsub_ignore_return--;
- if (arg1 == 0)
- arg1 = nullstr;
- if (echo_command_at_execute)
- xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL);
- result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
- if (arg1 != nullstr)
- free (arg1);
- }
- else if (cond->type == COND_BINARY)
- {
- rmatch = 0;
- patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
- (cond->op->word[0] == '!' || cond->op->word[0] == '=')) ||
- (cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
-#if defined (COND_REGEXP)
- rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' &&
- cond->op->word[2] == '\0');
-#endif
-
- if (ignore)
- comsub_ignore_return++;
- arg1 = cond_expand_word (cond->left->op, 0);
- if (ignore)
- comsub_ignore_return--;
- if (arg1 == 0)
- arg1 = nullstr;
- if (ignore)
- comsub_ignore_return++;
- arg2 = cond_expand_word (cond->right->op,
- (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0));
- if (ignore)
- comsub_ignore_return--;
- if (arg2 == 0)
- arg2 = nullstr;
-
- if (echo_command_at_execute)
- xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2);
-
-#if defined (COND_REGEXP)
- if (rmatch)
- {
- mflags = SHMAT_PWARN;
-#if defined (ARRAY_VARS)
- mflags |= SHMAT_SUBEXP;
-#endif
-
- result = sh_regmatch (arg1, arg2, mflags);
- }
- else
-#endif /* COND_REGEXP */
- {
- int oe;
- oe = extended_glob;
- extended_glob = 1;
- result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE)
- ? EXECUTION_SUCCESS
- : EXECUTION_FAILURE;
- extended_glob = oe;
- }
- if (arg1 != nullstr)
- free (arg1);
- if (arg2 != nullstr)
- free (arg2);
- }
- else
- {
- command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0);
- jump_to_top_level (DISCARD);
- result = EXECUTION_FAILURE;
- }
-
- if (invert)
- result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
-
- return result;
-}
-
-static int
-execute_cond_command (cond_command)
- COND_COM *cond_command;
-{
- int retval, save_line_number;
-
- retval = EXECUTION_SUCCESS;
- save_line_number = line_number;
-
- this_command_name = "[[";
- line_number = cond_command->line;
- /* If we're in a function, update the line number information. */
- if (variable_context && interactive_shell)
- line_number -= function_line_number;
- command_string_index = 0;
- print_cond_command (cond_command);
-
- if (signal_in_progress (DEBUG_TRAP) == 0)
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
- }
-
- /* Run the debug trap before each conditional command, but do it after we
- update the line number information. */
- retval = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && retval != EXECUTION_SUCCESS)
- {
- line_number = save_line_number;
- return (EXECUTION_SUCCESS);
- }
-#endif
-
-#if 0
- debug_print_cond_command (cond_command);
-#endif
-
- last_command_exit_value = retval = execute_cond_node (cond_command);
- line_number = save_line_number;
- return (retval);
-}
-#endif /* COND_COMMAND */
-
-static void
-bind_lastarg (arg)
- char *arg;
-{
- SHELL_VAR *var;
-
- if (arg == 0)
- arg = "";
- var = bind_variable ("_", arg, 0);
- VUNSETATTR (var, att_exported);
-}
-
-/* Execute a null command. Fork a subshell if the command uses pipes or is
- to be run asynchronously. This handles all the side effects that are
- supposed to take place. */
-static int
-execute_null_command (redirects, pipe_in, pipe_out, async)
- REDIRECT *redirects;
- int pipe_in, pipe_out, async;
-{
- int r;
- int forcefork;
- REDIRECT *rd;
-
- for (forcefork = 0, rd = redirects; rd; rd = rd->next)
- forcefork += rd->rflags & REDIR_VARASSIGN;
-
- if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
- {
- /* We have a null command, but we really want a subshell to take
- care of it. Just fork, do piping and redirections, and exit. */
- if (make_child ((char *)NULL, async) == 0)
- {
- /* Cancel traps, in trap.c. */
- restore_original_signals (); /* XXX */
-
- do_piping (pipe_in, pipe_out);
-
-#if defined (COPROCESS_SUPPORT)
- coproc_closeall ();
-#endif
-
- subshell_environment = 0;
- if (async)
- subshell_environment |= SUBSHELL_ASYNC;
- if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
- subshell_environment |= SUBSHELL_PIPE;
-
- if (do_redirections (redirects, RX_ACTIVE) == 0)
- exit (EXECUTION_SUCCESS);
- else
- exit (EXECUTION_FAILURE);
- }
- else
- {
- close_pipes (pipe_in, pipe_out);
-#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
- unlink_fifo_list ();
-#endif
- return (EXECUTION_SUCCESS);
- }
- }
- else
- {
- /* Even if there aren't any command names, pretend to do the
- redirections that are specified. The user expects the side
- effects to take place. If the redirections fail, then return
- failure. Otherwise, if a command substitution took place while
- expanding the command or a redirection, return the value of that
- substitution. Otherwise, return EXECUTION_SUCCESS. */
-
- r = do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE);
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
-
- if (r != 0)
- return (EXECUTION_FAILURE);
- else if (last_command_subst_pid != NO_PID)
- return (last_command_exit_value);
- else
- return (EXECUTION_SUCCESS);
- }
-}
-
-/* This is a hack to suppress word splitting for assignment statements
- given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */
-static void
-fix_assignment_words (words)
- WORD_LIST *words;
-{
- WORD_LIST *w, *wcmd;
- struct builtin *b;
- int assoc, global;
-
- if (words == 0)
- return;
-
- b = 0;
- assoc = global = 0;
-
- wcmd = words;
- for (w = words; w; w = w->next)
- if (w->word->flags & W_ASSIGNMENT)
- {
- if (b == 0)
- {
- /* Posix (post-2008) says that `command' doesn't change whether
- or not the builtin it shadows is a `declaration command', even
- though it removes other special builtin properties. In Posix
- mode, we skip over one or more instances of `command' and
- deal with the next word as the assignment builtin. */
- while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
- wcmd = wcmd->next;
- b = builtin_address_internal (wcmd->word->word, 0);
- if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
- return;
- else if (b && (b->flags & ASSIGNMENT_BUILTIN))
- wcmd->word->flags |= W_ASSNBLTIN;
- }
- w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
-#if defined (ARRAY_VARS)
- if (assoc)
- w->word->flags |= W_ASSIGNASSOC;
- if (global)
- w->word->flags |= W_ASSNGLOBAL;
-#endif
- }
-#if defined (ARRAY_VARS)
- /* Note that we saw an associative array option to a builtin that takes
- assignment statements. This is a bit of a kludge. */
- else if (w->word->word[0] == '-' && (strchr (w->word->word+1, 'A') || strchr (w->word->word+1, 'g')))
-#else
- else if (w->word->word[0] == '-' && strchr (w->word->word+1, 'g'))
-#endif
- {
- if (b == 0)
- {
- while (posixly_correct && wcmd && wcmd->word && wcmd->word->word && STREQ (wcmd->word->word, "command"))
- wcmd = wcmd->next;
- b = builtin_address_internal (wcmd->word->word, 0);
- if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
- return;
- else if (b && (b->flags & ASSIGNMENT_BUILTIN))
- wcmd->word->flags |= W_ASSNBLTIN;
- }
- if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A'))
- assoc = 1;
- if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g'))
- global = 1;
- }
-}
-
-/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting
- to PATHNAME, is a directory. Used by the autocd code below. */
-static int
-is_dirname (pathname)
- char *pathname;
-{
- char *temp;
- int ret;
-
- temp = search_for_command (pathname, 0);
- ret = (temp ? file_isdir (temp) : file_isdir (pathname));
- free (temp);
- return ret;
-}
-
-/* The meaty part of all the executions. We have to start hacking the
- real execution of commands here. Fork a process, set things up,
- execute the command. */
-static int
-execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
- SIMPLE_COM *simple_command;
- int pipe_in, pipe_out, async;
- struct fd_bitmap *fds_to_close;
-{
- WORD_LIST *words, *lastword;
- char *command_line, *lastarg, *temp;
- int first_word_quoted, result, builtin_is_special, already_forked, dofork;
- pid_t old_last_async_pid;
- sh_builtin_func_t *builtin;
- SHELL_VAR *func;
- volatile int old_builtin, old_command_builtin;
-
- result = EXECUTION_SUCCESS;
- special_builtin_failed = builtin_is_special = 0;
- command_line = (char *)0;
-
- QUIT;
-
- /* If we're in a function, update the line number information. */
- if (variable_context && interactive_shell && sourcelevel == 0)
- line_number -= function_line_number;
-
- /* Remember what this command line looks like at invocation. */
- command_string_index = 0;
- print_simple_command (simple_command);
-
-#if 0
- if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
-#else
- if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
-#endif
- {
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0;
- }
-
- /* Run the debug trap before each simple command, but do it after we
- update the line number information. */
- result = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode && result != EXECUTION_SUCCESS)
- return (EXECUTION_SUCCESS);
-#endif
-
- first_word_quoted =
- simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0;
-
- last_command_subst_pid = NO_PID;
- old_last_async_pid = last_asynchronous_pid;
-
- already_forked = dofork = 0;
-
- /* If we're in a pipeline or run in the background, set DOFORK so we
- make the child early, before word expansion. This keeps assignment
- statements from affecting the parent shell's environment when they
- should not. */
- dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async;
-
- /* Something like `%2 &' should restart job 2 in the background, not cause
- the shell to fork here. */
- if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE &&
- simple_command->words && simple_command->words->word &&
- simple_command->words->word->word &&
- (simple_command->words->word->word[0] == '%'))
- dofork = 0;
-
- if (dofork)
- {
- /* Do this now, because execute_disk_command will do it anyway in the
- vast majority of cases. */
- maybe_make_export_env ();
-
- /* Don't let a DEBUG trap overwrite the command string to be saved with
- the process/job associated with this child. */
- if (make_child (savestring (the_printed_command_except_trap), async) == 0)
- {
- already_forked = 1;
- simple_command->flags |= CMD_NO_FORK;
-
- subshell_environment = SUBSHELL_FORK;
- if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
- subshell_environment |= SUBSHELL_PIPE;
- if (async)
- subshell_environment |= SUBSHELL_ASYNC;
-
- /* We need to do this before piping to handle some really
- pathological cases where one of the pipe file descriptors
- is < 2. */
- if (fds_to_close)
- close_fd_bitmap (fds_to_close);
-
- do_piping (pipe_in, pipe_out);
- pipe_in = pipe_out = NO_PIPE;
-#if defined (COPROCESS_SUPPORT)
- coproc_closeall ();
-#endif
-
- last_asynchronous_pid = old_last_async_pid;
- }
- else
- {
- /* Don't let simple commands that aren't the last command in a
- pipeline change $? for the rest of the pipeline (or at all). */
- if (pipe_out != NO_PIPE)
- result = last_command_exit_value;
- close_pipes (pipe_in, pipe_out);
-#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
- unlink_fifo_list ();
-#endif
- command_line = (char *)NULL; /* don't free this. */
- bind_lastarg ((char *)NULL);
- return (result);
- }
- }
-
- /* If we are re-running this as the result of executing the `command'
- builtin, do not expand the command words a second time. */
- if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0)
- {
- current_fds_to_close = fds_to_close;
- fix_assignment_words (simple_command->words);
- /* Pass the ignore return flag down to command substitutions */
- if (simple_command->flags & CMD_IGNORE_RETURN) /* XXX */
- comsub_ignore_return++;
- words = expand_words (simple_command->words);
- if (simple_command->flags & CMD_IGNORE_RETURN)
- comsub_ignore_return--;
- current_fds_to_close = (struct fd_bitmap *)NULL;
- }
- else
- words = copy_word_list (simple_command->words);
-
- /* It is possible for WORDS not to have anything left in it.
- Perhaps all the words consisted of `$foo', and there was
- no variable `$foo'. */
- if (words == 0)
- {
- this_command_name = 0;
- result = execute_null_command (simple_command->redirects,
- pipe_in, pipe_out,
- already_forked ? 0 : async);
- if (already_forked)
- exit (result);
- else
- {
- bind_lastarg ((char *)NULL);
- set_pipestatus_from_exit (result);
- return (result);
- }
- }
-
- lastarg = (char *)NULL;
-
- begin_unwind_frame ("simple-command");
-
- if (echo_command_at_execute)
- xtrace_print_word_list (words, 1);
-
- builtin = (sh_builtin_func_t *)NULL;
- func = (SHELL_VAR *)NULL;
- if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0)
- {
- /* Posix.2 says special builtins are found before functions. We
- don't set builtin_is_special anywhere other than here, because
- this path is followed only when the `command' builtin is *not*
- being used, and we don't want to exit the shell if a special
- builtin executed with `command builtin' fails. `command' is not
- a special builtin. */
- if (posixly_correct)
- {
- builtin = find_special_builtin (words->word->word);
- if (builtin)
- builtin_is_special = 1;
- }
- if (builtin == 0)
- func = find_function (words->word->word);
- }
-
- /* In POSIX mode, assignment errors in the temporary environment cause a
- non-interactive shell to exit. */
- if (builtin_is_special && interactive_shell == 0 && tempenv_assign_error)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (ERREXIT);
- }
-
- add_unwind_protect (dispose_words, words);
- QUIT;
-
- /* Bind the last word in this command to "$_" after execution. */
- for (lastword = words; lastword->next; lastword = lastword->next)
- ;
- lastarg = lastword->word->word;
-
-#if defined (JOB_CONTROL)
- /* Is this command a job control related thing? */
- if (words->word->word[0] == '%' && already_forked == 0)
- {
- this_command_name = async ? "bg" : "fg";
- last_shell_builtin = this_shell_builtin;
- this_shell_builtin = builtin_address (this_command_name);
- result = (*this_shell_builtin) (words);
- goto return_result;
- }
-
- /* One other possiblilty. The user may want to resume an existing job.
- If they do, find out whether this word is a candidate for a running
- job. */
- if (job_control && already_forked == 0 && async == 0 &&
- !first_word_quoted &&
- !words->next &&
- words->word->word[0] &&
- !simple_command->redirects &&
- pipe_in == NO_PIPE &&
- pipe_out == NO_PIPE &&
- (temp = get_string_value ("auto_resume")))
- {
- int job, jflags, started_status;
-
- jflags = JM_STOPPED|JM_FIRSTMATCH;
- if (STREQ (temp, "exact"))
- jflags |= JM_EXACT;
- else if (STREQ (temp, "substring"))
- jflags |= JM_SUBSTRING;
- else
- jflags |= JM_PREFIX;
- job = get_job_by_name (words->word->word, jflags);
- if (job != NO_JOB)
- {
- run_unwind_frame ("simple-command");
- this_command_name = "fg";
- last_shell_builtin = this_shell_builtin;
- this_shell_builtin = builtin_address ("fg");
-
- started_status = start_job (job, 1);
- return ((started_status < 0) ? EXECUTION_FAILURE : started_status);
- }
- }
-#endif /* JOB_CONTROL */
-
-run_builtin:
- /* Remember the name of this command globally. */
- this_command_name = words->word->word;
-
- QUIT;
-
- /* This command could be a shell builtin or a user-defined function.
- We have already found special builtins by this time, so we do not
- set builtin_is_special. If this is a function or builtin, and we
- have pipes, then fork a subshell in here. Otherwise, just execute
- the command directly. */
- if (func == 0 && builtin == 0)
- builtin = find_shell_builtin (this_command_name);
-
- last_shell_builtin = this_shell_builtin;
- this_shell_builtin = builtin;
-
- if (builtin || func)
- {
- if (builtin)
- {
- old_builtin = executing_builtin;
- old_command_builtin = executing_command_builtin;
- unwind_protect_int (executing_builtin); /* modified in execute_builtin */
- unwind_protect_int (executing_command_builtin); /* ditto */
- }
- if (already_forked)
- {
- /* reset_terminating_signals (); */ /* XXX */
- /* Reset the signal handlers in the child, but don't free the
- trap strings. Set a flag noting that we have to free the
- trap strings if we run trap to change a signal disposition. */
- reset_signal_handlers ();
- subshell_environment |= SUBSHELL_RESETTRAP;
-
- if (async)
- {
- if ((simple_command->flags & CMD_STDIN_REDIR) &&
- pipe_in == NO_PIPE &&
- (stdin_redirects (simple_command->redirects) == 0))
- async_redirect_stdin ();
- setup_async_signals ();
- }
-
- subshell_level++;
- execute_subshell_builtin_or_function
- (words, simple_command->redirects, builtin, func,
- pipe_in, pipe_out, async, fds_to_close,
- simple_command->flags);
- subshell_level--;
- }
- else
- {
- result = execute_builtin_or_function
- (words, builtin, func, simple_command->redirects, fds_to_close,
- simple_command->flags);
- if (builtin)
- {
- if (result > EX_SHERRBASE)
- {
- result = builtin_status (result);
- if (builtin_is_special)
- special_builtin_failed = 1;
- }
- /* In POSIX mode, if there are assignment statements preceding
- a special builtin, they persist after the builtin
- completes. */
- if (posixly_correct && builtin_is_special && temporary_env)
- merge_temporary_env ();
- }
- else /* function */
- {
- if (result == EX_USAGE)
- result = EX_BADUSAGE;
- else if (result > EX_SHERRBASE)
- result = EXECUTION_FAILURE;
- }
-
- set_pipestatus_from_exit (result);
-
- goto return_result;
- }
- }
-
- if (autocd && interactive && words->word && is_dirname (words->word->word))
- {
- words = make_word_list (make_word ("cd"), words);
- xtrace_print_word_list (words, 0);
- goto run_builtin;
- }
-
- if (command_line == 0)
- command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : "");
-
-#if defined (PROCESS_SUBSTITUTION)
- if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0)
- simple_command->flags &= ~CMD_NO_FORK;
-#endif
-
- result = execute_disk_command (words, simple_command->redirects, command_line,
- pipe_in, pipe_out, async, fds_to_close,
- simple_command->flags);
-
- return_result:
- bind_lastarg (lastarg);
- FREE (command_line);
- dispose_words (words);
- if (builtin)
- {
- executing_builtin = old_builtin;
- executing_command_builtin = old_command_builtin;
- }
- discard_unwind_frame ("simple-command");
- this_command_name = (char *)NULL; /* points to freed memory now */
- return (result);
-}
-
-/* Translate the special builtin exit statuses. We don't really need a
- function for this; it's a placeholder for future work. */
-static int
-builtin_status (result)
- int result;
-{
- int r;
-
- switch (result)
- {
- case EX_USAGE:
- r = EX_BADUSAGE;
- break;
- case EX_REDIRFAIL:
- case EX_BADSYNTAX:
- case EX_BADASSIGN:
- case EX_EXPFAIL:
- r = EXECUTION_FAILURE;
- break;
- default:
- r = EXECUTION_SUCCESS;
- break;
- }
- return (r);
-}
-
-static int
-execute_builtin (builtin, words, flags, subshell)
- sh_builtin_func_t *builtin;
- WORD_LIST *words;
- int flags, subshell;
-{
- int old_e_flag, result, eval_unwind;
- int isbltinenv;
- char *error_trap;
-
- error_trap = 0;
- old_e_flag = exit_immediately_on_error;
- /* The eval builtin calls parse_and_execute, which does not know about
- the setting of flags, and always calls the execution functions with
- flags that will exit the shell on an error if -e is set. If the
- eval builtin is being called, and we're supposed to ignore the exit
- value of the command, we turn the -e flag off ourselves and disable
- the ERR trap, then restore them when the command completes. This is
- also a problem (as below) for the command and source/. builtins. */
- if (subshell == 0 && (flags & CMD_IGNORE_RETURN) &&
- (builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin))
- {
- begin_unwind_frame ("eval_builtin");
- unwind_protect_int (exit_immediately_on_error);
- error_trap = TRAP_STRING (ERROR_TRAP);
- if (error_trap)
- {
- error_trap = savestring (error_trap);
- add_unwind_protect (xfree, error_trap);
- add_unwind_protect (set_error_trap, error_trap);
- restore_default_signal (ERROR_TRAP);
- }
- exit_immediately_on_error = 0;
- eval_unwind = 1;
- }
- else
- eval_unwind = 0;
-
- /* The temporary environment for a builtin is supposed to apply to
- all commands executed by that builtin. Currently, this is a
- problem only with the `unset', `source' and `eval' builtins. */
-
- isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin);
-
- if (isbltinenv)
- {
- if (subshell == 0)
- begin_unwind_frame ("builtin_env");
-
- if (temporary_env)
- {
- push_scope (VC_BLTNENV, temporary_env);
- if (subshell == 0)
- add_unwind_protect (pop_scope, (flags & CMD_COMMAND_BUILTIN) ? 0 : "1");
- temporary_env = (HASH_TABLE *)NULL;
- }
- }
-
- /* `return' does a longjmp() back to a saved environment in execute_function.
- If a variable assignment list preceded the command, and the shell is
- running in POSIX mode, we need to merge that into the shell_variables
- table, since `return' is a POSIX special builtin. */
- if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env)
- {
- begin_unwind_frame ("return_temp_env");
- add_unwind_protect (merge_temporary_env, (char *)NULL);
- }
-
- executing_builtin++;
- executing_command_builtin |= builtin == command_builtin;
- result = ((*builtin) (words->next));
-
- /* This shouldn't happen, but in case `return' comes back instead of
- longjmp'ing, we need to unwind. */
- if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env)
- discard_unwind_frame ("return_temp_env");
-
- if (subshell == 0 && isbltinenv)
- run_unwind_frame ("builtin_env");
-
- if (eval_unwind)
- {
- exit_immediately_on_error += old_e_flag;
- if (error_trap)
- {
- set_error_trap (error_trap);
- xfree (error_trap);
- }
- discard_unwind_frame ("eval_builtin");
- }
-
- return (result);
-}
-
-static int
-execute_function (var, words, flags, fds_to_close, async, subshell)
- SHELL_VAR *var;
- WORD_LIST *words;
- int flags;
- struct fd_bitmap *fds_to_close;
- int async, subshell;
-{
- int return_val, result;
- COMMAND *tc, *fc, *save_current;
- char *debug_trap, *error_trap, *return_trap;
-#if defined (ARRAY_VARS)
- SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v;
- ARRAY *funcname_a;
- volatile ARRAY *bash_source_a;
- volatile ARRAY *bash_lineno_a;
-#endif
- FUNCTION_DEF *shell_fn;
- char *sfile, *t;
-
- USE_VAR(fc);
-
- if (funcnest_max > 0 && funcnest >= funcnest_max)
- {
- internal_error (_("%s: maximum function nesting level exceeded (%d)"), var->name, funcnest);
- funcnest = 0; /* XXX - should we reset it somewhere else? */
- jump_to_top_level (DISCARD);
- }
-
-#if defined (ARRAY_VARS)
- GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
- GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
- GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
-#endif
-
- tc = (COMMAND *)copy_command (function_cell (var));
- if (tc && (flags & CMD_IGNORE_RETURN))
- tc->flags |= CMD_IGNORE_RETURN;
-
- if (subshell == 0)
- {
- begin_unwind_frame ("function_calling");
- push_context (var->name, subshell, temporary_env);
- add_unwind_protect (pop_context, (char *)NULL);
- unwind_protect_int (line_number);
- unwind_protect_int (return_catch_flag);
- unwind_protect_jmp_buf (return_catch);
- add_unwind_protect (dispose_command, (char *)tc);
- unwind_protect_pointer (this_shell_function);
- unwind_protect_int (loop_level);
- unwind_protect_int (funcnest);
- }
- else
- push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */
-
- temporary_env = (HASH_TABLE *)NULL;
-
- this_shell_function = var;
- make_funcname_visible (1);
-
- debug_trap = TRAP_STRING(DEBUG_TRAP);
- error_trap = TRAP_STRING(ERROR_TRAP);
- return_trap = TRAP_STRING(RETURN_TRAP);
-
- /* The order of the unwind protects for debug_trap, error_trap and
- return_trap is important here! unwind-protect commands are run
- in reverse order of registration. If this causes problems, take
- out the xfree unwind-protect calls and live with the small memory leak. */
-
- /* function_trace_mode != 0 means that all functions inherit the DEBUG trap.
- if the function has the trace attribute set, it inherits the DEBUG trap */
- if (debug_trap && ((trace_p (var) == 0) && function_trace_mode == 0))
- {
- if (subshell == 0)
- {
- debug_trap = savestring (debug_trap);
- add_unwind_protect (xfree, debug_trap);
- add_unwind_protect (set_debug_trap, debug_trap);
- }
- restore_default_signal (DEBUG_TRAP);
- }
-
- /* error_trace_mode != 0 means that functions inherit the ERR trap. */
- if (error_trap && error_trace_mode == 0)
- {
- if (subshell == 0)
- {
- error_trap = savestring (error_trap);
- add_unwind_protect (xfree, error_trap);
- add_unwind_protect (set_error_trap, error_trap);
- }
- restore_default_signal (ERROR_TRAP);
- }
-
- /* Shell functions inherit the RETURN trap if function tracing is on
- globally or on individually for this function. */
-#if 0
- if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0))
-#else
- if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0)))
-#endif
- {
- if (subshell == 0)
- {
- return_trap = savestring (return_trap);
- add_unwind_protect (xfree, return_trap);
- add_unwind_protect (set_return_trap, return_trap);
- }
- restore_default_signal (RETURN_TRAP);
- }
-
- funcnest++;
-#if defined (ARRAY_VARS)
- /* This is quite similar to the code in shell.c and elsewhere. */
- shell_fn = find_function_def (this_shell_function->name);
- sfile = shell_fn ? shell_fn->source_file : "";
- array_push ((ARRAY *)funcname_a, this_shell_function->name);
-
- array_push ((ARRAY *)bash_source_a, sfile);
- t = itos (executing_line_number ());
- array_push ((ARRAY *)bash_lineno_a, t);
- free (t);
-#endif
-
- /* The temporary environment for a function is supposed to apply to
- all commands executed within the function body. */
-
- remember_args (words->next, 1);
-
- /* Update BASH_ARGV and BASH_ARGC */
- if (debugging_mode)
- push_args (words->next);
-
- /* Number of the line on which the function body starts. */
- line_number = function_line_number = tc->line;
-
-#if defined (JOB_CONTROL)
- if (subshell)
- stop_pipeline (async, (COMMAND *)NULL);
-#endif
-
- fc = tc;
-
- return_catch_flag++;
- return_val = setjmp (return_catch);
-
- if (return_val)
- {
- result = return_catch_value;
- /* Run the RETURN trap in the function's context. */
- save_current = currently_executing_command;
- run_return_trap ();
- currently_executing_command = save_current;
- }
- else
- {
- /* Run the debug trap here so we can trap at the start of a function's
- execution rather than the execution of the body's first command. */
- showing_function_line = 1;
- save_current = currently_executing_command;
- result = run_debug_trap ();
-#if defined (DEBUGGER)
- /* In debugging mode, if the DEBUG trap returns a non-zero status, we
- skip the command. */
- if (debugging_mode == 0 || result == EXECUTION_SUCCESS)
- {
- showing_function_line = 0;
- currently_executing_command = save_current;
- result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close);
-
- /* Run the RETURN trap in the function's context */
- save_current = currently_executing_command;
- run_return_trap ();
- currently_executing_command = save_current;
- }
-#else
- result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close);
-
- save_current = currently_executing_command;
- run_return_trap ();
- currently_executing_command = save_current;
-#endif
- showing_function_line = 0;
- }
-
- /* Restore BASH_ARGC and BASH_ARGV */
- if (debugging_mode)
- pop_args ();
-
- if (subshell == 0)
- run_unwind_frame ("function_calling");
-
-#if defined (ARRAY_VARS)
- /* These two variables cannot be unset, and cannot be affected by the
- function. */
- array_pop ((ARRAY *)bash_source_a);
- array_pop ((ARRAY *)bash_lineno_a);
-
- /* FUNCNAME can be unset, and so can potentially be changed by the
- function. */
- GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a);
- if (nfv == funcname_v)
- array_pop (funcname_a);
-#endif
-
- if (variable_context == 0 || this_shell_function == 0)
- {
- make_funcname_visible (0);
-#if defined (PROCESS_SUBSTITUTION)
- unlink_fifo_list ();
-#endif
- }
-
- return (result);
-}
-
-/* A convenience routine for use by other parts of the shell to execute
- a particular shell function. */
-int
-execute_shell_function (var, words)
- SHELL_VAR *var;
- WORD_LIST *words;
-{
- int ret;
- struct fd_bitmap *bitmap;
-
- bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE);
- begin_unwind_frame ("execute-shell-function");
- add_unwind_protect (dispose_fd_bitmap, (char *)bitmap);
-
- ret = execute_function (var, words, 0, bitmap, 0, 0);
-
- dispose_fd_bitmap (bitmap);
- discard_unwind_frame ("execute-shell-function");
-
- return ret;
-}
-
-/* Execute a shell builtin or function in a subshell environment. This
- routine does not return; it only calls exit(). If BUILTIN is non-null,
- it points to a function to call to execute a shell builtin; otherwise
- VAR points at the body of a function to execute. WORDS is the arguments
- to the command, REDIRECTS specifies redirections to perform before the
- command is executed. */
-static void
-execute_subshell_builtin_or_function (words, redirects, builtin, var,
- pipe_in, pipe_out, async, fds_to_close,
- flags)
- WORD_LIST *words;
- REDIRECT *redirects;
- sh_builtin_func_t *builtin;
- SHELL_VAR *var;
- int pipe_in, pipe_out, async;
- struct fd_bitmap *fds_to_close;
- int flags;
-{
- int result, r, funcvalue;
-#if defined (JOB_CONTROL)
- int jobs_hack;
-
- jobs_hack = (builtin == jobs_builtin) &&
- ((subshell_environment & SUBSHELL_ASYNC) == 0 || pipe_out != NO_PIPE);
-#endif
-
- /* A subshell is neither a login shell nor interactive. */
- login_shell = interactive = 0;
-
- if (async)
- subshell_environment |= SUBSHELL_ASYNC;
- if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
- subshell_environment |= SUBSHELL_PIPE;
-
- maybe_make_export_env (); /* XXX - is this needed? */
-
-#if defined (JOB_CONTROL)
- /* Eradicate all traces of job control after we fork the subshell, so
- all jobs begun by this subshell are in the same process group as
- the shell itself. */
-
- /* Allow the output of `jobs' to be piped. */
- if (jobs_hack)
- kill_current_pipeline ();
- else
- without_job_control ();
-
- set_sigchld_handler ();
-#endif /* JOB_CONTROL */
-
- set_sigint_handler ();
-
- if (fds_to_close)
- close_fd_bitmap (fds_to_close);
-
- do_piping (pipe_in, pipe_out);
-
- if (do_redirections (redirects, RX_ACTIVE) != 0)
- exit (EXECUTION_FAILURE);
-
- if (builtin)
- {
- /* Give builtins a place to jump back to on failure,
- so we don't go back up to main(). */
- result = setjmp (top_level);
-
- /* Give the return builtin a place to jump to when executed in a subshell
- or pipeline */
- funcvalue = 0;
- if (return_catch_flag && builtin == return_builtin)
- funcvalue = setjmp (return_catch);
-
- if (result == EXITPROG)
- exit (last_command_exit_value);
- else if (result)
- exit (EXECUTION_FAILURE);
- else if (funcvalue)
- exit (return_catch_value);
- else
- {
- r = execute_builtin (builtin, words, flags, 1);
- fflush (stdout);
- if (r == EX_USAGE)
- r = EX_BADUSAGE;
- exit (r);
- }
- }
- else
- {
- r = execute_function (var, words, flags, fds_to_close, async, 1);
- fflush (stdout);
- exit (r);
- }
-}
-
-/* Execute a builtin or function in the current shell context. If BUILTIN
- is non-null, it is the builtin command to execute, otherwise VAR points
- to the body of a function. WORDS are the command's arguments, REDIRECTS
- are the redirections to perform. FDS_TO_CLOSE is the usual bitmap of
- file descriptors to close.
-
- If BUILTIN is exec_builtin, the redirections specified in REDIRECTS are
- not undone before this function returns. */
-static int
-execute_builtin_or_function (words, builtin, var, redirects,
- fds_to_close, flags)
- WORD_LIST *words;
- sh_builtin_func_t *builtin;
- SHELL_VAR *var;
- REDIRECT *redirects;
- struct fd_bitmap *fds_to_close;
- int flags;
-{
- int result;
- REDIRECT *saved_undo_list;
-#if defined (PROCESS_SUBSTITUTION)
- int ofifo, nfifo, osize;
- char *ofifo_list;
-#endif
-
-
-#if defined (PROCESS_SUBSTITUTION)
- ofifo = num_fifos ();
- ofifo_list = copy_fifo_list (&osize);
-#endif
-
- if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0)
- {
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
- dispose_exec_redirects ();
-#if defined (PROCESS_SUBSTITUTION)
- free (ofifo_list);
-#endif
- return (EX_REDIRFAIL); /* was EXECUTION_FAILURE */
- }
-
- saved_undo_list = redirection_undo_list;
-
- /* Calling the "exec" builtin changes redirections forever. */
- if (builtin == exec_builtin)
- {
- dispose_redirects (saved_undo_list);
- saved_undo_list = exec_redirection_undo_list;
- exec_redirection_undo_list = (REDIRECT *)NULL;
- }
- else
- dispose_exec_redirects ();
-
- if (saved_undo_list)
- {
- begin_unwind_frame ("saved redirects");
- add_unwind_protect (cleanup_redirects, (char *)saved_undo_list);
- }
-
- redirection_undo_list = (REDIRECT *)NULL;
-
- if (builtin)
- result = execute_builtin (builtin, words, flags, 0);
- else
- result = execute_function (var, words, flags, fds_to_close, 0, 0);
-
- /* We do this before undoing the effects of any redirections. */
- fflush (stdout);
- fpurge (stdout);
- if (ferror (stdout))
- clearerr (stdout);
-
- /* If we are executing the `command' builtin, but this_shell_builtin is
- set to `exec_builtin', we know that we have something like
- `command exec [redirection]', since otherwise `exec' would have
- overwritten the shell and we wouldn't get here. In this case, we
- want to behave as if the `command' builtin had not been specified
- and preserve the redirections. */
- if (builtin == command_builtin && this_shell_builtin == exec_builtin)
- {
- int discard;
-
- discard = 0;
- if (saved_undo_list)
- {
- dispose_redirects (saved_undo_list);
- discard = 1;
- }
- redirection_undo_list = exec_redirection_undo_list;
- saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;
- if (discard)
- discard_unwind_frame ("saved redirects");
- }
-
- if (saved_undo_list)
- {
- redirection_undo_list = saved_undo_list;
- discard_unwind_frame ("saved redirects");
- }
-
- if (redirection_undo_list)
- {
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
- }
-
-#if defined (PROCESS_SUBSTITUTION)
- /* Close any FIFOs created by this builtin or function. */
- nfifo = num_fifos ();
- if (nfifo > ofifo)
- close_new_fifos (ofifo_list, osize);
- free (ofifo_list);
-#endif
-
- return (result);
-}
-
-void
-setup_async_signals ()
-{
-#if defined (__BEOS__)
- set_signal_handler (SIGHUP, SIG_IGN); /* they want csh-like behavior */
-#endif
-
-#if defined (JOB_CONTROL)
- if (job_control == 0)
-#endif
- {
- set_signal_handler (SIGINT, SIG_IGN);
- set_signal_ignored (SIGINT);
- set_signal_handler (SIGQUIT, SIG_IGN);
- set_signal_ignored (SIGQUIT);
- }
-}
-
-/* Execute a simple command that is hopefully defined in a disk file
- somewhere.
-
- 1) fork ()
- 2) connect pipes
- 3) look up the command
- 4) do redirections
- 5) execve ()
- 6) If the execve failed, see if the file has executable mode set.
- If so, and it isn't a directory, then execute its contents as
- a shell script.
-
- Note that the filename hashing stuff has to take place up here,
- in the parent. This is probably why the Bourne style shells
- don't handle it, since that would require them to go through
- this gnarly hair, for no good reason.
-
- NOTE: callers expect this to fork or exit(). */
-
-/* Name of a shell function to call when a command name is not found. */
-#ifndef NOTFOUND_HOOK
-# define NOTFOUND_HOOK "command_not_found_handle"
-#endif
-
-static int
-execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
- async, fds_to_close, cmdflags)
- WORD_LIST *words;
- REDIRECT *redirects;
- char *command_line;
- int pipe_in, pipe_out, async;
- struct fd_bitmap *fds_to_close;
- int cmdflags;
-{
- char *pathname, *command, **args;
- int nofork, result;
- pid_t pid;
- SHELL_VAR *hookf;
- WORD_LIST *wl;
-
- nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */
- pathname = words->word->word;
-
- result = EXECUTION_SUCCESS;
-#if defined (RESTRICTED_SHELL)
- command = (char *)NULL;
- if (restricted && mbschr (pathname, '/'))
- {
- internal_error (_("%s: restricted: cannot specify `/' in command names"),
- pathname);
- result = last_command_exit_value = EXECUTION_FAILURE;
-
- /* If we're not going to fork below, we must already be in a child
- process or a context in which it's safe to call exit(2). */
- if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
- exit (last_command_exit_value);
- else
- goto parent_return;
- }
-#endif /* RESTRICTED_SHELL */
-
- command = search_for_command (pathname, 1);
-
- if (command)
- {
- maybe_make_export_env ();
- put_command_name_into_env (command);
- }
-
- /* We have to make the child before we check for the non-existence
- of COMMAND, since we want the error messages to be redirected. */
- /* If we can get away without forking and there are no pipes to deal with,
- don't bother to fork, just directly exec the command. */
- if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
- pid = 0;
- else
- pid = make_child (savestring (command_line), async);
-
- if (pid == 0)
- {
- int old_interactive;
-
-#if 0
- /* This has been disabled for the time being. */
-#if !defined (ARG_MAX) || ARG_MAX >= 10240
- if (posixly_correct == 0)
- put_gnu_argv_flags_into_env ((long)getpid (), glob_argv_flags);
-#endif
-#endif
-
- reset_terminating_signals (); /* XXX */
- /* Cancel traps, in trap.c. */
- restore_original_signals ();
-
- /* restore_original_signals may have undone the work done
- by make_child to ensure that SIGINT and SIGQUIT are ignored
- in asynchronous children. */
- if (async)
- {
- if ((cmdflags & CMD_STDIN_REDIR) &&
- pipe_in == NO_PIPE &&
- (stdin_redirects (redirects) == 0))
- async_redirect_stdin ();
- setup_async_signals ();
- }
-
- /* This functionality is now provided by close-on-exec of the
- file descriptors manipulated by redirection and piping.
- Some file descriptors still need to be closed in all children
- because of the way bash does pipes; fds_to_close is a
- bitmap of all such file descriptors. */
- if (fds_to_close)
- close_fd_bitmap (fds_to_close);
-
- do_piping (pipe_in, pipe_out);
-
- old_interactive = interactive;
- if (async)
- interactive = 0;
-
- subshell_environment = SUBSHELL_FORK;
-
- if (redirects && (do_redirections (redirects, RX_ACTIVE) != 0))
- {
-#if defined (PROCESS_SUBSTITUTION)
- /* Try to remove named pipes that may have been created as the
- result of redirections. */
- unlink_fifo_list ();
-#endif /* PROCESS_SUBSTITUTION */
- exit (EXECUTION_FAILURE);
- }
-
- if (async)
- interactive = old_interactive;
-
- if (command == 0)
- {
- hookf = find_function (NOTFOUND_HOOK);
- if (hookf == 0)
- {
- /* Make sure filenames are displayed using printable characters */
- if (ansic_shouldquote (pathname))
- pathname = ansic_quote (pathname, 0, NULL);
- internal_error (_("%s: command not found"), pathname);
- exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */
- }
-
- /* May need to reinitialize more of the job control state here. */
- stop_making_children ();
-
- wl = make_word_list (make_word (NOTFOUND_HOOK), words);
- exit (execute_shell_function (hookf, wl));
- }
-
- /* Execve expects the command name to be in args[0]. So we
- leave it there, in the same format that the user used to
- type it in. */
- args = strvec_from_word_list (words, 0, 0, (int *)NULL);
- exit (shell_execve (command, args, export_env));
- }
- else
- {
-parent_return:
- QUIT;
-
- /* Make sure that the pipes are closed in the parent. */
- close_pipes (pipe_in, pipe_out);
-#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
- if (variable_context == 0)
- unlink_fifo_list ();
-#endif
- FREE (command);
- return (result);
- }
-}
-
-/* CPP defines to decide whether a particular index into the #! line
- corresponds to a valid interpreter name or argument character, or
- whitespace. The MSDOS define is to allow \r to be treated the same
- as \n. */
-
-#if !defined (MSDOS)
-# define STRINGCHAR(ind) \
- (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n')
-# define WHITECHAR(ind) \
- (ind < sample_len && whitespace (sample[ind]))
-#else /* MSDOS */
-# define STRINGCHAR(ind) \
- (ind < sample_len && !whitespace (sample[ind]) && sample[ind] != '\n' && sample[ind] != '\r')
-# define WHITECHAR(ind) \
- (ind < sample_len && whitespace (sample[ind]))
-#endif /* MSDOS */
-
-static char *
-getinterp (sample, sample_len, endp)
- char *sample;
- int sample_len, *endp;
-{
- register int i;
- char *execname;
- int start;
-
- /* Find the name of the interpreter to exec. */
- for (i = 2; i < sample_len && whitespace (sample[i]); i++)
- ;
-
- for (start = i; STRINGCHAR(i); i++)
- ;
-
- execname = substring (sample, start, i);
-
- if (endp)
- *endp = i;
- return execname;
-}
-
-#if !defined (HAVE_HASH_BANG_EXEC)
-/* If the operating system on which we're running does not handle
- the #! executable format, then help out. SAMPLE is the text read
- from the file, SAMPLE_LEN characters. COMMAND is the name of
- the script; it and ARGS, the arguments given by the user, will
- become arguments to the specified interpreter. ENV is the environment
- to pass to the interpreter.
-
- The word immediately following the #! is the interpreter to execute.
- A single argument to the interpreter is allowed. */
-
-static int
-execute_shell_script (sample, sample_len, command, args, env)
- char *sample;
- int sample_len;
- char *command;
- char **args, **env;
-{
- char *execname, *firstarg;
- int i, start, size_increment, larry;
-
- /* Find the name of the interpreter to exec. */
- execname = getinterp (sample, sample_len, &i);
- size_increment = 1;
-
- /* Now the argument, if any. */
- for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++)
- ;
-
- /* If there is more text on the line, then it is an argument for the
- interpreter. */
-
- if (STRINGCHAR(i))
- {
- for (start = i; STRINGCHAR(i); i++)
- ;
- firstarg = substring ((char *)sample, start, i);
- size_increment = 2;
- }
-
- larry = strvec_len (args) + size_increment;
- args = strvec_resize (args, larry + 1);
-
- for (i = larry - 1; i; i--)
- args[i] = args[i - size_increment];
-
- args[0] = execname;
- if (firstarg)
- {
- args[1] = firstarg;
- args[2] = command;
- }
- else
- args[1] = command;
-
- args[larry] = (char *)NULL;
-
- return (shell_execve (execname, args, env));
-}
-#undef STRINGCHAR
-#undef WHITECHAR
-
-#endif /* !HAVE_HASH_BANG_EXEC */
-
-static void
-initialize_subshell ()
-{
-#if defined (ALIAS)
- /* Forget about any aliases that we knew of. We are in a subshell. */
- delete_all_aliases ();
-#endif /* ALIAS */
-
-#if defined (HISTORY)
- /* Forget about the history lines we have read. This is a non-interactive
- subshell. */
- history_lines_this_session = 0;
-#endif
-
-#if defined (JOB_CONTROL)
- /* Forget about the way job control was working. We are in a subshell. */
- without_job_control ();
- set_sigchld_handler ();
- init_job_stats ();
-#endif /* JOB_CONTROL */
-
- /* Reset the values of the shell flags and options. */
- reset_shell_flags ();
- reset_shell_options ();
- reset_shopt_options ();
-
- /* Zero out builtin_env, since this could be a shell script run from a
- sourced file with a temporary environment supplied to the `source/.'
- builtin. Such variables are not supposed to be exported (empirical
- testing with sh and ksh). Just throw it away; don't worry about a
- memory leak. */
- if (vc_isbltnenv (shell_variables))
- shell_variables = shell_variables->down;
-
- clear_unwind_protect_list (0);
- /* XXX -- are there other things we should be resetting here? */
- parse_and_execute_level = 0; /* nothing left to restore it */
-
- /* We're no longer inside a shell function. */
- variable_context = return_catch_flag = funcnest = 0;
-
- executing_list = 0; /* XXX */
-
- /* If we're not interactive, close the file descriptor from which we're
- reading the current shell script. */
- if (interactive_shell == 0)
- unset_bash_input (0);
-}
-
-#if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE)
-# define SETOSTYPE(x) __setostype(x)
-#else
-# define SETOSTYPE(x)
-#endif
-
-#define READ_SAMPLE_BUF(file, buf, len) \
- do \
- { \
- fd = open(file, O_RDONLY); \
- if (fd >= 0) \
- { \
- len = read (fd, buf, 80); \
- close (fd); \
- } \
- else \
- len = -1; \
- } \
- while (0)
-
-/* Call execve (), handling interpreting shell scripts, and handling
- exec failures. */
-int
-shell_execve (command, args, env)
- char *command;
- char **args, **env;
-{
- int larray, i, fd;
- char sample[80];
- int sample_len;
-
- SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */
- execve (command, args, env);
- i = errno; /* error from execve() */
- CHECK_TERMSIG;
- SETOSTYPE (1);
-
- /* If we get to this point, then start checking out the file.
- Maybe it is something we can hack ourselves. */
- if (i != ENOEXEC)
- {
- if (file_isdir (command))
-#if defined (EISDIR)
- internal_error (_("%s: %s"), command, strerror (EISDIR));
-#else
- internal_error (_("%s: is a directory"), command);
-#endif
- else if (executable_file (command) == 0)
- {
- errno = i;
- file_error (command);
- }
- /* errors not involving the path argument to execve. */
- else if (i == E2BIG || i == ENOMEM)
- {
- errno = i;
- file_error (command);
- }
- else
- {
- /* The file has the execute bits set, but the kernel refuses to
- run it for some reason. See why. */
-#if defined (HAVE_HASH_BANG_EXEC)
- READ_SAMPLE_BUF (command, sample, sample_len);
- sample[sample_len - 1] = '\0';
- if (sample_len > 2 && sample[0] == '#' && sample[1] == '!')
- {
- char *interp;
- int ilen;
-
- interp = getinterp (sample, sample_len, (int *)NULL);
- ilen = strlen (interp);
- errno = i;
- if (interp[ilen - 1] == '\r')
- {
- interp = xrealloc (interp, ilen + 2);
- interp[ilen - 1] = '^';
- interp[ilen] = 'M';
- interp[ilen + 1] = '\0';
- }
- sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : "");
- FREE (interp);
- return (EX_NOEXEC);
- }
-#endif
- errno = i;
- file_error (command);
- }
- return ((i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); /* XXX Posix.2 says that exit status is 126 */
- }
-
- /* This file is executable.
- If it begins with #!, then help out people with losing operating
- systems. Otherwise, check to see if it is a binary file by seeing
- if the contents of the first line (or up to 80 characters) are in the
- ASCII set. If it's a text file, execute the contents as shell commands,
- otherwise return 126 (EX_BINARY_FILE). */
- READ_SAMPLE_BUF (command, sample, sample_len);
-
- if (sample_len == 0)
- return (EXECUTION_SUCCESS);
-
- /* Is this supposed to be an executable script?
- If so, the format of the line is "#! interpreter [argument]".
- A single argument is allowed. The BSD kernel restricts
- the length of the entire line to 32 characters (32 bytes
- being the size of the BSD exec header), but we allow 80
- characters. */
- if (sample_len > 0)
- {
-#if !defined (HAVE_HASH_BANG_EXEC)
- if (sample_len > 2 && sample[0] == '#' && sample[1] == '!')
- return (execute_shell_script (sample, sample_len, command, args, env));
- else
-#endif
- if (check_binary_file (sample, sample_len))
- {
- internal_error (_("%s: cannot execute binary file: %s"), command, strerror (i));
- return (EX_BINARY_FILE);
- }
- }
-
- /* We have committed to attempting to execute the contents of this file
- as shell commands. */
-
- initialize_subshell ();
-
- set_sigint_handler ();
-
- /* Insert the name of this shell into the argument list. */
- larray = strvec_len (args) + 1;
- args = strvec_resize (args, larray + 1);
-
- for (i = larray - 1; i; i--)
- args[i] = args[i - 1];
-
- args[0] = shell_name;
- args[1] = command;
- args[larray] = (char *)NULL;
-
- if (args[0][0] == '-')
- args[0]++;
-
-#if defined (RESTRICTED_SHELL)
- if (restricted)
- change_flag ('r', FLAG_OFF);
-#endif
-
- if (subshell_argv)
- {
- /* Can't free subshell_argv[0]; that is shell_name. */
- for (i = 1; i < subshell_argc; i++)
- free (subshell_argv[i]);
- free (subshell_argv);
- }
-
- dispose_command (currently_executing_command); /* XXX */
- currently_executing_command = (COMMAND *)NULL;
-
- subshell_argc = larray;
- subshell_argv = args;
- subshell_envp = env;
-
- unbind_args (); /* remove the positional parameters */
-
- longjmp (subshell_top_level, 1);
- /*NOTREACHED*/
-}
-
-static int
-execute_intern_function (name, funcdef)
- WORD_DESC *name;
- FUNCTION_DEF *funcdef;
-{
- SHELL_VAR *var;
-
- if (check_identifier (name, posixly_correct) == 0)
- {
- if (posixly_correct && interactive_shell == 0)
- {
- last_command_exit_value = EX_BADUSAGE;
- jump_to_top_level (ERREXIT);
- }
- return (EXECUTION_FAILURE);
- }
-
- /* Posix interpretation 383 */
- if (posixly_correct && find_special_builtin (name->word))
- {
- internal_error (_("`%s': is a special builtin"), name->word);
- last_command_exit_value = EX_BADUSAGE;
- jump_to_top_level (ERREXIT);
- }
-
- var = find_function (name->word);
- if (var && (readonly_p (var) || noassign_p (var)))
- {
- if (readonly_p (var))
- internal_error (_("%s: readonly function"), var->name);
- return (EXECUTION_FAILURE);
- }
-
-#if defined (DEBUGGER)
- bind_function_def (name->word, funcdef);
-#endif
-
- bind_function (name->word, funcdef->command);
- return (EXECUTION_SUCCESS);
-}
-
-#if defined (INCLUDE_UNUSED)
-#if defined (PROCESS_SUBSTITUTION)
-void
-close_all_files ()
-{
- register int i, fd_table_size;
-
- fd_table_size = getdtablesize ();
- if (fd_table_size > 256) /* clamp to a reasonable value */
- fd_table_size = 256;
-
- for (i = 3; i < fd_table_size; i++)
- close (i);
-}
-#endif /* PROCESS_SUBSTITUTION */
-#endif
-
-static void
-close_pipes (in, out)
- int in, out;
-{
- if (in >= 0)
- close (in);
- if (out >= 0)
- close (out);
-}
-
-static void
-dup_error (oldd, newd)
- int oldd, newd;
-{
- sys_error (_("cannot duplicate fd %d to fd %d"), oldd, newd);
-}
-
-/* Redirect input and output to be from and to the specified pipes.
- NO_PIPE and REDIRECT_BOTH are handled correctly. */
-static void
-do_piping (pipe_in, pipe_out)
- int pipe_in, pipe_out;
-{
- if (pipe_in != NO_PIPE)
- {
- if (dup2 (pipe_in, 0) < 0)
- dup_error (pipe_in, 0);
- if (pipe_in > 0)
- close (pipe_in);
-#ifdef __CYGWIN__
- /* Let stdio know the fd may have changed from text to binary mode. */
- freopen (NULL, "r", stdin);
-#endif /* __CYGWIN__ */
- }
- if (pipe_out != NO_PIPE)
- {
- if (pipe_out != REDIRECT_BOTH)
- {
- if (dup2 (pipe_out, 1) < 0)
- dup_error (pipe_out, 1);
- if (pipe_out == 0 || pipe_out > 1)
- close (pipe_out);
- }
- else
- {
- if (dup2 (1, 2) < 0)
- dup_error (1, 2);
- }
-#ifdef __CYGWIN__
- /* Let stdio know the fd may have changed from text to binary mode, and
- make sure to preserve stdout line buffering. */
- freopen (NULL, "w", stdout);
- sh_setlinebuf (stdout);
-#endif /* __CYGWIN__ */
- }
-}
+++ /dev/null
-/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-int FCT __P((CHAR *, CHAR *, int));
-
-static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
-static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
-static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
-static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
-
-/*static*/ CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
-
-int
-FCT (pattern, string, flags)
- CHAR *pattern;
- CHAR *string;
- int flags;
-{
- CHAR *se, *pe;
-
- if (string == 0 || pattern == 0)
- return FNM_NOMATCH;
-
- se = string + STRLEN ((XCHAR *)string);
- pe = pattern + STRLEN ((XCHAR *)pattern);
-
- return (GMATCH (string, se, pattern, pe, flags));
-}
-
-/* Match STRING against the filename pattern PATTERN, returning zero if
- it matches, FNM_NOMATCH if not. */
-static int
-GMATCH (string, se, pattern, pe, flags)
- CHAR *string, *se;
- CHAR *pattern, *pe;
- int flags;
-{
- CHAR *p, *n; /* pattern, string */
- INT c; /* current pattern character - XXX U_CHAR? */
- INT sc; /* current string character - XXX U_CHAR? */
-
- p = pattern;
- n = string;
-
- if (string == 0 || pattern == 0)
- return FNM_NOMATCH;
-
-#if DEBUG_MATCHING
-fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);
-fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
-#endif
-
- while (p < pe)
- {
- c = *p++;
- c = FOLD (c);
-
- sc = n < se ? *n : '\0';
-
-#ifdef EXTENDED_GLOB
- /* EXTMATCH () will handle recursively calling GMATCH, so we can
- just return what EXTMATCH() returns. */
- if ((flags & FNM_EXTMATCH) && *p == L('(') &&
- (c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */
- {
- int lflags;
- /* If we're not matching the start of the string, we're not
- concerned about the special cases for matching `.' */
- lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
- return (EXTMATCH (c, n, se, p, pe, lflags));
- }
-#endif /* EXTENDED_GLOB */
-
- switch (c)
- {
- case L('?'): /* Match single character */
- if (sc == '\0')
- return FNM_NOMATCH;
- else if ((flags & FNM_PATHNAME) && sc == L('/'))
- /* If we are matching a pathname, `?' can never match a `/'. */
- return FNM_NOMATCH;
- else if ((flags & FNM_PERIOD) && sc == L('.') &&
- (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
- /* `?' cannot match a `.' if it is the first character of the
- string or if it is the first character following a slash and
- we are matching a pathname. */
- return FNM_NOMATCH;
- break;
-
- case L('\\'): /* backslash escape removes special meaning */
- if (p == pe)
- return FNM_NOMATCH;
-
- if ((flags & FNM_NOESCAPE) == 0)
- {
- c = *p++;
- /* A trailing `\' cannot match. */
- if (p > pe)
- return FNM_NOMATCH;
- c = FOLD (c);
- }
- if (FOLD (sc) != (U_CHAR)c)
- return FNM_NOMATCH;
- break;
-
- case '*': /* Match zero or more characters */
- if (p == pe)
- return 0;
-
- if ((flags & FNM_PERIOD) && sc == L('.') &&
- (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
- /* `*' cannot match a `.' if it is the first character of the
- string or if it is the first character following a slash and
- we are matching a pathname. */
- return FNM_NOMATCH;
-
- /* Collapse multiple consecutive `*' and `?', but make sure that
- one character of the string is consumed for each `?'. */
- for (c = *p++; (c == L('?') || c == L('*')); c = *p++)
- {
- if ((flags & FNM_PATHNAME) && sc == L('/'))
- /* A slash does not match a wildcard under FNM_PATHNAME. */
- return FNM_NOMATCH;
-#ifdef EXTENDED_GLOB
- else if ((flags & FNM_EXTMATCH) && c == L('?') && *p == L('(')) /* ) */
- {
- CHAR *newn;
- for (newn = n; newn < se; ++newn)
- {
- if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
- return (0);
- }
- /* We didn't match. If we have a `?(...)', that's failure. */
- return FNM_NOMATCH;
- }
-#endif
- else if (c == L('?'))
- {
- if (sc == L('\0'))
- return FNM_NOMATCH;
- /* One character of the string is consumed in matching
- this ? wildcard, so *??? won't match if there are
- fewer than three characters. */
- n++;
- sc = n < se ? *n : '\0';
- }
-
-#ifdef EXTENDED_GLOB
- /* Handle ******(patlist) */
- if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/
- {
- CHAR *newn;
- /* We need to check whether or not the extended glob
- pattern matches the remainder of the string.
- If it does, we match the entire pattern. */
- for (newn = n; newn < se; ++newn)
- {
- if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
- return (0);
- }
- /* We didn't match the extended glob pattern, but
- that's OK, since we can match 0 or more occurrences.
- We need to skip the glob pattern and see if we
- match the rest of the string. */
- newn = PATSCAN (p + 1, pe, 0);
- /* If NEWN is 0, we have an ill-formed pattern. */
- p = newn ? newn : pe;
- }
-#endif
- if (p == pe)
- break;
- }
-
- /* If we've hit the end of the pattern and the last character of
- the pattern was handled by the loop above, we've succeeded.
- Otherwise, we need to match that last character. */
- if (p == pe && (c == L('?') || c == L('*')))
- return (0);
-
- /* General case, use recursion. */
- {
- U_CHAR c1;
-
- c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c;
- c1 = FOLD (c1);
- for (--p; n < se; ++n)
- {
- /* Only call strmatch if the first character indicates a
- possible match. We can check the first character if
- we're not doing an extended glob match. */
- if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
- continue;
-
- /* If we're doing an extended glob match and the pattern is not
- one of the extended glob patterns, we can check the first
- character. */
- if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/
- STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
- continue;
-
- /* Otherwise, we just recurse. */
- if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
- return (0);
- }
- return FNM_NOMATCH;
- }
-
- case L('['):
- {
- if (sc == L('\0') || n == se)
- return FNM_NOMATCH;
-
- /* A character class cannot match a `.' if it is the first
- character of the string or if it is the first character
- following a slash and we are matching a pathname. */
- if ((flags & FNM_PERIOD) && sc == L('.') &&
- (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
- return (FNM_NOMATCH);
-
- p = BRACKMATCH (p, sc, flags);
- if (p == 0)
- return FNM_NOMATCH;
- }
- break;
-
- default:
- if ((U_CHAR)c != FOLD (sc))
- return (FNM_NOMATCH);
- }
-
- ++n;
- }
-
- if (n == se)
- return (0);
-
- if ((flags & FNM_LEADING_DIR) && *n == L('/'))
- /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
- return 0;
-
- return (FNM_NOMATCH);
-}
-
-/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
- the value of the symbol, and move P past the collating symbol expression.
- The value is returned in *VP, if VP is not null. */
-static CHAR *
-PARSE_COLLSYM (p, vp)
- CHAR *p;
- INT *vp;
-{
- register int pc;
- INT val;
-
- p++; /* move past the `.' */
-
- for (pc = 0; p[pc]; pc++)
- if (p[pc] == L('.') && p[pc+1] == L(']'))
- break;
- val = COLLSYM (p, pc);
- if (vp)
- *vp = val;
- return (p + pc + 2);
-}
-
-/* Use prototype definition here because of type promotion. */
-static CHAR *
-#if defined (PROTOTYPES)
-BRACKMATCH (CHAR *p, U_CHAR test, int flags)
-#else
-BRACKMATCH (p, test, flags)
- CHAR *p;
- U_CHAR test;
- int flags;
-#endif
-{
- register CHAR cstart, cend, c;
- register int not; /* Nonzero if the sense of the character class is inverted. */
- int brcnt, forcecoll;;
- INT pc;
- CHAR *savep;
-
- test = FOLD (test);
-
- savep = p;
-
- /* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
- circumflex (`^') in its role in a `nonmatching list'. A bracket
- expression starting with an unquoted circumflex character produces
- unspecified results. This implementation treats the two identically. */
- if (not = (*p == L('!') || *p == L('^')))
- ++p;
-
- c = *p++;
- for (;;)
- {
- /* Initialize cstart and cend in case `-' is the last
- character of the pattern. */
- cstart = cend = c;
- forcecoll = 0;
-
- /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
- the end of the equivalence class, move the pattern pointer past
- it, and check for equivalence. XXX - this handles only
- single-character equivalence classes, which is wrong, or at
- least incomplete. */
- if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
- {
- pc = FOLD (p[1]);
- p += 4;
- if (COLLEQUIV (test, pc))
- {
-/*[*/ /* Move past the closing `]', since the first thing we do at
- the `matched:' label is back p up one. */
- p++;
- goto matched;
- }
- else
- {
- c = *p++;
- if (c == L('\0'))
- return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
- c = FOLD (c);
- continue;
- }
- }
-
- /* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
- if (c == L('[') && *p == L(':'))
- {
- CHAR *close, *ccname;
-
- pc = 0; /* make sure invalid char classes don't match. */
- /* Find end of character class name */
- for (close = p + 1; *close != '\0'; close++)
- if (*close == L(':') && *(close+1) == L(']'))
- break;
-
- if (*close != L('\0'))
- {
- ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
- if (ccname == 0)
- pc = 0;
- else
- {
- bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
- *(ccname + (close - p - 1)) = L('\0');
- pc = IS_CCLASS (test, (XCHAR *)ccname);
- }
- if (pc == -1)
- pc = 0;
- else
- p = close + 2;
-
- free (ccname);
- }
-
- if (pc)
- {
-/*[*/ /* Move past the closing `]', since the first thing we do at
- the `matched:' label is back p up one. */
- p++;
- goto matched;
- }
- else
- {
- /* continue the loop here, since this expression can't be
- the first part of a range expression. */
- c = *p++;
- if (c == L('\0'))
- return ((test == L('[')) ? savep : (CHAR *)0);
- else if (c == L(']'))
- break;
- c = FOLD (c);
- continue;
- }
- }
-
- /* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
- the symbol name, make sure it is terminated by `.]', translate
- the name to a character using the external table, and do the
- comparison. */
- if (c == L('[') && *p == L('.'))
- {
- p = PARSE_COLLSYM (p, &pc);
- /* An invalid collating symbol cannot be the first point of a
- range. If it is, we set cstart to one greater than `test',
- so any comparisons later will fail. */
- cstart = (pc == INVALID) ? test + 1 : pc;
- forcecoll = 1;
- }
-
- if (!(flags & FNM_NOESCAPE) && c == L('\\'))
- {
- if (*p == '\0')
- return (CHAR *)0;
- cstart = cend = *p++;
- }
-
- cstart = cend = FOLD (cstart);
-
- /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
- is not preceded by a backslash and is not part of a bracket
- expression produces undefined results.' This implementation
- treats the `[' as just a character to be matched if there is
- not a closing `]'. */
- if (c == L('\0'))
- return ((test == L('[')) ? savep : (CHAR *)0);
-
- c = *p++;
- c = FOLD (c);
-
- if ((flags & FNM_PATHNAME) && c == L('/'))
- /* [/] can never match when matching a pathname. */
- return (CHAR *)0;
-
- /* This introduces a range, unless the `-' is the last
- character of the class. Find the end of the range
- and move past it. */
- if (c == L('-') && *p != L(']'))
- {
- cend = *p++;
- if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
- cend = *p++;
- if (cend == L('\0'))
- return (CHAR *)0;
- if (cend == L('[') && *p == L('.'))
- {
- p = PARSE_COLLSYM (p, &pc);
- /* An invalid collating symbol cannot be the second part of a
- range expression. If we get one, we set cend to one fewer
- than the test character to make sure the range test fails. */
- cend = (pc == INVALID) ? test - 1 : pc;
- forcecoll = 1;
- }
- cend = FOLD (cend);
-
- c = *p++;
-
- /* POSIX.2 2.8.3.2: ``The ending range point shall collate
- equal to or higher than the starting range point; otherwise
- the expression shall be treated as invalid.'' Note that this
- applies to only the range expression; the rest of the bracket
- expression is still checked for matches. */
- if (RANGECMP (cstart, cend, forcecoll) > 0)
- {
- if (c == L(']'))
- break;
- c = FOLD (c);
- continue;
- }
- }
-
- if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
- goto matched;
-
- if (c == L(']'))
- break;
- }
- /* No match. */
- return (!not ? (CHAR *)0 : p);
-
-matched:
- /* Skip the rest of the [...] that already matched. */
- c = *--p;
- brcnt = 1;
- while (brcnt > 0)
- {
- /* A `[' without a matching `]' is just another character to match. */
- if (c == L('\0'))
- return ((test == L('[')) ? savep : (CHAR *)0);
-
- c = *p++;
- if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
- brcnt++;
- else if (c == L(']'))
- brcnt--;
- else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
- {
- if (*p == '\0')
- return (CHAR *)0;
- /* XXX 1003.2d11 is unclear if this is right. */
- ++p;
- }
- }
- return (not ? (CHAR *)0 : p);
-}
-
-#if defined (EXTENDED_GLOB)
-/* ksh-like extended pattern matching:
-
- [?*+@!](pat-list)
-
- where pat-list is a list of one or patterns separated by `|'. Operation
- is as follows:
-
- ?(patlist) match zero or one of the given patterns
- *(patlist) match zero or more of the given patterns
- +(patlist) match one or more of the given patterns
- @(patlist) match exactly one of the given patterns
- !(patlist) match anything except one of the given patterns
-*/
-
-/* Scan a pattern starting at STRING and ending at END, keeping track of
- embedded () and []. If DELIM is 0, we scan until a matching `)'
- because we're scanning a `patlist'. Otherwise, we scan until we see
- DELIM. In all cases, we never scan past END. The return value is the
- first character after the matching DELIM. */
-/*static*/ CHAR *
-PATSCAN (string, end, delim)
- CHAR *string, *end;
- INT delim;
-{
- int pnest, bnest, skip;
- INT cchar;
- CHAR *s, c, *bfirst;
-
- pnest = bnest = skip = 0;
- cchar = 0;
- bfirst = NULL;
-
- for (s = string; c = *s; s++)
- {
- if (s >= end)
- return (s);
- if (skip)
- {
- skip = 0;
- continue;
- }
- switch (c)
- {
- case L('\\'):
- skip = 1;
- break;
-
- case L('\0'):
- return ((CHAR *)NULL);
-
- /* `[' is not special inside a bracket expression, but it may
- introduce one of the special POSIX bracket expressions
- ([.SYM.], [=c=], [: ... :]) that needs special handling. */
- case L('['):
- if (bnest == 0)
- {
- bfirst = s + 1;
- if (*bfirst == L('!') || *bfirst == L('^'))
- bfirst++;
- bnest++;
- }
- else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
- cchar = s[1];
- break;
-
- /* `]' is not special if it's the first char (after a leading `!'
- or `^') in a bracket expression or if it's part of one of the
- special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */
- case L(']'):
- if (bnest)
- {
- if (cchar && s[-1] == cchar)
- cchar = 0;
- else if (s != bfirst)
- {
- bnest--;
- bfirst = 0;
- }
- }
- break;
-
- case L('('):
- if (bnest == 0)
- pnest++;
- break;
-
- case L(')'):
- if (bnest == 0 && pnest-- <= 0)
- return ++s;
- break;
-
- case L('|'):
- if (bnest == 0 && pnest == 0 && delim == L('|'))
- return ++s;
- break;
- }
- }
-
- return (NULL);
-}
-
-/* Return 0 if dequoted pattern matches S in the current locale. */
-static int
-STRCOMPARE (p, pe, s, se)
- CHAR *p, *pe, *s, *se;
-{
- int ret;
- CHAR c1, c2;
-
- c1 = *pe;
- c2 = *se;
-
- *pe = *se = '\0';
-#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL)
- ret = STRCOLL ((XCHAR *)p, (XCHAR *)s);
-#else
- ret = STRCMP ((XCHAR *)p, (XCHAR *)s);
-#endif
-
- *pe = c1;
- *se = c2;
-
- return (ret == 0 ? ret : FNM_NOMATCH);
-}
-
-/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
- 0 on success. This is handed the entire rest of the pattern and string
- the first time an extended pattern specifier is encountered, so it calls
- gmatch recursively. */
-static int
-EXTMATCH (xc, s, se, p, pe, flags)
- INT xc; /* select which operation */
- CHAR *s, *se;
- CHAR *p, *pe;
- int flags;
-{
- CHAR *prest; /* pointer to rest of pattern */
- CHAR *psub; /* pointer to sub-pattern */
- CHAR *pnext; /* pointer to next sub-pattern */
- CHAR *srest; /* pointer to rest of string */
- int m1, m2, xflags; /* xflags = flags passed to recursive matches */
-
-#if DEBUG_MATCHING
-fprintf(stderr, "extmatch: xc = %c\n", xc);
-fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
-fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
-fprintf(stderr, "extmatch: flags = %d\n", flags);
-#endif
-
- prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
- if (prest == 0)
- /* If PREST is 0, we failed to scan a valid pattern. In this
- case, we just want to compare the two as strings. */
- return (STRCOMPARE (p - 1, pe, s, se));
-
- switch (xc)
- {
- case L('+'): /* match one or more occurrences */
- case L('*'): /* match zero or more occurrences */
- /* If we can get away with no matches, don't even bother. Just
- call GMATCH on the rest of the pattern and return success if
- it succeeds. */
- if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0))
- return 0;
-
- /* OK, we have to do this the hard way. First, we make sure one of
- the subpatterns matches, then we try to match the rest of the
- string. */
- for (psub = p + 1; ; psub = pnext)
- {
- pnext = PATSCAN (psub, pe, L('|'));
- for (srest = s; srest <= se; srest++)
- {
- /* Match this substring (S -> SREST) against this
- subpattern (psub -> pnext - 1) */
- m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0;
- /* OK, we matched a subpattern, so make sure the rest of the
- string matches the rest of the pattern. Also handle
- multiple matches of the pattern. */
- if (m1)
- {
- /* if srest > s, we are not at start of string */
- xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
- m2 = (GMATCH (srest, se, prest, pe, xflags) == 0) ||
- (s != srest && GMATCH (srest, se, p - 1, pe, xflags) == 0);
- }
- if (m1 && m2)
- return (0);
- }
- if (pnext == prest)
- break;
- }
- return (FNM_NOMATCH);
-
- case L('?'): /* match zero or one of the patterns */
- case L('@'): /* match one (or more) of the patterns */
- /* If we can get away with no matches, don't even bother. Just
- call gmatch on the rest of the pattern and return success if
- it succeeds. */
- if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0))
- return 0;
-
- /* OK, we have to do this the hard way. First, we see if one of
- the subpatterns matches, then, if it does, we try to match the
- rest of the string. */
- for (psub = p + 1; ; psub = pnext)
- {
- pnext = PATSCAN (psub, pe, L('|'));
- srest = (prest == pe) ? se : s;
- for ( ; srest <= se; srest++)
- {
- /* if srest > s, we are not at start of string */
- xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
- if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 &&
- GMATCH (srest, se, prest, pe, xflags) == 0)
- return (0);
- }
- if (pnext == prest)
- break;
- }
- return (FNM_NOMATCH);
-
- case '!': /* match anything *except* one of the patterns */
- for (srest = s; srest <= se; srest++)
- {
- m1 = 0;
- for (psub = p + 1; ; psub = pnext)
- {
- pnext = PATSCAN (psub, pe, L('|'));
- /* If one of the patterns matches, just bail immediately. */
- if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0))
- break;
- if (pnext == prest)
- break;
- }
- /* if srest > s, we are not at start of string */
- xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
- if (m1 == 0 && GMATCH (srest, se, prest, pe, xflags) == 0)
- return (0);
- }
- return (FNM_NOMATCH);
- }
-
- return (FNM_NOMATCH);
-}
-#endif /* EXTENDED_GLOB */
-
-#undef IS_CCLASS
-#undef FOLD
-#undef CHAR
-#undef U_CHAR
-#undef XCHAR
-#undef INT
-#undef INVALID
-#undef FCT
-#undef GMATCH
-#undef COLLSYM
-#undef PARSE_COLLSYM
-#undef PATSCAN
-#undef STRCOMPARE
-#undef EXTMATCH
-#undef BRACKMATCH
-#undef STRCHR
-#undef STRCOLL
-#undef STRLEN
-#undef STRCMP
-#undef COLLEQUIV
-#undef RANGECMP
-#undef L
+++ /dev/null
-/* `dir', `vdir' and `ls' directory listing programs for GNU.
-
- Modified by Chet Ramey for Readline.
-
- Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
-
-/* Written by Richard Stallman and David MacKenzie. */
-
-/* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
- Flaherty <dennisf@denix.elk.miles.com> based on original patches by
- Greg Lee <lee@uhunix.uhcc.hawaii.edu>. */
-
-#ifndef _COLORS_H_
-#define _COLORS_H_
-
-#include <stdio.h> // size_t
-
-#if defined (HAVE_STDBOOL_H)
-# include <stdbool.h> // bool
-#else
-typedef int _rl_bool_t;
-
-#ifdef bool
-# undef bool
-#endif
-#define bool _rl_bool_t
-
-#ifndef true
-# define true 1
-# define false 0
-#endif
-
-#endif /* !HAVE_STDBOOL_H */
-
-/* Null is a valid character in a color indicator (think about Epson
- printers, for example) so we have to use a length/buffer string
- type. */
-struct bin_str
- {
- size_t len;
- const char *string;
- };
-
-/* file type indicators (dir, sock, fifo, ...)
- Default value is initialized in parse-colors.c.
- It is then modified from the values of $LS_COLORS. */
-extern struct bin_str _rl_color_indicator[];
-
-/* The LS_COLORS variable is in a termcap-like format. */
-typedef struct _color_ext_type
- {
- struct bin_str ext; /* The extension we're looking for */
- struct bin_str seq; /* The sequence to output when we do */
- struct _color_ext_type *next; /* Next in list */
- } COLOR_EXT_TYPE;
-
-/* file extensions indicators (.txt, .log, .jpg, ...)
- Values are taken from $LS_COLORS in rl_parse_colors(). */
-extern COLOR_EXT_TYPE *_rl_color_ext_list;
-
-#define FILETYPE_INDICATORS \
- { \
- C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE, \
- C_LINK, C_SOCK, C_FILE, C_DIR \
- }
-
-/* Whether we used any colors in the output so far. If so, we will
- need to restore the default color later. If not, we will need to
- call prep_non_filename_text before using color for the first time. */
-
-enum indicator_no
- {
- C_LEFT, C_RIGHT, C_END, C_RESET, C_NORM, C_FILE, C_DIR, C_LINK,
- C_FIFO, C_SOCK,
- C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID,
- C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE, C_CAP, C_MULTIHARDLINK,
- C_CLR_TO_EOL
- };
-
-
-#if !S_IXUGO
-# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
-#endif
-
-enum filetype
- {
- unknown,
- fifo,
- chardev,
- directory,
- blockdev,
- normal,
- symbolic_link,
- sock,
- whiteout,
- arg_directory
- };
-
-extern void _rl_put_indicator (const struct bin_str *ind);
-extern void _rl_set_normal_color (void);
-extern bool _rl_print_color_indicator (char *f);
-extern void _rl_prep_non_filename_text (void);
-
-#endif /* !_COLORS_H_ */
+++ /dev/null
-/* complete.c -- filename completion for readline. */
-
-/* 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 <http://www.gnu.org/licenses/>.
-*/
-
-#define READLINE_LIBRARY
-
-#if defined (HAVE_CONFIG_H)
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <fcntl.h>
-#if defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif
-
-#include <signal.h>
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#if defined (HAVE_STDLIB_H)
-# include <stdlib.h>
-#else
-# include "ansi_stdlib.h"
-#endif /* HAVE_STDLIB_H */
-
-#include <stdio.h>
-
-#include <errno.h>
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-#if defined (HAVE_PWD_H)
-#include <pwd.h>
-#endif
-
-#include "posixdir.h"
-#include "posixstat.h"
-
-/* System-specific feature definitions and include files. */
-#include "rldefs.h"
-#include "rlmbutil.h"
-
-/* Some standard library routines. */
-#include "readline.h"
-#include "xmalloc.h"
-#include "rlprivate.h"
-
-#if defined (COLOR_SUPPORT)
-# include "colors.h"
-#endif
-
-#ifdef __STDC__
-typedef int QSFUNC (const void *, const void *);
-#else
-typedef int QSFUNC ();
-#endif
-
-#ifdef HAVE_LSTAT
-# define LSTAT lstat
-#else
-# define LSTAT stat
-#endif
-
-/* Unix version of a hidden file. Could be different on other systems. */
-#define HIDDEN_FILE(fname) ((fname)[0] == '.')
-
-/* Most systems don't declare getpwent in <pwd.h> if _POSIX_SOURCE is
- defined. */
-#if defined (HAVE_GETPWENT) && (!defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE))
-extern struct passwd *getpwent PARAMS((void));
-#endif /* HAVE_GETPWENT && (!HAVE_GETPW_DECLS || _POSIX_SOURCE) */
-
-/* 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. */
-rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)NULL;
-
-#if defined (VISIBLE_STATS) || defined (COLOR_SUPPORT)
-# if !defined (X_OK)
-# define X_OK 1
-# endif
-#endif
-
-#if defined (VISIBLE_STATS)
-static int stat_char PARAMS((char *));
-#endif
-
-#if defined (COLOR_SUPPORT)
-static int colored_stat_start PARAMS((char *));
-static void colored_stat_end PARAMS((void));
-#endif
-
-static int path_isdir PARAMS((const char *));
-
-static char *rl_quote_filename PARAMS((char *, int, char *));
-
-static void _rl_complete_sigcleanup PARAMS((int, void *));
-
-static void set_completion_defaults PARAMS((int));
-static int get_y_or_n PARAMS((int));
-static int _rl_internal_pager PARAMS((int));
-static char *printable_part PARAMS((char *));
-static int fnwidth PARAMS((const char *));
-static int fnprint PARAMS((const char *, int));
-static int print_filename PARAMS((char *, char *, int));
-
-static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int));
-
-static char **remove_duplicate_matches PARAMS((char **));
-static void insert_match PARAMS((char *, int, int, char *));
-static int append_to_match PARAMS((char *, int, int, int));
-static void insert_all_matches PARAMS((char **, int, char *));
-static int complete_fncmp PARAMS((const char *, int, const char *, int));
-static void display_matches PARAMS((char **));
-static int compute_lcd_of_matches PARAMS((char **, int, const char *));
-static int postprocess_matches PARAMS((char ***, int));
-static int complete_get_screenwidth PARAMS((void));
-
-static char *make_quoted_replacement PARAMS((char *, int, char *));
-
-/* **************************************************************** */
-/* */
-/* Completion matching, from readline's point of view. */
-/* */
-/* **************************************************************** */
-
-/* Variables known only to the readline library. */
-
-/* If non-zero, non-unique completions always show the list of matches. */
-int _rl_complete_show_all = 0;
-
-/* If non-zero, non-unique completions show the list of matches, unless it
- is not possible to do partial completion and modify the line. */
-int _rl_complete_show_unmodified = 0;
-
-/* If non-zero, completed directory names have a slash appended. */
-int _rl_complete_mark_directories = 1;
-
-/* If non-zero, the symlinked directory completion behavior introduced in
- readline-4.2a is disabled, and symlinks that point to directories have
- a slash appended (subject to the value of _rl_complete_mark_directories).
- This is user-settable via the mark-symlinked-directories variable. */
-int _rl_complete_mark_symlink_dirs = 0;
-
-/* If non-zero, completions are printed horizontally in alphabetical order,
- like `ls -x'. */
-int _rl_print_completions_horizontally;
-
-/* Non-zero means that case is not significant in filename completion. */
-#if defined (__MSDOS__) && !defined (__DJGPP__)
-int _rl_completion_case_fold = 1;
-#else
-int _rl_completion_case_fold = 0;
-#endif
-
-/* Non-zero means that `-' and `_' are equivalent when comparing filenames
- for completion. */
-int _rl_completion_case_map = 0;
-
-/* If zero, don't match hidden files (filenames beginning with a `.' on
- Unix) when doing filename completion. */
-int _rl_match_hidden_files = 1;
-
-/* Length in characters of a common prefix replaced with an ellipsis (`...')
- when displaying completion matches. Matches whose printable portion has
- more than this number of displaying characters in common will have the common
- display prefix replaced with an ellipsis. */
-int _rl_completion_prefix_display_length = 0;
-
-/* The readline-private number of screen columns to use when displaying
- matches. If < 0 or > _rl_screenwidth, it is ignored. */
-int _rl_completion_columns = -1;
-
-/* Global variables available to applications using readline. */
-
-#if defined (VISIBLE_STATS)
-/* Non-zero means add an additional character to each filename displayed
- during listing completion iff rl_filename_completion_desired which helps
- to indicate the type of file being listed. */
-int rl_visible_stats = 0;
-#endif /* VISIBLE_STATS */
-
-#if defined (COLOR_SUPPORT)
-/* Non-zero means to use colors to indicate file type when listing possible
- completions. The colors used are taken from $LS_COLORS, if set. */
-int _rl_colored_stats = 1;
-#endif
-
-/* If non-zero, when completing in the middle of a word, don't insert
- characters from the match that match characters following point in
- the word. This means, for instance, completing when the cursor is
- after the `e' in `Makefile' won't result in `Makefilefile'. */
-int _rl_skip_completed_text = 0;
-
-/* If non-zero, menu completion displays the common prefix first in the
- cycle of possible completions instead of the last. */
-int _rl_menu_complete_prefix_first = 0;
-
-/* 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. */
-rl_icppfunc_t *rl_directory_completion_hook = (rl_icppfunc_t *)NULL;
-
-rl_icppfunc_t *rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL;
-
-rl_icppfunc_t *rl_filename_stat_hook = (rl_icppfunc_t *)NULL;
-
-/* 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. */
-rl_dequote_func_t *rl_filename_rewrite_hook = (rl_dequote_func_t *)NULL;
-
-/* Non-zero means readline completion functions perform tilde expansion. */
-int rl_complete_with_tilde_expansion = 0;
-
-/* Pointer to the generator function for completion_matches ().
- NULL means to use rl_filename_completion_function (), the default filename
- completer. */
-rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL;
-
-/* Pointer to generator function for rl_menu_complete (). NULL means to use
- *rl_completion_entry_function (see above). */
-rl_compentry_func_t *rl_menu_completion_entry_function = (rl_compentry_func_t *)NULL;
-
-/* 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. */
-rl_completion_func_t *rl_attempted_completion_function = (rl_completion_func_t *)NULL;
-
-/* Non-zero means to suppress normal filename completion after the
- user-specified completion function has been called. */
-int rl_attempted_completion_over = 0;
-
-/* Set to a character indicating the type of completion being performed
- by rl_complete_internal, available for use by application completion
- functions. */
-int rl_completion_type = 0;
-
-/* 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. A negative value means
- don't ask. */
-int rl_completion_query_items = 100;
-
-int _rl_page_completions = 1;
-
-/* The basic list of characters that signal a break between words for the
- completer routine. The contents of this variable is what breaks words
- in the shell, i.e. " \t\n\"\\'`@$><=" */
-const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; /* }) */
-
-/* List of basic quoting characters. */
-const char *rl_basic_quote_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. */
-/*const*/ char *rl_completer_word_break_characters = (/*const*/ char *)NULL;
-
-/* 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. */
-rl_cpvfunc_t *rl_completion_word_break_hook = (rl_cpvfunc_t *)NULL;
-
-/* 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. */
-const char *rl_completer_quote_characters = (const char *)NULL;
-
-/* List of characters that should be quoted in filenames by the completer. */
-const char *rl_filename_quote_characters = (const char *)NULL;
-
-/* 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. */
-const char *rl_special_prefixes = (const char *)NULL;
-
-/* If non-zero, then disallow duplicates in the matches. */
-int rl_ignore_completion_duplicates = 1;
-
-/* 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. */
-int rl_filename_completion_desired = 0;
-
-/* 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_filename_quote_chars. This is
- ALWAYS non-zero on entry, and can only be changed within a completion
- entry finder function. */
-int rl_filename_quoting_desired = 1;
-
-/* This function, if defined, is called by the completer when real
- filename completion is done, after all the matching names have been
- generated. It is passed a (char**) known as matches in the code below.
- It consists of a NULL-terminated array of pointers to potential
- matching strings. The 1st element (matches[0]) is the maximal
- substring that is common to all matches. This function can re-arrange
- the list of matches as required, but all elements of the array must be
- free()'d if they are deleted. The main intent of this function is
- to implement FIGNORE a la SunOS csh. */
-rl_compignore_func_t *rl_ignore_some_completions_function = (rl_compignore_func_t *)NULL;
-
-/* 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. */
-rl_quote_func_t *rl_filename_quoting_function = rl_quote_filename;
-
-/* 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. Readline doesn't do anything
- with this; it's set only by applications. */
-rl_dequote_func_t *rl_filename_dequoting_function = (rl_dequote_func_t *)NULL;
-
-/* 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. */
-rl_linebuf_func_t *rl_char_is_quoted_p = (rl_linebuf_func_t *)NULL;
-
-/* If non-zero, the completion functions don't append anything except a
- possible closing quote. This is set to 0 by rl_complete_internal and
- may be changed by an application-specific completion function. */
-int rl_completion_suppress_append = 0;
-
-/* Character appended to completed words when at the end of the line. The
- default is a space. */
-int rl_completion_append_character = ' ';
-
-/* 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. */
-int rl_completion_suppress_quote = 0;
-
-/* Set to any quote character readline thinks it finds before any application
- completion function is called. */
-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. */
-int rl_completion_found_quote;
-
-/* 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. */
-int rl_completion_mark_symlink_dirs;
-
-/* If non-zero, inhibit completion (temporarily). */
-int rl_inhibit_completion;
-
-/* Set to the last key used to invoke one of the completion functions */
-int rl_completion_invoking_key;
-
-/* If non-zero, sort the completion matches. On by default. */
-int rl_sort_completion_matches = 1;
-
-/* Variables local to this file. */
-
-/* Local variable states what happened during the last completion attempt. */
-static int completion_changed_buffer;
-
-/* The result of the query to the user about displaying completion matches */
-static int completion_y_or_n;
-
-/*************************************/
-/* */
-/* Bindable completion functions */
-/* */
-/*************************************/
-
-/* Complete the word at or before point. You have supplied the function
- that does the initial simple matching selection algorithm (see
- rl_completion_matches ()). The default is to do filename completion. */
-int
-rl_complete (ignore, invoking_key)
- int ignore, invoking_key;
-{
- rl_completion_invoking_key = invoking_key;
-
- if (rl_inhibit_completion)
- return (_rl_insert_char (ignore, invoking_key));
- else if (rl_last_func == rl_complete && !completion_changed_buffer)
- return (rl_complete_internal ('?'));
- else if (_rl_complete_show_all)
- return (rl_complete_internal ('!'));
- else if (_rl_complete_show_unmodified)
- return (rl_complete_internal ('@'));
- else
- return (rl_complete_internal (TAB));
-}
-
-/* List the possible completions. See description of rl_complete (). */
-int
-rl_possible_completions (ignore, invoking_key)
- int ignore, invoking_key;
-{
- rl_completion_invoking_key = invoking_key;
- return (rl_complete_internal ('?'));
-}
-
-int
-rl_insert_completions (ignore, invoking_key)
- int ignore, invoking_key;
-{
- rl_completion_invoking_key = invoking_key;
- return (rl_complete_internal ('*'));
-}
-
-/* Return the correct value to pass to rl_complete_internal performing
- the same tests as rl_complete. This allows consecutive calls to an
- application's completion function to list possible completions and for
- an application-specific completion function to honor the
- show-all-if-ambiguous readline variable. */
-int
-rl_completion_mode (cfunc)
- rl_command_func_t *cfunc;
-{
- if (rl_last_func == cfunc && !completion_changed_buffer)
- return '?';
- else if (_rl_complete_show_all)
- return '!';
- else if (_rl_complete_show_unmodified)
- return '@';
- else
- return TAB;
-}
-
-/************************************/
-/* */
-/* Completion utility functions */
-/* */
-/************************************/
-
-/* Reset readline state on a signal or other event. */
-void
-_rl_reset_completion_state ()
-{
- rl_completion_found_quote = 0;
- rl_completion_quote_character = 0;
-}
-
-static void
-_rl_complete_sigcleanup (sig, ptr)
- int sig;
- void *ptr;
-{
- if (sig == SIGINT) /* XXX - for now */
- _rl_free_match_list ((char **)ptr);
-}
-
-/* Set default values for readline word completion. These are the variables
- that application completion functions can change or inspect. */
-static void
-set_completion_defaults (what_to_do)
- int what_to_do;
-{
- /* Only the completion entry function can change these. */
- rl_filename_completion_desired = 0;
- rl_filename_quoting_desired = 1;
- rl_completion_type = what_to_do;
- rl_completion_suppress_append = rl_completion_suppress_quote = 0;
- rl_completion_append_character = ' ';
-
- /* The completion entry function may optionally change this. */
- rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs;
-}
-
-/* The user must press "y" or "n". Non-zero return means "y" pressed. */
-static int
-get_y_or_n (for_pager)
- int for_pager;
-{
- int c;
-
- /* For now, disable pager in callback mode, until we later convert to state
- driven functions. Have to wait until next major version to add new
- state definition, since it will change value of RL_STATE_DONE. */
-#if defined (READLINE_CALLBACKS)
- if (RL_ISSTATE (RL_STATE_CALLBACK))
- return 1;
-#endif
-
- for (;;)
- {
- RL_SETSTATE(RL_STATE_MOREINPUT);
- c = rl_read_key ();
- RL_UNSETSTATE(RL_STATE_MOREINPUT);
-
- if (c == 'y' || c == 'Y' || c == ' ')
- return (1);
- if (c == 'n' || c == 'N' || c == RUBOUT)
- return (0);
- if (c == ABORT_CHAR || c < 0)
- _rl_abort_internal ();
- if (for_pager && (c == NEWLINE || c == RETURN))
- return (2);
- if (for_pager && (c == 'q' || c == 'Q'))
- return (0);
- rl_ding ();
- }
-}
-
-static int
-_rl_internal_pager (lines)
- int lines;
-{
- int i;
-
- fprintf (rl_outstream, "--More--");
- fflush (rl_outstream);
- i = get_y_or_n (1);
- _rl_erase_entire_line ();
- if (i == 0)
- return -1;
- else if (i == 2)
- return (lines - 1);
- else
- return 0;
-}
-
-static int
-path_isdir (filename)
- const char *filename;
-{
- struct stat finfo;
-
- return (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode));
-}
-
-#if defined (VISIBLE_STATS)
-/* Return the character which best describes FILENAME.
- `@' for symbolic links
- `/' for directories
- `*' for executables
- `=' for sockets
- `|' for FIFOs
- `%' for character special devices
- `#' for block special devices */
-static int
-stat_char (filename)
- char *filename;
-{
- struct stat finfo;
- int character, r;
- char *f;
- const char *fn;
-
- /* Short-circuit a //server on cygwin, since that will always behave as
- a directory. */
-#if __CYGWIN__
- if (filename[0] == '/' && filename[1] == '/' && strchr (filename+2, '/') == 0)
- return '/';
-#endif
-
- f = 0;
- if (rl_filename_stat_hook)
- {
- f = savestring (filename);
- (*rl_filename_stat_hook) (&f);
- fn = f;
- }
- else
- fn = filename;
-
-#if defined (HAVE_LSTAT) && defined (S_ISLNK)
- r = lstat (fn, &finfo);
-#else
- r = stat (fn, &finfo);
-#endif
-
- if (r == -1)
- return (0);
-
- character = 0;
- if (S_ISDIR (finfo.st_mode))
- character = '/';
-#if defined (S_ISCHR)
- else if (S_ISCHR (finfo.st_mode))
- character = '%';
-#endif /* S_ISCHR */
-#if defined (S_ISBLK)
- else if (S_ISBLK (finfo.st_mode))
- character = '#';
-#endif /* S_ISBLK */
-#if defined (S_ISLNK)
- else if (S_ISLNK (finfo.st_mode))
- character = '@';
-#endif /* S_ISLNK */
-#if defined (S_ISSOCK)
- else if (S_ISSOCK (finfo.st_mode))
- character = '=';
-#endif /* S_ISSOCK */
-#if defined (S_ISFIFO)
- else if (S_ISFIFO (finfo.st_mode))
- character = '|';
-#endif
- else if (S_ISREG (finfo.st_mode))
- {
- if (access (filename, X_OK) == 0)
- character = '*';
- }
-
- free (f);
- return (character);
-}
-#endif /* VISIBLE_STATS */
-
-#if defined (COLOR_SUPPORT)
-static int
-colored_stat_start (filename)
- char *filename;
-{
- _rl_set_normal_color ();
- return (_rl_print_color_indicator (filename));
-}
-
-static void
-colored_stat_end ()
-{
- _rl_prep_non_filename_text ();
- _rl_put_indicator (&_rl_color_indicator[C_CLR_TO_EOL]);
-}
-#endif
-
-/* Return the portion of PATHNAME that should be output when listing
- possible completions. If we are hacking filename completion, we
- are only interested in the basename, the portion following the
- final slash. Otherwise, we return what we were passed. Since
- printing empty strings is not very informative, if we're doing
- filename completion, and the basename is the empty string, we look
- for the previous slash and return the portion following that. If
- there's no previous slash, we just return what we were passed. */
-static char *
-printable_part (pathname)
- char *pathname;
-{
- char *temp, *x;
-
- if (rl_filename_completion_desired == 0) /* don't need to do anything */
- return (pathname);
-
- temp = strrchr (pathname, '/');
-#if defined (__MSDOS__)
- if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':')
- temp = pathname + 1;
-#endif
-
- if (temp == 0 || *temp == '\0')
- return (pathname);
- /* If the basename is NULL, we might have a pathname like '/usr/src/'.
- Look for a previous slash and, if one is found, return the portion
- following that slash. If there's no previous slash, just return the
- pathname we were passed. */
- else if (temp[1] == '\0')
- {
- for (x = temp - 1; x > pathname; x--)
- if (*x == '/')
- break;
- return ((*x == '/') ? x + 1 : pathname);
- }
- else
- return ++temp;
-}
-
-/* Compute width of STRING when displayed on screen by print_filename */
-static int
-fnwidth (string)
- const char *string;
-{
- int width, pos;
-#if defined (HANDLE_MULTIBYTE)
- mbstate_t ps;
- int left, w;
- size_t clen;
- wchar_t wc;
-
- left = strlen (string) + 1;
- memset (&ps, 0, sizeof (mbstate_t));
-#endif
-
- width = pos = 0;
- while (string[pos])
- {
- if (CTRL_CHAR (string[pos]) || string[pos] == RUBOUT)
- {
- width += 2;
- pos++;
- }
- else
- {
-#if defined (HANDLE_MULTIBYTE)
- clen = mbrtowc (&wc, string + pos, left - pos, &ps);
- if (MB_INVALIDCH (clen))
- {
- width++;
- pos++;
- memset (&ps, 0, sizeof (mbstate_t));
- }
- else if (MB_NULLWCH (clen))
- break;
- else
- {
- pos += clen;
- w = WCWIDTH (wc);
- width += (w >= 0) ? w : 1;
- }
-#else
- width++;
- pos++;
-#endif
- }
- }
-
- return width;
-}
-
-#define ELLIPSIS_LEN 3
-
-static int
-fnprint (to_print, prefix_bytes)
- const char *to_print;
- int prefix_bytes;
-{
- int printed_len, w;
- const char *s;
-#if defined (HANDLE_MULTIBYTE)
- mbstate_t ps;
- const char *end;
- size_t tlen;
- int width;
- wchar_t wc;
-
- end = to_print + strlen (to_print) + 1;
- memset (&ps, 0, sizeof (mbstate_t));
-#endif
-
- printed_len = 0;
-
- /* Don't print only the ellipsis if the common prefix is one of the
- possible completions */
- if (to_print[prefix_bytes] == '\0')
- prefix_bytes = 0;
-
- if (prefix_bytes)
- {
- char ellipsis;
-
- ellipsis = (to_print[prefix_bytes] == '.') ? '_' : '.';
- for (w = 0; w < ELLIPSIS_LEN; w++)
- putc (ellipsis, rl_outstream);
- printed_len = ELLIPSIS_LEN;
- }
-
- s = to_print + prefix_bytes;
- while (*s)
- {
- if (CTRL_CHAR (*s))
- {
- putc ('^', rl_outstream);
- putc (UNCTRL (*s), rl_outstream);
- printed_len += 2;
- s++;
-#if defined (HANDLE_MULTIBYTE)
- memset (&ps, 0, sizeof (mbstate_t));
-#endif
- }
- else if (*s == RUBOUT)
- {
- putc ('^', rl_outstream);
- putc ('?', rl_outstream);
- printed_len += 2;
- s++;
-#if defined (HANDLE_MULTIBYTE)
- memset (&ps, 0, sizeof (mbstate_t));
-#endif
- }
- else
- {
-#if defined (HANDLE_MULTIBYTE)
- tlen = mbrtowc (&wc, s, end - s, &ps);
- if (MB_INVALIDCH (tlen))
- {
- tlen = 1;
- width = 1;
- memset (&ps, 0, sizeof (mbstate_t));
- }
- else if (MB_NULLWCH (tlen))
- break;
- else
- {
- w = WCWIDTH (wc);
- width = (w >= 0) ? w : 1;
- }
- fwrite (s, 1, tlen, rl_outstream);
- s += tlen;
- printed_len += width;
-#else
- putc (*s, rl_outstream);
- s++;
- printed_len++;
-#endif
- }
- }
-
- return printed_len;
-}
-
-/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we
- are using it, check for and output a single character for `special'
- filenames. Return the number of characters we output. */
-
-static int
-print_filename (to_print, full_pathname, prefix_bytes)
- char *to_print, *full_pathname;
- int prefix_bytes;
-{
- int printed_len, extension_char, slen, tlen;
- char *s, c, *new_full_pathname, *dn;
-
- extension_char = 0;
-#if defined (COLOR_SUPPORT)
- /* Defer printing if we want to prefix with a color indicator */
- if (_rl_colored_stats == 0 || rl_filename_completion_desired == 0)
-#endif
- printed_len = fnprint (to_print, prefix_bytes);
-
- if (rl_filename_completion_desired && (
-#if defined (VISIBLE_STATS)
- rl_visible_stats ||
-#endif
-#if defined (COLOR_SUPPORT)
- _rl_colored_stats ||
-#endif
- _rl_complete_mark_directories))
- {
- /* If to_print != full_pathname, to_print is the basename of the
- path passed. In this case, we try to expand the directory
- name before checking for the stat character. */
- if (to_print != full_pathname)
- {
- /* Terminate the directory name. */
- c = to_print[-1];
- to_print[-1] = '\0';
-
- /* If setting the last slash in full_pathname to a NUL results in
- full_pathname being the empty string, we are trying to complete
- files in the root directory. If we pass a null string to the
- bash directory completion hook, for example, it will expand it
- to the current directory. We just want the `/'. */
- if (full_pathname == 0 || *full_pathname == 0)
- dn = "/";
- else if (full_pathname[0] != '/')
- dn = full_pathname;
- else if (full_pathname[1] == 0)
- dn = "//"; /* restore trailing slash to `//' */
- else if (full_pathname[1] == '/' && full_pathname[2] == 0)
- dn = "/"; /* don't turn /// into // */
- else
- dn = full_pathname;
- s = tilde_expand (dn);
- if (rl_directory_completion_hook)
- (*rl_directory_completion_hook) (&s);
-
- slen = strlen (s);
- tlen = strlen (to_print);
- new_full_pathname = (char *)xmalloc (slen + tlen + 2);
- strcpy (new_full_pathname, s);
- if (s[slen - 1] == '/')
- slen--;
- else
- new_full_pathname[slen] = '/';
- new_full_pathname[slen] = '/';
- strcpy (new_full_pathname + slen + 1, to_print);
-
-#if defined (VISIBLE_STATS)
- if (rl_visible_stats)
- extension_char = stat_char (new_full_pathname);
- else
-#endif
- if (_rl_complete_mark_directories)
- {
- dn = 0;
- if (rl_directory_completion_hook == 0 && rl_filename_stat_hook)
- {
- dn = savestring (new_full_pathname);
- (*rl_filename_stat_hook) (&dn);
- free (new_full_pathname);
- new_full_pathname = dn;
- }
- if (path_isdir (new_full_pathname))
- extension_char = '/';
- }
-
-#if defined (COLOR_SUPPORT)
- if (_rl_colored_stats)
- {
- colored_stat_start (new_full_pathname);
- printed_len = fnprint (to_print, prefix_bytes);
- colored_stat_end ();
- }
-#endif
-
- xfree (new_full_pathname);
- to_print[-1] = c;
- }
- else
- {
- s = tilde_expand (full_pathname);
-#if defined (VISIBLE_STATS)
- if (rl_visible_stats)
- extension_char = stat_char (s);
- else
-#endif
- if (_rl_complete_mark_directories && path_isdir (s))
- extension_char = '/';
-
-#if defined (COLOR_SUPPORT)
- if (_rl_colored_stats)
- {
- colored_stat_start (s);
- printed_len = fnprint (to_print, prefix_bytes);
- colored_stat_end ();
- }
-#endif
-
- }
-
- xfree (s);
- if (extension_char)
- {
- putc (extension_char, rl_outstream);
- printed_len++;
- }
- }
-
- return printed_len;
-}
-
-static char *
-rl_quote_filename (s, rtype, qcp)
- char *s;
- int rtype;
- char *qcp;
-{
- char *r;
-
- r = (char *)xmalloc (strlen (s) + 2);
- *r = *rl_completer_quote_characters;
- strcpy (r + 1, s);
- if (qcp)
- *qcp = *rl_completer_quote_characters;
- return r;
-}
-
-/* Find the bounds of the current word for completion purposes, and leave
- rl_point set to the end of the word. This function skips quoted
- substrings (characters between matched pairs of characters in
- rl_completer_quote_characters). First we try to find an unclosed
- quoted substring on which to do matching. If one is not found, we use
- the word break characters to find the boundaries of the current word.
- We call an application-specific function to decide whether or not a
- particular word break character is quoted; if that function returns a
- non-zero result, the character does not break a word. This function
- returns the opening quote character if we found an unclosed quoted
- substring, '\0' otherwise. FP, if non-null, is set to a value saying
- which (shell-like) quote characters we found (single quote, double
- quote, or backslash) anywhere in the string. DP, if non-null, is set to
- the value of the delimiter character that caused a word break. */
-
-char
-_rl_find_completion_word (fp, dp)
- int *fp, *dp;
-{
- int scan, end, found_quote, delimiter, pass_next, isbrk;
- char quote_char, *brkchars;
-
- end = rl_point;
- found_quote = delimiter = 0;
- quote_char = '\0';
-
- brkchars = 0;
- if (rl_completion_word_break_hook)
- brkchars = (*rl_completion_word_break_hook) ();
- if (brkchars == 0)
- brkchars = rl_completer_word_break_characters;
-
- if (rl_completer_quote_characters)
- {
- /* We have a list of characters which can be used in pairs to
- quote substrings for the completer. Try to find the start
- of an unclosed quoted substring. */
- /* FOUND_QUOTE is set so we know what kind of quotes we found. */
- for (scan = pass_next = 0; scan < end; scan = MB_NEXTCHAR (rl_line_buffer, scan, 1, MB_FIND_ANY))
- {
- if (pass_next)
- {
- pass_next = 0;
- continue;
- }
-
- /* Shell-like semantics for single quotes -- don't allow backslash
- to quote anything in single quotes, especially not the closing
- quote. If you don't like this, take out the check on the value
- of quote_char. */
- if (quote_char != '\'' && rl_line_buffer[scan] == '\\')
- {
- pass_next = 1;
- found_quote |= RL_QF_BACKSLASH;
- continue;
- }
-
- if (quote_char != '\0')
- {
- /* Ignore everything until the matching close quote char. */
- if (rl_line_buffer[scan] == quote_char)
- {
- /* Found matching close. Abandon this substring. */
- quote_char = '\0';
- rl_point = end;
- }
- }
- else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan]))
- {
- /* Found start of a quoted substring. */
- quote_char = rl_line_buffer[scan];
- rl_point = scan + 1;
- /* Shell-like quoting conventions. */
- if (quote_char == '\'')
- found_quote |= RL_QF_SINGLE_QUOTE;
- else if (quote_char == '"')
- found_quote |= RL_QF_DOUBLE_QUOTE;
- else
- found_quote |= RL_QF_OTHER_QUOTE;
- }
- }
- }
-
- if (rl_point == end && quote_char == '\0')
- {
- /* We didn't find an unclosed quoted substring upon which to do
- completion, so use the word break characters to find the
- substring on which to complete. */
- while (rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_ANY))
- {
- scan = rl_line_buffer[rl_point];
-
- if (strchr (brkchars, scan) == 0)
- continue;
-
- /* Call the application-specific function to tell us whether
- this word break character is quoted and should be skipped. */
- if (rl_char_is_quoted_p && found_quote &&
- (*rl_char_is_quoted_p) (rl_line_buffer, rl_point))
- continue;
-
- /* Convoluted code, but it avoids an n^2 algorithm with calls
- to char_is_quoted. */
- break;
- }
- }
-
- /* If we are at an unquoted word break, then advance past it. */
- scan = rl_line_buffer[rl_point];
-
- /* If there is an application-specific function to say whether or not
- a character is quoted and we found a quote character, let that
- function decide whether or not a character is a word break, even
- if it is found in rl_completer_word_break_characters. Don't bother
- if we're at the end of the line, though. */
- if (scan)
- {
- if (rl_char_is_quoted_p)
- isbrk = (found_quote == 0 ||
- (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) &&
- strchr (brkchars, scan) != 0;
- else
- isbrk = strchr (brkchars, scan) != 0;
-
- if (isbrk)
- {
- /* If the character that caused the word break was a quoting
- character, then remember it as the delimiter. */
- if (rl_basic_quote_characters &&
- strchr (rl_basic_quote_characters, scan) &&
- (end - rl_point) > 1)
- delimiter = scan;
-
- /* If the character isn't needed to determine something special
- about what kind of completion to perform, then advance past it. */
- if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0)
- rl_point++;
- }
- }
-
- if (fp)
- *fp = found_quote;
- if (dp)
- *dp = delimiter;
-
- return (quote_char);
-}
-
-static char **
-gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
- char *text;
- int start, end;
- rl_compentry_func_t *our_func;
- int found_quote, quote_char;
-{
- char **matches;
-
- rl_completion_found_quote = found_quote;
- rl_completion_quote_character = quote_char;
-
- /* If the user wants to TRY to complete, but then wants to give
- up and use the default completion function, they set the
- variable rl_attempted_completion_function. */
- if (rl_attempted_completion_function)
- {
- matches = (*rl_attempted_completion_function) (text, start, end);
- if (RL_SIG_RECEIVED())
- {
- _rl_free_match_list (matches);
- matches = 0;
- RL_CHECK_SIGNALS ();
- }
-
- if (matches || rl_attempted_completion_over)
- {
- rl_attempted_completion_over = 0;
- return (matches);
- }
- }
-
- /* XXX -- filename dequoting moved into rl_filename_completion_function */
-
- /* rl_completion_matches will check for signals as well to avoid a long
- delay while reading a directory. */
- matches = rl_completion_matches (text, our_func);
- if (RL_SIG_RECEIVED())
- {
- _rl_free_match_list (matches);
- matches = 0;
- RL_CHECK_SIGNALS ();
- }
- return matches;
-}
-
-/* Filter out duplicates in MATCHES. This frees up the strings in
- MATCHES. */
-static char **
-remove_duplicate_matches (matches)
- char **matches;
-{
- char *lowest_common;
- int i, j, newlen;
- char dead_slot;
- char **temp_array;
-
- /* Sort the items. */
- for (i = 0; matches[i]; i++)
- ;
-
- /* Sort the array without matches[0], since we need it to
- stay in place no matter what. */
- if (i && rl_sort_completion_matches)
- qsort (matches+1, i-1, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare);
-
- /* Remember the lowest common denominator for it may be unique. */
- lowest_common = savestring (matches[0]);
-
- for (i = newlen = 0; matches[i + 1]; i++)
- {
- if (strcmp (matches[i], matches[i + 1]) == 0)
- {
- xfree (matches[i]);
- matches[i] = (char *)&dead_slot;
- }
- else
- newlen++;
- }
-
- /* We have marked all the dead slots with (char *)&dead_slot.
- Copy all the non-dead entries into a new array. */
- temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *));
- for (i = j = 1; matches[i]; i++)
- {
- if (matches[i] != (char *)&dead_slot)
- temp_array[j++] = matches[i];
- }
- temp_array[j] = (char *)NULL;
-
- if (matches[0] != (char *)&dead_slot)
- xfree (matches[0]);
-
- /* Place the lowest common denominator back in [0]. */
- temp_array[0] = lowest_common;
-
- /* If there is one string left, and it is identical to the
- lowest common denominator, then the LCD is the string to
- insert. */
- if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0)
- {
- xfree (temp_array[1]);
- temp_array[1] = (char *)NULL;
- }
- return (temp_array);
-}
-
-/* Find the common prefix of the list of matches, and put it into
- matches[0]. */
-static int
-compute_lcd_of_matches (match_list, matches, text)
- char **match_list;
- int matches;
- const char *text;
-{
- register int i, c1, c2, si;
- int low; /* Count of max-matched characters. */
- int lx;
- char *dtext; /* dequoted TEXT, if needed */
-#if defined (HANDLE_MULTIBYTE)
- int v;
- size_t v1, v2;
- mbstate_t ps1, ps2;
- wchar_t wc1, wc2;
-#endif
-
- /* If only one match, just use that. Otherwise, compare each
- member of the list with the next, finding out where they
- stop matching. */
- if (matches == 1)
- {
- match_list[0] = match_list[1];
- match_list[1] = (char *)NULL;
- return 1;
- }
-
- for (i = 1, low = 100000; i < matches; i++)
- {
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- memset (&ps1, 0, sizeof (mbstate_t));
- memset (&ps2, 0, sizeof (mbstate_t));
- }
-#endif
- if (_rl_completion_case_fold)
- {
- for (si = 0;
- (c1 = _rl_to_lower(match_list[i][si])) &&
- (c2 = _rl_to_lower(match_list[i + 1][si]));
- si++)
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- v1 = mbrtowc(&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1);
- v2 = mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2);
- if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
- {
- if (c1 != c2) /* do byte comparison */
- break;
- continue;
- }
- wc1 = towlower (wc1);
- wc2 = towlower (wc2);
- if (wc1 != wc2)
- break;
- else if (v1 > 1)
- si += v1 - 1;
- }
- else
-#endif
- if (c1 != c2)
- break;
- }
- else
- {
- for (si = 0;
- (c1 = match_list[i][si]) &&
- (c2 = match_list[i + 1][si]);
- si++)
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- mbstate_t ps_back;
- ps_back = ps1;
- if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2))
- break;
- else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1)
- si += v - 1;
- }
- else
-#endif
- if (c1 != c2)
- break;
- }
-
- if (low > si)
- low = si;
- }
-
- /* If there were multiple matches, but none matched up to even the
- first character, and the user typed something, use that as the
- value of matches[0]. */
- if (low == 0 && text && *text)
- {
- match_list[0] = (char *)xmalloc (strlen (text) + 1);
- strcpy (match_list[0], text);
- }
- else
- {
- match_list[0] = (char *)xmalloc (low + 1);
-
- /* XXX - this might need changes in the presence of multibyte chars */
-
- /* If we are ignoring case, try to preserve the case of the string
- the user typed in the face of multiple matches differing in case. */
- if (_rl_completion_case_fold)
- {
- /* We're making an assumption here:
- IF we're completing filenames AND
- the application has defined a filename dequoting function AND
- we found a quote character AND
- the application has requested filename quoting
- THEN
- we assume that TEXT was dequoted before checking against
- the file system and needs to be dequoted here before we
- check against the list of matches
- FI */
- dtext = (char *)NULL;
- if (rl_filename_completion_desired &&
- rl_filename_dequoting_function &&
- rl_completion_found_quote &&
- rl_filename_quoting_desired)
- {
- dtext = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
- text = dtext;
- }
-
- /* sort the list to get consistent answers. */
- qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
-
- si = strlen (text);
- lx = (si <= low) ? si : low; /* check shorter of text and matches */
- /* Try to preserve the case of what the user typed in the presence of
- multiple matches: check each match for something that matches
- what the user typed taking case into account; use it up to common
- length of matches if one is found. If not, just use first match. */
- for (i = 1; i <= matches; i++)
- if (strncmp (match_list[i], text, lx) == 0)
- {
- strncpy (match_list[0], match_list[i], low);
- break;
- }
- /* no casematch, use first entry */
- if (i > matches)
- strncpy (match_list[0], match_list[1], low);
-
- FREE (dtext);
- }
- else
- strncpy (match_list[0], match_list[1], low);
-
- match_list[0][low] = '\0';
- }
-
- return matches;
-}
-
-static int
-postprocess_matches (matchesp, matching_filenames)
- char ***matchesp;
- int matching_filenames;
-{
- char *t, **matches, **temp_matches;
- int nmatch, i;
-
- matches = *matchesp;
-
- if (matches == 0)
- return 0;
-
- /* It seems to me that in all the cases we handle we would like
- to ignore duplicate possiblilities. Scan for the text to
- insert being identical to the other completions. */
- if (rl_ignore_completion_duplicates)
- {
- temp_matches = remove_duplicate_matches (matches);
- xfree (matches);
- matches = temp_matches;
- }
-
- /* If we are matching filenames, then here is our chance to
- do clever processing by re-examining the list. Call the
- ignore function with the array as a parameter. It can
- munge the array, deleting matches as it desires. */
- if (rl_ignore_some_completions_function && matching_filenames)
- {
- for (nmatch = 1; matches[nmatch]; nmatch++)
- ;
- (void)(*rl_ignore_some_completions_function) (matches);
- if (matches == 0 || matches[0] == 0)
- {
- FREE (matches);
- *matchesp = (char **)0;
- return 0;
- }
- else
- {
- /* If we removed some matches, recompute the common prefix. */
- for (i = 1; matches[i]; i++)
- ;
- if (i > 1 && i < nmatch)
- {
- t = matches[0];
- compute_lcd_of_matches (matches, i - 1, t);
- FREE (t);
- }
- }
- }
-
- *matchesp = matches;
- return (1);
-}
-
-static int
-complete_get_screenwidth ()
-{
- int cols;
- char *envcols;
-
- cols = _rl_completion_columns;
- if (cols >= 0 && cols <= _rl_screenwidth)
- return cols;
- envcols = getenv ("COLUMNS");
- if (envcols && *envcols)
- cols = atoi (envcols);
- if (cols >= 0 && cols <= _rl_screenwidth)
- return cols;
- return _rl_screenwidth;
-}
-
-/* A convenience function for displaying a list of strings in
- columnar format on readline's output stream. MATCHES is the list
- of strings, in argv format, LEN is the number of strings in MATCHES,
- and MAX is the length of the longest string in MATCHES. */
-void
-rl_display_match_list (matches, len, max)
- char **matches;
- int len, max;
-{
- int count, limit, printed_len, lines, cols;
- int i, j, k, l, common_length, sind;
- char *temp, *t;
-
- /* Find the length of the prefix common to all items: length as displayed
- characters (common_length) and as a byte index into the matches (sind) */
- common_length = sind = 0;
- if (_rl_completion_prefix_display_length > 0)
- {
- t = printable_part (matches[0]);
- temp = strrchr (t, '/');
- common_length = temp ? fnwidth (temp) : fnwidth (t);
- sind = temp ? strlen (temp) : strlen (t);
-
- if (common_length > _rl_completion_prefix_display_length && common_length > ELLIPSIS_LEN)
- max -= common_length - ELLIPSIS_LEN;
- else
- common_length = sind = 0;
- }
-
- /* How many items of MAX length can we fit in the screen window? */
- cols = complete_get_screenwidth ();
- max += 2;
- limit = cols / max;
- if (limit != 1 && (limit * max == cols))
- limit--;
-
- /* If cols == 0, limit will end up -1 */
- if (cols < _rl_screenwidth && limit < 0)
- limit = 1;
-
- /* Avoid a possible floating exception. If max > cols,
- limit will be 0 and a divide-by-zero fault will result. */
- if (limit == 0)
- limit = 1;
-
- /* How many iterations of the printing loop? */
- count = (len + (limit - 1)) / limit;
-
- /* Watch out for special case. If LEN is less than LIMIT, then
- just do the inner printing loop.
- 0 < len <= limit implies count = 1. */
-
- /* Sort the items if they are not already sorted. */
- if (rl_ignore_completion_duplicates == 0 && rl_sort_completion_matches)
- qsort (matches + 1, len, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare);
-
- rl_crlf ();
-
- lines = 0;
- if (_rl_print_completions_horizontally == 0)
- {
- /* Print the sorted items, up-and-down alphabetically, like ls. */
- for (i = 1; i <= count; i++)
- {
- for (j = 0, l = i; j < limit; j++)
- {
- if (l > len || matches[l] == 0)
- break;
- else
- {
- temp = printable_part (matches[l]);
- printed_len = print_filename (temp, matches[l], sind);
-
- if (j + 1 < limit)
- for (k = 0; k < max - printed_len; k++)
- putc (' ', rl_outstream);
- }
- l += count;
- }
- rl_crlf ();
- lines++;
- if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count)
- {
- lines = _rl_internal_pager (lines);
- if (lines < 0)
- return;
- }
- }
- }
- else
- {
- /* Print the sorted items, across alphabetically, like ls -x. */
- for (i = 1; matches[i]; i++)
- {
- temp = printable_part (matches[i]);
- printed_len = print_filename (temp, matches[i], sind);
- /* Have we reached the end of this line? */
- if (matches[i+1])
- {
- if (i && (limit > 1) && (i % limit) == 0)
- {
- rl_crlf ();
- lines++;
- if (_rl_page_completions && lines >= _rl_screenheight - 1)
- {
- lines = _rl_internal_pager (lines);
- if (lines < 0)
- return;
- }
- }
- else
- for (k = 0; k < max - printed_len; k++)
- putc (' ', rl_outstream);
- }
- }
- rl_crlf ();
- }
-}
-
-/* Display MATCHES, a list of matching filenames in argv format. This
- handles the simple case -- a single match -- first. If there is more
- than one match, we compute the number of strings in the list and the
- length of the longest string, which will be needed by the display
- function. If the application wants to handle displaying the list of
- matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the
- address of a function, and we just call it. If we're handling the
- display ourselves, we just call rl_display_match_list. We also check
- that the list of matches doesn't exceed the user-settable threshold,
- and ask the user if he wants to see the list if there are more matches
- than RL_COMPLETION_QUERY_ITEMS. */
-static void
-display_matches (matches)
- char **matches;
-{
- int len, max, i;
- char *temp;
-
- /* Move to the last visible line of a possibly-multiple-line command. */
- _rl_move_vert (_rl_vis_botlin);
-
- /* Handle simple case first. What if there is only one answer? */
- if (matches[1] == 0)
- {
- temp = printable_part (matches[0]);
- rl_crlf ();
- print_filename (temp, matches[0], 0);
- rl_crlf ();
-
- rl_forced_update_display ();
- rl_display_fixed = 1;
-
- return;
- }
-
- /* There is more than one answer. Find out how many there are,
- and find the maximum printed length of a single entry. */
- for (max = 0, i = 1; matches[i]; i++)
- {
- temp = printable_part (matches[i]);
- len = fnwidth (temp);
-
- if (len > max)
- max = len;
- }
-
- len = i - 1;
-
- /* If the caller has defined a display hook, then call that now. */
- if (rl_completion_display_matches_hook)
- {
- (*rl_completion_display_matches_hook) (matches, len, max);
- return;
- }
-
- /* If there are many items, then ask the user if she really wants to
- see them all. */
- if (rl_completion_query_items > 0 && len >= rl_completion_query_items)
- {
- rl_crlf ();
- fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
- fflush (rl_outstream);
- if ((completion_y_or_n = get_y_or_n (0)) == 0)
- {
- rl_crlf ();
-
- rl_forced_update_display ();
- rl_display_fixed = 1;
-
- return;
- }
- }
-
- rl_display_match_list (matches, len, max);
-
- rl_forced_update_display ();
- rl_display_fixed = 1;
-}
-
-static char *
-make_quoted_replacement (match, mtype, qc)
- char *match;
- int mtype;
- char *qc; /* Pointer to quoting character, if any */
-{
- int should_quote, do_replace;
- char *replacement;
-
- /* If we are doing completion on quoted substrings, and any matches
- contain any of the completer_word_break_characters, then auto-
- matically prepend the substring with a quote character (just pick
- the first one from the list of such) if it does not already begin
- with a quote string. FIXME: Need to remove any such automatically
- inserted quote character when it no longer is necessary, such as
- if we change the string we are completing on and the new set of
- matches don't require a quoted substring. */
- replacement = match;
-
- should_quote = match && rl_completer_quote_characters &&
- rl_filename_completion_desired &&
- rl_filename_quoting_desired;
-
- if (should_quote)
- should_quote = should_quote && (!qc || !*qc ||
- (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc)));
-
- if (should_quote)
- {
- /* If there is a single match, see if we need to quote it.
- This also checks whether the common prefix of several
- matches needs to be quoted. */
- should_quote = rl_filename_quote_characters
- ? (_rl_strpbrk (match, rl_filename_quote_characters) != 0)
- : 0;
-
- do_replace = should_quote ? mtype : NO_MATCH;
- /* Quote the replacement, since we found an embedded
- word break character in a potential match. */
- if (do_replace != NO_MATCH && rl_filename_quoting_function)
- replacement = (*rl_filename_quoting_function) (match, do_replace, qc);
- }
- return (replacement);
-}
-
-static void
-insert_match (match, start, mtype, qc)
- char *match;
- int start, mtype;
- char *qc;
-{
- char *replacement, *r;
- char oqc;
- int end, rlen;
-
- oqc = qc ? *qc : '\0';
- replacement = make_quoted_replacement (match, mtype, qc);
-
- /* Now insert the match. */
- if (replacement)
- {
- rlen = strlen (replacement);
- /* Don't double an opening quote character. */
- if (qc && *qc && start && rl_line_buffer[start - 1] == *qc &&
- replacement[0] == *qc)
- start--;
- /* If make_quoted_replacement changed the quoting character, remove
- the opening quote and insert the (fully-quoted) replacement. */
- else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc &&
- replacement[0] != oqc)
- start--;
- end = rl_point - 1;
- /* Don't double a closing quote character */
- if (qc && *qc && end && rl_line_buffer[rl_point] == *qc && replacement[rlen - 1] == *qc)
- end++;
- if (_rl_skip_completed_text)
- {
- r = replacement;
- while (start < rl_end && *r && rl_line_buffer[start] == *r)
- {
- start++;
- r++;
- }
- if (start <= end || *r)
- _rl_replace_text (r, start, end);
- rl_point = start + strlen (r);
- }
- else
- _rl_replace_text (replacement, start, end);
- if (replacement != match)
- xfree (replacement);
- }
-}
-
-/* Append any necessary closing quote and a separator character to the
- just-inserted match. If the user has specified that directories
- should be marked by a trailing `/', append one of those instead. The
- default trailing character is a space. Returns the number of characters
- appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS
- has them) and don't add a suffix for a symlink to a directory. A
- nontrivial match is one that actually adds to the word being completed.
- The variable rl_completion_mark_symlink_dirs controls this behavior
- (it's initially set to the what the user has chosen, indicated by the
- value of _rl_complete_mark_symlink_dirs, but may be modified by an
- application's completion function). */
-static int
-append_to_match (text, delimiter, quote_char, nontrivial_match)
- char *text;
- int delimiter, quote_char, nontrivial_match;
-{
- char temp_string[4], *filename, *fn;
- int temp_string_index, s;
- struct stat finfo;
-
- temp_string_index = 0;
- if (quote_char && rl_point && rl_completion_suppress_quote == 0 &&
- rl_line_buffer[rl_point - 1] != quote_char)
- temp_string[temp_string_index++] = quote_char;
-
- if (delimiter)
- temp_string[temp_string_index++] = delimiter;
- else if (rl_completion_suppress_append == 0 && rl_completion_append_character)
- temp_string[temp_string_index++] = rl_completion_append_character;
-
- temp_string[temp_string_index++] = '\0';
-
- if (rl_filename_completion_desired)
- {
- filename = tilde_expand (text);
- if (rl_filename_stat_hook)
- {
- fn = savestring (filename);
- (*rl_filename_stat_hook) (&fn);
- xfree (filename);
- filename = fn;
- }
- s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0)
- ? LSTAT (filename, &finfo)
- : stat (filename, &finfo);
- if (s == 0 && S_ISDIR (finfo.st_mode))
- {
- if (_rl_complete_mark_directories /* && rl_completion_suppress_append == 0 */)
- {
- /* This is clumsy. Avoid putting in a double slash if point
- is at the end of the line and the previous character is a
- slash. */
- if (rl_point && rl_line_buffer[rl_point] == '\0' && rl_line_buffer[rl_point - 1] == '/')
- ;
- else if (rl_line_buffer[rl_point] != '/')
- rl_insert_text ("/");
- }
- }
-#ifdef S_ISLNK
- /* Don't add anything if the filename is a symlink and resolves to a
- directory. */
- else if (s == 0 && S_ISLNK (finfo.st_mode) && path_isdir (filename))
- ;
-#endif
- else
- {
- if (rl_point == rl_end && temp_string_index)
- rl_insert_text (temp_string);
- }
- xfree (filename);
- }
- else
- {
- if (rl_point == rl_end && temp_string_index)
- rl_insert_text (temp_string);
- }
-
- return (temp_string_index);
-}
-
-static void
-insert_all_matches (matches, point, qc)
- char **matches;
- int point;
- char *qc;
-{
- int i;
- char *rp;
-
- rl_begin_undo_group ();
- /* remove any opening quote character; make_quoted_replacement will add
- it back. */
- if (qc && *qc && point && rl_line_buffer[point - 1] == *qc)
- point--;
- rl_delete_text (point, rl_point);
- rl_point = point;
-
- if (matches[1])
- {
- for (i = 1; matches[i]; i++)
- {
- rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc);
- rl_insert_text (rp);
- rl_insert_text (" ");
- if (rp != matches[i])
- xfree (rp);
- }
- }
- else
- {
- rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc);
- rl_insert_text (rp);
- rl_insert_text (" ");
- if (rp != matches[0])
- xfree (rp);
- }
- rl_end_undo_group ();
-}
-
-void
-_rl_free_match_list (matches)
- char **matches;
-{
- register int i;
-
- if (matches == 0)
- return;
-
- for (i = 0; matches[i]; i++)
- xfree (matches[i]);
- xfree (matches);
-}
-
-/* Complete the word at or before point.
- WHAT_TO_DO says what to do with the completion.
- `?' means list the possible completions.
- TAB means do standard completion.
- `*' means insert all of the possible completions.
- `!' means to do standard completion, and list all possible completions if
- there is more than one.
- `@' means to do standard completion, and list all possible completions if
- there is more than one and partial completion is not possible. */
-int
-rl_complete_internal (what_to_do)
- int what_to_do;
-{
- char **matches;
- rl_compentry_func_t *our_func;
- int start, end, delimiter, found_quote, i, nontrivial_lcd;
- char *text, *saved_line_buffer;
- char quote_char;
-#if 1
- int tlen, mlen;
-#endif
-
- RL_SETSTATE(RL_STATE_COMPLETING);
-
- set_completion_defaults (what_to_do);
-
- saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL;
- our_func = rl_completion_entry_function
- ? rl_completion_entry_function
- : rl_filename_completion_function;
- /* We now look backwards for the start of a filename/variable word. */
- end = rl_point;
- found_quote = delimiter = 0;
- quote_char = '\0';
-
- if (rl_point)
- /* This (possibly) changes rl_point. If it returns a non-zero char,
- we know we have an open quote. */
- quote_char = _rl_find_completion_word (&found_quote, &delimiter);
-
- start = rl_point;
- rl_point = end;
-
- text = rl_copy_text (start, end);
- matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char);
- /* nontrivial_lcd is set if the common prefix adds something to the word
- being completed. */
- nontrivial_lcd = matches && strcmp (text, matches[0]) != 0;
- if (what_to_do == '!' || what_to_do == '@')
- tlen = strlen (text);
- xfree (text);
-
- if (matches == 0)
- {
- rl_ding ();
- FREE (saved_line_buffer);
- completion_changed_buffer = 0;
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- _rl_reset_completion_state ();
- return (0);
- }
-
- /* If we are matching filenames, the attempted completion function will
- have set rl_filename_completion_desired to a non-zero value. The basic
- rl_filename_completion_function does this. */
- i = rl_filename_completion_desired;
-
- if (postprocess_matches (&matches, i) == 0)
- {
- rl_ding ();
- FREE (saved_line_buffer);
- completion_changed_buffer = 0;
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- _rl_reset_completion_state ();
- return (0);
- }
-
- switch (what_to_do)
- {
- case TAB:
- case '!':
- case '@':
- /* Insert the first match with proper quoting. */
- if (what_to_do == TAB)
- {
- if (*matches[0])
- insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
- }
- else if (*matches[0] && matches[1] == 0)
- /* should we perform the check only if there are multiple matches? */
- insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
- else if (*matches[0]) /* what_to_do != TAB && multiple matches */
- {
- mlen = *matches[0] ? strlen (matches[0]) : 0;
- if (mlen >= tlen)
- insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
- }
-
- /* If there are more matches, ring the bell to indicate.
- If we are in vi mode, Posix.2 says to not ring the bell.
- If the `show-all-if-ambiguous' variable is set, display
- all the matches immediately. Otherwise, if this was the
- only match, and we are hacking files, check the file to
- see if it was a directory. If so, and the `mark-directories'
- variable is set, add a '/' to the name. If not, and we
- are at the end of the line, then add a space. */
- if (matches[1])
- {
- if (what_to_do == '!')
- {
- display_matches (matches);
- break;
- }
- else if (what_to_do == '@')
- {
- if (nontrivial_lcd == 0)
- display_matches (matches);
- break;
- }
- else if (rl_editing_mode != vi_mode)
- rl_ding (); /* There are other matches remaining. */
- }
- else
- append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
-
- break;
-
- case '*':
- insert_all_matches (matches, start, "e_char);
- break;
-
- case '?':
- if (rl_completion_display_matches_hook == 0)
- {
- _rl_sigcleanup = _rl_complete_sigcleanup;
- _rl_sigcleanarg = matches;
- }
- display_matches (matches);
- _rl_sigcleanup = 0;
- _rl_sigcleanarg = 0;
- break;
-
- default:
- _rl_ttymsg ("bad value %d for what_to_do in rl_complete", what_to_do);
- rl_ding ();
- FREE (saved_line_buffer);
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- _rl_free_match_list (matches);
- _rl_reset_completion_state ();
- return 1;
- }
-
- _rl_free_match_list (matches);
-
- /* Check to see if the line has changed through all of this manipulation. */
- if (saved_line_buffer)
- {
- completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0;
- xfree (saved_line_buffer);
- }
-
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- _rl_reset_completion_state ();
- return 0;
-}
-
-/***************************************************************/
-/* */
-/* Application-callable completion match generator functions */
-/* */
-/***************************************************************/
-
-/* Return an array of (char *) which is a list of completions for TEXT.
- If there are no completions, return a NULL pointer.
- The first entry in the returned array is the substitution for TEXT.
- The remaining entries are the possible completions.
- The array is terminated with a NULL pointer.
-
- ENTRY_FUNCTION is a function of two args, and returns a (char *).
- The first argument is TEXT.
- The second is a state argument; it should be zero on the first call, and
- non-zero on subsequent calls. It returns a NULL pointer to the caller
- when there are no more matches.
- */
-char **
-rl_completion_matches (text, entry_function)
- const char *text;
- rl_compentry_func_t *entry_function;
-{
- register int i;
-
- /* Number of slots in match_list. */
- int match_list_size;
-
- /* The list of matches. */
- char **match_list;
-
- /* Number of matches actually found. */
- int matches;
-
- /* Temporary string binder. */
- char *string;
-
- matches = 0;
- match_list_size = 10;
- match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *));
- match_list[1] = (char *)NULL;
-
- while (string = (*entry_function) (text, matches))
- {
- if (RL_SIG_RECEIVED ())
- {
- /* Start at 1 because we don't set matches[0] in this function.
- Only free the list members if we're building match list from
- rl_filename_completion_function, since we know that doesn't
- free the strings it returns. */
- if (entry_function == rl_filename_completion_function)
- {
- for (i = 1; match_list[i]; i++)
- xfree (match_list[i]);
- }
- xfree (match_list);
- match_list = 0;
- match_list_size = 0;
- RL_CHECK_SIGNALS ();
- }
-
- if (matches + 1 == match_list_size)
- match_list = (char **)xrealloc
- (match_list, ((match_list_size += 10) + 1) * sizeof (char *));
-
- match_list[++matches] = string;
- match_list[matches + 1] = (char *)NULL;
- }
-
- /* If there were any matches, then look through them finding out the
- lowest common denominator. That then becomes match_list[0]. */
- if (matches)
- compute_lcd_of_matches (match_list, matches, text);
- else /* There were no matches. */
- {
- xfree (match_list);
- match_list = (char **)NULL;
- }
- return (match_list);
-}
-
-/* A completion function for usernames.
- TEXT contains a partial username preceded by a random
- character (usually `~'). */
-char *
-rl_username_completion_function (text, state)
- const char *text;
- int state;
-{
-#if defined (__WIN32__) || defined (__OPENNT)
- return (char *)NULL;
-#else /* !__WIN32__ && !__OPENNT) */
- static char *username = (char *)NULL;
- static struct passwd *entry;
- static int namelen, first_char, first_char_loc;
- char *value;
-
- if (state == 0)
- {
- FREE (username);
-
- first_char = *text;
- first_char_loc = first_char == '~';
-
- username = savestring (&text[first_char_loc]);
- namelen = strlen (username);
- setpwent ();
- }
-
-#if defined (HAVE_GETPWENT)
- while (entry = getpwent ())
- {
- /* Null usernames should result in all users as possible completions. */
- if (namelen == 0 || (STREQN (username, entry->pw_name, namelen)))
- break;
- }
-#endif
-
- if (entry == 0)
- {
-#if defined (HAVE_GETPWENT)
- endpwent ();
-#endif
- return ((char *)NULL);
- }
- else
- {
- value = (char *)xmalloc (2 + strlen (entry->pw_name));
-
- *value = *text;
-
- strcpy (value + first_char_loc, entry->pw_name);
-
- if (first_char == '~')
- rl_filename_completion_desired = 1;
-
- return (value);
- }
-#endif /* !__WIN32__ && !__OPENNT */
-}
-
-/* Return non-zero if CONVFN matches FILENAME up to the length of FILENAME
- (FILENAME_LEN). If _rl_completion_case_fold is set, compare without
- regard to the alphabetic case of characters. If
- _rl_completion_case_map is set, make `-' and `_' equivalent. CONVFN is
- the possibly-converted directory entry; FILENAME is what the user typed. */
-static int
-complete_fncmp (convfn, convlen, filename, filename_len)
- const char *convfn;
- int convlen;
- const char *filename;
- int filename_len;
-{
- register char *s1, *s2;
- int d, len;
-#if defined (HANDLE_MULTIBYTE)
- size_t v1, v2;
- mbstate_t ps1, ps2;
- wchar_t wc1, wc2;
-#endif
-
-#if defined (HANDLE_MULTIBYTE)
- memset (&ps1, 0, sizeof (mbstate_t));
- memset (&ps2, 0, sizeof (mbstate_t));
-#endif
-
- if (filename_len == 0)
- return 1;
- if (convlen < filename_len)
- return 0;
-
- len = filename_len;
- s1 = (char *)convfn;
- s2 = (char *)filename;
-
- /* Otherwise, if these match up to the length of filename, then
- it is a match. */
- if (_rl_completion_case_fold && _rl_completion_case_map)
- {
- /* Case-insensitive comparison treating _ and - as equivalent */
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- do
- {
- v1 = mbrtowc (&wc1, s1, convlen, &ps1);
- v2 = mbrtowc (&wc2, s2, filename_len, &ps2);
- if (v1 == 0 && v2 == 0)
- return 1;
- else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
- {
- if (*s1 != *s2) /* do byte comparison */
- return 0;
- else if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
- return 0;
- s1++; s2++; len--;
- continue;
- }
- wc1 = towlower (wc1);
- wc2 = towlower (wc2);
- s1 += v1;
- s2 += v1;
- len -= v1;
- if ((wc1 == L'-' || wc1 == L'_') && (wc2 == L'-' || wc2 == L'_'))
- continue;
- if (wc1 != wc2)
- return 0;
- }
- while (len != 0);
- }
- else
-#endif
- {
- do
- {
- d = _rl_to_lower (*s1) - _rl_to_lower (*s2);
- /* *s1 == [-_] && *s2 == [-_] */
- if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_'))
- d = 0;
- if (d != 0)
- return 0;
- s1++; s2++; /* already checked convlen >= filename_len */
- }
- while (--len != 0);
- }
-
- return 1;
- }
- else if (_rl_completion_case_fold)
- {
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- do
- {
- v1 = mbrtowc (&wc1, s1, convlen, &ps1);
- v2 = mbrtowc (&wc2, s2, filename_len, &ps2);
- if (v1 == 0 && v2 == 0)
- return 1;
- else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
- {
- if (*s1 != *s2) /* do byte comparison */
- return 0;
- s1++; s2++; len--;
- continue;
- }
- wc1 = towlower (wc1);
- wc2 = towlower (wc2);
- if (wc1 != wc2)
- return 0;
- s1 += v1;
- s2 += v1;
- len -= v1;
- }
- while (len != 0);
- return 1;
- }
- else
-#endif
- if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) &&
- (convlen >= filename_len) &&
- (_rl_strnicmp (filename, convfn, filename_len) == 0))
- return 1;
- }
- else
- {
- if ((convfn[0] == filename[0]) &&
- (convlen >= filename_len) &&
- (strncmp (filename, convfn, filename_len) == 0))
- return 1;
- }
- return 0;
-}
-
-/* Okay, now we write the entry_function for filename completion. In the
- general case. Note that completion in the shell is a little different
- because of all the pathnames that must be followed when looking up the
- completion for a command. */
-char *
-rl_filename_completion_function (text, state)
- const char *text;
- int state;
-{
- static DIR *directory = (DIR *)NULL;
- static char *filename = (char *)NULL;
- static char *dirname = (char *)NULL;
- static char *users_dirname = (char *)NULL;
- static int filename_len;
- char *temp, *dentry, *convfn;
- int dirlen, dentlen, convlen;
- struct dirent *entry;
-
- /* If we don't have any state, then do some initialization. */
- if (state == 0)
- {
- /* If we were interrupted before closing the directory or reading
- all of its contents, close it. */
- if (directory)
- {
- closedir (directory);
- directory = (DIR *)NULL;
- }
- FREE (dirname);
- FREE (filename);
- FREE (users_dirname);
-
- filename = savestring (text);
- if (*text == 0)
- text = ".";
- dirname = savestring (text);
-
- temp = strrchr (dirname, '/');
-
-#if defined (__MSDOS__)
- /* special hack for //X/... */
- if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/')
- temp = strrchr (dirname + 3, '/');
-#endif
-
- if (temp)
- {
- strcpy (filename, ++temp);
- *temp = '\0';
- }
-#if defined (__MSDOS__)
- /* searches from current directory on the drive */
- else if (ISALPHA ((unsigned char)dirname[0]) && dirname[1] == ':')
- {
- strcpy (filename, dirname + 2);
- dirname[2] = '\0';
- }
-#endif
- else
- {
- dirname[0] = '.';
- dirname[1] = '\0';
- }
-
- /* We aren't done yet. We also support the "~user" syntax. */
-
- /* Save the version of the directory that the user typed, dequoting
- it if necessary. */
- if (rl_completion_found_quote && rl_filename_dequoting_function)
- users_dirname = (*rl_filename_dequoting_function) (dirname, rl_completion_quote_character);
- else
- users_dirname = savestring (dirname);
-
- if (*dirname == '~')
- {
- temp = tilde_expand (dirname);
- xfree (dirname);
- dirname = temp;
- }
-
- /* We have saved the possibly-dequoted version of the directory name
- the user typed. Now transform the directory name we're going to
- pass to opendir(2). The directory rewrite hook modifies only the
- directory name; the directory completion hook modifies both the
- directory name passed to opendir(2) and the version the user
- typed. Both the directory completion and rewrite hooks should perform
- any necessary dequoting. The hook functions return 1 if they modify
- the directory name argument. If either hook returns 0, it should
- not modify the directory name pointer passed as an argument. */
- if (rl_directory_rewrite_hook)
- (*rl_directory_rewrite_hook) (&dirname);
- else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname))
- {
- xfree (users_dirname);
- users_dirname = savestring (dirname);
- }
- else if (rl_completion_found_quote && rl_filename_dequoting_function)
- {
- /* delete single and double quotes */
- xfree (dirname);
- dirname = savestring (users_dirname);
- }
- directory = opendir (dirname);
-
- /* Now dequote a non-null filename. FILENAME will not be NULL, but may
- be empty. */
- if (*filename && rl_completion_found_quote && rl_filename_dequoting_function)
- {
- /* delete single and double quotes */
- temp = (*rl_filename_dequoting_function) (filename, rl_completion_quote_character);
- xfree (filename);
- filename = temp;
- }
- filename_len = strlen (filename);
-
- rl_filename_completion_desired = 1;
- }
-
- /* At this point we should entertain the possibility of hacking wildcarded
- filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name
- contains globbing characters, then build an array of directories, and
- then map over that list while completing. */
- /* *** UNIMPLEMENTED *** */
-
- /* Now that we have some state, we can read the directory. */
-
- entry = (struct dirent *)NULL;
- while (directory && (entry = readdir (directory)))
- {
- convfn = dentry = entry->d_name;
- convlen = dentlen = D_NAMLEN (entry);
-
- if (rl_filename_rewrite_hook)
- {
- convfn = (*rl_filename_rewrite_hook) (dentry, dentlen);
- convlen = (convfn == dentry) ? dentlen : strlen (convfn);
- }
-
- /* Special case for no filename. If the user has disabled the
- `match-hidden-files' variable, skip filenames beginning with `.'.
- All other entries except "." and ".." match. */
- if (filename_len == 0)
- {
- if (_rl_match_hidden_files == 0 && HIDDEN_FILE (convfn))
- continue;
-
- if (convfn[0] != '.' ||
- (convfn[1] && (convfn[1] != '.' || convfn[2])))
- break;
- }
- else
- {
- if (complete_fncmp (convfn, convlen, filename, filename_len))
- break;
- }
- }
-
- if (entry == 0)
- {
- if (directory)
- {
- closedir (directory);
- directory = (DIR *)NULL;
- }
- if (dirname)
- {
- xfree (dirname);
- dirname = (char *)NULL;
- }
- if (filename)
- {
- xfree (filename);
- filename = (char *)NULL;
- }
- if (users_dirname)
- {
- xfree (users_dirname);
- users_dirname = (char *)NULL;
- }
-
- return (char *)NULL;
- }
- else
- {
- /* dirname && (strcmp (dirname, ".") != 0) */
- if (dirname && (dirname[0] != '.' || dirname[1]))
- {
- if (rl_complete_with_tilde_expansion && *users_dirname == '~')
- {
- dirlen = strlen (dirname);
- temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry));
- strcpy (temp, dirname);
- /* Canonicalization cuts off any final slash present. We
- may need to add it back. */
- if (dirname[dirlen - 1] != '/')
- {
- temp[dirlen++] = '/';
- temp[dirlen] = '\0';
- }
- }
- else
- {
- dirlen = strlen (users_dirname);
- temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry));
- strcpy (temp, users_dirname);
- /* Make sure that temp has a trailing slash here. */
- if (users_dirname[dirlen - 1] != '/')
- temp[dirlen++] = '/';
- }
-
- strcpy (temp + dirlen, convfn);
- }
- else
- temp = savestring (convfn);
-
- if (convfn != dentry)
- xfree (convfn);
-
- return (temp);
- }
-}
-
-/* An initial implementation of a menu completion function a la tcsh. The
- first time (if the last readline command was not rl_old_menu_complete), we
- generate the list of matches. This code is very similar to the code in
- rl_complete_internal -- there should be a way to combine the two. Then,
- for each item in the list of matches, we insert the match in an undoable
- fashion, with the appropriate character appended (this happens on the
- second and subsequent consecutive calls to rl_old_menu_complete). When we
- hit the end of the match list, we restore the original unmatched text,
- ring the bell, and reset the counter to zero. */
-int
-rl_old_menu_complete (count, invoking_key)
- int count, invoking_key;
-{
- rl_compentry_func_t *our_func;
- int matching_filenames, found_quote;
-
- static char *orig_text;
- static char **matches = (char **)0;
- static int match_list_index = 0;
- static int match_list_size = 0;
- static int orig_start, orig_end;
- static char quote_char;
- static int delimiter;
-
- /* The first time through, we generate the list of matches and set things
- up to insert them. */
- if (rl_last_func != rl_old_menu_complete)
- {
- /* Clean up from previous call, if any. */
- FREE (orig_text);
- if (matches)
- _rl_free_match_list (matches);
-
- match_list_index = match_list_size = 0;
- matches = (char **)NULL;
-
- rl_completion_invoking_key = invoking_key;
-
- RL_SETSTATE(RL_STATE_COMPLETING);
-
- /* Only the completion entry function can change these. */
- set_completion_defaults ('%');
-
- our_func = rl_menu_completion_entry_function;
- if (our_func == 0)
- our_func = rl_completion_entry_function
- ? rl_completion_entry_function
- : rl_filename_completion_function;
-
- /* We now look backwards for the start of a filename/variable word. */
- orig_end = rl_point;
- found_quote = delimiter = 0;
- quote_char = '\0';
-
- if (rl_point)
- /* This (possibly) changes rl_point. If it returns a non-zero char,
- we know we have an open quote. */
- quote_char = _rl_find_completion_word (&found_quote, &delimiter);
-
- orig_start = rl_point;
- rl_point = orig_end;
-
- orig_text = rl_copy_text (orig_start, orig_end);
- matches = gen_completion_matches (orig_text, orig_start, orig_end,
- our_func, found_quote, quote_char);
-
- /* If we are matching filenames, the attempted completion function will
- have set rl_filename_completion_desired to a non-zero value. The basic
- rl_filename_completion_function does this. */
- matching_filenames = rl_filename_completion_desired;
-
- if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- FREE (orig_text);
- orig_text = (char *)0;
- completion_changed_buffer = 0;
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- return (0);
- }
-
- RL_UNSETSTATE(RL_STATE_COMPLETING);
-
- for (match_list_size = 0; matches[match_list_size]; match_list_size++)
- ;
- /* matches[0] is lcd if match_list_size > 1, but the circular buffer
- code below should take care of it. */
-
- if (match_list_size > 1 && _rl_complete_show_all)
- display_matches (matches);
- }
-
- /* Now we have the list of matches. Replace the text between
- rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
- matches[match_list_index], and add any necessary closing char. */
-
- if (matches == 0 || match_list_size == 0)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- completion_changed_buffer = 0;
- return (0);
- }
-
- match_list_index += count;
- if (match_list_index < 0)
- {
- while (match_list_index < 0)
- match_list_index += match_list_size;
- }
- else
- match_list_index %= match_list_size;
-
- if (match_list_index == 0 && match_list_size > 1)
- {
- rl_ding ();
- insert_match (orig_text, orig_start, MULT_MATCH, "e_char);
- }
- else
- {
- insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
- append_to_match (matches[match_list_index], delimiter, quote_char,
- strcmp (orig_text, matches[match_list_index]));
- }
-
- completion_changed_buffer = 1;
- return (0);
-}
-
-int
-rl_menu_complete (count, ignore)
- int count, ignore;
-{
- rl_compentry_func_t *our_func;
- int matching_filenames, found_quote;
-
- static char *orig_text;
- static char **matches = (char **)0;
- static int match_list_index = 0;
- static int match_list_size = 0;
- static int nontrivial_lcd = 0;
- static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
- static int orig_start, orig_end;
- static char quote_char;
- static int delimiter, cstate;
-
- /* The first time through, we generate the list of matches and set things
- up to insert them. */
- if ((rl_last_func != rl_menu_complete && rl_last_func != rl_backward_menu_complete) || full_completion)
- {
- /* Clean up from previous call, if any. */
- FREE (orig_text);
- if (matches)
- _rl_free_match_list (matches);
-
- match_list_index = match_list_size = 0;
- matches = (char **)NULL;
-
- full_completion = 0;
-
- RL_SETSTATE(RL_STATE_COMPLETING);
-
- /* Only the completion entry function can change these. */
- set_completion_defaults ('%');
-
- our_func = rl_menu_completion_entry_function;
- if (our_func == 0)
- our_func = rl_completion_entry_function
- ? rl_completion_entry_function
- : rl_filename_completion_function;
-
- /* We now look backwards for the start of a filename/variable word. */
- orig_end = rl_point;
- found_quote = delimiter = 0;
- quote_char = '\0';
-
- if (rl_point)
- /* This (possibly) changes rl_point. If it returns a non-zero char,
- we know we have an open quote. */
- quote_char = _rl_find_completion_word (&found_quote, &delimiter);
-
- orig_start = rl_point;
- rl_point = orig_end;
-
- orig_text = rl_copy_text (orig_start, orig_end);
- matches = gen_completion_matches (orig_text, orig_start, orig_end,
- our_func, found_quote, quote_char);
-
- nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0;
-
- /* If we are matching filenames, the attempted completion function will
- have set rl_filename_completion_desired to a non-zero value. The basic
- rl_filename_completion_function does this. */
- matching_filenames = rl_filename_completion_desired;
-
- if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- FREE (orig_text);
- orig_text = (char *)0;
- completion_changed_buffer = 0;
- RL_UNSETSTATE(RL_STATE_COMPLETING);
- return (0);
- }
-
- RL_UNSETSTATE(RL_STATE_COMPLETING);
-
- for (match_list_size = 0; matches[match_list_size]; match_list_size++)
- ;
-
- if (match_list_size == 0)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- match_list_index = 0;
- completion_changed_buffer = 0;
- return (0);
- }
-
- /* matches[0] is lcd if match_list_size > 1, but the circular buffer
- code below should take care of it. */
- if (*matches[0])
- {
- insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
- orig_end = orig_start + strlen (matches[0]);
- completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
- }
-
- if (match_list_size > 1 && _rl_complete_show_all)
- {
- display_matches (matches);
- /* If there are so many matches that the user has to be asked
- whether or not he wants to see the matches, menu completion
- is unwieldy. */
- if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- full_completion = 1;
- return (0);
- }
- else if (_rl_menu_complete_prefix_first)
- {
- rl_ding ();
- return (0);
- }
- }
- else if (match_list_size <= 1)
- {
- append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
- full_completion = 1;
- return (0);
- }
- else if (_rl_menu_complete_prefix_first && match_list_size > 1)
- {
- rl_ding ();
- return (0);
- }
- }
-
- /* Now we have the list of matches. Replace the text between
- rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
- matches[match_list_index], and add any necessary closing char. */
-
- if (matches == 0 || match_list_size == 0)
- {
- rl_ding ();
- FREE (matches);
- matches = (char **)0;
- completion_changed_buffer = 0;
- return (0);
- }
-
- match_list_index += count;
- if (match_list_index < 0)
- {
- while (match_list_index < 0)
- match_list_index += match_list_size;
- }
- else
- match_list_index %= match_list_size;
-
- if (match_list_index == 0 && match_list_size > 1)
- {
- rl_ding ();
- insert_match (matches[0], orig_start, MULT_MATCH, "e_char);
- }
- else
- {
- insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
- append_to_match (matches[match_list_index], delimiter, quote_char,
- strcmp (orig_text, matches[match_list_index]));
- }
-
- completion_changed_buffer = 1;
- return (0);
-}
-
-int
-rl_backward_menu_complete (count, key)
- int count, key;
-{
- /* Positive arguments to backward-menu-complete translate into negative
- arguments for menu-complete, and vice versa. */
- return (rl_menu_complete (-count, key));
-}
+++ /dev/null
-/* display.c -- readline redisplay facility. */
-
-/* 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 <http://www.gnu.org/licenses/>.
-*/
-
-#define READLINE_LIBRARY
-
-#if defined (HAVE_CONFIG_H)
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#include "posixstat.h"
-
-#if defined (HAVE_STDLIB_H)
-# include <stdlib.h>
-#else
-# include "ansi_stdlib.h"
-#endif /* HAVE_STDLIB_H */
-
-#include <stdio.h>
-
-#ifdef __MSDOS__
-# include <pc.h>
-#endif
-
-/* System-specific feature definitions and include files. */
-#include "rldefs.h"
-#include "rlmbutil.h"
-
-/* Termcap library stuff. */
-#include "tcap.h"
-
-/* Some standard library routines. */
-#include "readline.h"
-#include "history.h"
-
-#include "rlprivate.h"
-#include "xmalloc.h"
-
-#if !defined (strchr) && !defined (__STDC__)
-extern char *strchr (), *strrchr ();
-#endif /* !strchr && !__STDC__ */
-
-static void update_line PARAMS((char *, char *, int, int, int, int));
-static void space_to_eol PARAMS((int));
-static void delete_chars PARAMS((int));
-static void insert_some_chars PARAMS((char *, int, int));
-static void cr PARAMS((void));
-
-/* State of visible and invisible lines. */
-struct line_state
- {
- char *line;
- int *lbreaks;
- int lbsize;
-#if defined (HANDLE_MULTIBYTE)
- int *wrapped_line;
- int wbsize;
-#endif
- };
-
-/* The line display buffers. One is the line currently displayed on
- the screen. The other is the line about to be displayed. */
-static struct line_state line_state_array[2];
-static struct line_state *line_state_visible = &line_state_array[0];
-static struct line_state *line_state_invisible = &line_state_array[1];
-static int line_structures_initialized = 0;
-
-/* Backwards-compatible names. */
-#define inv_lbreaks (line_state_invisible->lbreaks)
-#define inv_lbsize (line_state_invisible->lbsize)
-#define vis_lbreaks (line_state_visible->lbreaks)
-#define vis_lbsize (line_state_visible->lbsize)
-
-#define visible_line (line_state_visible->line)
-#define invisible_line (line_state_invisible->line)
-
-#if defined (HANDLE_MULTIBYTE)
-static int _rl_col_width PARAMS((const char *, int, int, int));
-#else
-# define _rl_col_width(l, s, e, f) (((e) <= (s)) ? 0 : (e) - (s))
-#endif
-
-/* Heuristic used to decide whether it is faster to move from CUR to NEW
- by backing up or outputting a carriage return and moving forward. CUR
- and NEW are either both buffer positions or absolute screen positions. */
-#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
-
-/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
- buffer index in others. This macro is used when deciding whether the
- current cursor position is in the middle of a prompt string containing
- invisible characters. XXX - might need to take `modmark' into account. */
-#define PROMPT_ENDING_INDEX \
- ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1)
-
-
-/* **************************************************************** */
-/* */
-/* Display stuff */
-/* */
-/* **************************************************************** */
-
-/* This is the stuff that is hard for me. I never seem to write good
- display routines in C. Let's see how I do this time. */
-
-/* (PWP) Well... Good for a simple line updater, but totally ignores
- the problems of input lines longer than the screen width.
-
- update_line and the code that calls it makes a multiple line,
- automatically wrapping line update. Careful attention needs
- to be paid to the vertical position variables. */
-
-/* Keep two buffers; one which reflects the current contents of the
- screen, and the other to draw what we think the new contents should
- be. Then compare the buffers, and make whatever changes to the
- screen itself that we should. Finally, make the buffer that we
- just drew into be the one which reflects the current contents of the
- screen, and place the cursor where it belongs.
-
- Commands that want to can fix the display themselves, and then let
- this function know that the display has been fixed by setting the
- RL_DISPLAY_FIXED variable. This is good for efficiency. */
-
-/* Application-specific redisplay function. */
-rl_voidfunc_t *rl_redisplay_function = rl_redisplay;
-
-/* Global variables declared here. */
-/* What YOU turn on when you have handled all redisplay yourself. */
-int rl_display_fixed = 0;
-
-int _rl_suppress_redisplay = 0;
-int _rl_want_redisplay = 0;
-
-/* The stuff that gets printed out before the actual text of the line.
- This is usually pointing to rl_prompt. */
-char *rl_display_prompt = (char *)NULL;
-
-/* Pseudo-global variables declared here. */
-
-/* The visible cursor position. If you print some text, adjust this. */
-/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale
- supporting multibyte characters, and an absolute cursor position when
- in such a locale. This is an artifact of the donated multibyte support.
- Care must be taken when modifying its value. */
-int _rl_last_c_pos = 0;
-int _rl_last_v_pos = 0;
-
-static int cpos_adjusted;
-static int cpos_buffer_position;
-static int prompt_multibyte_chars;
-
-/* Number of lines currently on screen minus 1. */
-int _rl_vis_botlin = 0;
-
-/* Variables used only in this file. */
-/* The last left edge of text that was displayed. This is used when
- doing horizontal scrolling. It shifts in thirds of a screenwidth. */
-static int last_lmargin;
-
-/* A buffer for `modeline' messages. */
-static char *msg_buf = 0;
-static int msg_bufsiz = 0;
-
-/* Non-zero forces the redisplay even if we thought it was unnecessary. */
-static int forced_display;
-
-/* Default and initial buffer size. Can grow. */
-static int line_size = 1024;
-
-/* Variables to keep track of the expanded prompt string, which may
- include invisible characters. */
-
-static char *local_prompt, *local_prompt_prefix;
-static int local_prompt_len;
-static int prompt_visible_length, prompt_prefix_length;
-
-/* The number of invisible characters in the line currently being
- displayed on the screen. */
-static int visible_wrap_offset;
-
-/* The number of invisible characters in the prompt string. Static so it
- can be shared between rl_redisplay and update_line */
-static int wrap_offset;
-
-/* The index of the last invisible character in the prompt string. */
-static int prompt_last_invisible;
-
-/* The length (buffer offset) of the first line of the last (possibly
- multi-line) buffer displayed on the screen. */
-static int visible_first_line_len;
-
-/* Number of invisible characters on the first physical line of the prompt.
- Only valid when the number of physical characters in the prompt exceeds
- (or is equal to) _rl_screenwidth. */
-static int prompt_invis_chars_first_line;
-
-static int prompt_last_screen_line;
-
-static int prompt_physical_chars;
-
-/* set to a non-zero value by rl_redisplay if we are marking modified history
- lines and the current line is so marked. */
-static int modmark;
-
-/* Variables to save and restore prompt and display information. */
-
-/* These are getting numerous enough that it's time to create a struct. */
-
-static char *saved_local_prompt;
-static char *saved_local_prefix;
-static int saved_last_invisible;
-static int saved_visible_length;
-static int saved_prefix_length;
-static int saved_local_length;
-static int saved_invis_chars_first_line;
-static int saved_physical_chars;
-
-/* Return a character indicating the editing mode, for use in the prompt. */
-static int
-prompt_modechar ()
-{
- if (rl_editing_mode == emacs_mode)
- return '@';
- else if (_rl_keymap == vi_insertion_keymap)
- return '+'; /* vi insert mode */
- else
- return ':'; /* vi command mode */
-}
-
-/* Expand the prompt string S and return the number of visible
- characters in *LP, if LP is not null. This is currently more-or-less
- a placeholder for expansion. LIP, if non-null is a place to store the
- index of the last invisible character in the returned string. NIFLP,
- if non-zero, is a place to store the number of invisible characters in
- the first prompt line. The previous are used as byte counts -- indexes
- into a character buffer. */
-
-/* Current implementation:
- \001 (^A) start non-visible characters
- \002 (^B) end non-visible characters
- all characters except \001 and \002 (following a \001) are copied to
- the returned string; all characters except those between \001 and
- \002 are assumed to be `visible'. */
-
-static char *
-expand_prompt (pmt, lp, lip, niflp, vlp)
- char *pmt;
- int *lp, *lip, *niflp, *vlp;
-{
- char *r, *ret, *p, *igstart;
- int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
-
- /* Short-circuit if we can. */
- if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
- {
- if (pmt == rl_prompt && _rl_show_mode_in_prompt)
- {
- l = strlen (pmt);
- r = (char *)xmalloc (l + 2);
- r[0] = prompt_modechar ();
- strcpy (r + 1, pmt);
- }
- else
- r = savestring (pmt);
-
- if (lp)
- *lp = strlen (r);
- if (lip)
- *lip = 0;
- if (niflp)
- *niflp = 0;
- if (vlp)
- *vlp = lp ? *lp : strlen (r);
- return r;
- }
-
- l = strlen (pmt);
- r = ret = (char *)xmalloc (l + 2);
-
- rl = physchars = 0; /* move up here so mode show can set them */
- if (pmt == rl_prompt && _rl_show_mode_in_prompt)
- {
- *r++ = prompt_modechar ();
- rl = physchars = 1;
- }
-
- invfl = 0; /* invisible chars in first line of prompt */
- invflset = 0; /* we only want to set invfl once */
-
- igstart = 0;
- for (ignoring = last = ninvis = 0, p = pmt; p && *p; p++)
- {
- /* This code strips the invisible character string markers
- RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
- if (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */
- {
- ignoring = 1;
- igstart = p;
- continue;
- }
- else if (ignoring && *p == RL_PROMPT_END_IGNORE)
- {
- ignoring = 0;
- if (p != (igstart + 1))
- last = r - ret - 1;
- continue;
- }
- else
- {
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- pind = p - pmt;
- ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO);
- l = ind - pind;
- while (l--)
- *r++ = *p++;
- if (!ignoring)
- {
- /* rl ends up being assigned to prompt_visible_length,
- which is the number of characters in the buffer that
- contribute to characters on the screen, which might
- not be the same as the number of physical characters
- on the screen in the presence of multibyte characters */
- rl += ind - pind;
- physchars += _rl_col_width (pmt, pind, ind, 0);
- }
- else
- ninvis += ind - pind;
- p--; /* compensate for later increment */
- }
- else
-#endif
- {
- *r++ = *p;
- if (!ignoring)
- {
- rl++; /* visible length byte counter */
- physchars++;
- }
- else
- ninvis++; /* invisible chars byte counter */
- }
-
- if (invflset == 0 && rl >= _rl_screenwidth)
- {
- invfl = ninvis;
- invflset = 1;
- }
- }
- }
-
- if (rl < _rl_screenwidth)
- invfl = ninvis;
-
- *r = '\0';
- if (lp)
- *lp = rl;
- if (lip)
- *lip = last;
- if (niflp)
- *niflp = invfl;
- if (vlp)
- *vlp = physchars;
- return ret;
-}
-
-/* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from
- PMT and return the rest of PMT. */
-char *
-_rl_strip_prompt (pmt)
- char *pmt;
-{
- char *ret;
-
- ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL);
- return ret;
-}
-
-void
-_rl_reset_prompt ()
-{
- rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
-}
-
-/*
- * Expand the prompt string into the various display components, if
- * necessary.
- *
- * local_prompt = expanded last line of string in rl_display_prompt
- * (portion after the final newline)
- * local_prompt_prefix = portion before last newline of rl_display_prompt,
- * expanded via expand_prompt
- * prompt_visible_length = number of visible characters in local_prompt
- * prompt_prefix_length = number of visible characters in local_prompt_prefix
- *
- * This function is called once per call to readline(). It may also be
- * called arbitrarily to expand the primary prompt.
- *
- * The return value is the number of visible characters on the last line
- * of the (possibly multi-line) prompt.
- */
-int
-rl_expand_prompt (prompt)
- char *prompt;
-{
- char *p, *t;
- int c;
-
- /* Clear out any saved values. */
- FREE (local_prompt);
- FREE (local_prompt_prefix);
-
- local_prompt = local_prompt_prefix = (char *)0;
- local_prompt_len = 0;
- prompt_last_invisible = prompt_invis_chars_first_line = 0;
- prompt_visible_length = prompt_physical_chars = 0;
-
- if (prompt == 0 || *prompt == 0)
- return (0);
-
- p = strrchr (prompt, '\n');
- if (!p)
- {
- /* The prompt is only one logical line, though it might wrap. */
- local_prompt = expand_prompt (prompt, &prompt_visible_length,
- &prompt_last_invisible,
- &prompt_invis_chars_first_line,
- &prompt_physical_chars);
- local_prompt_prefix = (char *)0;
- local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
- return (prompt_visible_length);
- }
- else
- {
- /* The prompt spans multiple lines. */
- t = ++p;
- local_prompt = expand_prompt (p, &prompt_visible_length,
- &prompt_last_invisible,
- &prompt_invis_chars_first_line,
- &prompt_physical_chars);
- c = *t; *t = '\0';
- /* The portion of the prompt string up to and including the
- final newline is now null-terminated. */
- local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
- (int *)NULL,
- (int *)NULL,
- (int *)NULL);
- *t = c;
- local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
- return (prompt_prefix_length);
- }
-}
-
-/* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated
- arrays of line break markers. MINSIZE is the minimum size of VISIBLE_LINE
- and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is
- increased. If the lines have already been allocated, this ensures that
- they can hold at least MINSIZE characters. */
-static void
-init_line_structures (minsize)
- int minsize;
-{
- register int n;
-
- if (invisible_line == 0) /* initialize it */
- {
- if (line_size < minsize)
- line_size = minsize;
- visible_line = (char *)xmalloc (line_size);
- invisible_line = (char *)xmalloc (line_size);
- }
- else if (line_size < minsize) /* ensure it can hold MINSIZE chars */
- {
- line_size *= 2;
- if (line_size < minsize)
- line_size = minsize;
- visible_line = (char *)xrealloc (visible_line, line_size);
- invisible_line = (char *)xrealloc (invisible_line, line_size);
- }
-
- for (n = minsize; n < line_size; n++)
- {
- visible_line[n] = 0;
- invisible_line[n] = 1;
- }
-
- if (vis_lbreaks == 0)
- {
- /* should be enough. */
- inv_lbsize = vis_lbsize = 256;
-
-#if defined (HANDLE_MULTIBYTE)
- line_state_visible->wbsize = vis_lbsize;
- line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int));
-
- line_state_invisible->wbsize = inv_lbsize;
- line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int));
-#endif
-
- inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int));
- vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int));
- inv_lbreaks[0] = vis_lbreaks[0] = 0;
- }
-
- line_structures_initialized = 1;
-}
-
-/* Basic redisplay algorithm. */
-void
-rl_redisplay ()
-{
- register int in, out, c, linenum, cursor_linenum;
- register char *line;
- int inv_botlin, lb_botlin, lb_linenum, o_cpos;
- int newlines, lpos, temp, n0, num, prompt_lines_estimate;
- char *prompt_this_line;
-#if defined (HANDLE_MULTIBYTE)
- wchar_t wc;
- size_t wc_bytes;
- int wc_width;
- mbstate_t ps;
- int _rl_wrapped_multicolumn = 0;
-#endif
-
- if (_rl_echoing_p == 0)
- return;
-
- /* Block keyboard interrupts because this function manipulates global
- data structures. */
- _rl_block_sigint ();
- RL_SETSTATE (RL_STATE_REDISPLAYING);
-
- if (!rl_display_prompt)
- rl_display_prompt = "";
-
- if (line_structures_initialized == 0)
- {
- init_line_structures (0);
- rl_on_new_line ();
- }
-
- /* Draw the line into the buffer. */
- cpos_buffer_position = -1;
-
- prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars;
-
- line = invisible_line;
- out = inv_botlin = 0;
-
- /* Mark the line as modified or not. We only do this for history
- lines. */
- modmark = 0;
- if (_rl_mark_modified_lines && current_history () && rl_undo_list)
- {
- line[out++] = '*';
- line[out] = '\0';
- modmark = 1;
- }
-
- /* If someone thought that the redisplay was handled, but the currently
- visible line has a different modification state than the one about
- to become visible, then correct the caller's misconception. */
- if (visible_line[0] != invisible_line[0])
- rl_display_fixed = 0;
-
- /* If the prompt to be displayed is the `primary' readline prompt (the
- one passed to readline()), use the values we have already expanded.
- If not, use what's already in rl_display_prompt. WRAP_OFFSET is the
- number of non-visible characters in the prompt string. */
- if (rl_display_prompt == rl_prompt || local_prompt)
- {
- if (local_prompt_prefix && forced_display)
- _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
-
- if (local_prompt_len > 0)
- {
- temp = local_prompt_len + out + 2;
- if (temp >= line_size)
- {
- line_size = (temp + 1024) - (temp % 1024);
- visible_line = (char *)xrealloc (visible_line, line_size);
- line = invisible_line = (char *)xrealloc (invisible_line, line_size);
- }
- strncpy (line + out, local_prompt, local_prompt_len);
- out += local_prompt_len;
- }
- line[out] = '\0';
- wrap_offset = local_prompt_len - prompt_visible_length;
- }
- else
- {
- int pmtlen;
- prompt_this_line = strrchr (rl_display_prompt, '\n');
- if (!prompt_this_line)
- prompt_this_line = rl_display_prompt;
- else
- {
- prompt_this_line++;
- pmtlen = prompt_this_line - rl_display_prompt; /* temp var */
- if (forced_display)
- {
- _rl_output_some_chars (rl_display_prompt, pmtlen);
- /* Make sure we are at column zero even after a newline,
- regardless of the state of terminal output processing. */
- if (pmtlen < 2 || prompt_this_line[-2] != '\r')
- cr ();
- }
- }
-
- prompt_physical_chars = pmtlen = strlen (prompt_this_line);
- temp = pmtlen + out + 2;
- if (temp >= line_size)
- {
- line_size = (temp + 1024) - (temp % 1024);
- visible_line = (char *)xrealloc (visible_line, line_size);
- line = invisible_line = (char *)xrealloc (invisible_line, line_size);
- }
- strncpy (line + out, prompt_this_line, pmtlen);
- out += pmtlen;
- line[out] = '\0';
- wrap_offset = prompt_invis_chars_first_line = 0;
- }
-
-#define CHECK_INV_LBREAKS() \
- do { \
- if (newlines >= (inv_lbsize - 2)) \
- { \
- inv_lbsize *= 2; \
- inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
- } \
- } while (0)
-
-#if defined (HANDLE_MULTIBYTE)
-#define CHECK_LPOS() \
- do { \
- lpos++; \
- if (lpos >= _rl_screenwidth) \
- { \
- if (newlines >= (inv_lbsize - 2)) \
- { \
- inv_lbsize *= 2; \
- inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
- } \
- inv_lbreaks[++newlines] = out; \
- if (newlines >= (line_state_invisible->wbsize - 1)) \
- { \
- line_state_invisible->wbsize *= 2; \
- line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \
- } \
- line_state_invisible->wrapped_line[newlines] = _rl_wrapped_multicolumn; \
- lpos = 0; \
- } \
- } while (0)
-#else
-#define CHECK_LPOS() \
- do { \
- lpos++; \
- if (lpos >= _rl_screenwidth) \
- { \
- if (newlines >= (inv_lbsize - 2)) \
- { \
- inv_lbsize *= 2; \
- inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
- } \
- inv_lbreaks[++newlines] = out; \
- lpos = 0; \
- } \
- } while (0)
-#endif
-
- /* inv_lbreaks[i] is where line i starts in the buffer. */
- inv_lbreaks[newlines = 0] = 0;
- lpos = prompt_physical_chars + modmark;
-
-#if defined (HANDLE_MULTIBYTE)
- memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int));
- num = 0;
-#endif
-
- /* prompt_invis_chars_first_line is the number of invisible characters in
- the first physical line of the prompt.
- wrap_offset - prompt_invis_chars_first_line is the number of invis
- chars on the second (or, more generally, last) line. */
-
- /* This is zero-based, used to set the newlines */
- prompt_lines_estimate = lpos / _rl_screenwidth;
-
- /* what if lpos is already >= _rl_screenwidth before we start drawing the
- contents of the command line? */
- while (lpos >= _rl_screenwidth)
- {
- int z;
- /* fix from Darin Johnson <darin@acuson.com> for prompt string with
- invisible characters that is longer than the screen width. The
- prompt_invis_chars_first_line variable could be made into an array
- saying how many invisible characters there are per line, but that's
- probably too much work for the benefit gained. How many people have
- prompts that exceed two physical lines?
- Additional logic fix from Edward Catmur <ed@catmur.co.uk> */
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
- {
- n0 = num;
- temp = local_prompt_len;
- while (num < temp)
- {
- z = _rl_col_width (local_prompt, n0, num, 1);
- if (z > _rl_screenwidth)
- {
- num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY);
- break;
- }
- else if (z == _rl_screenwidth)
- break;
- num++;
- }
- temp = num;
- }
- else
-#endif /* !HANDLE_MULTIBYTE */
- temp = ((newlines + 1) * _rl_screenwidth);
-
- /* Now account for invisible characters in the current line. */
- /* XXX - this assumes that the invisible characters may be split, but only
- between the first and the last lines. */
- temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line
- : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line))
- : ((newlines == 0) ? wrap_offset : 0));
-
- inv_lbreaks[++newlines] = temp;
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
- lpos -= _rl_col_width (local_prompt, n0, num, 1);
- else
-#endif
- lpos -= _rl_screenwidth;
- }
-
- prompt_last_screen_line = newlines;
-
- /* Draw the rest of the line (after the prompt) into invisible_line, keeping
- track of where the cursor is (cpos_buffer_position), the number of the line containing
- the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
- It maintains an array of line breaks for display (inv_lbreaks).
- This handles expanding tabs for display and displaying meta characters. */
- lb_linenum = 0;
-#if defined (HANDLE_MULTIBYTE)
- in = 0;
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- memset (&ps, 0, sizeof (mbstate_t));
- /* XXX - what if wc_bytes ends up <= 0? check for MB_INVALIDCH */
- wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps);
- }
- else
- wc_bytes = 1;
- while (in < rl_end)
-#else
- for (in = 0; in < rl_end; in++)
-#endif
- {
- c = (unsigned char)rl_line_buffer[in];
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- if (MB_INVALIDCH (wc_bytes))
- {
- /* Byte sequence is invalid or shortened. Assume that the
- first byte represents a character. */
- wc_bytes = 1;
- /* Assume that a character occupies a single column. */
- wc_width = 1;
- memset (&ps, 0, sizeof (mbstate_t));
- }
- else if (MB_NULLWCH (wc_bytes))
- break; /* Found '\0' */
- else
- {
- temp = WCWIDTH (wc);
- wc_width = (temp >= 0) ? temp : 1;
- }
- }
-#endif
-
- if (out + 8 >= line_size) /* XXX - 8 for \t */
- {
- line_size *= 2;
- visible_line = (char *)xrealloc (visible_line, line_size);
- invisible_line = (char *)xrealloc (invisible_line, line_size);
- line = invisible_line;
- }
-
- if (in == rl_point)
- {
- cpos_buffer_position = out;
- lb_linenum = newlines;
- }
-
-#if defined (HANDLE_MULTIBYTE)
- if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */
-#else
- if (META_CHAR (c))
-#endif
- {
- if (_rl_output_meta_chars == 0)
- {
- sprintf (line + out, "\\%o", c);
-
- if (lpos + 4 >= _rl_screenwidth)
- {
- temp = _rl_screenwidth - lpos;
- CHECK_INV_LBREAKS ();
- inv_lbreaks[++newlines] = out + temp;
- lpos = 4 - temp;
- }
- else
- lpos += 4;
-
- out += 4;
- }
- else
- {
- line[out++] = c;
- CHECK_LPOS();
- }
- }
-#if defined (DISPLAY_TABS)
- else if (c == '\t')
- {
- register int newout;
-
-#if 0
- newout = (out | (int)7) + 1;
-#else
- newout = out + 8 - lpos % 8;
-#endif
- temp = newout - out;
- if (lpos + temp >= _rl_screenwidth)
- {
- register int temp2;
- temp2 = _rl_screenwidth - lpos;
- CHECK_INV_LBREAKS ();
- inv_lbreaks[++newlines] = out + temp2;
- lpos = temp - temp2;
- while (out < newout)
- line[out++] = ' ';
- }
- else
- {
- while (out < newout)
- line[out++] = ' ';
- lpos += temp;
- }
- }
-#endif
- else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
- {
- line[out++] = '\0'; /* XXX - sentinel */
- CHECK_INV_LBREAKS ();
- inv_lbreaks[++newlines] = out;
- lpos = 0;
- }
- else if (CTRL_CHAR (c) || c == RUBOUT)
- {
- line[out++] = '^';
- CHECK_LPOS();
- line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
- CHECK_LPOS();
- }
- else
- {
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- register int i;
-
- _rl_wrapped_multicolumn = 0;
-
- if (_rl_screenwidth < lpos + wc_width)
- for (i = lpos; i < _rl_screenwidth; i++)
- {
- /* The space will be removed in update_line() */
- line[out++] = ' ';
- _rl_wrapped_multicolumn++;
- CHECK_LPOS();
- }
- if (in == rl_point)
- {
- cpos_buffer_position = out;
- lb_linenum = newlines;
- }
- for (i = in; i < in+wc_bytes; i++)
- line[out++] = rl_line_buffer[i];
- for (i = 0; i < wc_width; i++)
- CHECK_LPOS();
- }
- else
- {
- line[out++] = c;
- CHECK_LPOS();
- }
-#else
- line[out++] = c;
- CHECK_LPOS();
-#endif
- }
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- in += wc_bytes;
- /* XXX - what if wc_bytes ends up <= 0? check for MB_INVALIDCH */
- wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps);
- }
- else
- in++;
-#endif
-
- }
- line[out] = '\0';
- if (cpos_buffer_position < 0)
- {
- cpos_buffer_position = out;
- lb_linenum = newlines;
- }
-
- inv_botlin = lb_botlin = newlines;
- CHECK_INV_LBREAKS ();
- inv_lbreaks[newlines+1] = out;
- cursor_linenum = lb_linenum;
-
- /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
- CURSOR_LINENUM == line number where the cursor should be placed. */
-
- /* PWP: now is when things get a bit hairy. The visible and invisible
- line buffers are really multiple lines, which would wrap every
- (screenwidth - 1) characters. Go through each in turn, finding
- the changed region and updating it. The line order is top to bottom. */
-
- /* If we can move the cursor up and down, then use multiple lines,
- otherwise, let long lines display in a single terminal line, and
- horizontally scroll it. */
-
- if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
- {
- int nleft, pos, changed_screen_line, tx;
-
- if (!rl_display_fixed || forced_display)
- {
- forced_display = 0;
-
- /* If we have more than a screenful of material to display, then
- only display a screenful. We should display the last screen,
- not the first. */
- if (out >= _rl_screenchars)
- {
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY);
- else
- out = _rl_screenchars - 1;
- }
-
- /* The first line is at character position 0 in the buffer. The
- second and subsequent lines start at inv_lbreaks[N], offset by
- OFFSET (which has already been calculated above). */
-
-#define INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset)
-#define WRAP_OFFSET(line, offset) ((line == 0) \
- ? (offset ? INVIS_FIRST() : 0) \
- : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0))
-#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
-#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
-#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l])
-#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
-#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
-#define INV_LINE(line) (invisible_line + inv_lbreaks[line])
-
-#define OLD_CPOS_IN_PROMPT() (cpos_adjusted == 0 && \
- _rl_last_c_pos != o_cpos && \
- _rl_last_c_pos > wrap_offset && \
- o_cpos < prompt_last_invisible)
-
- /* For each line in the buffer, do the updating display. */
- for (linenum = 0; linenum <= inv_botlin; linenum++)
- {
- /* This can lead us astray if we execute a program that changes
- the locale from a non-multibyte to a multibyte one. */
- o_cpos = _rl_last_c_pos;
- cpos_adjusted = 0;
- update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum,
- VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin);
-
- /* update_line potentially changes _rl_last_c_pos, but doesn't
- take invisible characters into account, since _rl_last_c_pos
- is an absolute cursor position in a multibyte locale. See
- if compensating here is the right thing, or if we have to
- change update_line itself. There are several cases in which
- update_line adjusts _rl_last_c_pos itself (so it can pass
- _rl_move_cursor_relative accurate values); it communicates
- this back by setting cpos_adjusted. If we assume that
- _rl_last_c_pos is correct (an absolute cursor position) each
- time update_line is called, then we can assume in our
- calculations that o_cpos does not need to be adjusted by
- wrap_offset. */
- if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT())
- _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */
- else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth &&
- (MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
- cpos_adjusted == 0 &&
- _rl_last_c_pos != o_cpos &&
- _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line))
- _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line);
-
- /* If this is the line with the prompt, we might need to
- compensate for invisible characters in the new line. Do
- this only if there is not more than one new line (which
- implies that we completely overwrite the old visible line)
- and the new line is shorter than the old. Make sure we are
- at the end of the new line before clearing. */
- if (linenum == 0 &&
- inv_botlin == 0 && _rl_last_c_pos == out &&
- (wrap_offset > visible_wrap_offset) &&
- (_rl_last_c_pos < visible_first_line_len))
- {
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- nleft = _rl_screenwidth - _rl_last_c_pos;
- else
- nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos;
- if (nleft)
- _rl_clear_to_eol (nleft);
- }
-#if 0
- /* This segment is intended to handle the case where the prompt
- has invisible characters on the second line and the new line
- to be displayed needs to clear the rest of the old characters
- out (e.g., when printing the i-search prompt). In general,
- the case of the new line being shorter than the old.
- Incomplete */
- else if (linenum == prompt_last_screen_line &&
- prompt_physical_chars > _rl_screenwidth &&
- wrap_offset != prompt_invis_chars_first_line &&
- _rl_last_c_pos == out &&
-#endif
-
-
- /* Since the new first line is now visible, save its length. */
- if (linenum == 0)
- visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset;
- }
-
- /* We may have deleted some lines. If so, clear the left over
- blank ones at the bottom out. */
- if (_rl_vis_botlin > inv_botlin)
- {
- char *tt;
- for (; linenum <= _rl_vis_botlin; linenum++)
- {
- tt = VIS_CHARS (linenum);
- _rl_move_vert (linenum);
- _rl_move_cursor_relative (0, tt);
- _rl_clear_to_eol
- ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth);
- }
- }
- _rl_vis_botlin = inv_botlin;
-
- /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a
- different screen line during this redisplay. */
- changed_screen_line = _rl_last_v_pos != cursor_linenum;
- if (changed_screen_line)
- {
- _rl_move_vert (cursor_linenum);
- /* If we moved up to the line with the prompt using _rl_term_up,
- the physical cursor position on the screen stays the same,
- but the buffer position needs to be adjusted to account
- for invisible characters. */
- if ((MB_CUR_MAX == 1 || rl_byte_oriented) && cursor_linenum == 0 && wrap_offset)
- _rl_last_c_pos += wrap_offset;
- }
-
- /* We have to reprint the prompt if it contains invisible
- characters, since it's not generally OK to just reprint
- the characters from the current cursor position. But we
- only need to reprint it if the cursor is before the last
- invisible character in the prompt string. */
- nleft = prompt_visible_length + wrap_offset;
- if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 &&
-#if 0
- _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt)
-#else
- _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt)
-#endif
- {
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- if (_rl_term_cr)
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif
- if (modmark)
- _rl_output_some_chars ("*", 1);
-
- _rl_output_some_chars (local_prompt, nleft);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft, 1) - wrap_offset + modmark;
- else
- _rl_last_c_pos = nleft + modmark;
- }
-
- /* Where on that line? And where does that line start
- in the buffer? */
- pos = inv_lbreaks[cursor_linenum];
- /* nleft == number of characters in the line buffer between the
- start of the line and the desired cursor position. */
- nleft = cpos_buffer_position - pos;
-
- /* NLEFT is now a number of characters in a buffer. When in a
- multibyte locale, however, _rl_last_c_pos is an absolute cursor
- position that doesn't take invisible characters in the prompt
- into account. We use a fudge factor to compensate. */
-
- /* Since _rl_backspace() doesn't know about invisible characters in the
- prompt, and there's no good way to tell it, we compensate for
- those characters here and call _rl_backspace() directly. */
- if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
- {
- /* TX == new physical cursor position in multibyte locale. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- tx = _rl_col_width (&visible_line[pos], 0, nleft, 1) - visible_wrap_offset;
- else
- tx = nleft;
- if (tx >= 0 && _rl_last_c_pos > tx)
- {
- _rl_backspace (_rl_last_c_pos - tx); /* XXX */
- _rl_last_c_pos = tx;
- }
- }
-
- /* We need to note that in a multibyte locale we are dealing with
- _rl_last_c_pos as an absolute cursor position, but moving to a
- point specified by a buffer position (NLEFT) that doesn't take
- invisible characters into account. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- _rl_move_cursor_relative (nleft, &invisible_line[pos]);
- else if (nleft != _rl_last_c_pos)
- _rl_move_cursor_relative (nleft, &invisible_line[pos]);
- }
- }
- else /* Do horizontal scrolling. */
- {
-#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0)
- int lmargin, ndisp, nleft, phys_c_pos, t;
-
- /* Always at top line. */
- _rl_last_v_pos = 0;
-
- /* Compute where in the buffer the displayed line should start. This
- will be LMARGIN. */
-
- /* The number of characters that will be displayed before the cursor. */
- ndisp = cpos_buffer_position - wrap_offset;
- nleft = prompt_visible_length + wrap_offset;
- /* Where the new cursor position will be on the screen. This can be
- longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
- phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
- t = _rl_screenwidth / 3;
-
- /* If the number of characters had already exceeded the screenwidth,
- last_lmargin will be > 0. */
-
- /* If the number of characters to be displayed is more than the screen
- width, compute the starting offset so that the cursor is about
- two-thirds of the way across the screen. */
- if (phys_c_pos > _rl_screenwidth - 2)
- {
- lmargin = cpos_buffer_position - (2 * t);
- if (lmargin < 0)
- lmargin = 0;
- /* If the left margin would be in the middle of a prompt with
- invisible characters, don't display the prompt at all. */
- if (wrap_offset && lmargin > 0 && lmargin < nleft)
- lmargin = nleft;
- }
- else if (ndisp < _rl_screenwidth - 2) /* XXX - was -1 */
- lmargin = 0;
- else if (phys_c_pos < 1)
- {
- /* If we are moving back towards the beginning of the line and
- the last margin is no longer correct, compute a new one. */
- lmargin = ((cpos_buffer_position - 1) / t) * t; /* XXX */
- if (wrap_offset && lmargin > 0 && lmargin < nleft)
- lmargin = nleft;
- }
- else
- lmargin = last_lmargin;
-
- /* If the first character on the screen isn't the first character
- in the display line, indicate this with a special character. */
- if (lmargin > 0)
- line[lmargin] = '<';
-
- /* If SCREENWIDTH characters starting at LMARGIN do not encompass
- the whole line, indicate that with a special character at the
- right edge of the screen. If LMARGIN is 0, we need to take the
- wrap offset into account. */
- t = lmargin + M_OFFSET (lmargin, wrap_offset) + _rl_screenwidth;
- if (t < out)
- line[t - 1] = '>';
-
- if (rl_display_fixed == 0 || forced_display || lmargin != last_lmargin)
- {
- forced_display = 0;
- o_cpos = _rl_last_c_pos;
- cpos_adjusted = 0;
- update_line (&visible_line[last_lmargin],
- &invisible_line[lmargin],
- 0,
- _rl_screenwidth + visible_wrap_offset,
- _rl_screenwidth + (lmargin ? 0 : wrap_offset),
- 0);
-
- if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && OLD_CPOS_IN_PROMPT())
- _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */
-
- /* If the visible new line is shorter than the old, but the number
- of invisible characters is greater, and we are at the end of
- the new line, we need to clear to eol. */
- t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset);
- if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) &&
- (_rl_last_c_pos == out) &&
- t < visible_first_line_len)
- {
- nleft = _rl_screenwidth - t;
- _rl_clear_to_eol (nleft);
- }
- visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset);
- if (visible_first_line_len > _rl_screenwidth)
- visible_first_line_len = _rl_screenwidth;
-
- _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
- last_lmargin = lmargin;
- }
- }
- fflush (rl_outstream);
-
- /* Swap visible and non-visible lines. */
- {
- struct line_state *vtemp = line_state_visible;
-
- line_state_visible = line_state_invisible;
- line_state_invisible = vtemp;
-
- rl_display_fixed = 0;
- /* If we are displaying on a single line, and last_lmargin is > 0, we
- are not displaying any invisible characters, so set visible_wrap_offset
- to 0. */
- if (_rl_horizontal_scroll_mode && last_lmargin)
- visible_wrap_offset = 0;
- else
- visible_wrap_offset = wrap_offset;
- }
-
- RL_UNSETSTATE (RL_STATE_REDISPLAYING);
- _rl_release_sigint ();
-}
-
-/* PWP: update_line() is based on finding the middle difference of each
- line on the screen; vis:
-
- /old first difference
- /beginning of line | /old last same /old EOL
- v v v v
-old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
-new: eddie> Oh, my little buggy says to me, as lurgid as
- ^ ^ ^ ^
- \beginning of line | \new last same \new end of line
- \new first difference
-
- All are character pointers for the sake of speed. Special cases for
- no differences, as well as for end of line additions must be handled.
-
- Could be made even smarter, but this works well enough */
-static void
-update_line (old, new, current_line, omax, nmax, inv_botlin)
- register char *old, *new;
- int current_line, omax, nmax, inv_botlin;
-{
- register char *ofd, *ols, *oe, *nfd, *nls, *ne;
- int temp, lendiff, wsatend, od, nd, twidth, o_cpos;
- int current_invis_chars;
- int col_lendiff, col_temp;
-#if defined (HANDLE_MULTIBYTE)
- mbstate_t ps_new, ps_old;
- int new_offset, old_offset;
-#endif
-
- /* If we're at the right edge of a terminal that supports xn, we're
- ready to wrap around, so do so. This fixes problems with knowing
- the exact cursor position and cut-and-paste with certain terminal
- emulators. In this calculation, TEMP is the physical screen
- position of the cursor. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- temp = _rl_last_c_pos;
- else
- temp = _rl_last_c_pos - WRAP_OFFSET (_rl_last_v_pos, visible_wrap_offset);
- if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
- && _rl_last_v_pos == current_line - 1)
- {
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- wchar_t wc;
- mbstate_t ps;
- int tempwidth, bytes;
- size_t ret;
-
- /* This fixes only double-column characters, but if the wrapped
- character comsumes more than three columns, spaces will be
- inserted in the string buffer. */
- if (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0)
- _rl_clear_to_eol (line_state_visible->wrapped_line[current_line]);
-
- memset (&ps, 0, sizeof (mbstate_t));
- ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps);
- if (MB_INVALIDCH (ret))
- {
- tempwidth = 1;
- ret = 1;
- }
- else if (MB_NULLWCH (ret))
- tempwidth = 0;
- else
- tempwidth = WCWIDTH (wc);
-
- if (tempwidth > 0)
- {
- int count, i;
- bytes = ret;
- for (count = 0; count < bytes; count++)
- putc (new[count], rl_outstream);
- _rl_last_c_pos = tempwidth;
- _rl_last_v_pos++;
- memset (&ps, 0, sizeof (mbstate_t));
- ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps);
- if (ret != 0 && bytes != 0)
- {
- if (MB_INVALIDCH (ret))
- ret = 1;
- memmove (old+bytes, old+ret, strlen (old+ret));
- memcpy (old, new, bytes);
- /* Fix up indices if we copy data from one line to another */
- omax += bytes - ret;
- for (i = current_line+1; i < inv_botlin+1; i++)
- vis_lbreaks[i] += bytes - ret;
- }
- }
- else
- {
- putc (' ', rl_outstream);
- _rl_last_c_pos = 1;
- _rl_last_v_pos++;
- if (old[0] && new[0])
- old[0] = new[0];
- }
- }
- else
-#endif
- {
- if (new[0])
- putc (new[0], rl_outstream);
- else
- putc (' ', rl_outstream);
- _rl_last_c_pos = 1;
- _rl_last_v_pos++;
- if (old[0] && new[0])
- old[0] = new[0];
- }
- }
-
-
- /* Find first difference. */
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- /* See if the old line is a subset of the new line, so that the
- only change is adding characters. */
- temp = (omax < nmax) ? omax : nmax;
- if (memcmp (old, new, temp) == 0) /* adding at the end */
- {
- new_offset = old_offset = temp;
- ofd = old + temp;
- nfd = new + temp;
- }
- else
- {
- memset (&ps_new, 0, sizeof(mbstate_t));
- memset (&ps_old, 0, sizeof(mbstate_t));
-
- if (omax == nmax && STREQN (new, old, omax))
- {
- old_offset = omax;
- new_offset = nmax;
- ofd = old + omax;
- nfd = new + nmax;
- }
- else
- {
- new_offset = old_offset = 0;
- for (ofd = old, nfd = new;
- (ofd - old < omax) && *ofd &&
- _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); )
- {
- old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY);
- new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY);
-
- ofd = old + old_offset;
- nfd = new + new_offset;
- }
- }
- }
- }
- else
-#endif
- for (ofd = old, nfd = new;
- (ofd - old < omax) && *ofd && (*ofd == *nfd);
- ofd++, nfd++)
- ;
-
- /* Move to the end of the screen line. ND and OD are used to keep track
- of the distance between ne and new and oe and old, respectively, to
- move a subtraction out of each loop. */
- for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++);
- for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++);
-
- /* If no difference, continue to next line. */
- if (ofd == oe && nfd == ne)
- return;
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && _rl_utf8locale)
- {
- wchar_t wc;
- mbstate_t ps = { 0 };
- int t;
-
- /* If the first character in the difference is a zero-width character,
- assume it's a combining character and back one up so the two base
- characters no longer compare equivalently. */
- t = mbrtowc (&wc, ofd, MB_CUR_MAX, &ps);
- if (t > 0 && UNICODE_COMBINING_CHAR (wc) && WCWIDTH (wc) == 0)
- {
- old_offset = _rl_find_prev_mbchar (old, ofd - old, MB_FIND_ANY);
- new_offset = _rl_find_prev_mbchar (new, nfd - new, MB_FIND_ANY);
- ofd = old + old_offset; /* equal by definition */
- nfd = new + new_offset;
- }
- }
-#endif
-
- wsatend = 1; /* flag for trailing whitespace */
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY);
- nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY);
-
- while ((ols > ofd) && (nls > nfd))
- {
- memset (&ps_old, 0, sizeof (mbstate_t));
- memset (&ps_new, 0, sizeof (mbstate_t));
-
-#if 0
- /* On advice from jir@yamato.ibm.com */
- _rl_adjust_point (old, ols - old, &ps_old);
- _rl_adjust_point (new, nls - new, &ps_new);
-#endif
-
- if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0)
- break;
-
- if (*ols == ' ')
- wsatend = 0;
-
- ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY);
- nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY);
- }
- }
- else
- {
-#endif /* HANDLE_MULTIBYTE */
- ols = oe - 1; /* find last same */
- nls = ne - 1;
- while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
- {
- if (*ols != ' ')
- wsatend = 0;
- ols--;
- nls--;
- }
-#if defined (HANDLE_MULTIBYTE)
- }
-#endif
-
- if (wsatend)
- {
- ols = oe;
- nls = ne;
- }
-#if defined (HANDLE_MULTIBYTE)
- /* This may not work for stateful encoding, but who cares? To handle
- stateful encoding properly, we have to scan each string from the
- beginning and compare. */
- else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0)
-#else
- else if (*ols != *nls)
-#endif
- {
- if (*ols) /* don't step past the NUL */
- {
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY);
- else
- ols++;
- }
- if (*nls)
- {
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY);
- else
- nls++;
- }
- }
-
- /* count of invisible characters in the current invisible line. */
- current_invis_chars = W_OFFSET (current_line, wrap_offset);
- if (_rl_last_v_pos != current_line)
- {
- _rl_move_vert (current_line);
- if ((MB_CUR_MAX == 1 || rl_byte_oriented) && current_line == 0 && visible_wrap_offset)
- _rl_last_c_pos += visible_wrap_offset;
- }
-
- /* If this is the first line and there are invisible characters in the
- prompt string, and the prompt string has not changed, and the current
- cursor position is before the last invisible character in the prompt,
- and the index of the character to move to is past the end of the prompt
- string, then redraw the entire prompt string. We can only do this
- reliably if the terminal supports a `cr' capability.
-
- This is not an efficiency hack -- there is a problem with redrawing
- portions of the prompt string if they contain terminal escape
- sequences (like drawing the `unbold' sequence without a corresponding
- `bold') that manifests itself on certain terminals. */
-
- lendiff = local_prompt_len;
- od = ofd - old; /* index of first difference in visible line */
- if (current_line == 0 && !_rl_horizontal_scroll_mode &&
- _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 &&
- od >= lendiff && _rl_last_c_pos < PROMPT_ENDING_INDEX)
- {
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif
- if (modmark)
- _rl_output_some_chars ("*", 1);
- _rl_output_some_chars (local_prompt, lendiff);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- /* We take wrap_offset into account here so we can pass correct
- information to _rl_move_cursor_relative. */
- _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff, 1) - wrap_offset + modmark;
- cpos_adjusted = 1;
- }
- else
- _rl_last_c_pos = lendiff + modmark;
- }
-
- o_cpos = _rl_last_c_pos;
-
- /* When this function returns, _rl_last_c_pos is correct, and an absolute
- cursor postion in multibyte mode, but a buffer index when not in a
- multibyte locale. */
- _rl_move_cursor_relative (od, old);
-#if 1
-#if defined (HANDLE_MULTIBYTE)
- /* We need to indicate that the cursor position is correct in the presence of
- invisible characters in the prompt string. Let's see if setting this when
- we make sure we're at the end of the drawn prompt string works. */
- if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 &&
- (_rl_last_c_pos > 0 || o_cpos > 0) &&
- _rl_last_c_pos == prompt_physical_chars)
- cpos_adjusted = 1;
-#endif
-#endif
-
- /* if (len (new) > len (old))
- lendiff == difference in buffer
- col_lendiff == difference on screen
- When not using multibyte characters, these are equal */
- lendiff = (nls - nfd) - (ols - ofd);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- col_lendiff = _rl_col_width (new, nfd - new, nls - new, 1) - _rl_col_width (old, ofd - old, ols - old, 1);
- else
- col_lendiff = lendiff;
-
- /* If we are changing the number of invisible characters in a line, and
- the spot of first difference is before the end of the invisible chars,
- lendiff needs to be adjusted. */
- if (current_line == 0 && !_rl_horizontal_scroll_mode &&
- current_invis_chars != visible_wrap_offset)
- {
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- lendiff += visible_wrap_offset - current_invis_chars;
- col_lendiff += visible_wrap_offset - current_invis_chars;
- }
- else
- {
- lendiff += visible_wrap_offset - current_invis_chars;
- col_lendiff = lendiff;
- }
- }
-
- /* Insert (diff (len (old), len (new)) ch. */
- temp = ne - nfd;
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- col_temp = _rl_col_width (new, nfd - new, ne - new, 1);
- else
- col_temp = temp;
-
- if (col_lendiff > 0) /* XXX - was lendiff */
- {
- /* Non-zero if we're increasing the number of lines. */
- int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
- /* If col_lendiff is > 0, implying that the new string takes up more
- screen real estate than the old, but lendiff is < 0, meaning that it
- takes fewer bytes, we need to just output the characters starting
- from the first difference. These will overwrite what is on the
- display, so there's no reason to do a smart update. This can really
- only happen in a multibyte environment. */
- if (lendiff < 0)
- {
- _rl_output_some_chars (nfd, temp);
- _rl_last_c_pos += _rl_col_width (nfd, 0, temp, 1);
- /* If nfd begins before any invisible characters in the prompt,
- adjust _rl_last_c_pos to account for wrap_offset and set
- cpos_adjusted to let the caller know. */
- if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- return;
- }
- /* Sometimes it is cheaper to print the characters rather than
- use the terminal's capabilities. If we're growing the number
- of lines, make sure we actually cause the new line to wrap
- around on auto-wrapping terminals. */
- else if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
- {
- /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
- _rl_horizontal_scroll_mode == 1, inserting the characters with
- _rl_term_IC or _rl_term_ic will screw up the screen because of the
- invisible characters. We need to just draw them. */
- /* The same thing happens if we're trying to draw before the last
- invisible character in the prompt string or we're increasing the
- number of invisible characters in the line and we're not drawing
- the entire prompt string. */
- if (*ols && ((_rl_horizontal_scroll_mode &&
- _rl_last_c_pos == 0 &&
- lendiff > prompt_visible_length &&
- current_invis_chars > 0) == 0) &&
- (((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
- current_line == 0 && wrap_offset &&
- ((nfd - new) <= prompt_last_invisible) &&
- (col_lendiff < prompt_visible_length)) == 0) &&
- (visible_wrap_offset >= current_invis_chars))
- {
- insert_some_chars (nfd, lendiff, col_lendiff);
- _rl_last_c_pos += col_lendiff;
- }
-#if 0 /* XXX - for now */
- else if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && _rl_last_c_pos == 0 && wrap_offset && (nfd-new) <= prompt_last_invisible && col_lendiff < prompt_visible_length && visible_wrap_offset >= current_invis_chars)
- {
- _rl_output_some_chars (nfd, lendiff);
- _rl_last_c_pos += col_lendiff;
- }
-#endif
- else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *ols == 0 && lendiff > 0)
- {
- /* At the end of a line the characters do not have to
- be "inserted". They can just be placed on the screen. */
- /* However, this screws up the rest of this block, which
- assumes you've done the insert because you can. */
- _rl_output_some_chars (nfd, lendiff);
- _rl_last_c_pos += col_lendiff;
- }
- else
- {
- _rl_output_some_chars (nfd, temp);
- _rl_last_c_pos += col_temp;
- /* If nfd begins before the last invisible character in the
- prompt, adjust _rl_last_c_pos to account for wrap_offset
- and set cpos_adjusted to let the caller know. */
- if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- return;
- }
- /* Copy (new) chars to screen from first diff to last match. */
- temp = nls - nfd;
- if ((temp - lendiff) > 0)
- {
- _rl_output_some_chars (nfd + lendiff, temp - lendiff);
- /* XXX -- this bears closer inspection. Fixes a redisplay bug
- reported against bash-3.0-alpha by Andreas Schwab involving
- multibyte characters and prompt strings with invisible
- characters, but was previously disabled. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff, 1);
- else
- twidth = temp - lendiff;
- _rl_last_c_pos += twidth;
- /* If nfd begins before the last invisible character in the
- prompt, adjust _rl_last_c_pos to account for wrap_offset
- and set cpos_adjusted to let the caller know. */
- if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- }
- }
- else
- {
- /* cannot insert chars, write to EOL */
- _rl_output_some_chars (nfd, temp);
- _rl_last_c_pos += col_temp;
- /* If we're in a multibyte locale and were before the last invisible
- char in the current line (which implies we just output some invisible
- characters) we need to adjust _rl_last_c_pos, since it represents
- a physical character position. */
- if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
- current_line == prompt_last_screen_line && wrap_offset &&
- wrap_offset != prompt_invis_chars_first_line &&
- ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth))))
- {
- _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line;
- cpos_adjusted = 1;
- }
- }
- }
- else /* Delete characters from line. */
- {
- /* If possible and inexpensive to use terminal deletion, then do so. */
- if (_rl_term_dc && (2 * col_temp) >= -col_lendiff)
- {
- /* If all we're doing is erasing the invisible characters in the
- prompt string, don't bother. It screws up the assumptions
- about what's on the screen. */
- if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
- -lendiff == visible_wrap_offset)
- col_lendiff = 0;
-
- if (col_lendiff)
- delete_chars (-col_lendiff); /* delete (diff) characters */
-
- /* Copy (new) chars to screen from first diff to last match */
- temp = nls - nfd;
- if (temp > 0)
- {
- /* If nfd begins at the prompt, or before the invisible
- characters in the prompt, we need to adjust _rl_last_c_pos
- in a multibyte locale to account for the wrap offset and
- set cpos_adjusted accordingly. */
- _rl_output_some_chars (nfd, temp);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- _rl_last_c_pos += _rl_col_width (nfd, 0, temp, 1);
- if (current_line == 0 && wrap_offset && _rl_last_c_pos > wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- }
- else
- _rl_last_c_pos += temp;
- }
- }
- /* Otherwise, print over the existing material. */
- else
- {
- if (temp > 0)
- {
- /* If nfd begins at the prompt, or before the invisible
- characters in the prompt, we need to adjust _rl_last_c_pos
- in a multibyte locale to account for the wrap offset and
- set cpos_adjusted accordingly. */
- _rl_output_some_chars (nfd, temp);
- _rl_last_c_pos += col_temp; /* XXX */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- if (current_line == 0 && wrap_offset && _rl_last_c_pos > wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- }
- }
- lendiff = (oe - old) - (ne - new);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- col_lendiff = _rl_col_width (old, 0, oe - old, 1) - _rl_col_width (new, 0, ne - new, 1);
- else
- col_lendiff = lendiff;
-
-#if 0
- if (col_lendiff)
-#else
- /* If we've already printed over the entire width of the screen,
- including the old material, then col_lendiff doesn't matter and
- space_to_eol will insert too many spaces. XXX - maybe we should
- adjust col_lendiff based on the difference between _rl_last_c_pos
- and _rl_screenwidth */
- if (col_lendiff && ((MB_CUR_MAX == 1 || rl_byte_oriented) || (_rl_last_c_pos < _rl_screenwidth)))
-#endif
- {
- if (_rl_term_autowrap && current_line < inv_botlin)
- space_to_eol (col_lendiff);
- else
- _rl_clear_to_eol (col_lendiff);
- }
- }
- }
-}
-
-/* Tell the update routines that we have moved onto a new (empty) line. */
-int
-rl_on_new_line ()
-{
- if (visible_line)
- visible_line[0] = '\0';
-
- _rl_last_c_pos = _rl_last_v_pos = 0;
- _rl_vis_botlin = last_lmargin = 0;
- if (vis_lbreaks)
- vis_lbreaks[0] = vis_lbreaks[1] = 0;
- visible_wrap_offset = 0;
- return 0;
-}
-
-/* Tell the update routines that we have moved onto a new line with the
- prompt already displayed. Code originally from the version of readline
- distributed with CLISP. rl_expand_prompt must have already been called
- (explicitly or implicitly). This still doesn't work exactly right. */
-int
-rl_on_new_line_with_prompt ()
-{
- int prompt_size, i, l, real_screenwidth, newlines;
- char *prompt_last_line, *lprompt;
-
- /* Initialize visible_line and invisible_line to ensure that they can hold
- the already-displayed prompt. */
- prompt_size = strlen (rl_prompt) + 1;
- init_line_structures (prompt_size);
-
- /* Make sure the line structures hold the already-displayed prompt for
- redisplay. */
- lprompt = local_prompt ? local_prompt : rl_prompt;
- strcpy (visible_line, lprompt);
- strcpy (invisible_line, lprompt);
-
- /* If the prompt contains newlines, take the last tail. */
- prompt_last_line = strrchr (rl_prompt, '\n');
- if (!prompt_last_line)
- prompt_last_line = rl_prompt;
-
- l = strlen (prompt_last_line);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l, 1); /* XXX */
- else
- _rl_last_c_pos = l;
-
- /* Dissect prompt_last_line into screen lines. Note that here we have
- to use the real screenwidth. Readline's notion of screenwidth might be
- one less, see terminal.c. */
- real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1);
- _rl_last_v_pos = l / real_screenwidth;
- /* If the prompt length is a multiple of real_screenwidth, we don't know
- whether the cursor is at the end of the last line, or already at the
- beginning of the next line. Output a newline just to be safe. */
- if (l > 0 && (l % real_screenwidth) == 0)
- _rl_output_some_chars ("\n", 1);
- last_lmargin = 0;
-
- newlines = 0; i = 0;
- while (i <= l)
- {
- _rl_vis_botlin = newlines;
- vis_lbreaks[newlines++] = i;
- i += real_screenwidth;
- }
- vis_lbreaks[newlines] = l;
- visible_wrap_offset = 0;
-
- rl_display_prompt = rl_prompt; /* XXX - make sure it's set */
-
- return 0;
-}
-
-/* Actually update the display, period. */
-int
-rl_forced_update_display ()
-{
- register char *temp;
-
- if (visible_line)
- {
- temp = visible_line;
- while (*temp)
- *temp++ = '\0';
- }
- rl_on_new_line ();
- forced_display++;
- (*rl_redisplay_function) ();
- return 0;
-}
-
-/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
- (Well, when we don't have multibyte characters, _rl_last_c_pos is a
- buffer index.)
- DATA is the contents of the screen line of interest; i.e., where
- the movement is being done. */
-void
-_rl_move_cursor_relative (new, data)
- int new;
- const char *data;
-{
- register int i;
- int woff; /* number of invisible chars on current line */
- int cpos, dpos; /* current and desired cursor positions */
- int adjust;
-
- woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset);
- cpos = _rl_last_c_pos;
-
- if (cpos == 0 && cpos == new)
- return;
-
-#if defined (HANDLE_MULTIBYTE)
- /* If we have multibyte characters, NEW is indexed by the buffer point in
- a multibyte string, but _rl_last_c_pos is the display position. In
- this case, NEW's display position is not obvious and must be
- calculated. We need to account for invisible characters in this line,
- as long as we are past them and they are counted by _rl_col_width. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- adjust = 1;
- /* Try to short-circuit common cases and eliminate a bunch of multibyte
- character function calls. */
- /* 1. prompt string */
- if (new == local_prompt_len && memcmp (data, local_prompt, new) == 0)
- {
- dpos = prompt_physical_chars;
- cpos_adjusted = 1;
- adjust = 0;
- }
- /* 2. prompt_string + line contents */
- else if (new > local_prompt_len && local_prompt && memcmp (data, local_prompt, local_prompt_len) == 0)
- {
- dpos = prompt_physical_chars + _rl_col_width (data, local_prompt_len, new, 1);
- cpos_adjusted = 1;
- adjust = 0;
- }
- else
- dpos = _rl_col_width (data, 0, new, 1);
-
- /* Use NEW when comparing against the last invisible character in the
- prompt string, since they're both buffer indices and DPOS is a
- desired display position. */
- if (adjust && ((new > prompt_last_invisible) || /* XXX - don't use woff here */
- (prompt_physical_chars >= _rl_screenwidth &&
- _rl_last_v_pos == prompt_last_screen_line &&
- wrap_offset >= woff && dpos >= woff &&
- new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))))
- /* XXX last comparison might need to be >= */
- {
- dpos -= woff;
- /* Since this will be assigned to _rl_last_c_pos at the end (more
- precisely, _rl_last_c_pos == dpos when this function returns),
- let the caller know. */
- cpos_adjusted = 1;
- }
- }
- else
-#endif
- dpos = new;
-
- /* If we don't have to do anything, then return. */
- if (cpos == dpos)
- return;
-
- /* It may be faster to output a CR, and then move forwards instead
- of moving backwards. */
- /* i == current physical cursor position. */
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- i = _rl_last_c_pos;
- else
-#endif
- i = _rl_last_c_pos - woff;
- if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
- (_rl_term_autowrap && i == _rl_screenwidth))
- {
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif /* !__MSDOS__ */
- cpos = _rl_last_c_pos = 0;
- }
-
- if (cpos < dpos)
- {
- /* Move the cursor forward. We do it by printing the command
- to move the cursor forward if there is one, else print that
- portion of the output buffer again. Which is cheaper? */
-
- /* The above comment is left here for posterity. It is faster
- to print one character (non-control) than to print a control
- sequence telling the terminal to move forward one character.
- That kind of control is for people who don't know what the
- data is underneath the cursor. */
-
- /* However, we need a handle on where the current display position is
- in the buffer for the immediately preceding comment to be true.
- In multibyte locales, we don't currently have that info available.
- Without it, we don't know where the data we have to display begins
- in the buffer and we have to go back to the beginning of the screen
- line. In this case, we can use the terminal sequence to move forward
- if it's available. */
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- if (_rl_term_forward_char)
- {
- for (i = cpos; i < dpos; i++)
- tputs (_rl_term_forward_char, 1, _rl_output_character_function);
- }
- else
- {
- tputs (_rl_term_cr, 1, _rl_output_character_function);
- for (i = 0; i < new; i++)
- putc (data[i], rl_outstream);
- }
- }
- else
- for (i = cpos; i < new; i++)
- putc (data[i], rl_outstream);
- }
-
-#if defined (HANDLE_MULTIBYTE)
- /* NEW points to the buffer point, but _rl_last_c_pos is the display point.
- The byte length of the string is probably bigger than the column width
- of the string, which means that if NEW == _rl_last_c_pos, then NEW's
- display point is less than _rl_last_c_pos. */
-#endif
- else if (cpos > dpos)
- _rl_backspace (cpos - dpos);
-
- _rl_last_c_pos = dpos;
-}
-
-/* PWP: move the cursor up or down. */
-void
-_rl_move_vert (to)
- int to;
-{
- register int delta, i;
-
- if (_rl_last_v_pos == to || to > _rl_screenheight)
- return;
-
- if ((delta = to - _rl_last_v_pos) > 0)
- {
- for (i = 0; i < delta; i++)
- putc ('\n', rl_outstream);
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif
- _rl_last_c_pos = 0;
- }
- else
- { /* delta < 0 */
-#ifdef __DJGPP__
- int row, col;
-
- fflush (rl_outstream);
- ScreenGetCursor (&row, &col);
- ScreenSetCursor (row + delta, col);
- i = -delta;
-#else
- if (_rl_term_up && *_rl_term_up)
- for (i = 0; i < -delta; i++)
- tputs (_rl_term_up, 1, _rl_output_character_function);
-#endif /* !__DJGPP__ */
- }
-
- _rl_last_v_pos = to; /* Now TO is here */
-}
-
-/* Physically print C on rl_outstream. This is for functions which know
- how to optimize the display. Return the number of characters output. */
-int
-rl_show_char (c)
- int c;
-{
- int n = 1;
- if (META_CHAR (c) && (_rl_output_meta_chars == 0))
- {
- fprintf (rl_outstream, "M-");
- n += 2;
- c = UNMETA (c);
- }
-
-#if defined (DISPLAY_TABS)
- if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT)
-#else
- if (CTRL_CHAR (c) || c == RUBOUT)
-#endif /* !DISPLAY_TABS */
- {
- fprintf (rl_outstream, "C-");
- n += 2;
- c = CTRL_CHAR (c) ? UNCTRL (c) : '?';
- }
-
- putc (c, rl_outstream);
- fflush (rl_outstream);
- return n;
-}
-
-int
-rl_character_len (c, pos)
- register int c, pos;
-{
- unsigned char uc;
-
- uc = (unsigned char)c;
-
- if (META_CHAR (uc))
- return ((_rl_output_meta_chars == 0) ? 4 : 1);
-
- if (uc == '\t')
- {
-#if defined (DISPLAY_TABS)
- return (((pos | 7) + 1) - pos);
-#else
- return (2);
-#endif /* !DISPLAY_TABS */
- }
-
- if (CTRL_CHAR (c) || c == RUBOUT)
- return (2);
-
- return ((ISPRINT (uc)) ? 1 : 2);
-}
-/* How to print things in the "echo-area". The prompt is treated as a
- mini-modeline. */
-static int msg_saved_prompt = 0;
-
-#if defined (USE_VARARGS)
-int
-#if defined (PREFER_STDARG)
-rl_message (const char *format, ...)
-#else
-rl_message (va_alist)
- va_dcl
-#endif
-{
- va_list args;
-#if defined (PREFER_VARARGS)
- char *format;
-#endif
-#if defined (HAVE_VSNPRINTF)
- int bneed;
-#endif
-
-#if defined (PREFER_STDARG)
- va_start (args, format);
-#else
- va_start (args);
- format = va_arg (args, char *);
-#endif
-
- if (msg_buf == 0)
- msg_buf = xmalloc (msg_bufsiz = 128);
-
-#if defined (HAVE_VSNPRINTF)
- bneed = vsnprintf (msg_buf, msg_bufsiz - 1, format, args);
- if (bneed >= msg_bufsiz - 1)
- {
- msg_bufsiz = bneed + 1;
- msg_buf = xrealloc (msg_buf, msg_bufsiz);
- va_end (args);
-
-#if defined (PREFER_STDARG)
- va_start (args, format);
-#else
- va_start (args);
- format = va_arg (args, char *);
-#endif
- vsnprintf (msg_buf, msg_bufsiz - 1, format, args);
- }
-#else
- vsprintf (msg_buf, format, args);
- msg_buf[msg_bufsiz - 1] = '\0'; /* overflow? */
-#endif
- va_end (args);
-
- if (saved_local_prompt == 0)
- {
- rl_save_prompt ();
- msg_saved_prompt = 1;
- }
- rl_display_prompt = msg_buf;
- local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
- &prompt_last_invisible,
- &prompt_invis_chars_first_line,
- &prompt_physical_chars);
- local_prompt_prefix = (char *)NULL;
- local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
- (*rl_redisplay_function) ();
-
- return 0;
-}
-#else /* !USE_VARARGS */
-int
-rl_message (format, arg1, arg2)
- char *format;
-{
- if (msg_buf == 0)
- msg_buf = xmalloc (msg_bufsiz = 128);
-
- sprintf (msg_buf, format, arg1, arg2);
- msg_buf[msg_bufsiz - 1] = '\0'; /* overflow? */
-
- rl_display_prompt = msg_buf;
- if (saved_local_prompt == 0)
- {
- rl_save_prompt ();
- msg_saved_prompt = 1;
- }
- local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
- &prompt_last_invisible,
- &prompt_invis_chars_first_line,
- &prompt_physical_chars);
- local_prompt_prefix = (char *)NULL;
- local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
- (*rl_redisplay_function) ();
-
- return 0;
-}
-#endif /* !USE_VARARGS */
-
-/* How to clear things from the "echo-area". */
-int
-rl_clear_message ()
-{
- rl_display_prompt = rl_prompt;
- if (msg_saved_prompt)
- {
- rl_restore_prompt ();
- msg_saved_prompt = 0;
- }
- (*rl_redisplay_function) ();
- return 0;
-}
-
-int
-rl_reset_line_state ()
-{
- rl_on_new_line ();
-
- rl_display_prompt = rl_prompt ? rl_prompt : "";
- forced_display = 1;
- return 0;
-}
-
-void
-rl_save_prompt ()
-{
- saved_local_prompt = local_prompt;
- saved_local_prefix = local_prompt_prefix;
- saved_prefix_length = prompt_prefix_length;
- saved_local_length = local_prompt_len;
- saved_last_invisible = prompt_last_invisible;
- saved_visible_length = prompt_visible_length;
- saved_invis_chars_first_line = prompt_invis_chars_first_line;
- saved_physical_chars = prompt_physical_chars;
-
- local_prompt = local_prompt_prefix = (char *)0;
- local_prompt_len = 0;
- prompt_last_invisible = prompt_visible_length = prompt_prefix_length = 0;
- prompt_invis_chars_first_line = prompt_physical_chars = 0;
-}
-
-void
-rl_restore_prompt ()
-{
- FREE (local_prompt);
- FREE (local_prompt_prefix);
-
- local_prompt = saved_local_prompt;
- local_prompt_prefix = saved_local_prefix;
- local_prompt_len = saved_local_length;
- prompt_prefix_length = saved_prefix_length;
- prompt_last_invisible = saved_last_invisible;
- prompt_visible_length = saved_visible_length;
- prompt_invis_chars_first_line = saved_invis_chars_first_line;
- prompt_physical_chars = saved_physical_chars;
-
- /* can test saved_local_prompt to see if prompt info has been saved. */
- saved_local_prompt = saved_local_prefix = (char *)0;
- saved_local_length = 0;
- saved_last_invisible = saved_visible_length = saved_prefix_length = 0;
- saved_invis_chars_first_line = saved_physical_chars = 0;
-}
-
-char *
-_rl_make_prompt_for_search (pchar)
- int pchar;
-{
- int len;
- char *pmt, *p;
-
- rl_save_prompt ();
-
- /* We've saved the prompt, and can do anything with the various prompt
- strings we need before they're restored. We want the unexpanded
- portion of the prompt string after any final newline. */
- p = rl_prompt ? strrchr (rl_prompt, '\n') : 0;
- if (p == 0)
- {
- len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
- pmt = (char *)xmalloc (len + 2);
- if (len)
- strcpy (pmt, rl_prompt);
- pmt[len] = pchar;
- pmt[len+1] = '\0';
- }
- else
- {
- p++;
- len = strlen (p);
- pmt = (char *)xmalloc (len + 2);
- if (len)
- strcpy (pmt, p);
- pmt[len] = pchar;
- pmt[len+1] = '\0';
- }
-
- /* will be overwritten by expand_prompt, called from rl_message */
- prompt_physical_chars = saved_physical_chars + 1;
- return pmt;
-}
-
-/* Quick redisplay hack when erasing characters at the end of the line. */
-void
-_rl_erase_at_end_of_line (l)
- int l;
-{
- register int i;
-
- _rl_backspace (l);
- for (i = 0; i < l; i++)
- putc (' ', rl_outstream);
- _rl_backspace (l);
- for (i = 0; i < l; i++)
- visible_line[--_rl_last_c_pos] = '\0';
- rl_display_fixed++;
-}
-
-/* Clear to the end of the line. COUNT is the minimum
- number of character spaces to clear, */
-void
-_rl_clear_to_eol (count)
- int count;
-{
-#ifndef __MSDOS__
- if (_rl_term_clreol)
- tputs (_rl_term_clreol, 1, _rl_output_character_function);
- else
-#endif
- if (count)
- space_to_eol (count);
-}
-
-/* Clear to the end of the line using spaces. COUNT is the minimum
- number of character spaces to clear, */
-static void
-space_to_eol (count)
- int count;
-{
- register int i;
-
- for (i = 0; i < count; i++)
- putc (' ', rl_outstream);
-
- _rl_last_c_pos += count;
-}
-
-void
-_rl_clear_screen ()
-{
-#ifndef __DJGPP__
- if (_rl_term_clrpag)
- tputs (_rl_term_clrpag, 1, _rl_output_character_function);
- else
- rl_crlf ();
-#else
- ScreenClear ();
- ScreenSetCursor (0, 0);
-#endif /* __DJGPP__ */
-}
-
-/* Insert COUNT characters from STRING to the output stream at column COL. */
-static void
-insert_some_chars (string, count, col)
- char *string;
- int count, col;
-{
-#if defined (__MSDOS__) || defined (__MINGW32__)
- _rl_output_some_chars (string, count);
-#else
- /* DEBUGGING */
- if (MB_CUR_MAX == 1 || rl_byte_oriented)
- if (count != col)
- _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", count, col);
-
- /* If IC is defined, then we do not have to "enter" insert mode. */
- if (_rl_term_IC)
- {
- char *buffer;
-
- buffer = tgoto (_rl_term_IC, 0, col);
- tputs (buffer, 1, _rl_output_character_function);
- _rl_output_some_chars (string, count);
- }
- else
- {
- register int i;
-
- /* If we have to turn on insert-mode, then do so. */
- if (_rl_term_im && *_rl_term_im)
- tputs (_rl_term_im, 1, _rl_output_character_function);
-
- /* If there is a special command for inserting characters, then
- use that first to open up the space. */
- if (_rl_term_ic && *_rl_term_ic)
- {
- for (i = col; i--; )
- tputs (_rl_term_ic, 1, _rl_output_character_function);
- }
-
- /* Print the text. */
- _rl_output_some_chars (string, count);
-
- /* If there is a string to turn off insert mode, we had best use
- it now. */
- if (_rl_term_ei && *_rl_term_ei)
- tputs (_rl_term_ei, 1, _rl_output_character_function);
- }
-#endif /* __MSDOS__ || __MINGW32__ */
-}
-
-/* Delete COUNT characters from the display line. */
-static void
-delete_chars (count)
- int count;
-{
- if (count > _rl_screenwidth) /* XXX */
- return;
-
-#if !defined (__MSDOS__) && !defined (__MINGW32__)
- if (_rl_term_DC && *_rl_term_DC)
- {
- char *buffer;
- buffer = tgoto (_rl_term_DC, count, count);
- tputs (buffer, count, _rl_output_character_function);
- }
- else
- {
- if (_rl_term_dc && *_rl_term_dc)
- while (count--)
- tputs (_rl_term_dc, 1, _rl_output_character_function);
- }
-#endif /* !__MSDOS__ && !__MINGW32__ */
-}
-
-void
-_rl_update_final ()
-{
- int full_lines;
-
- full_lines = 0;
- /* If the cursor is the only thing on an otherwise-blank last line,
- compensate so we don't print an extra CRLF. */
- if (_rl_vis_botlin && _rl_last_c_pos == 0 &&
- visible_line[vis_lbreaks[_rl_vis_botlin]] == 0)
- {
- _rl_vis_botlin--;
- full_lines = 1;
- }
- _rl_move_vert (_rl_vis_botlin);
- /* If we've wrapped lines, remove the final xterm line-wrap flag. */
- if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth))
- {
- char *last_line;
-
- last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
- cpos_buffer_position = -1; /* don't know where we are in buffer */
- _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */
- _rl_clear_to_eol (0);
- putc (last_line[_rl_screenwidth - 1], rl_outstream);
- }
- _rl_vis_botlin = 0;
- rl_crlf ();
- fflush (rl_outstream);
- rl_display_fixed++;
-}
-
-/* Move to the start of the current line. */
-static void
-cr ()
-{
- if (_rl_term_cr)
- {
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif
- _rl_last_c_pos = 0;
- }
-}
-
-/* Redraw the last line of a multi-line prompt that may possibly contain
- terminal escape sequences. Called with the cursor at column 0 of the
- line to draw the prompt on. */
-static void
-redraw_prompt (t)
- char *t;
-{
- char *oldp;
-
- oldp = rl_display_prompt;
- rl_save_prompt ();
-
- rl_display_prompt = t;
- local_prompt = expand_prompt (t, &prompt_visible_length,
- &prompt_last_invisible,
- &prompt_invis_chars_first_line,
- &prompt_physical_chars);
- local_prompt_prefix = (char *)NULL;
- local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
-
- rl_forced_update_display ();
-
- rl_display_prompt = oldp;
- rl_restore_prompt();
-}
-
-/* Redisplay the current line after a SIGWINCH is received. */
-void
-_rl_redisplay_after_sigwinch ()
-{
- char *t;
-
- /* Clear the last line (assuming that the screen size change will result in
- either more or fewer characters on that line only) and put the cursor at
- column 0. Make sure the right thing happens if we have wrapped to a new
- screen line. */
- if (_rl_term_cr)
- {
- _rl_move_vert (_rl_vis_botlin);
-
-#if defined (__MSDOS__)
- putc ('\r', rl_outstream);
-#else
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif
- _rl_last_c_pos = 0;
-#if defined (__MSDOS__)
- space_to_eol (_rl_screenwidth);
- putc ('\r', rl_outstream);
-#else
- if (_rl_term_clreol)
- tputs (_rl_term_clreol, 1, _rl_output_character_function);
- else
- {
- space_to_eol (_rl_screenwidth);
- tputs (_rl_term_cr, 1, _rl_output_character_function);
- }
-#endif
- if (_rl_last_v_pos > 0)
- _rl_move_vert (0);
- }
- else
- rl_crlf ();
-
- /* Redraw only the last line of a multi-line prompt. */
- t = strrchr (rl_display_prompt, '\n');
- if (t)
- redraw_prompt (++t);
- else
- rl_forced_update_display ();
-}
-
-void
-_rl_clean_up_for_exit ()
-{
- if (_rl_echoing_p)
- {
- _rl_move_vert (_rl_vis_botlin);
- _rl_vis_botlin = 0;
- fflush (rl_outstream);
- rl_restart_output (1, 0);
- }
-}
-
-void
-_rl_erase_entire_line ()
-{
- cr ();
- _rl_clear_to_eol (0);
- cr ();
- fflush (rl_outstream);
-}
-
-/* return the `current display line' of the cursor -- the number of lines to
- move up to get to the first screen line of the current readline line. */
-int
-_rl_current_display_line ()
-{
- int ret, nleft;
-
- /* Find out whether or not there might be invisible characters in the
- editing buffer. */
- if (rl_display_prompt == rl_prompt)
- nleft = _rl_last_c_pos - _rl_screenwidth - rl_visible_prompt_length;
- else
- nleft = _rl_last_c_pos - _rl_screenwidth;
-
- if (nleft > 0)
- ret = 1 + nleft / _rl_screenwidth;
- else
- ret = 0;
-
- return ret;
-}
-
-#if defined (HANDLE_MULTIBYTE)
-/* Calculate the number of screen columns occupied by STR from START to END.
- In the case of multibyte characters with stateful encoding, we have to
- scan from the beginning of the string to take the state into account. */
-static int
-_rl_col_width (str, start, end, flags)
- const char *str;
- int start, end, flags;
-{
- wchar_t wc;
- mbstate_t ps;
- int tmp, point, width, max;
-
- if (end <= start)
- return 0;
- if (MB_CUR_MAX == 1 || rl_byte_oriented)
-{
-_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1");
- return (end - start);
-}
-
- memset (&ps, 0, sizeof (mbstate_t));
-
- point = 0;
- max = end;
-
- /* Try to short-circuit common cases. The adjustment to remove wrap_offset
- is done by the caller. */
- /* 1. prompt string */
- if (flags && start == 0 && end == local_prompt_len && memcmp (str, local_prompt, local_prompt_len) == 0)
- return (prompt_physical_chars + wrap_offset);
- /* 2. prompt string + line contents */
- else if (flags && start == 0 && local_prompt_len > 0 && end > local_prompt_len && local_prompt && memcmp (str, local_prompt, local_prompt_len) == 0)
- {
- tmp = prompt_physical_chars + wrap_offset;
- /* XXX - try to call ourselves recursively with non-prompt portion */
- tmp += _rl_col_width (str, local_prompt_len, end, flags);
- return (tmp);
- }
-
- while (point < start)
- {
- tmp = mbrlen (str + point, max, &ps);
- if (MB_INVALIDCH ((size_t)tmp))
- {
- /* In this case, the bytes are invalid or too short to compose a
- multibyte character, so we assume that the first byte represents
- a single character. */
- point++;
- max--;
-
- /* 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 (MB_NULLWCH (tmp))
- break; /* Found '\0' */
- else
- {
- point += tmp;
- max -= tmp;
- }
- }
-
- /* If START is not a byte that starts a character, then POINT will be
- greater than START. In this case, assume that (POINT - START) gives
- a byte count that is the number of columns of difference. */
- width = point - start;
-
- while (point < end)
- {
- tmp = mbrtowc (&wc, str + point, max, &ps);
- if (MB_INVALIDCH ((size_t)tmp))
- {
- /* In this case, the bytes are invalid or too short to compose a
- multibyte character, so we assume that the first byte represents
- a single character. */
- point++;
- max--;
-
- /* and assume that the byte occupies a single column. */
- width++;
-
- /* 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 (MB_NULLWCH (tmp))
- break; /* Found '\0' */
- else
- {
- point += tmp;
- max -= tmp;
- tmp = WCWIDTH(wc);
- width += (tmp >= 0) ? tmp : 1;
- }
- }
-
- width += point - end;
-
- return width;
-}
-#endif /* HANDLE_MULTIBYTE */
+++ /dev/null
-# 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
+++ /dev/null
-@comment %**start of header (This is for running Texinfo on a region.)
-@setfilename rltech.info
-@comment %**end of header (This is for running Texinfo on a region.)
-
-@ifinfo
-This document describes the GNU Readline Library, a utility for aiding
-in the consistency of user interface across discrete programs that need
-to provide a command line interface.
-
-Copyright (C) 1988--2012 Free Software Foundation, Inc.
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-pare preserved on all copies.
-
-@ignore
-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).
-@end ignore
-
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, 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,
-except that this permission notice may be stated in a translation approved
-by the Foundation.
-@end ifinfo
-
-@node Programming with GNU Readline
-@chapter Programming with GNU Readline
-
-This chapter describes the interface between the @sc{gnu} Readline Library and
-other programs. If you are a programmer, and you wish to include the
-features found in @sc{gnu} Readline
-such as completion, line editing, and interactive history manipulation
-in your own programs, this section is for you.
-
-@menu
-* Basic Behavior:: Using the default behavior of Readline.
-* Custom Functions:: Adding your own functions to Readline.
-* Readline Variables:: Variables accessible to custom
- functions.
-* Readline Convenience Functions:: Functions which Readline supplies to
- aid in writing your own custom
- functions.
-* Readline Signal Handling:: How Readline behaves when it receives signals.
-* Custom Completers:: Supplanting or supplementing Readline's
- completion functions.
-@end menu
-
-@node Basic Behavior
-@section Basic Behavior
-
-Many programs provide a command line interface, such as @code{mail},
-@code{ftp}, and @code{sh}. For such programs, the default behaviour of
-Readline is sufficient. This section describes how to use Readline in
-the simplest way possible, perhaps to replace calls in your code to
-@code{gets()} or @code{fgets()}.
-
-@findex readline
-@cindex readline, function
-
-The function @code{readline()} prints a prompt @var{prompt}
-and then reads and returns a single line of text from the user.
-If @var{prompt} is @code{NULL} or the empty string, no prompt is displayed.
-The line @code{readline} returns is allocated with @code{malloc()};
-the caller should @code{free()} the line when it has finished with it.
-The declaration for @code{readline} in ANSI C is
-
-@example
-@code{char *readline (const char *@var{prompt});}
-@end example
-
-@noindent
-So, one might say
-@example
-@code{char *line = readline ("Enter a line: ");}
-@end example
-@noindent
-in order to read a line of text from the user.
-The line returned has the final newline removed, so only the
-text remains.
-
-If @code{readline} encounters an @code{EOF} while reading the line, and the
-line is empty at that point, then @code{(char *)NULL} is returned.
-Otherwise, the line is ended just as if a newline had been typed.
-
-If you want the user to be able to get at the line later, (with
-@key{C-p} for example), you must call @code{add_history()} to save the
-line away in a @dfn{history} list of such lines.
-
-@example
-@code{add_history (line)};
-@end example
-
-@noindent
-For full details on the GNU History Library, see the associated manual.
-
-It is preferable to avoid saving empty lines on the history list, since
-users rarely have a burning need to reuse a blank line. Here is
-a function which usefully replaces the standard @code{gets()} library
-function, and has the advantage of no static buffer to overflow:
-
-@example
-/* A static variable for holding the line. */
-static char *line_read = (char *)NULL;
-
-/* Read a string, and return a pointer to it.
- Returns NULL on EOF. */
-char *
-rl_gets ()
-@{
- /* If the buffer has already been allocated,
- return the memory to the free pool. */
- if (line_read)
- @{
- free (line_read);
- line_read = (char *)NULL;
- @}
-
- /* Get a line from the user. */
- line_read = readline ("");
-
- /* If the line has any text in it,
- save it on the history. */
- if (line_read && *line_read)
- add_history (line_read);
-
- return (line_read);
-@}
-@end example
-
-This function gives the user the default behaviour of @key{TAB}
-completion: completion on file names. If you do not want Readline to
-complete on filenames, you can change the binding of the @key{TAB} key
-with @code{rl_bind_key()}.
-
-@example
-@code{int rl_bind_key (int @var{key}, rl_command_func_t *@var{function});}
-@end example
-
-@code{rl_bind_key()} takes two arguments: @var{key} is the character that
-you want to bind, and @var{function} is the address of the function to
-call when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert()}
-makes @key{TAB} insert itself.
-@code{rl_bind_key()} returns non-zero if @var{key} is not a valid
-ASCII character code (between 0 and 255).
-
-Thus, to disable the default @key{TAB} behavior, the following suffices:
-@example
-@code{rl_bind_key ('\t', rl_insert);}
-@end example
-
-This code should be executed once at the start of your program; you
-might write a function called @code{initialize_readline()} which
-performs this and other desired initializations, such as installing
-custom completers (@pxref{Custom Completers}).
-
-@node Custom Functions
-@section Custom Functions
-
-Readline provides many functions for manipulating the text of
-the line, but it isn't possible to anticipate the needs of all
-programs. This section describes the various functions and variables
-defined within the Readline library which allow a user program to add
-customized functionality to Readline.
-
-Before declaring any functions that customize Readline's behavior, or
-using any functionality Readline provides in other code, an
-application writer should include the file @code{<readline/readline.h>}
-in any file that uses Readline's features. Since some of the definitions
-in @code{readline.h} use the @code{stdio} library, the file
-@code{<stdio.h>} should be included before @code{readline.h}.
-
-@code{readline.h} defines a C preprocessor variable that should
-be treated as an integer, @code{RL_READLINE_VERSION}, which may
-be used to conditionally compile application code depending on
-the installed Readline version. The value is a hexadecimal
-encoding of the major and minor version numbers of the library,
-of the form 0x@var{MMmm}. @var{MM} is the two-digit major
-version number; @var{mm} is the two-digit minor version number.
-For Readline 4.2, for example, the value of
-@code{RL_READLINE_VERSION} would be @code{0x0402}.
-
-@menu
-* Readline Typedefs:: C declarations to make code readable.
-* Function Writing:: Variables and calling conventions.
-@end menu
-
-@node Readline Typedefs
-@subsection Readline Typedefs
-
-For readabilty, we declare a number of new object types, all pointers
-to functions.
-
-The reason for declaring these new types is to make it easier to write
-code describing pointers to C functions with appropriately prototyped
-arguments and return values.
-
-For instance, say we want to declare a variable @var{func} as a pointer
-to a function which takes two @code{int} arguments and returns an
-@code{int} (this is the type of all of the Readline bindable functions).
-Instead of the classic C declaration
-
-@code{int (*func)();}
-
-@noindent
-or the ANSI-C style declaration
-
-@code{int (*func)(int, int);}
-
-@noindent
-we may write
-
-@code{rl_command_func_t *func;}
-
-The full list of function pointer types available is
-
-@table @code
-@item typedef int rl_command_func_t (int, int);
-
-@item typedef char *rl_compentry_func_t (const char *, int);
-
-@item typedef char **rl_completion_func_t (const char *, int, int);
-
-@item typedef char *rl_quote_func_t (char *, int, char *);
-
-@item typedef char *rl_dequote_func_t (char *, int);
-
-@item typedef int rl_compignore_func_t (char **);
-
-@item typedef void rl_compdisp_func_t (char **, int, int);
-
-@item typedef int rl_hook_func_t (void);
-
-@item typedef int rl_getc_func_t (FILE *);
-
-@item typedef int rl_linebuf_func_t (char *, int);
-
-@item typedef int rl_intfunc_t (int);
-@item #define rl_ivoidfunc_t rl_hook_func_t
-@item typedef int rl_icpfunc_t (char *);
-@item typedef int rl_icppfunc_t (char **);
-
-@item typedef void rl_voidfunc_t (void);
-@item typedef void rl_vintfunc_t (int);
-@item typedef void rl_vcpfunc_t (char *);
-@item typedef void rl_vcppfunc_t (char **);
-
-@end table
-
-@node Function Writing
-@subsection Writing a New Function
-
-In order to write new functions for Readline, you need to know the
-calling conventions for keyboard-invoked functions, and the names of the
-variables that describe the current state of the line read so far.
-
-The calling sequence for a command @code{foo} looks like
-
-@example
-@code{int foo (int count, int key)}
-@end example
-
-@noindent
-where @var{count} is the numeric argument (or 1 if defaulted) and
-@var{key} is the key that invoked this function.
-
-It is completely up to the function as to what should be done with the
-numeric argument. Some functions use it as a repeat count, some
-as a flag, and others to choose alternate behavior (refreshing the current
-line as opposed to refreshing the screen, for example). Some choose to
-ignore it. In general, if a
-function uses the numeric argument as a repeat count, it should be able
-to do something useful with both negative and positive arguments.
-At the very least, it should be aware that it can be passed a
-negative argument.
-
-A command function should return 0 if its action completes successfully,
-and a non-zero value if some error occurs.
-This is the convention obeyed by all of the builtin Readline bindable
-command functions.
-
-@node Readline Variables
-@section Readline Variables
-
-These variables are available to function writers.
-
-@deftypevar {char *} rl_line_buffer
-This is the line gathered so far. You are welcome to modify the
-contents of the line, but see @ref{Allowing Undoing}. The
-function @code{rl_extend_line_buffer} is available to increase
-the memory allocated to @code{rl_line_buffer}.
-@end deftypevar
-
-@deftypevar int rl_point
-The offset of the current cursor position in @code{rl_line_buffer}
-(the @emph{point}).
-@end deftypevar
-
-@deftypevar int rl_end
-The number of characters present in @code{rl_line_buffer}. When
-@code{rl_point} is at the end of the line, @code{rl_point} and
-@code{rl_end} are equal.
-@end deftypevar
-
-@deftypevar int rl_mark
-The @var{mark} (saved position) in the current line. If set, the mark
-and point define a @emph{region}.
-@end deftypevar
-
-@deftypevar int rl_done
-Setting this to a non-zero value causes Readline to return the current
-line immediately.
-@end deftypevar
-
-@deftypevar int rl_num_chars_to_read
-Setting this to a positive value before calling @code{readline()} causes
-Readline to return after accepting that many characters, rather
-than reading up to a character bound to @code{accept-line}.
-@end deftypevar
-
-@deftypevar int rl_pending_input
-Setting this to a value makes it the next keystroke read. This is a
-way to stuff a single character into the input stream.
-@end deftypevar
-
-@deftypevar int rl_dispatching
-Set to a non-zero value if a function is being called from a key binding;
-zero otherwise. Application functions can test this to discover whether
-they were called directly or by Readline's dispatching mechanism.
-@end deftypevar
-
-@deftypevar int rl_erase_empty_line
-Setting this to a non-zero value causes Readline to completely erase
-the current line, including any prompt, any time a newline is typed as
-the only character on an otherwise-empty line. The cursor is moved to
-the beginning of the newly-blank line.
-@end deftypevar
-
-@deftypevar {char *} rl_prompt
-The prompt Readline uses. This is set from the argument to
-@code{readline()}, and should not be assigned to directly.
-The @code{rl_set_prompt()} function (@pxref{Redisplay}) may
-be used to modify the prompt string after calling @code{readline()}.
-@end deftypevar
-
-@deftypevar {char *} rl_display_prompt
-The string displayed as the prompt. This is usually identical to
-@var{rl_prompt}, but may be changed temporarily by functions that
-use the prompt string as a message area, such as incremental search.
-@end deftypevar
-
-@deftypevar int rl_already_prompted
-If an application wishes to display the prompt itself, rather than have
-Readline do it the first time @code{readline()} is called, it should set
-this variable to a non-zero value after displaying the prompt.
-The prompt must also be passed as the argument to @code{readline()} so
-the redisplay functions can update the display properly.
-The calling application is responsible for managing the value; Readline
-never sets it.
-@end deftypevar
-
-@deftypevar {const char *} rl_library_version
-The version number of this revision of the library.
-@end deftypevar
-
-@deftypevar int rl_readline_version
-An integer encoding the current version of the library. The encoding is
-of the form 0x@var{MMmm}, where @var{MM} is the two-digit major version
-number, and @var{mm} is the two-digit minor version number.
-For example, for Readline-4.2, @code{rl_readline_version} would have the
-value 0x0402.
-@end deftypevar
-
-@deftypevar {int} rl_gnu_readline_p
-Always set to 1, denoting that this is @sc{gnu} readline rather than some
-emulation.
-@end deftypevar
-
-@deftypevar {const char *} rl_terminal_name
-The terminal type, used for initialization. If not set by the application,
-Readline sets this to the value of the @env{TERM} environment variable
-the first time it is called.
-@end deftypevar
-
-@deftypevar {const char *} rl_readline_name
-This variable is set to a unique name by each application using Readline.
-The value allows conditional parsing of the inputrc file
-(@pxref{Conditional Init Constructs}).
-@end deftypevar
-
-@deftypevar {FILE *} rl_instream
-The stdio stream from which Readline reads input.
-If @code{NULL}, Readline defaults to @var{stdin}.
-@end deftypevar
-
-@deftypevar {FILE *} rl_outstream
-The stdio stream to which Readline performs output.
-If @code{NULL}, Readline defaults to @var{stdout}.
-@end deftypevar
-
-@deftypevar int rl_prefer_env_winsize
-If non-zero, Readline gives values found in the @env{LINES} and
-@env{COLUMNS} environment variables greater precedence than values fetched
-from the kernel when computing the screen dimensions.
-@end deftypevar
-
-@deftypevar {rl_command_func_t *} rl_last_func
-The address of the last command function Readline executed. May be used to
-test whether or not a function is being executed twice in succession, for
-example.
-@end deftypevar
-
-@deftypevar {rl_hook_func_t *} rl_startup_hook
-If non-zero, this is the address of a function to call just
-before @code{readline} prints the first prompt.
-@end deftypevar
-
-@deftypevar {rl_hook_func_t *} rl_pre_input_hook
-If non-zero, this is the address of a function to call after
-the first prompt has been printed and just before @code{readline}
-starts reading input characters.
-@end deftypevar
-
-@deftypevar {rl_hook_func_t *} rl_event_hook
-If non-zero, this is the address of a function to call periodically
-when Readline is waiting for terminal input.
-By default, this will be called at most ten times a second if there
-is no keyboard input.
-@end deftypevar
-
-@deftypevar {rl_getc_func_t *} rl_getc_function
-If non-zero, Readline will call indirectly through this pointer
-to get a character from the input stream. By default, it is set to
-@code{rl_getc}, the default Readline character input function
-(@pxref{Character Input}).
-@end deftypevar
-
-@deftypevar {rl_voidfunc_t *} rl_redisplay_function
-If non-zero, Readline will call indirectly through this pointer
-to update the display with the current contents of the editing buffer.
-By default, it is set to @code{rl_redisplay}, the default Readline
-redisplay function (@pxref{Redisplay}).
-@end deftypevar
-
-@deftypevar {rl_vintfunc_t *} rl_prep_term_function
-If non-zero, Readline will call indirectly through this pointer
-to initialize the terminal. The function takes a single argument, an
-@code{int} flag that says whether or not to use eight-bit characters.
-By default, this is set to @code{rl_prep_terminal}
-(@pxref{Terminal Management}).
-@end deftypevar
-
-@deftypevar {rl_voidfunc_t *} rl_deprep_term_function
-If non-zero, Readline will call indirectly through this pointer
-to reset the terminal. This function should undo the effects of
-@code{rl_prep_term_function}.
-By default, this is set to @code{rl_deprep_terminal}
-(@pxref{Terminal Management}).
-@end deftypevar
-
-@deftypevar {Keymap} rl_executing_keymap
-This variable is set to the keymap (@pxref{Keymaps}) in which the
-currently executing readline function was found.
-@end deftypevar
-
-@deftypevar {Keymap} rl_binding_keymap
-This variable is set to the keymap (@pxref{Keymaps}) in which the
-last key binding occurred.
-@end deftypevar
-
-@deftypevar {char *} rl_executing_macro
-This variable is set to the text of any currently-executing macro.
-@end deftypevar
-
-@deftypevar int rl_executing_key
-The key that caused the dispatch to the currently-executing Readline function.
-@end deftypevar
-
-@deftypevar {char *} rl_executing_keyseq
-The full key sequence that caused the dispatch to the currently-executing
-Readline function.
-@end deftypevar
-
-@deftypevar int rl_key_sequence_length
-The number of characters in @var{rl_executing_keyseq}.
-@end deftypevar
-
-@deftypevar {int} rl_readline_state
-A variable with bit values that encapsulate the current Readline state.
-A bit is set with the @code{RL_SETSTATE} macro, and unset with the
-@code{RL_UNSETSTATE} macro. Use the @code{RL_ISSTATE} macro to test
-whether a particular state bit is set. Current state bits include:
-
-@table @code
-@item RL_STATE_NONE
-Readline has not yet been called, nor has it begun to intialize.
-@item RL_STATE_INITIALIZING
-Readline is initializing its internal data structures.
-@item RL_STATE_INITIALIZED
-Readline has completed its initialization.
-@item RL_STATE_TERMPREPPED
-Readline has modified the terminal modes to do its own input and redisplay.
-@item RL_STATE_READCMD
-Readline is reading a command from the keyboard.
-@item RL_STATE_METANEXT
-Readline is reading more input after reading the meta-prefix character.
-@item RL_STATE_DISPATCHING
-Readline is dispatching to a command.
-@item RL_STATE_MOREINPUT
-Readline is reading more input while executing an editing command.
-@item RL_STATE_ISEARCH
-Readline is performing an incremental history search.
-@item RL_STATE_NSEARCH
-Readline is performing a non-incremental history search.
-@item RL_STATE_SEARCH
-Readline is searching backward or forward through the history for a string.
-@item RL_STATE_NUMERICARG
-Readline is reading a numeric argument.
-@item RL_STATE_MACROINPUT
-Readline is currently getting its input from a previously-defined keyboard
-macro.
-@item RL_STATE_MACRODEF
-Readline is currently reading characters defining a keyboard macro.
-@item RL_STATE_OVERWRITE
-Readline is in overwrite mode.
-@item RL_STATE_COMPLETING
-Readline is performing word completion.
-@item RL_STATE_SIGHANDLER
-Readline is currently executing the readline signal handler.
-@item RL_STATE_UNDOING
-Readline is performing an undo.
-@item RL_STATE_INPUTPENDING
-Readline has input pending due to a call to @code{rl_execute_next()}.
-@item RL_STATE_TTYCSAVED
-Readline has saved the values of the terminal's special characters.
-@item RL_STATE_CALLBACK
-Readline is currently using the alternate (callback) interface
-(@pxref{Alternate Interface}).
-@item RL_STATE_VIMOTION
-Readline is reading the argument to a vi-mode "motion" command.
-@item RL_STATE_MULTIKEY
-Readline is reading a multiple-keystroke command.
-@item RL_STATE_VICMDONCE
-Readline has entered vi command (movement) mode at least one time during
-the current call to @code{readline()}.
-@item RL_STATE_DONE
-Readline has read a key sequence bound to @code{accept-line}
-and is about to return the line to the caller.
-@end table
-
-@end deftypevar
-
-@deftypevar {int} rl_explicit_arg
-Set to a non-zero value if an explicit numeric argument was specified by
-the user. Only valid in a bindable command function.
-@end deftypevar
-
-@deftypevar {int} rl_numeric_arg
-Set to the value of any numeric argument explicitly specified by the user
-before executing the current Readline function. Only valid in a bindable
-command function.
-@end deftypevar
-
-@deftypevar {int} rl_editing_mode
-Set to a value denoting Readline's current editing mode. A value of
-@var{1} means Readline is currently in emacs mode; @var{0}
-means that vi mode is active.
-@end deftypevar
-
-
-@node Readline Convenience Functions
-@section Readline Convenience Functions
-
-@menu
-* Function Naming:: How to give a function you write a name.
-* Keymaps:: Making keymaps.
-* Binding Keys:: Changing Keymaps.
-* Associating Function Names and Bindings:: Translate function names to
- key sequences.
-* Allowing Undoing:: How to make your functions undoable.
-* Redisplay:: Functions to control line display.
-* Modifying Text:: Functions to modify @code{rl_line_buffer}.
-* Character Input:: Functions to read keyboard input.
-* Terminal Management:: Functions to manage terminal settings.
-* Utility Functions:: Generally useful functions and hooks.
-* Miscellaneous Functions:: Functions that don't fall into any category.
-* Alternate Interface:: Using Readline in a `callback' fashion.
-* A Readline Example:: An example Readline function.
-@end menu
-
-@node Function Naming
-@subsection Naming a Function
-
-The user can dynamically change the bindings of keys while using
-Readline. This is done by representing the function with a descriptive
-name. The user is able to type the descriptive name when referring to
-the function. Thus, in an init file, one might find
-
-@example
-Meta-Rubout: backward-kill-word
-@end example
-
-This binds the keystroke @key{Meta-Rubout} to the function
-@emph{descriptively} named @code{backward-kill-word}. You, as the
-programmer, should bind the functions you write to descriptive names as
-well. Readline provides a function for doing that:
-
-@deftypefun int rl_add_defun (const char *name, rl_command_func_t *function, int key)
-Add @var{name} to the list of named functions. Make @var{function} be
-the function that gets called. If @var{key} is not -1, then bind it to
-@var{function} using @code{rl_bind_key()}.
-@end deftypefun
-
-Using this function alone is sufficient for most applications.
-It is the recommended way to add a few functions to the default
-functions that Readline has built in.
-If you need to do something other than adding a function to Readline,
-you may need to use the underlying functions described below.
-
-@node Keymaps
-@subsection Selecting a Keymap
-
-Key bindings take place on a @dfn{keymap}. The keymap is the
-association between the keys that the user types and the functions that
-get run. You can make your own keymaps, copy existing keymaps, and tell
-Readline which keymap to use.
-
-@deftypefun Keymap rl_make_bare_keymap (void)
-Returns a new, empty keymap. The space for the keymap is allocated with
-@code{malloc()}; the caller should free it by calling
-@code{rl_free_keymap()} when done.
-@end deftypefun
-
-@deftypefun Keymap rl_copy_keymap (Keymap map)
-Return a new keymap which is a copy of @var{map}.
-@end deftypefun
-
-@deftypefun Keymap rl_make_keymap (void)
-Return a new keymap with the printing characters bound to rl_insert,
-the lowercase Meta characters bound to run their equivalents, and
-the Meta digits bound to produce numeric arguments.
-@end deftypefun
-
-@deftypefun void rl_discard_keymap (Keymap keymap)
-Free the storage associated with the data in @var{keymap}.
-The caller should free @var{keymap}.
-@end deftypefun
-
-@deftypefun void rl_free_keymap (Keymap keymap)
-Free all storage associated with @var{keymap}. This calls
-@code{rl_discard_keymap} to free subordindate keymaps and macros.
-@end deftypefun
-
-Readline has several internal keymaps. These functions allow you to
-change which keymap is active.
-
-@deftypefun Keymap rl_get_keymap (void)
-Returns the currently active keymap.
-@end deftypefun
-
-@deftypefun void rl_set_keymap (Keymap keymap)
-Makes @var{keymap} the currently active keymap.
-@end deftypefun
-
-@deftypefun Keymap rl_get_keymap_by_name (const char *name)
-Return the keymap matching @var{name}. @var{name} is one which would
-be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}).
-@end deftypefun
-
-@deftypefun {char *} rl_get_keymap_name (Keymap keymap)
-Return the name matching @var{keymap}. @var{name} is one which would
-be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}).
-@end deftypefun
-
-@node Binding Keys
-@subsection Binding Keys
-
-Key sequences are associate with functions through the keymap.
-Readline has several internal keymaps: @code{emacs_standard_keymap},
-@code{emacs_meta_keymap}, @code{emacs_ctlx_keymap},
-@code{vi_movement_keymap}, and @code{vi_insertion_keymap}.
-@code{emacs_standard_keymap} is the default, and the examples in
-this manual assume that.
-
-Since @code{readline()} installs a set of default key bindings the first
-time it is called, there is always the danger that a custom binding
-installed before the first call to @code{readline()} will be overridden.
-An alternate mechanism is to install custom key bindings in an
-initialization function assigned to the @code{rl_startup_hook} variable
-(@pxref{Readline Variables}).
-
-These functions manage key bindings.
-
-@deftypefun int rl_bind_key (int key, rl_command_func_t *function)
-Binds @var{key} to @var{function} in the currently active keymap.
-Returns non-zero in the case of an invalid @var{key}.
-@end deftypefun
-
-@deftypefun int rl_bind_key_in_map (int key, rl_command_func_t *function, Keymap map)
-Bind @var{key} to @var{function} in @var{map}.
-Returns non-zero in the case of an invalid @var{key}.
-@end deftypefun
-
-@deftypefun int rl_bind_key_if_unbound (int key, rl_command_func_t *function)
-Binds @var{key} to @var{function} if it is not already bound in the
-currently active keymap.
-Returns non-zero in the case of an invalid @var{key} or if @var{key} is
-already bound.
-@end deftypefun
-
-@deftypefun int rl_bind_key_if_unbound_in_map (int key, rl_command_func_t *function, Keymap map)
-Binds @var{key} to @var{function} if it is not already bound in @var{map}.
-Returns non-zero in the case of an invalid @var{key} or if @var{key} is
-already bound.
-@end deftypefun
-
-@deftypefun int rl_unbind_key (int key)
-Bind @var{key} to the null function in the currently active keymap.
-Returns non-zero in case of error.
-@end deftypefun
-
-@deftypefun int rl_unbind_key_in_map (int key, Keymap map)
-Bind @var{key} to the null function in @var{map}.
-Returns non-zero in case of error.
-@end deftypefun
-
-@deftypefun int rl_unbind_function_in_map (rl_command_func_t *function, Keymap map)
-Unbind all keys that execute @var{function} in @var{map}.
-@end deftypefun
-
-@deftypefun int rl_unbind_command_in_map (const char *command, Keymap map)
-Unbind all keys that are bound to @var{command} in @var{map}.
-@end deftypefun
-
-@deftypefun int rl_bind_keyseq (const char *keyseq, rl_command_func_t *function)
-Bind the key sequence represented by the string @var{keyseq} to the function
-@var{function}, beginning in the current keymap.
-This makes new keymaps as necessary.
-The return value is non-zero if @var{keyseq} is invalid.
-@end deftypefun
-
-@deftypefun int rl_bind_keyseq_in_map (const char *keyseq, rl_command_func_t *function, Keymap map)
-Bind the key sequence represented by the string @var{keyseq} to the function
-@var{function}. This makes new keymaps as necessary.
-Initial bindings are performed in @var{map}.
-The return value is non-zero if @var{keyseq} is invalid.
-@end deftypefun
-
-@deftypefun int rl_set_key (const char *keyseq, rl_command_func_t *function, Keymap map)
-Equivalent to @code{rl_bind_keyseq_in_map}.
-@end deftypefun
-
-@deftypefun int rl_bind_keyseq_if_unbound (const char *keyseq, rl_command_func_t *function)
-Binds @var{keyseq} to @var{function} if it is not already bound in the
-currently active keymap.
-Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is
-already bound.
-@end deftypefun
-
-@deftypefun int rl_bind_keyseq_if_unbound_in_map (const char *keyseq, rl_command_func_t *function, Keymap map)
-Binds @var{keyseq} to @var{function} if it is not already bound in @var{map}.
-Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is
-already bound.
-@end deftypefun
-
-@deftypefun int rl_generic_bind (int type, const char *keyseq, char *data, Keymap map)
-Bind the key sequence represented by the string @var{keyseq} to the arbitrary
-pointer @var{data}. @var{type} says what kind of data is pointed to by
-@var{data}; this can be a function (@code{ISFUNC}), a macro
-(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as
-necessary. The initial keymap in which to do bindings is @var{map}.
-@end deftypefun
-
-@deftypefun int rl_parse_and_bind (char *line)
-Parse @var{line} as if it had been read from the @code{inputrc} file and
-perform any key bindings and variable assignments found
-(@pxref{Readline Init File}).
-@end deftypefun
-
-@deftypefun int rl_read_init_file (const char *filename)
-Read keybindings and variable assignments from @var{filename}
-(@pxref{Readline Init File}).
-@end deftypefun
-
-@node Associating Function Names and Bindings
-@subsection Associating Function Names and Bindings
-
-These functions allow you to find out what keys invoke named functions
-and the functions invoked by a particular key sequence. You may also
-associate a new function name with an arbitrary function.
-
-@deftypefun {rl_command_func_t *} rl_named_function (const char *name)
-Return the function with name @var{name}.
-@end deftypefun
-
-@deftypefun {rl_command_func_t *} rl_function_of_keyseq (const char *keyseq, Keymap map, int *type)
-Return the function invoked by @var{keyseq} in keymap @var{map}.
-If @var{map} is @code{NULL}, the current keymap is used. If @var{type} is
-not @code{NULL}, the type of the object is returned in the @code{int} variable
-it points to (one of @code{ISFUNC}, @code{ISKMAP}, or @code{ISMACR}).
-@end deftypefun
-
-@deftypefun {char **} rl_invoking_keyseqs (rl_command_func_t *function)
-Return an array of strings representing the key sequences used to
-invoke @var{function} in the current keymap.
-@end deftypefun
-
-@deftypefun {char **} rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map)
-Return an array of strings representing the key sequences used to
-invoke @var{function} in the keymap @var{map}.
-@end deftypefun
-
-@deftypefun void rl_function_dumper (int readable)
-Print the readline function names and the key sequences currently
-bound to them to @code{rl_outstream}. If @var{readable} is non-zero,
-the list is formatted in such a way that it can be made part of an
-@code{inputrc} file and re-read.
-@end deftypefun
-
-@deftypefun void rl_list_funmap_names (void)
-Print the names of all bindable Readline functions to @code{rl_outstream}.
-@end deftypefun
-
-@deftypefun {const char **} rl_funmap_names (void)
-Return 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, but not the pointers, using @code{free} or
-@code{rl_free} when you are done.
-@end deftypefun
-
-@deftypefun int rl_add_funmap_entry (const char *name, rl_command_func_t *function)
-Add @var{name} to the list of bindable Readline command names, and make
-@var{function} the function to be called when @var{name} is invoked.
-@end deftypefun
-
-@node Allowing Undoing
-@subsection Allowing Undoing
-
-Supporting the undo command is a painless thing, and makes your
-functions much more useful. It is certainly easy to try
-something if you know you can undo it.
-
-If your function simply inserts text once, or deletes text once, and
-uses @code{rl_insert_text()} or @code{rl_delete_text()} to do it, then
-undoing is already done for you automatically.
-
-If you do multiple insertions or multiple deletions, or any combination
-of these operations, you should group them together into one operation.
-This is done with @code{rl_begin_undo_group()} and
-@code{rl_end_undo_group()}.
-
-The types of events that can be undone are:
-
-@smallexample
-enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @};
-@end smallexample
-
-Notice that @code{UNDO_DELETE} means to insert some text, and
-@code{UNDO_INSERT} means to delete some text. That is, the undo code
-tells what to undo, not how to undo it. @code{UNDO_BEGIN} and
-@code{UNDO_END} are tags added by @code{rl_begin_undo_group()} and
-@code{rl_end_undo_group()}.
-
-@deftypefun int rl_begin_undo_group (void)
-Begins saving undo information in a group construct. The undo
-information usually comes from calls to @code{rl_insert_text()} and
-@code{rl_delete_text()}, but could be the result of calls to
-@code{rl_add_undo()}.
-@end deftypefun
-
-@deftypefun int rl_end_undo_group (void)
-Closes the current undo group started with @code{rl_begin_undo_group
-()}. There should be one call to @code{rl_end_undo_group()}
-for each call to @code{rl_begin_undo_group()}.
-@end deftypefun
-
-@deftypefun void rl_add_undo (enum undo_code what, int start, int end, char *text)
-Remember how to undo an event (according to @var{what}). The affected
-text runs from @var{start} to @var{end}, and encompasses @var{text}.
-@end deftypefun
-
-@deftypefun void rl_free_undo_list (void)
-Free the existing undo list.
-@end deftypefun
-
-@deftypefun int rl_do_undo (void)
-Undo the first thing on the undo list. Returns @code{0} if there was
-nothing to undo, non-zero if something was undone.
-@end deftypefun
-
-Finally, if you neither insert nor delete text, but directly modify the
-existing text (e.g., change its case), call @code{rl_modifying()}
-once, just before you modify the text. You must supply the indices of
-the text range that you are going to modify.
-
-@deftypefun int rl_modifying (int start, int end)
-Tell Readline to save the text between @var{start} and @var{end} as a
-single undo unit. It is assumed that you will subsequently modify
-that text.
-@end deftypefun
-
-@node Redisplay
-@subsection Redisplay
-
-@deftypefun void rl_redisplay (void)
-Change what's displayed on the screen to reflect the current contents
-of @code{rl_line_buffer}.
-@end deftypefun
-
-@deftypefun int rl_forced_update_display (void)
-Force the line to be updated and redisplayed, whether or not
-Readline thinks the screen display is correct.
-@end deftypefun
-
-@deftypefun int rl_on_new_line (void)
-Tell the update functions that we have moved onto a new (empty) line,
-usually after ouputting a newline.
-@end deftypefun
-
-@deftypefun int rl_on_new_line_with_prompt (void)
-Tell the update functions that we have moved onto a new line, with
-@var{rl_prompt} already displayed.
-This could be used by applications that want to output the prompt string
-themselves, but still need Readline to know the prompt string length for
-redisplay.
-It should be used after setting @var{rl_already_prompted}.
-@end deftypefun
-
-@deftypefun int rl_reset_line_state (void)
-Reset the display state to a clean state and redisplay the current line
-starting on a new line.
-@end deftypefun
-
-@deftypefun int rl_crlf (void)
-Move the cursor to the start of the next screen line.
-@end deftypefun
-
-@deftypefun int rl_show_char (int c)
-Display character @var{c} on @code{rl_outstream}.
-If Readline has not been set to display meta characters directly, this
-will convert meta characters to a meta-prefixed key sequence.
-This is intended for use by applications which wish to do their own
-redisplay.
-@end deftypefun
-
-@deftypefun int rl_message (const char *, @dots{})
-The arguments are a format string as would be supplied to @code{printf},
-possibly containing conversion specifications such as @samp{%d}, and
-any additional arguments necessary to satisfy the conversion specifications.
-The resulting string is displayed in the @dfn{echo area}. The echo area
-is also used to display numeric arguments and search strings.
-You should call @code{rl_save_prompt} to save the prompt information
-before calling this function.
-@end deftypefun
-
-@deftypefun int rl_clear_message (void)
-Clear the message in the echo area. If the prompt was saved with a call to
-@code{rl_save_prompt} before the last call to @code{rl_message},
-call @code{rl_restore_prompt} before calling this function.
-@end deftypefun
-
-@deftypefun void rl_save_prompt (void)
-Save the local Readline prompt display state in preparation for
-displaying a new message in the message area with @code{rl_message()}.
-@end deftypefun
-
-@deftypefun void rl_restore_prompt (void)
-Restore the local Readline prompt display state saved by the most
-recent call to @code{rl_save_prompt}.
-if @code{rl_save_prompt} was called to save the prompt before a call
-to @code{rl_message}, this function should be called before the
-corresponding call to @code{rl_clear_message}.
-@end deftypefun
-
-@deftypefun int rl_expand_prompt (char *prompt)
-Expand any special character sequences in @var{prompt} and set up the
-local Readline prompt redisplay variables.
-This function is called by @code{readline()}. It may also be called to
-expand the primary prompt if the @code{rl_on_new_line_with_prompt()}
-function or @code{rl_already_prompted} variable is used.
-It returns the number of visible characters on the last line of the
-(possibly multi-line) prompt.
-Applications may indicate that the prompt contains characters that take
-up no physical screen space when displayed by bracketing a sequence of
-such characters with the special markers @code{RL_PROMPT_START_IGNORE}
-and @code{RL_PROMPT_END_IGNORE} (declared in @file{readline.h}. This may
-be used to embed terminal-specific escape sequences in prompts.
-@end deftypefun
-
-@deftypefun int rl_set_prompt (const char *prompt)
-Make Readline use @var{prompt} for subsequent redisplay. This calls
-@code{rl_expand_prompt()} to expand the prompt and sets @code{rl_prompt}
-to the result.
-@end deftypefun
-
-@node Modifying Text
-@subsection Modifying Text
-
-@deftypefun int rl_insert_text (const char *text)
-Insert @var{text} into the line at the current cursor position.
-Returns the number of characters inserted.
-@end deftypefun
-
-@deftypefun int rl_delete_text (int start, int end)
-Delete the text between @var{start} and @var{end} in the current line.
-Returns the number of characters deleted.
-@end deftypefun
-
-@deftypefun {char *} rl_copy_text (int start, int end)
-Return a copy of the text between @var{start} and @var{end} in
-the current line.
-@end deftypefun
-
-@deftypefun int rl_kill_text (int start, int end)
-Copy the text between @var{start} and @var{end} in the current line
-to the kill ring, appending or prepending to the last kill if the
-last command was a kill command. The text is deleted.
-If @var{start} is less than @var{end},
-the text is appended, otherwise prepended. If the last command was
-not a kill, a new kill ring slot is used.
-@end deftypefun
-
-@deftypefun int rl_push_macro_input (char *macro)
-Cause @var{macro} to be inserted into the line, as if it had been invoked
-by a key bound to a macro. Not especially useful; use
-@code{rl_insert_text()} instead.
-@end deftypefun
-
-@node Character Input
-@subsection Character Input
-
-@deftypefun int rl_read_key (void)
-Return the next character available from Readline's current input stream.
-This handles input inserted into
-the input stream via @var{rl_pending_input} (@pxref{Readline Variables})
-and @code{rl_stuff_char()}, macros, and characters read from the keyboard.
-While waiting for input, this function will call any function assigned to
-the @code{rl_event_hook} variable.
-@end deftypefun
-
-@deftypefun int rl_getc (FILE *stream)
-Return the next character available from @var{stream}, which is assumed to
-be the keyboard.
-@end deftypefun
-
-@deftypefun int rl_stuff_char (int c)
-Insert @var{c} into the Readline input stream. It will be "read"
-before Readline attempts to read characters from the terminal with
-@code{rl_read_key()}. Up to 512 characters may be pushed back.
-@code{rl_stuff_char} returns 1 if the character was successfully inserted;
-0 otherwise.
-@end deftypefun
-
-@deftypefun int rl_execute_next (int c)
-Make @var{c} be the next command to be executed when @code{rl_read_key()}
-is called. This sets @var{rl_pending_input}.
-@end deftypefun
-
-@deftypefun int rl_clear_pending_input (void)
-Unset @var{rl_pending_input}, effectively negating the effect of any
-previous call to @code{rl_execute_next()}. This works only if the
-pending input has not already been read with @code{rl_read_key()}.
-@end deftypefun
-
-@deftypefun int rl_set_keyboard_input_timeout (int u)
-While waiting for keyboard input in @code{rl_read_key()}, Readline will
-wait for @var{u} microseconds for input before calling any function
-assigned to @code{rl_event_hook}. @var{u} must be greater than or equal
-to zero (a zero-length timeout is equivalent to a poll).
-The default waiting period is one-tenth of a second.
-Returns the old timeout value.
-@end deftypefun
-
-@node Terminal Management
-@subsection Terminal Management
-
-@deftypefun void rl_prep_terminal (int meta_flag)
-Modify the terminal settings for Readline's use, so @code{readline()}
-can read a single character at a time from the keyboard.
-The @var{meta_flag} argument should be non-zero if Readline should
-read eight-bit input.
-@end deftypefun
-
-@deftypefun void rl_deprep_terminal (void)
-Undo the effects of @code{rl_prep_terminal()}, leaving the terminal in
-the state in which it was before the most recent call to
-@code{rl_prep_terminal()}.
-@end deftypefun
-
-@deftypefun void rl_tty_set_default_bindings (Keymap kmap)
-Read the operating system's terminal editing characters (as would be
-displayed by @code{stty}) to their Readline equivalents.
-The bindings are performed in @var{kmap}.
-@end deftypefun
-
-@deftypefun void rl_tty_unset_default_bindings (Keymap kmap)
-Reset the bindings manipulated by @code{rl_tty_set_default_bindings} so
-that the terminal editing characters are bound to @code{rl_insert}.
-The bindings are performed in @var{kmap}.
-@end deftypefun
-
-@deftypefun int rl_reset_terminal (const char *terminal_name)
-Reinitialize Readline's idea of the terminal settings using
-@var{terminal_name} as the terminal type (e.g., @code{vt100}).
-If @var{terminal_name} is @code{NULL}, the value of the @code{TERM}
-environment variable is used.
-@end deftypefun
-
-@node Utility Functions
-@subsection Utility Functions
-
-@deftypefun int rl_save_state (struct readline_state *sp)
-Save a snapshot of Readline's internal state to @var{sp}.
-The contents of the @var{readline_state} structure are documented
-in @file{readline.h}.
-The caller is responsible for allocating the structure.
-@end deftypefun
-
-@deftypefun int rl_restore_state (struct readline_state *sp)
-Restore Readline's internal state to that stored in @var{sp}, which must
-have been saved by a call to @code{rl_save_state}.
-The contents of the @var{readline_state} structure are documented
-in @file{readline.h}.
-The caller is responsible for freeing the structure.
-@end deftypefun
-
-@deftypefun void rl_free (void *mem)
-Deallocate the memory pointed to by @var{mem}. @var{mem} must have been
-allocated by @code{malloc}.
-@end deftypefun
-
-@deftypefun void rl_replace_line (const char *text, int clear_undo)
-Replace the contents of @code{rl_line_buffer} with @var{text}.
-The point and mark are preserved, if possible.
-If @var{clear_undo} is non-zero, the undo list associated with the
-current line is cleared.
-@end deftypefun
-
-@deftypefun void rl_extend_line_buffer (int len)
-Ensure that @code{rl_line_buffer} has enough space to hold @var{len}
-characters, possibly reallocating it if necessary.
-@end deftypefun
-
-@deftypefun int rl_initialize (void)
-Initialize or re-initialize Readline's internal state.
-It's not strictly necessary to call this; @code{readline()} calls it before
-reading any input.
-@end deftypefun
-
-@deftypefun int rl_ding (void)
-Ring the terminal bell, obeying the setting of @code{bell-style}.
-@end deftypefun
-
-@deftypefun int rl_alphabetic (int c)
-Return 1 if @var{c} is an alphabetic character.
-@end deftypefun
-
-@deftypefun void rl_display_match_list (char **matches, int len, int max)
-A convenience function for displaying a list of strings in
-columnar format on Readline's output stream. @code{matches} is the list
-of strings, in argv format, such as a list of completion matches.
-@code{len} is the number of strings in @code{matches}, and @code{max}
-is the length of the longest string in @code{matches}. This function uses
-the setting of @code{print-completions-horizontally} to select how the
-matches are displayed (@pxref{Readline Init File Syntax}).
-When displaying completions, this function 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.
-@end deftypefun
-
-The following are implemented as macros, defined in @code{chardefs.h}.
-Applications should refrain from using them.
-
-@deftypefun int _rl_uppercase_p (int c)
-Return 1 if @var{c} is an uppercase alphabetic character.
-@end deftypefun
-
-@deftypefun int _rl_lowercase_p (int c)
-Return 1 if @var{c} is a lowercase alphabetic character.
-@end deftypefun
-
-@deftypefun int _rl_digit_p (int c)
-Return 1 if @var{c} is a numeric character.
-@end deftypefun
-
-@deftypefun int _rl_to_upper (int c)
-If @var{c} is a lowercase alphabetic character, return the corresponding
-uppercase character.
-@end deftypefun
-
-@deftypefun int _rl_to_lower (int c)
-If @var{c} is an uppercase alphabetic character, return the corresponding
-lowercase character.
-@end deftypefun
-
-@deftypefun int _rl_digit_value (int c)
-If @var{c} is a number, return the value it represents.
-@end deftypefun
-
-@node Miscellaneous Functions
-@subsection Miscellaneous Functions
-
-@deftypefun int rl_macro_bind (const char *keyseq, const char *macro, Keymap map)
-Bind the key sequence @var{keyseq} to invoke the macro @var{macro}.
-The binding is performed in @var{map}. When @var{keyseq} is invoked, the
-@var{macro} will be inserted into the line. This function is deprecated;
-use @code{rl_generic_bind()} instead.
-@end deftypefun
-
-@deftypefun void rl_macro_dumper (int readable)
-Print the key sequences bound to macros and their values, using
-the current keymap, to @code{rl_outstream}.
-If @var{readable} is non-zero, the list is formatted in such a way
-that it can be made part of an @code{inputrc} file and re-read.
-@end deftypefun
-
-@deftypefun int rl_variable_bind (const char *variable, const char *value)
-Make the Readline variable @var{variable} have @var{value}.
-This behaves as if the readline command
-@samp{set @var{variable} @var{value}} had been executed in an @code{inputrc}
-file (@pxref{Readline Init File Syntax}).
-@end deftypefun
-
-@deftypefun {char *} rl_variable_value (const char *variable)
-Return a string representing the value of the Readline variable @var{variable}.
-For boolean variables, this string is either @samp{on} or @samp{off}.
-@end deftypefun
-
-@deftypefun void rl_variable_dumper (int readable)
-Print the readline variable names and their current values
-to @code{rl_outstream}.
-If @var{readable} is non-zero, the list is formatted in such a way
-that it can be made part of an @code{inputrc} file and re-read.
-@end deftypefun
-
-@deftypefun int rl_set_paren_blink_timeout (int u)
-Set the time interval (in microseconds) that Readline waits when showing
-a balancing character when @code{blink-matching-paren} has been enabled.
-@end deftypefun
-
-@deftypefun {char *} rl_get_termcap (const char *cap)
-Retrieve the string value of the termcap capability @var{cap}.
-Readline fetches the termcap entry for the current terminal name and
-uses those capabilities to move around the screen line and perform other
-terminal-specific operations, like erasing a line. Readline does not
-use all of a terminal's capabilities, and this function will return
-values for only those capabilities Readline uses.
-@end deftypefun
-
-@deftypefun {void} rl_clear_history (void)
-Clear the history list by deleting all of the entries, in the same manner
-as the History library's @code{clear_history()} function.
-This differs from @code{clear_history} because it frees private data
-Readline saves in the history list.
-@end deftypefun
-
-@node Alternate Interface
-@subsection Alternate Interface
-
-An alternate interface is available to plain @code{readline()}. Some
-applications need to interleave keyboard I/O with file, device, or
-window system I/O, typically by using a main loop to @code{select()}
-on various file descriptors. To accomodate this need, readline can
-also be invoked as a `callback' function from an event loop. There
-are functions available to make this easy.
-
-@deftypefun void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler)
-Set up the terminal for readline I/O and display the initial
-expanded value of @var{prompt}. Save the value of @var{lhandler} to
-use as a function to call when a complete line of input has been entered.
-The function takes the text of the line as an argument.
-@end deftypefun
-
-@deftypefun void rl_callback_read_char (void)
-Whenever an application determines that keyboard input is available, it
-should call @code{rl_callback_read_char()}, which will read the next
-character from the current input source.
-If that character completes the line, @code{rl_callback_read_char} will
-invoke the @var{lhandler} function saved by @code{rl_callback_handler_install}
-to process the line.
-Before calling the @var{lhandler} function, the terminal settings are
-reset to the values they had before calling
-@code{rl_callback_handler_install}.
-If the @var{lhandler} function returns,
-the terminal settings are modified for Readline's use again.
-@code{EOF} is indicated by calling @var{lhandler} with a
-@code{NULL} line.
-@end deftypefun
-
-@deftypefun void rl_callback_handler_remove (void)
-Restore the terminal to its initial state and remove the line handler.
-This may be called from within a callback as well as independently.
-If the @var{lhandler} installed by @code{rl_callback_handler_install}
-does not exit the program, either this function or the function referred
-to by the value of @code{rl_deprep_term_function} should be called before
-the program exits to reset the terminal settings.
-@end deftypefun
-
-@node A Readline Example
-@subsection A Readline Example
-
-Here is a function which changes lowercase characters to their uppercase
-equivalents, and uppercase characters to lowercase. If
-this function was bound to @samp{M-c}, then typing @samp{M-c} would
-change the case of the character under point. Typing @samp{M-1 0 M-c}
-would change the case of the following 10 characters, leaving the cursor on
-the last character changed.
-
-@example
-/* Invert the case of the COUNT following characters. */
-int
-invert_case_line (count, key)
- int count, key;
-@{
- register int start, end, i;
-
- start = rl_point;
-
- if (rl_point >= rl_end)
- return (0);
-
- if (count < 0)
- @{
- direction = -1;
- count = -count;
- @}
- else
- direction = 1;
-
- /* Find the end of the range to modify. */
- end = start + (count * direction);
-
- /* Force it to be within range. */
- if (end > rl_end)
- end = rl_end;
- else if (end < 0)
- end = 0;
-
- if (start == end)
- return (0);
-
- if (start > end)
- @{
- int temp = start;
- start = end;
- end = temp;
- @}
-
- /* Tell readline that we are modifying the line,
- so it will save the undo information. */
- rl_modifying (start, end);
-
- for (i = start; i != end; i++)
- @{
- if (_rl_uppercase_p (rl_line_buffer[i]))
- rl_line_buffer[i] = _rl_to_lower (rl_line_buffer[i]);
- else if (_rl_lowercase_p (rl_line_buffer[i]))
- rl_line_buffer[i] = _rl_to_upper (rl_line_buffer[i]);
- @}
- /* Move point to on top of the last character changed. */
- rl_point = (direction == 1) ? end - 1 : start;
- return (0);
-@}
-@end example
-
-@node Readline Signal Handling
-@section Readline Signal Handling
-
-Signals are asynchronous events sent to a process by the Unix kernel,
-sometimes on behalf of another process. They are intended to indicate
-exceptional events, like a user pressing the interrupt key on his terminal,
-or a network connection being broken. There is a class of signals that can
-be sent to the process currently reading input from the keyboard. Since
-Readline changes the terminal attributes when it is called, it needs to
-perform special processing when such a signal is received in order to
-restore the terminal to a sane state, or provide application writers with
-functions to do so manually.
-
-Readline contains an internal signal handler that is installed for a
-number of signals (@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM},
-@code{SIGHUP},
-@code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}).
-When one of these signals is received, the signal handler
-will reset the terminal attributes to those that were in effect before
-@code{readline()} was called, reset the signal handling to what it was
-before @code{readline()} was called, and resend the signal to the calling
-application.
-If and when the calling application's signal handler returns, Readline
-will reinitialize the terminal and continue to accept input.
-When a @code{SIGINT} is received, the Readline signal handler performs
-some additional work, which will cause any partially-entered line to be
-aborted (see the description of @code{rl_free_line_state()} below).
-
-There is an additional Readline signal handler, for @code{SIGWINCH}, which
-the kernel sends to a process whenever the terminal's size changes (for
-example, if a user resizes an @code{xterm}). The Readline @code{SIGWINCH}
-handler updates Readline's internal screen size information, and then calls
-any @code{SIGWINCH} signal handler the calling application has installed.
-Readline calls the application's @code{SIGWINCH} signal handler without
-resetting the terminal to its original state. If the application's signal
-handler does more than update its idea of the terminal size and return (for
-example, a @code{longjmp} back to a main processing loop), it @emph{must}
-call @code{rl_cleanup_after_signal()} (described below), to restore the
-terminal state.
-
-Readline provides two variables that allow application writers to
-control whether or not it will catch certain signals and act on them
-when they are received. It is important that applications change the
-values of these variables only when calling @code{readline()}, not in
-a signal handler, so Readline's internal signal state is not corrupted.
-
-@deftypevar int rl_catch_signals
-If this variable is non-zero, Readline will install signal handlers for
-@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, @code{SIGHUP}, @code{SIGALRM},
-@code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}.
-
-The default value of @code{rl_catch_signals} is 1.
-@end deftypevar
-
-@deftypevar int rl_catch_sigwinch
-If this variable is non-zero, Readline will install a signal handler for
-@code{SIGWINCH}.
-
-The default value of @code{rl_catch_sigwinch} is 1.
-@end deftypevar
-
-If an application does not wish to have Readline catch any signals, or
-to handle signals other than those Readline catches (@code{SIGHUP},
-for example),
-Readline provides convenience functions to do the necessary terminal
-and internal state cleanup upon receipt of a signal.
-
-@deftypefun void rl_cleanup_after_signal (void)
-This function will reset the state of the terminal to what it was before
-@code{readline()} was called, and remove the Readline signal handlers for
-all signals, depending on the values of @code{rl_catch_signals} and
-@code{rl_catch_sigwinch}.
-@end deftypefun
-
-@deftypefun void rl_free_line_state (void)
-This will free any partial state associated with the current input line
-(undo information, any partial history entry, any partially-entered
-keyboard macro, and any partially-entered numeric argument). This
-should be called before @code{rl_cleanup_after_signal()}. The
-Readline signal handler for @code{SIGINT} calls this to abort the
-current input line.
-@end deftypefun
-
-@deftypefun void rl_reset_after_signal (void)
-This will reinitialize the terminal and reinstall any Readline signal
-handlers, depending on the values of @code{rl_catch_signals} and
-@code{rl_catch_sigwinch}.
-@end deftypefun
-
-If an application does not wish Readline to catch @code{SIGWINCH}, it may
-call @code{rl_resize_terminal()} or @code{rl_set_screen_size()} to force
-Readline to update its idea of the terminal size when a @code{SIGWINCH}
-is received.
-
-@deftypefun void rl_echo_signal_char (int sig)
-If an application wishes to install its own signal handlers, but still
-have readline display characters that generate signals, calling this
-function with @var{sig} set to @code{SIGINT}, @code{SIGQUIT}, or
-@code{SIGTSTP} will display the character generating that signal.
-@end deftypefun
-
-@deftypefun void rl_resize_terminal (void)
-Update Readline's internal screen size by reading values from the kernel.
-@end deftypefun
-
-@deftypefun void rl_set_screen_size (int rows, int cols)
-Set Readline's idea of the terminal size to @var{rows} rows and
-@var{cols} columns. If either @var{rows} or @var{columns} is less than
-or equal to 0, Readline's idea of that terminal dimension is unchanged.
-@end deftypefun
-
-If an application does not want to install a @code{SIGWINCH} handler, but
-is still interested in the screen dimensions, Readline's idea of the screen
-size may be queried.
-
-@deftypefun void rl_get_screen_size (int *rows, int *cols)
-Return Readline's idea of the terminal's size in the
-variables pointed to by the arguments.
-@end deftypefun
-
-@deftypefun void rl_reset_screen_size (void)
-Cause Readline to reobtain the screen size and recalculate its dimensions.
-@end deftypefun
-
-The following functions install and remove Readline's signal handlers.
-
-@deftypefun int rl_set_signals (void)
-Install Readline's signal handler for @code{SIGINT}, @code{SIGQUIT},
-@code{SIGTERM}, @code{SIGHUP}, @code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN},
-@code{SIGTTOU}, and @code{SIGWINCH}, depending on the values of
-@code{rl_catch_signals} and @code{rl_catch_sigwinch}.
-@end deftypefun
-
-@deftypefun int rl_clear_signals (void)
-Remove all of the Readline signal handlers installed by
-@code{rl_set_signals()}.
-@end deftypefun
-
-@node Custom Completers
-@section Custom Completers
-@cindex application-specific completion functions
-
-Typically, a program that reads commands from the user has a way of
-disambiguating commands and data. If your program is one of these, then
-it can provide completion for commands, data, or both.
-The following sections describe how your program and Readline
-cooperate to provide this service.
-
-@menu
-* How Completing Works:: The logic used to do completion.
-* Completion Functions:: Functions provided by Readline.
-* Completion Variables:: Variables which control completion.
-* A Short Completion Example:: An example of writing completer subroutines.
-@end menu
-
-@node How Completing Works
-@subsection How Completing Works
-
-In order to complete some text, the full list of possible completions
-must be available. That is, it is not possible to accurately
-expand a partial word without knowing all of the possible words
-which make sense in that context. The Readline library provides
-the user interface to completion, and two of the most common
-completion functions: filename and username. For completing other types
-of text, you must write your own completion function. This section
-describes exactly what such functions must do, and provides an example.
-
-There are three major functions used to perform completion:
-
-@enumerate
-@item
-The user-interface function @code{rl_complete()}. This function is
-called with the same arguments as other bindable Readline functions:
-@var{count} and @var{invoking_key}.
-It isolates the word to be completed and calls
-@code{rl_completion_matches()} to generate a list of possible completions.
-It then either lists the possible completions, inserts the possible
-completions, or actually performs the
-completion, depending on which behavior is desired.
-
-@item
-The internal function @code{rl_completion_matches()} uses an
-application-supplied @dfn{generator} function to generate the list of
-possible matches, and then returns the array of these matches.
-The caller should place the address of its generator function in
-@code{rl_completion_entry_function}.
-
-@item
-The generator function is called repeatedly from
-@code{rl_completion_matches()}, returning a string each time. The
-arguments to the generator function are @var{text} and @var{state}.
-@var{text} is the partial word to be completed. @var{state} is zero the
-first time the function is called, allowing the generator to perform
-any necessary initialization, and a positive non-zero integer for
-each subsequent call. The generator function returns
-@code{(char *)NULL} to inform @code{rl_completion_matches()} that there are
-no more possibilities left. Usually the generator function computes the
-list of possible completions when @var{state} is zero, and returns them
-one at a time on subsequent calls. Each string the generator function
-returns as a match must be allocated with @code{malloc()}; Readline
-frees the strings when it has finished with them.
-Such a generator function is referred to as an
-@dfn{application-specific completion function}.
-
-@end enumerate
-
-@deftypefun int rl_complete (int ignore, int invoking_key)
-Complete the word at or before point. You have supplied the function
-that does the initial simple matching selection algorithm (see
-@code{rl_completion_matches()}). The default is to do filename completion.
-@end deftypefun
-
-@deftypevar {rl_compentry_func_t *} rl_completion_entry_function
-This is a pointer to the generator function for
-@code{rl_completion_matches()}.
-If the value of @code{rl_completion_entry_function} is
-@code{NULL} then the default filename generator
-function, @code{rl_filename_completion_function()}, is used.
-An @dfn{application-specific completion function} is a function whose
-address is assigned to @code{rl_completion_entry_function} and whose
-return values are used to generate possible completions.
-@end deftypevar
-
-@node Completion Functions
-@subsection Completion Functions
-
-Here is the complete list of callable completion functions present in
-Readline.
-
-@deftypefun int rl_complete_internal (int what_to_do)
-Complete the word at or before point. @var{what_to_do} says what to do
-with the completion. A value of @samp{?} means list the possible
-completions. @samp{TAB} means do standard completion. @samp{*} means
-insert all of the possible completions. @samp{!} means to display
-all of the possible completions, if there is more than one, as well as
-performing partial completion. @samp{@@} is similar to @samp{!}, but
-possible completions are not listed if the possible completions share
-a common prefix.
-@end deftypefun
-
-@deftypefun int rl_complete (int ignore, int invoking_key)
-Complete the word at or before point. You have supplied the function
-that does the initial simple matching selection algorithm (see
-@code{rl_completion_matches()} and @code{rl_completion_entry_function}).
-The default is to do filename
-completion. This calls @code{rl_complete_internal()} with an
-argument depending on @var{invoking_key}.
-@end deftypefun
-
-@deftypefun int rl_possible_completions (int count, int invoking_key)
-List the possible completions. See description of @code{rl_complete
-()}. This calls @code{rl_complete_internal()} with an argument of
-@samp{?}.
-@end deftypefun
-
-@deftypefun int rl_insert_completions (int count, int invoking_key)
-Insert the list of possible completions into the line, deleting the
-partially-completed word. See description of @code{rl_complete()}.
-This calls @code{rl_complete_internal()} with an argument of @samp{*}.
-@end deftypefun
-
-@deftypefun int rl_completion_mode (rl_command_func_t *cfunc)
-Returns the apppriate value to pass to @code{rl_complete_internal()}
-depending on whether @var{cfunc} was called twice in succession and
-the values of the @code{show-all-if-ambiguous} and
-@code{show-all-if-unmodified} variables.
-Application-specific completion functions may use this function to present
-the same interface as @code{rl_complete()}.
-@end deftypefun
-
-@deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func)
-Returns an array of strings which is a list of completions for
-@var{text}. If there are no completions, returns @code{NULL}.
-The first entry in the returned array is the substitution for @var{text}.
-The remaining entries are the possible completions. The array is
-terminated with a @code{NULL} pointer.
-
-@var{entry_func} is a function of two args, and returns a
-@code{char *}. The first argument is @var{text}. The second is a
-state argument; it is zero on the first call, and non-zero on subsequent
-calls. @var{entry_func} returns a @code{NULL} pointer to the caller
-when there are no more matches.
-@end deftypefun
-
-@deftypefun {char *} rl_filename_completion_function (const char *text, int state)
-A generator function for filename completion in the general case.
-@var{text} is a partial filename.
-The Bash source is a useful reference for writing application-specific
-completion functions (the Bash completion functions call this and other
-Readline functions).
-@end deftypefun
-
-@deftypefun {char *} rl_username_completion_function (const char *text, int state)
-A completion generator for usernames. @var{text} contains a partial
-username preceded by a random character (usually @samp{~}). As with all
-completion generators, @var{state} is zero on the first call and non-zero
-for subsequent calls.
-@end deftypefun
-
-@node Completion Variables
-@subsection Completion Variables
-
-@deftypevar {rl_compentry_func_t *} rl_completion_entry_function
-A pointer to the generator function for @code{rl_completion_matches()}.
-@code{NULL} means to use @code{rl_filename_completion_function()},
-the default filename completer.
-@end deftypevar
-
-@deftypevar {rl_completion_func_t *} rl_attempted_completion_function
-A pointer to an alternative function to create matches.
-The function is called with @var{text}, @var{start}, and @var{end}.
-@var{start} and @var{end} are indices in @code{rl_line_buffer} defining
-the boundaries of @var{text}, which is a character string.
-If this function exists and returns @code{NULL}, or if this variable is
-set to @code{NULL}, then @code{rl_complete()} will call the value of
-@code{rl_completion_entry_function} to generate matches, otherwise the
-array of strings returned will be used.
-If this function sets the @code{rl_attempted_completion_over}
-variable to a non-zero value, Readline will not perform its default
-completion even if this function returns no matches.
-@end deftypevar
-
-@deftypevar {rl_quote_func_t *} rl_filename_quoting_function
-A pointer to a function that will quote a filename in an
-application-specific fashion. This is called if filename completion is being
-attempted and one of the characters in @code{rl_filename_quote_characters}
-appears in a completed filename. The function is called with
-@var{text}, @var{match_type}, and @var{quote_pointer}. The @var{text}
-is the filename to be quoted. The @var{match_type} is either
-@code{SINGLE_MATCH}, if there is only one completion match, or
-@code{MULT_MATCH}. Some functions use this to decide whether or not to
-insert a closing quote character. The @var{quote_pointer} is a pointer
-to any opening quote character the user typed. Some functions choose
-to reset this character.
-@end deftypevar
-
-@deftypevar {rl_dequote_func_t *} rl_filename_dequoting_function
-A pointer to a function that will remove application-specific quoting
-characters from a filename before completion is attempted, so those
-characters do not interfere with matching the text against names in
-the filesystem. It is called with @var{text}, the text of the word
-to be dequoted, and @var{quote_char}, which is the quoting character
-that delimits the filename (usually @samp{'} or @samp{"}). If
-@var{quote_char} is zero, the filename was not in an embedded string.
-@end deftypevar
-
-@deftypevar {rl_linebuf_func_t *} rl_char_is_quoted_p
-A pointer to a function to call that determines whether or not a specific
-character in the line buffer is quoted, according to whatever quoting
-mechanism the program calling Readline uses. The function is called with
-two arguments: @var{text}, the text of the line, and @var{index}, the
-index of the character in the line. It is used to decide whether a
-character found in @code{rl_completer_word_break_characters} should be
-used to break words for the completer.
-@end deftypevar
-
-@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function
-This function, if defined, is called by the completer when real filename
-completion is done, after all the matching names have been generated.
-It is passed a @code{NULL} terminated array of matches.
-The first element (@code{matches[0]}) is the
-maximal substring common to all matches. This function can
-re-arrange the list of matches as required, but each element deleted
-from the array must be freed.
-@end deftypevar
-
-@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook
-This function, if defined, is allowed to modify the directory portion
-of filenames Readline completes.
-It could be used to expand symbolic links or shell variables in pathnames.
-It is called with the address of a string (the current directory name) as an
-argument, and may modify that string.
-If the string is replaced with a new string, the old value should be freed.
-Any modified directory name should have a trailing slash.
-The modified value will be used as part of the completion, replacing
-the directory portion of the pathname the user typed.
-At the least, even if no other expansion is performed, this function should
-remove any quote characters from the directory name, because its result will
-be passed directly to @code{opendir()}.
-
-The directory completion hook returns an integer that should be non-zero if
-the function modifies its directory argument.
-The function should not modify the directory argument if it returns 0.
-@end deftypevar
-
-@deftypevar {rl_icppfunc_t *} rl_directory_rewrite_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 @code{rl_directory_completion_hook},
-it only modifies the directory name used in @code{opendir}, not what is
-displayed when the possible completions are printed or inserted. It is
-called before rl_directory_completion_hook.
-At the least, even if no other expansion is performed, this function should
-remove any quote characters from the directory name, because its result will
-be passed directly to @code{opendir()}.
-
-The directory rewrite hook returns an integer that should be non-zero if
-the function modfies its directory argument.
-The function should not modify the directory argument if it returns 0.
-@end deftypevar
-
-@deftypevar {rl_icppfunc_t *} rl_filename_stat_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.
-This function modifies its filename name argument, and the modified value
-is passed to @code{stat()} to determine the file's type and characteristics.
-This function does not need to remove quote characters from the filename.
-
-The stat hook returns an integer that should be non-zero if
-the function modfies its directory argument.
-The function should not modify the directory argument if it returns 0.
-@end deftypevar
-
-@deftypevar {rl_dequote_func_t *} rl_filename_rewrite_hook
-If non-zero, this is the address of a function called when reading
-directory entries from the filesystem for completion and comparing
-them to the partial word to be completed. The function should
-perform any necesary application or system-specific conversion on
-the filename, such as converting between character sets or converting
-from a filesystem format to a character input format.
-The function takes two arguments: @var{fname}, the filename to be converted,
-and @var{fnlen}, its length in bytes.
-It must either return its first argument (if no conversion takes place)
-or the converted filename in newly-allocated memory. The converted
-form is used to compare against the word to be completed, and, if it
-matches, is added to the list of matches. Readline will free the
-allocated string.
-@end deftypevar
-
-@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_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 in lieu of Readline displaying the list.
-It takes three arguments:
-(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length})
-where @var{matches} is the array of matching strings,
-@var{num_matches} is the number of strings in that array, and
-@var{max_length} is the length of the longest string in that array.
-Readline provides a convenience function, @code{rl_display_match_list},
-that takes care of doing the display to Readline's output stream. That
-function may be called from this hook.
-@end deftypevar
-
-@deftypevar {const char *} rl_basic_word_break_characters
-The basic list of characters that signal a break between words for the
-completer routine. The default value of this variable is the characters
-which break words for completion in Bash:
-@code{" \t\n\"\\'`@@$><=;|&@{("}.
-@end deftypevar
-
-@deftypevar {const char *} rl_basic_quote_characters
-A list of quote characters which can cause a word break.
-@end deftypevar
-
-@deftypevar {const char *} rl_completer_word_break_characters
-The list of characters that signal a break between words for
-@code{rl_complete_internal()}. The default list is the value of
-@code{rl_basic_word_break_characters}.
-@end deftypevar
-
-@deftypevar {rl_cpvfunc_t *} rl_completion_word_break_hook
-If non-zero, this is the address of a function to call when Readline is
-deciding where to separate words for word completion. It should return
-a character string like @code{rl_completer_word_break_characters} to be
-used to perform the current completion. The function may choose to set
-@code{rl_completer_word_break_characters} itself. If the function
-returns @code{NULL}, @code{rl_completer_word_break_characters} is used.
-@end deftypevar
-
-@deftypevar {const char *} rl_completer_quote_characters
-A list of characters which can be used to quote a substring of the line.
-Completion occurs on the entire substring, and within the substring
-@code{rl_completer_word_break_characters} are treated as any other character,
-unless they also appear within this list.
-@end deftypevar
-
-@deftypevar {const char *} rl_filename_quote_characters
-A list of characters that cause a filename to be quoted by the completer
-when they appear in a completed filename. The default is the null string.
-@end deftypevar
-
-@deftypevar {const char *} rl_special_prefixes
-The list of characters that are word break characters, but should be
-left in @var{text} when it is passed to the completion function.
-Programs can use this to help determine what kind of completing to do.
-For instance, Bash sets this variable to "$@@" so that it can complete
-shell variables and hostnames.
-@end deftypevar
-
-@deftypevar int rl_completion_query_items
-Up to this many items will be displayed in response to a
-possible-completions call. After that, readline asks the user if she is sure
-she wants to see them all. The default value is 100. A negative value
-indicates that Readline should never ask the user.
-@end deftypevar
-
-@deftypevar {int} rl_completion_append_character
-When a single completion alternative matches at the end of the command
-line, this character is appended to the inserted completion text. The
-default is a space character (@samp{ }). Setting this to the null
-character (@samp{\0}) prevents anything being appended automatically.
-This can be changed in application-specific completion functions to
-provide the ``most sensible word separator character'' according to
-an application-specific command line syntax specification.
-@end deftypevar
-
-@deftypevar int rl_completion_suppress_append
-If non-zero, @var{rl_completion_append_character} is not appended to
-matches at the end of the command line, as described above.
-It is set to 0 before any application-specific completion function
-is called, and may only be changed within such a function.
-@end deftypevar
-
-@deftypevar int rl_completion_quote_character
-When Readline is completing quoted text, as delimited by one of the
-characters in @var{rl_completer_quote_characters}, it sets this variable
-to the quoting character found.
-This is set before any application-specific completion function is called.
-@end deftypevar
-
-@deftypevar int rl_completion_suppress_quote
-If non-zero, Readline does not append a matching quote character when
-performing completion on a quoted string.
-It is set to 0 before any application-specific completion function
-is called, and may only be changed within such a function.
-@end deftypevar
-
-@deftypevar int rl_completion_found_quote
-When Readline is completing quoted text, it sets this variable
-to a non-zero value if the word being completed contains or is delimited
-by any quoting characters, including backslashes.
-This is set before any application-specific completion function is called.
-@end deftypevar
-
-@deftypevar int rl_completion_mark_symlink_dirs
-If non-zero, a slash will be appended to completed filenames that are
-symbolic links to directory names, subject to the value of the
-user-settable @var{mark-directories} variable.
-This variable exists so that application-specific completion functions
-can override the user's global preference (set via the
-@var{mark-symlinked-directories} Readline variable) if appropriate.
-This variable is set to the user's preference before any
-application-specific completion function is called, so unless that
-function modifies the value, the user's preferences are honored.
-@end deftypevar
-
-@deftypevar int rl_ignore_completion_duplicates
-If non-zero, then duplicates in the matches are removed.
-The default is 1.
-@end deftypevar
-
-@deftypevar int rl_filename_completion_desired
-Non-zero means that the results of the matches are to be treated as
-filenames. This is @emph{always} zero when completion is attempted,
-and can only be changed
-within an application-specific completion function. If it is set to a
-non-zero value by such a function, directory names have a slash appended
-and Readline attempts to quote completed filenames if they contain any
-characters in @code{rl_filename_quote_characters} and
-@code{rl_filename_quoting_desired} is set to a non-zero value.
-@end deftypevar
-
-@deftypevar int rl_filename_quoting_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
-completed filename contains any characters in
-@code{rl_filename_quote_chars}. This is @emph{always} non-zero
-when completion is attempted, and can only be changed within an
-application-specific completion function.
-The quoting is effected via a call to the function pointed to
-by @code{rl_filename_quoting_function}.
-@end deftypevar
-
-@deftypevar int rl_attempted_completion_over
-If an application-specific completion function assigned to
-@code{rl_attempted_completion_function} sets this variable to a non-zero
-value, Readline will not perform its default filename completion even
-if the application's completion function returns no matches.
-It should be set only by an application's completion function.
-@end deftypevar
-
-@deftypevar int rl_sort_completion_matches
-If an application sets this variable to 0, Readline will not sort the
-list of completions (which implies that it cannot remove any duplicate
-completions). The default value is 1, which means that Readline will
-sort the completions and, depending on the value of
-@code{rl_ignore_completion_duplicates}, will attempt to remove duplicate
-matches.
-@end deftypevar
-
-@deftypevar int rl_completion_type
-Set to a character describing the type of completion Readline is currently
-attempting; see the description of @code{rl_complete_internal()}
-(@pxref{Completion Functions}) for the list of characters.
-This is set to the appropriate value before any application-specific
-completion function is called, allowing such functions to present
-the same interface as @code{rl_complete()}.
-@end deftypevar
-
-@deftypevar int rl_completion_invoking_key
-Set to the final character in the key sequence that invoked one of the
-completion functions that call @code{rl_complete_internal()}. This is
-set to the appropriate value before any application-specific completion
-function is called.
-@end deftypevar
-
-@deftypevar int rl_inhibit_completion
-If this variable is non-zero, completion is inhibited. The completion
-character will be inserted as any other bound to @code{self-insert}.
-@end deftypevar
-
-@node A Short Completion Example
-@subsection A Short Completion Example
-
-Here is a small application demonstrating the use of the GNU Readline
-library. It is called @code{fileman}, and the source code resides in
-@file{examples/fileman.c}. This sample application provides
-completion of command names, line editing features, and access to the
-history list.
-
-@page
-@smallexample
-/* fileman.c -- A tiny application which demonstrates how to use the
- GNU Readline library. This application interactively allows users
- to manipulate files and their modes. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_FILE_H
-# include <sys/file.h>
-#endif
-#include <sys/stat.h>
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-
-#if defined (HAVE_STRING_H)
-# include <string.h>
-#else /* !HAVE_STRING_H */
-# include <strings.h>
-#endif /* !HAVE_STRING_H */
-
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-#include <time.h>
-
-#include <readline/readline.h>
-#include <readline/history.h>
-
-extern char *xmalloc PARAMS((size_t));
-
-/* The names of functions that actually do the manipulation. */
-int com_list PARAMS((char *));
-int com_view PARAMS((char *));
-int com_rename PARAMS((char *));
-int com_stat PARAMS((char *));
-int com_pwd PARAMS((char *));
-int com_delete PARAMS((char *));
-int com_help PARAMS((char *));
-int com_cd PARAMS((char *));
-int com_quit PARAMS((char *));
-
-/* A structure which contains information on the commands this program
- can understand. */
-
-typedef struct @{
- char *name; /* User printable name of the function. */
- rl_icpfunc_t *func; /* Function to call to do the job. */
- char *doc; /* Documentation for this function. */
-@} COMMAND;
-
-COMMAND commands[] = @{
- @{ "cd", com_cd, "Change to directory DIR" @},
- @{ "delete", com_delete, "Delete FILE" @},
- @{ "help", com_help, "Display this text" @},
- @{ "?", com_help, "Synonym for `help'" @},
- @{ "list", com_list, "List files in DIR" @},
- @{ "ls", com_list, "Synonym for `list'" @},
- @{ "pwd", com_pwd, "Print the current working directory" @},
- @{ "quit", com_quit, "Quit using Fileman" @},
- @{ "rename", com_rename, "Rename FILE to NEWNAME" @},
- @{ "stat", com_stat, "Print out statistics on FILE" @},
- @{ "view", com_view, "View the contents of FILE" @},
- @{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL @}
-@};
-
-/* Forward declarations. */
-char *stripwhite ();
-COMMAND *find_command ();
-
-/* The name of this program, as taken from argv[0]. */
-char *progname;
-
-/* When non-zero, this global means the user is done using this program. */
-int done;
-
-char *
-dupstr (s)
- char *s;
-@{
- char *r;
-
- r = xmalloc (strlen (s) + 1);
- strcpy (r, s);
- return (r);
-@}
-
-main (argc, argv)
- int argc;
- char **argv;
-@{
- char *line, *s;
-
- progname = argv[0];
-
- initialize_readline (); /* Bind our completer. */
-
- /* Loop reading and executing lines until the user quits. */
- for ( ; done == 0; )
- @{
- line = readline ("FileMan: ");
-
- if (!line)
- break;
-
- /* Remove leading and trailing whitespace from the line.
- Then, if there is anything left, add it to the history list
- and execute it. */
- s = stripwhite (line);
-
- if (*s)
- @{
- add_history (s);
- execute_line (s);
- @}
-
- free (line);
- @}
- exit (0);
-@}
-
-/* Execute a command line. */
-int
-execute_line (line)
- char *line;
-@{
- register int i;
- COMMAND *command;
- char *word;
-
- /* Isolate the command word. */
- i = 0;
- while (line[i] && whitespace (line[i]))
- i++;
- word = line + i;
-
- while (line[i] && !whitespace (line[i]))
- i++;
-
- if (line[i])
- line[i++] = '\0';
-
- command = find_command (word);
-
- if (!command)
- @{
- fprintf (stderr, "%s: No such command for FileMan.\n", word);
- return (-1);
- @}
-
- /* Get argument to command, if any. */
- while (whitespace (line[i]))
- i++;
-
- word = line + i;
-
- /* Call the function. */
- return ((*(command->func)) (word));
-@}
-
-/* Look up NAME as the name of a command, and return a pointer to that
- command. Return a NULL pointer if NAME isn't a command name. */
-COMMAND *
-find_command (name)
- char *name;
-@{
- register int i;
-
- for (i = 0; commands[i].name; i++)
- if (strcmp (name, commands[i].name) == 0)
- return (&commands[i]);
-
- return ((COMMAND *)NULL);
-@}
-
-/* Strip whitespace from the start and end of STRING. Return a pointer
- into STRING. */
-char *
-stripwhite (string)
- char *string;
-@{
- register char *s, *t;
-
- for (s = string; whitespace (*s); s++)
- ;
-
- if (*s == 0)
- return (s);
-
- t = s + strlen (s) - 1;
- while (t > s && whitespace (*t))
- t--;
- *++t = '\0';
-
- return s;
-@}
-
-/* **************************************************************** */
-/* */
-/* Interface to Readline Completion */
-/* */
-/* **************************************************************** */
-
-char *command_generator PARAMS((const char *, int));
-char **fileman_completion PARAMS((const char *, int, int));
-
-/* Tell the GNU Readline library how to complete. We want to try to complete
- on command names if this is the first word in the line, or on filenames
- if not. */
-initialize_readline ()
-@{
- /* Allow conditional parsing of the ~/.inputrc file. */
- rl_readline_name = "FileMan";
-
- /* Tell the completer that we want a crack first. */
- rl_attempted_completion_function = fileman_completion;
-@}
-
-/* Attempt to complete on the contents of TEXT. START and END bound the
- region of rl_line_buffer that contains the word to complete. TEXT is
- the word to complete. We can use the entire contents of rl_line_buffer
- in case we want to do some simple parsing. Return the array of matches,
- or NULL if there aren't any. */
-char **
-fileman_completion (text, start, end)
- const char *text;
- int start, end;
-@{
- char **matches;
-
- matches = (char **)NULL;
-
- /* If this word is at the start of the line, then it is a command
- to complete. Otherwise it is the name of a file in the current
- directory. */
- if (start == 0)
- matches = rl_completion_matches (text, command_generator);
-
- return (matches);
-@}
-
-/* Generator function for command completion. STATE lets us know whether
- to start from scratch; without any state (i.e. STATE == 0), then we
- start at the top of the list. */
-char *
-command_generator (text, state)
- const char *text;
- int state;
-@{
- static int list_index, len;
- char *name;
-
- /* If this is a new word to complete, initialize now. This includes
- saving the length of TEXT for efficiency, and initializing the index
- variable to 0. */
- if (!state)
- @{
- list_index = 0;
- len = strlen (text);
- @}
-
- /* Return the next name which partially matches from the command list. */
- while (name = commands[list_index].name)
- @{
- list_index++;
-
- if (strncmp (name, text, len) == 0)
- return (dupstr(name));
- @}
-
- /* If no names matched, then return NULL. */
- return ((char *)NULL);
-@}
-
-/* **************************************************************** */
-/* */
-/* FileMan Commands */
-/* */
-/* **************************************************************** */
-
-/* String to pass to system (). This is for the LIST, VIEW and RENAME
- commands. */
-static char syscom[1024];
-
-/* List the file(s) named in arg. */
-com_list (arg)
- char *arg;
-@{
- if (!arg)
- arg = "";
-
- sprintf (syscom, "ls -FClg %s", arg);
- return (system (syscom));
-@}
-
-com_view (arg)
- char *arg;
-@{
- if (!valid_argument ("view", arg))
- return 1;
-
-#if defined (__MSDOS__)
- /* more.com doesn't grok slashes in pathnames */
- sprintf (syscom, "less %s", arg);
-#else
- sprintf (syscom, "more %s", arg);
-#endif
- return (system (syscom));
-@}
-
-com_rename (arg)
- char *arg;
-@{
- too_dangerous ("rename");
- return (1);
-@}
-
-com_stat (arg)
- char *arg;
-@{
- struct stat finfo;
-
- if (!valid_argument ("stat", arg))
- return (1);
-
- if (stat (arg, &finfo) == -1)
- @{
- perror (arg);
- return (1);
- @}
-
- printf ("Statistics for `%s':\n", arg);
-
- printf ("%s has %d link%s, and is %d byte%s in length.\n",
- arg,
- finfo.st_nlink,
- (finfo.st_nlink == 1) ? "" : "s",
- finfo.st_size,
- (finfo.st_size == 1) ? "" : "s");
- printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
- printf (" Last access at: %s", ctime (&finfo.st_atime));
- printf (" Last modified at: %s", ctime (&finfo.st_mtime));
- return (0);
-@}
-
-com_delete (arg)
- char *arg;
-@{
- too_dangerous ("delete");
- return (1);
-@}
-
-/* Print out help for ARG, or for all of the commands if ARG is
- not present. */
-com_help (arg)
- char *arg;
-@{
- register int i;
- int printed = 0;
-
- for (i = 0; commands[i].name; i++)
- @{
- if (!*arg || (strcmp (arg, commands[i].name) == 0))
- @{
- printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
- printed++;
- @}
- @}
-
- if (!printed)
- @{
- printf ("No commands match `%s'. Possibilties are:\n", arg);
-
- for (i = 0; commands[i].name; i++)
- @{
- /* Print in six columns. */
- if (printed == 6)
- @{
- printed = 0;
- printf ("\n");
- @}
-
- printf ("%s\t", commands[i].name);
- printed++;
- @}
-
- if (printed)
- printf ("\n");
- @}
- return (0);
-@}
-
-/* Change to the directory ARG. */
-com_cd (arg)
- char *arg;
-@{
- if (chdir (arg) == -1)
- @{
- perror (arg);
- return 1;
- @}
-
- com_pwd ("");
- return (0);
-@}
-
-/* Print out the current working directory. */
-com_pwd (ignore)
- char *ignore;
-@{
- char dir[1024], *s;
-
- s = getcwd (dir, sizeof(dir) - 1);
- if (s == 0)
- @{
- printf ("Error getting pwd: %s\n", dir);
- return 1;
- @}
-
- printf ("Current directory is %s\n", dir);
- return 0;
-@}
-
-/* The user wishes to quit using this program. Just set DONE non-zero. */
-com_quit (arg)
- char *arg;
-@{
- done = 1;
- return (0);
-@}
-
-/* Function which tells you that you can't do this. */
-too_dangerous (caller)
- char *caller;
-@{
- fprintf (stderr,
- "%s: Too dangerous for me to distribute. Write it yourself.\n",
- caller);
-@}
-
-/* Return non-zero if ARG is a valid argument for CALLER, else print
- an error message and return zero. */
-int
-valid_argument (caller, arg)
- char *caller, *arg;
-@{
- if (!arg || !*arg)
- @{
- fprintf (stderr, "%s: Argument required.\n", caller);
- return (0);
- @}
-
- return (1);
-@}
-@end smallexample
+++ /dev/null
-@ignore
-Copyright (C) 1988-2012 Free Software Foundation, Inc.
-@end ignore
-
-@set EDITION 6.2
-@set VERSION 6.2
-@set UPDATED 27 August 2012
-@set UPDATED-MONTH August 2012
-
-@set LASTCHANGE Mon Aug 27 09:54:01 EDT 2012
+++ /dev/null
-/* input.c -- character input functions for readline. */
-
-/* Copyright (C) 1994-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 <http://www.gnu.org/licenses/>.
-*/
-
-#define READLINE_LIBRARY
-
-#if defined (__TANDEM)
-# include <floss.h>
-#endif
-
-#if defined (HAVE_CONFIG_H)
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <fcntl.h>
-#if defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif /* HAVE_SYS_FILE_H */
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#if defined (HAVE_STDLIB_H)
-# include <stdlib.h>
-#else
-# include "ansi_stdlib.h"
-#endif /* HAVE_STDLIB_H */
-
-#include <signal.h>
-
-#include "posixselect.h"
-
-#if defined (FIONREAD_IN_SYS_IOCTL)
-# include <sys/ioctl.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-/* System-specific feature definitions and include files. */
-#include "rldefs.h"
-#include "rlmbutil.h"
-
-/* Some standard library routines. */
-#include "readline.h"
-
-#include "rlprivate.h"
-#include "rlshell.h"
-#include "xmalloc.h"
-
-/* What kind of non-blocking I/O do we have? */
-#if !defined (O_NDELAY) && defined (O_NONBLOCK)
-# define O_NDELAY O_NONBLOCK /* Posix style */
-#endif
-
-/* Non-null means it is a pointer to a function to run while waiting for
- character input. */
-rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
-
-/* A function to replace _rl_input_available for applications using the
- callback interface. */
-rl_hook_func_t *rl_input_available_hook = (rl_hook_func_t *)NULL;
-
-rl_getc_func_t *rl_getc_function = rl_getc;
-
-static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */
-
-static int ibuffer_space PARAMS((void));
-static int rl_get_char PARAMS((int *));
-static int rl_gather_tyi PARAMS((void));
-
-/* **************************************************************** */
-/* */
-/* Character Input Buffering */
-/* */
-/* **************************************************************** */
-
-static int pop_index, push_index;
-static unsigned char ibuffer[512];
-static int ibuffer_len = sizeof (ibuffer) - 1;
-
-#define any_typein (push_index != pop_index)
-
-int
-_rl_any_typein ()
-{
- return any_typein;
-}
-
-/* Return the amount of space available in the buffer for stuffing
- characters. */
-static int
-ibuffer_space ()
-{
- if (pop_index > push_index)
- return (pop_index - push_index - 1);
- else
- return (ibuffer_len - (push_index - pop_index));
-}
-
-/* Get a key from the buffer of characters to be read.
- Return the key in KEY.
- Result is non-zero if there was a key, or 0 if there wasn't. */
-static int
-rl_get_char (key)
- int *key;
-{
- if (push_index == pop_index)
- return (0);
-
- *key = ibuffer[pop_index++];
-#if 0
- if (pop_index >= ibuffer_len)
-#else
- if (pop_index > ibuffer_len)
-#endif
- pop_index = 0;
-
- return (1);
-}
-
-/* Stuff KEY into the *front* of the input buffer.
- Returns non-zero if successful, zero if there is
- no space left in the buffer. */
-int
-_rl_unget_char (key)
- int key;
-{
- if (ibuffer_space ())
- {
- pop_index--;
- if (pop_index < 0)
- pop_index = ibuffer_len;
- ibuffer[pop_index] = key;
- return (1);
- }
- return (0);
-}
-
-int
-_rl_pushed_input_available ()
-{
- return (push_index != pop_index);
-}
-
-/* If a character is available to be read, then read it and stuff it into
- IBUFFER. Otherwise, just return. Returns number of characters read
- (0 if none available) and -1 on error (EIO). */
-static int
-rl_gather_tyi ()
-{
- int tty;
- register int tem, result;
- int chars_avail, k;
- char input;
-#if defined(HAVE_SELECT)
- fd_set readfds, exceptfds;
- struct timeval timeout;
-#endif
-
- chars_avail = 0;
- tty = fileno (rl_instream);
-
-#if defined (HAVE_SELECT)
- FD_ZERO (&readfds);
- FD_ZERO (&exceptfds);
- FD_SET (tty, &readfds);
- FD_SET (tty, &exceptfds);
- USEC_TO_TIMEVAL (_keyboard_input_timeout, timeout);
- result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
- if (result <= 0)
- return 0; /* Nothing to read. */
-#endif
-
- result = -1;
-#if defined (FIONREAD)
- errno = 0;
- result = ioctl (tty, FIONREAD, &chars_avail);
- if (result == -1 && errno == EIO)
- return -1;
-#endif
-
-#if defined (O_NDELAY)
- if (result == -1)
- {
- tem = fcntl (tty, F_GETFL, 0);
-
- fcntl (tty, F_SETFL, (tem | O_NDELAY));
- chars_avail = read (tty, &input, 1);
-
- fcntl (tty, F_SETFL, tem);
- if (chars_avail == -1 && errno == EAGAIN)
- return 0;
- if (chars_avail == 0) /* EOF */
- {
- rl_stuff_char (EOF);
- return (0);
- }
- }
-#endif /* O_NDELAY */
-
-#if defined (__MINGW32__)
- /* Use getch/_kbhit to check for available console input, in the same way
- that we read it normally. */
- chars_avail = isatty (tty) ? _kbhit () : 0;
- result = 0;
-#endif
-
- /* If there's nothing available, don't waste time trying to read
- something. */
- if (chars_avail <= 0)
- return 0;
-
- tem = ibuffer_space ();
-
- if (chars_avail > tem)
- chars_avail = tem;
-
- /* One cannot read all of the available input. I can only read a single
- character at a time, or else programs which require input can be
- thwarted. If the buffer is larger than one character, I lose.
- Damn! */
- if (tem < ibuffer_len)
- chars_avail = 0;
-
- if (result != -1)
- {
- while (chars_avail--)
- {
- RL_CHECK_SIGNALS ();
- k = (*rl_getc_function) (rl_instream);
- if (rl_stuff_char (k) == 0)
- break; /* some problem; no more room */
- if (k == NEWLINE || k == RETURN)
- break;
- }
- }
- else
- {
- if (chars_avail)
- rl_stuff_char (input);
- }
-
- return 1;
-}
-
-int
-rl_set_keyboard_input_timeout (u)
- int u;
-{
- int o;
-
- o = _keyboard_input_timeout;
- if (u >= 0)
- _keyboard_input_timeout = u;
- return (o);
-}
-
-/* Is there input available to be read on the readline input file
- descriptor? Only works if the system has select(2) or FIONREAD.
- Uses the value of _keyboard_input_timeout as the timeout; if another
- readline function wants to specify a timeout and not leave it up to
- the user, it should use _rl_input_queued(timeout_value_in_microseconds)
- instead. */
-int
-_rl_input_available ()
-{
-#if defined(HAVE_SELECT)
- fd_set readfds, exceptfds;
- struct timeval timeout;
-#endif
-#if !defined (HAVE_SELECT) && defined(FIONREAD)
- int chars_avail;
-#endif
- int tty;
-
- tty = fileno (rl_instream);
-
-#if defined (HAVE_SELECT)
- FD_ZERO (&readfds);
- FD_ZERO (&exceptfds);
- FD_SET (tty, &readfds);
- FD_SET (tty, &exceptfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = _keyboard_input_timeout;
- return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
-#else
-
-#if defined (FIONREAD)
- if (ioctl (tty, FIONREAD, &chars_avail) == 0)
- return (chars_avail);
-#endif
-
-#endif
-
-#if defined (__MINGW32__)
- if (isatty (tty))
- return (_kbhit ());
-#endif
-
- return 0;
-}
-
-int
-_rl_input_queued (t)
- int t;
-{
- int old_timeout, r;
-
- old_timeout = rl_set_keyboard_input_timeout (t);
- r = _rl_input_available ();
- rl_set_keyboard_input_timeout (old_timeout);
- return r;
-}
-
-void
-_rl_insert_typein (c)
- int c;
-{
- int key, t, i;
- char *string;
-
- i = key = 0;
- string = (char *)xmalloc (ibuffer_len + 1);
- string[i++] = (char) c;
-
- while ((t = rl_get_char (&key)) &&
- _rl_keymap[key].type == ISFUNC &&
- _rl_keymap[key].function == rl_insert)
- string[i++] = key;
-
- if (t)
- _rl_unget_char (key);
-
- string[i] = '\0';
- rl_insert_text (string);
- xfree (string);
-}
-
-/* Add KEY to the buffer of characters to be read. Returns 1 if the
- character was stuffed correctly; 0 otherwise. */
-int
-rl_stuff_char (key)
- int key;
-{
- if (ibuffer_space () == 0)
- return 0;
-
- if (key == EOF)
- {
- key = NEWLINE;
- rl_pending_input = EOF;
- RL_SETSTATE (RL_STATE_INPUTPENDING);
- }
- ibuffer[push_index++] = key;
-#if 0
- if (push_index >= ibuffer_len)
-#else
- if (push_index > ibuffer_len)
-#endif
- push_index = 0;
-
- return 1;
-}
-
-/* Make C be the next command to be executed. */
-int
-rl_execute_next (c)
- int c;
-{
- rl_pending_input = c;
- RL_SETSTATE (RL_STATE_INPUTPENDING);
- return 0;
-}
-
-/* Clear any pending input pushed with rl_execute_next() */
-int
-rl_clear_pending_input ()
-{
- rl_pending_input = 0;
- RL_UNSETSTATE (RL_STATE_INPUTPENDING);
- return 0;
-}
-
-/* **************************************************************** */
-/* */
-/* Character Input */
-/* */
-/* **************************************************************** */
-
-/* Read a key, including pending input. */
-int
-rl_read_key ()
-{
- int c, r;
-
- if (rl_pending_input)
- {
- c = rl_pending_input;
- rl_clear_pending_input ();
- }
- else
- {
- /* If input is coming from a macro, then use that. */
- if (c = _rl_next_macro_key ())
- return (c);
-
- /* If the user has an event function, then call it periodically. */
- if (rl_event_hook)
- {
- while (rl_event_hook)
- {
- if (rl_get_char (&c) != 0)
- break;
-
- if ((r = rl_gather_tyi ()) < 0) /* XXX - EIO */
- {
- rl_done = 1;
- return ('\n');
- }
- else if (r > 0) /* read something */
- continue;
-
- RL_CHECK_SIGNALS ();
- if (rl_done) /* XXX - experimental */
- return ('\n');
- (*rl_event_hook) ();
- }
- }
- else
- {
- if (rl_get_char (&c) == 0)
- c = (*rl_getc_function) (rl_instream);
-/* fprintf(stderr, "rl_read_key: calling RL_CHECK_SIGNALS: _rl_caught_signal = %d", _rl_caught_signal); */
- RL_CHECK_SIGNALS ();
- }
- }
-
- return (c);
-}
-
-int
-rl_getc (stream)
- FILE *stream;
-{
- int result;
- unsigned char c;
-
- while (1)
- {
- RL_CHECK_SIGNALS ();
-
- /* We know at this point that _rl_caught_signal == 0 */
-
-#if defined (__MINGW32__)
- if (isatty (fileno (stream)))
- return (getch ());
-#endif
- result = read (fileno (stream), &c, sizeof (unsigned char));
-
- if (result == sizeof (unsigned char))
- return (c);
-
- /* If zero characters are returned, then the file that we are
- reading from is empty! Return EOF in that case. */
- if (result == 0)
- return (EOF);
-
-#if defined (__BEOS__)
- if (errno == EINTR)
- continue;
-#endif
-
-#if defined (EWOULDBLOCK)
-# define X_EWOULDBLOCK EWOULDBLOCK
-#else
-# define X_EWOULDBLOCK -99
-#endif
-
-#if defined (EAGAIN)
-# define X_EAGAIN EAGAIN
-#else
-# define X_EAGAIN -99
-#endif
-
- if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
- {
- if (sh_unset_nodelay_mode (fileno (stream)) < 0)
- return (EOF);
- continue;
- }
-
-#undef X_EWOULDBLOCK
-#undef X_EAGAIN
-
- /* If the error that we received was EINTR, then try again,
- this is simply an interrupted system call to read ().
- Otherwise, some error ocurred, also signifying EOF. */
- if (errno != EINTR)
- return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
- else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
- return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
- else if (rl_event_hook)
- (*rl_event_hook) ();
- }
-}
-
-#if defined (HANDLE_MULTIBYTE)
-/* read multibyte char */
-int
-_rl_read_mbchar (mbchar, size)
- char *mbchar;
- int size;
-{
- int mb_len, c;
- size_t mbchar_bytes_length;
- wchar_t wc;
- mbstate_t ps, ps_back;
-
- memset(&ps, 0, sizeof (mbstate_t));
- memset(&ps_back, 0, sizeof (mbstate_t));
-
- mb_len = 0;
- while (mb_len < size)
- {
- RL_SETSTATE(RL_STATE_MOREINPUT);
- c = rl_read_key ();
- RL_UNSETSTATE(RL_STATE_MOREINPUT);
-
- if (c < 0)
- break;
-
- mbchar[mb_len++] = c;
-
- mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
- if (mbchar_bytes_length == (size_t)(-1))
- break; /* invalid byte sequence for the current locale */
- else if (mbchar_bytes_length == (size_t)(-2))
- {
- /* shorted bytes */
- ps = ps_back;
- continue;
- }
- else if (mbchar_bytes_length == 0)
- {
- mbchar[0] = '\0'; /* null wide character */
- mb_len = 1;
- break;
- }
- else if (mbchar_bytes_length > (size_t)(0))
- break;
- }
-
- return mb_len;
-}
-
-/* Read a multibyte-character string whose first character is FIRST into
- the buffer MB of length MLEN. Returns the last character read, which
- may be FIRST. Used by the search functions, among others. Very similar
- to _rl_read_mbchar. */
-int
-_rl_read_mbstring (first, mb, mlen)
- int first;
- char *mb;
- int mlen;
-{
- int i, c;
- mbstate_t ps;
-
- c = first;
- memset (mb, 0, mlen);
- for (i = 0; c >= 0 && i < mlen; i++)
- {
- mb[i] = (char)c;
- memset (&ps, 0, sizeof (mbstate_t));
- if (_rl_get_char_len (mb, &ps) == -2)
- {
- /* Read more for multibyte character */
- RL_SETSTATE (RL_STATE_MOREINPUT);
- c = rl_read_key ();
- RL_UNSETSTATE (RL_STATE_MOREINPUT);
- }
- else
- break;
- }
- return c;
-}
-#endif /* HANDLE_MULTIBYTE */
+++ /dev/null
-/* Readline.h -- the names of functions callable from within 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 <http://www.gnu.org/licenses/>.
-*/
-
-#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 <readline/rlstdc.h>
-# include <readline/rltypedefs.h>
-# include <readline/keymaps.h>
-# include <readline/tilde.h>
-#endif
-
-/* Hex-encoded Readline version number. */
-#define RL_READLINE_VERSION 0x0602 /* Readline 6.2 */
-#define RL_VERSION_MAJOR 6
-#define RL_VERSION_MINOR 2
-
-/* 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));
-/* Not available unless __CYGWIN__ is defined. */
-#ifdef __CYGWIN__
-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 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));
-
-/* 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));
-
-/* 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 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;
-
-/* 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;
- int kseqlen;
- FILE *inf;
- FILE *outf;
- int pendingin;
- char *macro;
-
- /* signal state */
- int catchsigs;
- int catchsigwinch;
-
- /* search state */
-
- /* completion state */
-
- /* options 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_ */
+++ /dev/null
-/* rlprivate.h -- functions and variables global to the readline library,
- but not intended for use by applications. */
-
-/* Copyright (C) 1999-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 <http://www.gnu.org/licenses/>.
-*/
-
-#if !defined (_RL_PRIVATE_H_)
-#define _RL_PRIVATE_H_
-
-#include "rlconf.h" /* for VISIBLE_STATS */
-#include "rlstdc.h"
-#include "posixjmp.h" /* defines procenv_t */
-
-/*************************************************************************
- * *
- * Convenience definitions *
- * *
- *************************************************************************/
-
-#define EMACS_MODE() (rl_editing_mode == emacs_mode)
-#define VI_COMMAND_MODE() (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
-#define VI_INSERT_MODE() (rl_editing_mode == vi_mode && _rl_keymap == vi_insertion_keymap)
-
-#define RL_CHECK_SIGNALS() \
- do { \
- if (_rl_caught_signal) _rl_signal_handler (_rl_caught_signal); \
- } while (0)
-
-#define RL_SIG_RECEIVED() (_rl_caught_signal != 0)
-#define RL_SIGINT_RECEIVED() (_rl_caught_signal == SIGINT)
-
-/*************************************************************************
- * *
- * Global structs undocumented in texinfo manual and not in readline.h *
- * *
- *************************************************************************/
-/* search types */
-#define RL_SEARCH_ISEARCH 0x01 /* incremental search */
-#define RL_SEARCH_NSEARCH 0x02 /* non-incremental search */
-#define RL_SEARCH_CSEARCH 0x04 /* intra-line char search */
-
-/* search flags */
-#define SF_REVERSE 0x01
-#define SF_FOUND 0x02
-#define SF_FAILED 0x04
-#define SF_CHGKMAP 0x08
-
-typedef struct __rl_search_context
-{
- int type;
- int sflags;
-
- char *search_string;
- int search_string_index;
- int search_string_size;
-
- char **lines;
- char *allocated_line;
- int hlen;
- int hindex;
-
- int save_point;
- int save_mark;
- int save_line;
- int last_found_line;
- char *prev_line_found;
-
- UNDO_LIST *save_undo_list;
-
- Keymap keymap; /* used when dispatching commands in search string */
- Keymap okeymap; /* original keymap */
-
- int history_pos;
- int direction;
-
- int prevc;
- int lastc;
-#if defined (HANDLE_MULTIBYTE)
- char mb[MB_LEN_MAX];
- char pmb[MB_LEN_MAX];
-#endif
-
- char *sline;
- int sline_len;
- int sline_index;
-
- char *search_terminators;
-} _rl_search_cxt;
-
-/* Callback data for reading numeric arguments */
-#define NUM_SAWMINUS 0x01
-#define NUM_SAWDIGITS 0x02
-#define NUM_READONE 0x04
-
-typedef int _rl_arg_cxt;
-
-/* A context for reading key sequences longer than a single character when
- using the callback interface. */
-#define KSEQ_DISPATCHED 0x01
-#define KSEQ_SUBSEQ 0x02
-#define KSEQ_RECURSIVE 0x04
-
-typedef struct __rl_keyseq_context
-{
- int flags;
- int subseq_arg;
- int subseq_retval; /* XXX */
- Keymap dmap;
-
- Keymap oldmap;
- int okey;
- struct __rl_keyseq_context *ocxt;
- int childval;
-} _rl_keyseq_cxt;
-
-/* vi-mode commands that use result of motion command to define boundaries */
-#define VIM_DELETE 0x01
-#define VIM_CHANGE 0x02
-#define VIM_YANK 0x04
-
-/* various states for vi-mode commands that use motion commands. reflects
- RL_READLINE_STATE */
-#define VMSTATE_READ 0x01
-#define VMSTATE_NUMARG 0x02
-
-typedef struct __rl_vimotion_context
-{
- int op;
- int state;
- int flags; /* reserved */
- _rl_arg_cxt ncxt;
- int numeric_arg;
- int start, end; /* rl_point, rl_end */
- int key, motion; /* initial key, motion command */
-} _rl_vimotion_cxt;
-
-/* fill in more as needed */
-/* `Generic' callback data and functions */
-typedef struct __rl_callback_generic_arg
-{
- int count;
- int i1, i2;
- /* add here as needed */
-} _rl_callback_generic_arg;
-
-typedef int _rl_callback_func_t PARAMS((_rl_callback_generic_arg *));
-
-typedef void _rl_sigcleanup_func_t PARAMS((int, void *));
-
-/*************************************************************************
- * *
- * Global functions undocumented in texinfo manual and not in readline.h *
- * *
- *************************************************************************/
-
-/*************************************************************************
- * *
- * Global variables undocumented in texinfo manual and not in readline.h *
- * *
- *************************************************************************/
-
-/* complete.c */
-extern int rl_complete_with_tilde_expansion;
-#if defined (VISIBLE_STATS)
-extern int rl_visible_stats;
-#endif /* VISIBLE_STATS */
-#if defined (COLOR_SUPPORT)
-extern int _rl_colored_stats;
-#endif
-
-/* readline.c */
-extern int rl_line_buffer_len;
-extern int rl_arg_sign;
-extern int rl_visible_prompt_length;
-extern int rl_byte_oriented;
-
-/* display.c */
-extern int rl_display_fixed;
-
-/* parens.c */
-extern int rl_blink_matching_paren;
-
-/*************************************************************************
- * *
- * Global functions and variables unused and undocumented *
- * *
- *************************************************************************/
-
-/* kill.c */
-extern int rl_set_retained_kills PARAMS((int));
-
-/* terminal.c */
-extern void _rl_set_screen_size PARAMS((int, int));
-
-/* undo.c */
-extern int _rl_fix_last_undo_of_type PARAMS((int, int, int));
-
-/* util.c */
-extern char *_rl_savestring PARAMS((const char *));
-
-/*************************************************************************
- * *
- * Functions and variables private to the readline library *
- * *
- *************************************************************************/
-
-/* NOTE: Functions and variables prefixed with `_rl_' are
- pseudo-global: they are global so they can be shared
- between files in the readline library, but are not intended
- to be visible to readline callers. */
-
-/*************************************************************************
- * Undocumented private functions *
- *************************************************************************/
-
-#if defined(READLINE_CALLBACKS)
-
-/* readline.c */
-extern void readline_internal_setup PARAMS((void));
-extern char *readline_internal_teardown PARAMS((int));
-extern int readline_internal_char PARAMS((void));
-
-extern _rl_keyseq_cxt *_rl_keyseq_cxt_alloc PARAMS((void));
-extern void _rl_keyseq_cxt_dispose PARAMS((_rl_keyseq_cxt *));
-extern void _rl_keyseq_chain_dispose PARAMS((void));
-
-extern int _rl_dispatch_callback PARAMS((_rl_keyseq_cxt *));
-
-/* callback.c */
-extern _rl_callback_generic_arg *_rl_callback_data_alloc PARAMS((int));
-extern void _rl_callback_data_dispose PARAMS((_rl_callback_generic_arg *));
-
-#endif /* READLINE_CALLBACKS */
-
-/* bind.c */
-extern char *_rl_untranslate_macro_value PARAMS((char *, int));
-
-/* complete.c */
-extern void _rl_reset_completion_state PARAMS((void));
-extern char _rl_find_completion_word PARAMS((int *, int *));
-extern void _rl_free_match_list PARAMS((char **));
-
-/* display.c */
-extern char *_rl_strip_prompt PARAMS((char *));
-extern void _rl_reset_prompt PARAMS((void));
-extern void _rl_move_cursor_relative PARAMS((int, const char *));
-extern void _rl_move_vert PARAMS((int));
-extern void _rl_save_prompt PARAMS((void));
-extern void _rl_restore_prompt PARAMS((void));
-extern char *_rl_make_prompt_for_search PARAMS((int));
-extern void _rl_erase_at_end_of_line PARAMS((int));
-extern void _rl_clear_to_eol PARAMS((int));
-extern void _rl_clear_screen PARAMS((void));
-extern void _rl_update_final PARAMS((void));
-extern void _rl_redisplay_after_sigwinch PARAMS((void));
-extern void _rl_clean_up_for_exit PARAMS((void));
-extern void _rl_erase_entire_line PARAMS((void));
-extern int _rl_current_display_line PARAMS((void));
-
-/* input.c */
-extern int _rl_any_typein PARAMS((void));
-extern int _rl_input_available PARAMS((void));
-extern int _rl_input_queued PARAMS((int));
-extern void _rl_insert_typein PARAMS((int));
-extern int _rl_unget_char PARAMS((int));
-extern int _rl_pushed_input_available PARAMS((void));
-
-/* isearch.c */
-extern _rl_search_cxt *_rl_scxt_alloc PARAMS((int, int));
-extern void _rl_scxt_dispose PARAMS((_rl_search_cxt *, int));
-
-extern int _rl_isearch_dispatch PARAMS((_rl_search_cxt *, int));
-extern int _rl_isearch_callback PARAMS((_rl_search_cxt *));
-
-extern int _rl_search_getchar PARAMS((_rl_search_cxt *));
-
-/* macro.c */
-extern void _rl_with_macro_input PARAMS((char *));
-extern int _rl_next_macro_key PARAMS((void));
-extern int _rl_prev_macro_key PARAMS((void));
-extern void _rl_push_executing_macro PARAMS((void));
-extern void _rl_pop_executing_macro PARAMS((void));
-extern void _rl_add_macro_char PARAMS((int));
-extern void _rl_kill_kbd_macro PARAMS((void));
-
-/* misc.c */
-extern int _rl_arg_overflow PARAMS((void));
-extern void _rl_arg_init PARAMS((void));
-extern int _rl_arg_getchar PARAMS((void));
-extern int _rl_arg_callback PARAMS((_rl_arg_cxt));
-extern void _rl_reset_argument PARAMS((void));
-
-extern void _rl_start_using_history PARAMS((void));
-extern int _rl_free_saved_history_line PARAMS((void));
-extern void _rl_set_insert_mode PARAMS((int, int));
-
-extern void _rl_revert_all_lines PARAMS((void));
-
-/* nls.c */
-extern int _rl_init_eightbit PARAMS((void));
-
-/* parens.c */
-extern void _rl_enable_paren_matching PARAMS((int));
-
-/* readline.c */
-extern void _rl_init_line_state PARAMS((void));
-extern void _rl_set_the_line PARAMS((void));
-extern int _rl_dispatch PARAMS((int, Keymap));
-extern int _rl_dispatch_subseq PARAMS((int, Keymap, int));
-extern void _rl_internal_char_cleanup PARAMS((void));
-
-/* rltty.c */
-extern int _rl_disable_tty_signals PARAMS((void));
-extern int _rl_restore_tty_signals PARAMS((void));
-
-/* search.c */
-extern int _rl_nsearch_callback PARAMS((_rl_search_cxt *));
-
-/* signals.c */
-extern void _rl_signal_handler PARAMS((int));
-
-extern void _rl_block_sigint PARAMS((void));
-extern void _rl_release_sigint PARAMS((void));
-extern void _rl_block_sigwinch PARAMS((void));
-extern void _rl_release_sigwinch PARAMS((void));
-
-/* terminal.c */
-extern void _rl_get_screen_size PARAMS((int, int));
-extern void _rl_sigwinch_resize_terminal PARAMS((void));
-extern int _rl_init_terminal_io PARAMS((const char *));
-#ifdef _MINIX
-extern void _rl_output_character_function PARAMS((int));
-#else
-extern int _rl_output_character_function PARAMS((int));
-#endif
-extern void _rl_output_some_chars PARAMS((const char *, int));
-extern int _rl_backspace PARAMS((int));
-extern void _rl_enable_meta_key PARAMS((void));
-extern void _rl_disable_meta_key PARAMS((void));
-extern void _rl_control_keypad PARAMS((int));
-extern void _rl_set_cursor PARAMS((int, int));
-
-/* text.c */
-extern void _rl_fix_point PARAMS((int));
-extern int _rl_replace_text PARAMS((const char *, int, int));
-extern int _rl_forward_char_internal PARAMS((int));
-extern int _rl_insert_char PARAMS((int, int));
-extern int _rl_overwrite_char PARAMS((int, int));
-extern int _rl_overwrite_rubout PARAMS((int, int));
-extern int _rl_rubout_char PARAMS((int, int));
-#if defined (HANDLE_MULTIBYTE)
-extern int _rl_char_search_internal PARAMS((int, int, char *, int));
-#else
-extern int _rl_char_search_internal PARAMS((int, int, int));
-#endif
-extern int _rl_set_mark_at_pos PARAMS((int));
-
-/* undo.c */
-extern UNDO_LIST *_rl_copy_undo_entry PARAMS((UNDO_LIST *));
-extern UNDO_LIST *_rl_copy_undo_list PARAMS((UNDO_LIST *));
-extern void _rl_free_undo_list PARAMS((UNDO_LIST *));
-
-/* util.c */
-#if defined (USE_VARARGS) && defined (PREFER_STDARG)
-extern void _rl_ttymsg (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
-extern void _rl_errmsg (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
-extern void _rl_trace (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
-#else
-extern void _rl_ttymsg ();
-extern void _rl_errmsg ();
-extern void _rl_trace ();
-#endif
-extern void _rl_audit_tty PARAMS((char *));
-
-extern int _rl_tropen PARAMS((void));
-
-extern int _rl_abort_internal PARAMS((void));
-extern int _rl_null_function PARAMS((int, int));
-extern char *_rl_strindex PARAMS((const char *, const char *));
-extern int _rl_qsort_string_compare PARAMS((char **, char **));
-extern int (_rl_uppercase_p) PARAMS((int));
-extern int (_rl_lowercase_p) PARAMS((int));
-extern int (_rl_pure_alphabetic) PARAMS((int));
-extern int (_rl_digit_p) PARAMS((int));
-extern int (_rl_to_lower) PARAMS((int));
-extern int (_rl_to_upper) PARAMS((int));
-extern int (_rl_digit_value) PARAMS((int));
-
-/* vi_mode.c */
-extern void _rl_vi_initialize_line PARAMS((void));
-extern void _rl_vi_reset_last PARAMS((void));
-extern void _rl_vi_set_last PARAMS((int, int, int));
-extern int _rl_vi_textmod_command PARAMS((int));
-extern void _rl_vi_done_inserting PARAMS((void));
-extern int _rl_vi_domove_callback PARAMS((_rl_vimotion_cxt *));
-
-/*************************************************************************
- * Undocumented private variables *
- *************************************************************************/
-
-/* bind.c */
-extern const char * const _rl_possible_control_prefixes[];
-extern const char * const _rl_possible_meta_prefixes[];
-
-/* callback.c */
-extern _rl_callback_func_t *_rl_callback_func;
-extern _rl_callback_generic_arg *_rl_callback_data;
-
-/* complete.c */
-extern int _rl_complete_show_all;
-extern int _rl_complete_show_unmodified;
-extern int _rl_complete_mark_directories;
-extern int _rl_complete_mark_symlink_dirs;
-extern int _rl_completion_prefix_display_length;
-extern int _rl_completion_columns;
-extern int _rl_print_completions_horizontally;
-extern int _rl_completion_case_fold;
-extern int _rl_completion_case_map;
-extern int _rl_match_hidden_files;
-extern int _rl_page_completions;
-extern int _rl_skip_completed_text;
-extern int _rl_menu_complete_prefix_first;
-
-/* display.c */
-extern int _rl_vis_botlin;
-extern int _rl_last_c_pos;
-extern int _rl_suppress_redisplay;
-extern int _rl_want_redisplay;
-
-/* isearch.c */
-extern char *_rl_isearch_terminators;
-
-extern _rl_search_cxt *_rl_iscxt;
-
-/* macro.c */
-extern char *_rl_executing_macro;
-
-/* misc.c */
-extern int _rl_history_preserve_point;
-extern int _rl_history_saved_point;
-
-extern _rl_arg_cxt _rl_argcxt;
-
-/* nls.c */
-extern int _rl_utf8locale;
-
-/* readline.c */
-extern int _rl_echoing_p;
-extern int _rl_horizontal_scroll_mode;
-extern int _rl_mark_modified_lines;
-extern int _rl_bell_preference;
-extern int _rl_meta_flag;
-extern int _rl_convert_meta_chars_to_ascii;
-extern int _rl_output_meta_chars;
-extern int _rl_bind_stty_chars;
-extern int _rl_revert_all_at_newline;
-extern int _rl_echo_control_chars;
-extern int _rl_show_mode_in_prompt;
-extern char *_rl_comment_begin;
-extern unsigned char _rl_parsing_conditionalized_out;
-extern Keymap _rl_keymap;
-extern FILE *_rl_in_stream;
-extern FILE *_rl_out_stream;
-extern int _rl_last_command_was_kill;
-extern int _rl_eof_char;
-extern procenv_t _rl_top_level;
-extern _rl_keyseq_cxt *_rl_kscxt;
-extern int _rl_keyseq_timeout;
-
-extern int _rl_executing_keyseq_size;
-
-/* search.c */
-extern _rl_search_cxt *_rl_nscxt;
-
-/* signals.c */
-extern int _rl_interrupt_immediately;
-extern int volatile _rl_caught_signal;
-
-extern _rl_sigcleanup_func_t *_rl_sigcleanup;
-extern void *_rl_sigcleanarg;
-
-extern int _rl_echoctl;
-
-extern int _rl_intr_char;
-extern int _rl_quit_char;
-extern int _rl_susp_char;
-
-/* terminal.c */
-extern int _rl_enable_keypad;
-extern int _rl_enable_meta;
-extern char *_rl_term_clreol;
-extern char *_rl_term_clrpag;
-extern char *_rl_term_im;
-extern char *_rl_term_ic;
-extern char *_rl_term_ei;
-extern char *_rl_term_DC;
-extern char *_rl_term_up;
-extern char *_rl_term_dc;
-extern char *_rl_term_cr;
-extern char *_rl_term_IC;
-extern char *_rl_term_forward_char;
-extern int _rl_screenheight;
-extern int _rl_screenwidth;
-extern int _rl_screenchars;
-extern int _rl_terminal_can_insert;
-extern int _rl_term_autowrap;
-
-/* undo.c */
-extern int _rl_doing_an_undo;
-extern int _rl_undo_group_level;
-
-/* vi_mode.c */
-extern int _rl_vi_last_command;
-extern _rl_vimotion_cxt *_rl_vimvcxt;
-
-#endif /* _RL_PRIVATE_H_ */
+++ /dev/null
-/* terminal.c -- controlling the terminal with termcap. */
-
-/* Copyright (C) 1996-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 <http://www.gnu.org/licenses/>.
-*/
-
-#define READLINE_LIBRARY
-
-#if defined (HAVE_CONFIG_H)
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-#include "posixstat.h"
-#include <fcntl.h>
-#if defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif /* HAVE_SYS_FILE_H */
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#if defined (HAVE_STDLIB_H)
-# include <stdlib.h>
-#else
-# include "ansi_stdlib.h"
-#endif /* HAVE_STDLIB_H */
-
-#if defined (HAVE_LOCALE_H)
-# include <locale.h>
-#endif
-
-#include <stdio.h>
-
-/* System-specific feature definitions and include files. */
-#include "rldefs.h"
-
-#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
-# include <sys/ioctl.h>
-#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
-
-#ifdef __MSDOS__
-# include <pc.h>
-#endif
-
-#include "rltty.h"
-#include "tcap.h"
-
-/* Some standard library routines. */
-#include "readline.h"
-#include "history.h"
-
-#include "rlprivate.h"
-#include "rlshell.h"
-#include "xmalloc.h"
-
-#if defined (__MINGW32__)
-# include <windows.h>
-# include <wincon.h>
-
-static void _win_get_screensize PARAMS((int *, int *));
-#endif
-
-#if defined (__EMX__)
-static void _emx_get_screensize PARAMS((int *, int *));
-#endif
-
-#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
-#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
-
-/* If the calling application sets this to a non-zero value, readline will
- use the $LINES and $COLUMNS environment variables to set its idea of the
- window size before interrogating the kernel. */
-int rl_prefer_env_winsize = 0;
-
-/* **************************************************************** */
-/* */
-/* Terminal and Termcap */
-/* */
-/* **************************************************************** */
-
-#ifndef __MSDOS__
-static char *term_buffer = (char *)NULL;
-static char *term_string_buffer = (char *)NULL;
-#endif
-
-static int tcap_initialized;
-
-#if !defined (__linux__) && !defined (NCURSES_VERSION)
-# if defined (__EMX__) || defined (NEED_EXTERN_PC)
-extern
-# endif /* __EMX__ || NEED_EXTERN_PC */
-char PC, *BC, *UP;
-#endif /* !__linux__ && !NCURSES_VERSION */
-
-/* Some strings to control terminal actions. These are output by tputs (). */
-char *_rl_term_clreol;
-char *_rl_term_clrpag;
-char *_rl_term_cr;
-char *_rl_term_backspace;
-char *_rl_term_goto;
-char *_rl_term_pc;
-
-/* Non-zero if we determine that the terminal can do character insertion. */
-int _rl_terminal_can_insert = 0;
-
-/* How to insert characters. */
-char *_rl_term_im;
-char *_rl_term_ei;
-char *_rl_term_ic;
-char *_rl_term_ip;
-char *_rl_term_IC;
-
-/* How to delete characters. */
-char *_rl_term_dc;
-char *_rl_term_DC;
-
-char *_rl_term_forward_char;
-
-/* How to go up a line. */
-char *_rl_term_up;
-
-/* A visible bell; char if the terminal can be made to flash the screen. */
-static char *_rl_visible_bell;
-
-/* Non-zero means the terminal can auto-wrap lines. */
-int _rl_term_autowrap = -1;
-
-/* Non-zero means that this terminal has a meta key. */
-static int term_has_meta;
-
-/* The sequences to write to turn on and off the meta key, if this
- terminal has one. */
-static char *_rl_term_mm;
-static char *_rl_term_mo;
-
-/* The key sequences output by the arrow keys, if this terminal has any. */
-static char *_rl_term_ku;
-static char *_rl_term_kd;
-static char *_rl_term_kr;
-static char *_rl_term_kl;
-
-/* How to initialize and reset the arrow keys, if this terminal has any. */
-static char *_rl_term_ks;
-static char *_rl_term_ke;
-
-/* The key sequences sent by the Home and End keys, if any. */
-static char *_rl_term_kh;
-static char *_rl_term_kH;
-static char *_rl_term_at7; /* @7 */
-
-/* Delete key */
-static char *_rl_term_kD;
-
-/* Insert key */
-static char *_rl_term_kI;
-
-/* Cursor control */
-static char *_rl_term_vs; /* very visible */
-static char *_rl_term_ve; /* normal */
-
-static void bind_termcap_arrow_keys PARAMS((Keymap));
-
-/* Variables that hold the screen dimensions, used by the display code. */
-int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
-
-/* Non-zero means the user wants to enable the keypad. */
-int _rl_enable_keypad;
-
-/* Non-zero means the user wants to enable a meta key. */
-int _rl_enable_meta = 1;
-
-#if defined (__EMX__)
-static void
-_emx_get_screensize (swp, shp)
- int *swp, *shp;
-{
- int sz[2];
-
- _scrsize (sz);
-
- if (swp)
- *swp = sz[0];
- if (shp)
- *shp = sz[1];
-}
-#endif
-
-#if defined (__MINGW32__)
-static void
-_win_get_screensize (swp, shp)
- int *swp, *shp;
-{
- HANDLE hConOut;
- CONSOLE_SCREEN_BUFFER_INFO scr;
-
- hConOut = GetStdHandle (STD_OUTPUT_HANDLE);
- if (hConOut != INVALID_HANDLE_VALUE)
- {
- if (GetConsoleScreenBufferInfo (hConOut, &scr))
- {
- *swp = scr.dwSize.X;
- *shp = scr.srWindow.Bottom - scr.srWindow.Top + 1;
- }
- }
-}
-#endif
-
-/* Get readline's idea of the screen size. TTY is a file descriptor open
- to the terminal. If IGNORE_ENV is true, we do not pay attention to the
- values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
- non-null serve to check whether or not we have initialized termcap. */
-void
-_rl_get_screen_size (tty, ignore_env)
- int tty, ignore_env;
-{
- char *ss;
-#if defined (TIOCGWINSZ)
- struct winsize window_size;
-#endif /* TIOCGWINSZ */
- int wr, wc;
-
- wr = wc = -1;
-#if defined (TIOCGWINSZ)
- if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
- {
- wc = (int) window_size.ws_col;
- wr = (int) window_size.ws_row;
- }
-#endif /* TIOCGWINSZ */
-
-#if defined (__EMX__)
- _emx_get_screensize (&wc, &wr);
-#elif defined (__MINGW32__)
- _win_get_screensize (&wc, &wr);
-#endif
-
- if (ignore_env || rl_prefer_env_winsize == 0)
- {
- _rl_screenwidth = wc;
- _rl_screenheight = wr;
- }
- else
- _rl_screenwidth = _rl_screenheight = -1;
-
- /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
- is unset. If we prefer the environment, check it first before
- assigning the value returned by the kernel. */
- if (_rl_screenwidth <= 0)
- {
- if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS")))
- _rl_screenwidth = atoi (ss);
-
- if (_rl_screenwidth <= 0)
- _rl_screenwidth = wc;
-
-#if defined (__DJGPP__)
- if (_rl_screenwidth <= 0)
- _rl_screenwidth = ScreenCols ();
-#else
- if (_rl_screenwidth <= 0 && term_string_buffer)
- _rl_screenwidth = tgetnum ("co");
-#endif
- }
-
- /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
- is unset. */
- if (_rl_screenheight <= 0)
- {
- if (ignore_env == 0 && (ss = sh_get_env_value ("LINES")))
- _rl_screenheight = atoi (ss);
-
- if (_rl_screenheight <= 0)
- _rl_screenheight = wr;
-
-#if defined (__DJGPP__)
- if (_rl_screenheight <= 0)
- _rl_screenheight = ScreenRows ();
-#else
- if (_rl_screenheight <= 0 && term_string_buffer)
- _rl_screenheight = tgetnum ("li");
-#endif
- }
-
- /* If all else fails, default to 80x24 terminal. */
- if (_rl_screenwidth <= 1)
- _rl_screenwidth = 80;
-
- if (_rl_screenheight <= 0)
- _rl_screenheight = 24;
-
- /* If we're being compiled as part of bash, set the environment
- variables $LINES and $COLUMNS to new values. Otherwise, just
- do a pair of putenv () or setenv () calls. */
- sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth);
-
- if (_rl_term_autowrap == 0)
- _rl_screenwidth--;
-
- _rl_screenchars = _rl_screenwidth * _rl_screenheight;
-}
-
-void
-_rl_set_screen_size (rows, cols)
- int rows, cols;
-{
- if (_rl_term_autowrap == -1)
- _rl_init_terminal_io (rl_terminal_name);
-
- if (rows > 0)
- _rl_screenheight = rows;
- if (cols > 0)
- {
- _rl_screenwidth = cols;
- if (_rl_term_autowrap == 0)
- _rl_screenwidth--;
- }
-
- if (rows > 0 || cols > 0)
- _rl_screenchars = _rl_screenwidth * _rl_screenheight;
-}
-
-void
-rl_set_screen_size (rows, cols)
- int rows, cols;
-{
- _rl_set_screen_size (rows, cols);
-}
-
-void
-rl_get_screen_size (rows, cols)
- int *rows, *cols;
-{
- if (rows)
- *rows = _rl_screenheight;
- if (cols)
- *cols = _rl_screenwidth;
-}
-
-void
-rl_reset_screen_size ()
-{
- _rl_get_screen_size (fileno (rl_instream), 0);
-}
-
-void
-_rl_sigwinch_resize_terminal ()
-{
- _rl_get_screen_size (fileno (rl_instream), 1);
-}
-
-void
-rl_resize_terminal ()
-{
- _rl_get_screen_size (fileno (rl_instream), 1);
- if (_rl_echoing_p)
- {
- if (CUSTOM_REDISPLAY_FUNC ())
- rl_forced_update_display ();
- else if (RL_ISSTATE(RL_STATE_REDISPLAYING) == 0)
- _rl_redisplay_after_sigwinch ();
- }
-}
-
-struct _tc_string {
- const char * const tc_var;
- char **tc_value;
-};
-
-/* This should be kept sorted, just in case we decide to change the
- search algorithm to something smarter. */
-static const struct _tc_string tc_strings[] =
-{
- { "@7", &_rl_term_at7 },
- { "DC", &_rl_term_DC },
- { "IC", &_rl_term_IC },
- { "ce", &_rl_term_clreol },
- { "cl", &_rl_term_clrpag },
- { "cr", &_rl_term_cr },
- { "dc", &_rl_term_dc },
- { "ei", &_rl_term_ei },
- { "ic", &_rl_term_ic },
- { "im", &_rl_term_im },
- { "kD", &_rl_term_kD }, /* delete */
- { "kH", &_rl_term_kH }, /* home down ?? */
- { "kI", &_rl_term_kI }, /* insert */
- { "kd", &_rl_term_kd },
- { "ke", &_rl_term_ke }, /* end keypad mode */
- { "kh", &_rl_term_kh }, /* home */
- { "kl", &_rl_term_kl },
- { "kr", &_rl_term_kr },
- { "ks", &_rl_term_ks }, /* start keypad mode */
- { "ku", &_rl_term_ku },
- { "le", &_rl_term_backspace },
- { "mm", &_rl_term_mm },
- { "mo", &_rl_term_mo },
- { "nd", &_rl_term_forward_char },
- { "pc", &_rl_term_pc },
- { "up", &_rl_term_up },
- { "vb", &_rl_visible_bell },
- { "vs", &_rl_term_vs },
- { "ve", &_rl_term_ve },
-};
-
-#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
-
-/* Read the desired terminal capability strings into BP. The capabilities
- are described in the TC_STRINGS table. */
-static void
-get_term_capabilities (bp)
- char **bp;
-{
-#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */
- register int i;
-
- for (i = 0; i < NUM_TC_STRINGS; i++)
- *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
-#endif
- tcap_initialized = 1;
-}
-
-int
-_rl_init_terminal_io (terminal_name)
- const char *terminal_name;
-{
- const char *term;
- char *buffer;
- int tty, tgetent_ret;
-
- term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
- _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
- tty = rl_instream ? fileno (rl_instream) : 0;
-
- if (term == 0)
- term = "dumb";
-
-#ifdef __MSDOS__
- _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
- _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
- _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
- _rl_term_mm = _rl_term_mo = (char *)NULL;
- _rl_terminal_can_insert = term_has_meta = _rl_term_autowrap = 0;
- _rl_term_cr = "\r";
- _rl_term_clreol = _rl_term_clrpag = _rl_term_backspace = (char *)NULL;
- _rl_term_goto = _rl_term_pc = _rl_term_ip = (char *)NULL;
- _rl_term_ks = _rl_term_ke =_rl_term_vs = _rl_term_ve = (char *)NULL;
- _rl_term_kh = _rl_term_kH = _rl_term_at7 = _rl_term_kI = (char *)NULL;
-#if defined(HACK_TERMCAP_MOTION)
- _rl_term_forward_char = (char *)NULL;
-#endif
-
- _rl_get_screen_size (tty, 0);
-#else /* !__MSDOS__ */
- /* I've separated this out for later work on not calling tgetent at all
- if the calling application has supplied a custom redisplay function,
- (and possibly if the application has supplied a custom input function). */
- if (CUSTOM_REDISPLAY_FUNC())
- {
- tgetent_ret = -1;
- }
- else
- {
- if (term_string_buffer == 0)
- term_string_buffer = (char *)xmalloc(2032);
-
- if (term_buffer == 0)
- term_buffer = (char *)xmalloc(4080);
-
- buffer = term_string_buffer;
-
- tgetent_ret = tgetent (term_buffer, term);
- }
-
- if (tgetent_ret <= 0)
- {
- FREE (term_string_buffer);
- FREE (term_buffer);
- buffer = term_buffer = term_string_buffer = (char *)NULL;
-
- _rl_term_autowrap = 0; /* used by _rl_get_screen_size */
-
- /* Allow calling application to set default height and width, using
- rl_set_screen_size */
- if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
- {
-#if defined (__EMX__)
- _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
- _rl_screenwidth--;
-#else /* !__EMX__ */
- _rl_get_screen_size (tty, 0);
-#endif /* !__EMX__ */
- }
-
- /* Defaults. */
- if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
- {
- _rl_screenwidth = 79;
- _rl_screenheight = 24;
- }
-
- /* Everything below here is used by the redisplay code (tputs). */
- _rl_screenchars = _rl_screenwidth * _rl_screenheight;
- _rl_term_cr = "\r";
- _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
- _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
- _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
- _rl_term_kh = _rl_term_kH = _rl_term_kI = _rl_term_kD = (char *)NULL;
- _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
- _rl_term_mm = _rl_term_mo = (char *)NULL;
- _rl_term_ve = _rl_term_vs = (char *)NULL;
- _rl_term_forward_char = (char *)NULL;
- _rl_terminal_can_insert = term_has_meta = 0;
-
- /* Reasonable defaults for tgoto(). Readline currently only uses
- tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
- change that later... */
- PC = '\0';
- BC = _rl_term_backspace = "\b";
- UP = _rl_term_up;
-
- return 0;
- }
-
- get_term_capabilities (&buffer);
-
- /* Set up the variables that the termcap library expects the application
- to provide. */
- PC = _rl_term_pc ? *_rl_term_pc : 0;
- BC = _rl_term_backspace;
- UP = _rl_term_up;
-
- if (!_rl_term_cr)
- _rl_term_cr = "\r";
-
- _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
-
- /* Allow calling application to set default height and width, using
- rl_set_screen_size */
- if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
- _rl_get_screen_size (tty, 0);
-
- /* "An application program can assume that the terminal can do
- character insertion if *any one of* the capabilities `IC',
- `im', `ic' or `ip' is provided." But we can't do anything if
- only `ip' is provided, so... */
- _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
-
- /* Check to see if this terminal has a meta key and clear the capability
- variables if there is none. */
- term_has_meta = tgetflag ("km") != 0;
- if (term_has_meta == 0)
- _rl_term_mm = _rl_term_mo = (char *)NULL;
-#endif /* !__MSDOS__ */
-
- /* Attempt to find and bind the arrow keys. Do not override already
- bound keys in an overzealous attempt, however. */
-
- bind_termcap_arrow_keys (emacs_standard_keymap);
-
-#if defined (VI_MODE)
- bind_termcap_arrow_keys (vi_movement_keymap);
- bind_termcap_arrow_keys (vi_insertion_keymap);
-#endif /* VI_MODE */
-
- return 0;
-}
-
-/* Bind the arrow key sequences from the termcap description in MAP. */
-static void
-bind_termcap_arrow_keys (map)
- Keymap map;
-{
- Keymap xkeymap;
-
- xkeymap = _rl_keymap;
- _rl_keymap = map;
-
- rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history);
- rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history);
- rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char);
- rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char);
-
- rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */
- rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line); /* End */
-
- rl_bind_keyseq_if_unbound (_rl_term_kD, rl_delete);
-
- _rl_keymap = xkeymap;
-}
-
-char *
-rl_get_termcap (cap)
- const char *cap;
-{
- register int i;
-
- if (tcap_initialized == 0)
- return ((char *)NULL);
- for (i = 0; i < NUM_TC_STRINGS; i++)
- {
- if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
- return *(tc_strings[i].tc_value);
- }
- return ((char *)NULL);
-}
-
-/* Re-initialize the terminal considering that the TERM/TERMCAP variable
- has changed. */
-int
-rl_reset_terminal (terminal_name)
- const char *terminal_name;
-{
- _rl_screenwidth = _rl_screenheight = 0;
- _rl_init_terminal_io (terminal_name);
- return 0;
-}
-
-/* A function for the use of tputs () */
-#ifdef _MINIX
-void
-_rl_output_character_function (c)
- int c;
-{
- putc (c, _rl_out_stream);
-}
-#else /* !_MINIX */
-int
-_rl_output_character_function (c)
- int c;
-{
- return putc (c, _rl_out_stream);
-}
-#endif /* !_MINIX */
-
-/* Write COUNT characters from STRING to the output stream. */
-void
-_rl_output_some_chars (string, count)
- const char *string;
- int count;
-{
- fwrite (string, 1, count, _rl_out_stream);
-}
-
-/* Move the cursor back. */
-int
-_rl_backspace (count)
- int count;
-{
- register int i;
-
-#ifndef __MSDOS__
- if (_rl_term_backspace)
- for (i = 0; i < count; i++)
- tputs (_rl_term_backspace, 1, _rl_output_character_function);
- else
-#endif
- for (i = 0; i < count; i++)
- putc ('\b', _rl_out_stream);
- return 0;
-}
-
-/* Move to the start of the next line. */
-int
-rl_crlf ()
-{
-#if defined (NEW_TTY_DRIVER) || defined (__MINT__)
- if (_rl_term_cr)
- tputs (_rl_term_cr, 1, _rl_output_character_function);
-#endif /* NEW_TTY_DRIVER || __MINT__ */
- putc ('\n', _rl_out_stream);
- return 0;
-}
-
-/* Ring the terminal bell. */
-int
-rl_ding ()
-{
- if (_rl_echoing_p)
- {
- switch (_rl_bell_preference)
- {
- case NO_BELL:
- default:
- break;
- case VISIBLE_BELL:
- if (_rl_visible_bell)
- {
-#ifdef __DJGPP__
- ScreenVisualBell ();
-#else
- tputs (_rl_visible_bell, 1, _rl_output_character_function);
-#endif
- break;
- }
- /* FALLTHROUGH */
- case AUDIBLE_BELL:
- fprintf (stderr, "\007");
- fflush (stderr);
- break;
- }
- return (0);
- }
- return (-1);
-}
-
-/* **************************************************************** */
-/* */
-/* Controlling the Meta Key and Keypad */
-/* */
-/* **************************************************************** */
-
-static int enabled_meta = 0; /* flag indicating we enabled meta mode */
-
-void
-_rl_enable_meta_key ()
-{
-#if !defined (__DJGPP__)
- if (term_has_meta && _rl_term_mm)
- {
- tputs (_rl_term_mm, 1, _rl_output_character_function);
- enabled_meta = 1;
- }
-#endif
-}
-
-void
-_rl_disable_meta_key ()
-{
-#if !defined (__DJGPP__)
- if (term_has_meta && _rl_term_mo && enabled_meta)
- {
- tputs (_rl_term_mo, 1, _rl_output_character_function);
- enabled_meta = 0;
- }
-#endif
-}
-
-void
-_rl_control_keypad (on)
- int on;
-{
-#if !defined (__DJGPP__)
- if (on && _rl_term_ks)
- tputs (_rl_term_ks, 1, _rl_output_character_function);
- else if (!on && _rl_term_ke)
- tputs (_rl_term_ke, 1, _rl_output_character_function);
-#endif
-}
-
-/* **************************************************************** */
-/* */
-/* Controlling the Cursor */
-/* */
-/* **************************************************************** */
-
-/* Set the cursor appropriately depending on IM, which is one of the
- insert modes (insert or overwrite). Insert mode gets the normal
- cursor. Overwrite mode gets a very visible cursor. Only does
- anything if we have both capabilities. */
-void
-_rl_set_cursor (im, force)
- int im, force;
-{
-#ifndef __MSDOS__
- if (_rl_term_ve && _rl_term_vs)
- {
- if (force || im != rl_insert_mode)
- {
- if (im == RL_IM_OVERWRITE)
- tputs (_rl_term_vs, 1, _rl_output_character_function);
- else
- tputs (_rl_term_ve, 1, _rl_output_character_function);
- }
- }
-#endif
-}
+++ /dev/null
-/* shquote - functions to quote and dequote strings */
-
-/* Copyright (C) 1999 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <config.h>
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-
-#include "syntax.h"
-#include <xmalloc.h>
-
-/* Default set of characters that should be backslash-quoted in strings */
-static const char bstab[256] =
- {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 0, 0, 0, 0, 0, /* TAB, NL */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- 1, 1, 1, 0, 1, 0, 1, 1, /* SPACE, !, DQUOTE, DOL, AMP, SQUOTE */
- 1, 1, 1, 0, 1, 0, 0, 0, /* LPAR, RPAR, STAR, COMMA */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 1, 1, /* SEMI, LESSTHAN, GREATERTHAN, QUEST */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 0, /* LBRACK, BS, RBRACK, CARAT */
-
- 1, 0, 0, 0, 0, 0, 0, 0, /* BACKQ */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 0, 0, /* LBRACE, BAR, RBRACE */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
-
-/* **************************************************************** */
-/* */
-/* Functions for quoting strings to be re-read as input */
-/* */
-/* **************************************************************** */
-
-/* Return a new string which is the single-quoted version of STRING.
- Used by alias and trap, among others. */
-char *
-sh_single_quote (string)
- const char *string;
-{
- register int c;
- char *result, *r;
- const char *s;
-
- result = (char *)xmalloc (3 + (4 * strlen (string)));
- r = result;
- *r++ = '\'';
-
- for (s = string; s && (c = *s); s++)
- {
- *r++ = c;
-
- if (c == '\'')
- {
- *r++ = '\\'; /* insert escaped single quote */
- *r++ = '\'';
- *r++ = '\''; /* start new quoted string */
- }
- }
-
- *r++ = '\'';
- *r = '\0';
-
- return (result);
-}
-
-/* Quote STRING using double quotes. Return a new string. */
-char *
-sh_double_quote (string)
- const char *string;
-{
- register unsigned char c;
- char *result, *r;
- const char *s;
-
- result = (char *)xmalloc (3 + (2 * strlen (string)));
- r = result;
- *r++ = '"';
-
- for (s = string; s && (c = *s); s++)
- {
- /* Backslash-newline disappears within double quotes, so don't add one. */
- if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n')
- *r++ = '\\';
- else if (c == CTLESC || c == CTLNUL)
- *r++ = CTLESC; /* could be '\\'? */
-
- *r++ = c;
- }
-
- *r++ = '"';
- *r = '\0';
-
- return (result);
-}
-
-/* Turn S into a simple double-quoted string. If FLAGS is non-zero, quote
- double quote characters in S with backslashes. */
-char *
-sh_mkdoublequoted (s, slen, flags)
- const char *s;
- int slen, flags;
-{
- char *r, *ret;
- int rlen;
-
- rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1;
- ret = r = (char *)xmalloc (rlen);
-
- *r++ = '"';
- while (*s)
- {
- if (flags && *s == '"')
- *r++ = '\\';
- *r++ = *s++;
- }
- *r++ = '"';
- *r = '\0';
-
- return ret;
-}
-
-/* Remove backslashes that are quoting characters that are special between
- double quotes. Return a new string. XXX - should this handle CTLESC
- and CTLNUL? */
-char *
-sh_un_double_quote (string)
- char *string;
-{
- register int c, pass_next;
- char *result, *r, *s;
-
- r = result = (char *)xmalloc (strlen (string) + 1);
-
- for (pass_next = 0, s = string; s && (c = *s); s++)
- {
- if (pass_next)
- {
- *r++ = c;
- pass_next = 0;
- continue;
- }
- if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE))
- {
- pass_next = 1;
- continue;
- }
- *r++ = c;
- }
-
- *r = '\0';
- return result;
-}
-
-/* Quote special characters in STRING using backslashes. Return a new
- string. NOTE: if the string is to be further expanded, we need a
- way to protect the CTLESC and CTLNUL characters. As I write this,
- the current callers will never cause the string to be expanded without
- going through the shell parser, which will protect the internal
- quoting characters. TABLE, if set, points to a map of the ascii code
- set with char needing to be backslash-quoted if table[char]==1. FLAGS,
- if 1, causes tildes to be quoted as well. */
-
-char *
-sh_backslash_quote (string, table, flags)
- char *string;
- char *table;
- int flags;
-{
- int c;
- char *result, *r, *s, *backslash_table;
-
- result = (char *)xmalloc (2 * strlen (string) + 1);
-
- backslash_table = table ? table : bstab;
- for (r = result, s = string; s && (c = *s); s++)
- {
- if (backslash_table[c] == 1)
- *r++ = '\\';
- else if (c == '#' && s == string) /* comment char */
- *r++ = '\\';
- else if ((flags&1) && c == '~' && (s == string || s[-1] == ':' || s[-1] == '='))
- /* Tildes are special at the start of a word or after a `:' or `='
- (technically unquoted, but it doesn't make a difference in practice) */
- *r++ = '\\';
- *r++ = c;
- }
-
- *r = '\0';
- return (result);
-}
-
-#if defined (PROMPT_STRING_DECODE)
-/* Quote characters that get special treatment when in double quotes in STRING
- using backslashes. Return a new string. */
-char *
-sh_backslash_quote_for_double_quotes (string)
- char *string;
-{
- unsigned char c;
- char *result, *r, *s;
-
- result = (char *)xmalloc (2 * strlen (string) + 1);
-
- for (r = result, s = string; s && (c = *s); s++)
- {
- if (sh_syntaxtab[c] & CBSDQUOTE)
- *r++ = '\\';
- /* I should probably add flags for these to sh_syntaxtab[] */
- else if (c == CTLESC || c == CTLNUL)
- *r++ = CTLESC; /* could be '\\'? */
-
- *r++ = c;
- }
-
- *r = '\0';
- return (result);
-}
-#endif /* PROMPT_STRING_DECODE */
-
-int
-sh_contains_shell_metas (string)
- char *string;
-{
- char *s;
-
- for (s = string; s && *s; s++)
- {
- switch (*s)
- {
- case ' ': case '\t': case '\n': /* IFS white space */
- case '\'': case '"': case '\\': /* quoting chars */
- case '|': case '&': case ';': /* shell metacharacters */
- case '(': case ')': case '<': case '>':
- case '!': case '{': case '}': /* reserved words */
- case '*': case '[': case '?': case ']': /* globbing chars */
- case '^':
- case '$': case '`': /* expansion chars */
- return (1);
- case '~': /* tilde expansion */
- if (s == string || s[-1] == '=' || s[-1] == ':')
- return (1);
- break;
- case '#':
- if (s == string) /* comment char */
- return (1);
- /* FALLTHROUGH */
- default:
- break;
- }
- }
-
- return (0);
-}
+++ /dev/null
-/* subst.c -- The part of the shell that does parameter, command, arithmetic,
- and globbing substitutions. */
-
-/* ``Have a little faith, there's magic in the night. You ain't a
- beauty, but, hey, you're alright.'' */
-
-/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "config.h"
-
-#include "bashtypes.h"
-#include <stdio.h>
-#include "chartypes.h"
-#if defined (HAVE_PWD_H)
-# include <pwd.h>
-#endif
-#include <signal.h>
-#include <errno.h>
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashansi.h"
-#include "posixstat.h"
-#include "bashintl.h"
-
-#include "shell.h"
-#include "parser.h"
-#include "flags.h"
-#include "jobs.h"
-#include "execute_cmd.h"
-#include "filecntl.h"
-#include "trap.h"
-#include "pathexp.h"
-#include "mailcheck.h"
-
-#include "shmbutil.h"
-#include "typemax.h"
-
-#include "builtins/getopt.h"
-#include "builtins/common.h"
-
-#include "builtins/builtext.h"
-
-#include <tilde/tilde.h>
-#include <glob/strmatch.h>
-
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-/* The size that strings change by. */
-#define DEFAULT_INITIAL_ARRAY_SIZE 112
-#define DEFAULT_ARRAY_SIZE 128
-
-/* Variable types. */
-#define VT_VARIABLE 0
-#define VT_POSPARMS 1
-#define VT_ARRAYVAR 2
-#define VT_ARRAYMEMBER 3
-#define VT_ASSOCVAR 4
-
-#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
-
-/* Flags for quoted_strchr */
-#define ST_BACKSL 0x01
-#define ST_CTLESC 0x02
-#define ST_SQUOTE 0x04 /* unused yet */
-#define ST_DQUOTE 0x08 /* unused yet */
-
-/* Flags for the `pflags' argument to param_expand() */
-#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
-#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
-#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
-#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */
-
-/* These defs make it easier to use the editor. */
-#define LBRACE '{'
-#define RBRACE '}'
-#define LPAREN '('
-#define RPAREN ')'
-
-#if defined (HANDLE_MULTIBYTE)
-#define WLPAREN L'('
-#define WRPAREN L')'
-#endif
-
-/* Evaluates to 1 if C is one of the shell's special parameters whose length
- can be taken, but is also one of the special expansion characters. */
-#define VALID_SPECIAL_LENGTH_PARAM(c) \
- ((c) == '-' || (c) == '?' || (c) == '#')
-
-/* Evaluates to 1 if C is one of the shell's special parameters for which an
- indirect variable reference may be made. */
-#define VALID_INDIR_PARAM(c) \
- ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
-
-/* Evaluates to 1 if C is one of the OP characters that follows the parameter
- in ${parameter[:]OPword}. */
-#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
-
-/* Evaluates to 1 if this is one of the shell's special variables. */
-#define SPECIAL_VAR(name, wi) \
- ((DIGIT (*name) && all_digits (name)) || \
- (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
- (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))
-
-/* An expansion function that takes a string and a quoted flag and returns
- a WORD_LIST *. Used as the type of the third argument to
- expand_string_if_necessary(). */
-typedef WORD_LIST *EXPFUNC __P((char *, int));
-
-/* Process ID of the last command executed within command substitution. */
-pid_t last_command_subst_pid = NO_PID;
-pid_t current_command_subst_pid = NO_PID;
-
-/* Variables used to keep track of the characters in IFS. */
-SHELL_VAR *ifs_var;
-char *ifs_value;
-unsigned char ifs_cmap[UCHAR_MAX + 1];
-
-#if defined (HANDLE_MULTIBYTE)
-unsigned char ifs_firstc[MB_LEN_MAX];
-size_t ifs_firstc_len;
-#else
-unsigned char ifs_firstc;
-#endif
-
-/* Sentinel to tell when we are performing variable assignments preceding a
- command name and putting them into the environment. Used to make sure
- we use the temporary environment when looking up variable values. */
-int assigning_in_environment;
-
-/* Used to hold a list of variable assignments preceding a command. Global
- so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
- SIGCHLD trap and so it can be saved and restored by the trap handlers. */
-WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
-
-/* Extern functions and variables from different files. */
-extern int last_command_exit_value, last_command_exit_signal;
-extern int subshell_environment, line_number;
-extern int subshell_level, parse_and_execute_level, sourcelevel;
-extern int eof_encountered;
-extern int return_catch_flag, return_catch_value;
-extern pid_t dollar_dollar_pid;
-extern int posixly_correct;
-extern char *this_command_name;
-extern struct fd_bitmap *current_fds_to_close;
-extern int wordexp_only;
-extern int expanding_redir;
-extern int tempenv_assign_error;
-
-#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
-extern wchar_t *wcsdup __P((const wchar_t *));
-#endif
-
-/* Non-zero means to allow unmatched globbed filenames to expand to
- a null file. */
-int allow_null_glob_expansion;
-
-/* Non-zero means to throw an error when globbing fails to match anything. */
-int fail_glob_expansion;
-
-#if 0
-/* Variables to keep track of which words in an expanded word list (the
- output of expand_word_list_internal) are the result of globbing
- expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
- (CURRENTLY UNUSED). */
-char *glob_argv_flags;
-static int glob_argv_flags_size;
-#endif
-
-static WORD_LIST expand_word_error, expand_word_fatal;
-static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
-static char expand_param_error, expand_param_fatal;
-static char extract_string_error, extract_string_fatal;
-
-/* Tell the expansion functions to not longjmp back to top_level on fatal
- errors. Enabled when doing completion and prompt string expansion. */
-static int no_longjmp_on_fatal_error = 0;
-
-/* Set by expand_word_unsplit; used to inhibit splitting and re-joining
- $* on $IFS, primarily when doing assignment statements. */
-static int expand_no_split_dollar_star = 0;
-
-/* A WORD_LIST of words to be expanded by expand_word_list_internal,
- without any leading variable assignments. */
-static WORD_LIST *garglist = (WORD_LIST *)NULL;
-
-static char *quoted_substring __P((char *, int, int));
-static int quoted_strlen __P((char *));
-static char *quoted_strchr __P((char *, int, int));
-
-static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));
-static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));
-static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
-static WORD_LIST *expand_string_internal __P((char *, int));
-static WORD_LIST *expand_string_leave_quoted __P((char *, int));
-static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));
-
-static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
-static char *make_quoted_char __P((int));
-static WORD_LIST *quote_list __P((WORD_LIST *));
-
-static int unquoted_substring __P((char *, char *));
-static int unquoted_member __P((int, char *));
-
-#if defined (ARRAY_VARS)
-static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
-#endif
-static int do_assignment_internal __P((const WORD_DESC *, int));
-
-static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));
-static char *string_extract __P((char *, int *, char *, int));
-static char *string_extract_double_quoted __P((char *, int *, int));
-static inline char *string_extract_single_quoted __P((char *, int *));
-static inline int skip_single_quoted __P((const char *, size_t, int));
-static int skip_double_quoted __P((char *, size_t, int));
-static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
-static char *extract_dollar_brace_string __P((char *, int *, int, int));
-static int skip_matched_pair __P((const char *, int, int, int, int));
-
-static char *pos_params __P((char *, int, int, int));
-
-static unsigned char *mb_getcharlens __P((char *, int));
-
-static char *remove_upattern __P((char *, char *, int));
-#if defined (HANDLE_MULTIBYTE)
-static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
-#endif
-static char *remove_pattern __P((char *, char *, int));
-
-static int match_upattern __P((char *, char *, int, char **, char **));
-#if defined (HANDLE_MULTIBYTE)
-static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
-#endif
-static int match_pattern __P((char *, char *, int, char **, char **));
-static int getpatspec __P((int, char *));
-static char *getpattern __P((char *, int, int));
-static char *variable_remove_pattern __P((char *, char *, int, int));
-static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
-static char *parameter_list_remove_pattern __P((int, char *, int, int));
-#ifdef ARRAY_VARS
-static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
-#endif
-static char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int));
-
-static char *process_substitute __P((char *, int));
-
-static char *read_comsub __P((int, int, int *));
-
-#ifdef ARRAY_VARS
-static arrayind_t array_length_reference __P((char *));
-#endif
-
-static int valid_brace_expansion_word __P((char *, int));
-static int chk_atstar __P((char *, int, int *, int *));
-static int chk_arithsub __P((const char *, int));
-
-static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));
-static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
-static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
-static void parameter_brace_expand_error __P((char *, char *));
-
-static int valid_length_expression __P((char *));
-static intmax_t parameter_brace_expand_length __P((char *));
-
-static char *skiparith __P((char *, int));
-static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
-static int get_var_and_type __P((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
-static char *mb_substring __P((char *, int, int));
-static char *parameter_brace_substring __P((char *, char *, int, char *, int, int));
-
-static int shouldexp_replacement __P((char *));
-
-static char *pos_params_pat_subst __P((char *, char *, char *, int));
-
-static char *parameter_brace_patsub __P((char *, char *, int, char *, int, int));
-
-static char *pos_params_casemod __P((char *, char *, int, int));
-static char *parameter_brace_casemod __P((char *, char *, int, int, char *, int, int));
-
-static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));
-static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));
-
-static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
-
-static WORD_LIST *word_list_split __P((WORD_LIST *));
-
-static void exp_jump_to_top_level __P((int));
-
-static WORD_LIST *separate_out_assignments __P((WORD_LIST *));
-static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
-#ifdef BRACE_EXPANSION
-static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
-#endif
-#if defined (ARRAY_VARS)
-static int make_internal_declare __P((char *, char *));
-#endif
-static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
-static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
-
-/* **************************************************************** */
-/* */
-/* Utility Functions */
-/* */
-/* **************************************************************** */
-
-#if defined (DEBUG)
-void
-dump_word_flags (flags)
- int flags;
-{
- int f;
-
- f = flags;
- fprintf (stderr, "%d -> ", f);
- if (f & W_ASSIGNASSOC)
- {
- f &= ~W_ASSIGNASSOC;
- fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
- }
- if (f & W_HASCTLESC)
- {
- f &= ~W_HASCTLESC;
- fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
- }
- if (f & W_NOPROCSUB)
- {
- f &= ~W_NOPROCSUB;
- fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
- }
- if (f & W_DQUOTE)
- {
- f &= ~W_DQUOTE;
- fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
- }
- if (f & W_HASQUOTEDNULL)
- {
- f &= ~W_HASQUOTEDNULL;
- fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
- }
- if (f & W_ASSIGNARG)
- {
- f &= ~W_ASSIGNARG;
- fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
- }
- if (f & W_ASSNBLTIN)
- {
- f &= ~W_ASSNBLTIN;
- fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
- }
- if (f & W_ASSNGLOBAL)
- {
- f &= ~W_ASSNGLOBAL;
- fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
- }
- if (f & W_COMPASSIGN)
- {
- f &= ~W_COMPASSIGN;
- fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
- }
- if (f & W_NOEXPAND)
- {
- f &= ~W_NOEXPAND;
- fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
- }
- if (f & W_ITILDE)
- {
- f &= ~W_ITILDE;
- fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
- }
- if (f & W_NOTILDE)
- {
- f &= ~W_NOTILDE;
- fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
- }
- if (f & W_ASSIGNRHS)
- {
- f &= ~W_ASSIGNRHS;
- fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
- }
- if (f & W_NOCOMSUB)
- {
- f &= ~W_NOCOMSUB;
- fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
- }
- if (f & W_DOLLARSTAR)
- {
- f &= ~W_DOLLARSTAR;
- fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
- }
- if (f & W_DOLLARAT)
- {
- f &= ~W_DOLLARAT;
- fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
- }
- if (f & W_TILDEEXP)
- {
- f &= ~W_TILDEEXP;
- fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
- }
- if (f & W_NOSPLIT2)
- {
- f &= ~W_NOSPLIT2;
- fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
- }
- if (f & W_NOSPLIT)
- {
- f &= ~W_NOSPLIT;
- fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
- }
- if (f & W_NOBRACE)
- {
- f &= ~W_NOBRACE;
- fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
- }
- if (f & W_NOGLOB)
- {
- f &= ~W_NOGLOB;
- fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
- }
- if (f & W_GLOBEXP)
- {
- f &= ~W_GLOBEXP;
- fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
- }
- if (f & W_ASSIGNMENT)
- {
- f &= ~W_ASSIGNMENT;
- fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
- }
- if (f & W_QUOTED)
- {
- f &= ~W_QUOTED;
- fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
- }
- if (f & W_HASDOLLAR)
- {
- f &= ~W_HASDOLLAR;
- fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
- }
- fprintf (stderr, "\n");
- fflush (stderr);
-}
-#endif
-
-#ifdef INCLUDE_UNUSED
-static char *
-quoted_substring (string, start, end)
- char *string;
- int start, end;
-{
- register int len, l;
- register char *result, *s, *r;
-
- len = end - start;
-
- /* Move to string[start], skipping quoted characters. */
- for (s = string, l = 0; *s && l < start; )
- {
- if (*s == CTLESC)
- {
- s++;
- continue;
- }
- l++;
- if (*s == 0)
- break;
- }
-
- r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
-
- /* Copy LEN characters, including quote characters. */
- s = string + l;
- for (l = 0; l < len; s++)
- {
- if (*s == CTLESC)
- *r++ = *s++;
- *r++ = *s;
- l++;
- if (*s == 0)
- break;
- }
- *r = '\0';
- return result;
-}
-#endif
-
-#ifdef INCLUDE_UNUSED
-/* Return the length of S, skipping over quoted characters */
-static int
-quoted_strlen (s)
- char *s;
-{
- register char *p;
- int i;
-
- i = 0;
- for (p = s; *p; p++)
- {
- if (*p == CTLESC)
- {
- p++;
- if (*p == 0)
- return (i + 1);
- }
- i++;
- }
-
- return i;
-}
-#endif
-
-/* Find the first occurrence of character C in string S, obeying shell
- quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
- characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
- escaped with CTLESC are skipped. */
-static char *
-quoted_strchr (s, c, flags)
- char *s;
- int c, flags;
-{
- register char *p;
-
- for (p = s; *p; p++)
- {
- if (((flags & ST_BACKSL) && *p == '\\')
- || ((flags & ST_CTLESC) && *p == CTLESC))
- {
- p++;
- if (*p == '\0')
- return ((char *)NULL);
- continue;
- }
- else if (*p == c)
- return p;
- }
- return ((char *)NULL);
-}
-
-/* Return 1 if CHARACTER appears in an unquoted portion of
- STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
-static int
-unquoted_member (character, string)
- int character;
- char *string;
-{
- size_t slen;
- int sindex, c;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- sindex = 0;
- while (c = string[sindex])
- {
- if (c == character)
- return (1);
-
- switch (c)
- {
- default:
- ADVANCE_CHAR (string, slen, sindex);
- break;
-
- case '\\':
- sindex++;
- if (string[sindex])
- ADVANCE_CHAR (string, slen, sindex);
- break;
-
- case '\'':
- sindex = skip_single_quoted (string, slen, ++sindex);
- break;
-
- case '"':
- sindex = skip_double_quoted (string, slen, ++sindex);
- break;
- }
- }
- return (0);
-}
-
-/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
-static int
-unquoted_substring (substr, string)
- char *substr, *string;
-{
- size_t slen;
- int sindex, c, sublen;
- DECLARE_MBSTATE;
-
- if (substr == 0 || *substr == '\0')
- return (0);
-
- slen = strlen (string);
- sublen = strlen (substr);
- for (sindex = 0; c = string[sindex]; )
- {
- if (STREQN (string + sindex, substr, sublen))
- return (1);
-
- switch (c)
- {
- case '\\':
- sindex++;
- if (string[sindex])
- ADVANCE_CHAR (string, slen, sindex);
- break;
-
- case '\'':
- sindex = skip_single_quoted (string, slen, ++sindex);
- break;
-
- case '"':
- sindex = skip_double_quoted (string, slen, ++sindex);
- break;
-
- default:
- ADVANCE_CHAR (string, slen, sindex);
- break;
- }
- }
- return (0);
-}
-
-/* Most of the substitutions must be done in parallel. In order
- to avoid using tons of unclear goto's, I have some functions
- for manipulating malloc'ed strings. They all take INDX, a
- pointer to an integer which is the offset into the string
- where manipulation is taking place. They also take SIZE, a
- pointer to an integer which is the current length of the
- character array for this string. */
-
-/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
- of space allocated to TARGET. SOURCE can be NULL, in which
- case nothing happens. Gets rid of SOURCE by freeing it.
- Returns TARGET in case the location has changed. */
-INLINE char *
-sub_append_string (source, target, indx, size)
- char *source, *target;
- int *indx, *size;
-{
- if (source)
- {
- int srclen, n;
-
- srclen = STRLEN (source);
- if (srclen >= (int)(*size - *indx))
- {
- n = srclen + *indx;
- n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
- target = (char *)xrealloc (target, (*size = n));
- }
-
- FASTCOPY (source, target + *indx, srclen);
- *indx += srclen;
- target[*indx] = '\0';
-
- free (source);
- }
- return (target);
-}
-
-#if 0
-/* UNUSED */
-/* Append the textual representation of NUMBER to TARGET.
- INDX and SIZE are as in SUB_APPEND_STRING. */
-char *
-sub_append_number (number, target, indx, size)
- intmax_t number;
- int *indx, *size;
- char *target;
-{
- char *temp;
-
- temp = itos (number);
- return (sub_append_string (temp, target, indx, size));
-}
-#endif
-
-/* Extract a substring from STRING, starting at SINDEX and ending with
- one of the characters in CHARLIST. Don't make the ending character
- part of the string. Leave SINDEX pointing at the ending character.
- Understand about backslashes in the string. If (flags & SX_VARNAME)
- is non-zero, and array variables have been compiled into the shell,
- everything between a `[' and a corresponding `]' is skipped over.
- If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
- update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
- contain a closing character from CHARLIST. */
-static char *
-string_extract (string, sindex, charlist, flags)
- char *string;
- int *sindex;
- char *charlist;
- int flags;
-{
- register int c, i;
- int found;
- size_t slen;
- char *temp;
- DECLARE_MBSTATE;
-
- slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
- i = *sindex;
- found = 0;
- while (c = string[i])
- {
- if (c == '\\')
- {
- if (string[i + 1])
- i++;
- else
- break;
- }
-#if defined (ARRAY_VARS)
- else if ((flags & SX_VARNAME) && c == '[')
- {
- int ni;
- /* If this is an array subscript, skip over it and continue. */
- ni = skipsubscript (string, i, 0);
- if (string[ni] == ']')
- i = ni;
- }
-#endif
- else if (MEMBER (c, charlist))
- {
- found = 1;
- break;
- }
-
- ADVANCE_CHAR (string, slen, i);
- }
-
- /* If we had to have a matching delimiter and didn't find one, return an
- error and let the caller deal with it. */
- if ((flags & SX_REQMATCH) && found == 0)
- {
- *sindex = i;
- return (&extract_string_error);
- }
-
- temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
- *sindex = i;
-
- return (temp);
-}
-
-/* Extract the contents of STRING as if it is enclosed in double quotes.
- SINDEX, when passed in, is the offset of the character immediately
- following the opening double quote; on exit, SINDEX is left pointing after
- the closing double quote. If STRIPDQ is non-zero, unquoted double
- quotes are stripped and the string is terminated by a null byte.
- Backslashes between the embedded double quotes are processed. If STRIPDQ
- is zero, an unquoted `"' terminates the string. */
-static char *
-string_extract_double_quoted (string, sindex, stripdq)
- char *string;
- int *sindex, stripdq;
-{
- size_t slen;
- char *send;
- int j, i, t;
- unsigned char c;
- char *temp, *ret; /* The new string we return. */
- int pass_next, backquote, si; /* State variables for the machine. */
- int dquote;
- DECLARE_MBSTATE;
-
- slen = strlen (string + *sindex) + *sindex;
- send = string + slen;
-
- pass_next = backquote = dquote = 0;
- temp = (char *)xmalloc (1 + slen - *sindex);
-
- j = 0;
- i = *sindex;
- while (c = string[i])
- {
- /* Process a character that was quoted by a backslash. */
- if (pass_next)
- {
- /* XXX - take another look at this in light of Interp 221 */
- /* Posix.2 sez:
-
- ``The backslash shall retain its special meaning as an escape
- character only when followed by one of the characters:
- $ ` " \ <newline>''.
-
- If STRIPDQ is zero, we handle the double quotes here and let
- expand_word_internal handle the rest. If STRIPDQ is non-zero,
- we have already been through one round of backslash stripping,
- and want to strip these backslashes only if DQUOTE is non-zero,
- indicating that we are inside an embedded double-quoted string. */
-
- /* If we are in an embedded quoted string, then don't strip
- backslashes before characters for which the backslash
- retains its special meaning, but remove backslashes in
- front of other characters. If we are not in an
- embedded quoted string, don't strip backslashes at all.
- This mess is necessary because the string was already
- surrounded by double quotes (and sh has some really weird
- quoting rules).
- The returned string will be run through expansion as if
- it were double-quoted. */
- if ((stripdq == 0 && c != '"') ||
- (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
- temp[j++] = '\\';
- pass_next = 0;
-
-add_one_character:
- COPY_CHAR_I (temp, j, string, send, i);
- continue;
- }
-
- /* A backslash protects the next character. The code just above
- handles preserving the backslash in front of any character but
- a double quote. */
- if (c == '\\')
- {
- pass_next++;
- i++;
- continue;
- }
-
- /* Inside backquotes, ``the portion of the quoted string from the
- initial backquote and the characters up to the next backquote
- that is not preceded by a backslash, having escape characters
- removed, defines that command''. */
- if (backquote)
- {
- if (c == '`')
- backquote = 0;
- temp[j++] = c;
- i++;
- continue;
- }
-
- if (c == '`')
- {
- temp[j++] = c;
- backquote++;
- i++;
- continue;
- }
-
- /* Pass everything between `$(' and the matching `)' or a quoted
- ${ ... } pair through according to the Posix.2 specification. */
- if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
- {
- int free_ret = 1;
-
- si = i + 2;
- if (string[i + 1] == LPAREN)
- ret = extract_command_subst (string, &si, 0);
- else
- ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
-
- temp[j++] = '$';
- temp[j++] = string[i + 1];
-
- /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
- is set. */
- if (ret == 0 && no_longjmp_on_fatal_error)
- {
- free_ret = 0;
- ret = string + i + 2;
- }
-
- for (t = 0; ret[t]; t++, j++)
- temp[j] = ret[t];
- temp[j] = string[si];
-
- if (string[si])
- {
- j++;
- i = si + 1;
- }
- else
- i = si;
-
- if (free_ret)
- free (ret);
- continue;
- }
-
- /* Add any character but a double quote to the quoted string we're
- accumulating. */
- if (c != '"')
- goto add_one_character;
-
- /* c == '"' */
- if (stripdq)
- {
- dquote ^= 1;
- i++;
- continue;
- }
-
- break;
- }
- temp[j] = '\0';
-
- /* Point to after the closing quote. */
- if (c)
- i++;
- *sindex = i;
-
- return (temp);
-}
-
-/* This should really be another option to string_extract_double_quoted. */
-static int
-skip_double_quoted (string, slen, sind)
- char *string;
- size_t slen;
- int sind;
-{
- int c, i;
- char *ret;
- int pass_next, backquote, si;
- DECLARE_MBSTATE;
-
- pass_next = backquote = 0;
- i = sind;
- while (c = string[i])
- {
- if (pass_next)
- {
- pass_next = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '\\')
- {
- pass_next++;
- i++;
- continue;
- }
- else if (backquote)
- {
- if (c == '`')
- backquote = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '`')
- {
- backquote++;
- i++;
- continue;
- }
- else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
- {
- si = i + 2;
- if (string[i + 1] == LPAREN)
- ret = extract_command_subst (string, &si, SX_NOALLOC);
- else
- ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
-
- i = si + 1;
- continue;
- }
- else if (c != '"')
- {
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else
- break;
- }
-
- if (c)
- i++;
-
- return (i);
-}
-
-/* Extract the contents of STRING as if it is enclosed in single quotes.
- SINDEX, when passed in, is the offset of the character immediately
- following the opening single quote; on exit, SINDEX is left pointing after
- the closing single quote. */
-static inline char *
-string_extract_single_quoted (string, sindex)
- char *string;
- int *sindex;
-{
- register int i;
- size_t slen;
- char *t;
- DECLARE_MBSTATE;
-
- /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
- slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
- i = *sindex;
- while (string[i] && string[i] != '\'')
- ADVANCE_CHAR (string, slen, i);
-
- t = substring (string, *sindex, i);
-
- if (string[i])
- i++;
- *sindex = i;
-
- return (t);
-}
-
-static inline int
-skip_single_quoted (string, slen, sind)
- const char *string;
- size_t slen;
- int sind;
-{
- register int c;
- DECLARE_MBSTATE;
-
- c = sind;
- while (string[c] && string[c] != '\'')
- ADVANCE_CHAR (string, slen, c);
-
- if (string[c])
- c++;
- return c;
-}
-
-/* Just like string_extract, but doesn't hack backslashes or any of
- that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
-static char *
-string_extract_verbatim (string, slen, sindex, charlist, flags)
- char *string;
- size_t slen;
- int *sindex;
- char *charlist;
- int flags;
-{
- register int i;
-#if defined (HANDLE_MULTIBYTE)
- size_t clen;
- wchar_t *wcharlist;
-#endif
- int c;
- char *temp;
- DECLARE_MBSTATE;
-
- if (charlist[0] == '\'' && charlist[1] == '\0')
- {
- temp = string_extract_single_quoted (string, sindex);
- --*sindex; /* leave *sindex at separator character */
- return temp;
- }
-
- i = *sindex;
-#if 0
- /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need
- this only if MB_CUR_MAX > 1. */
- slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1;
-#endif
-#if defined (HANDLE_MULTIBYTE)
- clen = strlen (charlist);
- wcharlist = 0;
-#endif
- while (c = string[i])
- {
-#if defined (HANDLE_MULTIBYTE)
- size_t mblength;
-#endif
- if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
- {
- i += 2;
- continue;
- }
- /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
- through, to protect the CTLNULs from later calls to
- remove_quoted_nulls. */
- else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
- {
- i += 2;
- continue;
- }
-
-#if defined (HANDLE_MULTIBYTE)
- mblength = MBLEN (string + i, slen - i);
- if (mblength > 1)
- {
- wchar_t wc;
- mblength = mbtowc (&wc, string + i, slen - i);
- if (MB_INVALIDCH (mblength))
- {
- if (MEMBER (c, charlist))
- break;
- }
- else
- {
- if (wcharlist == 0)
- {
- size_t len;
- len = mbstowcs (wcharlist, charlist, 0);
- if (len == -1)
- len = 0;
- wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
- mbstowcs (wcharlist, charlist, len + 1);
- }
-
- if (wcschr (wcharlist, wc))
- break;
- }
- }
- else
-#endif
- if (MEMBER (c, charlist))
- break;
-
- ADVANCE_CHAR (string, slen, i);
- }
-
-#if defined (HANDLE_MULTIBYTE)
- FREE (wcharlist);
-#endif
-
- temp = substring (string, *sindex, i);
- *sindex = i;
-
- return (temp);
-}
-
-/* Extract the $( construct in STRING, and return a new string.
- Start extracting at (SINDEX) as if we had just seen "$(".
- Make (SINDEX) get the position of the matching ")". )
- XFLAGS is additional flags to pass to other extraction functions. */
-char *
-extract_command_subst (string, sindex, xflags)
- char *string;
- int *sindex;
- int xflags;
-{
- if (string[*sindex] == LPAREN)
- return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
- else
- {
- xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
- return (xparse_dolparen (string, string+*sindex, sindex, xflags));
- }
-}
-
-/* Extract the $[ construct in STRING, and return a new string. (])
- Start extracting at (SINDEX) as if we had just seen "$[".
- Make (SINDEX) get the position of the matching "]". */
-char *
-extract_arithmetic_subst (string, sindex)
- char *string;
- int *sindex;
-{
- return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
-}
-
-#if defined (PROCESS_SUBSTITUTION)
-/* Extract the <( or >( construct in STRING, and return a new string.
- Start extracting at (SINDEX) as if we had just seen "<(".
- Make (SINDEX) get the position of the matching ")". */ /*))*/
-char *
-extract_process_subst (string, starter, sindex)
- char *string;
- char *starter;
- int *sindex;
-{
- return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
-}
-#endif /* PROCESS_SUBSTITUTION */
-
-#if defined (ARRAY_VARS)
-/* This can be fooled by unquoted right parens in the passed string. If
- each caller verifies that the last character in STRING is a right paren,
- we don't even need to call extract_delimited_string. */
-char *
-extract_array_assignment_list (string, sindex)
- char *string;
- int *sindex;
-{
- int slen;
- char *ret;
-
- slen = strlen (string); /* ( */
- if (string[slen - 1] == ')')
- {
- ret = substring (string, *sindex, slen - 1);
- *sindex = slen - 1;
- return ret;
- }
- return 0;
-}
-#endif
-
-/* Extract and create a new string from the contents of STRING, a
- character string delimited with OPENER and CLOSER. SINDEX is
- the address of an int describing the current offset in STRING;
- it should point to just after the first OPENER found. On exit,
- SINDEX gets the position of the last character of the matching CLOSER.
- If OPENER is more than a single character, ALT_OPENER, if non-null,
- contains a character string that can also match CLOSER and thus
- needs to be skipped. */
-static char *
-extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
- char *string;
- int *sindex;
- char *opener, *alt_opener, *closer;
- int flags;
-{
- int i, c, si;
- size_t slen;
- char *t, *result;
- int pass_character, nesting_level, in_comment;
- int len_closer, len_opener, len_alt_opener;
- DECLARE_MBSTATE;
-
- slen = strlen (string + *sindex) + *sindex;
- len_opener = STRLEN (opener);
- len_alt_opener = STRLEN (alt_opener);
- len_closer = STRLEN (closer);
-
- pass_character = in_comment = 0;
-
- nesting_level = 1;
- i = *sindex;
-
- while (nesting_level)
- {
- c = string[i];
-
- if (c == 0)
- break;
-
- if (in_comment)
- {
- if (c == '\n')
- in_comment = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
-
- if (pass_character) /* previous char was backslash */
- {
- pass_character = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
-
- /* Not exactly right yet; should handle shell metacharacters and
- multibyte characters, too. See COMMENT_BEGIN define in parse.y */
- if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
- {
- in_comment = 1;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
-
- if (c == CTLESC || c == '\\')
- {
- pass_character++;
- i++;
- continue;
- }
-
- /* Process a nested command substitution, but only if we're parsing an
- arithmetic substitution. */
- if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
- {
- si = i + 2;
- t = extract_command_subst (string, &si, flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
- /* Process a nested OPENER. */
- if (STREQN (string + i, opener, len_opener))
- {
- si = i + len_opener;
- t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
- /* Process a nested ALT_OPENER */
- if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
- {
- si = i + len_alt_opener;
- t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
- /* If the current substring terminates the delimited string, decrement
- the nesting level. */
- if (STREQN (string + i, closer, len_closer))
- {
- i += len_closer - 1; /* move to last byte of the closer */
- nesting_level--;
- if (nesting_level == 0)
- break;
- }
-
- /* Pass old-style command substitution through verbatim. */
- if (c == '`')
- {
- si = i + 1;
- t = string_extract (string, &si, "`", flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
- /* Pass single-quoted and double-quoted strings through verbatim. */
- if (c == '\'' || c == '"')
- {
- si = i + 1;
- i = (c == '\'') ? skip_single_quoted (string, slen, si)
- : skip_double_quoted (string, slen, si);
- continue;
- }
-
- /* move past this character, which was not special. */
- ADVANCE_CHAR (string, slen, i);
- }
-
- if (c == 0 && nesting_level)
- {
- if (no_longjmp_on_fatal_error == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
- exp_jump_to_top_level (DISCARD);
- }
- else
- {
- *sindex = i;
- return (char *)NULL;
- }
- }
-
- si = i - *sindex - len_closer + 1;
- if (flags & SX_NOALLOC)
- result = (char *)NULL;
- else
- {
- result = (char *)xmalloc (1 + si);
- strncpy (result, string + *sindex, si);
- result[si] = '\0';
- }
- *sindex = i;
-
- return (result);
-}
-
-/* Extract a parameter expansion expression within ${ and } from STRING.
- Obey the Posix.2 rules for finding the ending `}': count braces while
- skipping over enclosed quoted strings and command substitutions.
- SINDEX is the address of an int describing the current offset in STRING;
- it should point to just after the first `{' found. On exit, SINDEX
- gets the position of the matching `}'. QUOTED is non-zero if this
- occurs inside double quotes. */
-/* XXX -- this is very similar to extract_delimited_string -- XXX */
-static char *
-extract_dollar_brace_string (string, sindex, quoted, flags)
- char *string;
- int *sindex, quoted, flags;
-{
- register int i, c;
- size_t slen;
- int pass_character, nesting_level, si, dolbrace_state;
- char *result, *t;
- DECLARE_MBSTATE;
-
- pass_character = 0;
- nesting_level = 1;
- slen = strlen (string + *sindex) + *sindex;
-
- /* The handling of dolbrace_state needs to agree with the code in parse.y:
- parse_matched_pair(). The different initial value is to handle the
- case where this function is called to parse the word in
- ${param op word} (SX_WORD). */
- dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
- dolbrace_state = DOLBRACE_QUOTE;
-
- i = *sindex;
- while (c = string[i])
- {
- if (pass_character)
- {
- pass_character = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
-
- /* CTLESCs and backslashes quote the next character. */
- if (c == CTLESC || c == '\\')
- {
- pass_character++;
- i++;
- continue;
- }
-
- if (string[i] == '$' && string[i+1] == LBRACE)
- {
- nesting_level++;
- i += 2;
- continue;
- }
-
- if (c == RBRACE)
- {
- nesting_level--;
- if (nesting_level == 0)
- break;
- i++;
- continue;
- }
-
- /* Pass the contents of old-style command substitutions through
- verbatim. */
- if (c == '`')
- {
- si = i + 1;
- t = string_extract (string, &si, "`", flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
- /* Pass the contents of new-style command substitutions and
- arithmetic substitutions through verbatim. */
- if (string[i] == '$' && string[i+1] == LPAREN)
- {
- si = i + 2;
- t = extract_command_subst (string, &si, flags|SX_NOALLOC);
- i = si + 1;
- continue;
- }
-
-#if 0
- /* Pass the contents of single-quoted and double-quoted strings
- through verbatim. */
- if (c == '\'' || c == '"')
- {
- si = i + 1;
- i = (c == '\'') ? skip_single_quoted (string, slen, si)
- : skip_double_quoted (string, slen, si);
- /* skip_XXX_quoted leaves index one past close quote */
- continue;
- }
-#else /* XXX - bash-4.2 */
- /* Pass the contents of double-quoted strings through verbatim. */
- if (c == '"')
- {
- si = i + 1;
- i = skip_double_quoted (string, slen, si);
- /* skip_XXX_quoted leaves index one past close quote */
- continue;
- }
-
- if (c == '\'')
- {
-/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
- if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ADVANCE_CHAR (string, slen, i);
- else
- {
- si = i + 1;
- i = skip_single_quoted (string, slen, si);
- }
-
- continue;
- }
-#endif
-
- /* move past this character, which was not special. */
- ADVANCE_CHAR (string, slen, i);
-
- /* This logic must agree with parse.y:parse_matched_pair, since they
- share the same defines. */
- if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
- else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
- else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
- else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
- else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
- else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
- dolbrace_state = DOLBRACE_OP;
- else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
- dolbrace_state = DOLBRACE_WORD;
- }
-
- if (c == 0 && nesting_level)
- {
- if (no_longjmp_on_fatal_error == 0)
- { /* { */
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
- exp_jump_to_top_level (DISCARD);
- }
- else
- {
- *sindex = i;
- return ((char *)NULL);
- }
- }
-
- result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
- *sindex = i;
-
- return (result);
-}
-
-/* Remove backslashes which are quoting backquotes from STRING. Modifies
- STRING, and returns a pointer to it. */
-char *
-de_backslash (string)
- char *string;
-{
- register size_t slen;
- register int i, j, prev_i;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- i = j = 0;
-
- /* Loop copying string[i] to string[j], i >= j. */
- while (i < slen)
- {
- if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
- string[i + 1] == '$'))
- i++;
- prev_i = i;
- ADVANCE_CHAR (string, slen, i);
- if (j < prev_i)
- do string[j++] = string[prev_i++]; while (prev_i < i);
- else
- j = i;
- }
- string[j] = '\0';
-
- return (string);
-}
-
-#if 0
-/*UNUSED*/
-/* Replace instances of \! in a string with !. */
-void
-unquote_bang (string)
- char *string;
-{
- register int i, j;
- register char *temp;
-
- temp = (char *)xmalloc (1 + strlen (string));
-
- for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
- {
- if (string[i] == '\\' && string[i + 1] == '!')
- {
- temp[j] = '!';
- i++;
- }
- }
- strcpy (string, temp);
- free (temp);
-}
-#endif
-
-#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
-
-/* This function assumes s[i] == open; returns with s[ret] == close; used to
- parse array subscripts. FLAGS & 1 means to not attempt to skip over
- matched pairs of quotes or backquotes, or skip word expansions; it is
- intended to be used after expansion has been performed and during final
- assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
-static int
-skip_matched_pair (string, start, open, close, flags)
- const char *string;
- int start, open, close, flags;
-{
- int i, pass_next, backq, si, c, count;
- size_t slen;
- char *temp, *ss;
- DECLARE_MBSTATE;
-
- slen = strlen (string + start) + start;
- no_longjmp_on_fatal_error = 1;
-
- i = start + 1; /* skip over leading bracket */
- count = 1;
- pass_next = backq = 0;
- ss = (char *)string;
- while (c = string[i])
- {
- if (pass_next)
- {
- pass_next = 0;
- if (c == 0)
- CQ_RETURN(i);
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '\\')
- {
- pass_next = 1;
- i++;
- continue;
- }
- else if (backq)
- {
- if (c == '`')
- backq = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if ((flags & 1) == 0 && c == '`')
- {
- backq = 1;
- i++;
- continue;
- }
- else if ((flags & 1) == 0 && c == open)
- {
- count++;
- i++;
- continue;
- }
- else if (c == close)
- {
- count--;
- if (count == 0)
- break;
- i++;
- continue;
- }
- else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
- {
- i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
- : skip_double_quoted (ss, slen, ++i);
- /* no increment, the skip functions increment past the closing quote. */
- }
- else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
- {
- si = i + 2;
- if (string[si] == '\0')
- CQ_RETURN(si);
-
- if (string[i+1] == LPAREN)
- temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
- else
- temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
- i = si;
- if (string[i] == '\0') /* don't increment i past EOS in loop */
- break;
- i++;
- continue;
- }
- else
- ADVANCE_CHAR (string, slen, i);
- }
-
- CQ_RETURN(i);
-}
-
-#if defined (ARRAY_VARS)
-int
-skipsubscript (string, start, flags)
- const char *string;
- int start, flags;
-{
- return (skip_matched_pair (string, start, '[', ']', flags));
-}
-#endif
-
-/* Skip characters in STRING until we find a character in DELIMS, and return
- the index of that character. START is the index into string at which we
- begin. This is similar in spirit to strpbrk, but it returns an index into
- STRING and takes a starting index. This little piece of code knows quite
- a lot of shell syntax. It's very similar to skip_double_quoted and other
- functions of that ilk. */
-int
-skip_to_delim (string, start, delims, flags)
- char *string;
- int start;
- char *delims;
- int flags;
-{
- int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
- size_t slen;
- char *temp, open[3];
- DECLARE_MBSTATE;
-
- slen = strlen (string + start) + start;
- if (flags & SD_NOJMP)
- no_longjmp_on_fatal_error = 1;
- invert = (flags & SD_INVERT);
- skipcmd = (flags & SD_NOSKIPCMD) == 0;
-
- i = start;
- pass_next = backq = 0;
- while (c = string[i])
- {
- /* If this is non-zero, we should not let quote characters be delimiters
- and the current character is a single or double quote. We should not
- test whether or not it's a delimiter until after we skip single- or
- double-quoted strings. */
- skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
- if (pass_next)
- {
- pass_next = 0;
- if (c == 0)
- CQ_RETURN(i);
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '\\')
- {
- pass_next = 1;
- i++;
- continue;
- }
- else if (backq)
- {
- if (c == '`')
- backq = 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '`')
- {
- backq = 1;
- i++;
- continue;
- }
- else if (skipquote == 0 && invert == 0 && member (c, delims))
- break;
- else if (c == '\'' || c == '"')
- {
- i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
- : skip_double_quoted (string, slen, ++i);
- /* no increment, the skip functions increment past the closing quote. */
- }
- else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
- {
- si = i + 2;
- if (string[si] == '\0')
- CQ_RETURN(si);
-
- if (string[i+1] == LPAREN)
- temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
- else
- temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
- i = si;
- if (string[i] == '\0') /* don't increment i past EOS in loop */
- break;
- i++;
- continue;
- }
-#if defined (PROCESS_SUBSTITUTION)
- else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN)
- {
- si = i + 2;
- if (string[si] == '\0')
- CQ_RETURN(si);
- temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
- free (temp); /* no SX_ALLOC here */
- i = si;
- if (string[i] == '\0')
- break;
- i++;
- continue;
- }
-#endif /* PROCESS_SUBSTITUTION */
-#if defined (EXTENDED_GLOB)
- else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
- {
- si = i + 2;
- if (string[si] == '\0')
- CQ_RETURN(si);
-
- open[0] = c;
- open[1] = LPAREN;
- open[2] = '\0';
- temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
-
- i = si;
- if (string[i] == '\0') /* don't increment i past EOS in loop */
- break;
- i++;
- continue;
- }
-#endif
- else if ((skipquote || invert) && (member (c, delims) == 0))
- break;
- else
- ADVANCE_CHAR (string, slen, i);
- }
-
- CQ_RETURN(i);
-}
-
-#if defined (READLINE)
-/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
- an unclosed quoted string), or if the character at EINDEX is quoted
- by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
- single and double-quoted string parsing functions should not return an
- error if there are unclosed quotes or braces. The characters that this
- recognizes need to be the same as the contents of
- rl_completer_quote_characters. */
-
-int
-char_is_quoted (string, eindex)
- char *string;
- int eindex;
-{
- int i, pass_next, c;
- size_t slen;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- no_longjmp_on_fatal_error = 1;
- i = pass_next = 0;
- while (i <= eindex)
- {
- c = string[i];
-
- if (pass_next)
- {
- pass_next = 0;
- if (i >= eindex) /* XXX was if (i >= eindex - 1) */
- CQ_RETURN(1);
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (c == '\\')
- {
- pass_next = 1;
- i++;
- continue;
- }
- else if (c == '\'' || c == '"')
- {
- i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
- : skip_double_quoted (string, slen, ++i);
- if (i > eindex)
- CQ_RETURN(1);
- /* no increment, the skip_xxx functions go one past end */
- }
- else
- ADVANCE_CHAR (string, slen, i);
- }
-
- CQ_RETURN(0);
-}
-
-int
-unclosed_pair (string, eindex, openstr)
- char *string;
- int eindex;
- char *openstr;
-{
- int i, pass_next, openc, olen;
- size_t slen;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- olen = strlen (openstr);
- i = pass_next = openc = 0;
- while (i <= eindex)
- {
- if (pass_next)
- {
- pass_next = 0;
- if (i >= eindex) /* XXX was if (i >= eindex - 1) */
- return 0;
- ADVANCE_CHAR (string, slen, i);
- continue;
- }
- else if (string[i] == '\\')
- {
- pass_next = 1;
- i++;
- continue;
- }
- else if (STREQN (string + i, openstr, olen))
- {
- openc = 1 - openc;
- i += olen;
- }
- else if (string[i] == '\'' || string[i] == '"')
- {
- i = (string[i] == '\'') ? skip_single_quoted (string, slen, i)
- : skip_double_quoted (string, slen, i);
- if (i > eindex)
- return 0;
- }
- else
- ADVANCE_CHAR (string, slen, i);
- }
- return (openc);
-}
-
-/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
- individual words. If DELIMS is NULL, the current value of $IFS is used
- to split the string, and the function follows the shell field splitting
- rules. SENTINEL is an index to look for. NWP, if non-NULL,
- gets the number of words in the returned list. CWP, if non-NULL, gets
- the index of the word containing SENTINEL. Non-whitespace chars in
- DELIMS delimit separate fields. */
-WORD_LIST *
-split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
- char *string;
- int slen;
- char *delims;
- int sentinel, flags;
- int *nwp, *cwp;
-{
- int ts, te, i, nw, cw, ifs_split, dflags;
- char *token, *d, *d2;
- WORD_LIST *ret, *tl;
-
- if (string == 0 || *string == '\0')
- {
- if (nwp)
- *nwp = 0;
- if (cwp)
- *cwp = 0;
- return ((WORD_LIST *)NULL);
- }
-
- d = (delims == 0) ? ifs_value : delims;
- ifs_split = delims == 0;
-
- /* Make d2 the non-whitespace characters in delims */
- d2 = 0;
- if (delims)
- {
- size_t slength;
-#if defined (HANDLE_MULTIBYTE)
- size_t mblength = 1;
-#endif
- DECLARE_MBSTATE;
-
- slength = strlen (delims);
- d2 = (char *)xmalloc (slength + 1);
- i = ts = 0;
- while (delims[i])
- {
-#if defined (HANDLE_MULTIBYTE)
- mbstate_t state_bak;
- state_bak = state;
- mblength = MBRLEN (delims + i, slength, &state);
- if (MB_INVALIDCH (mblength))
- state = state_bak;
- else if (mblength > 1)
- {
- memcpy (d2 + ts, delims + i, mblength);
- ts += mblength;
- i += mblength;
- slength -= mblength;
- continue;
- }
-#endif
- if (whitespace (delims[i]) == 0)
- d2[ts++] = delims[i];
-
- i++;
- slength--;
- }
- d2[ts] = '\0';
- }
-
- ret = (WORD_LIST *)NULL;
-
- /* Remove sequences of whitespace characters at the start of the string, as
- long as those characters are delimiters. */
- for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
- ;
- if (string[i] == '\0')
- return (ret);
-
- ts = i;
- nw = 0;
- cw = -1;
- dflags = flags|SD_NOJMP;
- while (1)
- {
- te = skip_to_delim (string, ts, d, dflags);
-
- /* If we have a non-whitespace delimiter character, use it to make a
- separate field. This is just about what $IFS splitting does and
- is closer to the behavior of the shell parser. */
- if (ts == te && d2 && member (string[ts], d2))
- {
- te = ts + 1;
- /* If we're using IFS splitting, the non-whitespace delimiter char
- and any additional IFS whitespace delimits a field. */
- if (ifs_split)
- while (member (string[te], d) && spctabnl (string[te]))
- te++;
- else
- while (member (string[te], d2))
- te++;
- }
-
- token = substring (string, ts, te);
-
- ret = add_string_to_list (token, ret);
- free (token);
- nw++;
-
- if (sentinel >= ts && sentinel <= te)
- cw = nw;
-
- /* If the cursor is at whitespace just before word start, set the
- sentinel word to the current word. */
- if (cwp && cw == -1 && sentinel == ts-1)
- cw = nw;
-
- /* If the cursor is at whitespace between two words, make a new, empty
- word, add it before (well, after, since the list is in reverse order)
- the word we just added, and set the current word to that one. */
- if (cwp && cw == -1 && sentinel < ts)
- {
- tl = make_word_list (make_word (""), ret->next);
- ret->next = tl;
- cw = nw;
- nw++;
- }
-
- if (string[te] == 0)
- break;
-
- i = te;
- while (member (string[i], d) && (ifs_split || spctabnl(string[i])))
- i++;
-
- if (string[i])
- ts = i;
- else
- break;
- }
-
- /* Special case for SENTINEL at the end of STRING. If we haven't found
- the word containing SENTINEL yet, and the index we're looking for is at
- the end of STRING (or past the end of the previously-found token,
- possible if the end of the line is composed solely of IFS whitespace)
- add an additional null argument and set the current word pointer to that. */
- if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
- {
- if (whitespace (string[sentinel - 1]))
- {
- token = "";
- ret = add_string_to_list (token, ret);
- nw++;
- }
- cw = nw;
- }
-
- if (nwp)
- *nwp = nw;
- if (cwp)
- *cwp = cw;
-
- FREE (d2);
-
- return (REVERSE_LIST (ret, WORD_LIST *));
-}
-#endif /* READLINE */
-
-#if 0
-/* UNUSED */
-/* Extract the name of the variable to bind to from the assignment string. */
-char *
-assignment_name (string)
- char *string;
-{
- int offset;
- char *temp;
-
- offset = assignment (string, 0);
- if (offset == 0)
- return (char *)NULL;
- temp = substring (string, 0, offset);
- return (temp);
-}
-#endif
-
-/* **************************************************************** */
-/* */
-/* Functions to convert strings to WORD_LISTs and vice versa */
-/* */
-/* **************************************************************** */
-
-/* Return a single string of all the words in LIST. SEP is the separator
- to put between individual elements of LIST in the output string. */
-char *
-string_list_internal (list, sep)
- WORD_LIST *list;
- char *sep;
-{
- register WORD_LIST *t;
- char *result, *r;
- int word_len, sep_len, result_size;
-
- if (list == 0)
- return ((char *)NULL);
-
- /* Short-circuit quickly if we don't need to separate anything. */
- if (list->next == 0)
- return (savestring (list->word->word));
-
- /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
- sep_len = STRLEN (sep);
- result_size = 0;
-
- for (t = list; t; t = t->next)
- {
- if (t != list)
- result_size += sep_len;
- result_size += strlen (t->word->word);
- }
-
- r = result = (char *)xmalloc (result_size + 1);
-
- for (t = list; t; t = t->next)
- {
- if (t != list && sep_len)
- {
- if (sep_len > 1)
- {
- FASTCOPY (sep, r, sep_len);
- r += sep_len;
- }
- else
- *r++ = sep[0];
- }
-
- word_len = strlen (t->word->word);
- FASTCOPY (t->word->word, r, word_len);
- r += word_len;
- }
-
- *r = '\0';
- return (result);
-}
-
-/* Return a single string of all the words present in LIST, separating
- each word with a space. */
-char *
-string_list (list)
- WORD_LIST *list;
-{
- return (string_list_internal (list, " "));
-}
-
-/* An external interface that can be used by the rest of the shell to
- obtain a string containing the first character in $IFS. Handles all
- the multibyte complications. If LENP is non-null, it is set to the
- length of the returned string. */
-char *
-ifs_firstchar (lenp)
- int *lenp;
-{
- char *ret;
- int len;
-
- ret = xmalloc (MB_LEN_MAX + 1);
-#if defined (HANDLE_MULTIBYTE)
- if (ifs_firstc_len == 1)
- {
- ret[0] = ifs_firstc[0];
- ret[1] = '\0';
- len = ret[0] ? 1 : 0;
- }
- else
- {
- memcpy (ret, ifs_firstc, ifs_firstc_len);
- ret[len = ifs_firstc_len] = '\0';
- }
-#else
- ret[0] = ifs_firstc;
- ret[1] = '\0';
- len = ret[0] ? 0 : 1;
-#endif
-
- if (lenp)
- *lenp = len;
-
- return ret;
-}
-
-/* Return a single string of all the words present in LIST, obeying the
- quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
- expansion [of $*] appears within a double quoted string, it expands
- to a single field with the value of each parameter separated by the
- first character of the IFS variable, or by a <space> if IFS is unset." */
-char *
-string_list_dollar_star (list)
- WORD_LIST *list;
-{
- char *ret;
-#if defined (HANDLE_MULTIBYTE)
-# if defined (__GNUC__)
- char sep[MB_CUR_MAX + 1];
-# else
- char *sep = 0;
-# endif
-#else
- char sep[2];
-#endif
-
-#if defined (HANDLE_MULTIBYTE)
-# if !defined (__GNUC__)
- sep = (char *)xmalloc (MB_CUR_MAX + 1);
-# endif /* !__GNUC__ */
- if (ifs_firstc_len == 1)
- {
- sep[0] = ifs_firstc[0];
- sep[1] = '\0';
- }
- else
- {
- memcpy (sep, ifs_firstc, ifs_firstc_len);
- sep[ifs_firstc_len] = '\0';
- }
-#else
- sep[0] = ifs_firstc;
- sep[1] = '\0';
-#endif
-
- ret = string_list_internal (list, sep);
-#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
- free (sep);
-#endif
- return ret;
-}
-
-/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- is non-zero, the $@ appears within double quotes, and we should quote
- the list before converting it into a string. If IFS is unset, and the
- word is not quoted, we just need to quote CTLESC and CTLNUL characters
- in the words in the list, because the default value of $IFS is
- <space><tab><newline>, IFS characters in the words in the list should
- also be split. If IFS is null, and the word is not quoted, we need
- to quote the words in the list to preserve the positional parameters
- exactly. */
-char *
-string_list_dollar_at (list, quoted)
- WORD_LIST *list;
- int quoted;
-{
- char *ifs, *ret;
-#if defined (HANDLE_MULTIBYTE)
-# if defined (__GNUC__)
- char sep[MB_CUR_MAX + 1];
-# else
- char *sep = 0;
-# endif /* !__GNUC__ */
-#else
- char sep[2];
-#endif
- WORD_LIST *tlist;
-
- /* XXX this could just be ifs = ifs_value; */
- ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
-
-#if defined (HANDLE_MULTIBYTE)
-# if !defined (__GNUC__)
- sep = (char *)xmalloc (MB_CUR_MAX + 1);
-# endif /* !__GNUC__ */
- if (ifs && *ifs)
- {
- if (ifs_firstc_len == 1)
- {
- sep[0] = ifs_firstc[0];
- sep[1] = '\0';
- }
- else
- {
- memcpy (sep, ifs_firstc, ifs_firstc_len);
- sep[ifs_firstc_len] = '\0';
- }
- }
- else
- {
- sep[0] = ' ';
- sep[1] = '\0';
- }
-#else
- sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs;
- sep[1] = '\0';
-#endif
-
- /* XXX -- why call quote_list if ifs == 0? we can get away without doing
- it now that quote_escapes quotes spaces */
- tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
- ? quote_list (list)
- : list_quote_escapes (list);
-
- ret = string_list_internal (tlist, sep);
-#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
- free (sep);
-#endif
- return ret;
-}
-
-/* Turn the positional paramters into a string, understanding quoting and
- the various subtleties of using the first character of $IFS as the
- separator. Calls string_list_dollar_at, string_list_dollar_star, and
- string_list as appropriate. */
-char *
-string_list_pos_params (pchar, list, quoted)
- int pchar;
- WORD_LIST *list;
- int quoted;
-{
- char *ret;
- WORD_LIST *tlist;
-
- if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
- {
- tlist = quote_list (list);
- word_list_remove_quoted_nulls (tlist);
- ret = string_list_dollar_star (tlist);
- }
- else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
- {
- tlist = quote_list (list);
- word_list_remove_quoted_nulls (tlist);
- ret = string_list (tlist);
- }
- else if (pchar == '*')
- {
- /* Even when unquoted, string_list_dollar_star does the right thing
- making sure that the first character of $IFS is used as the
- separator. */
- ret = string_list_dollar_star (list);
- }
- else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- /* We use string_list_dollar_at, but only if the string is quoted, since
- that quotes the escapes if it's not, which we don't want. We could
- use string_list (the old code did), but that doesn't do the right
- thing if the first character of $IFS is not a space. We use
- string_list_dollar_star if the string is unquoted so we make sure that
- the elements of $@ are separated by the first character of $IFS for
- later splitting. */
- ret = string_list_dollar_at (list, quoted);
- else if (pchar == '@')
- ret = string_list_dollar_star (list);
- else
- ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
-
- return ret;
-}
-
-/* Return the list of words present in STRING. Separate the string into
- words at any of the characters found in SEPARATORS. If QUOTED is
- non-zero then word in the list will have its quoted flag set, otherwise
- the quoted flag is left as make_word () deemed fit.
-
- This obeys the P1003.2 word splitting semantics. If `separators' is
- exactly <space><tab><newline>, then the splitting algorithm is that of
- the Bourne shell, which treats any sequence of characters from `separators'
- as a delimiter. If IFS is unset, which results in `separators' being set
- to "", no splitting occurs. If separators has some other value, the
- following rules are applied (`IFS white space' means zero or more
- occurrences of <space>, <tab>, or <newline>, as long as those characters
- are in `separators'):
-
- 1) IFS white space is ignored at the start and the end of the
- string.
- 2) Each occurrence of a character in `separators' that is not
- IFS white space, along with any adjacent occurrences of
- IFS white space delimits a field.
- 3) Any nonzero-length sequence of IFS white space delimits a field.
- */
-
-/* BEWARE! list_string strips null arguments. Don't call it twice and
- expect to have "" preserved! */
-
-/* This performs word splitting and quoted null character removal on
- STRING. */
-#define issep(c) \
- (((separators)[0]) ? ((separators)[1] ? isifs(c) \
- : (c) == (separators)[0]) \
- : 0)
-
-WORD_LIST *
-list_string (string, separators, quoted)
- register char *string, *separators;
- int quoted;
-{
- WORD_LIST *result;
- WORD_DESC *t;
- char *current_word, *s;
- int sindex, sh_style_split, whitesep, xflags;
- size_t slen;
-
- if (!string || !*string)
- return ((WORD_LIST *)NULL);
-
- sh_style_split = separators && separators[0] == ' ' &&
- separators[1] == '\t' &&
- separators[2] == '\n' &&
- separators[3] == '\0';
- for (xflags = 0, s = ifs_value; s && *s; s++)
- {
- if (*s == CTLESC) xflags |= SX_NOCTLESC;
- else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
- }
-
- slen = 0;
- /* Remove sequences of whitespace at the beginning of STRING, as
- long as those characters appear in IFS. Do not do this if
- STRING is quoted or if there are no separator characters. */
- if (!quoted || !separators || !*separators)
- {
- for (s = string; *s && spctabnl (*s) && issep (*s); s++);
-
- if (!*s)
- return ((WORD_LIST *)NULL);
-
- string = s;
- }
-
- /* OK, now STRING points to a word that does not begin with white space.
- The splitting algorithm is:
- extract a word, stopping at a separator
- skip sequences of spc, tab, or nl as long as they are separators
- This obeys the field splitting rules in Posix.2. */
- slen = (MB_CUR_MAX > 1) ? strlen (string) : 1;
- for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
- {
- /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
- unless multibyte chars are possible. */
- current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
- if (current_word == 0)
- break;
-
- /* If we have a quoted empty string, add a quoted null argument. We
- want to preserve the quoted null character iff this is a quoted
- empty string; otherwise the quoted null characters are removed
- below. */
- if (QUOTED_NULL (current_word))
- {
- t = alloc_word_desc ();
- t->word = make_quoted_char ('\0');
- t->flags |= W_QUOTED|W_HASQUOTEDNULL;
- result = make_word_list (t, result);
- }
- else if (current_word[0] != '\0')
- {
- /* If we have something, then add it regardless. However,
- perform quoted null character removal on the current word. */
- remove_quoted_nulls (current_word);
- result = add_string_to_list (current_word, result);
- result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
- if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- result->word->flags |= W_QUOTED;
- }
-
- /* If we're not doing sequences of separators in the traditional
- Bourne shell style, then add a quoted null argument. */
- else if (!sh_style_split && !spctabnl (string[sindex]))
- {
- t = alloc_word_desc ();
- t->word = make_quoted_char ('\0');
- t->flags |= W_QUOTED|W_HASQUOTEDNULL;
- result = make_word_list (t, result);
- }
-
- free (current_word);
-
- /* Note whether or not the separator is IFS whitespace, used later. */
- whitesep = string[sindex] && spctabnl (string[sindex]);
-
- /* Move past the current separator character. */
- if (string[sindex])
- {
- DECLARE_MBSTATE;
- ADVANCE_CHAR (string, slen, sindex);
- }
-
- /* Now skip sequences of space, tab, or newline characters if they are
- in the list of separators. */
- while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
- sindex++;
-
- /* If the first separator was IFS whitespace and the current character
- is a non-whitespace IFS character, it should be part of the current
- field delimiter, not a separate delimiter that would result in an
- empty field. Look at POSIX.2, 3.6.5, (3)(b). */
- if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex]))
- {
- sindex++;
- /* An IFS character that is not IFS white space, along with any
- adjacent IFS white space, shall delimit a field. (SUSv3) */
- while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
- sindex++;
- }
- }
- return (REVERSE_LIST (result, WORD_LIST *));
-}
-
-/* Parse a single word from STRING, using SEPARATORS to separate fields.
- ENDPTR is set to the first character after the word. This is used by
- the `read' builtin. This is never called with SEPARATORS != $IFS;
- it should be simplified.
-
- XXX - this function is very similar to list_string; they should be
- combined - XXX */
-char *
-get_word_from_string (stringp, separators, endptr)
- char **stringp, *separators, **endptr;
-{
- register char *s;
- char *current_word;
- int sindex, sh_style_split, whitesep, xflags;
- size_t slen;
-
- if (!stringp || !*stringp || !**stringp)
- return ((char *)NULL);
-
- sh_style_split = separators && separators[0] == ' ' &&
- separators[1] == '\t' &&
- separators[2] == '\n' &&
- separators[3] == '\0';
- for (xflags = 0, s = ifs_value; s && *s; s++)
- {
- if (*s == CTLESC) xflags |= SX_NOCTLESC;
- if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
- }
-
- s = *stringp;
- slen = 0;
-
- /* Remove sequences of whitespace at the beginning of STRING, as
- long as those characters appear in IFS. */
- if (sh_style_split || !separators || !*separators)
- {
- for (; *s && spctabnl (*s) && isifs (*s); s++);
-
- /* If the string is nothing but whitespace, update it and return. */
- if (!*s)
- {
- *stringp = s;
- if (endptr)
- *endptr = s;
- return ((char *)NULL);
- }
- }
-
- /* OK, S points to a word that does not begin with white space.
- Now extract a word, stopping at a separator, save a pointer to
- the first character after the word, then skip sequences of spc,
- tab, or nl as long as they are separators.
-
- This obeys the field splitting rules in Posix.2. */
- sindex = 0;
- /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
- unless multibyte chars are possible. */
- slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
- current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
-
- /* Set ENDPTR to the first character after the end of the word. */
- if (endptr)
- *endptr = s + sindex;
-
- /* Note whether or not the separator is IFS whitespace, used later. */
- whitesep = s[sindex] && spctabnl (s[sindex]);
-
- /* Move past the current separator character. */
- if (s[sindex])
- {
- DECLARE_MBSTATE;
- ADVANCE_CHAR (s, slen, sindex);
- }
-
- /* Now skip sequences of space, tab, or newline characters if they are
- in the list of separators. */
- while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
- sindex++;
-
- /* If the first separator was IFS whitespace and the current character is
- a non-whitespace IFS character, it should be part of the current field
- delimiter, not a separate delimiter that would result in an empty field.
- Look at POSIX.2, 3.6.5, (3)(b). */
- if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex]))
- {
- sindex++;
- /* An IFS character that is not IFS white space, along with any adjacent
- IFS white space, shall delimit a field. */
- while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
- sindex++;
- }
-
- /* Update STRING to point to the next field. */
- *stringp = s + sindex;
- return (current_word);
-}
-
-/* Remove IFS white space at the end of STRING. Start at the end
- of the string and walk backwards until the beginning of the string
- or we find a character that's not IFS white space and not CTLESC.
- Only let CTLESC escape a white space character if SAW_ESCAPE is
- non-zero. */
-char *
-strip_trailing_ifs_whitespace (string, separators, saw_escape)
- char *string, *separators;
- int saw_escape;
-{
- char *s;
-
- s = string + STRLEN (string) - 1;
- while (s > string && ((spctabnl (*s) && isifs (*s)) ||
- (saw_escape && *s == CTLESC && spctabnl (s[1]))))
- s--;
- *++s = '\0';
- return string;
-}
-
-#if 0
-/* UNUSED */
-/* Split STRING into words at whitespace. Obeys shell-style quoting with
- backslashes, single and double quotes. */
-WORD_LIST *
-list_string_with_quotes (string)
- char *string;
-{
- WORD_LIST *list;
- char *token, *s;
- size_t s_len;
- int c, i, tokstart, len;
-
- for (s = string; s && *s && spctabnl (*s); s++)
- ;
- if (s == 0 || *s == 0)
- return ((WORD_LIST *)NULL);
-
- s_len = strlen (s);
- tokstart = i = 0;
- list = (WORD_LIST *)NULL;
- while (1)
- {
- c = s[i];
- if (c == '\\')
- {
- i++;
- if (s[i])
- i++;
- }
- else if (c == '\'')
- i = skip_single_quoted (s, s_len, ++i);
- else if (c == '"')
- i = skip_double_quoted (s, s_len, ++i);
- else if (c == 0 || spctabnl (c))
- {
- /* We have found the end of a token. Make a word out of it and
- add it to the word list. */
- token = substring (s, tokstart, i);
- list = add_string_to_list (token, list);
- free (token);
- while (spctabnl (s[i]))
- i++;
- if (s[i])
- tokstart = i;
- else
- break;
- }
- else
- i++; /* normal character */
- }
- return (REVERSE_LIST (list, WORD_LIST *));
-}
-#endif
-
-/********************************************************/
-/* */
-/* Functions to perform assignment statements */
-/* */
-/********************************************************/
-
-#if defined (ARRAY_VARS)
-static SHELL_VAR *
-do_compound_assignment (name, value, flags)
- char *name, *value;
- int flags;
-{
- SHELL_VAR *v;
- int mklocal, mkassoc;
- WORD_LIST *list;
-
- mklocal = flags & ASS_MKLOCAL;
- mkassoc = flags & ASS_MKASSOC;
-
- if (mklocal && variable_context)
- {
- v = find_variable (name);
- list = expand_compound_array_assignment (v, value, flags);
- if (mkassoc)
- v = make_local_assoc_variable (name);
- else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
- v = make_local_array_variable (name, 0);
- assign_compound_array_list (v, list, flags);
- }
- else
- v = assign_array_from_string (name, value, flags);
-
- return (v);
-}
-#endif
-
-/* Given STRING, an assignment string, get the value of the right side
- of the `=', and bind it to the left side. If EXPAND is true, then
- perform parameter expansion, command substitution, and arithmetic
- expansion on the right-hand side. Perform tilde expansion in any
- case. Do not perform word splitting on the result of expansion. */
-static int
-do_assignment_internal (word, expand)
- const WORD_DESC *word;
- int expand;
-{
- int offset, appendop, assign_list, aflags, retval;
- char *name, *value, *temp;
- SHELL_VAR *entry;
-#if defined (ARRAY_VARS)
- char *t;
- int ni;
-#endif
- const char *string;
-
- if (word == 0 || word->word == 0)
- return 0;
-
- appendop = assign_list = aflags = 0;
- string = word->word;
- offset = assignment (string, 0);
- name = savestring (string);
- value = (char *)NULL;
-
- if (name[offset] == '=')
- {
- if (name[offset - 1] == '+')
- {
- appendop = 1;
- name[offset - 1] = '\0';
- }
-
- name[offset] = 0; /* might need this set later */
- temp = name + offset + 1;
-
-#if defined (ARRAY_VARS)
- if (expand && (word->flags & W_COMPASSIGN))
- {
- assign_list = ni = 1;
- value = extract_array_assignment_list (temp, &ni);
- }
- else
-#endif
- if (expand && temp[0])
- value = expand_string_if_necessary (temp, 0, expand_string_assignment);
- else
- value = savestring (temp);
- }
-
- if (value == 0)
- {
- value = (char *)xmalloc (1);
- value[0] = '\0';
- }
-
- if (echo_command_at_execute)
- {
- if (appendop)
- name[offset - 1] = '+';
- xtrace_print_assignment (name, value, assign_list, 1);
- if (appendop)
- name[offset - 1] = '\0';
- }
-
-#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
-
- if (appendop)
- aflags |= ASS_APPEND;
-
-#if defined (ARRAY_VARS)
- if (t = mbschr (name, '[')) /*]*/
- {
- if (assign_list)
- {
- report_error (_("%s: cannot assign list to array member"), name);
- ASSIGN_RETURN (0);
- }
- entry = assign_array_element (name, value, aflags);
- if (entry == 0)
- ASSIGN_RETURN (0);
- }
- else if (assign_list)
- {
- if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
- aflags |= ASS_MKLOCAL;
- if (word->flags & W_ASSIGNASSOC)
- aflags |= ASS_MKASSOC;
- entry = do_compound_assignment (name, value, aflags);
- }
- else
-#endif /* ARRAY_VARS */
- entry = bind_variable (name, value, aflags);
-
- stupidly_hack_special_variables (name);
-
- /* Return 1 if the assignment seems to have been performed correctly. */
- if (entry == 0 || readonly_p (entry))
- retval = 0; /* assignment failure */
- else if (noassign_p (entry))
- {
- last_command_exit_value = EXECUTION_FAILURE;
- retval = 1; /* error status, but not assignment failure */
- }
- else
- retval = 1;
-
- if (entry && retval != 0 && noassign_p (entry) == 0)
- VUNSETATTR (entry, att_invisible);
-
- ASSIGN_RETURN (retval);
-}
-
-/* Perform the assignment statement in STRING, and expand the
- right side by doing tilde, command and parameter expansion. */
-int
-do_assignment (string)
- char *string;
-{
- WORD_DESC td;
-
- td.flags = W_ASSIGNMENT;
- td.word = string;
-
- return do_assignment_internal (&td, 1);
-}
-
-int
-do_word_assignment (word, flags)
- WORD_DESC *word;
- int flags;
-{
- return do_assignment_internal (word, 1);
-}
-
-/* Given STRING, an assignment string, get the value of the right side
- of the `=', and bind it to the left side. Do not perform any word
- expansions on the right hand side. */
-int
-do_assignment_no_expand (string)
- char *string;
-{
- WORD_DESC td;
-
- td.flags = W_ASSIGNMENT;
- td.word = string;
-
- return (do_assignment_internal (&td, 0));
-}
-
-/***************************************************
- * *
- * Functions to manage the positional parameters *
- * *
- ***************************************************/
-
-/* Return the word list that corresponds to `$*'. */
-WORD_LIST *
-list_rest_of_args ()
-{
- register WORD_LIST *list, *args;
- int i;
-
- /* Break out of the loop as soon as one of the dollar variables is null. */
- for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
- list = make_word_list (make_bare_word (dollar_vars[i]), list);
-
- for (args = rest_of_args; args; args = args->next)
- list = make_word_list (make_bare_word (args->word->word), list);
-
- return (REVERSE_LIST (list, WORD_LIST *));
-}
-
-int
-number_of_args ()
-{
- register WORD_LIST *list;
- int n;
-
- for (n = 0; n < 9 && dollar_vars[n+1]; n++)
- ;
- for (list = rest_of_args; list; list = list->next)
- n++;
- return n;
-}
-
-/* Return the value of a positional parameter. This handles values > 10. */
-char *
-get_dollar_var_value (ind)
- intmax_t ind;
-{
- char *temp;
- WORD_LIST *p;
-
- if (ind < 10)
- temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
- else /* We want something like ${11} */
- {
- ind -= 10;
- for (p = rest_of_args; p && ind--; p = p->next)
- ;
- temp = p ? savestring (p->word->word) : (char *)NULL;
- }
- return (temp);
-}
-
-/* Make a single large string out of the dollar digit variables,
- and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
- case of "$*" with respect to IFS. */
-char *
-string_rest_of_args (dollar_star)
- int dollar_star;
-{
- register WORD_LIST *list;
- char *string;
-
- list = list_rest_of_args ();
- string = dollar_star ? string_list_dollar_star (list) : string_list (list);
- dispose_words (list);
- return (string);
-}
-
-/* Return a string containing the positional parameters from START to
- END, inclusive. If STRING[0] == '*', we obey the rules for $*,
- which only makes a difference if QUOTED is non-zero. If QUOTED includes
- Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
- no quoting chars are added. */
-static char *
-pos_params (string, start, end, quoted)
- char *string;
- int start, end, quoted;
-{
- WORD_LIST *save, *params, *h, *t;
- char *ret;
- int i;
-
- /* see if we can short-circuit. if start == end, we want 0 parameters. */
- if (start == end)
- return ((char *)NULL);
-
- save = params = list_rest_of_args ();
- if (save == 0)
- return ((char *)NULL);
-
- if (start == 0) /* handle ${@:0[:x]} specially */
- {
- t = make_word_list (make_word (dollar_vars[0]), params);
- save = params = t;
- }
-
- for (i = start ? 1 : 0; params && i < start; i++)
- params = params->next;
- if (params == 0)
- return ((char *)NULL);
- for (h = t = params; params && i < end; i++)
- {
- t = params;
- params = params->next;
- }
-
- t->next = (WORD_LIST *)NULL;
-
- ret = string_list_pos_params (string[0], h, quoted);
-
- if (t != params)
- t->next = params;
-
- dispose_words (save);
- return (ret);
-}
-
-/******************************************************************/
-/* */
-/* Functions to expand strings to strings or WORD_LISTs */
-/* */
-/******************************************************************/
-
-#if defined (PROCESS_SUBSTITUTION)
-#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
-#else
-#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
-#endif
-
-/* If there are any characters in STRING that require full expansion,
- then call FUNC to expand STRING; otherwise just perform quote
- removal if necessary. This returns a new string. */
-static char *
-expand_string_if_necessary (string, quoted, func)
- char *string;
- int quoted;
- EXPFUNC *func;
-{
- WORD_LIST *list;
- size_t slen;
- int i, saw_quote;
- char *ret;
- DECLARE_MBSTATE;
-
- /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
- slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
- i = saw_quote = 0;
- while (string[i])
- {
- if (EXP_CHAR (string[i]))
- break;
- else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
- saw_quote = 1;
- ADVANCE_CHAR (string, slen, i);
- }
-
- if (string[i])
- {
- list = (*func) (string, quoted);
- if (list)
- {
- ret = string_list (list);
- dispose_words (list);
- }
- else
- ret = (char *)NULL;
- }
- else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
- ret = string_quote_removal (string, quoted);
- else
- ret = savestring (string);
-
- return ret;
-}
-
-static inline char *
-expand_string_to_string_internal (string, quoted, func)
- char *string;
- int quoted;
- EXPFUNC *func;
-{
- WORD_LIST *list;
- char *ret;
-
- if (string == 0 || *string == '\0')
- return ((char *)NULL);
-
- list = (*func) (string, quoted);
- if (list)
- {
- ret = string_list (list);
- dispose_words (list);
- }
- else
- ret = (char *)NULL;
-
- return (ret);
-}
-
-char *
-expand_string_to_string (string, quoted)
- char *string;
- int quoted;
-{
- return (expand_string_to_string_internal (string, quoted, expand_string));
-}
-
-char *
-expand_string_unsplit_to_string (string, quoted)
- char *string;
- int quoted;
-{
- return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
-}
-
-char *
-expand_assignment_string_to_string (string, quoted)
- char *string;
- int quoted;
-{
- return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
-}
-
-char *
-expand_arith_string (string, quoted)
- char *string;
- int quoted;
-{
- return (expand_string_if_necessary (string, quoted, expand_string));
-}
-
-#if defined (COND_COMMAND)
-/* Just remove backslashes in STRING. Returns a new string. */
-char *
-remove_backslashes (string)
- char *string;
-{
- char *r, *ret, *s;
-
- r = ret = (char *)xmalloc (strlen (string) + 1);
- for (s = string; s && *s; )
- {
- if (*s == '\\')
- s++;
- if (*s == 0)
- break;
- *r++ = *s++;
- }
- *r = '\0';
- return ret;
-}
-
-/* This needs better error handling. */
-/* Expand W for use as an argument to a unary or binary operator in a
- [[...]] expression. If SPECIAL is 1, this is the rhs argument
- to the != or == operator, and should be treated as a pattern. In
- this case, we quote the string specially for the globbing code. If
- SPECIAL is 2, this is an rhs argument for the =~ operator, and should
- be quoted appropriately for regcomp/regexec. The caller is responsible
- for removing the backslashes if the unquoted word is needed later. */
-char *
-cond_expand_word (w, special)
- WORD_DESC *w;
- int special;
-{
- char *r, *p;
- WORD_LIST *l;
- int qflags;
-
- if (w->word == 0 || w->word[0] == '\0')
- return ((char *)NULL);
-
- w->flags |= W_NOSPLIT2;
- l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
- if (l)
- {
- if (special == 0)
- {
- dequote_list (l);
- r = string_list (l);
- }
- else
- {
- qflags = QGLOB_CVTNULL;
- if (special == 2)
- qflags |= QGLOB_REGEXP;
- p = string_list (l);
- r = quote_string_for_globbing (p, qflags);
- free (p);
- }
- dispose_words (l);
- }
- else
- r = (char *)NULL;
-
- return r;
-}
-#endif
-
-/* Call expand_word_internal to expand W and handle error returns.
- A convenience function for functions that don't want to handle
- any errors or free any memory before aborting. */
-static WORD_LIST *
-call_expand_word_internal (w, q, i, c, e)
- WORD_DESC *w;
- int q, i, *c, *e;
-{
- WORD_LIST *result;
-
- result = expand_word_internal (w, q, i, c, e);
- if (result == &expand_word_error || result == &expand_word_fatal)
- {
- /* By convention, each time this error is returned, w->word has
- already been freed (it sometimes may not be in the fatal case,
- but that doesn't result in a memory leak because we're going
- to exit in most cases). */
- w->word = (char *)NULL;
- last_command_exit_value = EXECUTION_FAILURE;
- exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
- /* NOTREACHED */
- }
- else
- return (result);
-}
-
-/* Perform parameter expansion, command substitution, and arithmetic
- expansion on STRING, as if it were a word. Leave the result quoted.
- Since this does not perform word splitting, it leaves quoted nulls
- in the result. */
-static WORD_LIST *
-expand_string_internal (string, quoted)
- char *string;
- int quoted;
-{
- WORD_DESC td;
- WORD_LIST *tresult;
-
- if (string == 0 || *string == 0)
- return ((WORD_LIST *)NULL);
-
- td.flags = 0;
- td.word = savestring (string);
-
- tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
-
- FREE (td.word);
- return (tresult);
-}
-
-/* Expand STRING by performing parameter expansion, command substitution,
- and arithmetic expansion. Dequote the resulting WORD_LIST before
- returning it, but do not perform word splitting. The call to
- remove_quoted_nulls () is in here because word splitting normally
- takes care of quote removal. */
-WORD_LIST *
-expand_string_unsplit (string, quoted)
- char *string;
- int quoted;
-{
- WORD_LIST *value;
-
- if (string == 0 || *string == '\0')
- return ((WORD_LIST *)NULL);
-
- expand_no_split_dollar_star = 1;
- value = expand_string_internal (string, quoted);
- expand_no_split_dollar_star = 0;
-
- if (value)
- {
- if (value->word)
- {
- remove_quoted_nulls (value->word->word);
- value->word->flags &= ~W_HASQUOTEDNULL;
- }
- dequote_list (value);
- }
- return (value);
-}
-
-/* Expand the rhs of an assignment statement */
-WORD_LIST *
-expand_string_assignment (string, quoted)
- char *string;
- int quoted;
-{
- WORD_DESC td;
- WORD_LIST *value;
-
- if (string == 0 || *string == '\0')
- return ((WORD_LIST *)NULL);
-
- expand_no_split_dollar_star = 1;
-
- td.flags = W_ASSIGNRHS;
- td.word = savestring (string);
- value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
- FREE (td.word);
-
- expand_no_split_dollar_star = 0;
-
- if (value)
- {
- if (value->word)
- {
- remove_quoted_nulls (value->word->word);
- value->word->flags &= ~W_HASQUOTEDNULL;
- }
- dequote_list (value);
- }
- return (value);
-}
-
-
-/* Expand one of the PS? prompt strings. This is a sort of combination of
- expand_string_unsplit and expand_string_internal, but returns the
- passed string when an error occurs. Might want to trap other calls
- to jump_to_top_level here so we don't endlessly loop. */
-WORD_LIST *
-expand_prompt_string (string, quoted, wflags)
- char *string;
- int quoted;
- int wflags;
-{
- WORD_LIST *value;
- WORD_DESC td;
-
- if (string == 0 || *string == 0)
- return ((WORD_LIST *)NULL);
-
- td.flags = wflags;
- td.word = savestring (string);
-
- no_longjmp_on_fatal_error = 1;
- value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
- no_longjmp_on_fatal_error = 0;
-
- if (value == &expand_word_error || value == &expand_word_fatal)
- {
- value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
- return value;
- }
- FREE (td.word);
- if (value)
- {
- if (value->word)
- {
- remove_quoted_nulls (value->word->word);
- value->word->flags &= ~W_HASQUOTEDNULL;
- }
- dequote_list (value);
- }
- return (value);
-}
-
-/* Expand STRING just as if you were expanding a word, but do not dequote
- the resultant WORD_LIST. This is called only from within this file,
- and is used to correctly preserve quoted characters when expanding
- things like ${1+"$@"}. This does parameter expansion, command
- substitution, arithmetic expansion, and word splitting. */
-static WORD_LIST *
-expand_string_leave_quoted (string, quoted)
- char *string;
- int quoted;
-{
- WORD_LIST *tlist;
- WORD_LIST *tresult;
-
- if (string == 0 || *string == '\0')
- return ((WORD_LIST *)NULL);
-
- tlist = expand_string_internal (string, quoted);
-
- if (tlist)
- {
- tresult = word_list_split (tlist);
- dispose_words (tlist);
- return (tresult);
- }
- return ((WORD_LIST *)NULL);
-}
-
-/* This does not perform word splitting or dequote the WORD_LIST
- it returns. */
-static WORD_LIST *
-expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
- char *string;
- int quoted, *dollar_at_p, *has_dollar_at;
-{
- WORD_DESC td;
- WORD_LIST *tresult;
-
- if (string == 0 || *string == '\0')
- return (WORD_LIST *)NULL;
-
- td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
- td.word = string;
- tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
- return (tresult);
-}
-
-/* Expand STRING just as if you were expanding a word. This also returns
- a list of words. Note that filename globbing is *NOT* done for word
- or string expansion, just when the shell is expanding a command. This
- does parameter expansion, command substitution, arithmetic expansion,
- and word splitting. Dequote the resultant WORD_LIST before returning. */
-WORD_LIST *
-expand_string (string, quoted)
- char *string;
- int quoted;
-{
- WORD_LIST *result;
-
- if (string == 0 || *string == '\0')
- return ((WORD_LIST *)NULL);
-
- result = expand_string_leave_quoted (string, quoted);
- return (result ? dequote_list (result) : result);
-}
-
-/***************************************************
- * *
- * Functions to handle quoting chars *
- * *
- ***************************************************/
-
-/* Conventions:
-
- A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
- The parser passes CTLNUL as CTLESC CTLNUL. */
-
-/* Quote escape characters in string s, but no other characters. This is
- used to protect CTLESC and CTLNUL in variable values from the rest of
- the word expansion process after the variable is expanded (word splitting
- and filename generation). If IFS is null, we quote spaces as well, just
- in case we split on spaces later (in the case of unquoted $@, we will
- eventually attempt to split the entire word on spaces). Corresponding
- code exists in dequote_escapes. Even if we don't end up splitting on
- spaces, quoting spaces is not a problem. This should never be called on
- a string that is quoted with single or double quotes or part of a here
- document (effectively double-quoted). */
-char *
-quote_escapes (string)
- char *string;
-{
- register char *s, *t;
- size_t slen;
- char *result, *send;
- int quote_spaces, skip_ctlesc, skip_ctlnul;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- send = string + slen;
-
- quote_spaces = (ifs_value && *ifs_value == 0);
-
- for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
- skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
-
- t = result = (char *)xmalloc ((slen * 2) + 1);
- s = string;
-
- while (*s)
- {
- if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
- *t++ = CTLESC;
- COPY_CHAR_P (t, s, send);
- }
- *t = '\0';
- return (result);
-}
-
-static WORD_LIST *
-list_quote_escapes (list)
- WORD_LIST *list;
-{
- register WORD_LIST *w;
- char *t;
-
- for (w = list; w; w = w->next)
- {
- t = w->word->word;
- w->word->word = quote_escapes (t);
- free (t);
- }
- return list;
-}
-
-/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
-
- The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
- This is necessary to make unquoted CTLESC and CTLNUL characters in the
- data stream pass through properly.
-
- We need to remove doubled CTLESC characters inside quoted strings before
- quoting the entire string, so we do not double the number of CTLESC
- characters.
-
- Also used by parts of the pattern substitution code. */
-char *
-dequote_escapes (string)
- char *string;
-{
- register char *s, *t, *s1;
- size_t slen;
- char *result, *send;
- int quote_spaces;
- DECLARE_MBSTATE;
-
- if (string == 0)
- return string;
-
- slen = strlen (string);
- send = string + slen;
-
- t = result = (char *)xmalloc (slen + 1);
-
- if (strchr (string, CTLESC) == 0)
- return (strcpy (result, string));
-
- quote_spaces = (ifs_value && *ifs_value == 0);
-
- s = string;
- while (*s)
- {
- if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
- {
- s++;
- if (*s == '\0')
- break;
- }
- COPY_CHAR_P (t, s, send);
- }
- *t = '\0';
- return result;
-}
-
-/* Return a new string with the quoted representation of character C.
- This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
- set in any resultant WORD_DESC where this value is the word. */
-static char *
-make_quoted_char (c)
- int c;
-{
- char *temp;
-
- temp = (char *)xmalloc (3);
- if (c == 0)
- {
- temp[0] = CTLNUL;
- temp[1] = '\0';
- }
- else
- {
- temp[0] = CTLESC;
- temp[1] = c;
- temp[2] = '\0';
- }
- return (temp);
-}
-
-/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
- the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
- this value is the word. */
-char *
-quote_string (string)
- char *string;
-{
- register char *t;
- size_t slen;
- char *result, *send;
-
- if (*string == 0)
- {
- result = (char *)xmalloc (2);
- result[0] = CTLNUL;
- result[1] = '\0';
- }
- else
- {
- DECLARE_MBSTATE;
-
- slen = strlen (string);
- send = string + slen;
-
- result = (char *)xmalloc ((slen * 2) + 1);
-
- for (t = result; string < send; )
- {
- *t++ = CTLESC;
- COPY_CHAR_P (t, string, send);
- }
- *t = '\0';
- }
- return (result);
-}
-
-/* De-quote quoted characters in STRING. */
-char *
-dequote_string (string)
- char *string;
-{
- register char *s, *t;
- size_t slen;
- char *result, *send;
- DECLARE_MBSTATE;
-
- slen = strlen (string);
-
- t = result = (char *)xmalloc (slen + 1);
-
- if (QUOTED_NULL (string))
- {
- result[0] = '\0';
- return (result);
- }
-
- /* If no character in the string can be quoted, don't bother examining
- each character. Just return a copy of the string passed to us. */
- if (strchr (string, CTLESC) == NULL)
- return (strcpy (result, string));
-
- send = string + slen;
- s = string;
- while (*s)
- {
- if (*s == CTLESC)
- {
- s++;
- if (*s == '\0')
- break;
- }
- COPY_CHAR_P (t, s, send);
- }
-
- *t = '\0';
- return (result);
-}
-
-/* Quote the entire WORD_LIST list. */
-static WORD_LIST *
-quote_list (list)
- WORD_LIST *list;
-{
- register WORD_LIST *w;
- char *t;
-
- for (w = list; w; w = w->next)
- {
- t = w->word->word;
- w->word->word = quote_string (t);
- if (*t == 0)
- w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
- w->word->flags |= W_QUOTED;
- free (t);
- }
- return list;
-}
-
-/* De-quote quoted characters in each word in LIST. */
-WORD_LIST *
-dequote_list (list)
- WORD_LIST *list;
-{
- register char *s;
- register WORD_LIST *tlist;
-
- for (tlist = list; tlist; tlist = tlist->next)
- {
- s = dequote_string (tlist->word->word);
- if (QUOTED_NULL (tlist->word->word))
- tlist->word->flags &= ~W_HASQUOTEDNULL;
- free (tlist->word->word);
- tlist->word->word = s;
- }
- return list;
-}
-
-/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
- string. */
-char *
-remove_quoted_escapes (string)
- char *string;
-{
- char *t;
-
- if (string)
- {
- t = dequote_escapes (string);
- strcpy (string, t);
- free (t);
- }
-
- return (string);
-}
-
-/* Perform quoted null character removal on STRING. We don't allow any
- quoted null characters in the middle or at the ends of strings because
- of how expand_word_internal works. remove_quoted_nulls () turns
- STRING into an empty string iff it only consists of a quoted null,
- and removes all unquoted CTLNUL characters. */
-char *
-remove_quoted_nulls (string)
- char *string;
-{
- register size_t slen;
- register int i, j, prev_i;
- DECLARE_MBSTATE;
-
- if (strchr (string, CTLNUL) == 0) /* XXX */
- return string; /* XXX */
-
- slen = strlen (string);
- i = j = 0;
-
- while (i < slen)
- {
- if (string[i] == CTLESC)
- {
- /* Old code had j++, but we cannot assume that i == j at this
- point -- what if a CTLNUL has already been removed from the
- string? We don't want to drop the CTLESC or recopy characters
- that we've already copied down. */
- i++; string[j++] = CTLESC;
- if (i == slen)
- break;
- }
- else if (string[i] == CTLNUL)
- {
- i++;
- continue;
- }
-
- prev_i = i;
- ADVANCE_CHAR (string, slen, i);
- if (j < prev_i)
- {
- do string[j++] = string[prev_i++]; while (prev_i < i);
- }
- else
- j = i;
- }
- string[j] = '\0';
-
- return (string);
-}
-
-/* Perform quoted null character removal on each element of LIST.
- This modifies LIST. */
-void
-word_list_remove_quoted_nulls (list)
- WORD_LIST *list;
-{
- register WORD_LIST *t;
-
- for (t = list; t; t = t->next)
- {
- remove_quoted_nulls (t->word->word);
- t->word->flags &= ~W_HASQUOTEDNULL;
- }
-}
-
-/* **************************************************************** */
-/* */
-/* Functions for Matching and Removing Patterns */
-/* */
-/* **************************************************************** */
-
-#if defined (HANDLE_MULTIBYTE)
-#if 0 /* Currently unused */
-static unsigned char *
-mb_getcharlens (string, len)
- char *string;
- int len;
-{
- int i, offset, last;
- unsigned char *ret;
- char *p;
- DECLARE_MBSTATE;
-
- i = offset = 0;
- last = 0;
- ret = (unsigned char *)xmalloc (len);
- memset (ret, 0, len);
- while (string[last])
- {
- ADVANCE_CHAR (string, len, offset);
- ret[last] = offset - last;
- last = offset;
- }
- return ret;
-}
-#endif
-#endif
-
-/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
- can have one of 4 values:
- RP_LONG_LEFT remove longest matching portion at start of PARAM
- RP_SHORT_LEFT remove shortest matching portion at start of PARAM
- RP_LONG_RIGHT remove longest matching portion at end of PARAM
- RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
-*/
-
-#define RP_LONG_LEFT 1
-#define RP_SHORT_LEFT 2
-#define RP_LONG_RIGHT 3
-#define RP_SHORT_RIGHT 4
-
-/* Returns its first argument if nothing matched; new memory otherwise */
-static char *
-remove_upattern (param, pattern, op)
- char *param, *pattern;
- int op;
-{
- register int len;
- register char *end;
- register char *p, *ret, c;
-
- len = STRLEN (param);
- end = param + len;
-
- switch (op)
- {
- case RP_LONG_LEFT: /* remove longest match at start */
- for (p = end; p >= param; p--)
- {
- c = *p; *p = '\0';
- if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- *p = c;
- return (savestring (p));
- }
- *p = c;
-
- }
- break;
-
- case RP_SHORT_LEFT: /* remove shortest match at start */
- for (p = param; p <= end; p++)
- {
- c = *p; *p = '\0';
- if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- *p = c;
- return (savestring (p));
- }
- *p = c;
- }
- break;
-
- case RP_LONG_RIGHT: /* remove longest match at end */
- for (p = param; p <= end; p++)
- {
- if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- c = *p; *p = '\0';
- ret = savestring (param);
- *p = c;
- return (ret);
- }
- }
- break;
-
- case RP_SHORT_RIGHT: /* remove shortest match at end */
- for (p = end; p >= param; p--)
- {
- if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- c = *p; *p = '\0';
- ret = savestring (param);
- *p = c;
- return (ret);
- }
- }
- break;
- }
-
- return (param); /* no match, return original string */
-}
-
-#if defined (HANDLE_MULTIBYTE)
-/* Returns its first argument if nothing matched; new memory otherwise */
-static wchar_t *
-remove_wpattern (wparam, wstrlen, wpattern, op)
- wchar_t *wparam;
- size_t wstrlen;
- wchar_t *wpattern;
- int op;
-{
- wchar_t wc, *ret;
- int n;
-
- switch (op)
- {
- case RP_LONG_LEFT: /* remove longest match at start */
- for (n = wstrlen; n >= 0; n--)
- {
- wc = wparam[n]; wparam[n] = L'\0';
- if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- wparam[n] = wc;
- return (wcsdup (wparam + n));
- }
- wparam[n] = wc;
- }
- break;
-
- case RP_SHORT_LEFT: /* remove shortest match at start */
- for (n = 0; n <= wstrlen; n++)
- {
- wc = wparam[n]; wparam[n] = L'\0';
- if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- wparam[n] = wc;
- return (wcsdup (wparam + n));
- }
- wparam[n] = wc;
- }
- break;
-
- case RP_LONG_RIGHT: /* remove longest match at end */
- for (n = 0; n <= wstrlen; n++)
- {
- if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- wc = wparam[n]; wparam[n] = L'\0';
- ret = wcsdup (wparam);
- wparam[n] = wc;
- return (ret);
- }
- }
- break;
-
- case RP_SHORT_RIGHT: /* remove shortest match at end */
- for (n = wstrlen; n >= 0; n--)
- {
- if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
- {
- wc = wparam[n]; wparam[n] = L'\0';
- ret = wcsdup (wparam);
- wparam[n] = wc;
- return (ret);
- }
- }
- break;
- }
-
- return (wparam); /* no match, return original string */
-}
-#endif /* HANDLE_MULTIBYTE */
-
-static char *
-remove_pattern (param, pattern, op)
- char *param, *pattern;
- int op;
-{
- char *xret;
-
- if (param == NULL)
- return (param);
- if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
- return (savestring (param));
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1)
- {
- wchar_t *ret, *oret;
- size_t n;
- wchar_t *wparam, *wpattern;
- mbstate_t ps;
-
- n = xdupmbstowcs (&wpattern, NULL, pattern);
- if (n == (size_t)-1)
- {
- xret = remove_upattern (param, pattern, op);
- return ((xret == param) ? savestring (param) : xret);
- }
- n = xdupmbstowcs (&wparam, NULL, param);
- if (n == (size_t)-1)
- {
- free (wpattern);
- xret = remove_upattern (param, pattern, op);
- return ((xret == param) ? savestring (param) : xret);
- }
- oret = ret = remove_wpattern (wparam, n, wpattern, op);
- /* Don't bother to convert wparam back to multibyte string if nothing
- matched; just return copy of original string */
- if (ret == wparam)
- {
- free (wparam);
- free (wpattern);
- return (savestring (param));
- }
-
- free (wparam);
- free (wpattern);
-
- n = strlen (param);
- xret = (char *)xmalloc (n + 1);
- memset (&ps, '\0', sizeof (mbstate_t));
- n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
- xret[n] = '\0'; /* just to make sure */
- free (oret);
- return xret;
- }
- else
-#endif
- {
- xret = remove_upattern (param, pattern, op);
- return ((xret == param) ? savestring (param) : xret);
- }
-}
-
-/* Match PAT anywhere in STRING and return the match boundaries.
- This returns 1 in case of a successful match, 0 otherwise. SP
- and EP are pointers into the string where the match begins and
- ends, respectively. MTYPE controls what kind of match is attempted.
- MATCH_BEG and MATCH_END anchor the match at the beginning and end
- of the string, respectively. The longest match is returned. */
-static int
-match_upattern (string, pat, mtype, sp, ep)
- char *string, *pat;
- int mtype;
- char **sp, **ep;
-{
- int c, len, mlen;
- register char *p, *p1, *npat;
- char *end;
- int n1;
-
- /* If the pattern doesn't match anywhere in the string, go ahead and
- short-circuit right away. A minor optimization, saves a bunch of
- unnecessary calls to strmatch (up to N calls for a string of N
- characters) if the match is unsuccessful. To preserve the semantics
- of the substring matches below, we make sure that the pattern has
- `*' as first and last character, making a new pattern if necessary. */
- /* XXX - check this later if I ever implement `**' with special meaning,
- since this will potentially result in `**' at the beginning or end */
- len = STRLEN (pat);
- if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
- {
- p = npat = (char *)xmalloc (len + 3);
- p1 = pat;
- if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
- *p++ = '*';
- while (*p1)
- *p++ = *p1++;
- if (p1[-1] != '*' || p[-2] == '\\')
- *p++ = '*';
- *p = '\0';
- }
- else
- npat = pat;
- c = strmatch (npat, string, FNMATCH_EXTFLAG);
- if (npat != pat)
- free (npat);
- if (c == FNM_NOMATCH)
- return (0);
-
- len = STRLEN (string);
- end = string + len;
-
- mlen = umatchlen (pat, len);
-
- switch (mtype)
- {
- case MATCH_ANY:
- for (p = string; p <= end; p++)
- {
- if (match_pattern_char (pat, p))
- {
-#if 0
- for (p1 = end; p1 >= p; p1--)
-#else
- p1 = (mlen == -1) ? end : p + mlen;
- /* p1 - p = length of portion of string to be considered
- p = current position in string
- mlen = number of characters consumed by match (-1 for entire string)
- end = end of string
- we want to break immediately if the potential match len
- is greater than the number of characters remaining in the
- string
- */
- if (p1 > end)
- break;
- for ( ; p1 >= p; p1--)
-#endif
- {
- c = *p1; *p1 = '\0';
- if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
- {
- *p1 = c;
- *sp = p;
- *ep = p1;
- return 1;
- }
- *p1 = c;
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
- }
- }
-
- return (0);
-
- case MATCH_BEG:
- if (match_pattern_char (pat, string) == 0)
- return (0);
-
-#if 0
- for (p = end; p >= string; p--)
-#else
- for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
-#endif
- {
- c = *p; *p = '\0';
- if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
- {
- *p = c;
- *sp = string;
- *ep = p;
- return 1;
- }
- *p = c;
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
-
- return (0);
-
- case MATCH_END:
-#if 0
- for (p = string; p <= end; p++)
-#else
- for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
-#endif
- {
- if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
- {
- *sp = p;
- *ep = end;
- return 1;
- }
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
-
- return (0);
- }
-
- return (0);
-}
-
-#if defined (HANDLE_MULTIBYTE)
-/* Match WPAT anywhere in WSTRING and return the match boundaries.
- This returns 1 in case of a successful match, 0 otherwise. Wide
- character version. */
-static int
-match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
- wchar_t *wstring;
- char **indices;
- size_t wstrlen;
- wchar_t *wpat;
- int mtype;
- char **sp, **ep;
-{
- wchar_t wc, *wp, *nwpat, *wp1;
- size_t len;
- int mlen;
- int n, n1, n2, simple;
-
- simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
-#if defined (EXTENDED_GLOB)
- if (extended_glob)
- simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
-#endif
-
- /* If the pattern doesn't match anywhere in the string, go ahead and
- short-circuit right away. A minor optimization, saves a bunch of
- unnecessary calls to strmatch (up to N calls for a string of N
- characters) if the match is unsuccessful. To preserve the semantics
- of the substring matches below, we make sure that the pattern has
- `*' as first and last character, making a new pattern if necessary. */
- len = wcslen (wpat);
- if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
- {
- wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
- wp1 = wpat;
- if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
- *wp++ = L'*';
- while (*wp1 != L'\0')
- *wp++ = *wp1++;
- if (wp1[-1] != L'*' || wp1[-2] == L'\\')
- *wp++ = L'*';
- *wp = '\0';
- }
- else
- nwpat = wpat;
- len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
- if (nwpat != wpat)
- free (nwpat);
- if (len == FNM_NOMATCH)
- return (0);
-
- mlen = wmatchlen (wpat, wstrlen);
-
-/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
- switch (mtype)
- {
- case MATCH_ANY:
- for (n = 0; n <= wstrlen; n++)
- {
-#if 1
- n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
-#else
- n2 = match_pattern_wchar (wpat, wstring + n);
-#endif
- if (n2)
- {
-#if 0
- for (n1 = wstrlen; n1 >= n; n1--)
-#else
- n1 = (mlen == -1) ? wstrlen : n + mlen;
- if (n1 > wstrlen)
- break;
-
- for ( ; n1 >= n; n1--)
-#endif
- {
- wc = wstring[n1]; wstring[n1] = L'\0';
- if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
- {
- wstring[n1] = wc;
- *sp = indices[n];
- *ep = indices[n1];
- return 1;
- }
- wstring[n1] = wc;
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
- }
- }
-
- return (0);
-
- case MATCH_BEG:
- if (match_pattern_wchar (wpat, wstring) == 0)
- return (0);
-
-#if 0
- for (n = wstrlen; n >= 0; n--)
-#else
- for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
-#endif
- {
- wc = wstring[n]; wstring[n] = L'\0';
- if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
- {
- wstring[n] = wc;
- *sp = indices[0];
- *ep = indices[n];
- return 1;
- }
- wstring[n] = wc;
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
-
- return (0);
-
- case MATCH_END:
-#if 0
- for (n = 0; n <= wstrlen; n++)
-#else
- for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
-#endif
- {
- if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
- {
- *sp = indices[n];
- *ep = indices[wstrlen];
- return 1;
- }
-#if 1
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
-#endif
- }
-
- return (0);
- }
-
- return (0);
-}
-#endif /* HANDLE_MULTIBYTE */
-
-static int
-match_pattern (string, pat, mtype, sp, ep)
- char *string, *pat;
- int mtype;
- char **sp, **ep;
-{
-#if defined (HANDLE_MULTIBYTE)
- int ret;
- size_t n;
- wchar_t *wstring, *wpat;
- char **indices;
- size_t slen, plen, mslen, mplen;
-#endif
-
- if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
- return (0);
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1)
- {
-#if 0
- slen = STRLEN (string);
- mslen = MBSLEN (string);
- plen = STRLEN (pat);
- mplen = MBSLEN (pat);
- if (slen == mslen && plen == mplen)
-#else
- if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
-#endif
- return (match_upattern (string, pat, mtype, sp, ep));
-
- n = xdupmbstowcs (&wpat, NULL, pat);
- if (n == (size_t)-1)
- return (match_upattern (string, pat, mtype, sp, ep));
- n = xdupmbstowcs (&wstring, &indices, string);
- if (n == (size_t)-1)
- {
- free (wpat);
- return (match_upattern (string, pat, mtype, sp, ep));
- }
- ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
-
- free (wpat);
- free (wstring);
- free (indices);
-
- return (ret);
- }
- else
-#endif
- return (match_upattern (string, pat, mtype, sp, ep));
-}
-
-static int
-getpatspec (c, value)
- int c;
- char *value;
-{
- if (c == '#')
- return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
- else /* c == '%' */
- return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
-}
-
-/* Posix.2 says that the WORD should be run through tilde expansion,
- parameter expansion, command substitution and arithmetic expansion.
- This leaves the result quoted, so quote_string_for_globbing () has
- to be called to fix it up for strmatch (). If QUOTED is non-zero,
- it means that the entire expression was enclosed in double quotes.
- This means that quoting characters in the pattern do not make any
- special pattern characters quoted. For example, the `*' in the
- following retains its special meaning: "${foo#'*'}". */
-static char *
-getpattern (value, quoted, expandpat)
- char *value;
- int quoted, expandpat;
-{
- char *pat, *tword;
- WORD_LIST *l;
-#if 0
- int i;
-#endif
- /* There is a problem here: how to handle single or double quotes in the
- pattern string when the whole expression is between double quotes?
- POSIX.2 says that enclosing double quotes do not cause the pattern to
- be quoted, but does that leave us a problem with @ and array[@] and their
- expansions inside a pattern? */
-#if 0
- if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
- {
- i = 0;
- pat = string_extract_double_quoted (tword, &i, 1);
- free (tword);
- tword = pat;
- }
-#endif
-
- /* expand_string_for_rhs () leaves WORD quoted and does not perform
- word splitting. */
- l = *value ? expand_string_for_rhs (value,
- (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
- (int *)NULL, (int *)NULL)
- : (WORD_LIST *)0;
- pat = string_list (l);
- dispose_words (l);
- if (pat)
- {
- tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
- free (pat);
- pat = tword;
- }
- return (pat);
-}
-
-#if 0
-/* Handle removing a pattern from a string as a result of ${name%[%]value}
- or ${name#[#]value}. */
-static char *
-variable_remove_pattern (value, pattern, patspec, quoted)
- char *value, *pattern;
- int patspec, quoted;
-{
- char *tword;
-
- tword = remove_pattern (value, pattern, patspec);
-
- return (tword);
-}
-#endif
-
-static char *
-list_remove_pattern (list, pattern, patspec, itype, quoted)
- WORD_LIST *list;
- char *pattern;
- int patspec, itype, quoted;
-{
- WORD_LIST *new, *l;
- WORD_DESC *w;
- char *tword;
-
- for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
- {
- tword = remove_pattern (l->word->word, pattern, patspec);
- w = alloc_word_desc ();
- w->word = tword ? tword : savestring ("");
- new = make_word_list (w, new);
- }
-
- l = REVERSE_LIST (new, WORD_LIST *);
- tword = string_list_pos_params (itype, l, quoted);
- dispose_words (l);
-
- return (tword);
-}
-
-static char *
-parameter_list_remove_pattern (itype, pattern, patspec, quoted)
- int itype;
- char *pattern;
- int patspec, quoted;
-{
- char *ret;
- WORD_LIST *list;
-
- list = list_rest_of_args ();
- if (list == 0)
- return ((char *)NULL);
- ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
- dispose_words (list);
- return (ret);
-}
-
-#if defined (ARRAY_VARS)
-static char *
-array_remove_pattern (var, pattern, patspec, varname, quoted)
- SHELL_VAR *var;
- char *pattern;
- int patspec;
- char *varname; /* so we can figure out how it's indexed */
- int quoted;
-{
- ARRAY *a;
- HASH_TABLE *h;
- int itype;
- char *ret;
- WORD_LIST *list;
- SHELL_VAR *v;
-
- /* compute itype from varname here */
- v = array_variable_part (varname, &ret, 0);
- itype = ret[0];
-
- a = (v && array_p (v)) ? array_cell (v) : 0;
- h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
-
- list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
- if (list == 0)
- return ((char *)NULL);
- ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
- dispose_words (list);
-
- return ret;
-}
-#endif /* ARRAY_VARS */
-
-static char *
-parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
- char *varname, *value;
- int ind;
- char *patstr;
- int rtype, quoted, flags;
-{
- int vtype, patspec, starsub;
- char *temp1, *val, *pattern;
- SHELL_VAR *v;
-
- if (value == 0)
- return ((char *)NULL);
-
- this_command_name = varname;
-
- vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
- if (vtype == -1)
- return ((char *)NULL);
-
- starsub = vtype & VT_STARSUB;
- vtype &= ~VT_STARSUB;
-
- patspec = getpatspec (rtype, patstr);
- if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
- patstr++;
-
- /* Need to pass getpattern newly-allocated memory in case of expansion --
- the expansion code will free the passed string on an error. */
- temp1 = savestring (patstr);
- pattern = getpattern (temp1, quoted, 1);
- free (temp1);
-
- temp1 = (char *)NULL; /* shut up gcc */
- switch (vtype)
- {
- case VT_VARIABLE:
- case VT_ARRAYMEMBER:
- temp1 = remove_pattern (val, pattern, patspec);
- if (vtype == VT_VARIABLE)
- FREE (val);
- if (temp1)
- {
- val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- ? quote_string (temp1)
- : quote_escapes (temp1);
- free (temp1);
- temp1 = val;
- }
- break;
-#if defined (ARRAY_VARS)
- case VT_ARRAYVAR:
- temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
- if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
- {
- val = quote_escapes (temp1);
- free (temp1);
- temp1 = val;
- }
- break;
-#endif
- case VT_POSPARMS:
- temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
- if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
- {
- val = quote_escapes (temp1);
- free (temp1);
- temp1 = val;
- }
- break;
- }
-
- FREE (pattern);
- return temp1;
-}
-
-/*******************************************
- * *
- * Functions to expand WORD_DESCs *
- * *
- *******************************************/
-
-/* Expand WORD, performing word splitting on the result. This does
- parameter expansion, command substitution, arithmetic expansion,
- word splitting, and quote removal. */
-
-WORD_LIST *
-expand_word (word, quoted)
- WORD_DESC *word;
- int quoted;
-{
- WORD_LIST *result, *tresult;
-
- tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
- result = word_list_split (tresult);
- dispose_words (tresult);
- return (result ? dequote_list (result) : result);
-}
-
-/* Expand WORD, but do not perform word splitting on the result. This
- does parameter expansion, command substitution, arithmetic expansion,
- and quote removal. */
-WORD_LIST *
-expand_word_unsplit (word, quoted)
- WORD_DESC *word;
- int quoted;
-{
- WORD_LIST *result;
-
- expand_no_split_dollar_star = 1;
-#if defined (HANDLE_MULTIBYTE)
- if (ifs_firstc[0] == 0)
-#else
- if (ifs_firstc == 0)
-#endif
- word->flags |= W_NOSPLIT;
- word->flags |= W_NOSPLIT2;
- result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
- expand_no_split_dollar_star = 0;
-
- return (result ? dequote_list (result) : result);
-}
-
-/* Perform shell expansions on WORD, but do not perform word splitting or
- quote removal on the result. Virtually identical to expand_word_unsplit;
- could be combined if implementations don't diverge. */
-WORD_LIST *
-expand_word_leave_quoted (word, quoted)
- WORD_DESC *word;
- int quoted;
-{
- WORD_LIST *result;
-
- expand_no_split_dollar_star = 1;
-#if defined (HANDLE_MULTIBYTE)
- if (ifs_firstc[0] == 0)
-#else
- if (ifs_firstc == 0)
-#endif
- word->flags |= W_NOSPLIT;
- word->flags |= W_NOSPLIT2;
- result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
- expand_no_split_dollar_star = 0;
-
- return result;
-}
-
-#if defined (PROCESS_SUBSTITUTION)
-
-/*****************************************************************/
-/* */
-/* Hacking Process Substitution */
-/* */
-/*****************************************************************/
-
-#if !defined (HAVE_DEV_FD)
-/* Named pipes must be removed explicitly with `unlink'. This keeps a list
- of FIFOs the shell has open. unlink_fifo_list will walk the list and
- unlink all of them. add_fifo_list adds the name of an open FIFO to the
- list. NFIFO is a count of the number of FIFOs in the list. */
-#define FIFO_INCR 20
-
-struct temp_fifo {
- char *file;
- pid_t proc;
-};
-
-static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
-static int nfifo;
-static int fifo_list_size;
-
-char *
-copy_fifo_list (sizep)
- int *sizep;
-{
- if (sizep)
- *sizep = 0;
- return (char *)NULL;
-}
-
-static void
-add_fifo_list (pathname)
- char *pathname;
-{
- if (nfifo >= fifo_list_size - 1)
- {
- fifo_list_size += FIFO_INCR;
- fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
- fifo_list_size * sizeof (struct temp_fifo));
- }
-
- fifo_list[nfifo].file = savestring (pathname);
- nfifo++;
-}
-
-void
-unlink_fifo (i)
- int i;
-{
- if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
- {
- unlink (fifo_list[i].file);
- free (fifo_list[i].file);
- fifo_list[i].file = (char *)NULL;
- fifo_list[i].proc = -1;
- }
-}
-
-void
-unlink_fifo_list ()
-{
- int saved, i, j;
-
- if (nfifo == 0)
- return;
-
- for (i = saved = 0; i < nfifo; i++)
- {
- if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
- {
- unlink (fifo_list[i].file);
- free (fifo_list[i].file);
- fifo_list[i].file = (char *)NULL;
- fifo_list[i].proc = -1;
- }
- else
- saved++;
- }
-
- /* If we didn't remove some of the FIFOs, compact the list. */
- if (saved)
- {
- for (i = j = 0; i < nfifo; i++)
- if (fifo_list[i].file)
- {
- fifo_list[j].file = fifo_list[i].file;
- fifo_list[j].proc = fifo_list[i].proc;
- j++;
- }
- nfifo = j;
- }
- else
- nfifo = 0;
-}
-
-/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
- from some point in the past, and close all open FIFOs in fifo_list
- that are not marked as active in LIST. If LIST is NULL, close
- everything in fifo_list. LSIZE is the number of elements in LIST, in
- case it's larger than fifo_list_size (size of fifo_list). */
-void
-close_new_fifos (list, lsize)
- char *list;
- int lsize;
-{
- int i;
-
- if (list == 0)
- {
- unlink_fifo_list ();
- return;
- }
-
- for (i = 0; i < lsize; i++)
- if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
- unlink_fifo (i);
-
- for (i = lsize; i < fifo_list_size; i++)
- unlink_fifo (i);
-}
-
-int
-fifos_pending ()
-{
- return nfifo;
-}
-
-int
-num_fifos ()
-{
- return nfifo;
-}
-
-static char *
-make_named_pipe ()
-{
- char *tname;
-
- tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
- if (mkfifo (tname, 0600) < 0)
- {
- free (tname);
- return ((char *)NULL);
- }
-
- add_fifo_list (tname);
- return (tname);
-}
-
-#else /* HAVE_DEV_FD */
-
-/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
- has open to children. NFDS is a count of the number of bits currently
- set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
- of open files. */
-static char *dev_fd_list = (char *)NULL;
-static int nfds;
-static int totfds; /* The highest possible number of open files. */
-
-char *
-copy_fifo_list (sizep)
- int *sizep;
-{
- char *ret;
-
- if (nfds == 0 || totfds == 0)
- {
- if (sizep)
- *sizep = 0;
- return (char *)NULL;
- }
-
- if (sizep)
- *sizep = totfds;
- ret = (char *)xmalloc (totfds);
- return (memcpy (ret, dev_fd_list, totfds));
-}
-
-static void
-add_fifo_list (fd)
- int fd;
-{
- if (dev_fd_list == 0 || fd >= totfds)
- {
- int ofds;
-
- ofds = totfds;
- totfds = getdtablesize ();
- if (totfds < 0 || totfds > 256)
- totfds = 256;
- if (fd >= totfds)
- totfds = fd + 2;
-
- dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
- memset (dev_fd_list + ofds, '\0', totfds - ofds);
- }
-
- dev_fd_list[fd] = 1;
- nfds++;
-}
-
-int
-fifos_pending ()
-{
- return 0; /* used for cleanup; not needed with /dev/fd */
-}
-
-int
-num_fifos ()
-{
- return nfds;
-}
-
-void
-unlink_fifo (fd)
- int fd;
-{
- if (dev_fd_list[fd])
- {
- close (fd);
- dev_fd_list[fd] = 0;
- nfds--;
- }
-}
-
-void
-unlink_fifo_list ()
-{
- register int i;
-
- if (nfds == 0)
- return;
-
- for (i = 0; nfds && i < totfds; i++)
- unlink_fifo (i);
-
- nfds = 0;
-}
-
-/* Take LIST, which is a snapshot copy of dev_fd_list from some point in
- the past, and close all open fds in dev_fd_list that are not marked
- as open in LIST. If LIST is NULL, close everything in dev_fd_list.
- LSIZE is the number of elements in LIST, in case it's larger than
- totfds (size of dev_fd_list). */
-void
-close_new_fifos (list, lsize)
- char *list;
- int lsize;
-{
- int i;
-
- if (list == 0)
- {
- unlink_fifo_list ();
- return;
- }
-
- for (i = 0; i < lsize; i++)
- if (list[i] == 0 && i < totfds && dev_fd_list[i])
- unlink_fifo (i);
-
- for (i = lsize; i < totfds; i++)
- unlink_fifo (i);
-}
-
-#if defined (NOTDEF)
-print_dev_fd_list ()
-{
- register int i;
-
- fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
- fflush (stderr);
-
- for (i = 0; i < totfds; i++)
- {
- if (dev_fd_list[i])
- fprintf (stderr, " %d", i);
- }
- fprintf (stderr, "\n");
-}
-#endif /* NOTDEF */
-
-static char *
-make_dev_fd_filename (fd)
- int fd;
-{
- char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
-
- ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
-
- strcpy (ret, DEV_FD_PREFIX);
- p = inttostr (fd, intbuf, sizeof (intbuf));
- strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
-
- add_fifo_list (fd);
- return (ret);
-}
-
-#endif /* HAVE_DEV_FD */
-
-/* Return a filename that will open a connection to the process defined by
- executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
- a filename in /dev/fd corresponding to a descriptor that is one of the
- ends of the pipe. If not defined, we use named pipes on systems that have
- them. Systems without /dev/fd and named pipes are out of luck.
-
- OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
- use the read end of the pipe and dup that file descriptor to fd 0 in
- the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
- writing or use the write end of the pipe in the child, and dup that
- file descriptor to fd 1 in the child. The parent does the opposite. */
-
-static char *
-process_substitute (string, open_for_read_in_child)
- char *string;
- int open_for_read_in_child;
-{
- char *pathname;
- int fd, result;
- pid_t old_pid, pid;
-#if defined (HAVE_DEV_FD)
- int parent_pipe_fd, child_pipe_fd;
- int fildes[2];
-#endif /* HAVE_DEV_FD */
-#if defined (JOB_CONTROL)
- pid_t old_pipeline_pgrp;
-#endif
-
- if (!string || !*string || wordexp_only)
- return ((char *)NULL);
-
-#if !defined (HAVE_DEV_FD)
- pathname = make_named_pipe ();
-#else /* HAVE_DEV_FD */
- if (pipe (fildes) < 0)
- {
- sys_error (_("cannot make pipe for process substitution"));
- return ((char *)NULL);
- }
- /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
- the pipe in the parent, otherwise the read end. */
- parent_pipe_fd = fildes[open_for_read_in_child];
- child_pipe_fd = fildes[1 - open_for_read_in_child];
- /* Move the parent end of the pipe to some high file descriptor, to
- avoid clashes with FDs used by the script. */
- parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
-
- pathname = make_dev_fd_filename (parent_pipe_fd);
-#endif /* HAVE_DEV_FD */
-
- if (pathname == 0)
- {
- sys_error (_("cannot make pipe for process substitution"));
- return ((char *)NULL);
- }
-
- old_pid = last_made_pid;
-
-#if defined (JOB_CONTROL)
- old_pipeline_pgrp = pipeline_pgrp;
- pipeline_pgrp = shell_pgrp;
- save_pipeline (1);
-#endif /* JOB_CONTROL */
-
- pid = make_child ((char *)NULL, 1);
- if (pid == 0)
- {
- reset_terminating_signals (); /* XXX */
- free_pushed_string_input ();
- /* Cancel traps, in trap.c. */
- restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
- setup_async_signals ();
- subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
- }
-
-#if defined (JOB_CONTROL)
- set_sigchld_handler ();
- stop_making_children ();
- /* XXX - should we only do this in the parent? (as in command subst) */
- pipeline_pgrp = old_pipeline_pgrp;
-#endif /* JOB_CONTROL */
-
- if (pid < 0)
- {
- sys_error (_("cannot make child for process substitution"));
- free (pathname);
-#if defined (HAVE_DEV_FD)
- close (parent_pipe_fd);
- close (child_pipe_fd);
-#endif /* HAVE_DEV_FD */
- return ((char *)NULL);
- }
-
- if (pid > 0)
- {
-#if defined (JOB_CONTROL)
- restore_pipeline (1);
-#endif
-
-#if !defined (HAVE_DEV_FD)
- fifo_list[nfifo-1].proc = pid;
-#endif
-
- last_made_pid = old_pid;
-
-#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
- close_pgrp_pipe ();
-#endif /* JOB_CONTROL && PGRP_PIPE */
-
-#if defined (HAVE_DEV_FD)
- close (child_pipe_fd);
-#endif /* HAVE_DEV_FD */
-
- return (pathname);
- }
-
- set_sigint_handler ();
-
-#if defined (JOB_CONTROL)
- set_job_control (0);
-#endif /* JOB_CONTROL */
-
-#if !defined (HAVE_DEV_FD)
- /* Open the named pipe in the child. */
- fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
- if (fd < 0)
- {
- /* Two separate strings for ease of translation. */
- if (open_for_read_in_child)
- sys_error (_("cannot open named pipe %s for reading"), pathname);
- else
- sys_error (_("cannot open named pipe %s for writing"), pathname);
-
- exit (127);
- }
- if (open_for_read_in_child)
- {
- if (sh_unset_nodelay_mode (fd) < 0)
- {
- sys_error (_("cannot reset nodelay mode for fd %d"), fd);
- exit (127);
- }
- }
-#else /* HAVE_DEV_FD */
- fd = child_pipe_fd;
-#endif /* HAVE_DEV_FD */
-
- if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
- {
- sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
- open_for_read_in_child ? 0 : 1);
- exit (127);
- }
-
- if (fd != (open_for_read_in_child ? 0 : 1))
- close (fd);
-
- /* Need to close any files that this process has open to pipes inherited
- from its parent. */
- if (current_fds_to_close)
- {
- close_fd_bitmap (current_fds_to_close);
- current_fds_to_close = (struct fd_bitmap *)NULL;
- }
-
-#if defined (HAVE_DEV_FD)
- /* Make sure we close the parent's end of the pipe and clear the slot
- in the fd list so it is not closed later, if reallocated by, for
- instance, pipe(2). */
- close (parent_pipe_fd);
- dev_fd_list[parent_pipe_fd] = 0;
-#endif /* HAVE_DEV_FD */
-
- result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
-
-#if !defined (HAVE_DEV_FD)
- /* Make sure we close the named pipe in the child before we exit. */
- close (open_for_read_in_child ? 0 : 1);
-#endif /* !HAVE_DEV_FD */
-
- exit (result);
- /*NOTREACHED*/
-}
-#endif /* PROCESS_SUBSTITUTION */
-
-/***********************************/
-/* */
-/* Command Substitution */
-/* */
-/***********************************/
-
-static char *
-read_comsub (fd, quoted, rflag)
- int fd, quoted;
- int *rflag;
-{
- char *istring, buf[128], *bufp, *s;
- int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
- ssize_t bufn;
-
- istring = (char *)NULL;
- istring_index = istring_size = bufn = tflag = 0;
-
- for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
- skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
-
- /* Read the output of the command through the pipe. This may need to be
- changed to understand multibyte characters in the future. */
- while (1)
- {
- if (fd < 0)
- break;
- if (--bufn <= 0)
- {
- bufn = zread (fd, buf, sizeof (buf));
- if (bufn <= 0)
- break;
- bufp = buf;
- }
- c = *bufp++;
-
- if (c == 0)
- {
-#if 0
- internal_warning ("read_comsub: ignored null byte in input");
-#endif
- continue;
- }
-
- /* Add the character to ISTRING, possibly after resizing it. */
- RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
-
- /* This is essentially quote_string inline */
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
- istring[istring_index++] = CTLESC;
- /* Escape CTLESC and CTLNUL in the output to protect those characters
- from the rest of the word expansions (word splitting and globbing.)
- This is essentially quote_escapes inline. */
- else if (skip_ctlesc == 0 && c == CTLESC)
- {
- tflag |= W_HASCTLESC;
- istring[istring_index++] = CTLESC;
- }
- else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
- istring[istring_index++] = CTLESC;
-
- istring[istring_index++] = c;
-
-#if 0
-#if defined (__CYGWIN__)
- if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
- {
- istring_index--;
- istring[istring_index - 1] = '\n';
- }
-#endif
-#endif
- }
-
- if (istring)
- istring[istring_index] = '\0';
-
- /* If we read no output, just return now and save ourselves some
- trouble. */
- if (istring_index == 0)
- {
- FREE (istring);
- if (rflag)
- *rflag = tflag;
- return (char *)NULL;
- }
-
- /* Strip trailing newlines from the output of the command. */
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- {
- while (istring_index > 0)
- {
- if (istring[istring_index - 1] == '\n')
- {
- --istring_index;
-
- /* If the newline was quoted, remove the quoting char. */
- if (istring[istring_index - 1] == CTLESC)
- --istring_index;
- }
- else
- break;
- }
- istring[istring_index] = '\0';
- }
- else
- strip_trailing (istring, istring_index - 1, 1);
-
- if (rflag)
- *rflag = tflag;
- return istring;
-}
-
-/* Perform command substitution on STRING. This returns a WORD_DESC * with the
- contained string possibly quoted. */
-WORD_DESC *
-command_substitute (string, quoted)
- char *string;
- int quoted;
-{
- pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
- char *istring;
- int result, fildes[2], function_value, pflags, rc, tflag;
- WORD_DESC *ret;
-
- istring = (char *)NULL;
-
- /* Don't fork () if there is no need to. In the case of no command to
- run, just return NULL. */
- if (!string || !*string || (string[0] == '\n' && !string[1]))
- return ((WORD_DESC *)NULL);
-
- if (wordexp_only && read_but_dont_execute)
- {
- last_command_exit_value = EX_WEXPCOMSUB;
- jump_to_top_level (EXITPROG);
- }
-
- /* We're making the assumption here that the command substitution will
- eventually run a command from the file system. Since we'll run
- maybe_make_export_env in this subshell before executing that command,
- the parent shell and any other shells it starts will have to remake
- the environment. If we make it before we fork, other shells won't
- have to. Don't bother if we have any temporary variable assignments,
- though, because the export environment will be remade after this
- command completes anyway, but do it if all the words to be expanded
- are variable assignments. */
- if (subst_assign_varlist == 0 || garglist == 0)
- maybe_make_export_env (); /* XXX */
-
- /* Flags to pass to parse_and_execute() */
- pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
-
- /* Pipe the output of executing STRING into the current shell. */
- if (pipe (fildes) < 0)
- {
- sys_error (_("cannot make pipe for command substitution"));
- goto error_exit;
- }
-
- old_pid = last_made_pid;
-#if defined (JOB_CONTROL)
- old_pipeline_pgrp = pipeline_pgrp;
- /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
- if ((subshell_environment & SUBSHELL_PIPE) == 0)
- pipeline_pgrp = shell_pgrp;
- cleanup_the_pipeline ();
-#endif /* JOB_CONTROL */
-
- old_async_pid = last_asynchronous_pid;
- pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
- last_asynchronous_pid = old_async_pid;
-
- if (pid == 0)
- {
- /* Reset the signal handlers in the child, but don't free the
- trap strings. Set a flag noting that we have to free the
- trap strings if we run trap to change a signal disposition. */
- reset_signal_handlers ();
- subshell_environment |= SUBSHELL_RESETTRAP;
- }
-
-#if defined (JOB_CONTROL)
- /* XXX DO THIS ONLY IN PARENT ? XXX */
- set_sigchld_handler ();
- stop_making_children ();
- if (pid != 0)
- pipeline_pgrp = old_pipeline_pgrp;
-#else
- stop_making_children ();
-#endif /* JOB_CONTROL */
-
- if (pid < 0)
- {
- sys_error (_("cannot make child for command substitution"));
- error_exit:
-
- last_made_pid = old_pid;
-
- FREE (istring);
- close (fildes[0]);
- close (fildes[1]);
- return ((WORD_DESC *)NULL);
- }
-
- if (pid == 0)
- {
- set_sigint_handler (); /* XXX */
-
- free_pushed_string_input ();
-
- if (dup2 (fildes[1], 1) < 0)
- {
- sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
- exit (EXECUTION_FAILURE);
- }
-
- /* If standard output is closed in the parent shell
- (such as after `exec >&-'), file descriptor 1 will be
- the lowest available file descriptor, and end up in
- fildes[0]. This can happen for stdin and stderr as well,
- but stdout is more important -- it will cause no output
- to be generated from this command. */
- if ((fildes[1] != fileno (stdin)) &&
- (fildes[1] != fileno (stdout)) &&
- (fildes[1] != fileno (stderr)))
- close (fildes[1]);
-
- if ((fildes[0] != fileno (stdin)) &&
- (fildes[0] != fileno (stdout)) &&
- (fildes[0] != fileno (stderr)))
- close (fildes[0]);
-
-#ifdef __CYGWIN__
- /* Let stdio know the fd may have changed from text to binary mode, and
- make sure to preserve stdout line buffering. */
- freopen (NULL, "w", stdout);
- sh_setlinebuf (stdout);
-#endif /* __CYGWIN__ */
-
- /* The currently executing shell is not interactive. */
- interactive = 0;
-
- /* This is a subshell environment. */
- subshell_environment |= SUBSHELL_COMSUB;
-
- /* When not in POSIX mode, command substitution does not inherit
- the -e flag. */
- if (posixly_correct == 0)
- exit_immediately_on_error = 0;
-
- remove_quoted_escapes (string);
-
- startup_state = 2; /* see if we can avoid a fork */
- /* Give command substitution a place to jump back to on failure,
- so we don't go back up to main (). */
- result = setjmp (top_level);
-
- /* If we're running a command substitution inside a shell function,
- trap `return' so we don't return from the function in the subshell
- and go off to never-never land. */
- if (result == 0 && return_catch_flag)
- function_value = setjmp (return_catch);
- else
- function_value = 0;
-
- if (result == ERREXIT)
- rc = last_command_exit_value;
- else if (result == EXITPROG)
- rc = last_command_exit_value;
- else if (result)
- rc = EXECUTION_FAILURE;
- else if (function_value)
- rc = return_catch_value;
- else
- {
- subshell_level++;
- rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
- subshell_level--;
- }
-
- last_command_exit_value = rc;
- rc = run_exit_trap ();
-#if defined (PROCESS_SUBSTITUTION)
- unlink_fifo_list ();
-#endif
- exit (rc);
- }
- else
- {
-#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
- close_pgrp_pipe ();
-#endif /* JOB_CONTROL && PGRP_PIPE */
-
- close (fildes[1]);
-
- tflag = 0;
- istring = read_comsub (fildes[0], quoted, &tflag);
-
- close (fildes[0]);
-
- current_command_subst_pid = pid;
- last_command_exit_value = wait_for (pid);
- last_command_subst_pid = pid;
- last_made_pid = old_pid;
-
-#if defined (JOB_CONTROL)
- /* If last_command_exit_value > 128, then the substituted command
- was terminated by a signal. If that signal was SIGINT, then send
- SIGINT to ourselves. This will break out of loops, for instance. */
- if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
- kill (getpid (), SIGINT);
-
- /* wait_for gives the terminal back to shell_pgrp. If some other
- process group should have it, give it away to that group here.
- pipeline_pgrp is non-zero only while we are constructing a
- pipline, so what we are concerned about is whether or not that
- pipeline was started in the background. A pipeline started in
- the background should never get the tty back here. */
- if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
- give_terminal_to (pipeline_pgrp, 0);
-#endif /* JOB_CONTROL */
-
- ret = alloc_word_desc ();
- ret->word = istring;
- ret->flags = tflag;
-
- return ret;
- }
-}
-
-/********************************************************
- * *
- * Utility functions for parameter expansion *
- * *
- ********************************************************/
-
-#if defined (ARRAY_VARS)
-
-static arrayind_t
-array_length_reference (s)
- char *s;
-{
- int len;
- arrayind_t ind;
- char *akey;
- char *t, c;
- ARRAY *array;
- HASH_TABLE *h;
- SHELL_VAR *var;
-
- var = array_variable_part (s, &t, &len);
-
- /* If unbound variables should generate an error, report one and return
- failure. */
- if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
- {
- c = *--t;
- *t = '\0';
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (s);
- *t = c;
- return (-1);
- }
- else if (var == 0)
- return 0;
-
- /* We support a couple of expansions for variables that are not arrays.
- We'll return the length of the value for v[0], and 1 for v[@] or
- v[*]. Return 0 for everything else. */
-
- array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
- h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
-
- if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
- {
- if (assoc_p (var))
- return (h ? assoc_num_elements (h) : 0);
- else if (array_p (var))
- return (array ? array_num_elements (array) : 0);
- else
- return (var_isset (var) ? 1 : 0);
- }
-
- if (assoc_p (var))
- {
- t[len - 1] = '\0';
- akey = expand_assignment_string_to_string (t, 0); /* [ */
- t[len - 1] = ']';
- if (akey == 0 || *akey == 0)
- {
- err_badarraysub (t);
- FREE (akey);
- return (-1);
- }
- t = assoc_reference (assoc_cell (var), akey);
- free (akey);
- }
- else
- {
- ind = array_expand_index (var, t, len);
- /* negative subscripts to indexed arrays count back from end */
- if (var && array_p (var) && ind < 0)
- ind = array_max_index (array_cell (var)) + 1 + ind;
- if (ind < 0)
- {
- err_badarraysub (t);
- return (-1);
- }
- if (array_p (var))
- t = array_reference (array, ind);
- else
- t = (ind == 0) ? value_cell (var) : (char *)NULL;
- }
-
- len = MB_STRLEN (t);
- return (len);
-}
-#endif /* ARRAY_VARS */
-
-static int
-valid_brace_expansion_word (name, var_is_special)
- char *name;
- int var_is_special;
-{
- if (DIGIT (*name) && all_digits (name))
- return 1;
- else if (var_is_special)
- return 1;
-#if defined (ARRAY_VARS)
- else if (valid_array_reference (name))
- return 1;
-#endif /* ARRAY_VARS */
- else if (legal_identifier (name))
- return 1;
- else
- return 0;
-}
-
-static int
-chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
- char *name;
- int quoted;
- int *quoted_dollar_atp, *contains_dollar_at;
-{
- char *temp1;
-
- if (name == 0)
- {
- if (quoted_dollar_atp)
- *quoted_dollar_atp = 0;
- if (contains_dollar_at)
- *contains_dollar_at = 0;
- return 0;
- }
-
- /* check for $@ and $* */
- if (name[0] == '@' && name[1] == 0)
- {
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 1;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
- return 1;
- }
- else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
- {
- if (contains_dollar_at)
- *contains_dollar_at = 1;
- return 1;
- }
-
- /* Now check for ${array[@]} and ${array[*]} */
-#if defined (ARRAY_VARS)
- else if (valid_array_reference (name))
- {
- temp1 = mbschr (name, '[');
- if (temp1 && temp1[1] == '@' && temp1[2] == ']')
- {
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 1;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
- return 1;
- } /* [ */
- /* ${array[*]}, when unquoted, should be treated like ${array[@]},
- which should result in separate words even when IFS is unset. */
- if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
- {
- if (contains_dollar_at)
- *contains_dollar_at = 1;
- return 1;
- }
- }
-#endif
- return 0;
-}
-
-/* Parameter expand NAME, and return a new string which is the expansion,
- or NULL if there was no expansion.
- VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
- the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
- NAME was found inside of a double-quoted expression. */
-static WORD_DESC *
-parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
- char *name;
- int var_is_special, quoted, pflags;
- arrayind_t *indp;
-{
- WORD_DESC *ret;
- char *temp, *tt;
- intmax_t arg_index;
- SHELL_VAR *var;
- int atype, rflags;
- arrayind_t ind;
-
- ret = 0;
- temp = 0;
- rflags = 0;
-
- if (indp)
- *indp = INTMAX_MIN;
-
- /* Handle multiple digit arguments, as in ${11}. */
- if (legal_number (name, &arg_index))
- {
- tt = get_dollar_var_value (arg_index);
- if (tt)
- temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- ? quote_string (tt)
- : quote_escapes (tt);
- else
- temp = (char *)NULL;
- FREE (tt);
- }
- else if (var_is_special) /* ${@} */
- {
- int sindex;
- tt = (char *)xmalloc (2 + strlen (name));
- tt[sindex = 0] = '$';
- strcpy (tt + 1, name);
-
- ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
- (int *)NULL, (int *)NULL, pflags);
- free (tt);
- }
-#if defined (ARRAY_VARS)
- else if (valid_array_reference (name))
- {
-expand_arrayref:
- /* XXX - does this leak if name[@] or name[*]? */
- temp = array_value (name, quoted, 0, &atype, &ind);
- if (atype == 0 && temp)
- {
- temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- ? quote_string (temp)
- : quote_escapes (temp);
- rflags |= W_ARRAYIND;
- if (indp)
- *indp = ind;
- }
- else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- rflags |= W_HASQUOTEDNULL;
- }
-#endif
- else if (var = find_variable (name))
- {
- if (var_isset (var) && invisible_p (var) == 0)
- {
-#if defined (ARRAY_VARS)
- if (assoc_p (var))
- temp = assoc_reference (assoc_cell (var), "0");
- else if (array_p (var))
- temp = array_reference (array_cell (var), 0);
- else
- temp = value_cell (var);
-#else
- temp = value_cell (var);
-#endif
-
- if (temp)
- temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- ? quote_string (temp)
- : quote_escapes (temp);
- }
- else
- temp = (char *)NULL;
- }
-#if defined (ARRAY_VARS)
- /* Handle expanding nameref whose value is x[n] */
- else if (var = find_variable_last_nameref (name))
- {
- temp = nameref_cell (var);
- if (temp && *temp && valid_array_reference (temp))
- {
- name = temp;
- goto expand_arrayref;
- }
- temp = (char *)NULL;
- }
-#endif
- else
- temp = (char *)NULL;
-
- if (ret == 0)
- {
- ret = alloc_word_desc ();
- ret->word = temp;
- ret->flags |= rflags;
- }
- return ret;
-}
-
-/* Expand an indirect reference to a variable: ${!NAME} expands to the
- value of the variable whose name is the value of NAME. */
-static WORD_DESC *
-parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
- char *name;
- int var_is_special, quoted;
- int *quoted_dollar_atp, *contains_dollar_at;
-{
- char *temp, *t;
- WORD_DESC *w;
- SHELL_VAR *v;
-
- /* See if it's a nameref first, behave in ksh93-compatible fashion.
- There is at least one incompatibility: given ${!foo[0]} where foo=bar,
- bash performs an indirect lookup on foo[0] and expands the result;
- ksh93 expands bar[0]. We could do that here -- there are enough usable
- primitives to do that -- but do not at this point. */
- if (var_is_special == 0 && (v = find_variable_last_nameref (name)))
- {
- if (nameref_p (v) && (t = nameref_cell (v)) && *t)
- {
- w = alloc_word_desc ();
- w->word = savestring (t);
- w->flags = 0;
- return w;
- }
- }
-
- w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
- t = w->word;
- /* Have to dequote here if necessary */
- if (t)
- {
- temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- ? dequote_string (t)
- : dequote_escapes (t);
- free (t);
- t = temp;
- }
- dispose_word_desc (w);
-
- chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
- if (t == 0)
- return (WORD_DESC *)NULL;
-
- w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
- free (t);
-
- return w;
-}
-
-/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
- depending on the value of C, the separating character. C can be one of
- "-", "+", or "=". QUOTED is true if the entire brace expression occurs
- between double quotes. */
-static WORD_DESC *
-parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
- char *name, *value;
- int c, quoted, *qdollaratp, *hasdollarat;
-{
- WORD_DESC *w;
- WORD_LIST *l;
- char *t, *t1, *temp;
- int hasdol;
-
- /* If the entire expression is between double quotes, we want to treat
- the value as a double-quoted string, with the exception that we strip
- embedded unescaped double quotes (for sh backwards compatibility). */
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
- {
- hasdol = 0;
- temp = string_extract_double_quoted (value, &hasdol, 1);
- }
- else
- temp = value;
-
- w = alloc_word_desc ();
- hasdol = 0;
- /* XXX was 0 not quoted */
- l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
- : (WORD_LIST *)0;
- if (hasdollarat)
- *hasdollarat = hasdol || (l && l->next);
- if (temp != value)
- free (temp);
- if (l)
- {
- /* The expansion of TEMP returned something. We need to treat things
- slightly differently if HASDOL is non-zero. If we have "$@", the
- individual words have already been quoted. We need to turn them
- into a string with the words separated by the first character of
- $IFS without any additional quoting, so string_list_dollar_at won't
- do the right thing. We use string_list_dollar_star instead. */
- temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
-
- /* If l->next is not null, we know that TEMP contained "$@", since that
- is the only expansion that creates more than one word. */
- if (qdollaratp && ((hasdol && quoted) || l->next))
- *qdollaratp = 1;
- /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
- a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
- flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
- expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- (which is more paranoia than anything else), we need to return the
- quoted null string and set the flags to indicate it. */
- if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
- {
- w->flags |= W_HASQUOTEDNULL;
- }
- dispose_words (l);
- }
- else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
- {
- /* The brace expansion occurred between double quotes and there was
- a $@ in TEMP. It does not matter if the $@ is quoted, as long as
- it does not expand to anything. In this case, we want to return
- a quoted empty string. */
- temp = make_quoted_char ('\0');
- w->flags |= W_HASQUOTEDNULL;
- }
- else
- temp = (char *)NULL;
-
- if (c == '-' || c == '+')
- {
- w->word = temp;
- return w;
- }
-
- /* c == '=' */
- t = temp ? savestring (temp) : savestring ("");
- t1 = dequote_string (t);
- free (t);
-#if defined (ARRAY_VARS)
- if (valid_array_reference (name))
- assign_array_element (name, t1, 0);
- else
-#endif /* ARRAY_VARS */
- bind_variable (name, t1, 0);
-
- /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
- free (temp);
-
- w->word = t1;
- return w;
-}
-
-/* Deal with the right hand side of a ${name:?value} expansion in the case
- that NAME is null or not set. If VALUE is non-null it is expanded and
- used as the error message to print, otherwise a standard message is
- printed. */
-static void
-parameter_brace_expand_error (name, value)
- char *name, *value;
-{
- WORD_LIST *l;
- char *temp;
-
- last_command_exit_value = EXECUTION_FAILURE; /* ensure it's non-zero */
- if (value && *value)
- {
- l = expand_string (value, 0);
- temp = string_list (l);
- report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
- FREE (temp);
- dispose_words (l);
- }
- else
- report_error (_("%s: parameter null or not set"), name);
-
- /* Free the data we have allocated during this expansion, since we
- are about to longjmp out. */
- free (name);
- FREE (value);
-}
-
-/* Return 1 if NAME is something for which parameter_brace_expand_length is
- OK to do. */
-static int
-valid_length_expression (name)
- char *name;
-{
- return (name[1] == '\0' || /* ${#} */
- ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
- (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
-#if defined (ARRAY_VARS)
- valid_array_reference (name + 1) || /* ${#a[7]} */
-#endif
- legal_identifier (name + 1)); /* ${#PS1} */
-}
-
-/* Handle the parameter brace expansion that requires us to return the
- length of a parameter. */
-static intmax_t
-parameter_brace_expand_length (name)
- char *name;
-{
- char *t, *newname;
- intmax_t number, arg_index;
- WORD_LIST *list;
-#if defined (ARRAY_VARS)
- SHELL_VAR *var;
-#endif
-
- if (name[1] == '\0') /* ${#} */
- number = number_of_args ();
- else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */
- number = number_of_args ();
- else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
- {
- /* Take the lengths of some of the shell's special parameters. */
- switch (name[1])
- {
- case '-':
- t = which_set_flags ();
- break;
- case '?':
- t = itos (last_command_exit_value);
- break;
- case '$':
- t = itos (dollar_dollar_pid);
- break;
- case '!':
- if (last_asynchronous_pid == NO_PID)
- t = (char *)NULL; /* XXX - error if set -u set? */
- else
- t = itos (last_asynchronous_pid);
- break;
- case '#':
- t = itos (number_of_args ());
- break;
- }
- number = STRLEN (t);
- FREE (t);
- }
-#if defined (ARRAY_VARS)
- else if (valid_array_reference (name + 1))
- number = array_length_reference (name + 1);
-#endif /* ARRAY_VARS */
- else
- {
- number = 0;
-
- if (legal_number (name + 1, &arg_index)) /* ${#1} */
- {
- t = get_dollar_var_value (arg_index);
- if (t == 0 && unbound_vars_is_error)
- return INTMAX_MIN;
- number = MB_STRLEN (t);
- FREE (t);
- }
-#if defined (ARRAY_VARS)
- else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
- {
- if (assoc_p (var))
- t = assoc_reference (assoc_cell (var), "0");
- else
- t = array_reference (array_cell (var), 0);
- if (t == 0 && unbound_vars_is_error)
- return INTMAX_MIN;
- number = MB_STRLEN (t);
- }
-#endif
- else /* ${#PS1} */
- {
- newname = savestring (name);
- newname[0] = '$';
- list = expand_string (newname, Q_DOUBLE_QUOTES);
- t = list ? string_list (list) : (char *)NULL;
- free (newname);
- if (list)
- dispose_words (list);
-
- number = t ? MB_STRLEN (t) : 0;
- FREE (t);
- }
- }
-
- return (number);
-}
-
-/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
- so we do some ad-hoc parsing of an arithmetic expression to find
- the first DELIM, instead of using strchr(3). Two rules:
- 1. If the substring contains a `(', read until closing `)'.
- 2. If the substring contains a `?', read past one `:' for each `?'.
-*/
-
-static char *
-skiparith (substr, delim)
- char *substr;
- int delim;
-{
- size_t sublen;
- int skipcol, pcount, i;
- DECLARE_MBSTATE;
-
- sublen = strlen (substr);
- i = skipcol = pcount = 0;
- while (substr[i])
- {
- /* Balance parens */
- if (substr[i] == LPAREN)
- {
- pcount++;
- i++;
- continue;
- }
- if (substr[i] == RPAREN && pcount)
- {
- pcount--;
- i++;
- continue;
- }
- if (pcount)
- {
- ADVANCE_CHAR (substr, sublen, i);
- continue;
- }
-
- /* Skip one `:' for each `?' */
- if (substr[i] == ':' && skipcol)
- {
- skipcol--;
- i++;
- continue;
- }
- if (substr[i] == delim)
- break;
- if (substr[i] == '?')
- {
- skipcol++;
- i++;
- continue;
- }
- ADVANCE_CHAR (substr, sublen, i);
- }
-
- return (substr + i);
-}
-
-/* Verify and limit the start and end of the desired substring. If
- VTYPE == 0, a regular shell variable is being used; if it is 1,
- then the positional parameters are being used; if it is 2, then
- VALUE is really a pointer to an array variable that should be used.
- Return value is 1 if both values were OK, 0 if there was a problem
- with an invalid expression, or -1 if the values were out of range. */
-static int
-verify_substring_values (v, value, substr, vtype, e1p, e2p)
- SHELL_VAR *v;
- char *value, *substr;
- int vtype;
- intmax_t *e1p, *e2p;
-{
- char *t, *temp1, *temp2;
- arrayind_t len;
- int expok;
-#if defined (ARRAY_VARS)
- ARRAY *a;
- HASH_TABLE *h;
-#endif
-
- /* duplicate behavior of strchr(3) */
- t = skiparith (substr, ':');
- if (*t && *t == ':')
- *t = '\0';
- else
- t = (char *)0;
-
- temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
- *e1p = evalexp (temp1, &expok);
- free (temp1);
- if (expok == 0)
- return (0);
-
- len = -1; /* paranoia */
- switch (vtype)
- {
- case VT_VARIABLE:
- case VT_ARRAYMEMBER:
- len = MB_STRLEN (value);
- break;
- case VT_POSPARMS:
- len = number_of_args () + 1;
- if (*e1p == 0)
- len++; /* add one arg if counting from $0 */
- break;
-#if defined (ARRAY_VARS)
- case VT_ARRAYVAR:
- /* For arrays, the first value deals with array indices. Negative
- offsets count from one past the array's maximum index. Associative
- arrays treat the number of elements as the maximum index. */
- if (assoc_p (v))
- {
- h = assoc_cell (v);
- len = assoc_num_elements (h) + (*e1p < 0);
- }
- else
- {
- a = (ARRAY *)value;
- len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
- }
- break;
-#endif
- }
-
- if (len == -1) /* paranoia */
- return -1;
-
- if (*e1p < 0) /* negative offsets count from end */
- *e1p += len;
-
- if (*e1p > len || *e1p < 0)
- return (-1);
-
-#if defined (ARRAY_VARS)
- /* For arrays, the second offset deals with the number of elements. */
- if (vtype == VT_ARRAYVAR)
- len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
-#endif
-
- if (t)
- {
- t++;
- temp2 = savestring (t);
- temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
- free (temp2);
- t[-1] = ':';
- *e2p = evalexp (temp1, &expok);
- free (temp1);
- if (expok == 0)
- return (0);
-#if 1
- if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
-#else
- /* bash-4.3: allow positional parameter length < 0 to count backwards
- from end of positional parameters */
- if (vtype == VT_ARRAYVAR && *e2p < 0)
-#endif
- {
- internal_error (_("%s: substring expression < 0"), t);
- return (0);
- }
-#if defined (ARRAY_VARS)
- /* In order to deal with sparse arrays, push the intelligence about how
- to deal with the number of elements desired down to the array-
- specific functions. */
- if (vtype != VT_ARRAYVAR)
-#endif
- {
- if (*e2p < 0)
- {
- *e2p += len;
- if (*e2p < 0 || *e2p < *e1p)
- {
- internal_error (_("%s: substring expression < 0"), t);
- return (0);
- }
- }
- else
- *e2p += *e1p; /* want E2 chars starting at E1 */
- if (*e2p > len)
- *e2p = len;
- }
- }
- else
- *e2p = len;
-
- return (1);
-}
-
-/* Return the type of variable specified by VARNAME (simple variable,
- positional param, or array variable). Also return the value specified
- by VARNAME (value of a variable or a reference to an array element).
- QUOTED is the standard description of quoting state, using Q_* defines.
- FLAGS is currently a set of flags to pass to array_value. If IND is
- non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
- passed to array_value so the array index is not computed again.
- If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
- characters in the value are quoted with CTLESC and takes appropriate
- steps. For convenience, *VALP is set to the dequoted VALUE. */
-static int
-get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
- char *varname, *value;
- arrayind_t ind;
- int quoted, flags;
- SHELL_VAR **varp;
- char **valp;
-{
- int vtype;
- char *temp;
-#if defined (ARRAY_VARS)
- SHELL_VAR *v;
-#endif
- arrayind_t lind;
-
- /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
- vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
- if (vtype == VT_POSPARMS && varname[0] == '*')
- vtype |= VT_STARSUB;
- *varp = (SHELL_VAR *)NULL;
-
-#if defined (ARRAY_VARS)
- if (valid_array_reference (varname))
- {
- v = array_variable_part (varname, &temp, (int *)0);
- /* If we want to signal array_value to use an already-computed index,
- set LIND to that index */
- lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
- if (v && (array_p (v) || assoc_p (v)))
- { /* [ */
- if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
- {
- /* Callers have to differentiate betwen indexed and associative */
- vtype = VT_ARRAYVAR;
- if (temp[0] == '*')
- vtype |= VT_STARSUB;
- *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
- }
- else
- {
- vtype = VT_ARRAYMEMBER;
- *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
- }
- *varp = v;
- }
- else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
- {
- vtype = VT_VARIABLE;
- *varp = v;
- if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- *valp = dequote_string (value);
- else
- *valp = dequote_escapes (value);
- }
- else
- {
- vtype = VT_ARRAYMEMBER;
- *varp = v;
- *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
- }
- }
- else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
- {
- vtype = VT_ARRAYMEMBER;
- *varp = v;
- *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
- }
- else
-#endif
- {
- if (value && vtype == VT_VARIABLE)
- {
- if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- *valp = dequote_string (value);
- else
- *valp = dequote_escapes (value);
- }
- else
- *valp = value;
- }
-
- return vtype;
-}
-
-/******************************************************/
-/* */
-/* Functions to extract substrings of variable values */
-/* */
-/******************************************************/
-
-#if defined (HANDLE_MULTIBYTE)
-/* Character-oriented rather than strictly byte-oriented substrings. S and
- E, rather being strict indices into STRING, indicate character (possibly
- multibyte character) positions that require calculation.
- Used by the ${param:offset[:length]} expansion. */
-static char *
-mb_substring (string, s, e)
- char *string;
- int s, e;
-{
- char *tt;
- int start, stop, i, slen;
- DECLARE_MBSTATE;
-
- start = 0;
- /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
- slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
-
- i = s;
- while (string[start] && i--)
- ADVANCE_CHAR (string, slen, start);
- stop = start;
- i = e - s;
- while (string[stop] && i--)
- ADVANCE_CHAR (string, slen, stop);
- tt = substring (string, start, stop);
- return tt;
-}
-#endif
-
-/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
- is `@', use the positional parameters; otherwise, use the value of
- VARNAME. If VARNAME is an array variable, use the array elements. */
-
-static char *
-parameter_brace_substring (varname, value, ind, substr, quoted, flags)
- char *varname, *value;
- int ind;
- char *substr;
- int quoted, flags;
-{
- intmax_t e1, e2;
- int vtype, r, starsub;
- char *temp, *val, *tt, *oname;
- SHELL_VAR *v;
-
- if (value == 0)
- return ((char *)NULL);
-
- oname = this_command_name;
- this_command_name = varname;
-
- vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
- if (vtype == -1)
- {
- this_command_name = oname;
- return ((char *)NULL);
- }
-
- starsub = vtype & VT_STARSUB;
- vtype &= ~VT_STARSUB;
-
- r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
- this_command_name = oname;
- if (r <= 0)
- {
- if (vtype == VT_VARIABLE)
- FREE (val);
- return ((r == 0) ? &expand_param_error : (char *)NULL);
- }
-
- switch (vtype)
- {
- case VT_VARIABLE:
- case VT_ARRAYMEMBER:
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1)
- tt = mb_substring (val, e1, e2);
- else
-#endif
- tt = substring (val, e1, e2);
-
- if (vtype == VT_VARIABLE)
- FREE (val);
- if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- temp = quote_string (tt);
- else
- temp = tt ? quote_escapes (tt) : (char *)NULL;
- FREE (tt);
- break;
- case VT_POSPARMS:
- tt = pos_params (varname, e1, e2, quoted);
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
- {
- temp = tt ? quote_escapes (tt) : (char *)NULL;
- FREE (tt);
- }
- else
- temp = tt;
- break;
-#if defined (ARRAY_VARS)
- case VT_ARRAYVAR:
- if (assoc_p (v))
- /* we convert to list and take first e2 elements starting at e1th
- element -- officially undefined for now */
- temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
- else
- /* We want E2 to be the number of elements desired (arrays can be sparse,
- so verify_substring_values just returns the numbers specified and we
- rely on array_subrange to understand how to deal with them). */
- temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
- /* array_subrange now calls array_quote_escapes as appropriate, so the
- caller no longer needs to. */
- break;
-#endif
- default:
- temp = (char *)NULL;
- }
-
- return temp;
-}
-
-/****************************************************************/
-/* */
-/* Functions to perform pattern substitution on variable values */
-/* */
-/****************************************************************/
-
-static int
-shouldexp_replacement (s)
- char *s;
-{
- register char *p;
-
- for (p = s; p && *p; p++)
- {
- if (*p == '\\')
- p++;
- else if (*p == '&')
- return 1;
- }
- return 0;
-}
-
-char *
-pat_subst (string, pat, rep, mflags)
- char *string, *pat, *rep;
- int mflags;
-{
- char *ret, *s, *e, *str, *rstr, *mstr;
- int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
-
- if (string == 0)
- return (savestring (""));
-
- mtype = mflags & MATCH_TYPEMASK;
-
-#if 0 /* bash-4.2 ? */
- rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
-#else
- rxpand = 0;
-#endif
-
- /* Special cases:
- * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
- * with REP and return the result.
- * 2. A null pattern with mtype == MATCH_END means to append REP to
- * STRING and return the result.
- * These don't understand or process `&' in the replacement string.
- */
- if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
- {
- replen = STRLEN (rep);
- l = STRLEN (string);
- ret = (char *)xmalloc (replen + l + 2);
- if (replen == 0)
- strcpy (ret, string);
- else if (mtype == MATCH_BEG)
- {
- strcpy (ret, rep);
- strcpy (ret + replen, string);
- }
- else
- {
- strcpy (ret, string);
- strcpy (ret + l, rep);
- }
- return (ret);
- }
-
- ret = (char *)xmalloc (rsize = 64);
- ret[0] = '\0';
-
- for (replen = STRLEN (rep), rptr = 0, str = string;;)
- {
- if (match_pattern (str, pat, mtype, &s, &e) == 0)
- break;
- l = s - str;
-
- if (rxpand)
- {
- int x;
- mlen = e - s;
- mstr = xmalloc (mlen + 1);
- for (x = 0; x < mlen; x++)
- mstr[x] = s[x];
- mstr[mlen] = '\0';
- rstr = strcreplace (rep, '&', mstr, 0);
- rslen = strlen (rstr);
- }
- else
- {
- rstr = rep;
- rslen = replen;
- }
-
- RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
-
- /* OK, now copy the leading unmatched portion of the string (from
- str to s) to ret starting at rptr (the current offset). Then copy
- the replacement string at ret + rptr + (s - str). Increment
- rptr (if necessary) and str and go on. */
- if (l)
- {
- strncpy (ret + rptr, str, l);
- rptr += l;
- }
- if (replen)
- {
- strncpy (ret + rptr, rstr, rslen);
- rptr += rslen;
- }
- str = e; /* e == end of match */
-
- if (rstr != rep)
- free (rstr);
-
- if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
- break;
-
- if (s == e)
- {
- /* On a zero-length match, make sure we copy one character, since
- we increment one character to avoid infinite recursion. */
- RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
- ret[rptr++] = *str++;
- e++; /* avoid infinite recursion on zero-length match */
- }
- }
-
- /* Now copy the unmatched portion of the input string */
- if (str && *str)
- {
- RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
- strcpy (ret + rptr, str);
- }
- else
- ret[rptr] = '\0';
-
- return ret;
-}
-
-/* Do pattern match and replacement on the positional parameters. */
-static char *
-pos_params_pat_subst (string, pat, rep, mflags)
- char *string, *pat, *rep;
- int mflags;
-{
- WORD_LIST *save, *params;
- WORD_DESC *w;
- char *ret;
- int pchar, qflags;
-
- save = params = list_rest_of_args ();
- if (save == 0)
- return ((char *)NULL);
-
- for ( ; params; params = params->next)
- {
- ret = pat_subst (params->word->word, pat, rep, mflags);
- w = alloc_word_desc ();
- w->word = ret ? ret : savestring ("");
- dispose_word (params->word);
- params->word = w;
- }
-
- pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
- qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
-
-#if 0
- if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
- ret = string_list_dollar_star (quote_list (save));
- else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
- ret = string_list_dollar_star (save);
- else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
- ret = string_list_dollar_at (save, qflags);
- else
- ret = string_list_dollar_star (save);
-#else
- ret = string_list_pos_params (pchar, save, qflags);
-#endif
-
- dispose_words (save);
-
- return (ret);
-}
-
-/* Perform pattern substitution on VALUE, which is the expansion of
- VARNAME. PATSUB is an expression supplying the pattern to match
- and the string to substitute. QUOTED is a flags word containing
- the type of quoting currently in effect. */
-static char *
-parameter_brace_patsub (varname, value, ind, patsub, quoted, flags)
- char *varname, *value;
- int ind;
- char *patsub;
- int quoted, flags;
-{
- int vtype, mflags, starsub, delim;
- char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
- SHELL_VAR *v;
-
- if (value == 0)
- return ((char *)NULL);
-
- this_command_name = varname;
-
- vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
- if (vtype == -1)
- return ((char *)NULL);
-
- starsub = vtype & VT_STARSUB;
- vtype &= ~VT_STARSUB;
-
- mflags = 0;
- /* PATSUB is never NULL when this is called. */
- if (*patsub == '/')
- {
- mflags |= MATCH_GLOBREP;
- patsub++;
- }
-
- /* Malloc this because expand_string_if_necessary or one of the expansion
- functions in its call chain may free it on a substitution error. */
- lpatsub = savestring (patsub);
-
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- mflags |= MATCH_QUOTED;
-
- if (starsub)
- mflags |= MATCH_STARSUB;
-
- /* If the pattern starts with a `/', make sure we skip over it when looking
- for the replacement delimiter. */
- delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
- if (lpatsub[delim] == '/')
- {
- lpatsub[delim] = 0;
- rep = lpatsub + delim + 1;
- }
- else
- rep = (char *)NULL;
-
- if (rep && *rep == '\0')
- rep = (char *)NULL;
-
- /* Perform the same expansions on the pattern as performed by the
- pattern removal expansions. */
- pat = getpattern (lpatsub, quoted, 1);
-
- if (rep)
- /* We want to perform quote removal on the expanded replacement even if
- the entire expansion is double-quoted because the parser and string
- extraction functions treated quotes in the replacement string as
- special. */
- rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
-
- /* ksh93 doesn't allow the match specifier to be a part of the expanded
- pattern. This is an extension. Make sure we don't anchor the pattern
- at the beginning or end of the string if we're doing global replacement,
- though. */
- p = pat;
- if (mflags & MATCH_GLOBREP)
- mflags |= MATCH_ANY;
- else if (pat && pat[0] == '#')
- {
- mflags |= MATCH_BEG;
- p++;
- }
- else if (pat && pat[0] == '%')
- {
- mflags |= MATCH_END;
- p++;
- }
- else
- mflags |= MATCH_ANY;
-
- /* OK, we now want to substitute REP for PAT in VAL. If
- flags & MATCH_GLOBREP is non-zero, the substitution is done
- everywhere, otherwise only the first occurrence of PAT is
- replaced. The pattern matching code doesn't understand
- CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
- values passed in (VT_VARIABLE) so the pattern substitution
- code works right. We need to requote special chars after
- we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
- other cases if QUOTED == 0, since the posparams and arrays
- indexed by * or @ do special things when QUOTED != 0. */
-
- switch (vtype)
- {
- case VT_VARIABLE:
- case VT_ARRAYMEMBER:
- temp = pat_subst (val, p, rep, mflags);
- if (vtype == VT_VARIABLE)
- FREE (val);
- if (temp)
- {
- tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
- free (temp);
- temp = tt;
- }
- break;
- case VT_POSPARMS:
- temp = pos_params_pat_subst (val, p, rep, mflags);
- if (temp && (mflags & MATCH_QUOTED) == 0)
- {
- tt = quote_escapes (temp);
- free (temp);
- temp = tt;
- }
- break;
-#if defined (ARRAY_VARS)
- case VT_ARRAYVAR:
- temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
- : array_patsub (array_cell (v), p, rep, mflags);
- /* Don't call quote_escapes anymore; array_patsub calls
- array_quote_escapes as appropriate before adding the
- space separators; ditto for assoc_patsub. */
- break;
-#endif
- }
-
- FREE (pat);
- FREE (rep);
- free (lpatsub);
-
- return temp;
-}
-
-/****************************************************************/
-/* */
-/* Functions to perform case modification on variable values */
-/* */
-/****************************************************************/
-
-/* Do case modification on the positional parameters. */
-
-static char *
-pos_params_modcase (string, pat, modop, mflags)
- char *string, *pat;
- int modop;
- int mflags;
-{
- WORD_LIST *save, *params;
- WORD_DESC *w;
- char *ret;
- int pchar, qflags;
-
- save = params = list_rest_of_args ();
- if (save == 0)
- return ((char *)NULL);
-
- for ( ; params; params = params->next)
- {
- ret = sh_modcase (params->word->word, pat, modop);
- w = alloc_word_desc ();
- w->word = ret ? ret : savestring ("");
- dispose_word (params->word);
- params->word = w;
- }
-
- pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
- qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
-
- ret = string_list_pos_params (pchar, save, qflags);
- dispose_words (save);
-
- return (ret);
-}
-
-/* Perform case modification on VALUE, which is the expansion of
- VARNAME. MODSPEC is an expression supplying the type of modification
- to perform. QUOTED is a flags word containing the type of quoting
- currently in effect. */
-static char *
-parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags)
- char *varname, *value;
- int ind, modspec;
- char *patspec;
- int quoted, flags;
-{
- int vtype, starsub, modop, mflags, x;
- char *val, *temp, *pat, *p, *lpat, *tt;
- SHELL_VAR *v;
-
- if (value == 0)
- return ((char *)NULL);
-
- this_command_name = varname;
-
- vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
- if (vtype == -1)
- return ((char *)NULL);
-
- starsub = vtype & VT_STARSUB;
- vtype &= ~VT_STARSUB;
-
- modop = 0;
- mflags = 0;
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- mflags |= MATCH_QUOTED;
- if (starsub)
- mflags |= MATCH_STARSUB;
-
- p = patspec;
- if (modspec == '^')
- {
- x = p && p[0] == modspec;
- modop = x ? CASE_UPPER : CASE_UPFIRST;
- p += x;
- }
- else if (modspec == ',')
- {
- x = p && p[0] == modspec;
- modop = x ? CASE_LOWER : CASE_LOWFIRST;
- p += x;
- }
- else if (modspec == '~')
- {
- x = p && p[0] == modspec;
- modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
- p += x;
- }
-
- lpat = p ? savestring (p) : 0;
- /* Perform the same expansions on the pattern as performed by the
- pattern removal expansions. FOR LATER */
- pat = lpat ? getpattern (lpat, quoted, 1) : 0;
-
- /* OK, now we do the case modification. */
- switch (vtype)
- {
- case VT_VARIABLE:
- case VT_ARRAYMEMBER:
- temp = sh_modcase (val, pat, modop);
- if (vtype == VT_VARIABLE)
- FREE (val);
- if (temp)
- {
- tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
- free (temp);
- temp = tt;
- }
- break;
-
- case VT_POSPARMS:
- temp = pos_params_modcase (val, pat, modop, mflags);
- if (temp && (mflags & MATCH_QUOTED) == 0)
- {
- tt = quote_escapes (temp);
- free (temp);
- temp = tt;
- }
- break;
-
-#if defined (ARRAY_VARS)
- case VT_ARRAYVAR:
- temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
- : array_modcase (array_cell (v), pat, modop, mflags);
- /* Don't call quote_escapes; array_modcase calls array_quote_escapes
- as appropriate before adding the space separators; ditto for
- assoc_modcase. */
- break;
-#endif
- }
-
- FREE (pat);
- free (lpat);
-
- return temp;
-}
-
-/* Check for unbalanced parens in S, which is the contents of $(( ... )). If
- any occur, this must be a nested command substitution, so return 0.
- Otherwise, return 1. A valid arithmetic expression must always have a
- ( before a matching ), so any cases where there are more right parens
- means that this must not be an arithmetic expression, though the parser
- will not accept it without a balanced total number of parens. */
-static int
-chk_arithsub (s, len)
- const char *s;
- int len;
-{
- int i, count;
- DECLARE_MBSTATE;
-
- i = count = 0;
- while (i < len)
- {
- if (s[i] == LPAREN)
- count++;
- else if (s[i] == RPAREN)
- {
- count--;
- if (count < 0)
- return 0;
- }
-
- switch (s[i])
- {
- default:
- ADVANCE_CHAR (s, len, i);
- break;
-
- case '\\':
- i++;
- if (s[i])
- ADVANCE_CHAR (s, len, i);
- break;
-
- case '\'':
- i = skip_single_quoted (s, len, ++i);
- break;
-
- case '"':
- i = skip_double_quoted ((char *)s, len, ++i);
- break;
- }
- }
-
- return (count == 0);
-}
-
-/****************************************************************/
-/* */
-/* Functions to perform parameter expansion on a string */
-/* */
-/****************************************************************/
-
-/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
-static WORD_DESC *
-parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
- char *string;
- int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
-{
- int check_nullness, var_is_set, var_is_null, var_is_special;
- int want_substring, want_indir, want_patsub, want_casemod;
- char *name, *value, *temp, *temp1;
- WORD_DESC *tdesc, *ret;
- int t_index, sindex, c, tflag, modspec;
- intmax_t number;
- arrayind_t ind;
-
- temp = temp1 = value = (char *)NULL;
- var_is_set = var_is_null = var_is_special = check_nullness = 0;
- want_substring = want_indir = want_patsub = want_casemod = 0;
-
- sindex = *indexp;
- t_index = ++sindex;
- /* ${#var} doesn't have any of the other parameter expansions on it. */
- if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
- name = string_extract (string, &t_index, "}", SX_VARNAME);
- else
-#if defined (CASEMOD_EXPANSIONS)
- /* To enable case-toggling expansions using the `~' operator character
- change the 1 to 0. */
-# if defined (CASEMOD_CAPCASE)
- name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
-# else
- name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
-# endif /* CASEMOD_CAPCASE */
-#else
- name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
-#endif /* CASEMOD_EXPANSIONS */
-
- ret = 0;
- tflag = 0;
-
- ind = INTMAX_MIN;
-
- /* If the name really consists of a special variable, then make sure
- that we have the entire name. We don't allow indirect references
- to special variables except `#', `?', `@' and `*'. */
- if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
- (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
- {
- t_index++;
- temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
- name = (char *)xrealloc (name, 3 + (strlen (temp1)));
- *name = string[sindex];
- if (string[sindex] == '!')
- {
- /* indirect reference of $#, $?, $@, or $* */
- name[1] = string[sindex + 1];
- strcpy (name + 2, temp1);
- }
- else
- strcpy (name + 1, temp1);
- free (temp1);
- }
- sindex = t_index;
-
- /* Find out what character ended the variable name. Then
- do the appropriate thing. */
- if (c = string[sindex])
- sindex++;
-
- /* If c is followed by one of the valid parameter expansion
- characters, move past it as normal. If not, assume that
- a substring specification is being given, and do not move
- past it. */
- if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
- {
- check_nullness++;
- if (c = string[sindex])
- sindex++;
- }
- else if (c == ':' && string[sindex] != RBRACE)
- want_substring = 1;
- else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
- want_patsub = 1;
-#if defined (CASEMOD_EXPANSIONS)
- else if (c == '^' || c == ',' || c == '~')
- {
- modspec = c;
- want_casemod = 1;
- }
-#endif
-
- /* Catch the valid and invalid brace expressions that made it through the
- tests above. */
- /* ${#-} is a valid expansion and means to take the length of $-.
- Similarly for ${#?} and ${##}... */
- if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
- VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
- {
- name = (char *)xrealloc (name, 3);
- name[1] = c;
- name[2] = '\0';
- c = string[sindex++];
- }
-
- /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
- if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
- member (c, "%:=+/") && string[sindex] == RBRACE)
- {
- temp = (char *)NULL;
- goto bad_substitution;
- }
-
- /* Indirect expansion begins with a `!'. A valid indirect expansion is
- either a variable name, one of the positional parameters or a special
- variable that expands to one of the positional parameters. */
- want_indir = *name == '!' &&
- (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
- || VALID_INDIR_PARAM (name[1]));
-
- /* Determine the value of this variable. */
-
- /* Check for special variables, directly referenced. */
- if (SPECIAL_VAR (name, want_indir))
- var_is_special++;
-
- /* Check for special expansion things, like the length of a parameter */
- if (*name == '#' && name[1])
- {
- /* If we are not pointing at the character just after the
- closing brace, then we haven't gotten all of the name.
- Since it begins with a special character, this is a bad
- substitution. Also check NAME for validity before trying
- to go on. */
- if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
- {
- temp = (char *)NULL;
- goto bad_substitution;
- }
-
- number = parameter_brace_expand_length (name);
- if (number == INTMAX_MIN && unbound_vars_is_error)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (name+1);
- free (name);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
- free (name);
-
- *indexp = sindex;
- if (number < 0)
- return (&expand_wdesc_error);
- else
- {
- ret = alloc_word_desc ();
- ret->word = itos (number);
- return ret;
- }
- }
-
- /* ${@} is identical to $@. */
- if (name[0] == '@' && name[1] == '\0')
- {
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 1;
-
- if (contains_dollar_at)
- *contains_dollar_at = 1;
-
- tflag |= W_DOLLARAT;
- }
-
- /* Process ${!PREFIX*} expansion. */
- if (want_indir && string[sindex - 1] == RBRACE &&
- (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
- legal_variable_starter ((unsigned char) name[1]))
- {
- char **x;
- WORD_LIST *xlist;
-
- temp1 = savestring (name + 1);
- number = strlen (temp1);
- temp1[number - 1] = '\0';
- x = all_variables_matching_prefix (temp1);
- xlist = strvec_to_word_list (x, 0, 0);
- if (string[sindex - 2] == '*')
- temp = string_list_dollar_star (xlist);
- else
- {
- temp = string_list_dollar_at (xlist, quoted);
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 1;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
-
- tflag |= W_DOLLARAT;
- }
- free (x);
- dispose_words (xlist);
- free (temp1);
- *indexp = sindex;
-
- free (name);
-
- ret = alloc_word_desc ();
- ret->word = temp;
- ret->flags = tflag; /* XXX */
- return ret;
- }
-
-#if defined (ARRAY_VARS)
- /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
- if (want_indir && string[sindex - 1] == RBRACE &&
- string[sindex - 2] == ']' && valid_array_reference (name+1))
- {
- char *x, *x1;
-
- temp1 = savestring (name + 1);
- x = array_variable_name (temp1, &x1, (int *)0); /* [ */
- FREE (x);
- if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
- {
- temp = array_keys (temp1, quoted); /* handles assoc vars too */
- if (x1[0] == '@')
- {
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 1;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
-
- tflag |= W_DOLLARAT;
- }
-
- free (temp1);
- *indexp = sindex;
-
- ret = alloc_word_desc ();
- ret->word = temp;
- ret->flags = tflag; /* XXX */
- return ret;
- }
-
- free (temp1);
- }
-#endif /* ARRAY_VARS */
-
- /* Make sure that NAME is valid before trying to go on. */
- if (valid_brace_expansion_word (want_indir ? name + 1 : name,
- var_is_special) == 0)
- {
- temp = (char *)NULL;
- goto bad_substitution;
- }
-
- if (want_indir)
- tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
- else
- tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind);
-
- if (tdesc)
- {
- temp = tdesc->word;
- tflag = tdesc->flags;
- dispose_word_desc (tdesc);
- }
- else
- temp = (char *)0;
-
-#if defined (ARRAY_VARS)
- if (valid_array_reference (name))
- chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
-#endif
-
- var_is_set = temp != (char *)0;
- var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
-
- /* Get the rest of the stuff inside the braces. */
- if (c && c != RBRACE)
- {
- /* Extract the contents of the ${ ... } expansion
- according to the Posix.2 rules. */
- value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
- if (string[sindex] == RBRACE)
- sindex++;
- else
- goto bad_substitution;
- }
- else
- value = (char *)NULL;
-
- *indexp = sindex;
-
- /* All the cases where an expansion can possibly generate an unbound
- variable error. */
- if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
- {
- if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
- {
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (name);
- FREE (value);
- FREE (temp);
- free (name);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
- }
-
- /* If this is a substring spec, process it and add the result. */
- if (want_substring)
- {
- temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
- FREE (name);
- FREE (value);
- FREE (temp);
-
- if (temp1 == &expand_param_error)
- return (&expand_wdesc_error);
- else if (temp1 == &expand_param_fatal)
- return (&expand_wdesc_fatal);
-
- ret = alloc_word_desc ();
- ret->word = temp1;
- if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
- return ret;
- }
- else if (want_patsub)
- {
- temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
- FREE (name);
- FREE (value);
- FREE (temp);
-
- if (temp1 == &expand_param_error)
- return (&expand_wdesc_error);
- else if (temp1 == &expand_param_fatal)
- return (&expand_wdesc_fatal);
-
- ret = alloc_word_desc ();
- ret->word = temp1;
- if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
- return ret;
- }
-#if defined (CASEMOD_EXPANSIONS)
- else if (want_casemod)
- {
- temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
- FREE (name);
- FREE (value);
- FREE (temp);
-
- if (temp1 == &expand_param_error)
- return (&expand_wdesc_error);
- else if (temp1 == &expand_param_fatal)
- return (&expand_wdesc_fatal);
-
- ret = alloc_word_desc ();
- ret->word = temp1;
- if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
- return ret;
- }
-#endif
-
- /* Do the right thing based on which character ended the variable name. */
- switch (c)
- {
- default:
- case '\0':
- bad_substitution:
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("%s: bad substitution"), string ? string : "??");
- FREE (value);
- FREE (temp);
- free (name);
- return &expand_wdesc_error;
-
- case RBRACE:
- break;
-
- case '#': /* ${param#[#]pattern} */
- case '%': /* ${param%[%]pattern} */
- if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
- {
- FREE (value);
- break;
- }
- temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
- free (temp);
- free (value);
- free (name);
-
- ret = alloc_word_desc ();
- ret->word = temp1;
- if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
- return ret;
-
- case '-':
- case '=':
- case '?':
- case '+':
- if (var_is_set && var_is_null == 0)
- {
- /* If the operator is `+', we don't want the value of the named
- variable for anything, just the value of the right hand side. */
- if (c == '+')
- {
- /* XXX -- if we're double-quoted and the named variable is "$@",
- we want to turn off any special handling of "$@" --
- we're not using it, so whatever is on the rhs applies. */
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 0;
- if (contains_dollar_at)
- *contains_dollar_at = 0;
-
- FREE (temp);
- if (value)
- {
- /* From Posix discussion on austin-group list. Issue 221
- requires that backslashes escaping `}' inside
- double-quoted ${...} be removed. */
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- quoted |= Q_DOLBRACE;
- ret = parameter_brace_expand_rhs (name, value, c,
- quoted,
- quoted_dollar_atp,
- contains_dollar_at);
- /* XXX - fix up later, esp. noting presence of
- W_HASQUOTEDNULL in ret->flags */
- free (value);
- }
- else
- temp = (char *)NULL;
- }
- else
- {
- FREE (value);
- }
- /* Otherwise do nothing; just use the value in TEMP. */
- }
- else /* VAR not set or VAR is NULL. */
- {
- FREE (temp);
- temp = (char *)NULL;
- if (c == '=' && var_is_special)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("$%s: cannot assign in this way"), name);
- free (name);
- free (value);
- return &expand_wdesc_error;
- }
- else if (c == '?')
- {
- parameter_brace_expand_error (name, value);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
- else if (c != '+')
- {
- /* XXX -- if we're double-quoted and the named variable is "$@",
- we want to turn off any special handling of "$@" --
- we're not using it, so whatever is on the rhs applies. */
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
- *quoted_dollar_atp = 0;
- if (contains_dollar_at)
- *contains_dollar_at = 0;
-
- /* From Posix discussion on austin-group list. Issue 221 requires
- that backslashes escaping `}' inside double-quoted ${...} be
- removed. */
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- quoted |= Q_DOLBRACE;
- ret = parameter_brace_expand_rhs (name, value, c, quoted,
- quoted_dollar_atp,
- contains_dollar_at);
- /* XXX - fix up later, esp. noting presence of
- W_HASQUOTEDNULL in tdesc->flags */
- }
- free (value);
- }
-
- break;
- }
- free (name);
-
- if (ret == 0)
- {
- ret = alloc_word_desc ();
- ret->flags = tflag;
- ret->word = temp;
- }
- return (ret);
-}
-
-/* Expand a single ${xxx} expansion. The braces are optional. When
- the braces are used, parameter_brace_expand() does the work,
- possibly calling param_expand recursively. */
-static WORD_DESC *
-param_expand (string, sindex, quoted, expanded_something,
- contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
- pflags)
- char *string;
- int *sindex, quoted, *expanded_something, *contains_dollar_at;
- int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
-{
- char *temp, *temp1, uerror[3];
- int zindex, t_index, expok;
- unsigned char c;
- intmax_t number;
- SHELL_VAR *var;
- WORD_LIST *list;
- WORD_DESC *tdesc, *ret;
- int tflag;
-
- zindex = *sindex;
- c = string[++zindex];
-
- temp = (char *)NULL;
- ret = tdesc = (WORD_DESC *)NULL;
- tflag = 0;
-
- /* Do simple cases first. Switch on what follows '$'. */
- switch (c)
- {
- /* $0 .. $9? */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- temp1 = dollar_vars[TODIGIT (c)];
- if (unbound_vars_is_error && temp1 == (char *)NULL)
- {
- uerror[0] = '$';
- uerror[1] = c;
- uerror[2] = '\0';
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (uerror);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
- if (temp1)
- temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ? quote_string (temp1)
- : quote_escapes (temp1);
- else
- temp = (char *)NULL;
-
- break;
-
- /* $$ -- pid of the invoking shell. */
- case '$':
- temp = itos (dollar_dollar_pid);
- break;
-
- /* $# -- number of positional parameters. */
- case '#':
- temp = itos (number_of_args ());
- break;
-
- /* $? -- return value of the last synchronous command. */
- case '?':
- temp = itos (last_command_exit_value);
- break;
-
- /* $- -- flags supplied to the shell on invocation or by `set'. */
- case '-':
- temp = which_set_flags ();
- break;
-
- /* $! -- Pid of the last asynchronous command. */
- case '!':
- /* If no asynchronous pids have been created, expand to nothing.
- If `set -u' has been executed, and no async processes have
- been created, this is an expansion error. */
- if (last_asynchronous_pid == NO_PID)
- {
- if (expanded_something)
- *expanded_something = 0;
- temp = (char *)NULL;
- if (unbound_vars_is_error)
- {
- uerror[0] = '$';
- uerror[1] = c;
- uerror[2] = '\0';
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (uerror);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
- }
- else
- temp = itos (last_asynchronous_pid);
- break;
-
- /* The only difference between this and $@ is when the arg is quoted. */
- case '*': /* `$*' */
- list = list_rest_of_args ();
-
-#if 0
- /* According to austin-group posix proposal by Geoff Clare in
- <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
-
- "The shell shall write a message to standard error and
- immediately exit when it tries to expand an unset parameter
- other than the '@' and '*' special parameters."
- */
-
- if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
- {
- uerror[0] = '$';
- uerror[1] = '*';
- uerror[2] = '\0';
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (uerror);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
-#endif
-
- /* If there are no command-line arguments, this should just
- disappear if there are other characters in the expansion,
- even if it's quoted. */
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
- temp = (char *)NULL;
- else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
- {
- /* If we have "$*" we want to make a string of the positional
- parameters, separated by the first character of $IFS, and
- quote the whole string, including the separators. If IFS
- is unset, the parameters are separated by ' '; if $IFS is
- null, the parameters are concatenated. */
- temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
- if (temp)
- {
- temp1 = quote_string (temp);
- if (*temp == 0)
- tflag |= W_HASQUOTEDNULL;
- free (temp);
- temp = temp1;
- }
- }
- else
- {
- /* We check whether or not we're eventually going to split $* here,
- for example when IFS is empty and we are processing the rhs of
- an assignment statement. In that case, we don't separate the
- arguments at all. Otherwise, if the $* is not quoted it is
- identical to $@ */
-#if 1
-# if defined (HANDLE_MULTIBYTE)
- if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
-# else
- if (expand_no_split_dollar_star && ifs_firstc == 0)
-# endif
- temp = string_list_dollar_star (list);
- else
- temp = string_list_dollar_at (list, quoted);
-#else
- temp = string_list_dollar_at (list, quoted);
-#endif
- if (expand_no_split_dollar_star == 0 && contains_dollar_at)
- *contains_dollar_at = 1;
- }
-
- dispose_words (list);
- break;
-
- /* When we have "$@" what we want is "$1" "$2" "$3" ... This
- means that we have to turn quoting off after we split into
- the individually quoted arguments so that the final split
- on the first character of $IFS is still done. */
- case '@': /* `$@' */
- list = list_rest_of_args ();
-
-#if 0
- /* According to austin-group posix proposal by Geoff Clare in
- <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
-
- "The shell shall write a message to standard error and
- immediately exit when it tries to expand an unset parameter
- other than the '@' and '*' special parameters."
- */
-
- if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
- {
- uerror[0] = '$';
- uerror[1] = '@';
- uerror[2] = '\0';
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (uerror);
- return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
-#endif
-
- /* We want to flag the fact that we saw this. We can't turn
- off quoting entirely, because other characters in the
- string might need it (consider "\"$@\""), but we need some
- way to signal that the final split on the first character
- of $IFS should be done, even though QUOTED is 1. */
- /* XXX - should this test include Q_PATQUOTE? */
- if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- *quoted_dollar_at_p = 1;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
-
- /* We want to separate the positional parameters with the first
- character of $IFS in case $IFS is something other than a space.
- We also want to make sure that splitting is done no matter what --
- according to POSIX.2, this expands to a list of the positional
- parameters no matter what IFS is set to. */
- temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
-
- tflag |= W_DOLLARAT;
- dispose_words (list);
- break;
-
- case LBRACE:
- tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
- quoted_dollar_at_p,
- contains_dollar_at);
-
- if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
- return (tdesc);
- temp = tdesc ? tdesc->word : (char *)0;
-
- /* XXX */
- /* Quoted nulls should be removed if there is anything else
- in the string. */
- /* Note that we saw the quoted null so we can add one back at
- the end of this function if there are no other characters
- in the string, discard TEMP, and go on. The exception to
- this is when we have "${@}" and $1 is '', since $@ needs
- special handling. */
- if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
- {
- if (had_quoted_null_p)
- *had_quoted_null_p = 1;
- if (*quoted_dollar_at_p == 0)
- {
- free (temp);
- tdesc->word = temp = (char *)NULL;
- }
-
- }
-
- ret = tdesc;
- goto return0;
-
- /* Do command or arithmetic substitution. */
- case LPAREN:
- /* We have to extract the contents of this paren substitution. */
- t_index = zindex + 1;
- temp = extract_command_subst (string, &t_index, 0);
- zindex = t_index;
-
- /* For Posix.2-style `$(( ))' arithmetic substitution,
- extract the expression and pass it to the evaluator. */
- if (temp && *temp == LPAREN)
- {
- char *temp2;
- temp1 = temp + 1;
- temp2 = savestring (temp1);
- t_index = strlen (temp2) - 1;
-
- if (temp2[t_index] != RPAREN)
- {
- free (temp2);
- goto comsub;
- }
-
- /* Cut off ending `)' */
- temp2[t_index] = '\0';
-
- if (chk_arithsub (temp2, t_index) == 0)
- {
- free (temp2);
-#if 0
- internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
-#endif
- goto comsub;
- }
-
- /* Expand variables found inside the expression. */
- temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
- free (temp2);
-
-arithsub:
- /* No error messages. */
- this_command_name = (char *)NULL;
- number = evalexp (temp1, &expok);
- free (temp);
- free (temp1);
- if (expok == 0)
- {
- if (interactive_shell == 0 && posixly_correct)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- return (&expand_wdesc_fatal);
- }
- else
- return (&expand_wdesc_error);
- }
- temp = itos (number);
- break;
- }
-
-comsub:
- if (pflags & PF_NOCOMSUB)
- /* we need zindex+1 because string[zindex] == RPAREN */
- temp1 = substring (string, *sindex, zindex+1);
- else
- {
- tdesc = command_substitute (temp, quoted);
- temp1 = tdesc ? tdesc->word : (char *)NULL;
- if (tdesc)
- dispose_word_desc (tdesc);
- }
- FREE (temp);
- temp = temp1;
- break;
-
- /* Do POSIX.2d9-style arithmetic substitution. This will probably go
- away in a future bash release. */
- case '[':
- /* Extract the contents of this arithmetic substitution. */
- t_index = zindex + 1;
- temp = extract_arithmetic_subst (string, &t_index);
- zindex = t_index;
- if (temp == 0)
- {
- temp = savestring (string);
- if (expanded_something)
- *expanded_something = 0;
- goto return0;
- }
-
- /* Do initial variable expansion. */
- temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
-
- goto arithsub;
-
- default:
- /* Find the variable in VARIABLE_LIST. */
- temp = (char *)NULL;
-
- for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
- ;
- temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
-
- /* If this isn't a variable name, then just output the `$'. */
- if (temp1 == 0 || *temp1 == '\0')
- {
- FREE (temp1);
- temp = (char *)xmalloc (2);
- temp[0] = '$';
- temp[1] = '\0';
- if (expanded_something)
- *expanded_something = 0;
- goto return0;
- }
-
- /* If the variable exists, return its value cell. */
- var = find_variable (temp1);
-
- if (var && invisible_p (var) == 0 && var_isset (var))
- {
-#if defined (ARRAY_VARS)
- if (assoc_p (var) || array_p (var))
- {
- temp = array_p (var) ? array_reference (array_cell (var), 0)
- : assoc_reference (assoc_cell (var), "0");
- if (temp)
- temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ? quote_string (temp)
- : quote_escapes (temp);
- else if (unbound_vars_is_error)
- goto unbound_variable;
- }
- else
-#endif
- {
- temp = value_cell (var);
-
- temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
- ? quote_string (temp)
- : quote_escapes (temp);
- }
-
- free (temp1);
-
- goto return0;
- }
-#if defined (ARRAY_VARS)
- else if (var = find_variable_last_nameref (temp1))
- {
- temp = nameref_cell (var);
- if (temp && *temp && valid_array_reference (temp))
- {
- tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (int *)NULL);
- if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
- return (tdesc);
- ret = tdesc;
- goto return0;
- }
- else
- temp = (char *)NULL;
- }
-#endif
-
- temp = (char *)NULL;
-
-unbound_variable:
- if (unbound_vars_is_error)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- err_unboundvar (temp1);
- }
- else
- {
- free (temp1);
- goto return0;
- }
-
- free (temp1);
- last_command_exit_value = EXECUTION_FAILURE;
- return ((unbound_vars_is_error && interactive_shell == 0)
- ? &expand_wdesc_fatal
- : &expand_wdesc_error);
- }
-
- if (string[zindex])
- zindex++;
-
-return0:
- *sindex = zindex;
-
- if (ret == 0)
- {
- ret = alloc_word_desc ();
- ret->flags = tflag; /* XXX */
- ret->word = temp;
- }
- return ret;
-}
-
-/* Make a word list which is the result of parameter and variable
- expansion, command substitution, arithmetic substitution, and
- quote removal of WORD. Return a pointer to a WORD_LIST which is
- the result of the expansion. If WORD contains a null word, the
- word list returned is also null.
-
- QUOTED contains flag values defined in shell.h.
-
- ISEXP is used to tell expand_word_internal that the word should be
- treated as the result of an expansion. This has implications for
- how IFS characters in the word are treated.
-
- CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
- they point to an integer value which receives information about expansion.
- CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
- EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
- else zero.
-
- This only does word splitting in the case of $@ expansion. In that
- case, we split on ' '. */
-
-/* Values for the local variable quoted_state. */
-#define UNQUOTED 0
-#define PARTIALLY_QUOTED 1
-#define WHOLLY_QUOTED 2
-
-static WORD_LIST *
-expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
- WORD_DESC *word;
- int quoted, isexp;
- int *contains_dollar_at;
- int *expanded_something;
-{
- WORD_LIST *list;
- WORD_DESC *tword;
-
- /* The intermediate string that we build while expanding. */
- char *istring;
-
- /* The current size of the above object. */
- int istring_size;
-
- /* Index into ISTRING. */
- int istring_index;
-
- /* Temporary string storage. */
- char *temp, *temp1;
-
- /* The text of WORD. */
- register char *string;
-
- /* The size of STRING. */
- size_t string_size;
-
- /* The index into STRING. */
- int sindex;
-
- /* This gets 1 if we see a $@ while quoted. */
- int quoted_dollar_at;
-
- /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
- whether WORD contains no quoting characters, a partially quoted
- string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
- int quoted_state;
-
- /* State flags */
- int had_quoted_null;
- int has_dollar_at, temp_has_dollar_at;
- int tflag;
- int pflags; /* flags passed to param_expand */
-
- int assignoff; /* If assignment, offset of `=' */
-
- register unsigned char c; /* Current character. */
- int t_index; /* For calls to string_extract_xxx. */
-
- char twochars[2];
-
- DECLARE_MBSTATE;
-
- istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
- istring[istring_index = 0] = '\0';
- quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
- quoted_state = UNQUOTED;
-
- string = word->word;
- if (string == 0)
- goto finished_with_string;
- /* Don't need the string length for the SADD... and COPY_ macros unless
- multibyte characters are possible. */
- string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
-
- if (contains_dollar_at)
- *contains_dollar_at = 0;
-
- assignoff = -1;
-
- /* Begin the expansion. */
-
- for (sindex = 0; ;)
- {
- c = string[sindex];
-
- /* Case on toplevel character. */
- switch (c)
- {
- case '\0':
- goto finished_with_string;
-
- case CTLESC:
- sindex++;
-#if HANDLE_MULTIBYTE
- if (MB_CUR_MAX > 1 && string[sindex])
- {
- SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
- }
- else
-#endif
- {
- temp = (char *)xmalloc (3);
- temp[0] = CTLESC;
- temp[1] = c = string[sindex];
- temp[2] = '\0';
- }
-
-dollar_add_string:
- if (string[sindex])
- sindex++;
-
-add_string:
- if (temp)
- {
- istring = sub_append_string (temp, istring, &istring_index, &istring_size);
- temp = (char *)0;
- }
-
- break;
-
-#if defined (PROCESS_SUBSTITUTION)
- /* Process substitution. */
- case '<':
- case '>':
- {
- if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
- {
- sindex--; /* add_character: label increments sindex */
- goto add_character;
- }
- else
- t_index = sindex + 1; /* skip past both '<' and LPAREN */
-
- temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
- sindex = t_index;
-
- /* If the process substitution specification is `<()', we want to
- open the pipe for writing in the child and produce output; if
- it is `>()', we want to open the pipe for reading in the child
- and consume input. */
- temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
-
- FREE (temp1);
-
- goto dollar_add_string;
- }
-#endif /* PROCESS_SUBSTITUTION */
-
- case '=':
- /* Posix.2 section 3.6.1 says that tildes following `=' in words
- which are not assignment statements are not expanded. If the
- shell isn't in posix mode, though, we perform tilde expansion
- on `likely candidate' unquoted assignment statements (flags
- include W_ASSIGNMENT but not W_QUOTED). A likely candidate
- contains an unquoted :~ or =~. Something to think about: we
- now have a flag that says to perform tilde expansion on arguments
- to `assignment builtins' like declare and export that look like
- assignment statements. We now do tilde expansion on such words
- even in POSIX mode. */
- if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
- {
- if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
- goto add_ifs_character;
- else
- goto add_character;
- }
- /* If we're not in posix mode or forcing assignment-statement tilde
- expansion, note where the `=' appears in the word and prepare to
- do tilde expansion following the first `='. */
- if ((word->flags & W_ASSIGNMENT) &&
- (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
- assignoff == -1 && sindex > 0)
- assignoff = sindex;
- if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
- word->flags |= W_ITILDE;
-#if 0
- else if ((word->flags & W_ASSIGNMENT) &&
- (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
- string[sindex+1] == '~')
- word->flags |= W_ITILDE;
-#endif
- if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
- goto add_ifs_character;
- else
- goto add_character;
-
- case ':':
- if (word->flags & W_NOTILDE)
- {
- if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
- goto add_ifs_character;
- else
- goto add_character;
- }
-
- if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
- string[sindex+1] == '~')
- word->flags |= W_ITILDE;
-
- if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
- goto add_ifs_character;
- else
- goto add_character;
-
- case '~':
- /* If the word isn't supposed to be tilde expanded, or we're not
- at the start of a word or after an unquoted : or = in an
- assignment statement, we don't do tilde expansion. */
- if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
- (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
- (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- {
- word->flags &= ~W_ITILDE;
- if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
- goto add_ifs_character;
- else
- goto add_character;
- }
-
- if (word->flags & W_ASSIGNRHS)
- tflag = 2;
- else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
- tflag = 1;
- else
- tflag = 0;
-
- temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
-
- word->flags &= ~W_ITILDE;
-
- if (temp && *temp && t_index > 0)
- {
- temp1 = bash_tilde_expand (temp, tflag);
- if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
- {
- FREE (temp);
- FREE (temp1);
- goto add_character; /* tilde expansion failed */
- }
- free (temp);
- temp = temp1;
- sindex += t_index;
- goto add_quoted_string; /* XXX was add_string */
- }
- else
- {
- FREE (temp);
- goto add_character;
- }
-
- case '$':
- if (expanded_something)
- *expanded_something = 1;
-
- temp_has_dollar_at = 0;
- pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
- if (word->flags & W_NOSPLIT2)
- pflags |= PF_NOSPLIT2;
- if (word->flags & W_ASSIGNRHS)
- pflags |= PF_ASSIGNRHS;
- tword = param_expand (string, &sindex, quoted, expanded_something,
- &temp_has_dollar_at, "ed_dollar_at,
- &had_quoted_null, pflags);
- has_dollar_at += temp_has_dollar_at;
-
- if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
- {
- free (string);
- free (istring);
- return ((tword == &expand_wdesc_error) ? &expand_word_error
- : &expand_word_fatal);
- }
- if (contains_dollar_at && has_dollar_at)
- *contains_dollar_at = 1;
-
- if (tword && (tword->flags & W_HASQUOTEDNULL))
- had_quoted_null = 1;
-
- temp = tword ? tword->word : (char *)NULL;
- dispose_word_desc (tword);
-
- /* Kill quoted nulls; we will add them back at the end of
- expand_word_internal if nothing else in the string */
- if (had_quoted_null && temp && QUOTED_NULL (temp))
- {
- FREE (temp);
- temp = (char *)NULL;
- }
-
- goto add_string;
- break;
-
- case '`': /* Backquoted command substitution. */
- {
- t_index = sindex++;
-
- temp = string_extract (string, &sindex, "`", SX_REQMATCH);
- /* The test of sindex against t_index is to allow bare instances of
- ` to pass through, for backwards compatibility. */
- if (temp == &extract_string_error || temp == &extract_string_fatal)
- {
- if (sindex - 1 == t_index)
- {
- sindex = t_index;
- goto add_character;
- }
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
- free (string);
- free (istring);
- return ((temp == &extract_string_error) ? &expand_word_error
- : &expand_word_fatal);
- }
-
- if (expanded_something)
- *expanded_something = 1;
-
- if (word->flags & W_NOCOMSUB)
- /* sindex + 1 because string[sindex] == '`' */
- temp1 = substring (string, t_index, sindex + 1);
- else
- {
- de_backslash (temp);
- tword = command_substitute (temp, quoted);
- temp1 = tword ? tword->word : (char *)NULL;
- if (tword)
- dispose_word_desc (tword);
- }
- FREE (temp);
- temp = temp1;
- goto dollar_add_string;
- }
-
- case '\\':
- if (string[sindex + 1] == '\n')
- {
- sindex += 2;
- continue;
- }
-
- c = string[++sindex];
-
- if (quoted & Q_HERE_DOCUMENT)
- tflag = CBSHDOC;
- else if (quoted & Q_DOUBLE_QUOTES)
- tflag = CBSDQUOTE;
- else
- tflag = 0;
-
- /* From Posix discussion on austin-group list: Backslash escaping
- a } in ${...} is removed. Issue 0000221 */
- if ((quoted & Q_DOLBRACE) && c == RBRACE)
- {
- SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
- }
- else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
- {
- SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
- }
- else if (c == 0)
- {
- c = CTLNUL;
- sindex--; /* add_character: label increments sindex */
- goto add_character;
- }
- else
- {
- SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
- }
-
- sindex++;
-add_twochars:
- /* BEFORE jumping here, we need to increment sindex if appropriate */
- RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
- DEFAULT_ARRAY_SIZE);
- istring[istring_index++] = twochars[0];
- istring[istring_index++] = twochars[1];
- istring[istring_index] = '\0';
-
- break;
-
- case '"':
-#if 0
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
-#else
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
-#endif
- goto add_character;
-
- t_index = ++sindex;
- temp = string_extract_double_quoted (string, &sindex, 0);
-
- /* If the quotes surrounded the entire string, then the
- whole word was quoted. */
- quoted_state = (t_index == 1 && string[sindex] == '\0')
- ? WHOLLY_QUOTED
- : PARTIALLY_QUOTED;
-
- if (temp && *temp)
- {
- tword = alloc_word_desc ();
- tword->word = temp;
-
- temp = (char *)NULL;
-
- temp_has_dollar_at = 0; /* XXX */
- /* Need to get W_HASQUOTEDNULL flag through this function. */
- list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
- has_dollar_at += temp_has_dollar_at;
-
- if (list == &expand_word_error || list == &expand_word_fatal)
- {
- free (istring);
- free (string);
- /* expand_word_internal has already freed temp_word->word
- for us because of the way it prints error messages. */
- tword->word = (char *)NULL;
- dispose_word (tword);
- return list;
- }
-
- dispose_word (tword);
-
- /* "$@" (a double-quoted dollar-at) expands into nothing,
- not even a NULL word, when there are no positional
- parameters. */
- if (list == 0 && has_dollar_at)
- {
- quoted_dollar_at++;
- break;
- }
-
- /* If we get "$@", we know we have expanded something, so we
- need to remember it for the final split on $IFS. This is
- a special case; it's the only case where a quoted string
- can expand into more than one word. It's going to come back
- from the above call to expand_word_internal as a list with
- a single word, in which all characters are quoted and
- separated by blanks. What we want to do is to turn it back
- into a list for the next piece of code. */
- if (list)
- dequote_list (list);
-
- if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
- had_quoted_null = 1; /* XXX */
-
- if (has_dollar_at)
- {
- quoted_dollar_at++;
- if (contains_dollar_at)
- *contains_dollar_at = 1;
- if (expanded_something)
- *expanded_something = 1;
- }
- }
- else
- {
- /* What we have is "". This is a minor optimization. */
- FREE (temp);
- list = (WORD_LIST *)NULL;
- }
-
- /* The code above *might* return a list (consider the case of "$@",
- where it returns "$1", "$2", etc.). We can't throw away the
- rest of the list, and we have to make sure each word gets added
- as quoted. We test on tresult->next: if it is non-NULL, we
- quote the whole list, save it to a string with string_list, and
- add that string. We don't need to quote the results of this
- (and it would be wrong, since that would quote the separators
- as well), so we go directly to add_string. */
- if (list)
- {
- if (list->next)
- {
-#if 0
- if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
- temp = string_list_internal (quote_list (list), " ");
- else
-#endif
- /* Testing quoted_dollar_at makes sure that "$@" is
- split correctly when $IFS does not contain a space. */
- temp = quoted_dollar_at
- ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
- : string_list (quote_list (list));
- dispose_words (list);
- goto add_string;
- }
- else
- {
- temp = savestring (list->word->word);
- tflag = list->word->flags;
- dispose_words (list);
-
- /* If the string is not a quoted null string, we want
- to remove any embedded unquoted CTLNUL characters.
- We do not want to turn quoted null strings back into
- the empty string, though. We do this because we
- want to remove any quoted nulls from expansions that
- contain other characters. For example, if we have
- x"$*"y or "x$*y" and there are no positional parameters,
- the $* should expand into nothing. */
- /* We use the W_HASQUOTEDNULL flag to differentiate the
- cases: a quoted null character as above and when
- CTLNUL is contained in the (non-null) expansion
- of some variable. We use the had_quoted_null flag to
- pass the value through this function to its caller. */
- if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
- remove_quoted_nulls (temp); /* XXX */
- }
- }
- else
- temp = (char *)NULL;
-
- /* We do not want to add quoted nulls to strings that are only
- partially quoted; we can throw them away. The exception to
- this is when we are going to be performing word splitting,
- since we have to preserve a null argument if the next character
- will cause word splitting. */
- if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
- continue;
-
- add_quoted_string:
-
- if (temp)
- {
- temp1 = temp;
- temp = quote_string (temp);
- free (temp1);
- goto add_string;
- }
- else
- {
- /* Add NULL arg. */
- c = CTLNUL;
- sindex--; /* add_character: label increments sindex */
- goto add_character;
- }
-
- /* break; */
-
- case '\'':
-#if 0
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
-#else
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
-#endif
- goto add_character;
-
- t_index = ++sindex;
- temp = string_extract_single_quoted (string, &sindex);
-
- /* If the entire STRING was surrounded by single quotes,
- then the string is wholly quoted. */
- quoted_state = (t_index == 1 && string[sindex] == '\0')
- ? WHOLLY_QUOTED
- : PARTIALLY_QUOTED;
-
- /* If all we had was '', it is a null expansion. */
- if (*temp == '\0')
- {
- free (temp);
- temp = (char *)NULL;
- }
- else
- remove_quoted_escapes (temp); /* ??? */
-
- /* We do not want to add quoted nulls to strings that are only
- partially quoted; such nulls are discarded. */
- if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
- continue;
-
- /* If we have a quoted null expansion, add a quoted NULL to istring. */
- if (temp == 0)
- {
- c = CTLNUL;
- sindex--; /* add_character: label increments sindex */
- goto add_character;
- }
- else
- goto add_quoted_string;
-
- /* break; */
-
- default:
- /* This is the fix for " $@ " */
- add_ifs_character:
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
- {
- if (string[sindex]) /* from old goto dollar_add_string */
- sindex++;
- if (c == 0)
- {
- c = CTLNUL;
- goto add_character;
- }
- else
- {
-#if HANDLE_MULTIBYTE
- if (MB_CUR_MAX > 1)
- sindex--;
-
- if (MB_CUR_MAX > 1)
- {
- SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
- }
- else
-#endif
- {
- twochars[0] = CTLESC;
- twochars[1] = c;
- goto add_twochars;
- }
- }
- }
-
- SADD_MBCHAR (temp, string, sindex, string_size);
-
- add_character:
- RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
- DEFAULT_ARRAY_SIZE);
- istring[istring_index++] = c;
- istring[istring_index] = '\0';
-
- /* Next character. */
- sindex++;
- }
- }
-
-finished_with_string:
- /* OK, we're ready to return. If we have a quoted string, and
- quoted_dollar_at is not set, we do no splitting at all; otherwise
- we split on ' '. The routines that call this will handle what to
- do if nothing has been expanded. */
-
- /* Partially and wholly quoted strings which expand to the empty
- string are retained as an empty arguments. Unquoted strings
- which expand to the empty string are discarded. The single
- exception is the case of expanding "$@" when there are no
- positional parameters. In that case, we discard the expansion. */
-
- /* Because of how the code that handles "" and '' in partially
- quoted strings works, we need to make ISTRING into a QUOTED_NULL
- if we saw quoting characters, but the expansion was empty.
- "" and '' are tossed away before we get to this point when
- processing partially quoted strings. This makes "" and $xxx""
- equivalent when xxx is unset. We also look to see whether we
- saw a quoted null from a ${} expansion and add one back if we
- need to. */
-
- /* If we expand to nothing and there were no single or double quotes
- in the word, we throw it away. Otherwise, we return a NULL word.
- The single exception is for $@ surrounded by double quotes when
- there are no positional parameters. In that case, we also throw
- the word away. */
-
- if (*istring == '\0')
- {
- if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
- {
- istring[0] = CTLNUL;
- istring[1] = '\0';
- tword = make_bare_word (istring);
- tword->flags |= W_HASQUOTEDNULL; /* XXX */
- list = make_word_list (tword, (WORD_LIST *)NULL);
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- tword->flags |= W_QUOTED;
- }
- /* According to sh, ksh, and Posix.2, if a word expands into nothing
- and a double-quoted "$@" appears anywhere in it, then the entire
- word is removed. */
- else if (quoted_state == UNQUOTED || quoted_dollar_at)
- list = (WORD_LIST *)NULL;
-#if 0
- else
- {
- tword = make_bare_word (istring);
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- tword->flags |= W_QUOTED;
- list = make_word_list (tword, (WORD_LIST *)NULL);
- }
-#else
- else
- list = (WORD_LIST *)NULL;
-#endif
- }
- else if (word->flags & W_NOSPLIT)
- {
- tword = make_bare_word (istring);
- if (word->flags & W_ASSIGNMENT)
- tword->flags |= W_ASSIGNMENT; /* XXX */
- if (word->flags & W_COMPASSIGN)
- tword->flags |= W_COMPASSIGN; /* XXX */
- if (word->flags & W_NOGLOB)
- tword->flags |= W_NOGLOB; /* XXX */
- if (word->flags & W_NOBRACE)
- tword->flags |= W_NOBRACE; /* XXX */
- if (word->flags & W_NOEXPAND)
- tword->flags |= W_NOEXPAND; /* XXX */
- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
- tword->flags |= W_QUOTED;
- if (had_quoted_null && QUOTED_NULL (istring))
- tword->flags |= W_HASQUOTEDNULL;
- list = make_word_list (tword, (WORD_LIST *)NULL);
- }
- else
- {
- char *ifs_chars;
-
- ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
-
- /* If we have $@, we need to split the results no matter what. If
- IFS is unset or NULL, string_list_dollar_at has separated the
- positional parameters with a space, so we split on space (we have
- set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
- string_list_dollar_at has separated the positional parameters
- with the first character of $IFS, so we split on $IFS. */
- if (has_dollar_at && ifs_chars)
- list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
- else
- {
- tword = make_bare_word (istring);
- if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
- tword->flags |= W_QUOTED;
- if (word->flags & W_ASSIGNMENT)
- tword->flags |= W_ASSIGNMENT;
- if (word->flags & W_COMPASSIGN)
- tword->flags |= W_COMPASSIGN;
- if (word->flags & W_NOGLOB)
- tword->flags |= W_NOGLOB;
- if (word->flags & W_NOBRACE)
- tword->flags |= W_NOBRACE;
- if (word->flags & W_NOEXPAND)
- tword->flags |= W_NOEXPAND;
- if (had_quoted_null && QUOTED_NULL (istring))
- tword->flags |= W_HASQUOTEDNULL; /* XXX */
- list = make_word_list (tword, (WORD_LIST *)NULL);
- }
- }
-
- free (istring);
- return (list);
-}
-
-/* **************************************************************** */
-/* */
-/* Functions for Quote Removal */
-/* */
-/* **************************************************************** */
-
-/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
- backslash quoting rules for within double quotes or a here document. */
-char *
-string_quote_removal (string, quoted)
- char *string;
- int quoted;
-{
- size_t slen;
- char *r, *result_string, *temp, *send;
- int sindex, tindex, dquote;
- unsigned char c;
- DECLARE_MBSTATE;
-
- /* The result can be no longer than the original string. */
- slen = strlen (string);
- send = string + slen;
-
- r = result_string = (char *)xmalloc (slen + 1);
-
- for (dquote = sindex = 0; c = string[sindex];)
- {
- switch (c)
- {
- case '\\':
- c = string[++sindex];
- if (c == 0)
- {
- *r++ = '\\';
- break;
- }
- if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
- *r++ = '\\';
- /* FALLTHROUGH */
-
- default:
- SCOPY_CHAR_M (r, string, send, sindex);
- break;
-
- case '\'':
- if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
- {
- *r++ = c;
- sindex++;
- break;
- }
- tindex = sindex + 1;
- temp = string_extract_single_quoted (string, &tindex);
- if (temp)
- {
- strcpy (r, temp);
- r += strlen (r);
- free (temp);
- }
- sindex = tindex;
- break;
-
- case '"':
- dquote = 1 - dquote;
- sindex++;
- break;
- }
- }
- *r = '\0';
- return (result_string);
-}
-
-#if 0
-/* UNUSED */
-/* Perform quote removal on word WORD. This allocates and returns a new
- WORD_DESC *. */
-WORD_DESC *
-word_quote_removal (word, quoted)
- WORD_DESC *word;
- int quoted;
-{
- WORD_DESC *w;
- char *t;
-
- t = string_quote_removal (word->word, quoted);
- w = alloc_word_desc ();
- w->word = t ? t : savestring ("");
- return (w);
-}
-
-/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
- the members of the list are treated as if they are surrounded by
- double quotes. Return a new list, or NULL if LIST is NULL. */
-WORD_LIST *
-word_list_quote_removal (list, quoted)
- WORD_LIST *list;
- int quoted;
-{
- WORD_LIST *result, *t, *tresult, *e;
-
- for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
- {
- tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
-#if 0
- result = (WORD_LIST *) list_append (result, tresult);
-#else
- if (result == 0)
- result = e = tresult;
- else
- {
- e->next = tresult;
- while (e->next)
- e = e->next;
- }
-#endif
- }
- return (result);
-}
-#endif
-
-/*******************************************
- * *
- * Functions to perform word splitting *
- * *
- *******************************************/
-
-void
-setifs (v)
- SHELL_VAR *v;
-{
- char *t;
- unsigned char uc;
-
- ifs_var = v;
- ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
-
- /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
- handle multibyte chars in IFS */
- memset (ifs_cmap, '\0', sizeof (ifs_cmap));
- for (t = ifs_value ; t && *t; t++)
- {
- uc = *t;
- ifs_cmap[uc] = 1;
- }
-
-#if defined (HANDLE_MULTIBYTE)
- if (ifs_value == 0)
- {
- ifs_firstc[0] = '\0';
- ifs_firstc_len = 1;
- }
- else
- {
- size_t ifs_len;
- ifs_len = strnlen (ifs_value, MB_CUR_MAX);
- ifs_firstc_len = MBLEN (ifs_value, ifs_len);
- if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
- {
- ifs_firstc[0] = ifs_value[0];
- ifs_firstc[1] = '\0';
- ifs_firstc_len = 1;
- }
- else
- memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
- }
-#else
- ifs_firstc = ifs_value ? *ifs_value : 0;
-#endif
-}
-
-char *
-getifs ()
-{
- return ifs_value;
-}
-
-/* This splits a single word into a WORD LIST on $IFS, but only if the word
- is not quoted. list_string () performs quote removal for us, even if we
- don't do any splitting. */
-WORD_LIST *
-word_split (w, ifs_chars)
- WORD_DESC *w;
- char *ifs_chars;
-{
- WORD_LIST *result;
-
- if (w)
- {
- char *xifs;
-
- xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
- result = list_string (w->word, xifs, w->flags & W_QUOTED);
- }
- else
- result = (WORD_LIST *)NULL;
-
- return (result);
-}
-
-/* Perform word splitting on LIST and return the RESULT. It is possible
- to return (WORD_LIST *)NULL. */
-static WORD_LIST *
-word_list_split (list)
- WORD_LIST *list;
-{
- WORD_LIST *result, *t, *tresult, *e;
-
- for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
- {
- tresult = word_split (t->word, ifs_value);
- if (result == 0)
- result = e = tresult;
- else
- {
- e->next = tresult;
- while (e->next)
- e = e->next;
- }
- }
- return (result);
-}
-
-/**************************************************
- * *
- * Functions to expand an entire WORD_LIST *
- * *
- **************************************************/
-
-/* Do any word-expansion-specific cleanup and jump to top_level */
-static void
-exp_jump_to_top_level (v)
- int v;
-{
- set_pipestatus_from_exit (last_command_exit_value);
-
- /* Cleanup code goes here. */
- expand_no_split_dollar_star = 0; /* XXX */
- expanding_redir = 0;
- assigning_in_environment = 0;
-
- if (parse_and_execute_level == 0)
- top_level_cleanup (); /* from sig.c */
-
- jump_to_top_level (v);
-}
-
-/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
- ELIST, and set ELIST to the new list. */
-#define PREPEND_LIST(nlist, elist) \
- do { nlist->next = elist; elist = nlist; } while (0)
-
-/* Separate out any initial variable assignments from TLIST. If set -k has
- been executed, remove all assignment statements from TLIST. Initial
- variable assignments and other environment assignments are placed
- on SUBST_ASSIGN_VARLIST. */
-static WORD_LIST *
-separate_out_assignments (tlist)
- WORD_LIST *tlist;
-{
- register WORD_LIST *vp, *lp;
-
- if (tlist == 0)
- return ((WORD_LIST *)NULL);
-
- if (subst_assign_varlist)
- dispose_words (subst_assign_varlist); /* Clean up after previous error */
-
- subst_assign_varlist = (WORD_LIST *)NULL;
- vp = lp = tlist;
-
- /* Separate out variable assignments at the start of the command.
- Loop invariant: vp->next == lp
- Loop postcondition:
- lp = list of words left after assignment statements skipped
- tlist = original list of words
- */
- while (lp && (lp->word->flags & W_ASSIGNMENT))
- {
- vp = lp;
- lp = lp->next;
- }
-
- /* If lp != tlist, we have some initial assignment statements.
- We make SUBST_ASSIGN_VARLIST point to the list of assignment
- words and TLIST point to the remaining words. */
- if (lp != tlist)
- {
- subst_assign_varlist = tlist;
- /* ASSERT(vp->next == lp); */
- vp->next = (WORD_LIST *)NULL; /* terminate variable list */
- tlist = lp; /* remainder of word list */
- }
-
- /* vp == end of variable list */
- /* tlist == remainder of original word list without variable assignments */
- if (!tlist)
- /* All the words in tlist were assignment statements */
- return ((WORD_LIST *)NULL);
-
- /* ASSERT(tlist != NULL); */
- /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
-
- /* If the -k option is in effect, we need to go through the remaining
- words, separate out the assignment words, and place them on
- SUBST_ASSIGN_VARLIST. */
- if (place_keywords_in_env)
- {
- WORD_LIST *tp; /* tp == running pointer into tlist */
-
- tp = tlist;
- lp = tlist->next;
-
- /* Loop Invariant: tp->next == lp */
- /* Loop postcondition: tlist == word list without assignment statements */
- while (lp)
- {
- if (lp->word->flags & W_ASSIGNMENT)
- {
- /* Found an assignment statement, add this word to end of
- subst_assign_varlist (vp). */
- if (!subst_assign_varlist)
- subst_assign_varlist = vp = lp;
- else
- {
- vp->next = lp;
- vp = lp;
- }
-
- /* Remove the word pointed to by LP from TLIST. */
- tp->next = lp->next;
- /* ASSERT(vp == lp); */
- lp->next = (WORD_LIST *)NULL;
- lp = tp->next;
- }
- else
- {
- tp = lp;
- lp = lp->next;
- }
- }
- }
- return (tlist);
-}
-
-#define WEXP_VARASSIGN 0x001
-#define WEXP_BRACEEXP 0x002
-#define WEXP_TILDEEXP 0x004
-#define WEXP_PARAMEXP 0x008
-#define WEXP_PATHEXP 0x010
-
-/* All of the expansions, including variable assignments at the start of
- the list. */
-#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
-
-/* All of the expansions except variable assignments at the start of
- the list. */
-#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
-
-/* All of the `shell expansions': brace expansion, tilde expansion, parameter
- expansion, command substitution, arithmetic expansion, word splitting, and
- quote removal. */
-#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
-
-/* Take the list of words in LIST and do the various substitutions. Return
- a new list of words which is the expanded list, and without things like
- variable assignments. */
-
-WORD_LIST *
-expand_words (list)
- WORD_LIST *list;
-{
- return (expand_word_list_internal (list, WEXP_ALL));
-}
-
-/* Same as expand_words (), but doesn't hack variable or environment
- variables. */
-WORD_LIST *
-expand_words_no_vars (list)
- WORD_LIST *list;
-{
- return (expand_word_list_internal (list, WEXP_NOVARS));
-}
-
-WORD_LIST *
-expand_words_shellexp (list)
- WORD_LIST *list;
-{
- return (expand_word_list_internal (list, WEXP_SHELLEXP));
-}
-
-static WORD_LIST *
-glob_expand_word_list (tlist, eflags)
- WORD_LIST *tlist;
- int eflags;
-{
- char **glob_array, *temp_string;
- register int glob_index;
- WORD_LIST *glob_list, *output_list, *disposables, *next;
- WORD_DESC *tword;
-
- output_list = disposables = (WORD_LIST *)NULL;
- glob_array = (char **)NULL;
- while (tlist)
- {
- /* For each word, either globbing is attempted or the word is
- added to orig_list. If globbing succeeds, the results are
- added to orig_list and the word (tlist) is added to the list
- of disposable words. If globbing fails and failed glob
- expansions are left unchanged (the shell default), the
- original word is added to orig_list. If globbing fails and
- failed glob expansions are removed, the original word is
- added to the list of disposable words. orig_list ends up
- in reverse order and requires a call to REVERSE_LIST to
- be set right. After all words are examined, the disposable
- words are freed. */
- next = tlist->next;
-
- /* If the word isn't an assignment and contains an unquoted
- pattern matching character, then glob it. */
- if ((tlist->word->flags & W_NOGLOB) == 0 &&
- unquoted_glob_pattern_p (tlist->word->word))
- {
- glob_array = shell_glob_filename (tlist->word->word);
-
- /* Handle error cases.
- I don't think we should report errors like "No such file
- or directory". However, I would like to report errors
- like "Read failed". */
-
- if (glob_array == 0 || GLOB_FAILED (glob_array))
- {
- glob_array = (char **)xmalloc (sizeof (char *));
- glob_array[0] = (char *)NULL;
- }
-
- /* Dequote the current word in case we have to use it. */
- if (glob_array[0] == NULL)
- {
- temp_string = dequote_string (tlist->word->word);
- free (tlist->word->word);
- tlist->word->word = temp_string;
- }
-
- /* Make the array into a word list. */
- glob_list = (WORD_LIST *)NULL;
- for (glob_index = 0; glob_array[glob_index]; glob_index++)
- {
- tword = make_bare_word (glob_array[glob_index]);
- tword->flags |= W_GLOBEXP; /* XXX */
- glob_list = make_word_list (tword, glob_list);
- }
-
- if (glob_list)
- {
- output_list = (WORD_LIST *)list_append (glob_list, output_list);
- PREPEND_LIST (tlist, disposables);
- }
- else if (fail_glob_expansion != 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("no match: %s"), tlist->word->word);
- exp_jump_to_top_level (DISCARD);
- }
- else if (allow_null_glob_expansion == 0)
- {
- /* Failed glob expressions are left unchanged. */
- PREPEND_LIST (tlist, output_list);
- }
- else
- {
- /* Failed glob expressions are removed. */
- PREPEND_LIST (tlist, disposables);
- }
- }
- else
- {
- /* Dequote the string. */
- temp_string = dequote_string (tlist->word->word);
- free (tlist->word->word);
- tlist->word->word = temp_string;
- PREPEND_LIST (tlist, output_list);
- }
-
- strvec_dispose (glob_array);
- glob_array = (char **)NULL;
-
- tlist = next;
- }
-
- if (disposables)
- dispose_words (disposables);
-
- if (output_list)
- output_list = REVERSE_LIST (output_list, WORD_LIST *);
-
- return (output_list);
-}
-
-#if defined (BRACE_EXPANSION)
-static WORD_LIST *
-brace_expand_word_list (tlist, eflags)
- WORD_LIST *tlist;
- int eflags;
-{
- register char **expansions;
- char *temp_string;
- WORD_LIST *disposables, *output_list, *next;
- WORD_DESC *w;
- int eindex;
-
- for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
- {
- next = tlist->next;
-
- if (tlist->word->flags & W_NOBRACE)
- {
-itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);
- PREPEND_LIST (tlist, output_list);
- continue;
- }
-
- if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
- {
-/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
- PREPEND_LIST (tlist, output_list);
- continue;
- }
-
- /* Only do brace expansion if the word has a brace character. If
- not, just add the word list element to BRACES and continue. In
- the common case, at least when running shell scripts, this will
- degenerate to a bunch of calls to `mbschr', and then what is
- basically a reversal of TLIST into BRACES, which is corrected
- by a call to REVERSE_LIST () on BRACES when the end of TLIST
- is reached. */
- if (mbschr (tlist->word->word, LBRACE))
- {
- expansions = brace_expand (tlist->word->word);
-
- for (eindex = 0; temp_string = expansions[eindex]; eindex++)
- {
- w = alloc_word_desc ();
- w->word = temp_string;
-
- /* If brace expansion didn't change the word, preserve
- the flags. We may want to preserve the flags
- unconditionally someday -- XXX */
- if (STREQ (temp_string, tlist->word->word))
- w->flags = tlist->word->flags;
- else
- w = make_word_flags (w, temp_string);
-
- output_list = make_word_list (w, output_list);
- }
- free (expansions);
-
- /* Add TLIST to the list of words to be freed after brace
- expansion has been performed. */
- PREPEND_LIST (tlist, disposables);
- }
- else
- PREPEND_LIST (tlist, output_list);
- }
-
- if (disposables)
- dispose_words (disposables);
-
- if (output_list)
- output_list = REVERSE_LIST (output_list, WORD_LIST *);
-
- return (output_list);
-}
-#endif
-
-#if defined (ARRAY_VARS)
-/* Take WORD, a compound associative array assignment, and internally run
- 'declare -A w', where W is the variable name portion of WORD. */
-static int
-make_internal_declare (word, option)
- char *word;
- char *option;
-{
- int t;
- WORD_LIST *wl;
- WORD_DESC *w;
-
- w = make_word (word);
-
- t = assignment (w->word, 0);
- w->word[t] = '\0';
-
- wl = make_word_list (w, (WORD_LIST *)NULL);
- wl = make_word_list (make_word (option), wl);
-
- return (declare_builtin (wl));
-}
-#endif
-
-static WORD_LIST *
-shell_expand_word_list (tlist, eflags)
- WORD_LIST *tlist;
- int eflags;
-{
- WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
- int expanded_something, has_dollar_at;
- char *temp_string;
-
- /* We do tilde expansion all the time. This is what 1003.2 says. */
- new_list = (WORD_LIST *)NULL;
- for (orig_list = tlist; tlist; tlist = next)
- {
- temp_string = tlist->word->word;
-
- next = tlist->next;
-
-#if defined (ARRAY_VARS)
- /* If this is a compound array assignment to a builtin that accepts
- such assignments (e.g., `declare'), take the assignment and perform
- it separately, handling the semantics of declarations inside shell
- functions. This avoids the double-evaluation of such arguments,
- because `declare' does some evaluation of compound assignments on
- its own. */
- if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
- {
- int t;
-
- if (tlist->word->flags & W_ASSIGNASSOC)
- make_internal_declare (tlist->word->word, "-A");
-
- t = do_word_assignment (tlist->word, 0);
- if (t == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- exp_jump_to_top_level (DISCARD);
- }
-
- /* Now transform the word as ksh93 appears to do and go on */
- t = assignment (tlist->word->word, 0);
- tlist->word->word[t] = '\0';
- tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
- }
-#endif
-
- expanded_something = 0;
- expanded = expand_word_internal
- (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
-
- if (expanded == &expand_word_error || expanded == &expand_word_fatal)
- {
- /* By convention, each time this error is returned,
- tlist->word->word has already been freed. */
- tlist->word->word = (char *)NULL;
-
- /* Dispose our copy of the original list. */
- dispose_words (orig_list);
- /* Dispose the new list we're building. */
- dispose_words (new_list);
-
- last_command_exit_value = EXECUTION_FAILURE;
- if (expanded == &expand_word_error)
- exp_jump_to_top_level (DISCARD);
- else
- exp_jump_to_top_level (FORCE_EOF);
- }
-
- /* Don't split words marked W_NOSPLIT. */
- if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
- {
- temp_list = word_list_split (expanded);
- dispose_words (expanded);
- }
- else
- {
- /* If no parameter expansion, command substitution, process
- substitution, or arithmetic substitution took place, then
- do not do word splitting. We still have to remove quoted
- null characters from the result. */
- word_list_remove_quoted_nulls (expanded);
- temp_list = expanded;
- }
-
- expanded = REVERSE_LIST (temp_list, WORD_LIST *);
- new_list = (WORD_LIST *)list_append (expanded, new_list);
- }
-
- if (orig_list)
- dispose_words (orig_list);
-
- if (new_list)
- new_list = REVERSE_LIST (new_list, WORD_LIST *);
-
- return (new_list);
-}
-
-/* The workhorse for expand_words () and expand_words_no_vars ().
- First arg is LIST, a WORD_LIST of words.
- Second arg EFLAGS is a flags word controlling which expansions are
- performed.
-
- This does all of the substitutions: brace expansion, tilde expansion,
- parameter expansion, command substitution, arithmetic expansion,
- process substitution, word splitting, and pathname expansion, according
- to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
- set, or for which no expansion is done, do not undergo word splitting.
- Words with the W_NOGLOB bit set do not undergo pathname expansion; words
- with W_NOBRACE set do not undergo brace expansion (see
- brace_expand_word_list above). */
-static WORD_LIST *
-expand_word_list_internal (list, eflags)
- WORD_LIST *list;
- int eflags;
-{
- WORD_LIST *new_list, *temp_list;
- int tint;
-
- if (list == 0)
- return ((WORD_LIST *)NULL);
-
- garglist = new_list = copy_word_list (list);
- if (eflags & WEXP_VARASSIGN)
- {
- garglist = new_list = separate_out_assignments (new_list);
- if (new_list == 0)
- {
- if (subst_assign_varlist)
- {
- /* All the words were variable assignments, so they are placed
- into the shell's environment. */
- for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
- {
- this_command_name = (char *)NULL; /* no arithmetic errors */
- tint = do_word_assignment (temp_list->word, 0);
- /* Variable assignment errors in non-interactive shells
- running in Posix.2 mode cause the shell to exit. */
- if (tint == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- if (interactive_shell == 0 && posixly_correct)
- exp_jump_to_top_level (FORCE_EOF);
- else
- exp_jump_to_top_level (DISCARD);
- }
- }
- dispose_words (subst_assign_varlist);
- subst_assign_varlist = (WORD_LIST *)NULL;
- }
- return ((WORD_LIST *)NULL);
- }
- }
-
- /* Begin expanding the words that remain. The expansions take place on
- things that aren't really variable assignments. */
-
-#if defined (BRACE_EXPANSION)
- /* Do brace expansion on this word if there are any brace characters
- in the string. */
- if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
- new_list = brace_expand_word_list (new_list, eflags);
-#endif /* BRACE_EXPANSION */
-
- /* Perform the `normal' shell expansions: tilde expansion, parameter and
- variable substitution, command substitution, arithmetic expansion,
- and word splitting. */
- new_list = shell_expand_word_list (new_list, eflags);
-
- /* Okay, we're almost done. Now let's just do some filename
- globbing. */
- if (new_list)
- {
- if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
- /* Glob expand the word list unless globbing has been disabled. */
- new_list = glob_expand_word_list (new_list, eflags);
- else
- /* Dequote the words, because we're not performing globbing. */
- new_list = dequote_list (new_list);
- }
-
- if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
- {
- sh_wassign_func_t *assign_func;
- int is_special_builtin, is_builtin_or_func;
-
- /* If the remainder of the words expand to nothing, Posix.2 requires
- that the variable and environment assignments affect the shell's
- environment. */
- assign_func = new_list ? assign_in_env : do_word_assignment;
- tempenv_assign_error = 0;
-
- is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
- /* Posix says that special builtins exit if a variable assignment error
- occurs in an assignment preceding it. */
- is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
-
- for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
- {
- this_command_name = (char *)NULL;
- assigning_in_environment = (assign_func == assign_in_env);
- tint = (*assign_func) (temp_list->word, is_builtin_or_func);
- assigning_in_environment = 0;
- /* Variable assignment errors in non-interactive shells running
- in Posix.2 mode cause the shell to exit. */
- if (tint == 0)
- {
- if (assign_func == do_word_assignment)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- if (interactive_shell == 0 && posixly_correct && is_special_builtin)
- exp_jump_to_top_level (FORCE_EOF);
- else
- exp_jump_to_top_level (DISCARD);
- }
- else
- tempenv_assign_error++;
- }
- }
-
- dispose_words (subst_assign_varlist);
- subst_assign_varlist = (WORD_LIST *)NULL;
- }
-
-#if 0
- tint = list_length (new_list) + 1;
- RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
- for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
- glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
- glob_argv_flags[tint] = '\0';
-#endif
-
- return (new_list);
-}
+++ /dev/null
-:; ./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...
-:;
+++ /dev/null
-#! /bin/sh
-for cmd in sh bash ash ksh zsh
-do
- echo
- echo $cmd:
- for demo in shx?
- do
- $cmd $demo
- done
-done