+++ /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 glob_asciirange is 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.com>
-
- 9/22
- ----
-execute_cmd.c
- - execute_disk_command: before running the command-not-found hook,
- call kill_current_pipeline() to make sure we don't add processes
- to an existing pipeline or wait for processes erroneously
-
- 9/23
- ----
-lib/readline/input.c
- - rl_input_available_hook: new hook function, called from
- _rl_input_available (or _rl_input_queued) to return whether or not
- input is available wherever the input source is
-
-lib/readline/doc/rltech.texi
- - rl_input_available_hook: document
-
- 9/27
- ----
-lib/glob/sm_loop.c:
- - GMATCH: after one or more `*', an instance of ?(x) can match zero or
- 1 times (unlike ?, which has to match one character). The old code
- failed if it didn't match at least once. Fixes `a*?(x)' bug.
- - GMATCH: if we hit the end of the search string, but not the end of
- the pattern, and the rest of the pattern is something that can
- match the NUL at the end of the search string, we should successfully
- match. Fixes `a*!(x)' bug reported by <hans1worst@gmail.com>
-
- 10/2
- ----
-command.h
- - add c_lock member to coproc structure for future use to tell who is
- manipulating it
-
-execute_cmd.c
- - execute_coproc: block SIGCHLD while parent is forking coproc
- process and adding pid to sh_coproc struct to avoid race condition
- where child is reaped before the pid is assigned and the coproc is
- never marked as having died. Fixes race condition identified by
- Davide Baldini <baldiniebaldini@gmail.com>
- - add assignments to c_lock member of struct coproc in various
- functions that manipulate it; was used to identify race condition
- - coproc_pidchk: don't call coproc_dispose to avoid using malloc and
- other functions in a signal handler context
- - coproc_dispose: call BLOCK_SIGNAL/UNBLOCK_SIGNAL for SIGCHLD while
- manipulating the sh_coproc struct
-
- 10/6
- ----
-lib/readline/complete.c
- - rl_display_match_list: if printing completions horizontally, don't
- bother with spacing calculations if limit == 1, which means we are
- printing one completion per line no matter what. Fixes bug
- reported by David Kaasen <kaasen@nvg.ntnu.no>
-
- 10/7
- ----
-builtins/declare.def
- - declare_internal: add error checking for nameref attribute and
- variable assignments: self-references, attempts to make an array
- variable a nameref
-
-subst.c
- - parameter_brace_expand: handle parameter_brace_expand_word returning
- &expand_param_fatal or &expand_param_error and return the appropriate
- error value
- - parameter_brace_expand_word: if a nameref variable's value is not a
- valid identifier, return an error
- - param_expand: if a nameref variable's value is not a valid identifier,
- return an error
-
-test.c
- - unary_operator: add new -R variable, returns true if variable is set
- and has the nameref attribute. From ksh93
-
-builtins/test.def
- - add -R to description of conditional commands for help test
-
-doc/{bash.1,bashref.texi}
- - document new -R unary conditional operator
-
- 10/13
- -----
-trap.c
- - check_signals_and_traps: new function, convenience function for the
- rest of the shell to check for pending terminating and interrupt
- signals, and to check for and process any pending traps
- - any_signals_trapped: new function, returns non-zero if any signals
- are trapped and -1 if not
-
-trap.h
- - extern declaration for check_signals_and_traps
-
-bashline.c
- - bashline_reset: make sure we reset the event hook
- - bash_event_hook: call check_signals_and_traps instead of just
- checking for terminating signals so we can run pending traps and
- react to interrupts, and reset the event hook when we're done
-
-
- 10/14
- -----
-trap.c
- - trap_handler: if executing in a readline signal handler context,
- call bashline_set_event_hook to install bash_event_hook to process
- the signal (if bash cares about it)
-
-sig.c
- - sigint_sighandler: call bashline_set_event_hook to set the event
- hook if we're executing in a readline signal handler context
-
-lib/readline/input.c
- - rl_getc: call RL_CHECK_SIGNALS if read returns -1/EINTR and the caught
- signal is SIGINT or SIGQUIT rather than waiting until the next time
- around the loop
- - rl_getc: call rl_event_hook after calling RL_CHECK_SIGNALS to allow
- an application signal handler to set the event hook in its own
- signal handler (e.g., like bash trap_handler or sigint_sighandler)
-
-
-parse.y
- - yy_readline_get: don't set interrupt_immediately before we call
- readline(). Inspired by report from lanshun zhou
- <zls.sogou@gmail.com>
-
-input.c
- - getc_with_restart: add call to run_pending_traps after call to
- CHECK_TERMSIG
-
-lib/sh/zread.c
- - zread: call check_signals_and_traps if read() returns -1/EINTR
- instead of just ignoring the EINTR and deferring handling any
- signal that generated it
-
-builtins/mapfile.def
- - mapfile: don't set interrupt_immediately before calling zgetline()
- (which uses zread internally)
-
-builtins/read.def
- - read_builtin: don't set interrupt_immediately before calling zread
- (moved code around so that it was only being set right around calls
- to zread to avoid signal handler conflicts). Inspired by report
- from lanshun zhou <zls.sogou@gmail.com>
- - edit_line: don't set interrupt_immediately around call to readline()
- - include shmbutil.h
- - read_builtin: don't call read_mbchar unless is_basic(c) returns
- false for the character we just read
-
- 10/15
- -----
-sig.c
- - throw_to_top_level: if interrupt_state is non-zero, make sure that
- last_command_exit_value reflects 128+SIGINT if it's not already
- greater than 128
-
- 10/20
- -----
-builtins/wait.def
- - WAIT_RETURN: set wait_signal_received back to 0 for the potential
- next call to wait
-
-quit.h
- - CHECK_WAIT_INTR: macro to check whether trap_handler handled a
- signal and set wait_signal_received; longjmp to wait_intr_buf in
- that case
-
-jobs.c
- - wait_for, waitchld: call CHECK_WAIT_INTR at the same places we call
- CHECK_TERMSIG to check for terminating signals
- - wait_sigint_handler: don't longjmp out of the wait builtin unless
- interrupt_immediately is set; otherwise just SIGRETURN from the
- handler
- - wait_sigint_handler: if interrupt_immediately not set, but we are
- executing in the wait builtin and SIGINT is not trapped, treat it
- as a `normally received' SIGINT: restore the signal handler and
- send SIGINT to ourselves
- - waitchld: when in posix mode and running SIGCHLD traps, don't longjmp
- to wait_intr_buf (and let wait be interrupted) if we're running from
- a signal handler. Wait for CHECK_WAIT_INTR to do the longjmp.
- run_pending_traps will run the SIGCHLD trap later
-
-nojobs.c
- - reap_zombie_children, wait_for_single_pid, wait_for: call
- CHECK_WAIT_INTR where we call CHECK_TERMSIG
- - wait_sigint_handler: don't longjmp out of the wait builtin unless
- interrupt_immediately is set; otherwise just SIGRETURN from the
- handler
-
-trap.c
- - trap_handler: make sure wait_signal_received is set if the wait
- builtin is executing, and only longjmp if interrupt_immediately is
- set. This whole set of fixes was prompted by report from
- lanshun zhou <zls.sogou@gmail.com>
-
- 10/24
- -----
-lib/glob/glob.c
- - glob_filename: only check directory_name for globbing chars if
- it's of non-zero length
-
-lib/sh/strchrnul.c
- - new simpler implementation
-
-subst.c
- - command_substitute: call set_shellopts after turning off errexit
- in subshells so it's reflected in $SHELLOPTS
-
- 11/7
- ----
-builtins/evalstring.c
- - parse_and_execute: treat ERREXIT case like reader_loop does: set
- variable_context to 0 before longjmping back to top_level. Don't
- run the unwind-protect context to avoid side effects from popping
- function contexts. Part of fix for problem reported by Nikolai
- Kondrashov <nikolai.kondrashov@redhat.com>
-
-execute_cmd.c
- - execute_simple_command: call unlink_fifo_list only if this is the
- last element of a pipeline (or not in a pipeline), rather than for
- every child. Fixes difference in behavior between /dev/fd and
- FIFOs reported by Zev Weiss <zev@bewilderbeest.net>
- - execute_null_command: do the same thing in the parent branch after
- make_child
-
- 11/14
- -----
-subst.c
- - parameter_brace_expand: a variable is null if it's special ($@, $*),
- the expansion occurs within double quotes, and the expansion turns
- into a quoted null. Fixes debian bug 692447 reported by
- Matrosov Dmitriy <sgf.dma@gmail.com>
-
-jobs.c
- - run_sigchld_trap: make sure `running_trap' sentinel is set
- appropriately
- - waitchld: only run the sigchld trap if we're not in a signal
- handler, not running a trap, and executing the wait builtin.
- Otherwise, queue for later handling. We still run one instance
- of the trap handler per exited child. Bulk of fix for bug
- reported by Elliott Forney <idfah@cs.colostate.edu>
-
-trap.c
- - queue_sigchld_trap: set catch_flag so run_pending_traps notices,
- and set trapped_signal_received for completeness. Rest of fix
- for bug reported by Elliott Forney <idfah@cs.colostate.edu>
-
-lib/malloc/malloc.c
- - block_signals: renamed to _malloc_block_signals, made public
- - unblock_signals: renamed to _malloc_unblock_signals, made public
-
-lib/malloc/imalloc.h
- - extern declarations for _malloc_{un,}block_signals
-
-lib/malloc/table.c
- - mregister_alloc, mregister_free: block signals around table
- manipulation
-
- 11/15
- -----
-trap.c
- - run_pending_traps: set SIG_INPROGRESS flag around calls to
- run_sigchld_handler so other parts of the shell know that the
- SIGCHLD trap handler is executing
- - run_pending_traps: if we get a situation where we are looking at
- running a SIGCHLD trap but the trap string is IMPOSSIBLE_TRAP_HANDLER
- and the SIG_INPROGRESS flag is set, just skip it. This is possible
- if run_pending_traps is called from a SIGCHLD trap handler run by
- run_sigchld_trap
-
-doc/bash.1,lib/readline/doc/{rluser.texi,readline.3}
- - corrected description of the effect of `set history-size 0'. Report
- from Vesa-Matti J Kari <vmkari@cc.helsinki.fi>
-
-include/stdc.h
- - CPP_STRING: new define, replaces __STRING
-
-lib/malloc/{malloc.c,imalloc.h}
- - replace __STRING with CPP_STRING
-
- 11/16
- -----
-lib/readline/bind.c
- - sv_histsize: if argument evaluates to a value < 0, unstifle the
- history
-
- 11/22
- -----
-redir.c
- - do_redirection_internal: if we have REDIR_VARASSIGN set in the
- redirection flags and we set up `redirector' using fcntl or dup2,
- don't add a redirect to make sure it stays open. Let the
- script programmer manage the file handle. Fixes bug reported by
- Sam Liddicott <sam@liddicott.com>
-
- 11/24
- -----
-jobs.c
- - wait_for_any_job: new function, waits for an unspecified background
- job to exit and returns its exit status. Returns -1 on no background
- jobs or no children or other errors. Calls wait_for with new
- sentinel value ANY_PID
- - wait_for: changes to handle argument of ANY_PID: don't look up or
- try to modify the child struct, only go through the wait loop once.
- Return -1 if waitpid returns no children
-
-jobs.h
- - ANY_PID: new define
-
-builtins/wait.def
- - new option: -n. Means to wait for the next job and return its exit
- status. Returns 127 if there are no background jobs (or no
- children). Feature most recently requested by Elliott Forney
- <idfah@cs.colostate.edu>
-
-doc/{bash.1,bashref.texi}
- - document new `wait -n' option
-
-execute_cmd.c
- - execute_command_internal: save make_command_string () result in a
- temp variable before calling savestring() on it; avoids evaluating
- make_command_string() result twice. Fix from John E. Malmberg
- <wb8tyw@qsl.net>
-
- 11/28
- -----
-
-builtins/declare.def
- - declare_internal: if an array variable is declared using `declare -a'
- or `declare -A', but not assigned a value, set the `invisible'
- attribute so the variable does not show up as set. Fix for bug
- about variable initialization reported by Tim Friske <me@timfriske.com>
-
-builtins/{mapfile,read}.def
- - after calling find_or_make_array_variable, make sure the invisible
- flag is turned off, in case the variable was declared previously
- using `declare -a' or `declare -A'. Side effect of above change to
- declare_internal
-
-subst.c
- - shell_expand_word_list: handle the W_ASSNGLOBAL flag and put -g into
- the list of options passed to make_internal_declare as appropriate.
- Fix for bug reported by Tim Friske <me@timfriske.com>
-
- 11/30
- -----
-test.c
- - unary_op: make sure -v and -n check that the variable is not marked
- as invisible before calling var_isset. Fix for bug reported by Tim
- Friske <me@timfriske.com>
-
- 12/2
- ----
-subst.c
- - process_substitute: turn off the `expanding_redir' flag, which
- controls whether or not variables.c:find_variable_internal uses the
- temporary environment to find variables. We want to use the
- temp environment, since we don't have to worry about order of
- evaluation in a subshell. Fixes bug reported by Andrey Borzenkov
- <arvidjaar@gmail.com>
-
- 12/4
- ----
-lib/glob/glob.c
- - glob_filename: changes to avoid null filenames and multiple entries
- returned for patterns like **/** (globstar enabled). Fixes bug
- reported by Ulf Magnusson <ulfalizer@gmail.com>
-
- 12/10
- -----
-lib/glob/glob.c
- - glob_filename: finish up a series of changes to make globstar-style
- globbing more efficient, avoid more duplicate filenames, and be more
- compatible with other shells that implement it
- o collapse a sequence of **/**/** to one **
- o note when the directory name is all ** or ends in ** so we
- can treat it specially when the filename is **
- All inspired by report from Andrey Borzenkov <arvidjaar@gmail.com>
-
-lib/sh/zread.c
- - zreadn: new function, like zread, but takes an additional argument
- saying how many bytes to read into the local buffer. Can be used to
- implement `read -N' without so many one-byte calls to zreadc. Code
- from Mike Frysinger <vapier@gentoo.org>
-
- 12/12
- -----
-lib/glob/sm_loop.c
- - PATSCAN (glob_patscan): if passed string already points to end of
- pattern, return NULL immediately. Fixes problem with
- extglob_skipname reported by Raphaël Droz <raphael.droz@gmail.com>
-
- 12/13
- -----
-execute_cmd.c
- - execute_coproc: handle the command's exit status being inverted
- (an oversight). Fixes bug reported by DJ Mills
- <danielmills1@gmail.com> and Andreas Schwab <schwab@linux-m68k.org>
-
- 12/14
- -----
-lib/readline/readline.c
- - bind_arrow_keys_internal: add MINGW key bindings for Home, End,
- Delete, and Insert keys. Fix from Pierre Muller
- <pierre.muller@ics-cnrs.unistra.fr>
-
-builtins/printf.def
- - printf_builtin: '%()T' conversion: if there is no argument supplied,
- behave as if -1 had been supplied (current time). ksh93-like feature
- suggested by Clark Wang <dearvoid@gmail.com>
-
-doc/{bash.1,bashref.texi}
- - document new printf %()T default argument behavior
-
- 12/15
- -----
-lib/readline/display.c
- - displaying_prompt_first_line: new variable, indicates whether or
- not the first line of output is displaying the prompt. Always true
- in normal mode, sometimes false in horizontal scrolling mode
- - rl_redisplay: set displaying_prompt_first_line to true unless we
- are in horizontal mode; set to false in horizontal mode if the left
- margin of the displayed line is greater than the end of the prompt
- string
- - rl_redisplay: when in horizontal scroll mode, don't adjust
- _rl_last_c_pos by the wrap offset unless the line is displaying
- a prompt containing invisible chars
- - update line: don't adjust _rl_last_c_pos by the wrap offset unless
- the line is displaying a prompt containing invisible chars
- - update_line: if shrinking the line by reducing the number of
- displayed characters, but we have already moved the cursor to the
- beginning of the line where the first difference starts, don't
- try to delete characters
-
-builtins/read.def
- - unbuffered_read: set to 2 if invoked as `read -N'
- - if unbuffered_read is set to 2, compute the number of chars we
- need to read and read that many with zreadn. Posix mode still
- uses zreadintr. Code from Mike Frysinger <vapier@gentoo.org>
-
-doc/{bash.1,bashref.texi}
- - read: make it clear that if read times out, it saves any input
- read to that point into the variable arguments. Report from
- Fiedler Roman <Roman.Fiedler@ait.ac.at>
-
-subst.c
- - command_substitute: change direct assignment of exit_immediately_on_error
- to use change_flag ('e', FLAG_OFF) instead
-
-flags.c
- - use errexit_flag as the variable modified by changes to the -e
- option, reflect those changes to exit_immediately_on_error
-
-execute_cmd.c
- - execute_builtin: new global variable, builtin_ignoring_errexit, set
- to 0 by default and set to 1 if eval/source/command executing in a
- context where -e should be ignored
- - execute_builtin: set exit_immediately_on_error to errextit_flag
- after executing eval/source/command in a context where -e should
- be ignored
-
-flags.c
- - if builtin_ignoring_errexit is set, changes to errexit_flag are
- not reflected in the setting of exit_immediately_on_error. Fixes
- bug reported by Robert Schiele <rschiele@gmail.com>
-
- 12/23
- -----
-include/posixjmp.h
- - setjmp_nosigs: new define, call setjmp in such a way that it will
- not manipulate the signal mask
-
-{expr,test,trap}.c
- - setjmp_nosigs: call instead of setjmp; don't need to manipulate
- signal mask
-
-builtins/read.def
- - read_builtin: setjmp_nosigs: call instead of setjmp; don't need
- to manipulate signal mask
-
-builtins/evalstring.c:
- - parse_and_execute: setjmp_nosigs: call instead of setjmp; don't need
- to manipulate signal mask
- - parse_string: setjmp_nosigs: call instead of setjmp; don't need
- to manipulate signal mask
- - parse_and_execute: save and restore the signal mask if we get a
- longjmp that doesn't cause us to return or exit (case DISCARD)
-
- 12/24
- -----
-general.c
- - bash_tilde_expand: only set interrupt_immediately if there are no
- signals trapped; we want to jump to top level if interrupted but
- not run any trap commands
-
- 12/25
- -----
-jobs.c
- - run_sigchld_trap: no longer set interrupt_immediately before calling
- parse_and_execute, even if this is no longer run in a signal handler
- context
-
-input.c
- - getc_with_restart: add call to QUIT instead of CHECK_TERMSIG
-
-parse.y
- - yy_stream_get: now that getc_with_restart calls QUIT, don't need to
- set interrupt_immediately (already had call to run_pending_traps)
-
-execute_cmd.c
- - execute_subshell_builtin_or_function,execute_function,execute_in_subshell:
- setjmp_nosigs: call instead of setjmp when saving return_catch; don't
- need to manipulate signal mask
- - execute_subshell_builtin_or_function,execute_in_subshell:
- setjmp_nosigs: call instead of setjmp where appropriate when saving
- top_level; don't need to manipulate signal mask if we're going to
- exit right away
-
-subst.c
- - command_substitute: setjmp_nosigs: call instead of setjmp when saving
- return_catch; don't need to manipulate signal mask
- - command_substitute: setjmp_nosigs: call instead of setjmp where
- appropriate when saving top_level; don't need to manipulate signal
- mask if we're going to exit right away
-
-trap.c
- - run_exit_trap: setjmp_nosigs: call instead of setjmp when saving
- return_catch; don't need to manipulate signal mask
- - run_exit_trap: setjmp_nosigs: call instead of setjmp where
- appropriate when saving top_level; don't need to manipulate signal
- mask if we're going to exit right away
- - _run_trap_internal: setjmp_nosigs: call instead of setjmp when saving
- return_catch; don't need to manipulate signal mask
-
-builtins/evalfile.c
- - _evalfile: setjmp_nosigs: call instead of setjmp when saving
- return_catch; don't need to manipulate signal mask
-
-builtins/evalstring.c
- - evalstring: setjmp_nosigs: call instead of setjmp when saving
- return_catch; don't need to manipulate signal mask
-
-shell.c
- - main: setjmp_nosigs: call instead of setjmp where appropriate when
- saving top_level; don't need to manipulate signal mask if we're
- going to exit right away
- - run_one_command: setjmp_nosigs: call instead of setjmp where
- appropriate when saving top_level; don't need to manipulate signal
- mask if we're going to exit right away
- - run_wordexp: setjmp_nosigs: call instead of setjmp where
- appropriate when saving top_level; don't need to manipulate signal
- mask if we're going to exit right away
-
-eval.c
- - reader_loop: save and restore the signal mask if we get a longjmp
- that doesn't cause us to return or exit (case DISCARD)
-
- 12/26
- -----
-parse.y
- - shell_input_line_{index,size,len}: now of type size_t; in some cases
- the unsigned property makes a difference
- - STRING_SAVER: saved_line_{size,index} now of type size_t
- - shell_getc: don't allow shell_input_line to grow larger than SIZE_MAX;
- lines longer than that are truncated until read sees a newline;
- addresses theoretical buffer overflow described by Paul Eggert
- <eggert@cs.ucla.edu>
- - set_line_mbstate: size_t changes like shell_getc
- - shell_getc: if shell_input_line is larger than 32K, free it and
- start over to avoid large memory allocations sticking around
-
-variables.c
- - bind_global_variable: new function, binds value to a variable in
- the global shell_variables table
-
-variables.h
- - bind_global_variable: new extern declaration
-
-builtins/declare.def
- - declare_internal: if -g given with name=value, but variable is not
- found in the global variable table, make sure to call
- bind_global_variable so the variable is created and modified at
- global scope. Fixes a bug where declare -g x=y could modify `x'
- at a previous function scope
-
-command.h
- - W_ASSIGNARRAY: new word flag, compound indexed array assignment
-
-subst.h
- - ASS_MKGLOBAL: new assignment flag, forcing global assignment even in
- a function context, used by declare -g
-
-execute_cmd.c
- - fix_assignment_words: set W_ASSIGNARRAY flag if -a option given to
- declaration builtin
-
-subst.c
- - do_assignment_internal: explicitly handle case where we are
- executing in a function and we want to create a global array or
- assoc variable
- - shell_expand_word_list: call make_internal_declare if -a option
- given to declaration builtin (W_ASSIGNARRAY); handle -g option with
- it (W_ASSNGLOBAL). Fixes inconsistency noticed by Vicente Couce
- Diaz <vituko@gmail.com>, where declare -ag foo=(bar) could modify
- array variable foo at previous function scope, not global scope
-
- 12/27
- -----
-bashline.c
- - Minix needs the third argument to tputs to be a void funtion taking
- an int argument, not an int-returning function. Fix from
- John E. Malmberg <wb8tyw@qsl.net> as part of VMS bash port
-
- 12/29
- -----
-configure.ac,version.c,patchlevel.h
- - bash-4.3-devel: new version, new shell compatibility level (43)
-
-subst.c
- - parameter_brace_patsub: put the bash-4.2 code back in from the
- change of 3/3 that runs the replacement string through quote
- removal, make it dependent on shell_compatibility_level <= 42
-
-builtins/shopt.def
- - compat42: new shopt option
- - set_compatibility_level: change logic to set and unset various
- compat variables and shell_compatibility_level
-
-COMPAT
- - new documentation for bash-4.3 compatibility changes
-
-doc/{bash.1,bashref.texi}
- - compat42: document new shopt option
-
-builtins/shopt.def
- - set_compatibility_opts: new function, sets the various shopt
- compat variables based on the value of shell_compatibility_level
-
-builtins/common.h
- - set_compatibility_opts: new extern declaration
-
-variables.c
- - BASH_COMPAT: new special variable; sets the shell compatibility
- level. Accepts values in decimal (4.2) or integer (42) form;
- Unsetting variable, setting it to empty string, or setting it to
- out-of-range value sets the shell's compatibility level to the
- default for the current version. Valid values are 3.1/31 through
- the current version
- - sv_shcompat: new function implementing logic for BASH_COMPAT
-
-variables.h
- - sv_shcompat: new extern declaration
-
-doc/{bash.1,bashref.texi}
- - BASH_COMPAT: description of new variable
-
-lib/readline/complete.c
- - _rl_colored_stats: default back to 0 for 4.3 release branch
-
- 1/5/2013
- --------
-quit.h
- - remove spurious call to itrace in CHECK_WAIT_INTR
-
-bashline.c
- - bash_event_hook: if we're going to jump to top_level, make sure we
- clean up after readline() by calling rl_cleanup_after_signal().
- Fixes bug reported against devel branch by Raphaël Droz
- <raphael.droz@gmail.com>
- - bash_event_hook: reset the event hook before checking for signals
- or traps in case we longjmp
-
-doc/{bash.1,bashref.texi}
- - small additions to the set -e section to make it more clear that
- contexts where -e is ignored extend to compound commands as well
- as shell functions
-
-lib/readline/readline.h
- - rl_signal_event_hook: new extern declaration
-
-lib/readline/input.c
- - rl_signal_event_hook: new variable, hook function to call when a
- function (currently just read(2)) is interrupted by a signal and
- not restarted
- - rl_getc: call rl_signal_event_hook instead of rl_event_hook
-
-lib/readline/doc/rltech.texi
- - rl_signal_event_hook: document new function
-
-bashline.c
- - changes to set rl_signal_event_hook instead of rl_event_hook
-
-lib/readline/readline.h
- - change readline version numbers to 6.3
-
- 1/6
- ---
-doc/{bash.1,bashref.texi}
- - a couple of changes to the descriptions of the ERR trap and its
- effects based on a message from Rob Nagler <nagler@bivio.biz>
-
- 1/9
- ---
-expr.c
- - expassign: invalidate curlval before freeing and NULLing tokstr to
- avoid aliasing issues. Fixes bug reported by Eduardo A. Bustamante
- López<dualbus@gmail.com> and Dan Douglas <ormaaj@gmail.com>
-
-braces.c
- - array_concat: don't be so aggressive in trying to short-circuit. We
- can only short-circuit if we have a single-element array where the
- element is an empty string (array[0] == "" array[1] = 0x0). Existing
- practice requires us to replicate arrays and prefix or append empty
- strings. Fixes bug reported by Eduardo A. Bustamante López
- <dualbus@gmail.com>
-
- 1/11
- ----
-execute_cmd.c
- - execute_builtin: since mapfile uses evalstring() to run its callbacks
- internally, just like eval, so it needs to handle the case where the
- temp environment given to mapfile persists throughout the entire
- set of callback commands. This might be a problem with trap also, but
- trap isn't run in the same way. Fixes bug reported by Dan Douglas
- <ormaaj@gmail.com>
-
- 1/13
- ----
-redir.c
- - redirection_error: before expanding the redirection word (if
- expandable_redirection_filename returns true), disable command
- substitution during expansion. Fixes bug reported by Dan Douglas
- <ormaaj@gmail.com>
-
-subst.c
- - expand_word_internal: case '\\': if the next character is an IFS
- character, and the expansion occurs within double quotes, and the
- character is not one for which backslash retains its meaning, add
- the (escaped) '\' and the (escaped) character. Fixes bug reported
- by Dan Douglas <ormaaj@gmail.com>
-
- 1/15
- ----
-builtins/cd.def
- - cd_builtin: make sure call to internal_getopt handles -e option.
- Fixes bug reported by <mashimiao.fnst@cn.fujitsu.com>
-
- 1/17
- ----
-subst.c
- - expand_word_list_internal: make sure tempenv_assign_error is
- initialized to 0
-
-execute_cmd.c
- - execute_simple_command: make sure tempenv_assign_error is reset to 0
- after it's tested to see if an error should force the shell to exit.
- Fixes problem where a the failure of a tempenv assignment preceding
- a non-special builtin `sticks' and causes the next special builtin
- to exit the shell. From a discussion on bug-bash started by
- douxin <wq-doux@cn.fujitsu.com>
-
- 1/20
- ----
-subst.c
- - parameter_brace_expand_rhs: call stupidly_hack_special_variables
- after assigning with ${param[:]=word} even if IFS is changing.
- Suggested by Dan Douglas <ormaaj@gmail.com> [TENTATIVE, needs work
- on IFS side effects]
-
-command.h
- - W_GLOBEXP (which was unused) is now W_SPLITSPACE (which isn't used
- yet)
-
-{execute_cmd,subst,variables}.c
- - removed all code that mentioned W_GLOBEXP
- - removed mention of gnu_argv_flags and code that set it
-
- 1/22
- ----
-subst.c
- - param_expand: set W_SPLITSPACE if we expand (unquoted) $* and
- IFS is unset or null so we can be sure to split this on spaces
- no matter what happens with IFS later
- - expand_word_internal: note that param_expand returns W_SPLITSPACE
- in the returned word flags and keep track of that state with
- `split_on_spaces'
-
- 1/23
- ----
-subst.c
- - expand_word_internal: if split_on_spaces is non-zero, make sure
- we split `istring' on spaces and return the resultant word. The
- previous expansions should have quoted spaces in the positional
- parameters where necessary. Suggested by Dan Douglas
- <ormaaj@gmail.com>
-
-execute_cmd.c
- - execute_command_internal: make sure any subshell forked to run a
- group command or user subshell at the end of a pipeline runs any
- EXIT trap it sets. Fixes debian bash bug 698411
- http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=698411
-
-subst.c
- - shell_expand_word_list: fix code that creates args for and calls
- make_internal_declare to avoid calling it twice (missing `else'
- in 12/26 change)
- - do_assignment_internal: fix code from 12/26 change to fix problem
- where an existing assoc variable could be converted to an array
- without checking `mkassoc'
-
- 1/24
- ----
-builtins/evalfile.c
- - _evalfile: add missing `close (fd)' calls before returning to
- avoid fd leaks. Bug and fix from Roman Rakus <rrakus@redhat.com>
-
- 1/25
- ----
-builtins/read.def
- - read_builtin: don't try to play tricks with the top of the unwind-
- protect stack after read gets a SIGALRM; save input_string to new
- memory, run the stack, then restore input_string and assign the
- variables. Part of fix for bug reported by konsolebox
- <konsolebox@gmail.com>; the rest of the fix is with the changes in
- trap and signal handling and doing away with interrupt_immediately
-
- 1/26
- ----
-redir.c
- - redirection_expand, write_here_string, write_here_document: before
- calling any of the word expansion functions, after setting
- expanding_redir to 1 (which bypasses the temp environment in the
- variable lookup functions), call sv_ifs to reset the cached IFS-
- related variables set by subst.c:setifs(). This ensures that
- redirections will not get any IFS values that are set in the
- temporary environment, as Posix specifies. Then, after the word
- expansions, after resetting expanding_redir to 0, call sv_ifs
- again to make sure the cached IFS values are set from any
- assignments in the temporary environment. We force executing_builtin
- to 1 to `fool' the variable lookup functions into using any temp
- environment, then reset it to its old value after sv_ifs returns.
- This is what allows read() to use the (cached) IFS variables set
- in the temp environment. Fixes inconsistency reported by Dan Douglas
- <ormaaj@gmail.com>
-
- 1/29
- ----
-lib/readline/display.c
- - update_line: fix off-by-one error when updating vis_lbreaks array
- in a multibyte locale that occurs when moving multibyte chars from
- one line down to another. Bug report and fix from Egmont
- Koblinger <egmont@gmail.com>
-
- 1/30
- ----
-configure.ac
- - changed version to 4.3-alpha
-
-redir.c
- - redir_open: handle open returning -1/EINTR, which seems to happen
- a lot with FIFOs and SIGCHLD, and call QUIT to handle other
- signals that can interrupt open(2). Bug report and initial fix
- from Mike Frysinger <vapier@gentoo.org>
-
- 1/31
- ----
-subst.c
- - parameter_brace_expand: make sure to propagate the PF_ASSIGNRHS flag
- to parameter_brace_expand_word
- - parameter_brace_expand_word: make sure that if the PF_ASSIGNRHS flag
- is set and we are expanding ${a[@]} or ${a[*]} we set quoted to
- include Q_DOUBLE_QUOTES before calling array_value_internal, mirroring
- what we do for $@ and $*. Fixes inconsistency reported by Dan
- Douglas <ormaaj@gmail.com>
-
-configure.ac
- - use AC_CHECK_TOOL instead of AC_CHECK_PROG to check for ar, since it
- will find $host-prefixed versions of utilities. Report and fix from
- Mike Frysinger <vapier@gentoo.org>
-
-builtins/setattr.def
- - set_var_attribute: check whether bind_variable (called when the
- variable whose attributes are being modified is found in the temp
- environment) just modified a read-only global variable, and don't
- bother marking the temporary variable for propagation if so. The
- propagation is superfluous and will result in a strange error
- message
-
- 2/2
- ---
-variables.c
- - initialize_shell_variables: don't try to import function definitions
- with invalid names from the environment if already in posix mode,
- but create them as (invisible) exported variables so they pass
- through the environment. Print an error message so user knows
- what's wrong. Fixes bug reported by Tomas Trnka <ttrnka@mail.muni.cz>
-
- 2/9
- ---
-
-builtins/read.def
- - sigalrm_seen, alrmbuf: now global so the rest of the shell (trap.c)
- can use them
- - sigalrm: just sets flag, no longer longjmps to alrmbuf; problem was
- longjmp without manipulating signal mask, leaving SIGALRM blocked
-
-quit.h
- - move CHECK_ALRM macro here from builtins/read.def so trap.c:
- check_signals() can call it
-
-trap.c
- - check_signals: add call to CHECK_ALRM before QUIT
- - check_signals_and_traps: call check_signals() instead of including
- CHECK_ALRM and QUIT inline. Integrating check for read builtin's
- SIGALRM (where zread call to check_signals_and_traps can see it)
- fixes problem reported by Mike Frysinger <vapier@gentoo.org>
-
- 2/12
- ----
-lib/glob/xmbsrtowcs.c
- - xdupmbstowcs2: fixed but where end of string was not handled
- correctly, causing loop to go past end of string in a bunch of cases.
- Fixes bug reported by "Dashing" <dashing@hushmail.com>
-
-
- 2/13
- ----
-builtins/pushd.def
- - popd_builtin: treat any argument that isn't -n or of the form
- [-+][[:digit:]]* as an error. Fixes problem reported by Bruce
- Korb <bruce.korb@gmail.com>
-
- 2/14
- ----
-configure.ac
- - add check for sig_atomic_t; already a placeholder for it in
- config.h.in
-
- 2/15
- ----
-subst.c
- - do_compound_assignment: don't call assign_compound_array_list with
- a NULL variable in case make_local_xxx_variable returns NULL
- (it will if you try to shadow a readonly or noassign variable).
- Fixes bug reported by Richard Tollerton <rich.tollerton@ni.com>
-
- 2/16
- ----
-variables.c
- - make_local_variable: print error messager if an attempt is made to
- create a local variable shadowing a `noassign' variable. Previously
- we just silently refused to do it
-
-trap.[ch]
- - get_original_signal: now global so rest of the shell can use it
-
-sig.c
- - initialize_shell_signals: install a signal handler for SIGTERM
- that does nothing except set a sigterm_received flag instead of
- ignoring it with SIG_IGN, as long as SIGTERM is not ignored when
- the shell is started. Use get_original_signal early to get the
- original handler, since we will do that later anyway
- - set_signal_handler: if installing sigterm_sighandler as the SIGTERM
- handler, make sure to add SA_RESTART flag to make it as close to
- SIG_IGN as possible
-
-sig.h
- - sigterm_sighandler: new extern declaration
-
-quit.h
- - RESET_SIGTERM: set sigterm_receved to 0
- - CHECK_SIGTERM: check sigterm_received; if it's non-zero, treat it
- as a fatal signal and call termsig_handler to exit the shell
-
-jobs.c
- - make_child: call RESET_SIGTERM just before fork() so we can detect
- if the child process received a SIGTERM before it's able to change
- the signal handler back to what it was when the shell started
- (presumably SIG_DFL). Only has effect if the shell installed
- sigterm_sighandler for SIGTERM, interactive shells that were not
- started with SIG_IGN as the SIGTERM handler
- - make_child: call RESET_SIGTERM in the parent after fork() so the
- rest of the shell won't react to it
-
-execute_cmd.c
- - execute_simple_command: call CHECK_SIGTERM after make_child in child
- to catch SIGTERM received after fork() and before restoring old
- signal handlers
- - execute_disk_command: call CHECK_SIGTERM after make_child in child
- process after restoring old signal handlers and again just before
- calling shell_execve. Fixes race condition observed by
- Padraig Brady <p@draigbrady.com> when testing with his `timeout'
- program
-
-lib/readline/display.c
- - open_some_spaces: new function, subset of insert_some_chars that just
- opens up a specified number of spaces to be overwritten
- - insert_some_spaces: now just calls to open_some_spaces followed by
- _rl_output_some_chars
- - update_line: use col_temp instead of recalculating it using
- _rl_col_width in the case where we use more columns with fewer bytes
- - update_line: use open_some_spaces and then output the right number
- of chars instead of trying to print new characters then overwrite
- existing characters in two separate calls. This includes removing
- some dodgy code and making things simpler. Fix from Egmont
- Koblinger <egmont@gmail.com>
- - use new variable `bytes_to_insert' instead of overloading temp in
- some code blocks (nls - nfd, bytes that comprise the characters
- different in the new line from the old)
-
- 2/18
- ----
-redir.c
- - do_redirection_internal: add undoable redirection for the implicit
- close performed by the <&n- and >&n- redirections. Fixes bug
- reported by Stephane Chazelas <stephane.chazelas@gmail.com>
-
- 2/19
- ----
-sig.c
- - termsig_handler: an interactive shell killed by SIGHUP and keeping
- command history will try to save the shell history before exiting.
- This is an attempt to preserve the save-history-when-the-terminal-
- window-is-closed behavior
-
- 2/21
- ----
-braces.c
- - brace_expand: if a sequence expansion fails (e.g. because the
- integers overflow), treat that expansion as a simple string, including
- the braces, and try to process any remainder of the string. The
- remainder may include brace expansions. Derived from SuSE bug
- 804551 example (https://bugzilla.novell.com/show_bug.cgi?id=804551)
-
- 2/23
- ----
-{quit,sig}.h,sig.c
- - sigterm_received declaration now in sig.h; type is sig_atomic_t
- - sigwinch_received type now sig_atomic_t
- - sig.h includes bashtypes.h and <signal.h> if SIG_DFL not defined
- (same logic as trap.h) to pick up sig_atomic_t
-
-unwind_prot.c
- - include sig.h before quit.h (reverse order)
-
- 2/27
- ----
-builtins/shopt.def
- - reset_shopt_options: make sure check_window_size is reset to the
- default from config.h, not unconditionally to 0
-
-jobs.[ch]
- - last_made_pid, last_asynchronous_pid: now volatile. Change from SuSE
-
-jobs.c
- - wait_for: if we're using sigaction to install a handler for SIGCHLD,
- make sure we specify SA_RESTART
-
-lib/{tilde,readline}/shell.c
- - get_home_dir: instead of looking in the password file every time,
- look once and cache the result
-
-sig.[ch]
- - sigwinch_received, sigterm_received: now `volatile' qualified
-
-sig.c,quit.h
- - interrupt_state,terminating_signal: now sig_atomic_t
-
- 3/1
- ---
-MANIFEST,examples/*
- - removed around 120 files without FSF copyrights; requested by
- Karl Berry in early January
-
- 3/2
- ---
-lib/malloc/malloc.c
- - morecore: only check whether SIGCHLD is trapped if SIGCHLD is defined
-
-doc/bashref.texi
- - Fixed most of the examples in the GNU Parallel section to use better
- shell idioms following complaints on bug-bash; added a couple of
- examples and smoothed out the text
-
-quit.h
- - include "sig.h" for sig_atomic_t
-
-lib/readline/display.c
- - update_line: when inserting one or more characters at the end of
- the display line in a non-multibyte environment, just write from the
- first difference to the end of the line and return. We don't have
- to adjust _rl_last_c_pos. This is needed to adjust from the old
- two-part copy to a single call to _rl_output_some_chars (change of
- 2/16)
-
- 3/4
- ---
-Makefile.in,doc/Makefile.in
- - PACKAGE_TARNAME, docdir: new variables substituted by autoconf
- - OTHER_DOCS,OTHER_INSTALLED_DOCS: new variables with auxiliary
- documentation files to be installed into $(docdir)
- - install: add new rule to install $(OTHER_DOCS)
- - uninstall: add new rule to uninstall $(docdir)/$(OTHER_INSTALLED_DOCS)
-
-doc/bash.1
- - add URL to `POSIX' file in `SEE ALSO' section; put pointer to that
- section in --posix and set -o posix descriptions
-
-examples/
- - removed around 110 examples at the request of the FSF due to copyright
- issues
-
- 3/5
- ---
-builtins/setattr.def
- - readonly: modified help text slightly to make it clearer that
- functions aren't changed or displayed unless the -f option is given.
- Report from <gotmynick@gmail.com>
-
- 3/9
- ---
-include/typemax.h
- - SIZE_MAX: define to 65535 (Posix minimum maximum) if not defined
-
-parse.y
- - include "typemax.h" for possible SIZE_MAX definition, make sure we
- include it after shell.h
-
-{braces,expr}.c
- - include "typemax.h" for possible INTMAX_MIN and INTMAX_MAX definitions
-
- 3/10
- ----
-bashline.c
- - bash_default_completion: make sure completion type of `!' (same as
- TAB but with show-all-if-ambiguous set) and glob-word-completion
- sets rl_filename_completion_desired to 0 so extra backslashes don't
- get inserted by `quoting' the completion. We can't kill all the
- matches because show-all-if-ambiguous needs them. Bug report from
- Marcel (Felix) Giannelia <info@skeena.net>
-
-[bash-4.3-alpha frozen]
-
- 3/14
- ----
-general.c
- - trim_pathname: use memmove instead of memcpy since the source and
- destination pathnames may overlap. Report and fix from Matthew
- Riley <mattdr@google.com>
-
- 3/18
- ----
-configure.ac
- - socklen_t is defined as `unsigned int' if configure can't find it
-
- 3/20
- ----
-lib/readline/complete.c
- - S_ISVTX: since it's not defined on all platforms (Minix), make sure
- its use is protected with #ifdef
-
- 3/21
- ----
-doc/{bash.1,bashref.texi}
- - Added mention of ${!name[@]} and ${!name[*]} expansions to get all
- indices of an array. Suggested by Jonathan Leffler
- <jonathan.leffler@gmail.com>
-
- 3/24
- ----
-subst.h
- - SD_IGNOREQUOTE: new define for skip_to_delim; if set, means that
- single quotes (for now) will be treated as ordinary characters
-
-subst.c
- - skip_to_delim: handle SD_IGNOREQUOTE. no callers use it for now
-
- 3/25
- ----
-support/config.{guess,sub}
- - updated to versions from autoconf-2.69
-
- 3/31
- ----
-lib/sh/shquote.c
- - sh_single_quote: short-circuit quoting a single "'" instead of
- creating a long string with empty single-quoted strings
-
-parser.h
- - DOLBRACE_QUOTE2: new define, like DOLBRACE_QUOTE, but need to single-
- quote results of $'...' expansion because quote removal will be
- done later. Right now this is only done for ${word/pat/rep}
-
-parse.y
- - parse_matched_pair: set state to DOLBRACE_QUOTE2 for pattern
- substitution word expansion so we don't treat single quote specially
- in the pattern or replacement string
- - parse_matched_pair: if we're parsing a dollar-brace word expansion
- (${...}) and we're not treating single quote specially within
- double quotes, single-quote the translation of $'...' ansi-c
- escaped strings. Original report and fix from Eduardo A.
- Bustamante López <dualbus@gmail.com>
-
-subst.c
- - extract_dollar_brace_string: ${word/pat/rep} scanning now sets the
- DOLBRACE_QUOTE2 flag instead of DOLBRACE_QUOTE so we don't treat
- single quotes specially within a double-quoted string
-
-execute_cmd.c
- - fix_assignment_words: skip over assignment statements preceding a
- command word before trying to figure out whether or not assignment
- statements following a possible declaration command should be
- treated specially. Fixes bug reported by Dan Douglas
- <ormaaj@gmail.com>
-
- 4/4
- ---
-lib/readline/readline.c
- - _rl_dispatch_subseq: only call _rl_vi_set_last (and check whether
- the key is a text modification command) if the key sequence length
- is 1. That keeps the arrow keys from setting the last command
- when called in vi command mode. Fixes bug reported by Ian A.
- Watson <watson_ian_a@lilly.com>
-
- 4/6
- ---
-lib/readline/bind.c
- - rl_parse_and_bind: when parsing a double-quoted string as the value
- of a variable, make sure we skip past the leading double quote.
- Fix from Andreas Schwab <schwab@linux-m68k.org>
-
-variables.c
- - hash_lookup: set new local variable last_table_searched to the table
- a successful lookup appears in; tested in make_local_variable to
- solve the problem below
- - make_local_variable: if we find a variable with the tempenv flag
- set at the same `level' as variable_context', but not found in the
- temporary_env (temp environment preceding the builtin), return it.
- The temp environment preceding the function call has already been
- merged (in execute_function) into the list of variable contexts the
- function sees as shell_variables by the time this is called. Fixes
- inconsistency pointed out by Dan Douglas <ormaaj@gmail.com>
-
-subst.c
- - expand_arith_string: expanded out contents of expand_string,
- expand_string_internal, expand_string_if_necessary to create a
- WORD_DESC and call call_expand_word_internal() on it directly.
- We don't want process substitution to be performed ( 1<(2) ) should
- mean something different in an arithmetic expression context.
- It doesn't work to just turn on the DQUOTE flag, since that means
- that things like ${x["expression"]} are not expanded correctly.
- Fixes problem pointed out by Dan Douglas <ormaaj@gmail.com>
-
- 4/13
- ----
-subst.c
- - process_substitute: run the EXIT trap before exiting, as other
- shells seem to. Fixes problem pointed out by Dan Douglas
- <ormaaj@gmail.com>
-
-lib/readline/readline.c
- - readline_internal_setup: call rl_vi_insertion_mode to enter vi
- mode instead of rl_vi_insert_mode to avoid resetting the saved last
- command information. Posix says that `.' can repeat a command
- that was entered on a previous line so we need to save the info.
- Fixes bug reported by Ian A. Watson <watson_ian_a@lilly.com>
-
- 4/14
- ----
-lib/readline/complete.c
- - rl_completion_matches: make sure xrealloc returns something non-null
- (can happen when interrupted by a signal) before trying to add
- matches to match_list
-
-subst.c
- - array_remove_pattern: return NULL right away if array_variable_part
- returns an invisible variable
- - array_length_reference: handle array_variable_part returning an
- invisible variable
- - get_var_and_type: handle array_variable_part returning an invisible
- variable
-
- 4/15
- ----
-execute_cmd.c
- - execute_command_internal: make sure to run the EXIT trap for group
- commands anywhere in pipelines, not just at the end. From a point
- raised by Andreas Schwab <schwab@linux-m68k.org>
-
-variables.c
- - bind_int_variable: make sure invisible flag is unset. Fixes problems
- like "declare -ai a; : $(( a[4]=4 ));"
-
-arrayfunc.c
- - array_variable_part: return variable even if invisible flag set,
- callers must handle invisible vars
-
- 4/18
- ----
-builtins/set.def
- - unset_builtin: if -n flag given, call unset_nameref instead of
- unset_variable
-
-variables.c
- - find_variable_nameref: print warning message if nameref circular
- reference detected, return NULL and let caller deal with it
-
-builtins/declare.def
- - declare_builtin: only disallow global references at this point if
- we are at the global scope
-
- 5/16
- ----
-configure.ac
- - update release status to beta
-
- 5/23
- ----
-trap.c
- - run_pending_traps: save and restore pipeline around calls to
- evalstring() in case we get a trap while running a trap. Have to
- figure out the recursive running traps issue elsewhere. Fixes
- bug reported by Roman Rakus <rrakus@redhat.com>
- - run_pending_traps: make sure to set running_trap to the appropriate
- signal value when running a trap command
- - run_pending_traps: short-circuit immediately if running_trap set
- when invoked. Could change this later to only skip if it would
- run the same trap as currently being run (running_trap == sig + 1)
-
-configure.ac
- - add warning if bison not found
-
-lib/readline/doc/rltech.texi
- - new section with an example program illustrating the callback
- interface. Suggested by Peng Yu <pengyu.ut@gmail.com>
-
-examples/loadables/Makefile.in
- - remove references to `cut' and `getconf', which were removed in
- early March
-
- 5/28
- ----
-lib/sh/pathphys.c
- - sh_realpath: correct inverted two arguments to call to sh_makepath.
- Report and fix from Julien Thomas <jthomas@exosec.fr>
-
- 6/7
- ---
-execute_cmd.c
- - executing_line_number: the else clauses that are conditional on
- various options being defined can simply be if clauses -- they are
- mutually exclusive and all have `return' in the body. Fixes bug
- reported by Flavio Medeiros <flaviomotamedeiros@gmail.com>
-
- 6/25
- ----
-lib/readline/readline.c
- - readline_internal_setup: only sent the meta-key enable string to the
- terminal if we've been told to use one and the terminal has been
- successfully initialized (RL_ISSTATE (RL_STATE_TERMPREPPED) != 0).
- Suggested by Dan Mick <dan.mick@inktank.com>
-
-lib/readline/signals.c
- - _rl_signal_handler: call any defined signal hook after calling
- rl_resize_terminal when handling a SIGWINCH. We already have called
- the original SIGWINCH handler but will not be resending the signal
- to ourselves
-
- 6/27
- ----
-lib/readline/doc/history.3, doc/bash.1
- - fix description of the `$' modifier to note that it expands to the
- last *word*, which is not always the last argument. Report from
- ariyetz@gmail.com via gnu.org RT
-
- 6/29
- ----
-lib/glob/smatch.c
- - glob_asciiranges: initialize to value of GLOBASCII_DEFAULT instead
- of 0 (0 if not defined)
-
-configure.ac,config.h.in
- - --enable-glob-asciiranges-default: new option, controls the value of
- GLOBASCII_DEFAULT; use it to turn globasciiranges shopt option on
- by default
-
-doc/bashref.texi
- - document new --enable-glob-asciiranges-default configure option
-
-variables.c
- - assign_in_env: implement += value appending semantics for assignments
- preceding command names
-
- 7/4
- ---
-expr.c
- - set lasttok = NUM in all of the functions that result in a number,
- even if it's a boolean, to avoid errors with constructs like
- 1 * x = 1, which should be an asignment error. Fixes problem
- pointed out by Dan Douglas <ormaaj@gmail.com>
-
-parse.y
- - decode_prompt_string: don't bother to call strcpy if
- polite_directory_format returns its argument unchanged. It's not
- necessary and Mac OS X 10.9 aborts because of a supposed overlapping
- string copy. Bug and fix from simon@hitzemann.org
-
-subst.c
- - parameter_brace_find_indir: new function, code from
- parameter_brace_expand_indir that looks up the indirectly-referenced
- variable, but does not expand it
- - parameter_brace_expand_indir: call parameter_brace_find_indir to
- look up indirected variable reference
- - get_var_and_type: call parameter_brace_find_indir if it looks like we
- are trying to manipulate an indirect variable reference like
- ${!b%%foo}. This makes a difference if !b references an array
- variable. Bug report from Dan Douglas <ormaaj@gmail.com>
-
- 7/6
- ---
-lib/sh/casemod.c
- - sh_modcase: make sure argument passed to is_basic is <= UCHAR_MAX,
- since cval can convert something to a wchar_t greater than UCHAR_MAX.
- Fixes bug reported by Tomasz Tomasik <scx.mail@gmail.com>
-
- 7/8
- ---
-lib/readline/history.c
- - add_history_time: if history_length == 0, referencing history_length
- - 1 will result in an array bounds error, so make history_length be
- at least 1 before going on. Fixes bug reported by Geng Sheng Liu
- <gsliu.tju@gmail.com>
-
-builtins/setattr.def
- - show_func_attributes: display definition (if NODEFS argument is 0) and
- attributes for a particular function; used by `declare -fp name'
-
-builtins/declare.def
- - declare_internal: call show_func_attributes if -f supplied with -p.
- Fixes inconsistency observed by Linda Walsh <bash@tlinx.org>
-
-builtins/common.h
- - new extern declaration for show_func_attributes
-
-builtins/read.def
- - read_builtin: check the first supplied variable name for validity
- before attempting to read any input, since we know we will have to
- at least use that one. Don't check any other names yet. Suggested
- by jidanni@jidanni.org
-
- 7/10
- ----
-redir.c
- - do_redirection_internal: when closing a file descriptor with
- r_close_this ([n]<&-) count close errors as redirection errors if
- errno ends up as EIO or ENOSPC. Originally reported back in April
- 2012 by Andrey Zaitsev <jstcdr@gmail.com>
-
- 7/11
- ----
-redir.c
- - do_redirection_internal: before calling check_bash_input, make sure
- that we don't call check_bash_input for an asynchronous process that
- is replacing stdin with something else. The seek backwards affects
- the parent process as well, since parents and children share the
- file pointer. Fixes problem originally reported in March 2013 by
- Martin Jackson <mjackson220.list@gmail.com>
-
- 7/13
- ----
-doc/{bash.1,bashref.texi}
- - slight change to add a description of `shopt -o' suggested by Bruce
- Korb <bruce.korb@gmail.com>
-
- 7/19
- ----
-lib/readline/histfile.c
- - history_do_write: if close returns < 0, make sure we restore the
- backup history file and return a non-zero value
- - history_truncate_file: if write or close return < 0, make sure we
- return a non-zero value
-
-[bash-4.3-beta frozen]
-
- 7/21
- ----
-lib/readline/isearch.c
- - rl_display_search: now takes an entire search context flags word as
- the second argument, instead of just reverse flag; changed callers
- - rl_display_search: if the search has failed, add `failed ' to the
- beginning of the search prompt
- - _rl_isearch_dispatch: if the search has failed, display the entire
- search string with an indication that the search failed but with the
- last matching line. Suggested by jidanni@jidanni.org
-
-command.h
- - W_ASSIGNINT: new word flag; used internally for make_internal_declare
- and set by fix_assignment_words
-
-execute_cmd.c
- - fix_assignment_words: set W_ASSIGNINT if compound assignment and -i
- given as option. We don't do anything with the value yet
-
-subst.c
- - shell_expand_word_list: rework the way the option list that is
- passed to make_internal_declare is created
-
- 8/1
- ---
-doc/{bash.1,bashref.texi}
- - minor changes to description of $! based on a report from Chris
- Down <chris@chrisdown.name>
-
-arrayfunc.c
- - assign_array_element_internal: before trying to get an array's max
- index to process a negative subscript, make sure the array exists.
- Bug report from Geir Hauge <geir.hauge@gmail.com>
-
- 8/2
- ---
-arrayfunc.c
- - assign_array_element_internal: before using array_max_index() when
- processing a negative subscript, make sure the variable is an array.
- if it's not, use 0 as array_max_index assuming it's a string.
- Fixes bug report from Geir Hauge <geir.hauge@gmail.com>
-
- 8/3
- ---
-Makefile.in
- - pcomplete.o: add dependency on $(DEFDIR)/builtext.h. Suggested by
- Curtis Doty <curtis@greenkey.net>
-
- 8/5
- ---
-lib/glob/sm_loop.c
- - strcompare: short-circuit and return FNM_NOMATCH if the lengths of the
- pattern and string (pe - p and se - s, respectively) are not equal
- - strcompare: don't bother trying to set *pe or *se to '\0' if that's
- what they already are. Fixes bug reported by Geir Hauge
- <geir.hauge@gmail.com>
-
- 8/6
- ---
-doc/{bash.1,bashref.texi},builtins/hash.def,lib/readline/doc/rluser.texi
- - minor typo changes from Geir Hauge <geir.hauge@gmail.com>
-
-bultins/help.def
- - show_longdoc: avoid trying to translate the empty string because it
- often translates to some boilerplate about the project and
- translation. Report and fix from Geir Hauge <geir.hauge@gmail.com>
-
- 8/8
- ---
-builtins/help.def
- - help_builtin: try two passes through the list of help topics for each
- argument: one doing exact string matching and one, if the first pass
- fails to find a match, doing string prefix matching like previous
- versions. This prevents `help read' from matching both `read' and
- `readonly', but allows `help r' to match everything beginning with
- `r'. Inspired by report from Geir Hauge <geir.hauge@gmail.com>
-
- 8/13
- ----
-builtins/fc.def
- - fc_builtin,fc_gethnum: calculate `real' end of the history list and
- use it if -0 is specified as the beginning or end of the history
- range to list. Doesn't work for fc -e or fc -s by design. Feature
- requested by Mike Fied <micfied@gmail.com>
-
- 8/16
- ----
-trap.c
- - _run_trap_internal: use {save,restore}_parser_state instead of
- {save,restore}_token_state. It's more comprehensive
-
- 8/23
- ----
-doc/bash.1
- - disown: remove repeated text. Report and fix from Thomas Hood
- <jdthood@gmail.com>
-
- 8/25
- ----
-lib/readline/rltty.c
- - set_special_char: fix prototype (last arg is rl_command_func_t *)
-
-sig.c
- - set_signal_handler: return oact.sa_handler only if sigaction
- succeeds; if it doesn't, return SIG_DFL (reasonable default). From
- https://bugzilla.redhat.com/show_bug.cgi?id=911404
-
-bashline.c
- - attempt_shell_completion: fix to skip assignment statements preceding
- command name even if there are no programmable completions defined.
- From https://bugzilla.redhat.com/show_bug.cgi?id=994659
- - attempt_shell_completion: if still completing command word following
- assignment statements, do command completion even if programmable
- completion defined for partial command name entered so far
-
- 8/26
- ----
-pcomplete.c
- - pcomp_filename_completion_function: make sure rl_filename_dequoting_function
- is non-NULL before trying to call it. Bug and fix from
- Andreas Schwab <schwab@linux-m68k.org>
-
-bashline.c
- - bash_command_name_stat_hook: if *name is not something we're going
- to look up in $PATH (absolute_program(*name) != 0), just call the
- usual bash_filename_stat_hook and return those results. This makes
- completions like $PWD/exam[TAB] add a trailing slash
-
- 9/2
- ---
-builtins/read.def
- - read_builtin: before comparing what we read to the delim, make sure
- we are not supposed to be ignoring the delimiter (read -N). We
- set the delim to -1, but it's possible to read a character whose
- int value ends up being between -1 and -128. Fixes bug
- reported by Stephane Chazelas <stephane.chazelas@gmail.com>
-
-doc/{bash.1,bashref.texi}
- - word splitting: crib some language from Posix to make it clear that
- characters in IFS are treated as field *terminators*, not field
- *separators*. Addresses issue raised by DJ Mills
- <danielmills1@gmail.com>
-
-lib/readline/{util.c,rldefs.h}
- - _rl_stricmp,_rl_strnicmp: now take const char * string arguments;
- changed prototype declarations
-
- 9/5
- ---
-doc/{bash.1,bashref.texi}
- - [[: modify description of pattern matching to make it clear that the
- match is performed as if the extglob option were enabled. From Red
- Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=1002078
-
- 9/12
- ----
-lib/readline/isearch.c
- - _rl_isearch_dispatch: if we read an ESC and it's supposed to
- terminate the search, make sure we check for typeahead with
- _rl_pushed_input_available, since installing a hook function causes
- typeahead to be collected in `ibuffer' (input.c). If there is any,
- make sure we still use the ESC as a prefix character. Bug and fix
- from Mike Miller <mtmiller@ieee.org>
-
- 9/16
- ----
-builtins/{caller,cd,kill,pushd,wait}.def
- - builtin_usage(): make sure call to this sets return status to
- EX_USAGE
-
- 9/18
- ----
-terminal.c
- - rl_change_environment: new application-settable variable; if non-
- zero (the default), readline will modify LINES and COLUMNS in the
- environment when it handles SIGWINCH
- - _rl_get_screen_size: if rl_change_environment is non-zero, use setenv
- to modify LINES and COLUMNS environment variables
-
-readline.h
- - rl_change_environment: new extern declaration for applications
-
- 9/22
- ----
-configure.ac
- - relstatus: bumped version to bash-4.3-beta2
-
- 9/24
- ----
-
-lib/readline/readline.c
- - bind_arrow_keys_internal: added more key bindings for the numeric key
- pad arrow keys on mingw32. Patch from Pierre Muller
- <pierre.muller@ics-cnrs.unistra.fr>
-
- 10/19
- -----
-
-bashline.c
- - maybe_restore_tilde: version of restore_tilde that honors `direxpand';
- calls restore_tilde after saving directory expansion hook if
- necessary. Report from Andreas Schwab <schwab@linux-m68k.org>
-
-builtins/cd.def
- - -@: new option, allows cd to use `extended attributes' present in
- NFSv4, ZFS; idea taken from ksh93. Attributes associated with a
- file are presented as a directory containing the attributes as
- individual files. Original patch contributed by Cedric Blancher
- <cedric.blancher@gmail.com>
-
- 10/20
- -----
-aclocal.m4
- - BASH_CHECK_MULTIBYTE: check for wcwidth being broken with unicode
- combining characters needs a value to use when cross-compiling.
- Bug report from Bert Sutherland <bertsutherland@gmail.com>
-
-doc/{bash.1,bashref.texi}
- - document new -@ option to cd builtin
-
- 10/28
- -----
-lib/glob/{{gmisc,glob}.c,glob.h}
- - extglob_pattern renamed to extglob_pattern_p, declared in glob.h
-
-subst.c
- - expand_word_internal: typo fix: case to fix " $@\ " bug in bash-4.2
- had a typo (& isexp instead of &&)
-
- 10/29
- -----
-input.c
- - getc_with_restart: make sure local_index and local_bufused are
- reset to 0 before returning EOF, in case we are running an interactive
- shell without line editing and ignoreeof is set. Report and fix
- from Yong Zhang <yong.zhang@windriver.com>
-
-lib/readline/search.c
- - _rl_nsearch_init: take out extra third argument to rl_message; it
- only matches prototype (and maybe format) in cases where
- PREFER_STDARG and USE_VARARGS are both undefined, which is rare
-
- 10/31
- -----
-subst.c
- - process_substitute: when opening the named pipe in the child, open
- without O_NONBLOCK to avoid race conditions. Happens often on AIX.
- Bug report and fix from Michael Haubenwallner
- <michael.haubenwallner@salomon.at>
-
-builtins/ulimit.def
- - RLIMIT_NTHR: if RLIMIT_PTHREAD is not defined, but RLIMIT_NTHR is,
- use RLIMIT_NTHR (NetBSD)
-
- 11/5
- ----
-locale.c
- - set_default_locale_vars,set_locale_var: if TEXTDOMAINDIR has been
- set, and default_dir has a non-null value, call bindtextdomain(3)
- when TEXTDOMAIN is assigned a value. Fixes problem reported by
- Michael Arlt <qwertologe@googlemail.com>
-
- 11/6
- ----
-builtins/cd.def
- - cdxattr: only create synthetic pathname in `buf' if NDIRP argument
- is non-null
- - change_to_directory: if we have specified -@ and cdxattr returns
- failure, fail immediately. Fixes bug reported by Joshuah Hurst
- <joshhurst@gmail.com>
-
- 11/12
- -----
-redir.c
- - print_redirection: change r_err_and_out (&>) and its append form,
- r_append_err_and_out (&>>) cases to separate redirection operator
- from filename by a space, in case we have a process substitution.
- Fixes bug reported by admn ombres <admn.ombres@gmail.com>
-
- 11/15
- -----
-execute_cmd.c
- - execute_simple_command: don't close process substitution fds until
- we are finished executing any current shell function. Partial fix
- for bug reported by John Dawson <john.dawson@gmail.com>
-
-support/shobj-conf
- - add support for Darwin 13 (Mac OS X 10.9, Mavericks). Based on a
- report by Ludwig Schwardt <ludwig.schwardt@gmail.com>
-
- 11/20
- -----
-[bash-4.3-rc1 frozen]
-
- 11/24
- -----
-builtins/printf.def
- - bind_printf_variable: make sure that the variable assigned to is
- no longer marked as invisible. Fixes bug reported by NBaH
- <nbah@sfr.fr>
-
- 11/28
- -----
-jobs.c
- - delete_old_job: fix off-by-one error in job index in call to
- internal_warning. Bug report from Peter Cordes <peter@cordes.ca>
-
- 11/30
- -----
-doc/bashref.texi
- - add string to description of special parameters with name of
- special parameter prefixed by a $, so you can search for $#,
- for instance
-
- 12/2
- ----
-lib/readline/{histexpand.c
- - get_history_event: account for current_history() possibly returning
- NULL. Report and fix from Pankaj Sharma <pankaj.s01@samsung.com>
-
-
- 12/11
- -----
-
-lib/readline/parse-colors.c
- - get_funky_string: don't call abort if we see something we can't
- parse; just return an error
- - _rl_parse_colors: if we encounter an error while parsing $LS_COLORS
- we need to leave _rl_color_ext_list as NULL after freeing its
- elements, then turn off _rl_colored_stats. Report and fix from Martin
- Wesdorp <mwesdorp@casema.nl>
-
- 12/13
- -----
-
-lib/readline/parse-colors.c
- - _rl_parse_colors: if we encounter an unrecognized prefix, throw an
- error but try to recover and go on to the next specification
-
-variables.c
- - make_local_variable: for new variables this function creates, set
- the att_invisible attribute. All callers from declare_internal.
- Indirectly, this is a fix for bug with `declare -n var; var=foo;'
- reported by Pierre Gaston <pierre.gaston@gmail.com>
- - bind_variable: if assigning to nameref variable that doesn't have
- a value yet (e.g., with `declare -n var; var=foo'), don't try to
- use the unset name. Fixes a segfault reported by Pierre Gaston
- <pierre.gaston@gmail.com>
-
-execute_cmd.c
- - execute_command_internal: make sure last_command_exit_value is set
- to 0 after any command executed in the background. Fixes bug
- reported by Martin Kealey <martin@kurahaupo.gen.nz>
-
- 12/17
- -----
-support/config.{guess,sub}
- - updated to latest versions from git
-
- 12/19
- -----
-parse.y
- - struct STRING_SAVER: now has a new `flags' element, to identify the
- caller: alias expansion, double-paren parsing, or parse_and_execute
- - push_string: now sets flags to PSH_ALIAS if `ap' argument is non-NULL
- - push_string: now doesn't attempt to call strlen on a NULL string to
- set shell_input_line_size
- - parser_expanding_alias, parser_save_alias, parser_restore_alias: new
- functions to provide an external interface to push_string and
- pop_string; parser_save_alias sets flags element to PSH_SOURCE (could
- be renamed PSH_EXTERN someday)
- - shell_getc: when yy_getc returns '\0', instead of just testing
- whether the pushed_string_list is not-empty before popping it, don't
- pop if if the saved string has flags PSH_SOURCE, indicating that
- parse_and_execute set it before setting bash_input to the string.
- We should continue reading to the end of that string before popping
- back to a potential alias. Partial solution for the problem of aliases
- with embedded newlines containing `.' commands being executed out of
- order reported by Andrew Martin <andrew.martin@gmail.com>
- - shell_getc: when yy_getc returns '\0' and there is a saved string of
- type PSH_SOURCE, restart the read without popping the string stack
- if we have not read to the end of bash_input.location.string. Rest
- of fix for out-of-order execution problem
-
-externs.h
- - parser_expanding_alias, parser_save_alias, parser_restore_alias: new
- extern function declarations
-
-builtins/evalstring.c
- - pe_prologue: if the parser is expanding an alias, make sure to add
- an unwind-protect to restore the alias; undoes the work that will be
- performed by parse_and_execute/parse_string
- - parse_and_execute,parse_string: after calling push_stream to save
- bash_input, check whether or not the parser is currently expanding
- an alias (parser_expanding_alias() != 0). If it is, we want to save
- that string in the pushed_string_list, which we do with
- parser_save_alias.
-
- 12/23
- -----
-execute_cmd.c
- - execute_for_command: make sure to set line_number before expanding
- the word list, so expansion errors have the right line number.
- From a report from Ben Okopnik <ben@okopnik.com>
-
-expr.c
- - exp2: save token pointer before calling readtok(), arrange to use
- saved token pointer when printing error token on a division by 0
- error
-
- 12/27
- -----
-lib/readline/display.c
- - rl_redisplay: when calculating effects of invisible characters in a
- prompt that is split across physical screen lines to set the indices
- of linebreaks, don't bother testing local_prompt_prefix (line 751).
- That prefix doesn't matter when calculating prompt visible and
- invisible characters. Fixes problem reported by Jinesh Choksi
- <jinesh@onelittlehope.com>
-
-Makefile.in
- - install: make sure to use $(DESTDIR) when installing OTHER_DOCS.
- Report and fix from Matthias Klose <doko@debian.org>
-
-doc/texinfo.tex
- - updated to version of 2013-09-11
-
- 12/28
- -----
-lib/readline/undo.c
- - rl_do_undo: if we are undoing from a history entry (rl_undo_list ==
- current_history()->data), make sure the change to rl_line_buffer is
- reflected in the history entry. We use the guts of
- rl_maybe_replace_line to do the work. Fixes problem reported by
- gregrwm <backuppc-users@whitleymott.net>
-
- 12/30
- -----
-sig.c
- - sigint_sighandler: if we get a SIGINT (and this signal handler is
- installed) while the wait builtin is running, note that we received
- it in the same way as jobs.c:wait_sigint_handler and return. The
- various wait_for functions will look for that with CHECK_WAIT_INTR.
- This fixes the wait builtin not being interruptible in an interactive
- job control shell
-
- 12/31
- -----
-trap.c
- - set_signal_hard_ignored: rename set_signal_ignored to this, since it
- both sets original_signals[sig] and sets the HARD_IGNORE flag
- - set_signal_ignored: new function, now just sets original_signals[sig]
-
-trap.h
- - set_signal_hard_ignored: new external declaration
-
-sig.c
- - initialize_terminating_signals: call set_signal_hard_ignored instead
- of set_signal_ignored for signals with disposition SIG_IGN when the
- shell starts
-
-execute_cmd.c
- - setup_async_signals: make sure we get the original dispositions for
- SIGINT and SIGQUIT before starting the subshell, and don't call
- set_signal_ignored because that sets original_signals[sig]. If we
- don't, subsequent attempts to reset handling using trap will fail
- because it thinks the original dispositions were SIG_IGN. Posix
- interpretation 751 (http://austingroupbugs.net/view.php?id=751)
-
- 1/2/2014
- --------
-lib/sh/stringvec.c
- - strvec_mcreate, strvec_mresize: versions of create and resize that
- use malloc and realloc, respectively, instead of xmalloc/xrealloc
-
-braces.c
- - expand_amble,mkseq: use strvec_mcreate/strvec_mresize so we can
- catch and handle memory allocation failures instead of aborting
- with the xmalloc/xrealloc interface
-
-lib/sh/strdup.c
- - strdup replacement function for ancient systems that don't have it
-
-lib/sh/itos.c
- - mitos: new function, itos that uses strdup instead of savestring
-
-externs.h
- - strvec_mcreate/strvec_mresize: new extern declarations
- - mitos: new extern declaration
-
-configure.ac
- - bash version moved to 4.3-rc2
-
- 1/6
- ---
-doc/bash.1,lib/readline/doc/{rluser.texi,readline.3}
- - separate the description of what happens when readline reads the
- tty EOF character from the description of delete-char, leaving a
- note in the delete-char description about common binding for ^D.
- From suggestion by Parke <parke.nexus@gmail.com>
-
-lib/readline/doc/{version.texi,history.3,*.texi}
- - updated email addresses and copyright dates
-
- 1/7
- ---
-variables.c
- - delete_var: new function, just removes a variable from a hash table
- and frees it, without doing anything else
- - make_variable_value: if we are trying to assign to a nameref variable,
- return NULL if the value is null or the empty string or not a valid
- identifier
-
-variables.h
- - delete_var: new extern declaration
-
-subst.h
- - ASS_NAMEREF: new define for assignments, means assigning to a nameref
- variable
-
-builtins/declare.def
- - declare_internal: if we are creating and assigning to a nameref
- variable, make sure the value is a valid variable name (checks done
- by make_variable_value via bind_variable_value) and display an
- error message, deleting the variable we just created, if it is not.
- Fixes bug reported by Peggy Russell <prusselltechgroup@gmail.com>
-
- 1/9
- ---
-builtins/declare.def
- - declare_internal: turning on nameref attribute for an existing
- variable turns off -i/-l/-u/-c attributes (essentially the ones
- that cause evaluation at assignment time) for ksh93 compat
-
-builtins/setattr.def
- - show_name_attributes: if asked to display attributes and values for
- a nameref variable, don't follow the nameref chain to the end. More
- ksh93 compat
-
- 1/10
- ----
-trap.c
- - _run_trap_internal: use {save,restore}_parser_state instead of
- {save,restore}_token_state, like in run_pending_traps(); don't
- need to save and restore last_command_exit_value as a result
- - _run_trap_internal: call {save,restore}_pipeline like in
- run_pending_traps()
- - run_pending_traps: since we no longer run traps in a signal handler
- context, do not block and unblock the trapped signal while the
- trap is executing
- - run_pending_traps: allow recursive invocations (basically, running
- traps from a trap handler) with only a warning if the shell is
- compiled in debug mode. If a caller doesn't want this to happen,
- it should test running_trap > 0. signal_in_progress (sig) only works
- for the signals the shell handles specially
-
-bashline.c
- - bash_event_hook: make sure we clean up readline if interrupt_state
- is set, not only when SIGINT is not trapped. check_signals_and_traps
- will call check_signals, which calls QUIT, which will longjmp back
- to top_level, running the interrupt trap along the way. Fixes the
- problem of signal handlers being reset out from under readline, and
- not being set properly the next time readline is called, because
- signals_set_flag is still set to 1. XXX - might need to do this
- for other signals too?
-
- 1/11
- ----
-subst.h
- - SD_GLOB: new define for skip_to_delim; means we are scanning a
- glob pattern.
-
-subst.c
- - skip_to_delim: if flags include SD_GLOB, assume we are scanning a
- glob pattern. Currently only used to skip bracket expressions
- which may contain one of the delimiters
-
- 1/12
- ----
-subst.c
- - parameter_brace_expand: when expanding $@ as part of substring
- expansion, pattern substitution, or case modification, don't turn
- on the QUOTED_NULL flag. The code that constructs the word to be
- returned from expand_word_internal expects a different code path
- when $@ is being expanded. Fixes bug reported by Theodoros
- V. Kalamatianos <thkala@gmail.com>
-
- 1/19
- ----
-subst.c
- - list_dequote_escapes: new function; analogue of list_quote_escapes
-
-pathexp.c
- - quote_string_for_globbing: fix case where unescaped ^A is last char
- in string; need to pass it through unaltered instead of turning it
- into a bare backslash
- - quote_string_for_globbing: when quoting for regexp matching in [[,
- don't treat backslash as a quote character; quote the backslash as
- any other character. Part of investigation into reports from
- Eduardo A. Bustamante López <dualbus@gmail.com>
-
- 1/25
- ----
-builtins/gen-helpfiles.c
- - write_helpfiles: add prototype
- - make sure to #undef xmalloc/xfree/xrealloc/free if USING_BASH_MALLOC
- is defined. the code does not use them, and we don't link against
- xmalloc.o. Report from Linda Walsh <bash@tlinx.org>
-
-Makefile.in
- - variables.o: add dependency on builtins/builtext.h; helps with
- parallel builds. Report from Linda Walsh <bash@tlinx.org>
-
-support/shobj-conf
- - darwin: combine the stanzas into one that will not require them to
- be updated on each Mac OS X release. Report and fix from Max Horn
- <max@quendi.de>
-
- 1/27
- ----
-support/shobj-conf
- - darwin: changed the install_name embedded into the shared library
- to contain only the major version number, not the minor one. The
- idea is that the minor versions should all be API/ABI compatible,
- and it is better to link automatically with the latest one. Idea
- from Max Horn <max@quendi.de>
-
- 1/29
- ----
-[bash-4.3-rc2 released]
-
- 1/30
- ----
-lib/readline/readline.h
- - rl_clear_history, rl_free_keymap: add extern declarations. Report
- from Hiroo Hayashi <hiroo.hayashi@computer.org>
-
-general.c
- - include trap.h for any_signals_trapped() prototype
-
-lib/sh/unicode.c
- - include <stdio.h> for sprintf prototype
-
- 1/31
- ----
-execute_cmd.c
- - execute_simple_command: only posix-mode shells should exit on an
- assignment failure in the temporary environment preceding a special
- builtin. This is what the documentation and code comments have
- always said
- - execute_simple_command: make sure redirection errors, word expansion
- errors, and assignment errors to Posix special builtins cause a
- non-interactive posix mode shell to exit. Previously the shell
- would not exit if the failed special builtin was on the LHS of ||
- or &&
-
-pathexp.c
- - quote_string_for_globbing: when quoting a regular expression
- (QGLOB_REGEXP), allow an unquoted backslash to pass through
- unaltered. Don't use it as a quote character or quote it. More
- investigation from 1/24 and report by Mike Frysinger
- <vapier@gentoo.org>
- - quote_string_for_globbing: when quoting a regular expression
- (QGLOB_REGEXP), turn CTLESC CTLESC into CTLESC without adding a
- backslash to quote it. We should not have to quote it because it is
- not a character special to EREs. More investigation from 1/24
-
-lib/glob/glob.c
- - glob_testdir: now takes a second flags argument (currently unused);
- changed prototype and callers
-
- 2/1
- ---
-lib/glob/glob.c
- - glob_testdir: if flags argument includes GX_ALLDIRS (globstar), use
- lstat so we skip symlinks when traversing the directory tree.
- Originally reported by Chris Down <chris@chrisdown.name>
-
- 2/2
- ---
-lib/readline/undo.c
- - rl_do_undo: make sure CUR is non-zero before dereferencing it to
- check cur->data against rl_undo_list. Report and fix from
- Andreas Schwab <schwab@linux-m68k.org>
-
-doc/{bash.1,bashref.texi}
- - added slight clarifying language to the description of $*,
- describing what happens when the expansion is not within double
- quotes
-
- 2/4
- ---
-test.c
- - unary_test: add code to -v case so that it interprets `bare' array
- references (foo[1]) and returns true if that index has a value
-
- 2/5
- ---
-trap.c
- - restore_default_signal: fix SIGCHLD special case for SIG_TRAPPED flag
- off but SIG_INPROGRESS mode set and handler IMPOSSIBLE_TRAP_HANDLER;
- continue with resetting handler in this case. maybe_set_sigchld_trap
- will check these things before resetting sigchld trap from
- run_sigchld_trap. Fixes (apparently long-standing?) problem reported
- by Alexandru Damian <alexandru.damian@intel.com>
-
- 2/6
- ---
-lib/sh/strtrans.c
- - ansic_quote: fixed a bug when copying a printable character that
- consumes more than one byte; byte counter was not being incremented.
- Bug report from jidanni@jidanni.org
-
- 2/7
- ---
-input.c
- - getc_with_restart: if read(2) returns -1/EINTR and interrupt_state or
- terminating_signal is set (which means QUIT; will longjmp out of this
- function), make sure the local buffer variables are zeroed out to
- avoid reading past the end of the buffer on the next call. Bug report
- from Dan Jacobson <jidanni@jidanni.org>
-
- 2/9
- ---
-bashline.c
- - command_word_completion_function: if a directory in $PATH contains
- quote characters, we need to quote them before passing the candidate
- path to rl_filename_completion_function, which performs dequoting on
- the pathname it's passed. Fixes bug reported by Ilyushkin Nikita
- <ilyushkeane@gmail.com>
-
- 2/11
- ----
-parse.y
- - xparse_dolparen: save and restore shell_eof_token around call to
- parse_string, intead of just leaving it set to ')'
- - shell_getc: when -v is set, only print the command line when
- shell_eof_token is 0, so we don't print it multiple times when
- recursively entering the parser to parse $(...) commands. Fixes
- bug reported by Greg Wooledge <wooledg@eeg.ccf.org>
-
-[changed release status to 4.3-release]
-
- 2/13
- ----
-lib/sh/strtrans.c
- - ansic_quote: handle case where mbrtowc reports that the multibyte
- sequence is incomplete or invalid. Fixes bug reported by
- Eduardo A. Bustamante López <dualbus@gmail.com>
-
- 2/14
- ----
-variables.c
- - find_variable_nameref_context: fix a problem that caused the loop
- to go one context too close to the global context. In some cases,
- simple variable assignment would set a variable in the global
- context instead of a local context. Bug report from
- Geir Hauge <geir.hauge@gmail.com>
-
- 2/26
- ----
-[bash-4.3 released]
-
- 2/27
- ----
-aclocal.m4
- - broken wcwidth check: fix typo reported by David Michael
- <fedora.dm0@gmail.com>
-
- 2/28
- ----
-support/bashbug.sh
- - add ${BUGADDR} to error message printed if sending mail fails
-
-trap.c
- - _run_trap_internal: don't call {save,restore}_pipeline if running
- DEBUG trap; run_debug_trap calls them itself. Fixes bug reported
- by Moe Tunes <moetunes42@gmail.com>
-
-test.c
- - unary_test: fix 'R' case by using find_variable_noref instead of
- find_variable
- - test_unop: add back missing 'R' case. Fixes bug reported by
- NBaH <nbah@sfr.fr>
-
- 3/2
- ---
-jobs.c
- - end_job_control: if job control is active, we changed the terminal's
- process group, so make sure we restore it. Fixes bug reported by
- Eduardo A. Bustamante López <dualbus@gmail.com>
-
- 3/7
- ---
-pcomplete.c
- - pcomp_curtxt: new variable, holds the original text to be completed
- as passed to the programmable completion code
- - pcomp_filename_completion_function: if we are running compgen
- (presumably in a shell function completion) and performing readline
- completion, check the word being completed. If it's not empty, but
- the original word passed to the programmable completion code is an
- empty string (""), call a dequoting function if one is available.
- This compensates for an assumption in bash-completion. Reported by
- Albert Shih <Albert.Shih@obspm.fr>
-
-lib/readline/readline.c
- - _rl_dispatch_subseq: when deciding whether or not to set vi mode's
- idea of the last command, use whether or not the dispatching keymap
- is vi_movement_keymap instead of the key sequence length. The `c',
- `d', and `y' commands all take motion commands as `arguments' and
- will produce key sequences longer than 1 character. The arrow keys
- will end up dispatching out of a different keymap, so the test will
- prevent arrow keys from setting the last command (the problem in
- bash-4.2). Bug report from Daan van Rossum <daan@flash.uchicago.edu>
-
-lib/readline/vi_mode.c
- - _rl_vi_motion_command: convenience function to test whether a key is
- a vi-mode motion command
-
-lib/readline/rlprivate.h
- - _rl_vi_motion_command: extern declaration
-
-parse.y
- - parse_matched_pair: we should not skip processing single quotes in
- posix mode if dolbrace_state == DOLBRACE_QUOTE2 (pattern
- substitution). Fixes bug reported by David Sines
- <dave.gma@googlemail.com>
-
- 3/10
- ----
-lib/readline/readline.c
- - _rl_dispatch_callback: treat a return value of -1 as the end of
- a command dispatch sequence if the current context doesn't
- indicate that we're reading a multi-key sequence
- ((cxt->flags & KSEQ_SUBSEQ) == 0). Turn off the multikey flag
- and free the context chain in this case. Fixes one bug reported
- by Felix Yan <felixonmars@gmail.com> to bug-readline list
- - _rl_dispatch_callback: treat a return value of > 0 the same as 0
- and return from the function, since only values < 0 cause us to
- simulate recursion. Rest of fix for bug tracked down by
- Anatol Pomozov <anatol.pomozov@gmail.com>
-
- 3/11
- ----
-
-execute_cmd.c
- - execute_in_subshell: if a longjmp occurs, set result to
- EXECUTION_FAILURE only if last_command_exit_value == EXECUTION_SUCCESS;
- use value of last_command_exit_value otherwise. Fixes cosmetic
- issue reported by Dennis Lambe Jr. <malsyned@malsyned.net>
-
-doc/bash.1
- - shell-kill-word and shell-backward-kill-word should be documented
- as unbound by default. Report from Oliver Hartley
- <ohartley@talktalk.net>
-
-trap.c
- - run_pending_traps: save value of $? before running trap commands in
- trap_saved_exit_value, like run_exit_trap
- - _run_trap_internal: save value of $? before running trap commands in
- trap_saved_exit_value, like run_exit_trap
-
-builtins/common.c
- - get_exitstat: when running `return' in a trap action, and it is not
- supplied an argument, use the saved exit status in
- trap_saved_exit_value. Fixes Posix problem reported by
- Eduardo A. Bustamante López <dualbus@gmail.com>
-
- 3/13
- ----
-lib/sh/shquote.c
- - sh_contains_quotes: new function, returns true if a given string
- contains any of the shell quote characters (single quote, double
- quote, or backslash)
-
-externs.h
- - sh_contains_quotes: new extern declaration
-
-pcomplete.c
- - pcomp_filename_completion_function: more changes for the benefit of
- bash-completion: if the argument is not the same as the original
- argument passed to the programmable completion code (pcomp_curtxt),
- and we are being run by compgen as part of a completion, dequote the
- argument as bash-completion expects. Fix for the complete-word-
- with-quoted-special-chars problem with bash-completion
-
- 3/17
- ----
-execute_cmd.c
- - execute_intern_function: when in posix mode, make defining a function
- with the same name as a special builtin a fatal error only when the
- shell is not interactive. Interactive shells display an error
- message and go on. From a discussion with Doug McIlroy
- <doug@cs.dartmouth.edu>
-
- 3/18
- ----
-arrayfunc.c
- - assign_compound_array_list: when using expand_assignment_string_to_string
- to expand the value in a ( [x]=y ) compound assignment, make sure
- that we convert 0x0 to "" when expanding [x]= so it doesn't appear as
- if the index is unset. Fixes bug reported by Geir Hauge
- <geir.hauge@gmail.com>
-
-builtins/common.c
- - get_exitstat: update fix of 3/11 to allow the DEBUG trap to use the
- current value of $? instead of the value it had before the trap
- action was run. This is one reason the DEBUG trap exists, and
- extended debug mode uses it. Might want to do this only in Posix
- mode
-
-doc/{bash.1,bashref.texi}
- - return: add language cribbed from Posix saying what happens when
- return is run without an argument from a trap, including the DEBUG
- trap exception
-
- 3/19
- ----
-lib/glob/gmisc.c
- - extglob_pattern_p: make sure ?(patlist) is flagged as an extglob
- pattern
-
-lib/glob/glob.c
- - extglob_skipname: rewrite to handle patterns that begin but do not
- end with an extglob pattern; change test for easy case and loop
- through patterns accordingly. Fixes problem with matching filenames
- with a leading dot reported by Stephane Chazelas
- <stephane.chazelas@gmail.com>
- - wextglob_skipname: make analogous changes
-
- 3/20
- ----
-Makefile.in
- - pass -DDEBUG down to builds in readline and history directories
-
-lib/readline/util.c
- - _rl_trace and related functions are now only compiled in if DEBUG
- is defined
-
-lib/readline/Makefile.in
- - substitute @DEBUG@ and pass -DDEBUG, if necessary, to compilation
- in LOCAL_CFLAGS
-
- 3/21
- ----
-parse.y
- - shell_getc: when checking whether or not to reallocate
- shell_input_line to add trailing newline, don't try to subtract from
- shell_input_line_size. size_t is unsigned, so if its value is less
- than 3 (like, say, 2), size-3 is a very large number and the string
- will not be reallocated. Use len+3 > size instead of len > size-3.
- Fixes bug reported in
- https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1295467
-
- 3/27
- ----
-lib/readline/display.c
- - _rl_clean_up_for_exit: don't bother to call _rl_move_vert to whatever
- readline thinks the last displayed line is if it's 0. Two reasons: a
- minor optimization, and it protects against unwanted moving if this
- function is called twice, as it is when ^C is pressed. Fixes bug
- reported by Egmont Koblinger <egmont@gmail.com>
-
- 3/28
- ----
-bashline.c
- - invalid_completion: new function, used to identify attempts to
- complete words that are syntax errors
- - attempt_shell_completion: if invalid_completion returns true for a
- word in a command position, punt on all completions. Fixes cosmetic
- issue reported by Uwe Storbeck <uwe@ibr.ch>
- - attempt_shell_completion: add clause so that in_command_position
- remains set to 1 for an empty word following a command separator like
- (, &, or |
-
-lib/readline/kill.c
- - rl_yank, rl_yank_nth_arg_internal: don't return -1 from bindable
- functions, return 1 instead
-
-lib/readline/text.c
- - rl_rubout, _rl_rubout_char, rl_delete, rl_change_case,
- rl_transpose_chars, rl_transpose_words, _rl_set_mark_at_pos,
- rl_exchange_point_and_mark, _rl_insert_next, _rl_char_search,
- _rl_char_search_internal:
- don't return -1 from bindable functions, return 1 instead
-
-lib/readline/vi_mode.c
- - rl_vi_end_word, rl_vi_rubout, rl_vi_delete, rl_vi_char_search,
- rl_vi_match, _rl_vi_set_mark, _rl_vi_goto_mark:
- don't return -1 from bindable functions, return 1 instead
-
-lib/readline/macro.c
- - rl_start_kbd_macro, rl_end_kbd_macro:
- don't return -1 from bindable functions, return 1 instead
-
-builtins/setattr.def
- - set_var_attribute: honor setting of no_invisible_vars when setting
- att_invisible on a variable
- - include "../flags.h" for no_invisible_vars
-
-builtins/declare.def
- - declare_internal: honor setting of no_invisible_vars when setting
- att_invisible on a variable
- - include "../flags.h" for no_invisible_vars
-
-Makefile.in,builtins/Makefile.in
- - make sure declare.o and setattr.o depend on flags.h
-
-execute_cmd.c
- - decpoint: new function, returns locale's decimal point or `.' default
- - mkfmt: use decpoint() to get decimal point instead of unconditionally
- using `.'. Fixes bug reported by Andrey Tataranovich
- <tataranovich@gmail.com> in debian bug 741669
-
- 4/10
- ----
-lib/readline/rltypedefs.h
- - add back old Function/VFunction/etc typedefs, since other packages
- (python, samba) use them. Mark as deprecated using gcc and clang
- attributes. Report and fix from Max Horn <max@quendi.de>
-
- 4/14
- ----
-jobs.c
- - run_sigchld_trap: unwind-protect value of this_shell_builtin, since
- it matters in some cases whether or not we are running `wait' or
- `eval'. Fixes bug reported by Eduardo A. Bustamante López
- <dualbus@gmail.com>
-
- 4/18
- ----
-shell.h
- - sh_parser_state_t: add `need_here_doc' flags member, since
- xparse_dolparen (via parse_command) sets it to 0
-
-parse.y
- - gather_here_documents: make sure need_here_doc is > 0, since we
- don't want to just decrement it forever if it ends up < 0. Partial
- fix for bug reported by Jared Yanovich <slovichon@gmail.com>
- - {save,restore}_parser_state: save and restore need_here_doc flag.
- Rest of fix for bug reported by Jared Yanovich <slovichon@gmail.com>
-
- 4/19
- ----
-subst.c
- - cond_expand_word: since we are not supposed to be performing word
- splitting here, set expand_no_split_dollar_star to 1 in addition to
- setting W_NOSPLIT2
- - expand_word_internal: if we have a case where we have an unquoted
- $@ but we are in a case where we don't want to split (W_NOSPLIT2),
- make sure we return a list consisting of a single word with the
- arguments separated by spaces and don't do word splitting. Fixes
- bug reported by Greg Wooledge <wooledg@eeg.ccf.org> from an IRC
- discussion
-
-builtins/hash.def
- - print_portable_hash_info: single-quote pathnames and hashed filenames
- that contain shell metacharacters. Fixes bug reported by
- <g1pi@libero.it> in debian bash bug #739853
-
- 4/23
- ----
-{bashhist,bashline}.c
-builtins{bind,help,type}.def
-lib/glob/glob.c, lib/intl/{loadmsgcat,localealias}.c,lib/sh/mktime.c
- - fixes to memory leaks uncovered by coverity scan
-
- 4/24
- ----
-{bashhist,subst,redir,assoc,jobs,array,trap}.c
-lib/intl/l10flist.c
-builtins/complete.def
- - fixes to memory leaks and other resource usage problems uncovered by
- coverity scan
-
-redir.c
- - do_redirection_internal: if dup2 fails (presumably because of a
- resource limit), close the file descriptor we opened before returning
- error
-
- 4/25
- ----
-config-top.h
- - DEFAULT_BASHRC: new define with the name of the default shell
- startup file
-
-bashline.c
- - bash_directory_completion_matches: don't dequote the directory name.
- If rl_completion_found_quote is non-zero, readline will dequote the
- filename itself. Fixes bug reported by Clark Wang
- <dearvoid@gmail.com>
+++ /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
-#
-# Master distribution manifest for bash
-#
-#
-# Filename type
-#
-CWRU d
-CWRU/misc d
-builtins d
-cross-build d
-doc d
-examples d
-#examples/obashdb d
-examples/complete d
-examples/functions d
-examples/scripts d
-#examples/scripts.v2 d
-#examples/scripts.noah d
-examples/startup-files d
-#examples/startup-files/apple d
-examples/misc d
-examples/loadables d
-examples/loadables/perl d
-include d
-lib d
-lib/glob d
-lib/glob/doc d
-lib/intl d
-lib/malloc d
-lib/readline d
-lib/readline/doc d
-lib/readline/examples d
-lib/sh d
-lib/termcap d
-lib/tilde d
-m4 d
-po d
-support d
-tests d
-tests/misc d
-ABOUT-NLS f
-ChangeLog s CWRU/changelog
-CHANGES f
-COMPAT f
-COPYING f
-INSTALL f
-MANIFEST f
-NEWS f
-NOTES f
-POSIX f
-README f
-RBASH f
-AUTHORS f
-Y2K f
-configure.ac f
-configure f 755
-Makefile.in f
-config-top.h f
-config-bot.h f
-config.h.in f
-aclocal.m4 f
-array.c f
-arrayfunc.c f
-assoc.c f
-eval.c f
-print_cmd.c f
-general.c f
-list.c f
-locale.c f
-stringlib.c f
-variables.c f
-make_cmd.c f
-copy_cmd.c f
-unwind_prot.c f
-dispose_cmd.c f
-bashhist.c f
-hashcmd.c f
-hashlib.c f
-parse.y f
-pathexp.c f
-subst.c f
-shell.c f
-trap.c f
-sig.c f
-siglist.c f
-version.c f
-flags.c f
-jobs.c f
-input.c f
-mailcheck.c f
-test.c f
-expr.c f
-alias.c f
-execute_cmd.c f
-findcmd.c f
-redir.c f
-bashline.c f
-braces.c f
-bracecomp.c f
-nojobs.c f
-error.c f
-xmalloc.c f
-pcomplete.c f
-pcomplib.c f
-mksyntax.c f
-alias.h f
-builtins.h f
-bashhist.h f
-bashline.h f
-conftypes.h f
-patchlevel.h f
-variables.h f
-array.h f
-arrayfunc.h f
-assoc.h f
-jobs.h f
-findcmd.h f
-hashlib.h f
-quit.h f
-flags.h f
-shell.h f
-syntax.h f
-pathexp.h f
-parser.h f
-pcomplete.h f
-sig.h f
-test.h f
-trap.h f
-general.h f
-unwind_prot.h f
-input.h f
-error.h f
-command.h f
-externs.h f
-siglist.h f
-subst.h f
-dispose_cmd.h f
-hashcmd.h f
-bashansi.h f
-bashjmp.h f
-bashintl.h f
-make_cmd.h f
-execute_cmd.h f
-redir.h f
-bashtypes.h f
-mailcheck.h f
-xmalloc.h f
-y.tab.c f
-y.tab.h f
-parser-built f
-pathnames.h.in f
-builtins/Makefile.in f
-builtins/alias.def f
-builtins/bind.def f
-builtins/break.def f
-builtins/builtin.def f
-builtins/caller.def f
-builtins/cd.def f
-builtins/colon.def f
-builtins/command.def f
-builtins/complete.def f
-builtins/common.c f
-builtins/declare.def f
-builtins/echo.def f
-builtins/enable.def f
-builtins/eval.def f
-builtins/evalfile.c f
-builtins/evalstring.c f
-builtins/exec.def f
-builtins/exit.def f
-builtins/fc.def f
-builtins/fg_bg.def f
-builtins/gen-helpfiles.c f
-builtins/getopt.c f
-builtins/getopt.h f
-builtins/getopts.def f
-builtins/hash.def f
-builtins/help.def f
-builtins/let.def f
-builtins/history.def f
-builtins/jobs.def f
-builtins/kill.def f
-builtins/mapfile.def f
-builtins/mkbuiltins.c f
-builtins/printf.def f
-builtins/pushd.def f
-builtins/read.def f
-builtins/reserved.def f
-builtins/return.def f
-builtins/set.def f
-builtins/setattr.def f
-builtins/shift.def f
-builtins/shopt.def f
-builtins/source.def f
-builtins/suspend.def f
-builtins/test.def f
-builtins/times.def f
-builtins/trap.def f
-builtins/type.def f
-builtins/ulimit.def f
-builtins/umask.def f
-builtins/wait.def f
-builtins/psize.c f
-builtins/psize.sh f
-builtins/inlib.def f
-builtins/bashgetopt.c f
-builtins/common.h f
-builtins/bashgetopt.h f
-cross-build/cygwin32.cache f
-cross-build/x86-beos.cache f
-cross-build/opennt.cache f
-include/ansi_stdlib.h f
-include/chartypes.h f
-include/filecntl.h f
-include/gettext.h f
-include/maxpath.h f
-include/memalloc.h f
-include/ocache.h f
-include/posixdir.h f
-include/posixjmp.h f
-include/posixselect.h f
-include/posixstat.h f
-include/posixtime.h f
-include/posixwait.h f
-include/shmbchar.h f
-include/shmbutil.h f
-include/shtty.h f
-include/stat-time.h f
-include/stdc.h f
-include/systimes.h f
-include/typemax.h f
-include/unionwait.h f
-lib/glob/Makefile.in f
-lib/glob/sm_loop.c f
-lib/glob/smatch.c f
-lib/glob/strmatch.c f
-lib/glob/strmatch.h f
-lib/glob/glob.c f
-lib/glob/glob.h f
-lib/glob/glob_loop.c f
-lib/glob/gmisc.c f
-lib/glob/xmbsrtowcs.c f
-lib/glob/collsyms.h f
-lib/glob/doc/Makefile f
-lib/glob/doc/glob.texi f
-lib/glob/ndir.h f
-lib/intl/ChangeLog f
-lib/intl/Makefile.in f
-lib/intl/VERSION f
-lib/intl/bindtextdom.c f
-lib/intl/config.charset f
-lib/intl/dcgettext.c f
-lib/intl/dcigettext.c f
-lib/intl/dcngettext.c f
-lib/intl/dgettext.c f
-lib/intl/dngettext.c f
-lib/intl/eval-plural.h f
-lib/intl/explodename.c f
-lib/intl/finddomain.c f
-lib/intl/gettext.c f
-lib/intl/gettextP.h f
-lib/intl/gmo.h f
-lib/intl/hash-string.h f
-lib/intl/intl-compat.c f
-lib/intl/l10nflist.c f
-lib/intl/libgnuintl.h.in f
-lib/intl/loadinfo.h f
-lib/intl/loadmsgcat.c f
-lib/intl/localcharset.c f
-lib/intl/localcharset.h f
-lib/intl/locale.alias f
-lib/intl/localealias.c f
-lib/intl/localename.c f
-lib/intl/log.c f
-lib/intl/ngettext.c f
-lib/intl/os2compat.c f
-lib/intl/os2compat.h f
-lib/intl/osdep.c f
-lib/intl/plural-exp.c f
-lib/intl/plural-exp.h f
-lib/intl/plural.c f
-lib/intl/plural.y f
-lib/intl/ref-add.sin f
-lib/intl/ref-del.sin f
-lib/intl/relocatable.c f
-lib/intl/relocatable.h f
-lib/intl/textdomain.c f
-lib/malloc/Makefile.in f
-lib/malloc/getpagesize.h f
-lib/malloc/imalloc.h f
-lib/malloc/mstats.h f
-lib/malloc/shmalloc.h f
-lib/malloc/table.h f
-lib/malloc/watch.h f
-lib/malloc/alloca.c f
-lib/malloc/malloc.c f
-lib/malloc/stats.c f
-lib/malloc/table.c f
-lib/malloc/trace.c f
-lib/malloc/watch.c f
-lib/malloc/xmalloc.c f
-lib/malloc/xleaktrace f 755
-lib/malloc/stub.c f
-lib/malloc/i386-alloca.s f
-lib/malloc/x386-alloca.s f
-lib/readline/COPYING f
-lib/readline/Makefile.in f
-lib/readline/ChangeLog f
-lib/readline/README f
-lib/readline/STANDALONE f
-lib/readline/readline.c f
-lib/readline/vi_mode.c f
-lib/readline/emacs_keymap.c f
-lib/readline/vi_keymap.c f
-lib/readline/history.c f
-lib/readline/histexpand.c f
-lib/readline/histsearch.c f
-lib/readline/histfile.c f
-lib/readline/funmap.c f
-lib/readline/keymaps.c f
-lib/readline/util.c f
-lib/readline/terminal.c f
-lib/readline/xfree.c f
-lib/readline/xmalloc.c f
-lib/readline/search.c f
-lib/readline/isearch.c f
-lib/readline/parens.c f
-lib/readline/rltty.c f
-lib/readline/compat.c f
-lib/readline/complete.c f
-lib/readline/bind.c f
-lib/readline/display.c f
-lib/readline/signals.c f
-lib/readline/kill.c f
-lib/readline/text.c f
-lib/readline/undo.c f
-lib/readline/macro.c f
-lib/readline/input.c f
-lib/readline/callback.c f
-lib/readline/mbutil.c f
-lib/readline/misc.c f
-lib/readline/nls.c f
-lib/readline/shell.c f
-lib/readline/colors.c f
-lib/readline/parse-colors.c f
-lib/readline/savestring.c f
-lib/readline/tilde.c f
-lib/readline/tilde.h f
-lib/readline/rldefs.h f
-lib/readline/rlconf.h f
-lib/readline/rlmbutil.h f
-lib/readline/rlshell.h f
-lib/readline/rltty.h f
-lib/readline/rltypedefs.h f
-lib/readline/rlwinsize.h f
-lib/readline/readline.h f
-lib/readline/tcap.h f
-lib/readline/keymaps.h f
-lib/readline/history.h f
-lib/readline/histlib.h f
-lib/readline/chardefs.h f
-lib/readline/posixdir.h f
-lib/readline/posixjmp.h f
-lib/readline/posixselect.h f
-lib/readline/posixstat.h f
-lib/readline/ansi_stdlib.h f
-lib/readline/rlstdc.h f
-lib/readline/rlprivate.h f
-lib/readline/colors.h f
-lib/readline/parse-colors.h f
-lib/readline/xmalloc.h f
-lib/readline/doc/Makefile f
-lib/readline/doc/version.texi f
-lib/readline/doc/rlman.texi f
-lib/readline/doc/rltech.texi f
-lib/readline/doc/rluser.texi f
-lib/readline/doc/rluserman.texi f
-lib/readline/doc/history.texi f
-lib/readline/doc/hstech.texi f
-lib/readline/doc/hsuser.texi f
-lib/readline/doc/fdl.texi f
-lib/readline/examples/Makefile f
-lib/readline/examples/excallback.c f
-lib/readline/examples/fileman.c f
-lib/readline/examples/manexamp.c f
-lib/readline/examples/histexamp.c f
-lib/readline/examples/rltest.c f
-lib/readline/examples/rl-callbacktest.c f
-lib/readline/examples/rl.c f
-lib/readline/examples/rlcat.c f
-lib/readline/examples/Inputrc f
-lib/sh/Makefile.in f
-lib/sh/casemod.c f
-lib/sh/clktck.c f
-lib/sh/clock.c f
-lib/sh/dprintf.c f
-lib/sh/eaccess.c f
-lib/sh/fmtullong.c f
-lib/sh/fmtulong.c f
-lib/sh/fmtumax.c f
-lib/sh/fnxform.c f
-lib/sh/fpurge.c f
-lib/sh/getcwd.c f
-lib/sh/getenv.c f
-lib/sh/inet_aton.c f
-lib/sh/input_avail.c f
-lib/sh/itos.c f
-lib/sh/mailstat.c f
-lib/sh/makepath.c f
-lib/sh/mbscasecmp.c f
-lib/sh/mbschr.c f
-lib/sh/mbscmp.c f
-lib/sh/memset.c f
-lib/sh/mktime.c f
-lib/sh/netconn.c f
-lib/sh/netopen.c f
-lib/sh/oslib.c f
-lib/sh/pathcanon.c f
-lib/sh/pathphys.c f
-lib/sh/rename.c f
-lib/sh/setlinebuf.c f
-lib/sh/shmatch.c f
-lib/sh/shmbchar.c f
-lib/sh/shquote.c f
-lib/sh/shtty.c f
-lib/sh/snprintf.c f
-lib/sh/spell.c f
-lib/sh/strcasecmp.c f
-lib/sh/strcasestr.c f
-lib/sh/strchrnul.c f
-lib/sh/strdup.c f
-lib/sh/strerror.c f
-lib/sh/strftime.c f
-lib/sh/stringlist.c f
-lib/sh/stringvec.c f
-lib/sh/strnlen.c f
-lib/sh/strpbrk.c f
-lib/sh/strstr.c f
-lib/sh/strtod.c f
-lib/sh/strtoimax.c f
-lib/sh/strtol.c f
-lib/sh/strtoll.c f
-lib/sh/strtoul.c f
-lib/sh/strtoull.c f
-lib/sh/strtoumax.c f
-lib/sh/strtrans.c f
-lib/sh/times.c f
-lib/sh/timeval.c f
-lib/sh/tmpfile.c f
-lib/sh/uconvert.c f
-lib/sh/ufuncs.c f
-lib/sh/unicode.c f
-lib/sh/vprint.c f
-lib/sh/wcsdup.c f
-lib/sh/wcsnwidth.c f
-lib/sh/wcswidth.c f
-lib/sh/winsize.c f
-lib/sh/zcatfd.c f
-lib/sh/zgetline.c f
-lib/sh/zmapfd.c f
-lib/sh/zread.c f
-lib/sh/zwrite.c f
-lib/termcap/Makefile.in f
-lib/termcap/ltcap.h f
-lib/termcap/termcap.c f
-lib/termcap/termcap.h f
-lib/termcap/tparam.c f
-lib/termcap/version.c f
-lib/tilde/README f
-lib/tilde/Makefile.in f
-lib/tilde/tilde.c f
-lib/tilde/tilde.h f
-lib/tilde/shell.c f
-m4/stat-time.m4 f
-m4/timespec.m4 f
-po/LINGUAS f
-po/Makefile.in.in f
-po/Makevars f
-po/POTFILES.in f
-po/README f
-po/Rules-builtins f
-po/Rules-quot f
-po/bash.pot f
-po/boldquot.sed f
-po/en@boldquot.gmo f
-po/en@boldquot.header f
-po/en@boldquot.po f
-po/en@quot.gmo f
-po/en@quot.header f
-po/en@quot.po f
-po/af.gmo f
-po/af.po f
-po/bg.gmo f
-po/bg.po f
-po/ca.gmo f
-po/ca.po f
-po/cs.gmo f
-po/cs.po f
-po/da.gmo f
-po/da.po f
-po/de.gmo f
-po/de.po f
-po/el.gmo f
-po/el.po f
-po/eo.gmo f
-po/eo.po f
-po/es.gmo f
-po/es.po f
-po/et.gmo f
-po/et.po f
-po/fi.gmo f
-po/fi.po f
-po/fr.gmo f
-po/fr.po f
-po/ga.gmo f
-po/ga.po f
-po/gl.gmo f
-po/gl.po f
-po/hr.gmo f
-po/hr.po f
-po/hu.gmo f
-po/hu.po f
-po/id.gmo f
-po/id.po f
-po/it.gmo f
-po/it.po f
-po/ja.gmo f
-po/ja.po f
-po/lt.gmo f
-po/lt.po f
-po/nl.gmo f
-po/nl.po f
-po/pl.gmo f
-po/pl.po f
-po/pt_BR.gmo f
-po/pt_BR.po f
-po/ro.gmo f
-po/ro.po f
-po/ru.gmo f
-po/ru.po f
-po/sk.gmo f
-po/sk.po f
-po/sl.gmo f
-po/sr.po f
-po/sr.gmo f
-po/sl.po f
-po/sv.gmo f
-po/sv.po f
-po/tr.gmo f
-po/tr.po f
-po/uk.gmo f
-po/uk.po f
-po/vi.gmo f
-po/vi.po f
-po/zh_CN.gmo f
-po/zh_CN.po f
-po/zh_TW.gmo f
-po/zh_TW.po f
-po/insert-header.sin f
-po/quot.sed f
-po/remove-potcdate.sin f
-CWRU/misc/open-files.c f
-CWRU/misc/sigs.c f
-CWRU/misc/sigstat.c f
-CWRU/misc/bison f
-CWRU/misc/errlist.c f
-CWRU/misc/hpux10-dlfcn.h f
-CWRU/PLATFORMS f
-CWRU/README f
-CWRU/changelog f
-CWRU/sh-redir-hack f
-doc/FAQ f
-doc/Makefile.in f
-doc/bash.1 f
-doc/bashbug.1 f
-doc/builtins.1 f
-doc/rbash.1 f
-doc/README f
-doc/INTRO f
-doc/texinfo.tex f
-doc/bashref.texi f
-doc/version.texi f
-doc/bashref.info f
-doc/article.ms f
-doc/htmlpost.sh f 755
-doc/infopost.sh f 755
-doc/fdl.texi f
-doc/fdl.txt f
-#
-doc/article.ps f
-doc/rose94.ps f
-doc/bash.ps f
-doc/bashbug.ps f
-doc/builtins.ps f
-doc/rbash.ps f
-doc/bashref.ps f
-doc/bashref.dvi f
-doc/bash.0 f
-doc/bashbug.0 f
-doc/builtins.0 f
-doc/rbash.0 f
-doc/article.txt f
-doc/bash.html f
-doc/bashref.html f
-doc/article.pdf f
-doc/bash.pdf f
-doc/bashref.pdf f
-doc/rose94.pdf f
-doc/aosa-bash.pdf f
-#
-support/Makefile.in f
-support/bashversion.c f
-support/checkbashisms f 755
-support/config.guess f
-support/config.rpath f 755
-support/config.sub f
-support/printenv.sh f 755
-support/printenv.c f
-support/bash.xbm f
-support/missing f 755
-support/mkclone f 755
-support/mkconffiles f 755
-support/mkdirs f 755
-support/mkinstalldirs f 755
-support/mkversion.sh f 755
-support/mksignames.c f
-support/signames.c f
-support/bashbug.sh f
-support/man2html.c f
-support/recho.c f
-support/zecho.c f
-support/xcase.c f
-support/SYMLINKS f
-support/fixlinks f 755
-support/install.sh f 755
-support/texi2dvi f 755
-support/texi2html f 755
-support/xenix-link.sh f 755
-support/shobj-conf f 755
-support/rlvers.sh f 755
-examples/INDEX.txt f
-examples/INDEX.html f
-#examples/obashdb/PERMISSION f
-#examples/obashdb/README f
-#examples/obashdb/bashdb f
-#examples/obashdb/bashdb.el f
-examples/complete/bash_completion f
-examples/complete/cdfunc f
-examples/complete/complete-examples f
-#examples/complete/complete.ianmac f
-#examples/complete/complete2.ianmac f
-#examples/complete/complete.freebsd f
-#examples/complete/complete.gnu-longopt f
-examples/complete/bashcc-1.0.1.tar.gz f
-examples/loadables/README f
-examples/loadables/template.c f
-examples/loadables/Makefile.in f
-examples/loadables/necho.c f
-examples/loadables/hello.c f
-examples/loadables/print.c f
-examples/loadables/realpath.c f
-examples/loadables/sleep.c f
-examples/loadables/strftime.c f
-examples/loadables/truefalse.c f
-#examples/loadables/getconf.h f
-#examples/loadables/getconf.c f
-examples/loadables/finfo.c f
-examples/loadables/cat.c f
-#examples/loadables/cut.c f
-examples/loadables/logname.c f
-examples/loadables/basename.c f
-examples/loadables/dirname.c f
-examples/loadables/tty.c f
-examples/loadables/pathchk.c f
-examples/loadables/tee.c f
-examples/loadables/rmdir.c f
-examples/loadables/head.c f
-examples/loadables/printenv.c f
-examples/loadables/push.c f
-examples/loadables/id.c f
-examples/loadables/whoami.c f
-examples/loadables/uname.c f
-examples/loadables/sync.c f
-examples/loadables/mkdir.c f
-examples/loadables/ln.c f
-examples/loadables/mypid.c f
-examples/loadables/unlink.c f
-examples/loadables/perl/Makefile.in f
-examples/loadables/perl/README f
-examples/loadables/perl/bperl.c f
-examples/loadables/perl/iperl.c f
-#examples/loadables/sprintf.c f
-#examples/loadables/xtitle.c f
-examples/functions/array-stuff f
-examples/functions/array-to-string f
-examples/functions/autoload f
-examples/functions/autoload.v2 f
-examples/functions/autoload.v3 f
-examples/functions/basename f
-#examples/functions/basename2 f
-#examples/functions/coproc.bash f
-#examples/functions/coshell.README f
-#examples/functions/coshell.bash f
-examples/functions/csh-compat f
-#examples/functions/dirfuncs f
-examples/functions/dirname f
-examples/functions/dirstack f
-#examples/functions/emptydir f
-examples/functions/exitstat f
-examples/functions/external f
-examples/functions/fact f
-examples/functions/fstty f
-examples/functions/func f
-#examples/functions/gethtml f
-#examples/functions/getoptx.bash f
-examples/functions/inetaddr f
-examples/functions/inpath f
-#examples/functions/isnum.bash f
-examples/functions/isnum2 f
-examples/functions/isvalidip f
-#examples/functions/jdate.bash f
-#examples/functions/jj.bash f
-#examples/functions/keep f
-examples/functions/ksh-cd f
-examples/functions/ksh-compat-test f
-examples/functions/kshenv f
-examples/functions/login f
-#examples/functions/lowercase f
-#examples/functions/manpage f
-#examples/functions/mhfold f
-#examples/functions/newdirstack.bsh f
-examples/functions/notify.bash f
-#examples/functions/pathfuncs f
-#examples/functions/recurse f
-#examples/functions/repeat2 f
-#examples/functions/repeat3 f
-examples/functions/seq f
-examples/functions/seq2 f
-examples/functions/shcat f
-examples/functions/shcat2 f
-examples/functions/sort-pos-params f
-#examples/functions/sqroot f
-examples/functions/substr f
-examples/functions/substr2 f
-#examples/functions/term f
-examples/functions/whatis f
-examples/functions/whence f
-examples/functions/which f
-#examples/functions/xalias.bash f
-#examples/functions/xfind.bash f
-#examples/scripts/adventure.sh f
-#examples/scripts/bash-hexdump.sh f
-#examples/scripts/bcsh.sh f
-examples/scripts/cat.sh f
-examples/scripts/center f
-#examples/scripts/dd-ex.sh f
-#examples/scripts/fixfiles.bash f
-#examples/scripts/hanoi.bash f
-examples/scripts/inpath f
-#examples/scripts/krand.bash f
-#examples/scripts/line-input.bash f
-#examples/scripts/nohup.bash f
-#examples/scripts/precedence f
-#examples/scripts/randomcard.bash f
-#examples/scripts/scrollbar f
-#examples/scripts/scrollbar2 f
-#examples/scripts/self-repro f
-#examples/scripts/showperm.bash f
-examples/scripts/shprompt f
-examples/scripts/spin.bash f
-#examples/scripts/timeout f
-#examples/scripts/timeout2 f
-#examples/scripts/timeout3 f
-#examples/scripts/vtree2 f
-#examples/scripts/vtree3 f
-#examples/scripts/vtree3a f
-#examples/scripts/websrv.sh f
-examples/scripts/xterm_title f
-examples/scripts/zprintf f
-examples/startup-files/README f
-examples/startup-files/Bashrc.bfox f
-examples/startup-files/Bash_aliases f
-examples/startup-files/Bash_profile f
-examples/startup-files/bash-profile f
-examples/startup-files/bashrc f
-#examples/startup-files/apple/README f
-#examples/startup-files/apple/aliases f
-#examples/startup-files/apple/bash.defaults f
-#examples/startup-files/apple/environment f
-#examples/startup-files/apple/login f
-#examples/startup-files/apple/logout f
-#examples/startup-files/apple/rc f
-#examples/misc/suncmd.termcap f
-examples/misc/aliasconv.sh f
-examples/misc/aliasconv.bash f
-examples/misc/cshtobash f
-tests/README f
-tests/COPYRIGHT f
-tests/alias.tests f
-tests/alias1.sub f
-tests/alias.right f
-tests/appendop.tests f
-tests/appendop1.sub f
-tests/appendop2.sub f
-tests/appendop.right f
-tests/arith-for.tests f
-tests/arith-for.right f
-tests/arith.tests f
-tests/arith.right f
-tests/arith1.sub f
-tests/arith2.sub f
-tests/arith3.sub f
-tests/arith4.sub f
-tests/arith5.sub f
-tests/arith6.sub f
-tests/array.tests f
-tests/array.right f
-tests/array1.sub f
-tests/array2.sub f
-tests/array3.sub f
-tests/array4.sub f
-tests/array5.sub f
-tests/array6.sub f
-tests/array7.sub f
-tests/array8.sub f
-tests/array9.sub f
-tests/array10.sub f
-tests/array11.sub f
-tests/array12.sub f
-tests/array13.sub f
-tests/array14.sub f
-tests/array15.sub f
-tests/array16.sub f
-tests/array-at-star f
-tests/array2.right f
-tests/assoc.tests f
-tests/assoc.right f
-tests/assoc1.sub f
-tests/assoc2.sub f
-tests/assoc3.sub f
-tests/assoc4.sub f
-tests/assoc5.sub f
-tests/assoc6.sub f
-tests/assoc7.sub f
-tests/braces.tests f
-tests/braces.right f
-tests/builtins.tests f
-tests/builtins.right f
-tests/builtins1.sub f
-tests/builtins2.sub f
-tests/builtins3.sub f
-tests/builtins4.sub f
-tests/source1.sub f
-tests/source2.sub f
-tests/source3.sub f
-tests/source4.sub f
-tests/source5.sub f
-tests/source6.sub f
-tests/source7.sub f
-tests/case.tests f
-tests/case.right f
-tests/case1.sub f
-tests/casemod.tests f
-tests/casemod.right f
-tests/comsub.tests f
-tests/comsub.right f
-tests/comsub1.sub f
-tests/comsub-eof.tests f
-tests/comsub-eof0.sub f
-tests/comsub-eof1.sub f
-tests/comsub-eof2.sub f
-tests/comsub-eof3.sub f
-tests/comsub-eof4.sub f
-tests/comsub-eof5.sub f
-tests/comsub-eof.right f
-tests/comsub-posix.tests f
-tests/comsub-posix.right f
-tests/comsub-posix1.sub f
-tests/comsub-posix2.sub f
-tests/comsub-posix3.sub f
-tests/cond.tests f
-tests/cond.right f
-tests/cond-regexp1.sub f
-tests/cond-regexp2.sub f
-tests/cond-regexp3.sub f
-tests/coproc.tests f
-tests/coproc.right f
-tests/cprint.tests f
-tests/cprint.right f
-tests/dbg-support.right f
-tests/dbg-support.sub f
-tests/dbg-support.tests f
-tests/dbg-support2.right f
-tests/dbg-support2.tests f
-tests/dbg-support3.sub f
-tests/dollar-at-star f
-tests/dollar-at-star1.sub f
-tests/dollar-at1.sub f
-tests/dollar-at2.sub f
-tests/dollar-at3.sub f
-tests/dollar-at4.sub f
-tests/dollar-at5.sub f
-tests/dollar-at6.sub f
-tests/dollar-star1.sub f
-tests/dollar-star2.sub f
-tests/dollar-star3.sub f
-tests/dollar-star4.sub f
-tests/dollar-star5.sub f
-tests/dollar-star6.sub f
-tests/dollar-star7.sub f
-tests/dollar.right f
-tests/dstack.tests f
-tests/dstack.right f
-tests/dstack2.tests f
-tests/dstack2.right f
-tests/errors.tests f
-tests/errors.right f
-tests/errors1.sub f
-tests/errors2.sub f
-tests/errors3.sub f
-tests/execscript f
-tests/exec.right f
-tests/exec1.sub f 755
-tests/exec2.sub f
-tests/exec3.sub f
-tests/exec4.sub f
-tests/exec5.sub f
-tests/exec6.sub f
-tests/exec7.sub f
-tests/exec8.sub f
-tests/exec9.sub f
-tests/exp.tests f
-tests/exp.right f
-tests/exp1.sub f
-tests/exp2.sub f
-tests/exp3.sub f
-tests/exp4.sub f
-tests/exp5.sub f
-tests/exp6.sub f
-tests/extglob.tests f
-tests/extglob.right f
-tests/extglob1.sub f
-tests/extglob1a.sub f
-tests/extglob3.sub f
-tests/extglob2.tests f
-tests/extglob2.right f
-tests/extglob3.tests f
-tests/extglob3.right f
-tests/func.tests f
-tests/func.right f
-tests/func1.sub f
-tests/func2.sub f
-tests/func3.sub f
-tests/func4.sub f
-tests/getopts.tests f
-tests/getopts.right f
-tests/getopts1.sub f
-tests/getopts2.sub f
-tests/getopts3.sub f
-tests/getopts4.sub f
-tests/getopts5.sub f
-tests/getopts6.sub f
-tests/getopts7.sub f
-tests/glob.tests f
-tests/glob1.sub f
-tests/glob.right f
-tests/globstar.tests f
-tests/globstar.right f
-tests/globstar1.sub f
-tests/globstar2.sub f
-tests/heredoc.tests f
-tests/heredoc.right f
-tests/heredoc1.sub f
-tests/heredoc2.sub f
-tests/heredoc3.sub f
-tests/herestr.tests f
-tests/herestr.right f
-tests/histexp.tests f
-tests/histexp.right f
-tests/history.tests f
-tests/history.right f
-tests/history.list f 444
-tests/history1.sub f
-tests/history2.sub f
-tests/ifs.tests f
-tests/ifs.right f
-tests/ifs-posix.tests f
-tests/ifs-posix.right f
-tests/input-line.sh f
-tests/input-line.sub f
-tests/input.right f
-tests/intl.tests f
-tests/intl1.sub f
-tests/intl2.sub f
-tests/intl.right f
-tests/iquote.tests f
-tests/iquote.right f
-tests/iquote1.sub f
-tests/invert.tests f
-tests/invert.right f
-tests/jobs.tests f
-tests/jobs1.sub f
-tests/jobs2.sub f
-tests/jobs3.sub f
-tests/jobs4.sub f
-tests/jobs5.sub f
-tests/jobs.right f
-tests/lastpipe.right f
-tests/lastpipe.tests f
-tests/lastpipe1.sub f
-tests/mapfile.data f
-tests/mapfile.right f
-tests/mapfile.tests f
-tests/mapfile1.sub f
-tests/more-exp.tests f
-tests/more-exp.right f
-tests/nameref.tests f
-tests/nameref1.sub f
-tests/nameref2.sub f
-tests/nameref3.sub f
-tests/nameref4.sub f
-tests/nameref5.sub f
-tests/nameref6.sub f
-tests/nameref7.sub f
-tests/nameref8.sub f
-tests/nameref.right f
-tests/new-exp.tests f
-tests/new-exp1.sub f
-tests/new-exp2.sub f
-tests/new-exp3.sub f
-tests/new-exp4.sub f
-tests/new-exp5.sub f
-tests/new-exp6.sub f
-tests/new-exp7.sub f
-tests/new-exp8.sub f
-tests/new-exp9.sub f
-tests/new-exp.right f
-tests/nquote.tests f
-tests/nquote.right f
-tests/nquote1.sub f
-tests/nquote2.sub f
-tests/nquote1.tests f
-tests/nquote1.right f
-tests/nquote2.tests f
-tests/nquote2.right f
-tests/nquote3.tests f
-tests/nquote3.right f
-tests/nquote4.tests f
-tests/nquote4.right f
-tests/nquote5.tests f
-tests/nquote5.right f
-tests/posix2.tests f
-tests/posix2.right f
-tests/posixexp.tests f
-tests/posixexp.right f
-tests/posixexp1.sub f
-tests/posixexp2.sub f
-tests/posixexp2.tests f
-tests/posixexp2.right f
-tests/posixpat.tests f
-tests/posixpat.right f
-tests/posixpipe.tests f
-tests/posixpipe.right f
-tests/prec.right f
-tests/precedence f
-tests/printf.tests f
-tests/printf.right f
-tests/printf1.sub f
-tests/printf2.sub f
-tests/printf3.sub f
-tests/printf4.sub f
-tests/quote.tests f
-tests/quote.right f
-tests/quote1.sub f
-tests/read.tests f
-tests/read.right f
-tests/read1.sub f
-tests/read2.sub f
-tests/read3.sub f
-tests/read4.sub f
-tests/read5.sub f
-tests/read6.sub f
-tests/redir.tests f
-tests/redir.right f
-tests/redir1.sub f
-tests/redir2.sub f
-tests/redir3.sub f
-tests/redir3.in1 f
-tests/redir3.in2 f
-tests/redir4.sub f
-tests/redir4.in1 f
-tests/redir5.sub f
-tests/redir6.sub f
-tests/redir7.sub f
-tests/redir8.sub f
-tests/redir9.sub f
-tests/redir10.sub f
-tests/rhs-exp.tests f
-tests/rhs-exp.right f
-tests/rhs-exp1.sub f
-tests/rsh.tests f
-tests/rsh.right f
-tests/run-all f
-tests/run-minimal f
-tests/run-alias f
-tests/run-appendop f
-tests/run-arith-for f
-tests/run-arith f
-tests/run-array f
-tests/run-array2 f
-tests/run-assoc f
-tests/run-braces f
-tests/run-builtins f
-tests/run-case f
-tests/run-casemod f
-tests/run-comsub f
-tests/run-comsub-eof f
-tests/run-comsub-posix f
-tests/run-cond f
-tests/run-coproc f
-tests/run-cprint f
-tests/run-dbg-support f
-tests/run-dbg-support2 f
-tests/run-dirstack f
-tests/run-dollars f
-tests/run-errors f
-tests/run-execscript f
-tests/run-exp-tests f
-tests/run-extglob f
-tests/run-extglob2 f
-tests/run-extglob3 f
-tests/run-func f
-tests/run-getopts f
-tests/run-glob-test f
-tests/run-globstar f
-tests/run-heredoc f
-tests/run-herestr f
-tests/run-histexpand f
-tests/run-history f
-tests/run-ifs f
-tests/run-ifs-posix f
-tests/run-input-test f
-tests/run-intl f
-tests/run-iquote f
-tests/run-invert f
-tests/run-jobs f
-tests/run-lastpipe f
-tests/run-mapfile f
-tests/run-more-exp f
-tests/run-nameref f
-tests/run-new-exp f
-tests/run-nquote f
-tests/run-nquote1 f
-tests/run-nquote2 f
-tests/run-nquote3 f
-tests/run-nquote4 f
-tests/run-nquote5 f
-tests/run-posix2 f
-tests/run-posixexp f
-tests/run-posixexp2 f
-tests/run-posixpat f
-tests/run-posixpipe f
-tests/run-precedence f
-tests/run-printf f
-tests/run-quote f
-tests/run-read f
-tests/run-redir f
-tests/run-rhs-exp f
-tests/run-rsh f
-tests/run-set-e f
-tests/run-set-x f
-tests/run-shopt f
-tests/run-strip f
-tests/run-test f
-tests/run-tilde f
-tests/run-tilde2 f
-tests/run-trap f
-tests/run-type f
-tests/run-varenv f
-tests/run-vredir f
-tests/set-e.tests f
-tests/set-e1.sub f
-tests/set-e2.sub f
-tests/set-e3.sub f
-tests/set-e3a.sub f
-tests/set-e.right f
-tests/set-x.tests f
-tests/set-x1.sub f
-tests/set-x.right f
-tests/shopt.tests f
-tests/shopt.right f
-tests/strip.tests f
-tests/strip.right f
-tests/test.tests f
-tests/test.right f
-tests/tilde.tests f
-tests/tilde.right f
-tests/tilde2.tests f
-tests/tilde2.right f
-tests/trap.tests f
-tests/trap.right f
-tests/trap1.sub f 755
-tests/trap2.sub f 755
-tests/trap2a.sub f 755
-tests/trap3.sub f
-tests/trap4.sub f
-tests/trap5.sub f
-tests/type.tests f
-tests/type.right f
-tests/type1.sub f
-tests/type2.sub f
-tests/type3.sub f
-tests/type4.sub f
-tests/unicode1.sub f
-tests/unicode2.sub f
-tests/unicode3.sub f
-tests/varenv.right f
-tests/varenv.sh f
-tests/varenv1.sub f
-tests/varenv2.sub f
-tests/varenv3.sub f
-tests/varenv4.sub f
-tests/varenv5.sub f
-tests/varenv6.sub f
-tests/version f
-tests/version.mini f
-tests/vredir.tests f
-tests/vredir.right f
-tests/vredir1.sub f
-tests/vredir2.sub f
-tests/vredir3.sub f
-tests/vredir4.sub f
-tests/vredir5.sub f
-tests/vredir6.sub f
-tests/misc/dev-tcp.tests f
-tests/misc/perf-script f
-tests/misc/perftest f
-tests/misc/read-nchars.tests f
-tests/misc/redir-t2.sh f
-tests/misc/run-r2.sh f
-tests/misc/sigint-1.sh f
-tests/misc/sigint-2.sh f
-tests/misc/sigint-3.sh f
-tests/misc/sigint-4.sh f
-tests/misc/test-minus-e.1 f
-tests/misc/test-minus-e.2 f
-tests/misc/wait-bg.tests f
-#examples/scripts.v2/PERMISSION f
-#examples/scripts.v2/README f
-#examples/scripts.v2/arc2tarz f
-#examples/scripts.v2/bashrand f
-#examples/scripts.v2/cal2day.bash f
-#examples/scripts.v2/cdhist.bash f
-#examples/scripts.v2/corename f
-#examples/scripts.v2/fman f
-#examples/scripts.v2/frcp f
-#examples/scripts.v2/lowercase f
-#examples/scripts.v2/ncp f
-#examples/scripts.v2/newext f
-#examples/scripts.v2/nmv f
-#examples/scripts.v2/pages f
-#examples/scripts.v2/pf f
-#examples/scripts.v2/ren f
-#examples/scripts.v2/rename f
-#examples/scripts.v2/repeat f
-#examples/scripts.v2/untar f
-#examples/scripts.v2/uudec f
-#examples/scripts.v2/uuenc f
-#examples/scripts.v2/vtree f
-#examples/scripts.v2/where f
-#examples/scripts.v2/pmtop f
-#examples/scripts.v2/shprof f
-#examples/scripts.noah/PERMISSION f
-#examples/scripts.noah/README f
-#examples/scripts.noah/aref.bash f
-#examples/scripts.noah/bash.sub.bash f
-#examples/scripts.noah/bash_version.bash f
-#examples/scripts.noah/meta.bash f
-#examples/scripts.noah/mktmp.bash f
-#examples/scripts.noah/number.bash f
-#examples/scripts.noah/prompt.bash f
-#examples/scripts.noah/remap_keys.bash f
-#examples/scripts.noah/require.bash f
-#examples/scripts.noah/send_mail.bash f
-#examples/scripts.noah/shcat.bash f
-#examples/scripts.noah/source.bash f
-#examples/scripts.noah/string.bash f
-#examples/scripts.noah/stty.bash f
-#examples/scripts.noah/y_or_n_p.bash f
+++ /dev/null
-/* bashhist.c -- bash interface to the GNU history library. */
-
-/* Copyright (C) 1993-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 (HISTORY)
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
- # include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include "bashtypes.h"
-#include <stdio.h>
-#include <errno.h>
-#include "bashansi.h"
-#include "posixstat.h"
-#include "filecntl.h"
-
-#include "bashintl.h"
-
-#if defined (SYSLOG_HISTORY)
-# include <syslog.h>
-#endif
-
-#include "shell.h"
-#include "flags.h"
-#include "input.h"
-#include "parser.h" /* for the struct dstack stuff. */
-#include "pathexp.h" /* for the struct ignorevar stuff */
-#include "bashhist.h" /* matching prototypes and declarations */
-#include "builtins/common.h"
-
-#include <readline/history.h>
-#include <glob/glob.h>
-#include <glob/strmatch.h>
-
-#if defined (READLINE)
-# include "bashline.h"
-extern int rl_done, rl_dispatching; /* should really include readline.h */
-#endif
-
-#if !defined (errno)
-extern int errno;
-#endif
-
-static int histignore_item_func __P((struct ign *));
-static int check_history_control __P((char *));
-static void hc_erasedups __P((char *));
-static void really_add_history __P((char *));
-
-static struct ignorevar histignore =
-{
- "HISTIGNORE",
- (struct ign *)0,
- 0,
- (char *)0,
- (sh_iv_item_func_t *)histignore_item_func,
-};
-
-#define HIGN_EXPAND 0x01
-
-/* Declarations of bash history variables. */
-/* Non-zero means to remember lines typed to the shell on the history
- list. This is different than the user-controlled behaviour; this
- becomes zero when we read lines from a file, for example. */
-int remember_on_history = 1;
-int enable_history_list = 1; /* value for `set -o history' */
-
-/* The number of lines that Bash has added to this history session. The
- difference between the number of the top element in the history list
- (offset from history_base) and the number of lines in the history file.
- Appending this session's history to the history file resets this to 0. */
-int history_lines_this_session;
-
-/* The number of lines that Bash has read from the history file. */
-int history_lines_in_file;
-
-#if defined (BANG_HISTORY)
-/* Non-zero means do no history expansion on this line, regardless
- of what history_expansion says. */
-int history_expansion_inhibited;
-#endif
-
-/* With the old default, every line was saved in the history individually.
- I.e., if the user enters:
- bash$ for i in a b c
- > do
- > echo $i
- > done
- Each line will be individually saved in the history.
- bash$ history
- 10 for i in a b c
- 11 do
- 12 echo $i
- 13 done
- 14 history
- If the variable command_oriented_history is set, multiple lines
- which form one command will be saved as one history entry.
- bash$ for i in a b c
- > do
- > echo $i
- > done
- bash$ history
- 10 for i in a b c
- do
- echo $i
- done
- 11 history
- The user can then recall the whole command all at once instead
- of just being able to recall one line at a time.
-
- This is now enabled by default.
- */
-int command_oriented_history = 1;
-
-/* Set to 1 if the first line of a possibly-multi-line command was saved
- in the history list. Managed by maybe_add_history(), but global so
- the history-manipluating builtins can see it. */
-int current_command_first_line_saved = 0;
-
-/* Non-zero means to store newlines in the history list when using
- command_oriented_history rather than trying to use semicolons. */
-int literal_history;
-
-/* Non-zero means to append the history to the history file at shell
- exit, even if the history has been stifled. */
-int force_append_history;
-
-/* A nit for picking at history saving. Flags have the following values:
-
- Value == 0 means save all lines parsed by the shell on the history.
- Value & HC_IGNSPACE means save all lines that do not start with a space.
- Value & HC_IGNDUPS means save all lines that do not match the last
- line saved.
- Value & HC_ERASEDUPS means to remove all other matching lines from the
- history list before saving the latest line. */
-int history_control;
-
-/* Set to 1 if the last command was added to the history list successfully
- as a separate history entry; set to 0 if the line was ignored or added
- to a previous entry as part of command-oriented-history processing. */
-int hist_last_line_added;
-
-/* Set to 1 if builtins/history.def:push_history added the last history
- entry. */
-int hist_last_line_pushed;
-
-#if defined (READLINE)
-/* If non-zero, and readline is being used, the user is offered the
- chance to re-edit a failed history expansion. */
-int history_reediting;
-
-/* If non-zero, and readline is being used, don't directly execute a
- line with history substitution. Reload it into the editing buffer
- instead and let the user further edit and confirm with a newline. */
-int hist_verify;
-
-#endif /* READLINE */
-
-/* Non-zero means to not save function definitions in the history list. */
-int dont_save_function_defs;
-
-/* Variables declared in other files used here. */
-extern int current_command_line_count;
-
-extern struct dstack dstack;
-extern int parser_state;
-
-static int bash_history_inhibit_expansion __P((char *, int));
-#if defined (READLINE)
-static void re_edit __P((char *));
-#endif
-static int history_expansion_p __P((char *));
-static int shell_comment __P((char *));
-static int should_expand __P((char *));
-static HIST_ENTRY *last_history_entry __P((void));
-static char *expand_histignore_pattern __P((char *));
-static int history_should_ignore __P((char *));
-
-/* Is the history expansion starting at string[i] one that should not
- be expanded? */
-static int
-bash_history_inhibit_expansion (string, i)
- char *string;
- int i;
-{
- /* The shell uses ! as a pattern negation character in globbing [...]
- expressions, so let those pass without expansion. */
- if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
- return (1);
- /* The shell uses ! as the indirect expansion character, so let those
- expansions pass as well. */
- else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
- member ('}', string + i + 1))
- return (1);
- /* The shell uses $! as a defined parameter expansion. */
- else if (i > 1 && string[i - 1] == '$' && string[i] == '!')
- return (1);
-#if defined (EXTENDED_GLOB)
- else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
- return (1);
-#endif
- else
- return (0);
-}
-
-void
-bash_initialize_history ()
-{
- history_quotes_inhibit_expansion = 1;
- history_search_delimiter_chars = ";&()|<>";
- history_inhibit_expansion_function = bash_history_inhibit_expansion;
-#if defined (BANG_HISTORY)
- sv_histchars ("histchars");
-#endif
-}
-
-void
-bash_history_reinit (interact)
- int interact;
-{
-#if defined (BANG_HISTORY)
- history_expansion = interact != 0;
- history_expansion_inhibited = 1;
-#endif
- remember_on_history = enable_history_list = interact != 0;
- history_inhibit_expansion_function = bash_history_inhibit_expansion;
-}
-
-void
-bash_history_disable ()
-{
- remember_on_history = 0;
-#if defined (BANG_HISTORY)
- history_expansion_inhibited = 1;
-#endif
-}
-
-void
-bash_history_enable ()
-{
- remember_on_history = 1;
-#if defined (BANG_HISTORY)
- history_expansion_inhibited = 0;
-#endif
- history_inhibit_expansion_function = bash_history_inhibit_expansion;
- sv_history_control ("HISTCONTROL");
- sv_histignore ("HISTIGNORE");
-}
-
-/* Load the history list from the history file. */
-void
-load_history ()
-{
- char *hf;
-
- /* Truncate history file for interactive shells which desire it.
- Note that the history file is automatically truncated to the
- size of HISTSIZE if the user does not explicitly set the size
- differently. */
- set_if_not ("HISTSIZE", "500");
- sv_histsize ("HISTSIZE");
-
- set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
- sv_histsize ("HISTFILESIZE");
-
- /* Read the history in HISTFILE into the history list. */
- hf = get_string_value ("HISTFILE");
-
- if (hf && *hf && file_exists (hf))
- {
- read_history (hf);
- using_history ();
- history_lines_in_file = where_history ();
- }
-}
-
-void
-bash_clear_history ()
-{
- clear_history ();
- history_lines_this_session = 0;
-}
-
-/* Delete and free the history list entry at offset I. */
-int
-bash_delete_histent (i)
- int i;
-{
- HIST_ENTRY *discard;
-
- discard = remove_history (i);
- if (discard)
- free_history_entry (discard);
- history_lines_this_session--;
-
- return 1;
-}
-
-int
-bash_delete_last_history ()
-{
- register int i;
- HIST_ENTRY **hlist, *histent;
- int r;
-
- hlist = history_list ();
- if (hlist == NULL)
- return 0;
-
- for (i = 0; hlist[i]; i++)
- ;
- i--;
-
- /* History_get () takes a parameter that must be offset by history_base. */
- histent = history_get (history_base + i); /* Don't free this */
- if (histent == NULL)
- return 0;
-
- r = bash_delete_histent (i);
-
- if (where_history () > history_length)
- history_set_pos (history_length);
-
- return r;
-}
-
-#ifdef INCLUDE_UNUSED
-/* Write the existing history out to the history file. */
-void
-save_history ()
-{
- char *hf;
- int r;
-
- hf = get_string_value ("HISTFILE");
- if (hf && *hf && file_exists (hf))
- {
- /* Append only the lines that occurred this session to
- the history file. */
- using_history ();
-
- if (history_lines_this_session <= where_history () || force_append_history)
- r = append_history (history_lines_this_session, hf);
- else
- r = write_history (hf);
- sv_histsize ("HISTFILESIZE");
- }
-}
-#endif
-
-int
-maybe_append_history (filename)
- char *filename;
-{
- int fd, result;
- struct stat buf;
-
- result = EXECUTION_SUCCESS;
- if (history_lines_this_session && (history_lines_this_session <= where_history ()))
- {
- /* If the filename was supplied, then create it if necessary. */
- if (stat (filename, &buf) == -1 && errno == ENOENT)
- {
- fd = open (filename, O_WRONLY|O_CREAT, 0600);
- if (fd < 0)
- {
- builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
- return (EXECUTION_FAILURE);
- }
- close (fd);
- }
- result = append_history (history_lines_this_session, filename);
- history_lines_in_file += history_lines_this_session;
- history_lines_this_session = 0;
- }
- return (result);
-}
-
-/* If this is an interactive shell, then append the lines executed
- this session to the history file. */
-int
-maybe_save_shell_history ()
-{
- int result;
- char *hf;
-
- result = 0;
- if (history_lines_this_session)
- {
- hf = get_string_value ("HISTFILE");
-
- if (hf && *hf)
- {
- /* If the file doesn't exist, then create it. */
- if (file_exists (hf) == 0)
- {
- int file;
- file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (file != -1)
- close (file);
- }
-
- /* Now actually append the lines if the history hasn't been
- stifled. If the history has been stifled, rewrite the
- history file. */
- using_history ();
- if (history_lines_this_session <= where_history () || force_append_history)
- {
- result = append_history (history_lines_this_session, hf);
- history_lines_in_file += history_lines_this_session;
- }
- else
- {
- result = write_history (hf);
- history_lines_in_file = history_lines_this_session;
- }
- history_lines_this_session = 0;
-
- sv_histsize ("HISTFILESIZE");
- }
- }
- return (result);
-}
-
-#if defined (READLINE)
-/* Tell readline () that we have some text for it to edit. */
-static void
-re_edit (text)
- char *text;
-{
- if (bash_input.type == st_stdin)
- bash_re_edit (text);
-}
-#endif /* READLINE */
-
-/* Return 1 if this line needs history expansion. */
-static int
-history_expansion_p (line)
- char *line;
-{
- register char *s;
-
- for (s = line; *s; s++)
- if (*s == history_expansion_char || *s == history_subst_char)
- return 1;
- return 0;
-}
-
-/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then
- print the results of expanding the line if there were any changes.
- If there is an error, return NULL, otherwise the expanded line is
- returned. If ADDIT is non-zero the line is added to the history
- list after history expansion. ADDIT is just a suggestion;
- REMEMBER_ON_HISTORY can veto, and does.
- Right now this does history expansion. */
-char *
-pre_process_line (line, print_changes, addit)
- char *line;
- int print_changes, addit;
-{
- char *history_value;
- char *return_value;
- int expanded;
-
- return_value = line;
- expanded = 0;
-
-# if defined (BANG_HISTORY)
- /* History expand the line. If this results in no errors, then
- add that line to the history if ADDIT is non-zero. */
- if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
- {
- expanded = history_expand (line, &history_value);
-
- if (expanded)
- {
- if (print_changes)
- {
- if (expanded < 0)
- internal_error ("%s", history_value);
-#if defined (READLINE)
- else if (hist_verify == 0 || expanded == 2)
-#else
- else
-#endif
- fprintf (stderr, "%s\n", history_value);
- }
-
- /* If there was an error, return NULL. */
- if (expanded < 0 || expanded == 2) /* 2 == print only */
- {
-# if defined (READLINE)
- if (expanded == 2 && rl_dispatching == 0 && *history_value)
-# else
- if (expanded == 2 && *history_value)
-# endif /* !READLINE */
- maybe_add_history (history_value);
-
- free (history_value);
-
-# if defined (READLINE)
- /* New hack. We can allow the user to edit the
- failed history expansion. */
- if (history_reediting && expanded < 0 && rl_done)
- re_edit (line);
-# endif /* READLINE */
- return ((char *)NULL);
- }
-
-# if defined (READLINE)
- if (hist_verify && expanded == 1)
- {
- re_edit (history_value);
- return ((char *)NULL);
- }
-# endif
- }
-
- /* Let other expansions know that return_value can be free'ed,
- and that a line has been added to the history list. Note
- that we only add lines that have something in them. */
- expanded = 1;
- return_value = history_value;
- }
-# endif /* BANG_HISTORY */
-
- if (addit && remember_on_history && *return_value)
- maybe_add_history (return_value);
-
-#if 0
- if (expanded == 0)
- return_value = savestring (line);
-#endif
-
- return (return_value);
-}
-
-/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
- * that the line is a shell comment. */
-static int
-shell_comment (line)
- char *line;
-{
- char *p;
-
- for (p = line; p && *p && whitespace (*p); p++)
- ;
- return (p && *p == '#');
-}
-
-#ifdef INCLUDE_UNUSED
-/* Remove shell comments from LINE. A `#' and anything after it is a comment.
- This isn't really useful yet, since it doesn't handle quoting. */
-static char *
-filter_comments (line)
- char *line;
-{
- char *p;
-
- for (p = line; p && *p && *p != '#'; p++)
- ;
- if (p && *p == '#')
- *p = '\0';
- return (line);
-}
-#endif
-
-/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line
- should be saved; 0 if it should be discarded. */
-static int
-check_history_control (line)
- char *line;
-{
- HIST_ENTRY *temp;
- int r;
-
- if (history_control == 0)
- return 1;
-
- /* ignorespace or ignoreboth */
- if ((history_control & HC_IGNSPACE) && *line == ' ')
- return 0;
-
- /* ignoredups or ignoreboth */
- if (history_control & HC_IGNDUPS)
- {
- using_history ();
- temp = previous_history ();
-
- r = (temp == 0 || STREQ (temp->line, line) == 0);
-
- using_history ();
-
- if (r == 0)
- return r;
- }
-
- return 1;
-}
-
-/* Remove all entries matching LINE from the history list. Triggered when
- HISTCONTROL includes `erasedups'. */
-static void
-hc_erasedups (line)
- char *line;
-{
- HIST_ENTRY *temp;
- int r;
-
- using_history ();
- while (temp = previous_history ())
- {
- if (STREQ (temp->line, line))
- {
- r = where_history ();
- remove_history (r);
- }
- }
- using_history ();
-}
-
-/* Add LINE to the history list, handling possibly multi-line compound
- commands. We note whether or not we save the first line of each command
- (which is usually the entire command and history entry), and don't add
- the second and subsequent lines of a multi-line compound command if we
- didn't save the first line. We don't usually save shell comment lines in
- compound commands in the history, because they could have the effect of
- commenting out the rest of the command when the entire command is saved as
- a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If
- LITERAL_HISTORY is set, we're saving lines in the history with embedded
- newlines, so it's OK to save comment lines. If we're collecting the body
- of a here-document, we should act as if literal_history is enabled, because
- we want to save the entire contents of the here-document as it was
- entered. We also make sure to save multiple-line quoted strings or other
- constructs. */
-void
-maybe_add_history (line)
- char *line;
-{
- hist_last_line_added = 0;
-
- /* Don't use the value of history_control to affect the second
- and subsequent lines of a multi-line command (old code did
- this only when command_oriented_history is enabled). */
- if (current_command_line_count > 1)
- {
- if (current_command_first_line_saved &&
- ((parser_state & PST_HEREDOC) || literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
- bash_add_history (line);
- return;
- }
-
- /* This is the first line of a (possible multi-line) command. Note whether
- or not we should save the first line and remember it. */
- current_command_first_line_saved = check_add_history (line, 0);
-}
-
-/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
- history if it's OK. Used by `history -s' as well as maybe_add_history().
- Returns 1 if the line was saved in the history, 0 otherwise. */
-int
-check_add_history (line, force)
- char *line;
- int force;
-{
- if (check_history_control (line) && history_should_ignore (line) == 0)
- {
- /* We're committed to saving the line. If the user has requested it,
- remove other matching lines from the history. */
- if (history_control & HC_ERASEDUPS)
- hc_erasedups (line);
-
- if (force)
- {
- really_add_history (line);
- using_history ();
- }
- else
- bash_add_history (line);
- return 1;
- }
- return 0;
-}
-
-#if defined (SYSLOG_HISTORY)
-#define SYSLOG_MAXLEN 600
-
-void
-bash_syslog_history (line)
- const char *line;
-{
- char trunc[SYSLOG_MAXLEN];
-
- if (strlen(line) < SYSLOG_MAXLEN)
- syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
- else
- {
- strncpy (trunc, line, SYSLOG_MAXLEN);
- trunc[SYSLOG_MAXLEN - 1] = '\0';
- syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
- }
-}
-#endif
-
-/* Add a line to the history list.
- The variable COMMAND_ORIENTED_HISTORY controls the style of history
- remembering; when non-zero, and LINE is not the first line of a
- complete parser construct, append LINE to the last history line instead
- of adding it as a new line. */
-void
-bash_add_history (line)
- char *line;
-{
- int add_it, offset, curlen;
- HIST_ENTRY *current, *old;
- char *chars_to_add, *new_line;
-
- add_it = 1;
- if (command_oriented_history && current_command_line_count > 1)
- {
- /* The second and subsequent lines of a here document have the trailing
- newline preserved. We don't want to add extra newlines here, but we
- do want to add one after the first line (which is the command that
- contains the here-doc specifier). parse.y:history_delimiting_chars()
- does the right thing to take care of this for us. We don't want to
- add extra newlines if the user chooses to enable literal_history,
- so we have to duplicate some of what that function does here. */
- if ((parser_state & PST_HEREDOC) && literal_history && current_command_line_count > 2 && line[strlen (line) - 1] == '\n')
- chars_to_add = "";
- else
- chars_to_add = literal_history ? "\n" : history_delimiting_chars (line);
-
- using_history ();
- current = previous_history ();
-
- if (current)
- {
- /* If the previous line ended with an escaped newline (escaped
- with backslash, but otherwise unquoted), then remove the quoted
- newline, since that is what happens when the line is parsed. */
- curlen = strlen (current->line);
-
- if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
- current->line[curlen - 2] != '\\')
- {
- current->line[curlen - 1] = '\0';
- curlen--;
- chars_to_add = "";
- }
-
- /* If we're not in some kind of quoted construct, the current history
- entry ends with a newline, and we're going to add a semicolon,
- don't. In some cases, it results in a syntax error (e.g., before
- a close brace), and it should not be needed. */
- if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
- chars_to_add++;
-
- new_line = (char *)xmalloc (1
- + curlen
- + strlen (line)
- + strlen (chars_to_add));
- sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
- offset = where_history ();
- old = replace_history_entry (offset, new_line, current->data);
- free (new_line);
-
- if (old)
- free_history_entry (old);
-
- add_it = 0;
- }
- }
-
- if (add_it)
- really_add_history (line);
-
-#if defined (SYSLOG_HISTORY)
- bash_syslog_history (line);
-#endif
-
- using_history ();
-}
-
-static void
-really_add_history (line)
- char *line;
-{
- hist_last_line_added = 1;
- hist_last_line_pushed = 0;
- add_history (line);
- history_lines_this_session++;
-}
-
-int
-history_number ()
-{
- using_history ();
- return (remember_on_history ? history_base + where_history () : 1);
-}
-
-static int
-should_expand (s)
- char *s;
-{
- char *p;
-
- for (p = s; p && *p; p++)
- {
- if (*p == '\\')
- p++;
- else if (*p == '&')
- return 1;
- }
- return 0;
-}
-
-static int
-histignore_item_func (ign)
- struct ign *ign;
-{
- if (should_expand (ign->val))
- ign->flags |= HIGN_EXPAND;
- return (0);
-}
-
-void
-setup_history_ignore (varname)
- char *varname;
-{
- setup_ignore_patterns (&histignore);
-}
-
-static HIST_ENTRY *
-last_history_entry ()
-{
- HIST_ENTRY *he;
-
- using_history ();
- he = previous_history ();
- using_history ();
- return he;
-}
-
-char *
-last_history_line ()
-{
- HIST_ENTRY *he;
-
- he = last_history_entry ();
- if (he == 0)
- return ((char *)NULL);
- return he->line;
-}
-
-static char *
-expand_histignore_pattern (pat)
- char *pat;
-{
- HIST_ENTRY *phe;
- char *ret;
-
- phe = last_history_entry ();
-
- if (phe == (HIST_ENTRY *)0)
- return (savestring (pat));
-
- ret = strcreplace (pat, '&', phe->line, 1);
-
- return ret;
-}
-
-/* Return 1 if we should not put LINE into the history according to the
- patterns in HISTIGNORE. */
-static int
-history_should_ignore (line)
- char *line;
-{
- register int i, match;
- char *npat;
-
- if (histignore.num_ignores == 0)
- return 0;
-
- for (i = match = 0; i < histignore.num_ignores; i++)
- {
- if (histignore.ignores[i].flags & HIGN_EXPAND)
- npat = expand_histignore_pattern (histignore.ignores[i].val);
- else
- npat = histignore.ignores[i].val;
-
- match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
-
- if (histignore.ignores[i].flags & HIGN_EXPAND)
- free (npat);
-
- if (match)
- break;
- }
-
- return match;
-}
-#endif /* HISTORY */
+++ /dev/null
-This file is bind.def, from which is created bind.c.
-It implements the builtin "bind" in Bash.
-
-Copyright (C) 1987-2009 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Bash is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Bash. If not, see <http://www.gnu.org/licenses/>.
-
-$PRODUCES bind.c
-
-#include <config.h>
-
-$BUILTIN bind
-$DEPENDS_ON READLINE
-$FUNCTION bind_builtin
-$SHORT_DOC bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]
-Set Readline key bindings and variables.
-
-Bind a key sequence to a Readline function or a macro, or set a
-Readline variable. The non-option argument syntax is equivalent to
-that found in ~/.inputrc, but must be passed as a single argument:
-e.g., bind '"\C-x\C-r": re-read-init-file'.
-
-Options:
- -m keymap Use KEYMAP as the keymap for the duration of this
- command. Acceptable keymap names are emacs,
- emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,
- vi-command, and vi-insert.
- -l List names of functions.
- -P List function names and bindings.
- -p List functions and bindings in a form that can be
- reused as input.
- -S List key sequences that invoke macros and their values
- -s List key sequences that invoke macros and their values
- in a form that can be reused as input.
- -V List variable names and values
- -v List variable names and values in a form that can
- be reused as input.
- -q function-name Query about which keys invoke the named function.
- -u function-name Unbind all keys which are bound to the named function.
- -r keyseq Remove the binding for KEYSEQ.
- -f filename Read key bindings from FILENAME.
- -x keyseq:shell-command Cause SHELL-COMMAND to be executed when
- KEYSEQ is entered.
- -X List key sequences bound with -x and associated commands
- in a form that can be reused as input.
-
-Exit Status:
-bind returns 0 unless an unrecognized option is given or an error occurs.
-$END
-
-#if defined (READLINE)
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-#include <readline/readline.h>
-#include <readline/history.h>
-
-#include "../bashintl.h"
-
-#include "../shell.h"
-#include "../bashline.h"
-#include "bashgetopt.h"
-#include "common.h"
-
-static int query_bindings __P((char *));
-static int unbind_command __P((char *));
-
-extern int no_line_editing;
-
-#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
-
-#define LFLAG 0x0001
-#define PFLAG 0x0002
-#define FFLAG 0x0004
-#define VFLAG 0x0008
-#define QFLAG 0x0010
-#define MFLAG 0x0020
-#define RFLAG 0x0040
-#define PPFLAG 0x0080
-#define VVFLAG 0x0100
-#define SFLAG 0x0200
-#define SSFLAG 0x0400
-#define UFLAG 0x0800
-#define XFLAG 0x1000
-#define XXFLAG 0x2000
-
-int
-bind_builtin (list)
- WORD_LIST *list;
-{
- int return_code;
- Keymap kmap, saved_keymap;
- int flags, opt;
- char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq;
-
- if (no_line_editing)
- {
-#if 0
- builtin_error (_("line editing not enabled"));
- return (EXECUTION_FAILURE);
-#else
- builtin_warning (_("line editing not enabled"));
-#endif
- }
-
- kmap = saved_keymap = (Keymap) NULL;
- flags = 0;
- initfile = map_name = fun_name = unbind_name = remove_seq = (char *)NULL;
- return_code = EXECUTION_SUCCESS;
-
- if (bash_readline_initialized == 0)
- initialize_readline ();
-
- begin_unwind_frame ("bind_builtin");
- unwind_protect_var (rl_outstream);
-
- rl_outstream = stdout;
-
- reset_internal_getopt ();
- while ((opt = internal_getopt (list, "lvpVPsSXf:q:u:m:r:x:")) != EOF)
- {
- switch (opt)
- {
- case 'l':
- flags |= LFLAG;
- break;
- case 'v':
- flags |= VFLAG;
- break;
- case 'p':
- flags |= PFLAG;
- break;
- case 'f':
- flags |= FFLAG;
- initfile = list_optarg;
- break;
- case 'm':
- flags |= MFLAG;
- map_name = list_optarg;
- break;
- case 'q':
- flags |= QFLAG;
- fun_name = list_optarg;
- break;
- case 'u':
- flags |= UFLAG;
- unbind_name = list_optarg;
- break;
- case 'r':
- flags |= RFLAG;
- remove_seq = list_optarg;
- break;
- case 'V':
- flags |= VVFLAG;
- break;
- case 'P':
- flags |= PPFLAG;
- break;
- case 's':
- flags |= SFLAG;
- break;
- case 'S':
- flags |= SSFLAG;
- break;
- case 'x':
- flags |= XFLAG;
- cmd_seq = list_optarg;
- break;
- case 'X':
- flags |= XXFLAG;
- break;
- default:
- builtin_usage ();
- BIND_RETURN (EX_USAGE);
- }
- }
-
- list = loptend;
-
- /* First, see if we need to install a special keymap for this
- command. Then start on the arguments. */
-
- if ((flags & MFLAG) && map_name)
- {
- kmap = rl_get_keymap_by_name (map_name);
- if (kmap == 0)
- {
- builtin_error (_("`%s': invalid keymap name"), map_name);
- BIND_RETURN (EXECUTION_FAILURE);
- }
- }
-
- if (kmap)
- {
- saved_keymap = rl_get_keymap ();
- rl_set_keymap (kmap);
- }
-
- /* XXX - we need to add exclusive use tests here. It doesn't make sense
- to use some of these options together. */
- /* Now hack the option arguments */
- if (flags & LFLAG)
- rl_list_funmap_names ();
-
- if (flags & PFLAG)
- rl_function_dumper (1);
-
- if (flags & PPFLAG)
- rl_function_dumper (0);
-
- if (flags & SFLAG)
- rl_macro_dumper (1);
-
- if (flags & SSFLAG)
- rl_macro_dumper (0);
-
- if (flags & VFLAG)
- rl_variable_dumper (1);
-
- if (flags & VVFLAG)
- rl_variable_dumper (0);
-
- if ((flags & FFLAG) && initfile)
- {
- if (rl_read_init_file (initfile) != 0)
- {
- builtin_error (_("%s: cannot read: %s"), initfile, strerror (errno));
- BIND_RETURN (EXECUTION_FAILURE);
- }
- }
-
- if ((flags & QFLAG) && fun_name)
- return_code = query_bindings (fun_name);
-
- if ((flags & UFLAG) && unbind_name)
- return_code = unbind_command (unbind_name);
-
- if ((flags & RFLAG) && remove_seq)
- {
- if (rl_bind_keyseq (remove_seq, (rl_command_func_t *)NULL) != 0)
- {
- builtin_error (_("`%s': cannot unbind"), remove_seq);
- BIND_RETURN (EXECUTION_FAILURE);
- }
- }
-
- if (flags & XFLAG)
- return_code = bind_keyseq_to_unix_command (cmd_seq);
-
- if (flags & XXFLAG)
- return_code = print_unix_command_map ();
-
- /* Process the rest of the arguments as binding specifications. */
- while (list)
- {
- rl_parse_and_bind (list->word->word);
- list = list->next;
- }
-
- bind_exit:
- if (saved_keymap)
- rl_set_keymap (saved_keymap);
-
- run_unwind_frame ("bind_builtin");
-
- return (sh_chkwrite (return_code));
-}
-
-static int
-query_bindings (name)
- char *name;
-{
- rl_command_func_t *function;
- char **keyseqs;
- int j;
-
- function = rl_named_function (name);
- if (function == 0)
- {
- builtin_error (_("`%s': unknown function name"), name);
- return EXECUTION_FAILURE;
- }
-
- keyseqs = rl_invoking_keyseqs (function);
-
- if (!keyseqs)
- {
- printf (_("%s is not bound to any keys.\n"), name);
- return EXECUTION_FAILURE;
- }
-
- printf (_("%s can be invoked via "), name);
- for (j = 0; j < 5 && keyseqs[j]; j++)
- printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n");
- if (keyseqs[j])
- printf ("...\n");
- strvec_dispose (keyseqs);
- return EXECUTION_SUCCESS;
-}
-
-static int
-unbind_command (name)
- char *name;
-{
- rl_command_func_t *function;
-
- function = rl_named_function (name);
- if (function == 0)
- {
- builtin_error (_("`%s': unknown function name"), name);
- return EXECUTION_FAILURE;
- }
-
- rl_unbind_function_in_map (function, rl_get_keymap ());
- return EXECUTION_SUCCESS;
-}
-#endif /* READLINE */
+++ /dev/null
-This file is hash.def, from which is created hash.c.
-It implements the builtin "hash" in Bash.
-
-Copyright (C) 1987-2013 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Bash is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Bash. If not, see <http://www.gnu.org/licenses/>.
-
-$PRODUCES hash.c
-
-$BUILTIN hash
-$FUNCTION hash_builtin
-$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
-Remember or display program locations.
-
-Determine and remember the full pathname of each command NAME. If
-no arguments are given, information about remembered commands is displayed.
-
-Options:
- -d forget the remembered location of each NAME
- -l display in a format that may be reused as input
- -p pathname use PATHNAME as the full pathname of NAME
- -r forget all remembered locations
- -t print the remembered location of each NAME, preceding
- each location with the corresponding NAME if multiple
- NAMEs are given
-Arguments:
- NAME Each NAME is searched for in $PATH and added to the list
- of remembered commands.
-
-Exit Status:
-Returns success unless NAME is not found or an invalid option is given.
-$END
-
-#include <config.h>
-
-#include <stdio.h>
-
-#include "../bashtypes.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include <errno.h>
-
-#include "../bashansi.h"
-#include "../bashintl.h"
-
-#include "../shell.h"
-#include "../builtins.h"
-#include "../flags.h"
-#include "../findcmd.h"
-#include "../hashcmd.h"
-#include "common.h"
-#include "bashgetopt.h"
-
-extern int posixly_correct;
-extern int dot_found_in_search;
-extern char *this_command_name;
-
-static int add_hashed_command __P((char *, int));
-static int print_hash_info __P((BUCKET_CONTENTS *));
-static int print_portable_hash_info __P((BUCKET_CONTENTS *));
-static int print_hashed_commands __P((int));
-static int list_hashed_filename_targets __P((WORD_LIST *, int));
-
-/* Print statistics on the current state of hashed commands. If LIST is
- not empty, then rehash (or hash in the first place) the specified
- commands. */
-int
-hash_builtin (list)
- WORD_LIST *list;
-{
- int expunge_hash_table, list_targets, list_portably, delete, opt;
- char *w, *pathname;
-
- if (hashing_enabled == 0)
- {
- builtin_error (_("hashing disabled"));
- return (EXECUTION_FAILURE);
- }
-
- expunge_hash_table = list_targets = list_portably = delete = 0;
- pathname = (char *)NULL;
- reset_internal_getopt ();
- while ((opt = internal_getopt (list, "dlp:rt")) != -1)
- {
- switch (opt)
- {
- case 'd':
- delete = 1;
- break;
- case 'l':
- list_portably = 1;
- break;
- case 'p':
- pathname = list_optarg;
- break;
- case 'r':
- expunge_hash_table = 1;
- break;
- case 't':
- list_targets = 1;
- break;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
-
- /* hash -t requires at least one argument. */
- if (list == 0 && list_targets)
- {
- sh_needarg ("-t");
- return (EXECUTION_FAILURE);
- }
-
- /* We want hash -r to be silent, but hash -- to print hashing info, so
- we test expunge_hash_table. */
- if (list == 0 && expunge_hash_table == 0)
- {
- opt = print_hashed_commands (list_portably);
- if (opt == 0 && posixly_correct == 0)
- printf (_("%s: hash table empty\n"), this_command_name);
-
- return (EXECUTION_SUCCESS);
- }
-
- if (expunge_hash_table)
- phash_flush ();
-
- /* If someone runs `hash -r -t xyz' he will be disappointed. */
- if (list_targets)
- return (list_hashed_filename_targets (list, list_portably));
-
-#if defined (RESTRICTED_SHELL)
- if (restricted && pathname && strchr (pathname, '/'))
- {
- sh_restricted (pathname);
- return (EXECUTION_FAILURE);
- }
-#endif
-
- for (opt = EXECUTION_SUCCESS; list; list = list->next)
- {
- /* Add, remove or rehash the specified commands. */
- w = list->word->word;
- if (absolute_program (w))
- continue;
- else if (pathname)
- {
- if (is_directory (pathname))
- {
-#ifdef EISDIR
- builtin_error ("%s: %s", pathname, strerror (EISDIR));
-#else
- builtin_error (_("%s: is a directory"), pathname);
-#endif
- opt = EXECUTION_FAILURE;
- }
- else
- phash_insert (w, pathname, 0, 0);
- }
- else if (delete)
- {
- if (phash_remove (w))
- {
- sh_notfound (w);
- opt = EXECUTION_FAILURE;
- }
- }
- else if (add_hashed_command (w, 0))
- opt = EXECUTION_FAILURE;
- }
-
- fflush (stdout);
- return (opt);
-}
-
-static int
-add_hashed_command (w, quiet)
- char *w;
- int quiet;
-{
- int rv;
- char *full_path;
-
- rv = 0;
- if (find_function (w) == 0 && find_shell_builtin (w) == 0)
- {
- phash_remove (w);
- full_path = find_user_command (w);
- if (full_path && executable_file (full_path))
- phash_insert (w, full_path, dot_found_in_search, 0);
- else
- {
- if (quiet == 0)
- sh_notfound (w);
- rv++;
- }
- FREE (full_path);
- }
- return (rv);
-}
-
-/* Print information about current hashed info. */
-static int
-print_hash_info (item)
- BUCKET_CONTENTS *item;
-{
- printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
- return 0;
-}
-
-static int
-print_portable_hash_info (item)
- BUCKET_CONTENTS *item;
-{
- printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key);
- return 0;
-}
-
-static int
-print_hashed_commands (fmt)
- int fmt;
-{
- if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
- return (0);
-
- if (fmt == 0)
- printf (_("hits\tcommand\n"));
- hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
- return (1);
-}
-
-static int
-list_hashed_filename_targets (list, fmt)
- WORD_LIST *list;
- int fmt;
-{
- int all_found, multiple;
- char *target;
- WORD_LIST *l;
-
- all_found = 1;
- multiple = list->next != 0;
-
- for (l = list; l; l = l->next)
- {
- target = phash_search (l->word->word);
- if (target == 0)
- {
- all_found = 0;
- sh_notfound (l->word->word);
- continue;
- }
- if (fmt)
- printf ("builtin hash -p %s %s\n", target, l->word->word);
- else
- {
- if (multiple)
- printf ("%s\t", l->word->word);
- printf ("%s\n", target);
- }
- free (target);
- }
-
- return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
-}
+++ /dev/null
-This file is help.def, from which is created help.c.
-It implements the builtin "help" in Bash.
-
-Copyright (C) 1987-2013 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Bash is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Bash. If not, see <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, m, pass, this_found;
-
- 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 (pass = 1, this_found = 0; pass < 3; pass++)
- {
- for (i = 0; name = shell_builtins[i].name; i++)
- {
- QUIT;
-
- /* First pass: look for exact string or pattern matches.
- Second pass: look for prefix matches like bash-4.2 */
- if (pass == 1)
- m = (strcmp (pattern, name) == 0) ||
- (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
- else
- m = strncmp (pattern, name, plen) == 0;
-
- if (m)
- {
- this_found = 1;
- 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 (pass == 1 && this_found == 1)
- break;
- }
- }
-
- 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);
-}
-
-#if defined (HANDLE_MULTIBYTE)
-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, n;
- 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 - 2;
- wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
- n = mbstowcs (wcstr+1, helpdoc, slen + 1);
- wcstr[n+1] = L'\0';
-
- /* Turn tabs and newlines into spaces for column display, since wcwidth
- returns -1 for them */
- for (j = 1; j < n; j++)
- if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
- wcstr[j] = L' ';
-
- displen = wcsnwidth (wcstr+1, slen, width - 2) + 1; /* +1 for ' ' or '*' */
-
- wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
-
- /* This assumes each wide char takes up one column position when displayed */
- 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;
- }
-
- /* at least one space */
- 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 - 2;
- n = mbstowcs (wcstr+1, helpdoc, slen + 1);
- wcstr[n+1] = L'\0'; /* make sure null-terminated */
-
- /* Turn tabs and newlines into spaces for column display */
- for (j = 1; j < n; j++)
- if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
- wcstr[j] = L' ';
-
- displen = wcsnwidth (wcstr+1, slen, width - 2);
-
- wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
-
- /* This assumes each wide char takes up one column position when displayed */
- wcstr[width - 3] = L'>'; /* indicate truncation */
- wcstr[width - 2] = L'\0';
-
- printf ("%ls\n", wcstr);
-
- free (wcstr);
-}
-#endif /* HANDLE_MULTIBYTE */
-
-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;
-
-#if defined (HANDLE_MULTIBYTE)
- if (MB_CUR_MAX > 1)
- wdispcolumn (i, blurb, sizeof (blurb), width, height);
- else
-#endif
- dispcolumn (i, blurb, sizeof (blurb), width, height);
- }
-}
-#endif /* HELP_BUILTIN */
+++ /dev/null
-This file is type.def, from which is created type.c.
-It implements the builtin "type" in Bash.
-
-Copyright (C) 1987-2011 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Bash is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Bash. If not, see <http://www.gnu.org/licenses/>.
-
-$PRODUCES type.c
-
-$BUILTIN type
-$FUNCTION type_builtin
-$SHORT_DOC type [-afptP] name [name ...]
-Display information about command type.
-
-For each NAME, indicate how it would be interpreted if used as a
-command name.
-
-Options:
- -a display all locations containing an executable named NAME;
- includes aliases, builtins, and functions, if and only if
- the `-p' option is not also used
- -f suppress shell function lookup
- -P force a PATH search for each NAME, even if it is an alias,
- builtin, or function, and returns the name of the disk file
- that would be executed
- -p returns either the name of the disk file that would be executed,
- or nothing if `type -t NAME' would not return `file'.
- -t output a single word which is one of `alias', `keyword',
- `function', `builtin', `file' or `', if NAME is an alias, shell
- reserved word, shell function, shell builtin, disk file, or not
- found, respectively
-
-Arguments:
- NAME Command name to be interpreted.
-
-Exit Status:
-Returns success if all of the NAMEs are found; fails if any are not found.
-$END
-
-#include <config.h>
-
-#include "../bashtypes.h"
-#include "posixstat.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include "../bashansi.h"
-#include "../bashintl.h"
-
-#include "../shell.h"
-#include "../findcmd.h"
-#include "../hashcmd.h"
-
-#if defined (ALIAS)
-#include "../alias.h"
-#endif /* ALIAS */
-
-#include "common.h"
-#include "bashgetopt.h"
-
-extern int find_reserved_word __P((char *));
-
-extern char *this_command_name;
-extern int expand_aliases, posixly_correct;
-
-/* For each word in LIST, find out what the shell is going to do with
- it as a simple command. i.e., which file would this shell use to
- execve, or if it is a builtin command, or an alias. Possible flag
- arguments:
- -t Returns the "type" of the object, one of
- `alias', `keyword', `function', `builtin',
- or `file'.
-
- -p Returns the pathname of the file if -type is
- a file.
-
- -a Returns all occurrences of words, whether they
- be a filename in the path, alias, function,
- or builtin.
-
- -f Suppress shell function lookup, like `command'.
-
- -P Force a path search even in the presence of other
- definitions.
-
- Order of evaluation:
- alias
- keyword
- function
- builtin
- file
- */
-
-int
-type_builtin (list)
- WORD_LIST *list;
-{
- int dflags, any_failed, opt;
- WORD_LIST *this;
-
- if (list == 0)
- return (EXECUTION_SUCCESS);
-
- dflags = CDESC_SHORTDESC; /* default */
- any_failed = 0;
-
- /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
- the arguments and converting those options to the form that
- internal_getopt recognizes. Converts `--type', `--path', and `--all'
- also. THIS SHOULD REALLY GO AWAY. */
- for (this = list; this && this->word->word[0] == '-'; this = this->next)
- {
- char *flag = &(this->word->word[1]);
-
- if (STREQ (flag, "type") || STREQ (flag, "-type"))
- {
- this->word->word[1] = 't';
- this->word->word[2] = '\0';
- }
- else if (STREQ (flag, "path") || STREQ (flag, "-path"))
- {
- this->word->word[1] = 'p';
- this->word->word[2] = '\0';
- }
- else if (STREQ (flag, "all") || STREQ (flag, "-all"))
- {
- this->word->word[1] = 'a';
- this->word->word[2] = '\0';
- }
- }
-
- reset_internal_getopt ();
- while ((opt = internal_getopt (list, "afptP")) != -1)
- {
- switch (opt)
- {
- case 'a':
- dflags |= CDESC_ALL;
- break;
- case 'f':
- dflags |= CDESC_NOFUNCS;
- break;
- case 'p':
- dflags |= CDESC_PATH_ONLY;
- dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
- break;
- case 't':
- dflags |= CDESC_TYPE;
- dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
- break;
- case 'P': /* shorthand for type -ap */
- dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
- dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
- break;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
-
- while (list)
- {
- int found;
-
- found = describe_command (list->word->word, dflags);
-
- if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
- sh_notfound (list->word->word);
-
- any_failed += found == 0;
- list = list->next;
- }
-
- opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
- return (sh_chkwrite (opt));
-}
-
-/*
- * Describe COMMAND as required by the type and command builtins.
- *
- * Behavior is controlled by DFLAGS. Flag values are
- * CDESC_ALL print all descriptions of a command
- * CDESC_SHORTDESC print the description for type and command -V
- * CDESC_REUSABLE print in a format that may be reused as input
- * CDESC_TYPE print the type for type -t
- * CDESC_PATH_ONLY print the path for type -p
- * CDESC_FORCE_PATH force a path search for type -P
- * CDESC_NOFUNCS skip function lookup for type -f
- * CDESC_ABSPATH convert to absolute path, no ./ prefix
- *
- * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
- * return after finding it once.
- */
-int
-describe_command (command, dflags)
- char *command;
- int dflags;
-{
- int found, i, found_file, f, all;
- char *full_path, *x;
- SHELL_VAR *func;
-#if defined (ALIAS)
- alias_t *alias;
-#endif
-
- all = (dflags & CDESC_ALL) != 0;
- found = found_file = 0;
- full_path = (char *)NULL;
-
-#if defined (ALIAS)
- /* Command is an alias? */
- if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
- {
- if (dflags & CDESC_TYPE)
- puts ("alias");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is aliased to `%s'\n"), command, alias->value);
- else if (dflags & CDESC_REUSABLE)
- {
- x = sh_single_quote (alias->value);
- printf ("alias %s=%s\n", command, x);
- free (x);
- }
-
- found = 1;
-
- if (all == 0)
- return (1);
- }
-#endif /* ALIAS */
-
- /* Command is a shell reserved word? */
- if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
- {
- if (dflags & CDESC_TYPE)
- puts ("keyword");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is a shell keyword\n"), command);
- else if (dflags & CDESC_REUSABLE)
- printf ("%s\n", command);
-
- found = 1;
-
- if (all == 0)
- return (1);
- }
-
- /* Command is a function? */
- if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
- {
- if (dflags & CDESC_TYPE)
- puts ("function");
- else if (dflags & CDESC_SHORTDESC)
- {
- char *result;
-
- printf (_("%s is a function\n"), command);
-
- /* We're blowing away THE_PRINTED_COMMAND here... */
-
- result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
- printf ("%s\n", result);
- }
- else if (dflags & CDESC_REUSABLE)
- printf ("%s\n", command);
-
- found = 1;
-
- if (all == 0)
- return (1);
- }
-
- /* Command is a builtin? */
- if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
- {
- if (dflags & CDESC_TYPE)
- puts ("builtin");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is a shell builtin\n"), command);
- else if (dflags & CDESC_REUSABLE)
- printf ("%s\n", command);
-
- found = 1;
-
- if (all == 0)
- return (1);
- }
-
- /* Command is a disk file? */
- /* If the command name given is already an absolute command, just
- check to see if it is executable. */
- if (absolute_program (command))
- {
- f = file_status (command);
- if (f & FS_EXECABLE)
- {
- if (dflags & CDESC_TYPE)
- puts ("file");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is %s\n"), command, command);
- else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
- printf ("%s\n", command);
-
- /* There's no use looking in the hash table or in $PATH,
- because they're not consulted when an absolute program
- name is supplied. */
- return (1);
- }
- }
-
- /* If the user isn't doing "-a", then we might care about
- whether the file is present in our hash table. */
- if (all == 0 || (dflags & CDESC_FORCE_PATH))
- {
- if (full_path = phash_search (command))
- {
- if (dflags & CDESC_TYPE)
- puts ("file");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is hashed (%s)\n"), command, full_path);
- else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
- printf ("%s\n", full_path);
-
- free (full_path);
- return (1);
- }
- }
-
- /* Now search through $PATH. */
- while (1)
- {
- if (all == 0)
- full_path = find_user_command (command);
- else
- full_path =
- user_command_matches (command, FS_EXEC_ONLY, found_file);
- /* XXX - should that be FS_EXEC_PREFERRED? */
-
- if (full_path == 0)
- break;
-
- /* If we found the command as itself by looking through $PATH, it
- probably doesn't exist. Check whether or not the command is an
- executable file. If it's not, don't report a match. This is
- the default posix mode behavior */
- if (STREQ (full_path, command) || posixly_correct)
- {
- f = file_status (full_path);
- if ((f & FS_EXECABLE) == 0)
- {
- free (full_path);
- full_path = (char *)NULL;
- if (all == 0)
- break;
- }
- else if (ABSPATH (full_path))
- ; /* placeholder; don't need to do anything yet */
- else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
- {
- f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
- x = sh_makepath ((char *)NULL, full_path, f);
- free (full_path);
- full_path = x;
- }
- }
- /* If we require a full path and don't have one, make one */
- else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
- full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
-
- found_file++;
- found = 1;
-
- if (dflags & CDESC_TYPE)
- puts ("file");
- else if (dflags & CDESC_SHORTDESC)
- printf (_("%s is %s\n"), command, full_path);
- else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
- printf ("%s\n", full_path);
-
- free (full_path);
- full_path = (char *)NULL;
-
- if (all == 0)
- break;
- }
-
- return (found);
-}
+++ /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
-*** ../bash-4.3-patched/lib/readline/display.c 2014-04-08 18:19:36.000000000 -0400
---- lib/readline/display.c 2014-04-20 18:32:52.000000000 -0400
-***************
-*** 1036,1040 ****
- _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
---- 1036,1040 ----
- _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
-***************
-*** 1638,1642 ****
- 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)
- {
---- 1638,1642 ----
- 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)
- {
-***************
-*** 1826,1831 ****
- _rl_last_c_pos += bytes_to_insert;
-
- if (_rl_horizontal_scroll_mode && ((oe-old) > (ne-new)))
-! goto clear_rest_of_line;
- }
- }
---- 1826,1836 ----
- _rl_last_c_pos += bytes_to_insert;
-
-+ /* XXX - we only want to do this if we are at the end of the line
-+ so we move there with _rl_move_cursor_relative */
- if (_rl_horizontal_scroll_mode && ((oe-old) > (ne-new)))
-! {
-! _rl_move_cursor_relative (ne-new, new);
-! goto clear_rest_of_line;
-! }
- }
- }
-***************
-*** 2695,2698 ****
---- 2700,2709 ----
- }
-
-+ void
-+ _rl_ttyflush ()
-+ {
-+ 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. */
+++ /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
-/* execute_cmd.c -- Execute a COMMAND structure. */
-
-/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <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. */
-volatile 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;
-
-/* Are we currently ignoring the -e option for the duration of a builtin's
- execution? */
-int builtin_ignoring_errexit = 0;
-
-/* 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; /* bash-4.2 */
-
-volatile int from_return_trap = 0;
-
-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)
- if (currently_executing_command->type == cm_arith)
- return currently_executing_command->value.Arith->line;
-#endif
-#if defined (ARITH_FOR_COMMAND)
- 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 asynchronously.
- 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;
- char *tcmd;
- 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;
- tcmd = make_command_string (command);
- paren_pid = make_child (savestring (tcmd), 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. */
- /* This handles { command; } & */
- s = user_subshell == 0 && command->type == cm_group && pipe_in == NO_PIPE && pipe_out == NO_PIPE && asynchronous;
- /* run exit trap for : | { ...; } and { ...; } | : */
- /* run exit trap for : | ( ...; ) and ( ...; ) | : */
- s += user_subshell == 0 && command->type == cm_group && (pipe_in != NO_PIPE || pipe_out != NO_PIPE) && asynchronous == 0;
-
- 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 ();
-
- /* Posix 2013 2.9.3.1: "the exit status of an asynchronous list
- shall be zero." */
- last_command_exit_value = 0;
- 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 };
-
-#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)
-static int
-decpoint ()
-{
- struct lconv *lv;
-
- lv = localeconv ();
- return (lv && lv->decimal_point && lv->decimal_point[0]) ? lv->decimal_point[0] : '.';
-}
-#else
-# define decpoint() '.'
-#endif
-
-/* 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++] = decpoint ();
- 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 (EXIT_TRAP);
- }
-
- /* 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_nosigs (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_nosigs (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 = (last_command_exit_value == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : last_command_exit_value;
- 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;
- int lock;
- }
-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, 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 = cp->c_lock = 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_lock = 2;
-
- cp->c_pid = pid;
- cp->c_name = savestring (name);
-#if MULTIPLE_COPROCS
- cpl_add (cp);
-#endif
- cp->c_lock = 0;
- return (cp);
-}
-
-static void
-coproc_free (cp)
- struct coproc *cp;
-{
- free (cp);
-}
-
-void
-coproc_dispose (cp)
- struct coproc *cp;
-{
- sigset_t set, oset;
-
- if (cp == 0)
- return;
-
- BLOCK_SIGNAL (SIGCHLD, set, oset);
- cp->c_lock = 3;
- coproc_unsetvars (cp);
- FREE (cp->c_name);
- coproc_close (cp);
-#if MULTIPLE_COPROCS
- coproc_free (cp);
-#else
- coproc_init (cp);
- cp->c_lock = 0;
-#endif
- UNBLOCK_SIGNAL (oset);
-}
-
-/* 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)
- {
- cp->c_lock = 4;
- cp->c_status = status;
- cp->c_flags |= COPROC_DEAD;
- cp->c_flags &= ~COPROC_RUNNING;
- /* Don't dispose the coproc or unset the COPROC_XXX variables because
- this is executed in a signal handler context. Wait until coproc_reap
- takes care of it. */
- cp->c_lock = 0;
- }
-}
-
-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, invert;
- pid_t coproc_pid;
- Coproc *cp;
- char *tcmd;
- sigset_t set, oset;
-
- /* 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
-
- invert = (command->flags & CMD_INVERT_RETURN) != 0;
- 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 */
-
- BLOCK_SIGNAL (SIGCHLD, set, oset);
-
- coproc_pid = make_child (savestring (tcmd), 1);
-
- if (coproc_pid == 0)
- {
- close (rpipe[0]);
- close (wpipe[1]);
-
- UNBLOCK_SIGNAL (oset);
- 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]);
-
- /* XXX - possibly run Coproc->name through word expansion? */
- 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);
-
- UNBLOCK_SIGNAL (oset);
-
-#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 (invert ? EXECUTION_FAILURE : 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;
-
- line_number = for_command->line; /* for expansion error messages */
- 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);
-if (wlist && wlist->next)
- itrace("%s expands_word_unsplit gives multiple words", case_command->word->word);
- 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 (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->next)
- itrace("%s expands_word_leave_quoted gives multiple words", list->word->word);
-
- 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;
-#if 0
- char *t1, *t2;
-#endif
-
- 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
-
-#if 0
- t1 = strescape(arg1);
- t2 = strescape(arg2);
- itrace("execute_cond_node: sh_regmatch on `%s' and `%s'", t1, t2);
- free(t1);
- free(t2);
-#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)
- if (pipe_out == NO_PIPE)
- 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, array, integer;
-
- if (words == 0)
- return;
-
- b = 0;
- assoc = global = array = integer = 0;
-
- /* Skip over assignment statements preceding a command name */
- wcmd = words;
- for (wcmd = words; wcmd; wcmd = wcmd->next)
- if ((wcmd->word->flags & W_ASSIGNMENT) == 0)
- break;
-
- for (w = wcmd; 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 (array)
- w->word->flags |= W_ASSIGNARRAY;
-#endif
- if (global)
- w->word->flags |= W_ASSNGLOBAL;
- if (integer)
- w->word->flags |= W_ASSIGNINT;
- }
-#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, '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;
- else if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'a'))
- array = 1;
- if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g'))
- global = 1;
- if ((wcmd->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'i'))
- integer = 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;
-
- CHECK_SIGTERM;
- }
- 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)
- /* Close /dev/fd file descriptors in the parent after forking the
- last child in a (possibly one-element) pipeline. Defer this
- until any running shell function completes. */
- if (pipe_out == NO_PIPE && variable_context == 0) /* XXX */
- unlink_fifo_list (); /* XXX */
-#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 (posixly_correct && builtin_is_special && interactive_shell == 0 && tempenv_assign_error)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (ERREXIT);
- }
- tempenv_assign_error = 0; /* don't care about this any more */
-
- 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 possibililty. 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)
- {
- switch (result)
- {
- case EX_REDIRFAIL:
- case EX_BADASSIGN:
- case EX_EXPFAIL:
- /* These errors cause non-interactive posix mode shells to exit */
- if (posixly_correct && builtin_is_special && interactive_shell == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (ERREXIT);
- }
- }
- 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);
- unwind_protect_int (builtin_ignoring_errexit);
- 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;
- builtin_ignoring_errexit = 1;
- 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.
- `mapfile' is a special case because it uses evalstring (same as
- eval or source) to run its callbacks. */
- isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin || builtin == mapfile_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 = errexit_flag;
- builtin_ignoring_errexit = 0;
- 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;
-
- from_return_trap = 0;
-
- return_catch_flag++;
- return_val = setjmp_nosigs (return_catch);
-
- if (return_val)
- {
- result = return_catch_value;
- /* Run the RETURN trap in the function's context. */
- save_current = currently_executing_command;
- if (from_return_trap == 0)
- 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_nosigs (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_nosigs (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
- {
- /* Make sure we get the original signal dispositions now so we don't
- confuse the trap builtin later if the subshell tries to use it to
- reset SIGINT/SIGQUIT. Don't call set_signal_ignored; that sets
- the value of original_signals to SIG_IGN. Posix interpretation 751. */
- get_original_signal (SIGINT);
- set_signal_handler (SIGINT, SIG_IGN);
-
- get_original_signal (SIGQUIT);
- set_signal_handler (SIGQUIT, SIG_IGN);
- }
-}
-
-/* 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;
-
- reset_terminating_signals (); /* XXX */
- /* Cancel traps, in trap.c. */
- restore_original_signals ();
-
- CHECK_SIGTERM;
-
- /* 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 */
- }
-
-#if defined (JOB_CONTROL)
- /* May need to reinitialize more of the job control state here. */
- kill_current_pipeline ();
-#endif
-
- wl = make_word_list (make_word (NOTFOUND_HOOK), words);
- exit (execute_shell_function (hookf, wl));
- }
-
- CHECK_SIGTERM;
-
- /* 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 (interactive_shell ? DISCARD : 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
-/* glob.c -- file-name wildcard pattern matching for Bash.
-
- Copyright (C) 1985-2009 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne-Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* To whomever it may concern: I have never seen the code which most
- Unix programs use to perform this function. I wrote this from scratch
- based on specifications for the pattern matching. --RMS. */
-
-#include <config.h>
-
-#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
- #pragma alloca
-#endif /* _AIX && RISC6000 && !__GNUC__ */
-
-#include "bashtypes.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashansi.h"
-#include "posixdir.h"
-#include "posixstat.h"
-#include "shmbutil.h"
-#include "xmalloc.h"
-
-#include "filecntl.h"
-#if !defined (F_OK)
-# define F_OK 0
-#endif
-
-#include "stdc.h"
-#include "memalloc.h"
-
-#include <signal.h>
-
-#include "shell.h"
-
-#include "glob.h"
-#include "strmatch.h"
-
-#if !defined (HAVE_BCOPY) && !defined (bcopy)
-# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
-#endif /* !HAVE_BCOPY && !bcopy */
-
-#if !defined (NULL)
-# if defined (__STDC__)
-# define NULL ((void *) 0)
-# else
-# define NULL 0x0
-# endif /* __STDC__ */
-#endif /* !NULL */
-
-#if !defined (FREE)
-# define FREE(x) if (x) free (x)
-#endif
-
-/* Don't try to alloca() more than this much memory for `struct globval'
- in glob_vector() */
-#ifndef ALLOCA_MAX
-# define ALLOCA_MAX 100000
-#endif
-
-struct globval
- {
- struct globval *next;
- char *name;
- };
-
-extern void throw_to_top_level __P((void));
-extern int sh_eaccess __P((char *, int));
-extern char *sh_makepath __P((const char *, const char *, int));
-extern int signal_is_pending __P((int));
-extern void run_pending_traps __P((void));
-
-extern int extended_glob;
-
-/* Global variable which controls whether or not * matches .*.
- Non-zero means don't match .*. */
-int noglob_dot_filenames = 1;
-
-/* Global variable which controls whether or not filename globbing
- is done without regard to case. */
-int glob_ignore_case = 0;
-
-/* Global variable to return to signify an error in globbing. */
-char *glob_error_return;
-
-static struct globval finddirs_error_return;
-
-/* Some forward declarations. */
-static int skipname __P((char *, char *, int));
-#if HANDLE_MULTIBYTE
-static int mbskipname __P((char *, char *, int));
-#endif
-#if HANDLE_MULTIBYTE
-static void udequote_pathname __P((char *));
-static void wdequote_pathname __P((char *));
-#else
-# define dequote_pathname udequote_pathname
-#endif
-static void dequote_pathname __P((char *));
-static int glob_testdir __P((char *, int));
-static char **glob_dir_to_array __P((char *, char **, int));
-
-/* Make sure these names continue to agree with what's in smatch.c */
-extern char *glob_patscan __P((char *, char *, int));
-extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
-
-/* Compile `glob_loop.c' for single-byte characters. */
-#define CHAR unsigned char
-#define INT int
-#define L(CS) CS
-#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p
-#include "glob_loop.c"
-
-/* Compile `glob_loop.c' again for multibyte characters. */
-#if HANDLE_MULTIBYTE
-
-#define CHAR wchar_t
-#define INT wint_t
-#define L(CS) L##CS
-#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p
-#include "glob_loop.c"
-
-#endif /* HANDLE_MULTIBYTE */
-
-/* And now a function that calls either the single-byte or multibyte version
- of internal_glob_pattern_p. */
-int
-glob_pattern_p (pattern)
- const char *pattern;
-{
-#if HANDLE_MULTIBYTE
- size_t n;
- wchar_t *wpattern;
- int r;
-
- if (MB_CUR_MAX == 1)
- return (internal_glob_pattern_p ((unsigned char *)pattern));
-
- /* Convert strings to wide chars, and call the multibyte version. */
- n = xdupmbstowcs (&wpattern, NULL, pattern);
- if (n == (size_t)-1)
- /* Oops. Invalid multibyte sequence. Try it as single-byte sequence. */
- return (internal_glob_pattern_p ((unsigned char *)pattern));
-
- r = internal_glob_wpattern_p (wpattern);
- free (wpattern);
-
- return r;
-#else
- return (internal_glob_pattern_p (pattern));
-#endif
-}
-
-#if EXTENDED_GLOB
-/* Return 1 if all subpatterns in the extended globbing pattern PAT indicate
- that the name should be skipped. XXX - doesn't handle pattern negation,
- not sure if it should */
-static int
-extglob_skipname (pat, dname, flags)
- char *pat, *dname;
- int flags;
-{
- char *pp, *pe, *t, *se;
- int n, r, negate;
-
- negate = *pat == '!';
- pp = pat + 2;
- se = pp + strlen (pp) - 1; /* end of string */
- pe = glob_patscan (pp, se, 0); /* end of extglob pattern (( */
- /* we should check for invalid extglob pattern here */
- /* if pe != se we have more of the pattern at the end of the extglob
- pattern. Check the easy case first ( */
- if (pe == se && *pe == ')' && (t = strchr (pp, '|')) == 0)
- {
- *pe = '\0';
-#if defined (HANDLE_MULTIBYTE)
- r = mbskipname (pp, dname, flags);
-#else
- r = skipname (pp, dname, flags); /*(*/
-#endif
- *pe = ')';
- return r;
- }
-
- /* check every subpattern */
- while (t = glob_patscan (pp, pe, '|'))
- {
- n = t[-1];
- t[-1] = '\0';
-#if defined (HANDLE_MULTIBYTE)
- r = mbskipname (pp, dname, flags);
-#else
- r = skipname (pp, dname, flags);
-#endif
- t[-1] = n;
- if (r == 0) /* if any pattern says not skip, we don't skip */
- return r;
- pp = t;
- } /*(*/
-
- /* glob_patscan might find end of pattern */
- if (pp == se)
- return r;
-
- /* but if it doesn't then we didn't match a leading dot */
- return 0;
-}
-#endif
-
-/* Return 1 if DNAME should be skipped according to PAT. Mostly concerned
- with matching leading `.'. */
-static int
-skipname (pat, dname, flags)
- char *pat;
- char *dname;
- int flags;
-{
-#if EXTENDED_GLOB
- if (extglob_pattern_p (pat)) /* XXX */
- return (extglob_skipname (pat, dname, flags));
-#endif
-
- /* If a leading dot need not be explicitly matched, and the pattern
- doesn't start with a `.', don't match `.' or `..' */
- if (noglob_dot_filenames == 0 && pat[0] != '.' &&
- (pat[0] != '\\' || pat[1] != '.') &&
- (dname[0] == '.' &&
- (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))))
- return 1;
-
- /* If a dot must be explicitly matched, check to see if they do. */
- else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' &&
- (pat[0] != '\\' || pat[1] != '.'))
- return 1;
-
- return 0;
-}
-
-#if HANDLE_MULTIBYTE
-
-static int
-wchkname (pat_wc, dn_wc)
- wchar_t *pat_wc, *dn_wc;
-{
- /* If a leading dot need not be explicitly matched, and the
- pattern doesn't start with a `.', don't match `.' or `..' */
- if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
- (pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
- (dn_wc[0] == L'.' &&
- (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
- return 1;
-
- /* If a leading dot must be explicitly matched, check to see if the
- pattern and dirname both have one. */
- else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
- pat_wc[0] != L'.' &&
- (pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
- return 1;
-
- return 0;
-}
-
-static int
-wextglob_skipname (pat, dname, flags)
- wchar_t *pat, *dname;
- int flags;
-{
-#if EXTENDED_GLOB
- wchar_t *pp, *pe, *t, n, *se;
- int r, negate;
-
- negate = *pat == L'!';
- pp = pat + 2;
- se = pp + wcslen (pp) - 1; /*(*/
- pe = glob_patscan_wc (pp, se, 0);
-
- if (pe == se && *pe == ')' && (t = wcschr (pp, L'|')) == 0)
- {
- *pe = L'\0';
- r = wchkname (pp, dname); /*(*/
- *pe = L')';
- return r;
- }
-
- /* check every subpattern */
- while (t = glob_patscan_wc (pp, pe, '|'))
- {
- n = t[-1];
- t[-1] = L'\0';
- r = wchkname (pp, dname);
- t[-1] = n;
- if (r == 0)
- return 0;
- pp = t;
- }
-
- if (pp == pe) /* glob_patscan_wc might find end of pattern */
- return r;
-
- /* but if it doesn't then we didn't match a leading dot */
- return 0;
-#else
- return (wchkname (pat, dname));
-#endif
-}
-
-/* Return 1 if DNAME should be skipped according to PAT. Handles multibyte
- characters in PAT and DNAME. Mostly concerned with matching leading `.'. */
-static int
-mbskipname (pat, dname, flags)
- char *pat, *dname;
- int flags;
-{
- int ret, ext;
- wchar_t *pat_wc, *dn_wc;
- size_t pat_n, dn_n;
-
- if (mbsmbchar (dname) == 0 && mbsmbchar (pat) == 0)
- return (skipname (pat, dname, flags));
-
- ext = 0;
-#if EXTENDED_GLOB
- ext = extglob_pattern_p (pat);
-#endif
-
- pat_wc = dn_wc = (wchar_t *)NULL;
-
- pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
- if (pat_n != (size_t)-1)
- dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
-
- ret = 0;
- if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
- ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wchkname (pat_wc, dn_wc);
- else
- ret = skipname (pat, dname, flags);
-
- FREE (pat_wc);
- FREE (dn_wc);
-
- return ret;
-}
-#endif /* HANDLE_MULTIBYTE */
-
-/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
-static void
-udequote_pathname (pathname)
- char *pathname;
-{
- register int i, j;
-
- for (i = j = 0; pathname && pathname[i]; )
- {
- if (pathname[i] == '\\')
- i++;
-
- pathname[j++] = pathname[i++];
-
- if (pathname[i - 1] == 0)
- break;
- }
- if (pathname)
- pathname[j] = '\0';
-}
-
-#if HANDLE_MULTIBYTE
-/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
-static void
-wdequote_pathname (pathname)
- char *pathname;
-{
- mbstate_t ps;
- size_t len, n;
- wchar_t *wpathname;
- int i, j;
- wchar_t *orig_wpathname;
-
- len = strlen (pathname);
- /* Convert the strings into wide characters. */
- n = xdupmbstowcs (&wpathname, NULL, pathname);
- if (n == (size_t) -1)
- {
- /* Something wrong. Fall back to single-byte */
- udequote_pathname (pathname);
- return;
- }
- orig_wpathname = wpathname;
-
- for (i = j = 0; wpathname && wpathname[i]; )
- {
- if (wpathname[i] == L'\\')
- i++;
-
- wpathname[j++] = wpathname[i++];
-
- if (wpathname[i - 1] == L'\0')
- break;
- }
- if (wpathname)
- wpathname[j] = L'\0';
-
- /* Convert the wide character string into unibyte character set. */
- memset (&ps, '\0', sizeof(mbstate_t));
- n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps);
- pathname[len] = '\0';
-
- /* Can't just free wpathname here; wcsrtombs changes it in many cases. */
- free (orig_wpathname);
-}
-
-static void
-dequote_pathname (pathname)
- char *pathname;
-{
- if (MB_CUR_MAX > 1)
- wdequote_pathname (pathname);
- else
- udequote_pathname (pathname);
-}
-#endif /* HANDLE_MULTIBYTE */
-
-/* Test whether NAME exists. */
-
-#if defined (HAVE_LSTAT)
-# define GLOB_TESTNAME(name) (lstat (name, &finfo))
-#else /* !HAVE_LSTAT */
-# if !defined (AFS)
-# define GLOB_TESTNAME(name) (sh_eaccess (name, F_OK))
-# else /* AFS */
-# define GLOB_TESTNAME(name) (access (name, F_OK))
-# endif /* AFS */
-#endif /* !HAVE_LSTAT */
-
-/* Return 0 if DIR is a directory, -1 otherwise. */
-static int
-glob_testdir (dir, flags)
- char *dir;
- int flags;
-{
- struct stat finfo;
- int r;
-
-/*itrace("glob_testdir: testing %s" flags = %d, dir, flags);*/
-#if defined (HAVE_LSTAT)
- r = (flags & GX_ALLDIRS) ? lstat (dir, &finfo) : stat (dir, &finfo);
-#else
- r = stat (dir, &finfo);
-#endif
- if (r < 0)
- return (-1);
-
- if (S_ISDIR (finfo.st_mode) == 0)
- return (-1);
-
- return (0);
-}
-
-/* Recursively scan SDIR for directories matching PAT (PAT is always `**').
- FLAGS is simply passed down to the recursive call to glob_vector. Returns
- a list of matching directory names. EP, if non-null, is set to the last
- element of the returned list. NP, if non-null, is set to the number of
- directories in the returned list. These two variables exist for the
- convenience of the caller (always glob_vector). */
-static struct globval *
-finddirs (pat, sdir, flags, ep, np)
- char *pat;
- char *sdir;
- int flags;
- struct globval **ep;
- int *np;
-{
- char **r, *n;
- int ndirs;
- struct globval *ret, *e, *g;
-
-/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/
- e = ret = 0;
- r = glob_vector (pat, sdir, flags);
- if (r == 0 || r[0] == 0)
- {
- if (np)
- *np = 0;
- if (ep)
- *ep = 0;
- if (r && r != &glob_error_return)
- free (r);
- return (struct globval *)0;
- }
- for (ndirs = 0; r[ndirs] != 0; ndirs++)
- {
- g = (struct globval *) malloc (sizeof (struct globval));
- if (g == 0)
- {
- while (ret) /* free list built so far */
- {
- g = ret->next;
- free (ret);
- ret = g;
- }
-
- free (r);
- if (np)
- *np = 0;
- if (ep)
- *ep = 0;
- return (&finddirs_error_return);
- }
- if (e == 0)
- e = g;
-
- g->next = ret;
- ret = g;
-
- g->name = r[ndirs];
- }
-
- free (r);
- if (ep)
- *ep = e;
- if (np)
- *np = ndirs;
-
- return ret;
-}
-
-/* Return a vector of names of files in directory DIR
- whose names match glob pattern PAT.
- The names are not in any particular order.
- Wildcards at the beginning of PAT do not match an initial period.
-
- The vector is terminated by an element that is a null pointer.
-
- To free the space allocated, first free the vector's elements,
- then free the vector.
-
- Return 0 if cannot get enough memory to hold the pointer
- and the names.
-
- Return -1 if cannot access directory DIR.
- Look in errno for more information. */
-
-char **
-glob_vector (pat, dir, flags)
- char *pat;
- char *dir;
- int flags;
-{
- DIR *d;
- register struct dirent *dp;
- struct globval *lastlink, *e, *dirlist;
- register struct globval *nextlink;
- register char *nextname, *npat, *subdir;
- unsigned int count;
- int lose, skip, ndirs, isdir, sdlen, add_current, patlen;
- register char **name_vector;
- register unsigned int i;
- int mflags; /* Flags passed to strmatch (). */
- int pflags; /* flags passed to sh_makepath () */
- int nalloca;
- struct globval *firstmalloc, *tmplink;
- char *convfn;
-
- lastlink = 0;
- count = lose = skip = add_current = 0;
-
- firstmalloc = 0;
- nalloca = 0;
-
-/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
- /* If PAT is empty, skip the loop, but return one (empty) filename. */
- if (pat == 0 || *pat == '\0')
- {
- if (glob_testdir (dir, 0) < 0)
- return ((char **) &glob_error_return);
-
- nextlink = (struct globval *)alloca (sizeof (struct globval));
- if (nextlink == NULL)
- return ((char **) NULL);
-
- nextlink->next = (struct globval *)0;
- nextname = (char *) malloc (1);
- if (nextname == 0)
- lose = 1;
- else
- {
- lastlink = nextlink;
- nextlink->name = nextname;
- nextname[0] = '\0';
- count = 1;
- }
-
- skip = 1;
- }
-
- patlen = (pat && *pat) ? strlen (pat) : 0;
-
- /* If the filename pattern (PAT) does not contain any globbing characters,
- we can dispense with reading the directory, and just see if there is
- a filename `DIR/PAT'. If there is, and we can access it, just make the
- vector to return and bail immediately. */
- if (skip == 0 && glob_pattern_p (pat) == 0)
- {
- int dirlen;
- struct stat finfo;
-
- if (glob_testdir (dir, 0) < 0)
- return ((char **) &glob_error_return);
-
- dirlen = strlen (dir);
- nextname = (char *)malloc (dirlen + patlen + 2);
- npat = (char *)malloc (patlen + 1);
- if (nextname == 0 || npat == 0)
- {
- FREE (nextname);
- FREE (npat);
- lose = 1;
- }
- else
- {
- strcpy (npat, pat);
- dequote_pathname (npat);
-
- strcpy (nextname, dir);
- nextname[dirlen++] = '/';
- strcpy (nextname + dirlen, npat);
-
- if (GLOB_TESTNAME (nextname) >= 0)
- {
- free (nextname);
- nextlink = (struct globval *)alloca (sizeof (struct globval));
- if (nextlink)
- {
- nextlink->next = (struct globval *)0;
- lastlink = nextlink;
- nextlink->name = npat;
- count = 1;
- }
- else
- {
- free (npat);
- lose = 1;
- }
- }
- else
- {
- free (nextname);
- free (npat);
- }
- }
-
- skip = 1;
- }
-
- if (skip == 0)
- {
- /* Open the directory, punting immediately if we cannot. If opendir
- is not robust (i.e., it opens non-directories successfully), test
- that DIR is a directory and punt if it's not. */
-#if defined (OPENDIR_NOT_ROBUST)
- if (glob_testdir (dir, 0) < 0)
- return ((char **) &glob_error_return);
-#endif
-
- d = opendir (dir);
- if (d == NULL)
- return ((char **) &glob_error_return);
-
- /* Compute the flags that will be passed to strmatch(). We don't
- need to do this every time through the loop. */
- mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
-
-#ifdef FNM_CASEFOLD
- if (glob_ignore_case)
- mflags |= FNM_CASEFOLD;
-#endif
-
- if (extended_glob)
- mflags |= FNM_EXTMATCH;
-
- add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR));
-
- /* Scan the directory, finding all names that match.
- For each name that matches, allocate a struct globval
- on the stack and store the name in it.
- Chain those structs together; lastlink is the front of the chain. */
- while (1)
- {
- /* Make globbing interruptible in the shell. */
- if (interrupt_state || terminating_signal)
- {
- lose = 1;
- break;
- }
- else if (signal_is_pending (SIGINT)) /* XXX - make SIGINT traps responsive */
- {
- lose = 1;
- break;
- }
-
- dp = readdir (d);
- if (dp == NULL)
- break;
-
- /* If this directory entry is not to be used, try again. */
- if (REAL_DIR_ENTRY (dp) == 0)
- continue;
-
-#if 0
- if (dp->d_name == 0 || *dp->d_name == 0)
- continue;
-#endif
-
-#if HANDLE_MULTIBYTE
- if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags))
- continue;
- else
-#endif
- if (skipname (pat, dp->d_name, flags))
- continue;
-
- /* If we're only interested in directories, don't bother with files */
- if (flags & (GX_MATCHDIRS|GX_ALLDIRS))
- {
- pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0;
- if (flags & GX_NULLDIR)
- pflags |= MP_IGNDOT;
- subdir = sh_makepath (dir, dp->d_name, pflags);
- isdir = glob_testdir (subdir, flags);
- if (isdir < 0 && (flags & GX_MATCHDIRS))
- {
- free (subdir);
- continue;
- }
- }
-
- if (flags & GX_ALLDIRS)
- {
- if (isdir == 0)
- {
- dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs);
- if (dirlist == &finddirs_error_return)
- {
- free (subdir);
- lose = 1;
- break;
- }
- if (ndirs) /* add recursive directories to list */
- {
- if (firstmalloc == 0)
- firstmalloc = e;
- e->next = lastlink;
- lastlink = dirlist;
- count += ndirs;
- }
- }
-
- nextlink = (struct globval *) malloc (sizeof (struct globval));
- if (firstmalloc == 0)
- firstmalloc = nextlink;
- sdlen = strlen (subdir);
- nextname = (char *) malloc (sdlen + 1);
- if (nextlink == 0 || nextname == 0)
- {
- FREE (nextlink);
- FREE (nextname);
- free (subdir);
- lose = 1;
- break;
- }
- nextlink->next = lastlink;
- lastlink = nextlink;
- nextlink->name = nextname;
- bcopy (subdir, nextname, sdlen + 1);
- free (subdir);
- ++count;
- continue;
- }
- else if (flags & GX_MATCHDIRS)
- free (subdir);
-
- convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp));
- if (strmatch (pat, convfn, mflags) != FNM_NOMATCH)
- {
- if (nalloca < ALLOCA_MAX)
- {
- nextlink = (struct globval *) alloca (sizeof (struct globval));
- nalloca += sizeof (struct globval);
- }
- else
- {
- nextlink = (struct globval *) malloc (sizeof (struct globval));
- if (firstmalloc == 0)
- firstmalloc = nextlink;
- }
-
- nextname = (char *) malloc (D_NAMLEN (dp) + 1);
- if (nextlink == 0 || nextname == 0)
- {
- FREE (nextlink);
- FREE (nextname);
- lose = 1;
- break;
- }
- nextlink->next = lastlink;
- lastlink = nextlink;
- nextlink->name = nextname;
- bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
- ++count;
- }
- }
-
- (void) closedir (d);
- }
-
- /* compat: if GX_ADDCURDIR, add the passed directory also. Add an empty
- directory name as a placeholder if GX_NULLDIR (in which case the passed
- directory name is "."). */
- if (add_current)
- {
- sdlen = strlen (dir);
- nextname = (char *)malloc (sdlen + 1);
- nextlink = (struct globval *) malloc (sizeof (struct globval));
- if (nextlink == 0 || nextname == 0)
- {
- FREE (nextlink);
- FREE (nextname);
- lose = 1;
- }
- else
- {
- nextlink->name = nextname;
- nextlink->next = lastlink;
- lastlink = nextlink;
- if (flags & GX_NULLDIR)
- nextname[0] = '\0';
- else
- bcopy (dir, nextname, sdlen + 1);
- ++count;
- }
- }
-
- if (lose == 0)
- {
- name_vector = (char **) malloc ((count + 1) * sizeof (char *));
- lose |= name_vector == NULL;
- }
-
- /* Have we run out of memory? */
- if (lose)
- {
- tmplink = 0;
-
- /* Here free the strings we have got. */
- while (lastlink)
- {
- /* Since we build the list in reverse order, the first N entries
- will be allocated with malloc, if firstmalloc is set, from
- lastlink to firstmalloc. */
- if (firstmalloc)
- {
- if (lastlink == firstmalloc)
- firstmalloc = 0;
- tmplink = lastlink;
- }
- else
- tmplink = 0;
- free (lastlink->name);
- lastlink = lastlink->next;
- FREE (tmplink);
- }
-
- /* Don't call QUIT; here; let higher layers deal with it. */
-
- return ((char **)NULL);
- }
-
- /* Copy the name pointers from the linked list into the vector. */
- for (tmplink = lastlink, i = 0; i < count; ++i)
- {
- name_vector[i] = tmplink->name;
- tmplink = tmplink->next;
- }
-
- name_vector[count] = NULL;
-
- /* If we allocated some of the struct globvals, free them now. */
- if (firstmalloc)
- {
- tmplink = 0;
- while (lastlink)
- {
- tmplink = lastlink;
- if (lastlink == firstmalloc)
- lastlink = firstmalloc = 0;
- else
- lastlink = lastlink->next;
- free (tmplink);
- }
- }
-
- return (name_vector);
-}
-
-/* Return a new array which is the concatenation of each string in ARRAY
- to DIR. This function expects you to pass in an allocated ARRAY, and
- it takes care of free()ing that array. Thus, you might think of this
- function as side-effecting ARRAY. This should handle GX_MARKDIRS. */
-static char **
-glob_dir_to_array (dir, array, flags)
- char *dir, **array;
- int flags;
-{
- register unsigned int i, l;
- int add_slash;
- char **result, *new;
- struct stat sb;
-
- l = strlen (dir);
- if (l == 0)
- {
- if (flags & GX_MARKDIRS)
- for (i = 0; array[i]; i++)
- {
- if ((stat (array[i], &sb) == 0) && S_ISDIR (sb.st_mode))
- {
- l = strlen (array[i]);
- new = (char *)realloc (array[i], l + 2);
- if (new == 0)
- return NULL;
- new[l] = '/';
- new[l+1] = '\0';
- array[i] = new;
- }
- }
- return (array);
- }
-
- add_slash = dir[l - 1] != '/';
-
- i = 0;
- while (array[i] != NULL)
- ++i;
-
- result = (char **) malloc ((i + 1) * sizeof (char *));
- if (result == NULL)
- return (NULL);
-
- for (i = 0; array[i] != NULL; i++)
- {
- /* 3 == 1 for NUL, 1 for slash at end of DIR, 1 for GX_MARKDIRS */
- result[i] = (char *) malloc (l + strlen (array[i]) + 3);
-
- if (result[i] == NULL)
- {
- int ind;
- for (ind = 0; ind < i; ind++)
- free (result[ind]);
- free (result);
- return (NULL);
- }
-
- strcpy (result[i], dir);
- if (add_slash)
- result[i][l] = '/';
- strcpy (result[i] + l + add_slash, array[i]);
- if (flags & GX_MARKDIRS)
- {
- if ((stat (result[i], &sb) == 0) && S_ISDIR (sb.st_mode))
- {
- size_t rlen;
- rlen = strlen (result[i]);
- result[i][rlen] = '/';
- result[i][rlen+1] = '\0';
- }
- }
- }
- result[i] = NULL;
-
- /* Free the input array. */
- for (i = 0; array[i] != NULL; i++)
- free (array[i]);
- free ((char *) array);
-
- return (result);
-}
-
-/* Do globbing on PATHNAME. Return an array of pathnames that match,
- marking the end of the array with a null-pointer as an element.
- If no pathnames match, then the array is empty (first element is null).
- If there isn't enough memory, then return NULL.
- If a file system error occurs, return -1; `errno' has the error code. */
-char **
-glob_filename (pathname, flags)
- char *pathname;
- int flags;
-{
- char **result;
- unsigned int result_size;
- char *directory_name, *filename, *dname;
- unsigned int directory_len;
- int free_dirname; /* flag */
- int dflags;
-
- result = (char **) malloc (sizeof (char *));
- result_size = 1;
- if (result == NULL)
- return (NULL);
-
- result[0] = NULL;
-
- directory_name = NULL;
-
- /* Find the filename. */
- filename = strrchr (pathname, '/');
- if (filename == NULL)
- {
- filename = pathname;
- directory_name = "";
- directory_len = 0;
- free_dirname = 0;
- }
- else
- {
- directory_len = (filename - pathname) + 1;
- directory_name = (char *) malloc (directory_len + 1);
-
- if (directory_name == 0) /* allocation failed? */
- {
- free (result);
- return (NULL);
- }
-
- bcopy (pathname, directory_name, directory_len);
- directory_name[directory_len] = '\0';
- ++filename;
- free_dirname = 1;
- }
-
- /* If directory_name contains globbing characters, then we
- have to expand the previous levels. Just recurse. */
- if (directory_len > 0 && glob_pattern_p (directory_name))
- {
- char **directories, *d, *p;
- register unsigned int i;
- int all_starstar, last_starstar;
-
- all_starstar = last_starstar = 0;
- d = directory_name;
- dflags = flags & ~GX_MARKDIRS;
- /* Collapse a sequence of ** patterns separated by one or more slashes
- to a single ** terminated by a slash or NUL */
- if ((flags & GX_GLOBSTAR) && d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0'))
- {
- p = d;
- while (d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0'))
- {
- p = d;
- if (d[2])
- {
- d += 3;
- while (*d == '/')
- d++;
- if (*d == 0)
- break;
- }
- }
- if (*d == 0)
- all_starstar = 1;
- d = p;
- dflags |= GX_ALLDIRS|GX_ADDCURDIR;
- directory_len = strlen (d);
- }
-
- /* If there is a non [star][star]/ component in directory_name, we
- still need to collapse trailing sequences of [star][star]/ into
- a single one and note that the directory name ends with [star][star],
- so we can compensate if filename is [star][star] */
- if ((flags & GX_GLOBSTAR) && all_starstar == 0)
- {
- int dl, prev;
- prev = dl = directory_len;
- while (dl >= 4 && d[dl - 1] == '/' &&
- d[dl - 2] == '*' &&
- d[dl - 3] == '*' &&
- d[dl - 4] == '/')
- prev = dl, dl -= 3;
- if (dl != directory_len)
- last_starstar = 1;
- directory_len = prev;
- }
-
- /* If the directory name ends in [star][star]/ but the filename is
- [star][star], just remove the final [star][star] from the directory
- so we don't have to scan everything twice. */
- if (last_starstar && directory_len > 4 &&
- filename[0] == '*' && filename[1] == '*' && filename[2] == 0)
- {
- directory_len -= 3;
- }
-
- if (d[directory_len - 1] == '/')
- d[directory_len - 1] = '\0';
-
- directories = glob_filename (d, dflags);
-
- if (free_dirname)
- {
- free (directory_name);
- directory_name = NULL;
- }
-
- if (directories == NULL)
- goto memory_error;
- else if (directories == (char **)&glob_error_return)
- {
- free ((char *) result);
- return ((char **) &glob_error_return);
- }
- else if (*directories == NULL)
- {
- free ((char *) directories);
- free ((char *) result);
- return ((char **) &glob_error_return);
- }
-
- /* If we have something like [star][star]/[star][star], it's no use to
- glob **, then do it again, and throw half the results away. */
- if (all_starstar && filename[0] == '*' && filename[1] == '*' && filename[2] == 0)
- {
- free ((char *) directories);
- free (directory_name);
- directory_name = NULL;
- directory_len = 0;
- goto only_filename;
- }
-
- /* We have successfully globbed the preceding directory name.
- For each name in DIRECTORIES, call glob_vector on it and
- FILENAME. Concatenate the results together. */
- for (i = 0; directories[i] != NULL; ++i)
- {
- char **temp_results;
- int shouldbreak;
-
- shouldbreak = 0;
- /* XXX -- we've recursively scanned any directories resulting from
- a `**', so turn off the flag. We turn it on again below if
- filename is `**' */
- /* Scan directory even on a NULL filename. That way, `*h/'
- returns only directories ending in `h', instead of all
- files ending in `h' with a `/' appended. */
- dname = directories[i];
- dflags = flags & ~(GX_MARKDIRS|GX_ALLDIRS|GX_ADDCURDIR);
- if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
- dflags |= GX_ALLDIRS|GX_ADDCURDIR;
- if (dname[0] == '\0' && filename[0])
- {
- dflags |= GX_NULLDIR;
- dname = "."; /* treat null directory name and non-null filename as current directory */
- }
- temp_results = glob_vector (filename, dname, dflags);
-
- /* Handle error cases. */
- if (temp_results == NULL)
- goto memory_error;
- else if (temp_results == (char **)&glob_error_return)
- /* This filename is probably not a directory. Ignore it. */
- ;
- else
- {
- char **array;
- register unsigned int l;
-
- /* If we're expanding **, we don't need to glue the directory
- name to the results; we've already done it in glob_vector */
- if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && (filename[2] == '\0' || filename[2] == '/'))
- {
- /* When do we remove null elements from temp_results? And
- how to avoid duplicate elements in the final result? */
- /* If (dflags & GX_NULLDIR) glob_filename potentially left a
- NULL placeholder in the temp results just in case
- glob_vector/glob_dir_to_array did something with it, but
- if it didn't, and we're not supposed to be passing them
- through for some reason ((flags & GX_NULLDIR) == 0) we
- need to remove all the NULL elements from the beginning
- of TEMP_RESULTS. */
- /* If we have a null directory name and ** as the filename,
- we have just searched for everything from the current
- directory on down. Break now (shouldbreak = 1) to avoid
- duplicate entries in the final result. */
-#define NULL_PLACEHOLDER(x) ((x) && *(x) && **(x) == 0)
- if ((dflags & GX_NULLDIR) && (flags & GX_NULLDIR) == 0 &&
- NULL_PLACEHOLDER (temp_results))
-#undef NULL_PLACEHOLDER
- {
- register int i, n;
- for (n = 0; temp_results[n] && *temp_results[n] == 0; n++)
- ;
- i = n;
- do
- temp_results[i - n] = temp_results[i];
- while (temp_results[i++] != 0);
- array = temp_results;
- shouldbreak = 1;
- }
- else
- array = temp_results;
- }
- else
- array = glob_dir_to_array (directories[i], temp_results, flags);
- l = 0;
- while (array[l] != NULL)
- ++l;
-
- result =
- (char **)realloc (result, (result_size + l) * sizeof (char *));
-
- if (result == NULL)
- goto memory_error;
-
- for (l = 0; array[l] != NULL; ++l)
- result[result_size++ - 1] = array[l];
-
- result[result_size - 1] = NULL;
-
- /* Note that the elements of ARRAY are not freed. */
- if (array != temp_results)
- free ((char *) array);
- else if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
- free (temp_results); /* expanding ** case above */
-
- if (shouldbreak)
- break;
- }
- }
- /* Free the directories. */
- for (i = 0; directories[i]; i++)
- free (directories[i]);
-
- free ((char *) directories);
-
- return (result);
- }
-
-only_filename:
- /* If there is only a directory name, return it. */
- if (*filename == '\0')
- {
- result = (char **) realloc ((char *) result, 2 * sizeof (char *));
- if (result == NULL)
- {
- if (free_dirname)
- free (directory_name);
- return (NULL);
- }
- /* Handle GX_MARKDIRS here. */
- result[0] = (char *) malloc (directory_len + 1);
- if (result[0] == NULL)
- goto memory_error;
- bcopy (directory_name, result[0], directory_len + 1);
- if (free_dirname)
- free (directory_name);
- result[1] = NULL;
- return (result);
- }
- else
- {
- char **temp_results;
-
- /* There are no unquoted globbing characters in DIRECTORY_NAME.
- Dequote it before we try to open the directory since there may
- be quoted globbing characters which should be treated verbatim. */
- if (directory_len > 0)
- dequote_pathname (directory_name);
-
- /* We allocated a small array called RESULT, which we won't be using.
- Free that memory now. */
- free (result);
-
- /* Just return what glob_vector () returns appended to the
- directory name. */
- /* If flags & GX_ALLDIRS, we're called recursively */
- dflags = flags & ~GX_MARKDIRS;
- if (directory_len == 0)
- dflags |= GX_NULLDIR;
- if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
- {
- dflags |= GX_ALLDIRS|GX_ADDCURDIR;
-#if 0
- /* If we want all directories (dflags & GX_ALLDIRS) and we're not
- being called recursively as something like `echo [star][star]/[star].o'
- ((flags & GX_ALLDIRS) == 0), we want to prevent glob_vector from
- adding a null directory name to the front of the temp_results
- array. We turn off ADDCURDIR if not called recursively and
- dlen == 0 */
-#endif
- if (directory_len == 0 && (flags & GX_ALLDIRS) == 0)
- dflags &= ~GX_ADDCURDIR;
- }
- temp_results = glob_vector (filename,
- (directory_len == 0 ? "." : directory_name),
- dflags);
-
- if (temp_results == NULL || temp_results == (char **)&glob_error_return)
- {
- if (free_dirname)
- free (directory_name);
- QUIT; /* XXX - shell */
- run_pending_traps ();
- return (temp_results);
- }
-
- result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags);
-
- if (free_dirname)
- free (directory_name);
- return (result);
- }
-
- /* We get to memory_error if the program has run out of memory, or
- if this is the shell, and we have been interrupted. */
- memory_error:
- if (result != NULL)
- {
- register unsigned int i;
- for (i = 0; result[i] != NULL; ++i)
- free (result[i]);
- free ((char *) result);
- }
-
- if (free_dirname && directory_name)
- free (directory_name);
-
- QUIT;
- run_pending_traps ();
-
- return (NULL);
-}
-
-#if defined (TEST)
-
-main (argc, argv)
- int argc;
- char **argv;
-{
- unsigned int i;
-
- for (i = 1; i < argc; ++i)
- {
- char **value = glob_filename (argv[i], 0);
- if (value == NULL)
- puts ("Out of memory.");
- else if (value == &glob_error_return)
- perror (argv[i]);
- else
- for (i = 0; value[i] != NULL; i++)
- puts (value[i]);
- }
-
- exit (0);
-}
-#endif /* TEST. */
+++ /dev/null
-/* loadmsgcat.c - Load needed message catalogs. */
-
-/* Copyright (C) 1995-1999, 2000-2003, 2005-2009 Free Software Foundation, Inc.
-
- This file is part of GNU Bash.
-
- 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/>.
-*/
-
-/* Tell glibc's <string.h> to provide a prototype for mempcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef __GNUC__
-# undef alloca
-# define alloca __builtin_alloca
-# define HAVE_ALLOCA 1
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-#endif
-
-#ifdef _LIBC
-# include <langinfo.h>
-# include <locale.h>
-#endif
-
-#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
- || (defined _LIBC && defined _POSIX_MAPPED_FILES)
-# include <sys/mman.h>
-# undef HAVE_MMAP
-# define HAVE_MMAP 1
-#else
-# undef HAVE_MMAP
-#endif
-
-#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
-# include <stdint.h>
-#endif
-#if defined HAVE_INTTYPES_H || defined _LIBC
-# include <inttypes.h>
-#endif
-
-#include "gmo.h"
-#include "gettextP.h"
-#include "hash-string.h"
-#include "plural-exp.h"
-
-#ifdef _LIBC
-# include "../locale/localeinfo.h"
-#endif
-
-/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
- Note that our fallback values need not be literal strings, because we don't
- use them with preprocessor string concatenation. */
-#if !defined PRId8 || PRI_MACROS_BROKEN
-# undef PRId8
-# define PRId8 "d"
-#endif
-#if !defined PRIi8 || PRI_MACROS_BROKEN
-# undef PRIi8
-# define PRIi8 "i"
-#endif
-#if !defined PRIo8 || PRI_MACROS_BROKEN
-# undef PRIo8
-# define PRIo8 "o"
-#endif
-#if !defined PRIu8 || PRI_MACROS_BROKEN
-# undef PRIu8
-# define PRIu8 "u"
-#endif
-#if !defined PRIx8 || PRI_MACROS_BROKEN
-# undef PRIx8
-# define PRIx8 "x"
-#endif
-#if !defined PRIX8 || PRI_MACROS_BROKEN
-# undef PRIX8
-# define PRIX8 "X"
-#endif
-#if !defined PRId16 || PRI_MACROS_BROKEN
-# undef PRId16
-# define PRId16 "d"
-#endif
-#if !defined PRIi16 || PRI_MACROS_BROKEN
-# undef PRIi16
-# define PRIi16 "i"
-#endif
-#if !defined PRIo16 || PRI_MACROS_BROKEN
-# undef PRIo16
-# define PRIo16 "o"
-#endif
-#if !defined PRIu16 || PRI_MACROS_BROKEN
-# undef PRIu16
-# define PRIu16 "u"
-#endif
-#if !defined PRIx16 || PRI_MACROS_BROKEN
-# undef PRIx16
-# define PRIx16 "x"
-#endif
-#if !defined PRIX16 || PRI_MACROS_BROKEN
-# undef PRIX16
-# define PRIX16 "X"
-#endif
-#if !defined PRId32 || PRI_MACROS_BROKEN
-# undef PRId32
-# define PRId32 "d"
-#endif
-#if !defined PRIi32 || PRI_MACROS_BROKEN
-# undef PRIi32
-# define PRIi32 "i"
-#endif
-#if !defined PRIo32 || PRI_MACROS_BROKEN
-# undef PRIo32
-# define PRIo32 "o"
-#endif
-#if !defined PRIu32 || PRI_MACROS_BROKEN
-# undef PRIu32
-# define PRIu32 "u"
-#endif
-#if !defined PRIx32 || PRI_MACROS_BROKEN
-# undef PRIx32
-# define PRIx32 "x"
-#endif
-#if !defined PRIX32 || PRI_MACROS_BROKEN
-# undef PRIX32
-# define PRIX32 "X"
-#endif
-#if !defined PRId64 || PRI_MACROS_BROKEN
-# undef PRId64
-# define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
-#endif
-#if !defined PRIi64 || PRI_MACROS_BROKEN
-# undef PRIi64
-# define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
-#endif
-#if !defined PRIo64 || PRI_MACROS_BROKEN
-# undef PRIo64
-# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
-#endif
-#if !defined PRIu64 || PRI_MACROS_BROKEN
-# undef PRIu64
-# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
-#endif
-#if !defined PRIx64 || PRI_MACROS_BROKEN
-# undef PRIx64
-# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
-#endif
-#if !defined PRIX64 || PRI_MACROS_BROKEN
-# undef PRIX64
-# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
-#endif
-#if !defined PRIdLEAST8 || PRI_MACROS_BROKEN
-# undef PRIdLEAST8
-# define PRIdLEAST8 "d"
-#endif
-#if !defined PRIiLEAST8 || PRI_MACROS_BROKEN
-# undef PRIiLEAST8
-# define PRIiLEAST8 "i"
-#endif
-#if !defined PRIoLEAST8 || PRI_MACROS_BROKEN
-# undef PRIoLEAST8
-# define PRIoLEAST8 "o"
-#endif
-#if !defined PRIuLEAST8 || PRI_MACROS_BROKEN
-# undef PRIuLEAST8
-# define PRIuLEAST8 "u"
-#endif
-#if !defined PRIxLEAST8 || PRI_MACROS_BROKEN
-# undef PRIxLEAST8
-# define PRIxLEAST8 "x"
-#endif
-#if !defined PRIXLEAST8 || PRI_MACROS_BROKEN
-# undef PRIXLEAST8
-# define PRIXLEAST8 "X"
-#endif
-#if !defined PRIdLEAST16 || PRI_MACROS_BROKEN
-# undef PRIdLEAST16
-# define PRIdLEAST16 "d"
-#endif
-#if !defined PRIiLEAST16 || PRI_MACROS_BROKEN
-# undef PRIiLEAST16
-# define PRIiLEAST16 "i"
-#endif
-#if !defined PRIoLEAST16 || PRI_MACROS_BROKEN
-# undef PRIoLEAST16
-# define PRIoLEAST16 "o"
-#endif
-#if !defined PRIuLEAST16 || PRI_MACROS_BROKEN
-# undef PRIuLEAST16
-# define PRIuLEAST16 "u"
-#endif
-#if !defined PRIxLEAST16 || PRI_MACROS_BROKEN
-# undef PRIxLEAST16
-# define PRIxLEAST16 "x"
-#endif
-#if !defined PRIXLEAST16 || PRI_MACROS_BROKEN
-# undef PRIXLEAST16
-# define PRIXLEAST16 "X"
-#endif
-#if !defined PRIdLEAST32 || PRI_MACROS_BROKEN
-# undef PRIdLEAST32
-# define PRIdLEAST32 "d"
-#endif
-#if !defined PRIiLEAST32 || PRI_MACROS_BROKEN
-# undef PRIiLEAST32
-# define PRIiLEAST32 "i"
-#endif
-#if !defined PRIoLEAST32 || PRI_MACROS_BROKEN
-# undef PRIoLEAST32
-# define PRIoLEAST32 "o"
-#endif
-#if !defined PRIuLEAST32 || PRI_MACROS_BROKEN
-# undef PRIuLEAST32
-# define PRIuLEAST32 "u"
-#endif
-#if !defined PRIxLEAST32 || PRI_MACROS_BROKEN
-# undef PRIxLEAST32
-# define PRIxLEAST32 "x"
-#endif
-#if !defined PRIXLEAST32 || PRI_MACROS_BROKEN
-# undef PRIXLEAST32
-# define PRIXLEAST32 "X"
-#endif
-#if !defined PRIdLEAST64 || PRI_MACROS_BROKEN
-# undef PRIdLEAST64
-# define PRIdLEAST64 PRId64
-#endif
-#if !defined PRIiLEAST64 || PRI_MACROS_BROKEN
-# undef PRIiLEAST64
-# define PRIiLEAST64 PRIi64
-#endif
-#if !defined PRIoLEAST64 || PRI_MACROS_BROKEN
-# undef PRIoLEAST64
-# define PRIoLEAST64 PRIo64
-#endif
-#if !defined PRIuLEAST64 || PRI_MACROS_BROKEN
-# undef PRIuLEAST64
-# define PRIuLEAST64 PRIu64
-#endif
-#if !defined PRIxLEAST64 || PRI_MACROS_BROKEN
-# undef PRIxLEAST64
-# define PRIxLEAST64 PRIx64
-#endif
-#if !defined PRIXLEAST64 || PRI_MACROS_BROKEN
-# undef PRIXLEAST64
-# define PRIXLEAST64 PRIX64
-#endif
-#if !defined PRIdFAST8 || PRI_MACROS_BROKEN
-# undef PRIdFAST8
-# define PRIdFAST8 "d"
-#endif
-#if !defined PRIiFAST8 || PRI_MACROS_BROKEN
-# undef PRIiFAST8
-# define PRIiFAST8 "i"
-#endif
-#if !defined PRIoFAST8 || PRI_MACROS_BROKEN
-# undef PRIoFAST8
-# define PRIoFAST8 "o"
-#endif
-#if !defined PRIuFAST8 || PRI_MACROS_BROKEN
-# undef PRIuFAST8
-# define PRIuFAST8 "u"
-#endif
-#if !defined PRIxFAST8 || PRI_MACROS_BROKEN
-# undef PRIxFAST8
-# define PRIxFAST8 "x"
-#endif
-#if !defined PRIXFAST8 || PRI_MACROS_BROKEN
-# undef PRIXFAST8
-# define PRIXFAST8 "X"
-#endif
-#if !defined PRIdFAST16 || PRI_MACROS_BROKEN
-# undef PRIdFAST16
-# define PRIdFAST16 "d"
-#endif
-#if !defined PRIiFAST16 || PRI_MACROS_BROKEN
-# undef PRIiFAST16
-# define PRIiFAST16 "i"
-#endif
-#if !defined PRIoFAST16 || PRI_MACROS_BROKEN
-# undef PRIoFAST16
-# define PRIoFAST16 "o"
-#endif
-#if !defined PRIuFAST16 || PRI_MACROS_BROKEN
-# undef PRIuFAST16
-# define PRIuFAST16 "u"
-#endif
-#if !defined PRIxFAST16 || PRI_MACROS_BROKEN
-# undef PRIxFAST16
-# define PRIxFAST16 "x"
-#endif
-#if !defined PRIXFAST16 || PRI_MACROS_BROKEN
-# undef PRIXFAST16
-# define PRIXFAST16 "X"
-#endif
-#if !defined PRIdFAST32 || PRI_MACROS_BROKEN
-# undef PRIdFAST32
-# define PRIdFAST32 "d"
-#endif
-#if !defined PRIiFAST32 || PRI_MACROS_BROKEN
-# undef PRIiFAST32
-# define PRIiFAST32 "i"
-#endif
-#if !defined PRIoFAST32 || PRI_MACROS_BROKEN
-# undef PRIoFAST32
-# define PRIoFAST32 "o"
-#endif
-#if !defined PRIuFAST32 || PRI_MACROS_BROKEN
-# undef PRIuFAST32
-# define PRIuFAST32 "u"
-#endif
-#if !defined PRIxFAST32 || PRI_MACROS_BROKEN
-# undef PRIxFAST32
-# define PRIxFAST32 "x"
-#endif
-#if !defined PRIXFAST32 || PRI_MACROS_BROKEN
-# undef PRIXFAST32
-# define PRIXFAST32 "X"
-#endif
-#if !defined PRIdFAST64 || PRI_MACROS_BROKEN
-# undef PRIdFAST64
-# define PRIdFAST64 PRId64
-#endif
-#if !defined PRIiFAST64 || PRI_MACROS_BROKEN
-# undef PRIiFAST64
-# define PRIiFAST64 PRIi64
-#endif
-#if !defined PRIoFAST64 || PRI_MACROS_BROKEN
-# undef PRIoFAST64
-# define PRIoFAST64 PRIo64
-#endif
-#if !defined PRIuFAST64 || PRI_MACROS_BROKEN
-# undef PRIuFAST64
-# define PRIuFAST64 PRIu64
-#endif
-#if !defined PRIxFAST64 || PRI_MACROS_BROKEN
-# undef PRIxFAST64
-# define PRIxFAST64 PRIx64
-#endif
-#if !defined PRIXFAST64 || PRI_MACROS_BROKEN
-# undef PRIXFAST64
-# define PRIXFAST64 PRIX64
-#endif
-#if !defined PRIdMAX || PRI_MACROS_BROKEN
-# undef PRIdMAX
-# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
-#endif
-#if !defined PRIiMAX || PRI_MACROS_BROKEN
-# undef PRIiMAX
-# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
-#endif
-#if !defined PRIoMAX || PRI_MACROS_BROKEN
-# undef PRIoMAX
-# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
-#endif
-#if !defined PRIuMAX || PRI_MACROS_BROKEN
-# undef PRIuMAX
-# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
-#endif
-#if !defined PRIxMAX || PRI_MACROS_BROKEN
-# undef PRIxMAX
-# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
-#endif
-#if !defined PRIXMAX || PRI_MACROS_BROKEN
-# undef PRIXMAX
-# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
-#endif
-#if !defined PRIdPTR || PRI_MACROS_BROKEN
-# undef PRIdPTR
-# define PRIdPTR \
- (sizeof (void *) == sizeof (long) ? "ld" : \
- sizeof (void *) == sizeof (int) ? "d" : \
- "lld")
-#endif
-#if !defined PRIiPTR || PRI_MACROS_BROKEN
-# undef PRIiPTR
-# define PRIiPTR \
- (sizeof (void *) == sizeof (long) ? "li" : \
- sizeof (void *) == sizeof (int) ? "i" : \
- "lli")
-#endif
-#if !defined PRIoPTR || PRI_MACROS_BROKEN
-# undef PRIoPTR
-# define PRIoPTR \
- (sizeof (void *) == sizeof (long) ? "lo" : \
- sizeof (void *) == sizeof (int) ? "o" : \
- "llo")
-#endif
-#if !defined PRIuPTR || PRI_MACROS_BROKEN
-# undef PRIuPTR
-# define PRIuPTR \
- (sizeof (void *) == sizeof (long) ? "lu" : \
- sizeof (void *) == sizeof (int) ? "u" : \
- "llu")
-#endif
-#if !defined PRIxPTR || PRI_MACROS_BROKEN
-# undef PRIxPTR
-# define PRIxPTR \
- (sizeof (void *) == sizeof (long) ? "lx" : \
- sizeof (void *) == sizeof (int) ? "x" : \
- "llx")
-#endif
-#if !defined PRIXPTR || PRI_MACROS_BROKEN
-# undef PRIXPTR
-# define PRIXPTR \
- (sizeof (void *) == sizeof (long) ? "lX" : \
- sizeof (void *) == sizeof (int) ? "X" : \
- "llX")
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ISO C functions. This is required by the standard
- because some ISO C functions will require linking with this object
- file and the name space must not be polluted. */
-# define open __open
-# define close __close
-# define read __read
-# define mmap __mmap
-# define munmap __munmap
-#endif
-
-/* For those losing systems which don't have `alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
-#endif
-
-/* For systems that distinguish between text and binary I/O.
- O_BINARY is usually declared in <fcntl.h>. */
-#if !defined O_BINARY && defined _O_BINARY
- /* For MSC-compatible compilers. */
-# define O_BINARY _O_BINARY
-# define O_TEXT _O_TEXT
-#endif
-#ifdef __BEOS__
- /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
-# undef O_BINARY
-# undef O_TEXT
-#endif
-/* On reasonable systems, binary I/O is the default. */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-
-/* Prototypes for local functions. Needed to ensure compiler checking of
- function argument counts despite of K&R C function definition syntax. */
-static const char *get_sysdep_segment_value PARAMS ((const char *name));
-
-
-/* We need a sign, whether a new catalog was loaded, which can be associated
- with all translations. This is important if the translations are
- cached by one of GCC's features. */
-int _nl_msg_cat_cntr;
-
-
-/* Expand a system dependent string segment. Return NULL if unsupported. */
-static const char *
-get_sysdep_segment_value (name)
- const char *name;
-{
- /* Test for an ISO C 99 section 7.8.1 format string directive.
- Syntax:
- P R I { d | i | o | u | x | X }
- { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR } */
- /* We don't use a table of 14 times 6 'const char *' strings here, because
- data relocations cost startup time. */
- if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I')
- {
- if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u'
- || name[3] == 'x' || name[3] == 'X')
- {
- if (name[4] == '8' && name[5] == '\0')
- {
- if (name[3] == 'd')
- return PRId8;
- if (name[3] == 'i')
- return PRIi8;
- if (name[3] == 'o')
- return PRIo8;
- if (name[3] == 'u')
- return PRIu8;
- if (name[3] == 'x')
- return PRIx8;
- if (name[3] == 'X')
- return PRIX8;
- abort ();
- }
- if (name[4] == '1' && name[5] == '6' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId16;
- if (name[3] == 'i')
- return PRIi16;
- if (name[3] == 'o')
- return PRIo16;
- if (name[3] == 'u')
- return PRIu16;
- if (name[3] == 'x')
- return PRIx16;
- if (name[3] == 'X')
- return PRIX16;
- abort ();
- }
- if (name[4] == '3' && name[5] == '2' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId32;
- if (name[3] == 'i')
- return PRIi32;
- if (name[3] == 'o')
- return PRIo32;
- if (name[3] == 'u')
- return PRIu32;
- if (name[3] == 'x')
- return PRIx32;
- if (name[3] == 'X')
- return PRIX32;
- abort ();
- }
- if (name[4] == '6' && name[5] == '4' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId64;
- if (name[3] == 'i')
- return PRIi64;
- if (name[3] == 'o')
- return PRIo64;
- if (name[3] == 'u')
- return PRIu64;
- if (name[3] == 'x')
- return PRIx64;
- if (name[3] == 'X')
- return PRIX64;
- abort ();
- }
- if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A'
- && name[7] == 'S' && name[8] == 'T')
- {
- if (name[9] == '8' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST8;
- if (name[3] == 'i')
- return PRIiLEAST8;
- if (name[3] == 'o')
- return PRIoLEAST8;
- if (name[3] == 'u')
- return PRIuLEAST8;
- if (name[3] == 'x')
- return PRIxLEAST8;
- if (name[3] == 'X')
- return PRIXLEAST8;
- abort ();
- }
- if (name[9] == '1' && name[10] == '6' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST16;
- if (name[3] == 'i')
- return PRIiLEAST16;
- if (name[3] == 'o')
- return PRIoLEAST16;
- if (name[3] == 'u')
- return PRIuLEAST16;
- if (name[3] == 'x')
- return PRIxLEAST16;
- if (name[3] == 'X')
- return PRIXLEAST16;
- abort ();
- }
- if (name[9] == '3' && name[10] == '2' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST32;
- if (name[3] == 'i')
- return PRIiLEAST32;
- if (name[3] == 'o')
- return PRIoLEAST32;
- if (name[3] == 'u')
- return PRIuLEAST32;
- if (name[3] == 'x')
- return PRIxLEAST32;
- if (name[3] == 'X')
- return PRIXLEAST32;
- abort ();
- }
- if (name[9] == '6' && name[10] == '4' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST64;
- if (name[3] == 'i')
- return PRIiLEAST64;
- if (name[3] == 'o')
- return PRIoLEAST64;
- if (name[3] == 'u')
- return PRIuLEAST64;
- if (name[3] == 'x')
- return PRIxLEAST64;
- if (name[3] == 'X')
- return PRIXLEAST64;
- abort ();
- }
- }
- if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S'
- && name[7] == 'T')
- {
- if (name[8] == '8' && name[9] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST8;
- if (name[3] == 'i')
- return PRIiFAST8;
- if (name[3] == 'o')
- return PRIoFAST8;
- if (name[3] == 'u')
- return PRIuFAST8;
- if (name[3] == 'x')
- return PRIxFAST8;
- if (name[3] == 'X')
- return PRIXFAST8;
- abort ();
- }
- if (name[8] == '1' && name[9] == '6' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST16;
- if (name[3] == 'i')
- return PRIiFAST16;
- if (name[3] == 'o')
- return PRIoFAST16;
- if (name[3] == 'u')
- return PRIuFAST16;
- if (name[3] == 'x')
- return PRIxFAST16;
- if (name[3] == 'X')
- return PRIXFAST16;
- abort ();
- }
- if (name[8] == '3' && name[9] == '2' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST32;
- if (name[3] == 'i')
- return PRIiFAST32;
- if (name[3] == 'o')
- return PRIoFAST32;
- if (name[3] == 'u')
- return PRIuFAST32;
- if (name[3] == 'x')
- return PRIxFAST32;
- if (name[3] == 'X')
- return PRIXFAST32;
- abort ();
- }
- if (name[8] == '6' && name[9] == '4' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST64;
- if (name[3] == 'i')
- return PRIiFAST64;
- if (name[3] == 'o')
- return PRIoFAST64;
- if (name[3] == 'u')
- return PRIuFAST64;
- if (name[3] == 'x')
- return PRIxFAST64;
- if (name[3] == 'X')
- return PRIXFAST64;
- abort ();
- }
- }
- if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X'
- && name[7] == '\0')
- {
- if (name[3] == 'd')
- return PRIdMAX;
- if (name[3] == 'i')
- return PRIiMAX;
- if (name[3] == 'o')
- return PRIoMAX;
- if (name[3] == 'u')
- return PRIuMAX;
- if (name[3] == 'x')
- return PRIxMAX;
- if (name[3] == 'X')
- return PRIXMAX;
- abort ();
- }
- if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R'
- && name[7] == '\0')
- {
- if (name[3] == 'd')
- return PRIdPTR;
- if (name[3] == 'i')
- return PRIiPTR;
- if (name[3] == 'o')
- return PRIoPTR;
- if (name[3] == 'u')
- return PRIuPTR;
- if (name[3] == 'x')
- return PRIxPTR;
- if (name[3] == 'X')
- return PRIXPTR;
- abort ();
- }
- }
- }
- /* Other system dependent strings are not valid. */
- return NULL;
-}
-
-/* Initialize the codeset dependent parts of an opened message catalog.
- Return the header entry. */
-const char *
-internal_function
-_nl_init_domain_conv (domain_file, domain, domainbinding)
- struct loaded_l10nfile *domain_file;
- struct loaded_domain *domain;
- struct binding *domainbinding;
-{
- /* Find out about the character set the file is encoded with.
- This can be found (in textual form) in the entry "". If this
- entry does not exist or if this does not contain the `charset='
- information, we will assume the charset matches the one the
- current locale and we don't have to perform any conversion. */
- char *nullentry;
- size_t nullentrylen;
-
- /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
- domain->codeset_cntr =
- (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
-#ifdef _LIBC
- domain->conv = (__gconv_t) -1;
-#else
-# if HAVE_ICONV
- domain->conv = (iconv_t) -1;
-# endif
-#endif
- domain->conv_tab = NULL;
-
- /* Get the header entry. */
- nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
-
- if (nullentry != NULL)
- {
-#if defined _LIBC || HAVE_ICONV
- const char *charsetstr;
-
- charsetstr = strstr (nullentry, "charset=");
- if (charsetstr != NULL)
- {
- size_t len;
- char *charset;
- const char *outcharset;
-
- charsetstr += strlen ("charset=");
- len = strcspn (charsetstr, " \t\n");
-
- charset = (char *) alloca (len + 1);
-# if defined _LIBC || HAVE_MEMPCPY
- *((char *) mempcpy (charset, charsetstr, len)) = '\0';
-# else
- memcpy (charset, charsetstr, len);
- charset[len] = '\0';
-# endif
-
- /* The output charset should normally be determined by the
- locale. But sometimes the locale is not used or not correctly
- set up, so we provide a possibility for the user to override
- this. Moreover, the value specified through
- bind_textdomain_codeset overrides both. */
- if (domainbinding != NULL && domainbinding->codeset != NULL)
- outcharset = domainbinding->codeset;
- else
- {
- outcharset = getenv ("OUTPUT_CHARSET");
- if (outcharset == NULL || outcharset[0] == '\0')
- {
-# ifdef _LIBC
- outcharset = _NL_CURRENT (LC_CTYPE, CODESET);
-# else
-# if HAVE_ICONV
- extern const char *locale_charset PARAMS ((void));
- outcharset = locale_charset ();
-# endif
-# endif
- }
- }
-
-# ifdef _LIBC
- /* We always want to use transliteration. */
- outcharset = norm_add_slashes (outcharset, "TRANSLIT");
- charset = norm_add_slashes (charset, NULL);
- if (__gconv_open (outcharset, charset, &domain->conv,
- GCONV_AVOID_NOCONV)
- != __GCONV_OK)
- domain->conv = (__gconv_t) -1;
-# else
-# if HAVE_ICONV
- /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
- we want to use transliteration. */
-# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
- || _LIBICONV_VERSION >= 0x0105
- if (strchr (outcharset, '/') == NULL)
- {
- char *tmp;
-
- len = strlen (outcharset);
- tmp = (char *) alloca (len + 10 + 1);
- memcpy (tmp, outcharset, len);
- memcpy (tmp + len, "//TRANSLIT", 10 + 1);
- outcharset = tmp;
-
- domain->conv = iconv_open (outcharset, charset);
-
- freea (outcharset);
- }
- else
-# endif
- domain->conv = iconv_open (outcharset, charset);
-# endif
-# endif
-
- freea (charset);
- }
-#endif /* _LIBC || HAVE_ICONV */
- }
-
- return nullentry;
-}
-
-/* Frees the codeset dependent parts of an opened message catalog. */
-void
-internal_function
-_nl_free_domain_conv (domain)
- struct loaded_domain *domain;
-{
- if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
- free (domain->conv_tab);
-
-#ifdef _LIBC
- if (domain->conv != (__gconv_t) -1)
- __gconv_close (domain->conv);
-#else
-# if HAVE_ICONV
- if (domain->conv != (iconv_t) -1)
- iconv_close (domain->conv);
-# endif
-#endif
-}
-
-/* Load the message catalogs specified by FILENAME. If it is no valid
- message catalog do nothing. */
-void
-internal_function
-_nl_load_domain (domain_file, domainbinding)
- struct loaded_l10nfile *domain_file;
- struct binding *domainbinding;
-{
- int fd;
- size_t size;
-#ifdef _LIBC
- struct stat64 st;
-#else
- struct stat st;
-#endif
- struct mo_file_header *data = (struct mo_file_header *) -1;
- int use_mmap = 0;
- struct loaded_domain *domain;
- int revision;
- const char *nullentry;
-
- domain_file->decided = 1;
- domain_file->data = NULL;
-
- /* Note that it would be useless to store domainbinding in domain_file
- because domainbinding might be == NULL now but != NULL later (after
- a call to bind_textdomain_codeset). */
-
- /* If the record does not represent a valid locale the FILENAME
- might be NULL. This can happen when according to the given
- specification the locale file name is different for XPG and CEN
- syntax. */
- if (domain_file->filename == NULL)
- return;
-
- /* Try to open the addressed file. */
- fd = open (domain_file->filename, O_RDONLY | O_BINARY);
- if (fd == -1)
- return;
-
- /* We must know about the size of the file. */
- if (
-#ifdef _LIBC
- __builtin_expect (fstat64 (fd, &st) != 0, 0)
-#else
- __builtin_expect (fstat (fd, &st) != 0, 0)
-#endif
- || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
- || __builtin_expect (size < sizeof (struct mo_file_header), 0))
- {
- /* Something went wrong. */
- close (fd);
- return;
- }
-
-#ifdef HAVE_MMAP
- /* Now we are ready to load the file. If mmap() is available we try
- this first. If not available or it failed we try to load it. */
- data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
- MAP_PRIVATE, fd, 0);
-
- if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
- {
- /* mmap() call was successful. */
- close (fd);
- use_mmap = 1;
- }
-#endif
-
- /* If the data is not yet available (i.e. mmap'ed) we try to load
- it manually. */
- if (data == (struct mo_file_header *) -1)
- {
- size_t to_read;
- char *read_ptr;
-
- data = (struct mo_file_header *) malloc (size);
- if (data == NULL)
- return;
-
- to_read = size;
- read_ptr = (char *) data;
- do
- {
- long int nb = (long int) read (fd, read_ptr, to_read);
- if (nb <= 0)
- {
-#ifdef EINTR
- if (nb == -1 && errno == EINTR)
- continue;
-#endif
- close (fd);
- return;
- }
- read_ptr += nb;
- to_read -= nb;
- }
- while (to_read > 0);
-
- close (fd);
- }
-
- /* Using the magic number we can test whether it really is a message
- catalog file. */
- if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
- 0))
- {
- /* The magic number is wrong: not a message catalog file. */
-#ifdef HAVE_MMAP
- if (use_mmap)
- munmap ((caddr_t) data, size);
- else
-#endif
- free (data);
- return;
- }
-
- domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
- if (domain == NULL)
- {
-#ifdef HAVE_MMAP
- if (use_mmap)
- munmap ((caddr_t) data, size);
- else
-#endif
- free (data);
- return;
- }
- domain_file->data = domain;
-
- domain->data = (char *) data;
- domain->use_mmap = use_mmap;
- domain->mmap_size = size;
- domain->must_swap = data->magic != _MAGIC;
- domain->malloced = NULL;
-
- /* Fill in the information about the available tables. */
- revision = W (domain->must_swap, data->revision);
- /* We support only the major revision 0. */
- switch (revision >> 16)
- {
- case 0:
- domain->nstrings = W (domain->must_swap, data->nstrings);
- domain->orig_tab = (const struct string_desc *)
- ((char *) data + W (domain->must_swap, data->orig_tab_offset));
- domain->trans_tab = (const struct string_desc *)
- ((char *) data + W (domain->must_swap, data->trans_tab_offset));
- domain->hash_size = W (domain->must_swap, data->hash_tab_size);
- domain->hash_tab =
- (domain->hash_size > 2
- ? (const nls_uint32 *)
- ((char *) data + W (domain->must_swap, data->hash_tab_offset))
- : NULL);
- domain->must_swap_hash_tab = domain->must_swap;
-
- /* Now dispatch on the minor revision. */
- switch (revision & 0xffff)
- {
- case 0:
- domain->n_sysdep_strings = 0;
- domain->orig_sysdep_tab = NULL;
- domain->trans_sysdep_tab = NULL;
- break;
- case 1:
- default:
- {
- nls_uint32 n_sysdep_strings;
-
- if (domain->hash_tab == NULL)
- /* This is invalid. These minor revisions need a hash table. */
- goto invalid;
-
- n_sysdep_strings =
- W (domain->must_swap, data->n_sysdep_strings);
- if (n_sysdep_strings > 0)
- {
- nls_uint32 n_sysdep_segments;
- const struct sysdep_segment *sysdep_segments;
- const char **sysdep_segment_values;
- const nls_uint32 *orig_sysdep_tab;
- const nls_uint32 *trans_sysdep_tab;
- size_t memneed;
- char *mem;
- struct sysdep_string_desc *inmem_orig_sysdep_tab;
- struct sysdep_string_desc *inmem_trans_sysdep_tab;
- nls_uint32 *inmem_hash_tab;
- unsigned int i;
-
- /* Get the values of the system dependent segments. */
- n_sysdep_segments =
- W (domain->must_swap, data->n_sysdep_segments);
- sysdep_segments = (const struct sysdep_segment *)
- ((char *) data
- + W (domain->must_swap, data->sysdep_segments_offset));
- sysdep_segment_values =
- alloca (n_sysdep_segments * sizeof (const char *));
- for (i = 0; i < n_sysdep_segments; i++)
- {
- const char *name =
- (char *) data
- + W (domain->must_swap, sysdep_segments[i].offset);
- nls_uint32 namelen =
- W (domain->must_swap, sysdep_segments[i].length);
-
- if (!(namelen > 0 && name[namelen - 1] == '\0'))
- {
- freea (sysdep_segment_values);
- goto invalid;
- }
-
- sysdep_segment_values[i] = get_sysdep_segment_value (name);
- }
-
- orig_sysdep_tab = (const nls_uint32 *)
- ((char *) data
- + W (domain->must_swap, data->orig_sysdep_tab_offset));
- trans_sysdep_tab = (const nls_uint32 *)
- ((char *) data
- + W (domain->must_swap, data->trans_sysdep_tab_offset));
-
- /* Compute the amount of additional memory needed for the
- system dependent strings and the augmented hash table. */
- memneed = 2 * n_sysdep_strings
- * sizeof (struct sysdep_string_desc)
- + domain->hash_size * sizeof (nls_uint32);
- for (i = 0; i < 2 * n_sysdep_strings; i++)
- {
- const struct sysdep_string *sysdep_string =
- (const struct sysdep_string *)
- ((char *) data
- + W (domain->must_swap,
- i < n_sysdep_strings
- ? orig_sysdep_tab[i]
- : trans_sysdep_tab[i - n_sysdep_strings]));
- size_t need = 0;
- const struct segment_pair *p = sysdep_string->segments;
-
- if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
- for (p = sysdep_string->segments;; p++)
- {
- nls_uint32 sysdepref;
-
- need += W (domain->must_swap, p->segsize);
-
- sysdepref = W (domain->must_swap, p->sysdepref);
- if (sysdepref == SEGMENTS_END)
- break;
-
- if (sysdepref >= n_sysdep_segments)
- {
- /* Invalid. */
- freea (sysdep_segment_values);
- goto invalid;
- }
-
- need += strlen (sysdep_segment_values[sysdepref]);
- }
-
- memneed += need;
- }
-
- /* Allocate additional memory. */
- mem = (char *) malloc (memneed);
- if (mem == NULL)
- goto invalid;
-
- domain->malloced = mem;
- inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
- mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
- inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
- mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
- inmem_hash_tab = (nls_uint32 *) mem;
- mem += domain->hash_size * sizeof (nls_uint32);
-
- /* Compute the system dependent strings. */
- for (i = 0; i < 2 * n_sysdep_strings; i++)
- {
- const struct sysdep_string *sysdep_string =
- (const struct sysdep_string *)
- ((char *) data
- + W (domain->must_swap,
- i < n_sysdep_strings
- ? orig_sysdep_tab[i]
- : trans_sysdep_tab[i - n_sysdep_strings]));
- const char *static_segments =
- (char *) data
- + W (domain->must_swap, sysdep_string->offset);
- const struct segment_pair *p = sysdep_string->segments;
-
- /* Concatenate the segments, and fill
- inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and
- inmem_trans_sysdep_tab[i-n_sysdep_strings] (for
- i >= n_sysdep_strings). */
-
- if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END)
- {
- /* Only one static segment. */
- inmem_orig_sysdep_tab[i].length =
- W (domain->must_swap, p->segsize);
- inmem_orig_sysdep_tab[i].pointer = static_segments;
- }
- else
- {
- inmem_orig_sysdep_tab[i].pointer = mem;
-
- for (p = sysdep_string->segments;; p++)
- {
- nls_uint32 segsize =
- W (domain->must_swap, p->segsize);
- nls_uint32 sysdepref =
- W (domain->must_swap, p->sysdepref);
- size_t n;
-
- if (segsize > 0)
- {
- memcpy (mem, static_segments, segsize);
- mem += segsize;
- static_segments += segsize;
- }
-
- if (sysdepref == SEGMENTS_END)
- break;
-
- n = strlen (sysdep_segment_values[sysdepref]);
- memcpy (mem, sysdep_segment_values[sysdepref], n);
- mem += n;
- }
-
- inmem_orig_sysdep_tab[i].length =
- mem - inmem_orig_sysdep_tab[i].pointer;
- }
- }
-
- /* Compute the augmented hash table. */
- for (i = 0; i < domain->hash_size; i++)
- inmem_hash_tab[i] =
- W (domain->must_swap_hash_tab, domain->hash_tab[i]);
- for (i = 0; i < n_sysdep_strings; i++)
- {
- const char *msgid = inmem_orig_sysdep_tab[i].pointer;
- nls_uint32 hash_val = hash_string (msgid);
- nls_uint32 idx = hash_val % domain->hash_size;
- nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
-
- for (;;)
- {
- if (inmem_hash_tab[idx] == 0)
- {
- /* Hash table entry is empty. Use it. */
- inmem_hash_tab[idx] = 1 + domain->nstrings + i;
- break;
- }
-
- if (idx >= domain->hash_size - incr)
- idx -= domain->hash_size - incr;
- else
- idx += incr;
- }
- }
-
- freea (sysdep_segment_values);
-
- domain->n_sysdep_strings = n_sysdep_strings;
- domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
- domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
-
- domain->hash_tab = inmem_hash_tab;
- domain->must_swap_hash_tab = 0;
- }
- else
- {
- domain->n_sysdep_strings = 0;
- domain->orig_sysdep_tab = NULL;
- domain->trans_sysdep_tab = NULL;
- }
- }
- break;
- }
- break;
- default:
- /* This is an invalid revision. */
- invalid:
- /* This is an invalid .mo file. */
- if (domain->malloced)
- free (domain->malloced);
-#ifdef HAVE_MMAP
- if (use_mmap)
- munmap ((caddr_t) data, size);
- else
-#endif
- free (data);
- free (domain);
- domain_file->data = NULL;
- return;
- }
-
- /* Now initialize the character set converter from the character set
- the file is encoded with (found in the header entry) to the domain's
- specified character set or the locale's character set. */
- nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
-
- /* Also look for a plural specification. */
- EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
-}
-
-
-#ifdef _LIBC
-void
-internal_function
-_nl_unload_domain (domain)
- struct loaded_domain *domain;
-{
- if (domain->plural != &__gettext_germanic_plural)
- __gettext_free_exp (domain->plural);
-
- _nl_free_domain_conv (domain);
-
- if (domain->malloced)
- free (domain->malloced);
-
-# ifdef _POSIX_MAPPED_FILES
- if (domain->use_mmap)
- munmap ((caddr_t) domain->data, domain->mmap_size);
- else
-# endif /* _POSIX_MAPPED_FILES */
- free ((void *) domain->data);
-
- free (domain);
-}
-#endif
+++ /dev/null
-/* localealias.c - Handle aliases for locale names. */
-
-/* Copyright (C) 1995-1999, 2000-2001, 2003, 2005-2009 Free Software Foundation, Inc.
-
- This file is part of GNU Bash.
-
- 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/>.
-*/
-
-/* Tell glibc's <string.h> to provide a prototype for mempcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#if defined _LIBC || defined HAVE___FSETLOCKING
-# include <stdio_ext.h>
-#endif
-#include <sys/types.h>
-
-#ifdef __GNUC__
-# undef alloca
-# define alloca __builtin_alloca
-# define HAVE_ALLOCA 1
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gettextP.h"
-
-#if ENABLE_RELOCATABLE
-# include "relocatable.h"
-#else
-# define relocate(pathname) (pathname)
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ANSI C functions. This is required by the standard
- because some ANSI C functions will require linking with this object
- file and the name space must not be polluted. */
-# define strcasecmp __strcasecmp
-
-# ifndef mempcpy
-# define mempcpy __mempcpy
-# endif
-# define HAVE_MEMPCPY 1
-# define HAVE___FSETLOCKING 1
-
-/* We need locking here since we can be called from different places. */
-# include <bits/libc-lock.h>
-
-__libc_lock_define_initialized (static, lock);
-#endif
-
-#ifndef internal_function
-# define internal_function
-#endif
-
-/* Some optimizations for glibc. */
-#ifdef _LIBC
-# define FEOF(fp) feof_unlocked (fp)
-# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
-#else
-# define FEOF(fp) feof (fp)
-# define FGETS(buf, n, fp) fgets (buf, n, fp)
-#endif
-
-/* For those losing systems which don't have `alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
-#endif
-
-#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
-# undef fgets
-# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
-#endif
-#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
-# undef feof
-# define feof(s) feof_unlocked (s)
-#endif
-
-
-struct alias_map
-{
- const char *alias;
- const char *value;
-};
-
-
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-
-libc_freeres_ptr (static char *string_space);
-static size_t string_space_act;
-static size_t string_space_max;
-libc_freeres_ptr (static struct alias_map *map);
-static size_t nmap;
-static size_t maxmap;
-
-
-/* Prototypes for local functions. */
-static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
- internal_function;
-static int extend_alias_table PARAMS ((void));
-static int alias_compare PARAMS ((const struct alias_map *map1,
- const struct alias_map *map2));
-
-
-const char *
-_nl_expand_alias (name)
- const char *name;
-{
- static const char *locale_alias_path;
- struct alias_map *retval;
- const char *result = NULL;
- size_t added;
-
-#ifdef _LIBC
- __libc_lock_lock (lock);
-#endif
-
- if (locale_alias_path == NULL)
- locale_alias_path = LOCALE_ALIAS_PATH;
-
- do
- {
- struct alias_map item;
-
- item.alias = name;
-
- if (nmap > 0)
- retval = (struct alias_map *) bsearch (&item, map, nmap,
- sizeof (struct alias_map),
- (int (*) PARAMS ((const void *,
- const void *))
- ) alias_compare);
- else
- retval = NULL;
-
- /* We really found an alias. Return the value. */
- if (retval != NULL)
- {
- result = retval->value;
- break;
- }
-
- /* Perhaps we can find another alias file. */
- added = 0;
- while (added == 0 && locale_alias_path[0] != '\0')
- {
- const char *start;
-
- while (locale_alias_path[0] == PATH_SEPARATOR)
- ++locale_alias_path;
- start = locale_alias_path;
-
- while (locale_alias_path[0] != '\0'
- && locale_alias_path[0] != PATH_SEPARATOR)
- ++locale_alias_path;
-
- if (start < locale_alias_path)
- added = read_alias_file (start, locale_alias_path - start);
- }
- }
- while (added != 0);
-
-#ifdef _LIBC
- __libc_lock_unlock (lock);
-#endif
-
- return result;
-}
-
-
-static size_t
-internal_function
-read_alias_file (fname, fname_len)
- const char *fname;
- int fname_len;
-{
- FILE *fp;
- char *full_fname;
- size_t added;
- static const char aliasfile[] = "/locale.alias";
-
- full_fname = (char *) alloca (fname_len + sizeof aliasfile);
-#ifdef HAVE_MEMPCPY
- mempcpy (mempcpy (full_fname, fname, fname_len),
- aliasfile, sizeof aliasfile);
-#else
- memcpy (full_fname, fname, fname_len);
- memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
-#endif
-
- fp = fopen (relocate (full_fname), "r");
- freea (full_fname);
- if (fp == NULL)
- return 0;
-
-#ifdef HAVE___FSETLOCKING
- /* No threads present. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
-#endif
-
- added = 0;
- while (!FEOF (fp))
- {
- /* It is a reasonable approach to use a fix buffer here because
- a) we are only interested in the first two fields
- b) these fields must be usable as file names and so must not
- be that long
- We avoid a multi-kilobyte buffer here since this would use up
- stack space which we might not have if the program ran out of
- memory. */
- char buf[400];
- char *alias;
- char *value;
- char *cp;
-
- if (FGETS (buf, sizeof buf, fp) == NULL)
- /* EOF reached. */
- break;
-
- cp = buf;
- /* Ignore leading white space. */
- while (isspace ((unsigned char) cp[0]))
- ++cp;
-
- /* A leading '#' signals a comment line. */
- if (cp[0] != '\0' && cp[0] != '#')
- {
- alias = cp++;
- while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
- ++cp;
- /* Terminate alias name. */
- if (cp[0] != '\0')
- *cp++ = '\0';
-
- /* Now look for the beginning of the value. */
- while (isspace ((unsigned char) cp[0]))
- ++cp;
-
- if (cp[0] != '\0')
- {
- size_t alias_len;
- size_t value_len;
-
- value = cp++;
- while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
- ++cp;
- /* Terminate value. */
- if (cp[0] == '\n')
- {
- /* This has to be done to make the following test
- for the end of line possible. We are looking for
- the terminating '\n' which do not overwrite here. */
- *cp++ = '\0';
- *cp = '\n';
- }
- else if (cp[0] != '\0')
- *cp++ = '\0';
-
- if (nmap >= maxmap)
- if (__builtin_expect (extend_alias_table (), 0))
- {
- fclose (fp);
- return added;
- }
-
- alias_len = strlen (alias) + 1;
- value_len = strlen (value) + 1;
-
- if (string_space_act + alias_len + value_len > string_space_max)
- {
- /* Increase size of memory pool. */
- size_t new_size = (string_space_max
- + (alias_len + value_len > 1024
- ? alias_len + value_len : 1024));
- char *new_pool = (char *) realloc (string_space, new_size);
- if (new_pool == NULL)
- return added;
-
- if (__builtin_expect (string_space != new_pool, 0))
- {
- size_t i;
-
- for (i = 0; i < nmap; i++)
- {
- map[i].alias += new_pool - string_space;
- map[i].value += new_pool - string_space;
- }
- }
-
- string_space = new_pool;
- string_space_max = new_size;
- }
-
- map[nmap].alias = memcpy (&string_space[string_space_act],
- alias, alias_len);
- string_space_act += alias_len;
-
- map[nmap].value = memcpy (&string_space[string_space_act],
- value, value_len);
- string_space_act += value_len;
-
- ++nmap;
- ++added;
- }
- }
-
- /* Possibly not the whole line fits into the buffer. Ignore
- the rest of the line. */
- while (strchr (buf, '\n') == NULL)
- if (FGETS (buf, sizeof buf, fp) == NULL)
- /* Make sure the inner loop will be left. The outer loop
- will exit at the `feof' test. */
- break;
- }
-
- /* Should we test for ferror()? I think we have to silently ignore
- errors. --drepper */
- fclose (fp);
-
- if (added > 0)
- qsort (map, nmap, sizeof (struct alias_map),
- (int (*) PARAMS ((const void *, const void *))) alias_compare);
-
- return added;
-}
-
-
-static int
-extend_alias_table ()
-{
- size_t new_size;
- struct alias_map *new_map;
-
- new_size = maxmap == 0 ? 100 : 2 * maxmap;
- new_map = (struct alias_map *) realloc (map, (new_size
- * sizeof (struct alias_map)));
- if (new_map == NULL)
- /* Simply don't extend: we don't have any more core. */
- return -1;
-
- map = new_map;
- maxmap = new_size;
- return 0;
-}
-
-
-static int
-alias_compare (map1, map2)
- const struct alias_map *map1;
- const struct alias_map *map2;
-{
-#if defined _LIBC || defined HAVE_STRCASECMP
- return strcasecmp (map1->alias, map2->alias);
-#else
- const unsigned char *p1 = (const unsigned char *) map1->alias;
- const unsigned char *p2 = (const unsigned char *) map2->alias;
- unsigned char c1, c2;
-
- if (p1 == p2)
- return 0;
-
- do
- {
- /* I know this seems to be odd but the tolower() function in
- some systems libc cannot handle nonalpha characters. */
- c1 = isupper (*p1) ? tolower (*p1) : *p1;
- c2 = isupper (*p2) ? tolower (*p2) : *p2;
- if (c1 == '\0')
- break;
- ++p1;
- ++p2;
- }
- while (c1 == c2);
-
- return c1 - c2;
-#endif
-}
+++ /dev/null
-/* display.c -- readline redisplay facility. */
-
-/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
-
- This file is part of the GNU Readline Library (Readline), a library
- for reading lines of text with interactive input and history editing.
-
- Readline is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Readline is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Readline. If not, see <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 open_some_spaces PARAMS((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 displaying_prompt_first_line;
-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 += (newlines == 0) ? prompt_invis_chars_first_line
- : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line);
-
- 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. */
- displaying_prompt_first_line = 1;
- 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;
-
- displaying_prompt_first_line = lmargin < nleft;
-
- /* 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) &&
- displaying_prompt_first_line && 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) && displaying_prompt_first_line &&
- 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;
- int bytes_to_insert;
-#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 consumes 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 position in multibyte mode, but a buffer index when not in a
- multibyte locale. */
- _rl_move_cursor_relative (od, old);
-
-#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
-
- /* if (len (new) > len (old))
- lendiff == difference in buffer (bytes)
- col_lendiff == difference on screen (columns)
- 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;
- }
- }
-
- /* We use temp as a count of the number of bytes from the first difference
- to the end of the new line. col_temp is the corresponding number of
- screen columns. A `dumb' update moves to the spot of first difference
- and writes TEMP bytes. */
- /* 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;
-
- /* how many bytes from the new line buffer to write to the display */
- bytes_to_insert = nls - nfd;
-
- /* col_lendiff > 0 if we are adding characters to the line */
- 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 += col_temp; /* XXX - was _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 && displaying_prompt_first_line && 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))
- {
- open_some_spaces (col_lendiff);
- _rl_output_some_chars (nfd, bytes_to_insert);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- _rl_last_c_pos += _rl_col_width (nfd, 0, bytes_to_insert, 1);
- else
- _rl_last_c_pos += bytes_to_insert;
- }
- 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. */
- _rl_output_some_chars (nfd, temp);
- _rl_last_c_pos += col_temp;
- return;
- }
- else /* just write from first difference to end of new line */
- {
- _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 && displaying_prompt_first_line && wrap_offset && ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- return;
- }
-
- if (bytes_to_insert > lendiff)
- {
- /* 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 && displaying_prompt_first_line && 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 &&
- displaying_prompt_first_line &&
- 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 &&
- displaying_prompt_first_line &&
- -lendiff == visible_wrap_offset)
- col_lendiff = 0;
-
- /* If we have moved lmargin and we're shrinking the line, we've
- already moved the cursor to the first character of the new line,
- so deleting -col_lendiff characters will mess up the cursor
- position calculation */
- if (_rl_horizontal_scroll_mode && displaying_prompt_first_line == 0 &&
- col_lendiff && _rl_last_c_pos < -col_lendiff)
- col_lendiff = 0;
-
- if (col_lendiff)
- delete_chars (-col_lendiff); /* delete (diff) characters */
-
- /* Copy (new) chars to screen from first diff to last match,
- overwriting what is there. */
- if (bytes_to_insert > 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, bytes_to_insert);
- if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- {
- _rl_last_c_pos += _rl_col_width (nfd, 0, bytes_to_insert, 1);
- if (current_line == 0 && wrap_offset &&
- displaying_prompt_first_line &&
- _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 += bytes_to_insert;
-
- /* XXX - we only want to do this if we are at the end of the line
- so we move there with _rl_move_cursor_relative */
- if (_rl_horizontal_scroll_mode && ((oe-old) > (ne-new)))
- {
- int target;
-
- target = ne-new;
- target -= wrap_offset;
- _rl_move_cursor_relative (ne-new, new);
- goto clear_rest_of_line;
- }
- }
- }
- /* 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 &&
- displaying_prompt_first_line &&
- _rl_last_c_pos > wrap_offset &&
- ((nfd - new) <= prompt_last_invisible))
- {
- _rl_last_c_pos -= wrap_offset;
- cpos_adjusted = 1;
- }
- }
- }
-clear_rest_of_line:
- 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 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)))
- {
- 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);
-
- if (displaying_prompt_first_line == 0)
- adjust = 0;
-
- /* 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;
- }
- else if (local_prompt != saved_local_prompt)
- {
- FREE (local_prompt);
- FREE (local_prompt_prefix);
- local_prompt = (char *)NULL;
- }
- 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;
- }
- else if (local_prompt != saved_local_prompt)
- {
- FREE (local_prompt);
- FREE (local_prompt_prefix);
- local_prompt = (char *)NULL;
- }
- 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;
-{
- open_some_spaces (col);
- _rl_output_some_chars (string, count);
-}
-
-/* Insert COL spaces, keeping the cursor at the same position. We follow the
- ncurses documentation and use either im/ei with explicit spaces, or IC/ic
- by itself. We assume there will either be ei or we don't need to use it. */
-static void
-open_some_spaces (col)
- int col;
-{
-#if !defined (__MSDOS__) && !defined (__MINGW32__)
- char *buffer;
- register int i;
-
- /* If IC is defined, then we do not have to "enter" insert mode. */
- if (_rl_term_IC)
- {
- buffer = tgoto (_rl_term_IC, 0, col);
- tputs (buffer, 1, _rl_output_character_function);
- }
- else if (_rl_term_im && *_rl_term_im)
- {
- tputs (_rl_term_im, 1, _rl_output_character_function);
- /* just output the desired number of spaces */
- for (i = col; i--; )
- _rl_output_character_function (' ');
- /* If there is a string to turn off insert mode, use it now. */
- if (_rl_term_ei && *_rl_term_ei)
- tputs (_rl_term_ei, 1, _rl_output_character_function);
- /* and move back the right number of spaces */
- _rl_backspace (col);
- }
- else if (_rl_term_ic && *_rl_term_ic)
- {
- /* If there is a special command for inserting characters, then
- use that first to open up the space. */
- for (i = col; i--; )
- tputs (_rl_term_ic, 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)
- {
- if (_rl_vis_botlin > 0) /* minor optimization plus bug fix */
- _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);
-}
-
-void
-_rl_ttyflush ()
-{
- 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)
- /* this can happen in some cases where it's inconvenient to check */
- 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
-/* mktime - convert struct tm to a time_t value */
-
-/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
- Contributed by Paul Eggert (eggert@twinsun.com).
-
- 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/>.
-*/
-/* Define this to have a standalone program to test this implementation of
- mktime. */
-/* #define DEBUG 1 */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef _LIBC
-# define HAVE_LIMITS_H 1
-# define HAVE_LOCALTIME_R 1
-# define STDC_HEADERS 1
-#endif
-
-/* Assume that leap seconds are possible, unless told otherwise.
- If the host has a `zic' command with a `-L leapsecondfilename' option,
- then it supports leap seconds; otherwise it probably doesn't. */
-#ifndef LEAP_SECONDS_POSSIBLE
-#define LEAP_SECONDS_POSSIBLE 1
-#endif
-
-#ifndef VMS
-#include <sys/types.h> /* Some systems define `time_t' here. */
-#endif
-#include <time.h>
-
-#if HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include "bashansi.h"
-
-#if DEBUG
-#include <stdio.h>
-/* Make it work even if the system's libc has its own mktime routine. */
-#define mktime my_mktime
-#endif /* DEBUG */
-
-#ifndef __P
-#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
-#define __P(args) args
-#else
-#define __P(args) ()
-#endif /* GCC. */
-#endif /* Not __P. */
-
-#ifndef CHAR_BIT
-#define CHAR_BIT 8
-#endif
-
-#ifndef INT_MIN
-#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
-#endif
-#ifndef INT_MAX
-#define INT_MAX (~0 - INT_MIN)
-#endif
-
-#ifndef TIME_T_MIN
-#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
- : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
-#endif
-#ifndef TIME_T_MAX
-#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
-#endif
-
-#define TM_YEAR_BASE 1900
-#define EPOCH_YEAR 1970
-
-#ifndef __isleap
-/* Nonzero if YEAR is a leap year (every 4 years,
- except every 100th isn't, and every 400th is). */
-#define __isleap(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-#endif
-
-/* How many days come before each month (0-12). */
-const unsigned short int __mon_yday[2][13] =
- {
- /* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
- /* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
- };
-
-static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
-time_t __mktime_internal __P ((struct tm *,
- struct tm *(*) (const time_t *, struct tm *),
- time_t *));
-
-
-static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
-static struct tm *
-my_localtime_r (t, tp)
- const time_t *t;
- struct tm *tp;
-{
- struct tm *l = localtime (t);
- if (! l)
- return 0;
- *tp = *l;
- return tp;
-}
-
-
-/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
- measured in seconds, ignoring leap seconds.
- YEAR uses the same numbering as TM->tm_year.
- All values are in range, except possibly YEAR.
- If overflow occurs, yield the low order bits of the correct answer. */
-static time_t
-ydhms_tm_diff (year, yday, hour, min, sec, tp)
- int year, yday, hour, min, sec;
- const struct tm *tp;
-{
- /* Compute intervening leap days correctly even if year is negative.
- Take care to avoid int overflow. time_t overflow is OK, since
- only the low order bits of the correct time_t answer are needed.
- Don't convert to time_t until after all divisions are done, since
- time_t might be unsigned. */
- int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
- int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
- int a100 = a4 / 25 - (a4 % 25 < 0);
- int b100 = b4 / 25 - (b4 % 25 < 0);
- int a400 = a100 >> 2;
- int b400 = b100 >> 2;
- int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
- time_t years = year - (time_t) tp->tm_year;
- time_t days = (365 * years + intervening_leap_days
- + (yday - tp->tm_yday));
- return (60 * (60 * (24 * days + (hour - tp->tm_hour))
- + (min - tp->tm_min))
- + (sec - tp->tm_sec));
-}
-
-
-static time_t localtime_offset;
-
-/* Convert *TP to a time_t value. */
-time_t
-mktime (tp)
- struct tm *tp;
-{
-#ifdef _LIBC
- /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
- time zone names contained in the external variable `tzname' shall
- be set as if the tzset() function had been called. */
- __tzset ();
-#endif
-
- return __mktime_internal (tp, my_localtime_r, &localtime_offset);
-}
-
-/* Convert *TP to a time_t value, inverting
- the monotonic and mostly-unit-linear conversion function CONVERT.
- Use *OFFSET to keep track of a guess at the offset of the result,
- compared to what the result would be for UTC without leap seconds.
- If *OFFSET's guess is correct, only one CONVERT call is needed. */
-time_t
-__mktime_internal (tp, convert, offset)
- struct tm *tp;
- struct tm *(*convert) __P ((const time_t *, struct tm *));
- time_t *offset;
-{
- time_t t, dt, t0;
- struct tm tm;
-
- /* The maximum number of probes (calls to CONVERT) should be enough
- to handle any combinations of time zone rule changes, solar time,
- and leap seconds. Posix.1 prohibits leap seconds, but some hosts
- have them anyway. */
- int remaining_probes = 4;
-
- /* Time requested. Copy it in case CONVERT modifies *TP; this can
- occur if TP is localtime's returned value and CONVERT is localtime. */
- int sec = tp->tm_sec;
- int min = tp->tm_min;
- int hour = tp->tm_hour;
- int mday = tp->tm_mday;
- int mon = tp->tm_mon;
- int year_requested = tp->tm_year;
- int isdst = tp->tm_isdst;
-
- /* Ensure that mon is in range, and set year accordingly. */
- int mon_remainder = mon % 12;
- int negative_mon_remainder = mon_remainder < 0;
- int mon_years = mon / 12 - negative_mon_remainder;
- int year = year_requested + mon_years;
-
- /* The other values need not be in range:
- the remaining code handles minor overflows correctly,
- assuming int and time_t arithmetic wraps around.
- Major overflows are caught at the end. */
-
- /* Calculate day of year from year, month, and day of month.
- The result need not be in range. */
- int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
- [mon_remainder + 12 * negative_mon_remainder])
- + mday - 1);
-
-#if LEAP_SECONDS_POSSIBLE
- /* Handle out-of-range seconds specially,
- since ydhms_tm_diff assumes every minute has 60 seconds. */
- int sec_requested = sec;
- if (sec < 0)
- sec = 0;
- if (59 < sec)
- sec = 59;
-#endif
-
- /* Invert CONVERT by probing. First assume the same offset as last time.
- Then repeatedly use the error to improve the guess. */
-
- tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
- tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
- t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
-
- for (t = t0 + *offset;
- (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
- t += dt)
- if (--remaining_probes == 0)
- return -1;
-
- /* Check whether tm.tm_isdst has the requested value, if any. */
- if (0 <= isdst && 0 <= tm.tm_isdst)
- {
- int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
- if (dst_diff)
- {
- /* Move two hours in the direction indicated by the disagreement,
- probe some more, and switch to a new time if found.
- The largest known fallback due to daylight savings is two hours:
- once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
- time_t ot = t - 2 * 60 * 60 * dst_diff;
- while (--remaining_probes != 0)
- {
- struct tm otm;
- if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
- (*convert) (&ot, &otm))))
- {
- t = ot;
- tm = otm;
- break;
- }
- if ((ot += dt) == t)
- break; /* Avoid a redundant probe. */
- }
- }
- }
-
- *offset = t - t0;
-
-#if LEAP_SECONDS_POSSIBLE
- if (sec_requested != tm.tm_sec)
- {
- /* Adjust time to reflect the tm_sec requested, not the normalized value.
- Also, repair any damage from a false match due to a leap second. */
- t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
- (*convert) (&t, &tm);
- }
-#endif
-
- if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
- {
- /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
- so check for major overflows. A gross check suffices,
- since if t has overflowed, it is off by a multiple of
- TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
- the difference that is bounded by a small value. */
-
- double dyear = (double) year_requested + mon_years - tm.tm_year;
- double dday = 366 * dyear + mday;
- double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
-
- if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
- return -1;
- }
-
- *tp = tm;
- return t;
-}
-
-#ifdef weak_alias
-weak_alias (mktime, timelocal)
-#endif
-\f
-#if DEBUG
-
-static int
-not_equal_tm (a, b)
- struct tm *a;
- struct tm *b;
-{
- return ((a->tm_sec ^ b->tm_sec)
- | (a->tm_min ^ b->tm_min)
- | (a->tm_hour ^ b->tm_hour)
- | (a->tm_mday ^ b->tm_mday)
- | (a->tm_mon ^ b->tm_mon)
- | (a->tm_year ^ b->tm_year)
- | (a->tm_mday ^ b->tm_mday)
- | (a->tm_yday ^ b->tm_yday)
- | (a->tm_isdst ^ b->tm_isdst));
-}
-
-static void
-print_tm (tp)
- struct tm *tp;
-{
- printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
- tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
- tp->tm_hour, tp->tm_min, tp->tm_sec,
- tp->tm_yday, tp->tm_wday, tp->tm_isdst);
-}
-
-static int
-check_result (tk, tmk, tl, tml)
- time_t tk;
- struct tm tmk;
- time_t tl;
- struct tm tml;
-{
- if (tk != tl || not_equal_tm (&tmk, &tml))
- {
- printf ("mktime (");
- print_tm (&tmk);
- printf (")\nyields (");
- print_tm (&tml);
- printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
- return 1;
- }
-
- return 0;
-}
-
-int
-main (argc, argv)
- int argc;
- char **argv;
-{
- int status = 0;
- struct tm tm, tmk, tml;
- time_t tk, tl;
- char trailer;
-
- if ((argc == 3 || argc == 4)
- && (sscanf (argv[1], "%d-%d-%d%c",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
- == 3)
- && (sscanf (argv[2], "%d:%d:%d%c",
- &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
- == 3))
- {
- tm.tm_year -= TM_YEAR_BASE;
- tm.tm_mon--;
- tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
- tmk = tm;
- tl = mktime (&tmk);
- tml = *localtime (&tl);
- printf ("mktime returns %ld == ", (long) tl);
- print_tm (&tmk);
- printf ("\n");
- status = check_result (tl, tmk, tl, tml);
- }
- else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
- {
- time_t from = atol (argv[1]);
- time_t by = atol (argv[2]);
- time_t to = atol (argv[3]);
-
- if (argc == 4)
- for (tl = from; tl <= to; tl += by)
- {
- tml = *localtime (&tl);
- tmk = tml;
- tk = mktime (&tmk);
- status |= check_result (tk, tmk, tl, tml);
- }
- else
- for (tl = from; tl <= to; tl += by)
- {
- /* Null benchmark. */
- tml = *localtime (&tl);
- tmk = tml;
- tk = tl;
- status |= check_result (tk, tmk, tl, tml);
- }
- }
- else
- printf ("Usage:\
-\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
-\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
-\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
- argv[0], argv[0], argv[0]);
-
- return status;
-}
-
-#endif /* DEBUG */
-\f
-/*
-Local Variables:
-compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
-End:
-*/
+++ /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-2013 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <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 ')'
-#define LBRACK '['
-#define RBRACK ']'
-
-#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];
-int ifs_is_set, ifs_is_null;
-
-#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;
-extern int builtin_ignoring_errexit;
-
-#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 WORD_LIST *list_dequote_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 char *parameter_brace_find_indir __P((char *, int, int, int));
-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_ASSIGNARRAY)
- {
- f &= ~W_ASSIGNARRAY;
- fprintf (stderr, "W_ASSIGNARRAY%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_ASSIGNINT)
- {
- f &= ~W_ASSIGNINT;
- fprintf (stderr, "W_ASSIGNINT%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_SPLITSPACE)
- {
- f &= ~W_SPLITSPACE;
- fprintf (stderr, "W_SPLITSPACE%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;
- }
-
- /* 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 > 42 && 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;
- }
-
- /* 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_QUOTE2; /* XXX */
- 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 ((flags & SD_GLOB) && c == LBRACK)
- {
- si = i + 1;
- if (string[si] == '\0')
- CQ_RETURN(si);
-
- temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
-
- i = si;
- if (string[i] == '\0') /* don't increment i past EOS in loop */
- break;
- i++;
- continue;
- }
- 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 parameters 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, mkglobal;
- WORD_LIST *list;
-
- mklocal = flags & ASS_MKLOCAL;
- mkassoc = flags & ASS_MKASSOC;
- mkglobal = flags & ASS_MKGLOBAL;
-
- 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);
- if (v)
- assign_compound_array_list (v, list, flags);
- }
- /* In a function but forcing assignment in global context */
- else if (mkglobal && variable_context)
- {
- v = find_global_variable (name);
- list = expand_compound_array_assignment (v, value, flags);
- if (v == 0 && mkassoc)
- v = make_new_assoc_variable (name);
- else if (v && mkassoc && assoc_p (v) == 0)
- v = convert_var_to_assoc (v);
- else if (v == 0)
- v = make_new_array_variable (name);
- else if (v && mkassoc == 0 && array_p (v) == 0)
- v = convert_var_to_array (v);
- if (v)
- 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_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
- aflags |= ASS_MKGLOBAL;
- 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)
- {
- dispose_words (save);
- 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;
-{
- WORD_DESC td;
- WORD_LIST *list, *tlist;
- 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])
- {
- /* This is expanded version of expand_string_internal as it's called by
- expand_string_leave_quoted */
- td.flags = W_NOPROCSUB; /* don't want process substitution */
- td.word = savestring (string);
- list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
- /* This takes care of the calls from expand_string_leave_quoted and
- expand_string */
- if (list)
- {
- tlist = word_list_split (list);
- dispose_words (list);
- list = tlist;
- if (list)
- dequote_list (list);
- }
- /* This comes from expand_string_if_necessary */
- if (list)
- {
- ret = string_list (list);
- dispose_words (list);
- }
- else
- ret = (char *)NULL;
- FREE (td.word);
- }
- else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
- ret = string_quote_removal (string, quoted);
- else
- ret = savestring (string);
-
- return ret;
-}
-
-#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);
-
- expand_no_split_dollar_star = 1;
- w->flags |= W_NOSPLIT2;
- l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
- expand_no_split_dollar_star = 0;
- if (l)
- {
- if (special == 0) /* LHS */
- {
- dequote_list (l);
- r = string_list (l);
- }
- else
- {
- /* Need to figure out whether or not we should call dequote_escapes
- or a new dequote_ctlnul function here, and under what
- circumstances. */
- 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 */
- return (NULL);
- }
- 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;
-}
-
-static WORD_LIST *
-list_dequote_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 = dequote_escapes (t);
- free (t);
- }
- return list;
-}
-
-/* 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))
- {
- 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--)
- {
- 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);
-
- for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
- {
- c = *p; *p = '\0';
- if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
- {
- *p = c;
- *sp = string;
- *ep = p;
- return 1;
- }
- *p = c;
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
- }
-
- return (0);
-
- case MATCH_END:
- for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
- {
- if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
- {
- *sp = p;
- *ep = end;
- return 1;
- }
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
- }
-
- 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++)
- {
- n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
- if (n2)
- {
- n1 = (mlen == -1) ? wstrlen : n + mlen;
- if (n1 > wstrlen)
- break;
-
- for ( ; n1 >= n; n1--)
- {
- 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 MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
- }
- }
- }
-
- return (0);
-
- case MATCH_BEG:
- if (match_pattern_wchar (wpat, wstring) == 0)
- return (0);
-
- for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
- {
- 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 MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
- }
-
- return (0);
-
- case MATCH_END:
- for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
- {
- if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
- {
- *sp = indices[n];
- *ep = indices[wstrlen];
- return 1;
- }
- /* If MLEN != -1, we have a fixed length pattern. */
- if (mlen != -1)
- break;
- }
-
- 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 (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
- 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);
-
- /* XXX */
- if (v && invisible_p (var))
- return ((char *)NULL);
-
- 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_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 */
-
- /* subshells shouldn't have this flag, which controls using the temporary
- environment for variable lookups. */
- expanding_redir = 0;
-
- 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 */
-
- last_command_exit_value = result;
- result = run_exit_trap ();
- 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)
- {
- builtin_ignoring_errexit = 0;
- change_flag ('e', FLAG_OFF);
- set_shellopts ();
- }
-
- 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_nosigs (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_nosigs (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
- pipeline, 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 || invisible_p (var) || (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 || invisible_p (var))
- 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[*]? */
- if (pflags & PF_ASSIGNRHS)
- {
- temp = array_variable_name (name, &tt, (int *)0);
- if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == ']')
- temp = array_value (name, quoted|Q_DOUBLE_QUOTES, 0, &atype, &ind);
- else
- temp = array_value (name, quoted, 0, &atype, &ind);
- }
- else
- 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;
- }
- else if (var = find_variable_last_nameref (name))
- {
- temp = nameref_cell (var);
-#if defined (ARRAY_VARS)
- /* Handle expanding nameref whose value is x[n] */
- if (temp && *temp && valid_array_reference (temp))
- {
- name = temp;
- goto expand_arrayref;
- }
- else
-#endif
- /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
- if (temp && *temp && legal_identifier (temp) == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("%s: invalid variable name for name reference"), temp);
- temp = &expand_param_error;
- }
- else
- temp = (char *)NULL;
- }
- else
- temp = (char *)NULL;
-
- if (ret == 0)
- {
- ret = alloc_word_desc ();
- ret->word = temp;
- ret->flags |= rflags;
- }
- return ret;
-}
-
-static char *
-parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
- char *name;
- int var_is_special, quoted, find_nameref;
-{
- char *temp, *t;
- WORD_DESC *w;
- SHELL_VAR *v;
-
- if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name)) &&
- nameref_p (v) && (t = nameref_cell (v)) && *t)
- return (savestring (t));
-
- /* If var_is_special == 0, and name is not an array reference, this does
- more expansion than necessary. It should really look up the variable's
- value and not try to expand it. */
- 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);
-
- return t;
-}
-
-/* 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;
- }
- }
-
- t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
- if (t == 0 || *t == 0)
- {
- report_error (_("%s: invalid indirect expansion"), name);
- w = alloc_word_desc ();
- w->word = &expand_param_error;
- w->flags = 0;
- return 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, *vname;
- 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);
-
- /* bash-4.4/5.0 */
- vname = name;
- if (*name == '!' &&
- (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
- {
- vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
- if (vname == 0 || *vname == 0)
- {
- report_error (_("%s: invalid indirect expansion"), name);
- free (vname);
- dispose_word (w);
- return &expand_wdesc_error;
- }
- if (legal_identifier (vname) == 0)
- {
- report_error (_("%s: invalid variable name"), vname);
- free (vname);
- dispose_word (w);
- return &expand_wdesc_error;
- }
- }
-
-#if defined (ARRAY_VARS)
- if (valid_array_reference (vname))
- assign_array_element (vname, t1, 0);
- else
-#endif /* ARRAY_VARS */
- bind_variable (vname, t1, 0);
-#if 0
- if (STREQ (vname, "IFS") == 0)
-#endif
- stupidly_hack_special_variables (vname);
-
- if (vname != name)
- free (vname);
-
- /* 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, want_indir;
- char *temp, *vname;
- WORD_DESC *wd;
-#if defined (ARRAY_VARS)
- SHELL_VAR *v;
-#endif
- arrayind_t lind;
-
- want_indir = *varname == '!' &&
- (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
- || VALID_INDIR_PARAM (varname[1]));
- if (want_indir)
- vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
- else
- vname = varname;
-
- /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
- vtype = (vname[0] == '@' || vname[0] == '*') && vname[1] == '\0';
- if (vtype == VT_POSPARMS && vname[0] == '*')
- vtype |= VT_STARSUB;
- *varp = (SHELL_VAR *)NULL;
-
-#if defined (ARRAY_VARS)
- if (valid_array_reference (vname))
- {
- v = array_variable_part (vname, &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 && invisible_p (v))
- {
- vtype = VT_ARRAYMEMBER;
- *varp = (SHELL_VAR *)NULL;
- *valp = (char *)NULL;
- }
- if (v && (array_p (v) || assoc_p (v)))
- { /* [ */
- if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
- {
- /* Callers have to differentiate between 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 (vname, 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 (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
- }
- }
- else if ((v = find_variable (vname)) && (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;
- }
-
- if (want_indir)
- free (vname);
-
- 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;
-
- ret = string_list_pos_params (pchar, save, qflags);
-
- 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. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
- if (shell_compatibility_level > 42)
- rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
- /* This is the bash-4.2 code. */
- else if ((mflags & MATCH_QUOTED) == 0)
- rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
- else
- rep = expand_string_to_string_internal (rep, quoted, 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|PF_ASSIGNRHS)), &ind);
-
- if (tdesc)
- {
- temp = tdesc->word;
- tflag = tdesc->flags;
- dispose_word_desc (tdesc);
- }
- else
- temp = (char *)0;
-
- if (temp == &expand_param_error || temp == &expand_param_fatal)
- {
- FREE (name);
- FREE (value);
- return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
- }
-
-#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);
- /* XXX - this may not need to be restricted to special variables */
- if (check_nullness)
- var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
-
- /* 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;
- /* We test quoted_dollar_atp because we want variants with double-quoted
- "$@" to take a different code path. In fact, we make sure at the end
- of expand_word_internal that we're only looking at these flags if
- quoted_dollar_at == 0. */
- if (temp1 &&
- (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
- 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_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
- 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_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
- 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 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);
- if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
- tflag |= W_SPLITSPACE;
- }
-
- 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. */
- /* XXX - what to do when in a context where word splitting is not
- performed? Even when IFS is not the default, posix seems to imply
- that we behave like unquoted $* ? Maybe we should use PF_NOSPLIT2
- here. */
- 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;
- }
- else if (var = find_variable_last_nameref (temp1))
- {
- temp = nameref_cell (var);
-#if defined (ARRAY_VARS)
- if (temp && *temp && valid_array_reference (temp))
- {
- tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL);
- if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
- return (tdesc);
- ret = tdesc;
- goto return0;
- }
- else
-#endif
- /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
- if (temp && *temp && legal_identifier (temp) == 0)
- {
- last_command_exit_value = EXECUTION_FAILURE;
- report_error (_("%s: invalid variable name for name reference"), temp);
- return (&expand_wdesc_error); /* XXX */
- }
- else
- temp = (char *)NULL;
- }
-
- 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 split_on_spaces;
- 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;
- split_on_spaces = 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 top-level 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;
- split_on_spaces += (tword->flags & W_SPLITSPACE);
-
- 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);
- }
- /* This is the fix for " $@\ " */
- else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
- {
- RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
- DEFAULT_ARRAY_SIZE);
- istring[istring_index++] = CTLESC;
- istring[istring_index++] = '\\';
- istring[istring_index] = '\0';
-
- 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 ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- 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)
- {
- /* 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 ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
- 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;
- char *tstring;
-
- 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
- SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
- unset or null, and we want to make sure that we split on spaces
- regardless of what else has happened to IFS since the expansion. */
- if (split_on_spaces)
- list = list_string (istring, " ", 1); /* XXX quoted == 1? */
- /* If we have $@ (has_dollar_at != 0) and we are in a context where we
- don't want to split the result (W_NOSPLIT2), and we are not quoted,
- we have already separated the arguments with the first character of
- $IFS. In this case, we want to return a list with a single word
- with the separator possibly replaced with a space (it's what other
- shells seem to do).
- quoted_dollar_at is internal to this function and is set if we are
- passed an argument that is unquoted (quoted == 0) but we encounter a
- double-quoted $@ while expanding it. */
- else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
- {
- /* Only split and rejoin if we have to */
- if (*ifs_chars && *ifs_chars != ' ')
- {
- list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
- tstring = string_list (list);
- }
- else
- tstring = istring;
- tword = make_bare_word (tstring);
- if (tstring != istring)
- free (tstring);
- goto set_word_flags;
- }
- else if (has_dollar_at && ifs_chars)
- list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
- else
- {
- tword = make_bare_word (istring);
-set_word_flags:
- 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";
-
- ifs_is_set = ifs_var != 0;
- ifs_is_null = ifs_is_set && (*ifs_value == 0);
-
- /* 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]);
- 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;
- char opts[8], opti;
-
- opti = 0;
- if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_ASSIGNARRAY))
- opts[opti++] = '-';
-
- if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
- {
- opts[opti++] = 'g';
- opts[opti++] = 'A';
- }
- else if (tlist->word->flags & W_ASSIGNASSOC)
- opts[opti++] = 'A';
- else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
- {
- opts[opti++] = 'g';
- opts[opti++] = 'a';
- }
- else if (tlist->word->flags & W_ASSIGNARRAY)
- opts[opti++] = 'a';
- else if (tlist->word->flags & W_ASSNGLOBAL)
- opts[opti++] = 'g';
-
-#if 0
- /* If we have special handling note the integer attribute */
- if (opti > 0 && (tlist->word->flags & W_ASSIGNINT))
- opts[opti++] = 'i';
-#endif
-
- opts[opti] = '\0';
- if (opti > 0)
- make_internal_declare (tlist->word->word, opts);
-
- 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|W_ASSIGNARRAY);
- }
-#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;
-
- tempenv_assign_error = 0;
- 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;
- }
-
- return (new_list);
-}
+++ /dev/null
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
-THIS_SH=$BUILD_DIR/bash
-PATH=$PATH:$BUILD_DIR
-
-export THIS_SH PATH
-
-rm -f /tmp/xx
-
-/bin/sh "$@"
+++ /dev/null
-# first, let's start with the basics
-
-recho "$@"
-recho "$*"
-
-recho $@
-recho $*
-
-set a b
-
-recho "$*"
-
-# If IFS is null, the parameters are joined without separators
-IFS=''
-recho "$*"
-
-# If IFS is unset, the parameters are separated by spaces
-unset IFS
-recho "${*}"
-
-recho "$@"
-recho $@
-
-IFS='/'
-set bob 'tom dick harry' joe
-set $*
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set ${*}
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set $@
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set ${@}
-recho $#
-recho $1
-recho $2
-recho $3
-
-# according to POSIX.2, unquoted $* should expand to multiple words if
-# $IFS is null, just like unquoted $@
-IFS=''
-set bob 'tom dick harry' joe
-set $*
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set $@
-recho $#
-recho $1
-recho $2
-recho $3
-
-# if IFS is unset, the individual positional parameters are split on
-# " \t\n" if $* or $@ are unquoted
-unset IFS
-set bob 'tom dick harry' joe
-set $*
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set $@
-recho $#
-recho $1
-recho $2
-recho $3
-
-# but not for "$@" or "$*"
-set bob 'tom dick harry' joe
-set "$*"
-recho $#
-recho $1
-recho $2
-recho $3
-
-set bob 'tom dick harry' joe
-set "$@"
-recho $#
-recho $1
-recho $2
-recho $3
-
-# POSIX.2 says these should both expand the positional parameters
-# to multiple words
-set a b c d e
-IFS=""
-recho $@
-recho "$@"
-
-# this example is straight from the POSIX.2 rationale
-set foo bar bam
-
-recho "$@"
-recho "$*"
-
-unset IFS
-
-recho "$@"
-recho $@
-recho "$*"
-
-IFS=:
-
-# special variables
-set -- 1 2 3 4 5 6 7 8 9 10
-
-bar=${*}
-foo=$*
-echo foo = "$foo"
-echo bar = "$bar"
-
-foo1=$@
-bar1=${@}
-
-echo foo1 = "$foo1"
-echo bar1 = "$bar1"
-
-foo2="$*"
-bar2="${*}"
-
-echo foo2 = "$foo2"
-echo bar2 = "$bar2"
-
-eval foo3='$*' bar3='${*}'
-echo foo3 = "$foo3"
-echo bar3 = "$bar3"
-
-case $* in
-*\:*) echo ok 1;;
-*) echo bad 1;;
-esac
-
-case $@ in
-*\:*) echo bad 2;;
-*) echo ok 2;;
-esac
-
-case "$*" in
-*\:*) echo ok 3;;
-*) echo bad 3;;
-esac
-
-case "$@" in
-*\:*) echo bad 4;;
-*) echo ok 4;;
-esac
-
-IFS=$' \t\n'
-
-bar=${*}
-foo=$*
-echo foo = "$foo"
-echo bar = "$bar"
-
-foo1=$@
-bar1=${@}
-
-echo foo1 = "$foo1"
-echo bar1 = "$bar1"
-
-foo2="$*"
-bar2="${*}"
-
-echo foo2 = "$foo2"
-echo bar2 = "$bar2"
-
-eval foo3='$*' bar3='${*}'
-echo foo3 = "$foo3"
-echo bar3 = "$bar3"
-
-case $* in
-*\ *) echo ok 1;;
-*) echo bad 1;;
-esac
-
-case $@ in
-*\ *) echo ok 2;;
-*) echo bad 2;;
-esac
-
-case "$*" in
-*\ *) echo ok 3;;
-*) echo bad 3;;
-esac
-
-case "$@" in
-*\ *) echo ok 4;;
-*) echo bad 4;;
-esac
-
-# tests for the effect of quoting $* and $@ in an assignment context (plus
-# arrays) -- bugs through bash 4.2
-${THIS_SH} ./dollar-at-star1.sub
-
-# tests for special expansion of "$*" and "${array[*]}" when used with other
-# expansions -- bugs through bash-2.05b
-${THIS_SH} ./dollar-star1.sub
-
-# tests for expansion of "$@" on rhs of things like ${param:+word}. Bugs
-# though bash-2.05b
-${THIS_SH} ./dollar-at1.sub
-
-# tests for expansion of other variables in double-quoted strings containing
-# $@. Bugs through bash-2.05b
-${THIS_SH} ./dollar-at2.sub
-
-# tests for various expansions of $* in different contexts -- word split,
-# no splitting, etc. when $IFS is NUL
-${THIS_SH} ./dollar-star2.sub
-
-# tests for expansions of "${array[*]}" and "${array[@]}" when $IFS is not the
-# default and the array contains null elements
-${THIS_SH} ./dollar-star3.sub
-
-# test for set -u and expansions of $@ when there are no positional parameters
-${THIS_SH} ./dollar-at3.sub
-# test for set -u and expansions of $* when there are no positional parameters
-${THIS_SH} ./dollar-star4.sub
-
-# tests for expansions of $* when IFS is null
-${THIS_SH} ./dollar-star5.sub
-
-# tests for inappropriate word splitting through bash-4.2
-${THIS_SH} ./dollar-at4.sub
-
-# tests for problems with "$@" preceded and followed by other quoted expansions
-# through bash-4.2
-${THIS_SH} ./dollar-at5.sub
-
-# tests for problems with "${@:1}" and other expansions with null entries
-# in positional parameters
-${THIS_SH} ./dollar-at6.sub
-
-# tests for expansions of $* when $1 == ""; problem through bash-4.2
-${THIS_SH} ./dollar-star6.sub
-
-# tests for expansions of $* (unquoted) when IFS changes (e.g., ${IFS:=-})
-# problem through bash-4.2
-${THIS_SH} ./dollar-star7.sub
-
-exit 0
+++ /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