+++ /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/20
- ----
-lib/readline/display.c
- - When using horizontal scrolling, the redisplay code erases too much
- of the line containing successful results, so make sure we only
- erase to the end of the line after making sure we move the cursor
- to the end. Fixes bug reported by <Trond.Endrestol@ximalas.info>
-
- 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>
-
- 4/27
- ----
-subst.c
- - parameter_brace_expand_rhs: if parameter_brace_find_indir returns
- NULL or "", or if it returns something that is not a valid identifier,
- report an error and return &expand_wdesc_error so the error can
- propagate up. Fixes bug reported by Andre Holzhey
- <andre.holzhey@gmx.de>
-
- 4/29
- ----
-subst.c
- - parameter_brace_substring: don't short-circuit right away if the
- value is NULL but we are looking at the positional parameters. Part
- of fix for bug reported by Pierre Gaston <pierre.gaston@gmail.com>
- - pos_params: if there are no positional parameters, only short-circuit
- if we are looking for $1 and above. Rest of fix for bug reported
- by Pierre Gaston <pierre.gaston@gmail.com>
-
-subst.h
- - SD_NOPROCSUB: new flag for skip_to_delim, means to not allow any
- process subsitutions (should not have overloaded SD_NOSKIPCMD)
-
-subst.c
- - skip_to_delim: honor SD_NOPROCSUB flag
-
-make_cmd.c
- - make_arith_for_expr: set W_NOPROCSUB flag in the created word
- - make_arith_for_command: set SD_NOPROCSUB in the flags argument to
- skip_to_delim so we don't treat <( or >( as a process substitution
- (we won't evaluate them in eval_arith_for_expr anyway). Fixes
- bug reported by Pierre Gaston <pierre.gaston@gmail.com>
-
- 5/1
- ---
-lib/glob/gmisc.c
- - glob_dirscan: new function, takes a pattern and a directory separator
- argument and advances the pattern to the last occurrence of the
- separator. Like strrchr, but understands extended glob patterns and
- uses glob_patscan to skip over them
-
-lib/glob/glob.c
- - extglob_skipname: if the extended globbing pattern is invalid, don't
- skip the name
- - glob_filename: if there is a slash in the pattern to be matched, and
- extglob is enabled, use glob_dirscan to find the real last occurrence
- of `/' to avoid being confused by slashes in extglob patterns. Fix
- for bug reported by Pierre Gaston <pierre.gaston@gmail.com>
-
- 5/6
- ---
-variables.c
- - make_local_variable: only set the att_invisible attribute if
- no_invisible_vars isn't set
- - find_variable_for_assignment: new function, intended to be called by
- code that eventually wants to assign a value to the variable; will not
- skip invisible variables; currently identical to find_variable
- - find_variable_no_invisible: new function, finds the first visible
- instance of variable with a given name in the variable context chain;
- eventually will be used to replace find_variable; separate right now
- for testing
-
-variables.h
- - find_variable_for_assignment: extern declaration
- - find_variable_no_invisible: extern declaration
-
- 5/7
- ---
-variables.c
- - make_local_variable: don't clear `invisible' attribute if we are
- returning an existing local variable at the right context. Let the
- upper layers do that. Fixes bug reported by Dan Douglas
- <ormaaj@gmail.com>
-
- 5/8
- ---
-lib/readline/input.c
- - rl_getc: call RL_CHECK_SIGNALS if a read(2) is interrupted (-1/EINTR)
- by SIGALRM or SIGVTALRM (placeholder for non-keyboard-generated
- signals of interest)
-
-builtins/read.def
- - edit_line: call bashline_set_event_hook and
- bashline_reset_event_hook around call to readline(), so the right
- signal handling happens
- - read_builtin: make sure we add an unwind_protect call to
- bashline_reset_event_hook. These changes fix bug reported in
- https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1317476
-
-bashline.c
- - bash_event_hook: make sure we clean up the readline state by calling
- rl_cleanup_after_signal if sigalrm_seen is non-zero. The read builtin
- sets this when it times out
-
- 5/12
- ----
-doc/{bash.1,bashref.texi}
- - clarify language to make it clear that changing attributes of a
- nameref variable (e.g., export), actually changes the attributes of
- the referenced variable. Fixes omission noted by Jeff Haemer
- <jeffrey.haemer@gmail.com>
-
-arrayfunc.c
- - bind_array_var_internal: make sure ENTRY no longer has invisible
- attribute before returning. Fixes bug reported by Geir Hauge
- <geir.hauge@gmail.com>
-
- 5/22
- ----
-execute_cmd.c
- - shell_execve: if execve fails and we return 127 or 126, make sure to
- set last_command_exit_value if a call to file_error or report_error
- causes the shell to exit. This ensures that the shell exits with
- the right value.
-
- 6/6
- ---
-shell.c
- - drop_priv_mode: print an error message on setuid() failure, optionally
- exit if errno == EAGAIN, as it can be on Linux when RLIMIT_NPROC for
- the target user is exceeded.
-
-config-top.h
- - EXIT_ON_SETUID_FAILURE: new settable define, will cause the shell to
- exit if setuid fails with errno == EAGAIN
-
- 6/10
- ----
-parse.y
- - time_command_acceptable: fix so time is accepted everywhere the
- grammar is looking for a `compound_list'. Fixes bug reported by
- Dale Worley <worley@alum.mit.edu>
-
- 6/12
- ----
-subst.c
- - clear_fifo_list: new function, clears FDs associated with open pipes
- in current FIFO list without closing the file descriptors. Can
- possibly be used when shell_execve fails and the shell jumps back
- to top_level and we don't want the shell to close the open FIFOs
- each time through the read-execute loop. Bug reported by Harald
- Koenig <koenig@tat.physik.uni-tuebingen.de>
-
-
- 6/16
- ----
-builtins/shopt.def
- - compat42: make sure the `compat42' option sets the correct variable
- for compatibility level. Fixes bug reported by Ondrej Oprala
- <ooprala@redhat.com>
-
-support/bashbug.sh
- - fix typo when echoing $USAGE. Report from Shantanu Kulkarni
- <djbware@shantanukulkarni.org>
-
-execute_cmd.c
- - shell_execve: before longjmp back to subshell_top_level, clear out the
- FIFO fd list by calling clear_fifo_list so the FDs (which we inherited
- from our parent) aren't closed every time through the read-eval loop.
- Fix for bug reported by Harald Koenig <koenig@tat.physik.uni-tuebingen.de>
-
- 6/18
- ----
-subst.c
- - extract_process_subst: add additional argument: xflags, allow callers to
- pass flags like extract_command_subst
- - extract_process_subst: call xparse_dolparen like command substitution
- to avoid problems when parsing commands constructs with embedded open
- parens. Fixes bug reported by Tim Friske <me@timfriske.com>
-
-subst.h
- - extract_process_subst: modified prototype for extern declaration
-
- 6/19
- ----
-execute_cmd.c
- - execute_pipeline: if running with lastpipe enabled, make sure that we
- check whether or not the job id is valid using INVALID_JOB before
- calling job_exit_status. the jobs list can get frozen and unfrozen in
- the presence of nested pipelines and loops and wait_for can clear a
- job table entry. Fixes bug reported by <scorp.dev.null@gmail.com>
-
-jobs.c
- - freeze_jobs_list: now returns old value of jobs_list_frozen; unused at
- current time
-
-jobs.h
- - freeze_jobs_list: change return value
-
- 6/20
- ----
-lib/glob/smatch.c
- - MEMCHR: single-byte and wide character defines (memchr/wmemchr)
-
-lib/glob/sm_loop.c
- - GMATCH: when the wildcards are the last element of the pattern, make
- sure they do not match a string containing a `/' if FNM_PATHNAME is
- set in FLAGS
- - GMATCH: when recursively calling GMATCH after we see a `*', don't
- try to consume the rest of the pattern with `*' if FNM_PATHNAME is
- set in FLAGS, just consume up to the next slash and then see whether
- or not the rest of the pattern matches. Fixes bug reported by Ian
- Kelling <ian@iankelling.org>
- - GMATCH: when processing `*' in the pattern, after skipping consecutive
- wildcards, if we hit a literal `/' in the pattern and we're looking
- for a pathname, skip characters in the string until we find a `/'
- (no slash means the match fails), and try to match the rest of the
- pattern against the portion of the string after the next `/'. Picked
- up from gnulib/glibc
-
-pathexp.c
- - split_ignorespec: since split_ignorespec gets globbing patterns,
- make sure we call skip_to_delim with the SD_GLOB flag so delimiters
- that occur within bracket expressions don't delimit the pattern.
- Fixes problem with [[:digit:]] in GLOBIGNORE reported by Ian Kelling
- <ian@iankelling.org>
-
-unwind_prot.c
- - unwind_protect_tag_on_stack: new function, returns 1 if unwind-protect
- frame corresponding to `tag' argument is on unwind-protect stack
-
-unwind_prot.h
- - unwind_protect_tag_on_stack: extern declaration
-
- 6/30
- ----
-lib/readline/misc.c
- - _rl_revert_all_lines: set entry->data to 0 after assigning it to
- rl_undo_list to avoid pointer aliasing problems that would result
- in entry->line being freed by an undo. The subsequent free would
- be a double free. Report and fix from Jared Yanovich
- <slovichon@gmail.com>
-
-subst.c
- - command_substitute: other shells do not appear to inherit the -v
- option when reading and executing command substitutions. Reported
- by Ondrej Oprala <ooprala@redhat.com>
-
- 7/1
- ---
-config-top.h
- - CHECKHASH_DEFAULT: new define that supplies the default value for
- check_hashed_filenames (`checkhash' shopt option); still 0 by default
-
-findcmd.c
- - check_hashed_filenames: initialize using CHECKHASH_DEFAULT
-
-lib/readline/histexpand.c
- - history_expand: double quotes can inhibit recognition of the history
- comment character if history_quotes_inhibit_expansion is non-zero
-
-lib/readline/doc/{history.3,hstech.texi}
- - history_quotes_inhibit_expansion: expand definition to note that it
- inhibits scanning for the history comment character as well; correct
- typo to make it clear that it only works on double-quoted strings
-
-lib/sh/zgetline.c
- - add new fourth argument: DELIM, allows delimiter to be something
- other than newline (if DELIM != '\n', UNBUFFERED_READ should be
- non-zero)
- - UNBUFFERED_READ is now fifth argument
- - check character against DELIM rather than strictly newline
-
-externs.h
- - zgetline: change function prototype for extern declaration
-
-builtins/mapfile.def
- - mapfile: change calling sequence for zgetline calls
- - mapfile_builtin: new -d option: DELIM, like in read builtin
- - mapfile_builtin: pass `delim' to mapfile() as new argument; default
- to '\n' unless -d option supplied
- - mapfile: take new DELIM argument, pass to zgetline
- - mapfile: if DELIM != '\n', set unbuffered_read to 1
-
-doc/{bash.1,bashref.texi}
- - mapfile: document new `-d DELIM' option
-
- 7/5
- ---
-lib/readline/histfile.c
- - history_truncate_file: if there is an error writing the truncated
- history list back to the history file, use the same strategy as
- history_do_write: create a backup file, rename the history file to
- the backup file, and restore the original history file from the
- backup file name if the write or the close fails. Suggestion from
- Chen Gang <gang.chen.5i5j@gmail.com> to bug-readline
-
-execute_cmd.c
- - evalnest, evalnest_max: new variables establishing maximum number of
- recursive `eval' calls; current max is 4096
- - execute_builtin: unwind-protect value of evalnest around calls to
- eval builtin. Suggested by Oliver Morais <oliver.morais@gmail.com>
- - {initialize_subshell,execute_subshell_builtin_or_function}: reset
- evalnest to 0 in a subshell
-
-builtins/setattr.def
- - show_name_attributes: show a variable's attributes even if it's
- invisible (don't show any value since it has none). This means that
- declare -p var will display VAR's attributes even when var marked
- as invisible. Feature request from Peggy Russell
- <prusselltechgroup@gmail.com>
- - show_var_attributes: don't print assignment if array or assoc
- attribute is set but variable marked as invisible
-
-tests/array.right
- - special note: changed all declare -a output tests because the shell
- will no longer print out values for invisible array variables. This
- is a change, but one for correctness:
-
- declare -a foo='()'
- and
- declare -a foo
- are not equivalent
-
- 7/22
- ----
-subst.c
- - parameter_brace_expand: after calling parameter_brace_expand_indir,
- turn off the W_ARRAYIND flag in the word it returns, because there
- is no way for it to return the index that should be used, and the
- rest of the function assumes that IND is valid if W_ARRAYIND is set.
- Fixes bug reported by Corentin Peuvrel <cpeuvrel@pom-monitoring.com>
-
- 8/2
- ---
-parse.y
- - read_token_word: if we read a character that will end a command
- substitution, don't skip over quoted newlines when we read an
- additional character to figure out whether it's a two-character
- token. This lets the higher layers deal with quoted newlines after
- the command substitution. Fixes bug reported by EmanueL Czirai
- <amanual@riseup.net>
-
- 8/11
- ----
-execute_cmd.c
- - execute_pipeline: check whether lastpipe_jid corresponds to a valid
- job before calling append_process, for the same reason as fix from
- 6/19. Fixes bug reported by <lolilolicon@gmail.com>
-
- 8/12
- ----
-lib/sh/unicode.c
- - stub_charset: use strncpy instead of strcpy because we are copying
- into a local fixed-length buffer. Fixes vulnerability reported by
- <romerox.adrian@gmail.com>
-
-execute_cmd.c
- - execute_pipeline: if we don't call append_process, call
- wait_for_single_pid to get the status of `lastpid', since that will
- check the status of already-reaped processes. Fixes spurious error
- message about non-existent process from fix of 8/11
-
- 8/15
- ----
-jobs.c
- - running_in_background: new variable, keeps track of whether or not we
- are running in the background (not perfect yet)
- - initialize_job_control: even if we are not turning on job control,
- get the terminal pgrp so we can use it later
- - {set_job_control,initialize_job_control}: set running_in_background
- to 1 if terminal pgrp != shell pgrp
- - {stop_pipeline,make_child,wait_for}: if we are running in the
- background, don't mess with the terminal's process group; assume that
- the parent shell will do that. Fixes bug reprted by Greg Wooledge
- <wooledg@eeg.ccf.org>
-
-shell.c
- - shell_reinitialize: reset running_in_background back to 0
-
- 8/24
- ----
-execute_cmd.c
- - {execute_connection,execute_command_internal}: make sure that
- asynchronous commands always set $? to 0 and are not affected by the
- command's exit status being inverted using `!'. Fixes bug reported
- by Vincent Lefevre <vincent@vinc17.net>
-
-lib/readline/display.c
- - rl_message: call vsnprintf with full msg_bufsiz, since it counts
- one fewer than the buffer length passed as an argument. Bug report
- and fix from Dylan Cali <calid1984@gmail.com>
-
- 8/26
- ----
-builtins/evalstring.c
- - evalstring: if CURRENT_TOKEN == yacc_EOF, reset it to newline. This is
- instead of calling reset_parser(); that might still be needed. Fixes
- bug with eval and a subsequent statement ending with EOF reported by
- <jim.avera@gmail.org>
-
-pcomplete.c
- - filter_stringlist: when extglob is on, a leading ! in the filter
- pattern should be left alone when it introduces a !(pat) pattern;
- otherwise it messes up the pattern. Fixes bug reported by David
- Korn <dgkorn@gmail.com>
-
- 8/27
- ----
-doc/{bash.1,bashref.texi}
- - clarify the behavior of bash when given the -c option, since $0 is
- technically not a positional parameter. Bug reported by Stephane
- Chazelas <stephane.chazelas@gmail.com>
-
- 8/28
- ----
-lib/readline/history.c
- - add_history: use history_max_entries (if history is stifled) or
- DEFAULT_HISTORY_INITIAL_SIZE if not (new define, defaults to 502)
- to size the initial allocation of the history array. Assumption
- is that this will reduce the number of allocations
-
- 8/29
- ----
-execute_command.c:
- - sourcenest, sourcenest_max: new variables used to track level of
- sourced files and (maybe) one day catch infinite source recursion
- - execute_builtin: if current source level exceeds sourcenest_max,
- trigger an error and jump back to the top level
- - {initialize_subshell,execute_subshell_builtin_or_function}: reset
- sourcenest to 0 in a subshell
-
- 9/2
- ---
-variables.c
- - bind_variable: if a nameref expands to an array reference, make
- sure that assign_array_element gets called (maybe even
- recursively) instead of bind_variable_internal, so invalid variable
- names (like arr[0]) don't get created. Fixes bug reported by
- <lolilolicon@gmail.com>
-
- 9/3
- ---
-execute_cmd.c
- - evalnest_max,sourcenest_max: initialize from EVALNEST_MAX and
- SOURCENEST_MAX, respectively. Feature suggested by
- <bogun.dmitriy@gmail.com>
-
-config-top.h
- - define EVALNEST_MAX and SOURCENEST_MAX to 0
-
- 9/6
- ---
-bashline.c
- - find_cmd_start: fix to (crudely) deal with >| token; even though
- skip_to_delim finds `|' as a delimiter, we call it again and use
- what the second call finds. Fixes bug reported by Dan Jacobson
- <jidanni@jidanni.org>
-
-findcmd.c
- - find_in_path_element: if in posix mode, do not expand a literal
- tilde in a $PATH element
-
-doc/bashref.texi
- - add change to tilde expansion in $PATH elements to posix mode
- description
-
-builtins/common.h
- - ISHELP: new define for builtins that do their own option parsing
- and don't use internal_getopt(); checks whether argument is --help
- - CHECK_HELPOPT: convenience define to help builtins that do their
- own option parsing to check for --help with one line of code
- - CASE_HELPOPT: convenience define to help builtins that use
- internal_getopt() check for --help with one line of code
-
-builtins/help.def
- - builtin_help: new function, prints out --help output for current
- builtin
-
-builtins/{kill,let,pushd}.def
- - add CHECK_HELPOPT to builtins that use ISOPTION; call builtin_help
- and return EX_USAGE (kill/let/pushd/popd/dirs)
-
-builtins/{caller,fg_bg}.def
- - use CHECK_HELPOPT to recognize --help, since these builtins perform
- checks that can cause them to return before calling no_options
- (caller/fg/bg)
-
-builtins/{exit,return}.def
- - use CHECK_HELPOPT to recognize --help before calling get_exitstat()
- (return/exit/logout)
-
-builtins/{break,shift}.def
- - use CHECK_HELPOPT to recognize --help before any other checks
- (break/continue/shift)
-
-builtins/bashgetopt.h
- - GETOPT_EOF: convenience define
- - GETOPT_HELP: new define, to indicate internal_getopt saw --help
-
-builtins/bashgetopt.c
- - internal_getopt: return GETOPT_HELP for --help
-
-builtins/common.c
- - no_options: recognize --help, call builtin_help and return 2
- (builtin/eval/source/./times)
-
-builtins/command.def
- - use CASE_HELPOPT() to handle --help after calling internal_getopt()
- (command)
-
-builtins/{colon,echo,test}.def
- - do not recognize --help (:/true/false/echo/test)
-
- 9/8
- ---
-sig.c
- - termsig_sighandler: if readline is active now, set the bashline event
- hook. Old code just set it for interactive shells. Part of fix for
- bug reported by <mickael9@gmail.com>
-
-bashline.c
- - bash_event_hook: call rl_cleanup_after_signal if terminating_signal
- is non-zero, since check_signals_and_traps() will cause the shell to
- exit if it is and we want to clean up the readline state first. Rest
- of fix for bug reported by <mickael9@gmail.com>
-
- 9/9
- ---
-jobs.c
- - waitchld: when running the wait builtin in posix mode, with a trap set
- on SIGCHLD, use queue_sigchld_trap instead of trap_handler (SIGCHLD),
- otherwise you will lose SIGCHLDs when children_exited > 1. Fixes bug
- reported by <crispusfairbairn@gmail.com>
-
-builtins/read.def
- - read_builtin: if we are changing the tty settings, call
- initialize_terminating_signals so we have a chance to catch all
- terminating signals and potentially clean up the terminal before
- exiting
- - read_builtin: tty_modified: new variable, set to 1 if we change the
- terminal attributes and have to call ttyrestore() to restore them
- - if one of the `reads' returns -1/EINTR due to a terminating signal,
- and we have modified the terminal, call ttyrestore before calling
- CHECK_TERMSIG
- - ttyrestore: set tty_modified to 0 when called
-
- 9/10
- ----
-builtins/read.def
- - termsave: now global to file so other functions can use it
- - read_tty_cleanup: if tty_modified is non-zero, call ttycleanup to restore
- old terminal settings and turn off tty_modified
-
-sig.c
- - termsig_handler: call read_tty_cleanup if currently executing read
- builtin; it does the right thing. Final piece of fix for bug reported
- by Jan Rome <jan.rome@gmail.com>
-
- 9/11
- ----
-general.c
- - printable_filename: general function to return a printable representation
- of a string (presumed to be a filename)
-
-general.h
- - extern declaration for printable_filename
-
-execute_cmd.c
- - execute_disk_command: use printable_filename
-
-builtins/{bind,cd,enable,hash,source}.def
- - use printable_filename as appropriate when printing error messages.
- From a suggestion by Vincent Lefevre <vincent@vinc17.net>
-
-builtins/bind.def
- - use CASE_HELPOPT() to handle --help after calling internal_getopt()
- (bind)
-
- 9/12
- ----
-builtins/common.h
- - SEVAL_FUNCDEF: new flag for parse_and_execute; it means that we only
- accept a single function definition command, as when we are importing
- functions from the environment
- - SEVAL_ONECMD: new flag for parse_and_execute; for future use
-
-builtins/evalstring.c
- - parse_and_execute: if the SEVAL_FUNCDEF flag is set, disallow anything
- but a function definition command
-
-variables.c
- - initialize_shell_variables: don't allow functions with invalid names
- to be imported from the environment, even though we still allow them
- to be defined
- - initialize_shell_variables: when importing function definitions from
- the environment, call parse_and_execute with the SEVAL_FUNCDEF flag
- to force the command to be just a function definition
-
-subst.c
- - param_expand: when expanding a $name variable expansion, make sure that
- the variable is visible and set before following the nameref chain
- - param_expand: when expanding a $name variable expansion and following the
- nameref chain, make sure the resulting variable is visible and set
- before using it
-
- 9/13
- ----
-variables.c
- - initialize_shell_variables: when importing function definitions from
- environment, use SEVAL_ONECMD flag for parse_and_execute. Part of
- CVE-2014-6271
-
-builtins/evalstring.c
- - parse_and_execute: if SEVAL_ONECMD flag set, return immediately after
- calling execute_command_internal. Final piece for fix for bug
- reported by Stephane Chazelas <stephane.chazelas@gmail.com>. Part of
- CVE-2014-6271
-
- 9/24
- ----
-parse.y
- - reset_parser: reset eol_ungetc_lookahead to 0 here, since we don't want
- shell_getc returning it on the next call. Fixes problem reported by
- Tavis Ormandy <taviso@cmpxchg8b.com> and Michal Zalewski
- <lcamtuf@coredump.cx>. Potentially part of CVE-2014-6271; fix for
- CVE-2014-7169
-
- 9/25
- ----
-parse.y
- - push_heredoc: new function, pushes a here-doc redirection onto
- redir_stack handling overflow of redir_stack. Exits on overflow.
- Original fix from Florian Weimer <fweimer@redhat.com>. Fix for
- CVE-2014-7186
- - change straight assignments to redir_stack to call push_redir
- - add one to size of word_lineno stack to avoid off-by-one error
- below in read_token_word. Overflow just results in line numbers
- being wrong. Fix for CVE-2014-7187
-
- 9/27
- ----
-{execute_cmd,trap}.c
- - changes to make minimal-config builds work again, mostly missing
- #ifdefs for optional features
-
-builtins/common.c
- - builtin_help: dummy version to be included if HELP_BUILTIN not
- defined, for minimal-config builds
-
-variables.c
- - initialize_shell_variables: incorporated patches from Florian
- Weimer <fweimer@redhat.com> to change the strings bash looks
- for when importing shell functions from the environment. It
- adds a prefix (BASH_FUNC_) and a suffix (%%) to the name to
- mark it as having been created by bash as an exported function.
- Fix for remote attacks part of CVE-2014-6271 and CVE-2014-7169
- - mk_env_string: takes new argument, indicating whether we are
- constructing a function
- - mk_env_string: encodes function names as described above, so
- initialize_shell_variables can find them
-
- 9/28
- ----
-copy_cmd.c
- - copy_redirects: before calling savestring on here_doc_eof, make
- sure it's not NULL (it could have been the result of a here
- document delimited by EOF or EOS). Fixes bug reported by
- Michal Zalewski <lcamtuf@coredump.cx>. Fix for CVE-2014-6277
-
-make_cmd.c
- - make_redirection: initialize here_doc_eof member to NULL. Rest of
- fix for CVE-2014-6277
-
- 9/29
- ----
-parse.y
- - current_input_line_state: return a sh_input_line_state_t containing
- the current shell_input_line and its index and size variables
-
-shell.h
- - current_input_line_state: extern declaration
-
-builtins/evalstring.c
- - parse_and_execute: call reset_parser() before returning if
- SEVAL_ONECMD set. Fixes bug reported by Michal Zalewski
- <lcamtuf@coredump.cx> and designated CVE-2014-6278
- - parse_and_execute: if we parse a function definition when
- SEVAL_FUNCDEF is set, but don't consume the entire passed string,
- throw an error, reset the parser, and return. Part of fix for
- CVE-2014-6278
- - parse_and_execute: if parsing the shell function definition when
- SEVAL_FUNCDEF is set transforms the function name (e.g., if it
- begins with a newline or begins or ends with whitespace), throw
- an error, reset the parser, and return. Fixes bug reported by
- Eric Kobrin <ekobrin@akamai.com>
-
- 10/2
- ----
-jobs.c
- - bgp_prune: don't do anything if bgpids.npid == 0 or bgpids.list == NULL.
- This can happen if something gets run before the job control framework
- is initialized. Bug report from <mancha1@zoho.com>
-
- 10/3
- ----
-parse.y
- - xparse_dolparen: don't set token_to_read to newline after calling
- parse_string() and cleaning up when the shell is not interactive. This
- makes the parser thing it's ok to read new commands even if it's not in
- a state where that should be possible. Underlying fix for bug reported
- by Michal Zalewski <lcamtuf@coredump.cx> and designated CVE-6278
- - parser_remaining_input: new function, returns the portion of
- shell_input_line that hasn't yet been read
- - current_input_line_state: removed
-
-shell.h
- - parser_remaining_input: extern declaration
- - current_input_line_state: removed
-
-builtins/evalstring.c
- - parse_and_execute: change code that checks whether parse_command has
- consumed the entire passed string when SEVAL_FUNCDEF is used to use
- parser_remaining_input instead of messing around with (new)
- current_input_line_state. Part of fix for CVE-2014-6278
-
-variables.c
- - initialize_shell_variables: if we don't call parse_and_execute, free the
- temporary string, since parse_and_execute won't. Report and fix from
- Eric Kobrin <ekobrin@akamai.com>
-
- 10/4
- ----
-print_cmd.c
- - print_function_def: when in posix mode, print shell function
- definitions as posix specifies them, without the leading
- `function' keyword
+++ /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-at-star2.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/exportfunc.tests f
-tests/exportfunc.right f
-tests/exportfunc1.sub f
-tests/exportfunc2.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/mapfile2.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/parser.tests f
-tests/parser.right f
-tests/parser1.sub 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-exportfunc 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-parser 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
-/* common.c - utility functions for all builtins */
-
-/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <config.h>
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <chartypes.h>
-#include "../bashtypes.h"
-#include "posixstat.h"
-#include <signal.h>
-
-#include <errno.h>
-
-#if defined (PREFER_STDARG)
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#include "../bashansi.h"
-#include "../bashintl.h"
-
-#define NEED_FPURGE_DECL
-
-#include "../shell.h"
-#include "maxpath.h"
-#include "../flags.h"
-#include "../jobs.h"
-#include "../builtins.h"
-#include "../input.h"
-#include "../execute_cmd.h"
-#include "../trap.h"
-#include "bashgetopt.h"
-#include "common.h"
-#include "builtext.h"
-#include <tilde/tilde.h>
-
-#if defined (HISTORY)
-# include "../bashhist.h"
-#endif
-
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-extern int indirection_level, subshell_environment;
-extern int line_number;
-extern int last_command_exit_value;
-extern int trap_saved_exit_value;
-extern int running_trap;
-extern int posixly_correct;
-extern char *this_command_name, *shell_name;
-extern const char * const bash_getcwd_errstr;
-
-/* Used by some builtins and the mainline code. */
-sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
-sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
-
-/* **************************************************************** */
-/* */
-/* Error reporting, usage, and option processing */
-/* */
-/* **************************************************************** */
-
-/* This is a lot like report_error (), but it is for shell builtins
- instead of shell control structures, and it won't ever exit the
- shell. */
-
-static void
-builtin_error_prolog ()
-{
- char *name;
-
- name = get_name_for_error ();
- fprintf (stderr, "%s: ", name);
-
- if (interactive_shell == 0)
- fprintf (stderr, _("line %d: "), executing_line_number ());
-
- if (this_command_name && *this_command_name)
- fprintf (stderr, "%s: ", this_command_name);
-}
-
-void
-#if defined (PREFER_STDARG)
-builtin_error (const char *format, ...)
-#else
-builtin_error (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
- va_list args;
-
- builtin_error_prolog ();
-
- SH_VA_START (args, format);
-
- vfprintf (stderr, format, args);
- va_end (args);
- fprintf (stderr, "\n");
-}
-
-void
-#if defined (PREFER_STDARG)
-builtin_warning (const char *format, ...)
-#else
-builtin_warning (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
- va_list args;
-
- builtin_error_prolog ();
- fprintf (stderr, _("warning: "));
-
- SH_VA_START (args, format);
-
- vfprintf (stderr, format, args);
- va_end (args);
- fprintf (stderr, "\n");
-}
-
-/* Print a usage summary for the currently-executing builtin command. */
-void
-builtin_usage ()
-{
- if (this_command_name && *this_command_name)
- fprintf (stderr, _("%s: usage: "), this_command_name);
- fprintf (stderr, "%s\n", _(current_builtin->short_doc));
- fflush (stderr);
-}
-
-/* Return if LIST is NULL else barf and jump to top_level. Used by some
- builtins that do not accept arguments. */
-void
-no_args (list)
- WORD_LIST *list;
-{
- if (list)
- {
- builtin_error (_("too many arguments"));
- top_level_cleanup ();
- jump_to_top_level (DISCARD);
- }
-}
-
-/* Check that no options were given to the currently-executing builtin,
- and return 0 if there were options. */
-int
-no_options (list)
- WORD_LIST *list;
-{
- int opt;
-
- reset_internal_getopt ();
- if ((opt = internal_getopt (list, "")) != -1)
- {
- if (opt == GETOPT_HELP)
- {
- builtin_help ();
- return (2);
- }
- builtin_usage ();
- return (1);
- }
- return (0);
-}
-
-void
-sh_needarg (s)
- char *s;
-{
- builtin_error (_("%s: option requires an argument"), s);
-}
-
-void
-sh_neednumarg (s)
- char *s;
-{
- builtin_error (_("%s: numeric argument required"), s);
-}
-
-void
-sh_notfound (s)
- char *s;
-{
- builtin_error (_("%s: not found"), s);
-}
-
-/* Function called when one of the builtin commands detects an invalid
- option. */
-void
-sh_invalidopt (s)
- char *s;
-{
- builtin_error (_("%s: invalid option"), s);
-}
-
-void
-sh_invalidoptname (s)
- char *s;
-{
- builtin_error (_("%s: invalid option name"), s);
-}
-
-void
-sh_invalidid (s)
- char *s;
-{
- builtin_error (_("`%s': not a valid identifier"), s);
-}
-
-void
-sh_invalidnum (s)
- char *s;
-{
- char *msg;
-
- if (*s == '0' && isdigit (s[1]))
- msg = _("invalid octal number");
- else if (*s == '0' && s[1] == 'x')
- msg = _("invalid hex number");
- else
- msg = _("invalid number");
- builtin_error ("%s: %s", s, msg);
-}
-
-void
-sh_invalidsig (s)
- char *s;
-{
- builtin_error (_("%s: invalid signal specification"), s);
-}
-
-void
-sh_badpid (s)
- char *s;
-{
- builtin_error (_("`%s': not a pid or valid job spec"), s);
-}
-
-void
-sh_readonly (s)
- const char *s;
-{
- builtin_error (_("%s: readonly variable"), s);
-}
-
-void
-sh_erange (s, desc)
- char *s, *desc;
-{
- if (s)
- builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
- else
- builtin_error (_("%s out of range"), desc ? desc : _("argument"));
-}
-
-#if defined (JOB_CONTROL)
-void
-sh_badjob (s)
- char *s;
-{
- builtin_error (_("%s: no such job"), s);
-}
-
-void
-sh_nojobs (s)
- char *s;
-{
- if (s)
- builtin_error (_("%s: no job control"), s);
- else
- builtin_error (_("no job control"));
-}
-#endif
-
-#if defined (RESTRICTED_SHELL)
-void
-sh_restricted (s)
- char *s;
-{
- if (s)
- builtin_error (_("%s: restricted"), s);
- else
- builtin_error (_("restricted"));
-}
-#endif
-
-void
-sh_notbuiltin (s)
- char *s;
-{
- builtin_error (_("%s: not a shell builtin"), s);
-}
-
-void
-sh_wrerror ()
-{
-#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE)
- if (errno != EPIPE)
-#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */
- builtin_error (_("write error: %s"), strerror (errno));
-}
-
-void
-sh_ttyerror (set)
- int set;
-{
- if (set)
- builtin_error (_("error setting terminal attributes: %s"), strerror (errno));
- else
- builtin_error (_("error getting terminal attributes: %s"), strerror (errno));
-}
-
-int
-sh_chkwrite (s)
- int s;
-{
- fflush (stdout);
- if (ferror (stdout))
- {
- sh_wrerror ();
- fpurge (stdout);
- clearerr (stdout);
- return (EXECUTION_FAILURE);
- }
- return (s);
-}
-
-/* **************************************************************** */
-/* */
-/* Shell positional parameter manipulation */
-/* */
-/* **************************************************************** */
-
-/* Convert a WORD_LIST into a C-style argv. Return the number of elements
- in the list in *IP, if IP is non-null. A convenience function for
- loadable builtins; also used by `test'. */
-char **
-make_builtin_argv (list, ip)
- WORD_LIST *list;
- int *ip;
-{
- char **argv;
-
- argv = strvec_from_word_list (list, 0, 1, ip);
- argv[0] = this_command_name;
- return argv;
-}
-
-/* Remember LIST in $1 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
- non-zero, then discard whatever the existing arguments are, else
- only discard the ones that are to be replaced. */
-void
-remember_args (list, destructive)
- WORD_LIST *list;
- int destructive;
-{
- register int i;
-
- for (i = 1; i < 10; i++)
- {
- if ((destructive || list) && dollar_vars[i])
- {
- free (dollar_vars[i]);
- dollar_vars[i] = (char *)NULL;
- }
-
- if (list)
- {
- dollar_vars[i] = savestring (list->word->word);
- list = list->next;
- }
- }
-
- /* If arguments remain, assign them to REST_OF_ARGS.
- Note that copy_word_list (NULL) returns NULL, and
- that dispose_words (NULL) does nothing. */
- if (destructive || list)
- {
- dispose_words (rest_of_args);
- rest_of_args = copy_word_list (list);
- }
-
- if (destructive)
- set_dollar_vars_changed ();
-}
-
-static int changed_dollar_vars;
-
-/* Have the dollar variables been reset to new values since we last
- checked? */
-int
-dollar_vars_changed ()
-{
- return (changed_dollar_vars);
-}
-
-void
-set_dollar_vars_unchanged ()
-{
- changed_dollar_vars = 0;
-}
-
-void
-set_dollar_vars_changed ()
-{
- if (variable_context)
- changed_dollar_vars |= ARGS_FUNC;
- else if (this_shell_builtin == set_builtin)
- changed_dollar_vars |= ARGS_SETBLTIN;
- else
- changed_dollar_vars |= ARGS_INVOC;
-}
-
-/* **************************************************************** */
-/* */
-/* Validating numeric input and arguments */
-/* */
-/* **************************************************************** */
-
-/* Read a numeric arg for this_command_name, the name of the shell builtin
- that wants it. LIST is the word list that the arg is to come from.
- Accept only the numeric argument; report an error if other arguments
- follow. If FATAL is 1, call throw_to_top_level, which exits the
- shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the
- current command; if FATAL is 0, return an indication of an invalid
- number by setting *NUMOK == 0 and return -1. */
-int
-get_numeric_arg (list, fatal, count)
- WORD_LIST *list;
- int fatal;
- intmax_t *count;
-{
- char *arg;
-
- if (count)
- *count = 1;
-
- if (list && list->word && ISOPTION (list->word->word, '-'))
- list = list->next;
-
- if (list)
- {
- arg = list->word->word;
- if (arg == 0 || (legal_number (arg, count) == 0))
- {
- sh_neednumarg (list->word->word ? list->word->word : "`'");
- if (fatal == 0)
- return 0;
- else if (fatal == 1) /* fatal == 1; abort */
- throw_to_top_level ();
- else /* fatal == 2; discard current command */
- {
- top_level_cleanup ();
- jump_to_top_level (DISCARD);
- }
- }
- no_args (list->next);
- }
-
- return (1);
-}
-
-/* Get an eight-bit status value from LIST */
-int
-get_exitstat (list)
- WORD_LIST *list;
-{
- int status;
- intmax_t sval;
- char *arg;
-
- if (list && list->word && ISOPTION (list->word->word, '-'))
- list = list->next;
-
- if (list == 0)
- {
- /* If we're not running the DEBUG trap, the return builtin, when not
- given any arguments, uses the value of $? before the trap ran. If
- given an argument, return uses it. This means that the trap can't
- change $?. The DEBUG trap gets to change $?, though, since that is
- part of its reason for existing, and because the extended debug mode
- does things with the return value. */
- if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1)
- return (trap_saved_exit_value);
- return (last_command_exit_value);
- }
-
- arg = list->word->word;
- if (arg == 0 || legal_number (arg, &sval) == 0)
- {
- sh_neednumarg (list->word->word ? list->word->word : "`'");
- return EX_BADUSAGE;
- }
- no_args (list->next);
-
- status = sval & 255;
- return status;
-}
-
-/* Return the octal number parsed from STRING, or -1 to indicate
- that the string contained a bad number. */
-int
-read_octal (string)
- char *string;
-{
- int result, digits;
-
- result = digits = 0;
- while (*string && ISOCTAL (*string))
- {
- digits++;
- result = (result * 8) + (*string++ - '0');
- if (result > 0777)
- return -1;
- }
-
- if (digits == 0 || *string)
- result = -1;
-
- return (result);
-}
-
-/* **************************************************************** */
-/* */
-/* Manipulating the current working directory */
-/* */
-/* **************************************************************** */
-
-/* Return a consed string which is the current working directory.
- FOR_WHOM is the name of the caller for error printing. */
-char *the_current_working_directory = (char *)NULL;
-
-char *
-get_working_directory (for_whom)
- char *for_whom;
-{
- if (no_symbolic_links)
- {
- FREE (the_current_working_directory);
- the_current_working_directory = (char *)NULL;
- }
-
- if (the_current_working_directory == 0)
- {
-#if defined (GETCWD_BROKEN)
- the_current_working_directory = getcwd (0, PATH_MAX);
-#else
- the_current_working_directory = getcwd (0, 0);
-#endif
- if (the_current_working_directory == 0)
- {
- fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
- (for_whom && *for_whom) ? for_whom : get_name_for_error (),
- _(bash_getcwd_errstr), strerror (errno));
- return (char *)NULL;
- }
- }
-
- return (savestring (the_current_working_directory));
-}
-
-/* Make NAME our internal idea of the current working directory. */
-void
-set_working_directory (name)
- char *name;
-{
- FREE (the_current_working_directory);
- the_current_working_directory = savestring (name);
-}
-
-/* **************************************************************** */
-/* */
-/* Job control support functions */
-/* */
-/* **************************************************************** */
-
-#if defined (JOB_CONTROL)
-int
-get_job_by_name (name, flags)
- const char *name;
- int flags;
-{
- register int i, wl, cl, match, job;
- register PROCESS *p;
- register JOB *j;
-
- job = NO_JOB;
- wl = strlen (name);
- for (i = js.j_jobslots - 1; i >= 0; i--)
- {
- j = get_job_by_jid (i);
- if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
- continue;
-
- p = j->pipe;
- do
- {
- if (flags & JM_EXACT)
- {
- cl = strlen (p->command);
- match = STREQN (p->command, name, cl);
- }
- else if (flags & JM_SUBSTRING)
- match = strcasestr (p->command, name) != (char *)0;
- else
- match = STREQN (p->command, name, wl);
-
- if (match == 0)
- {
- p = p->next;
- continue;
- }
- else if (flags & JM_FIRSTMATCH)
- return i; /* return first match */
- else if (job != NO_JOB)
- {
- if (this_shell_builtin)
- builtin_error (_("%s: ambiguous job spec"), name);
- else
- internal_error (_("%s: ambiguous job spec"), name);
- return (DUP_JOB);
- }
- else
- job = i;
- }
- while (p != j->pipe);
- }
-
- return (job);
-}
-
-/* Return the job spec found in LIST. */
-int
-get_job_spec (list)
- WORD_LIST *list;
-{
- register char *word;
- int job, jflags;
-
- if (list == 0)
- return (js.j_current);
-
- word = list->word->word;
-
- if (*word == '\0')
- return (NO_JOB);
-
- if (*word == '%')
- word++;
-
- if (DIGIT (*word) && all_digits (word))
- {
- job = atoi (word);
- return (job > js.j_jobslots ? NO_JOB : job - 1);
- }
-
- jflags = 0;
- switch (*word)
- {
- case 0:
- case '%':
- case '+':
- return (js.j_current);
-
- case '-':
- return (js.j_previous);
-
- case '?': /* Substring search requested. */
- jflags |= JM_SUBSTRING;
- word++;
- /* FALLTHROUGH */
-
- default:
- return get_job_by_name (word, jflags);
- }
-}
-#endif /* JOB_CONTROL */
-
-/*
- * NOTE: `kill' calls this function with forcecols == 0
- */
-int
-display_signal_list (list, forcecols)
- WORD_LIST *list;
- int forcecols;
-{
- register int i, column;
- char *name;
- int result, signum, dflags;
- intmax_t lsignum;
-
- result = EXECUTION_SUCCESS;
- if (!list)
- {
- for (i = 1, column = 0; i < NSIG; i++)
- {
- name = signal_name (i);
- if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
- continue;
-
- if (posixly_correct && !forcecols)
- {
- /* This is for the kill builtin. POSIX.2 says the signal names
- are displayed without the `SIG' prefix. */
- if (STREQN (name, "SIG", 3))
- name += 3;
- printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
- }
- else
- {
- printf ("%2d) %s", i, name);
-
- if (++column < 5)
- printf ("\t");
- else
- {
- printf ("\n");
- column = 0;
- }
- }
- }
-
- if ((posixly_correct && !forcecols) || column != 0)
- printf ("\n");
- return result;
- }
-
- /* List individual signal names or numbers. */
- while (list)
- {
- if (legal_number (list->word->word, &lsignum))
- {
- /* This is specified by Posix.2 so that exit statuses can be
- mapped into signal numbers. */
- if (lsignum > 128)
- lsignum -= 128;
- if (lsignum < 0 || lsignum >= NSIG)
- {
- sh_invalidsig (list->word->word);
- result = EXECUTION_FAILURE;
- list = list->next;
- continue;
- }
-
- signum = lsignum;
- name = signal_name (signum);
- if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
- {
- list = list->next;
- continue;
- }
-#if defined (JOB_CONTROL)
- /* POSIX.2 says that `kill -l signum' prints the signal name without
- the `SIG' prefix. */
- printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
-#else
- printf ("%s\n", name);
-#endif
- }
- else
- {
- dflags = DSIG_NOCASE;
- if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
- dflags |= DSIG_SIGPREFIX;
- signum = decode_signal (list->word->word, dflags);
- if (signum == NO_SIG)
- {
- sh_invalidsig (list->word->word);
- result = EXECUTION_FAILURE;
- list = list->next;
- continue;
- }
- printf ("%d\n", signum);
- }
- list = list->next;
- }
- return (result);
-}
-
-/* **************************************************************** */
-/* */
-/* Finding builtin commands and their functions */
-/* */
-/* **************************************************************** */
-
-/* Perform a binary search and return the address of the builtin function
- whose name is NAME. If the function couldn't be found, or the builtin
- is disabled or has no function associated with it, return NULL.
- Return the address of the builtin.
- DISABLED_OKAY means find it even if the builtin is disabled. */
-struct builtin *
-builtin_address_internal (name, disabled_okay)
- char *name;
- int disabled_okay;
-{
- int hi, lo, mid, j;
-
- hi = num_shell_builtins - 1;
- lo = 0;
-
- while (lo <= hi)
- {
- mid = (lo + hi) / 2;
-
- j = shell_builtins[mid].name[0] - name[0];
-
- if (j == 0)
- j = strcmp (shell_builtins[mid].name, name);
-
- if (j == 0)
- {
- /* It must have a function pointer. It must be enabled, or we
- must have explicitly allowed disabled functions to be found,
- and it must not have been deleted. */
- if (shell_builtins[mid].function &&
- ((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
- ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
- return (&shell_builtins[mid]);
- else
- return ((struct builtin *)NULL);
- }
- if (j > 0)
- hi = mid - 1;
- else
- lo = mid + 1;
- }
- return ((struct builtin *)NULL);
-}
-
-/* Return the pointer to the function implementing builtin command NAME. */
-sh_builtin_func_t *
-find_shell_builtin (name)
- char *name;
-{
- current_builtin = builtin_address_internal (name, 0);
- return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
-}
-
-/* Return the address of builtin with NAME, whether it is enabled or not. */
-sh_builtin_func_t *
-builtin_address (name)
- char *name;
-{
- current_builtin = builtin_address_internal (name, 1);
- return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
-}
-
-/* Return the function implementing the builtin NAME, but only if it is a
- POSIX.2 special builtin. */
-sh_builtin_func_t *
-find_special_builtin (name)
- char *name;
-{
- current_builtin = builtin_address_internal (name, 0);
- return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
- current_builtin->function :
- (sh_builtin_func_t *)NULL);
-}
-
-static int
-shell_builtin_compare (sbp1, sbp2)
- struct builtin *sbp1, *sbp2;
-{
- int result;
-
- if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
- result = strcmp (sbp1->name, sbp2->name);
-
- return (result);
-}
-
-/* Sort the table of shell builtins so that the binary search will work
- in find_shell_builtin. */
-void
-initialize_shell_builtins ()
-{
- qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
- (QSFUNC *)shell_builtin_compare);
-}
+++ /dev/null
-This file is setattr.def, from which is created setattr.c.
-It implements the builtins "export" and "readonly", in Bash.
-
-Copyright (C) 1987-2012 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Bash is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Bash. If not, see <http://www.gnu.org/licenses/>.
-
-$PRODUCES setattr.c
-
-#include <config.h>
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include "../bashansi.h"
-#include "../bashintl.h"
-
-#include "../shell.h"
-#include "../flags.h"
-#include "common.h"
-#include "bashgetopt.h"
-
-extern int posixly_correct;
-extern int array_needs_making;
-extern char *this_command_name;
-extern sh_builtin_func_t *this_shell_builtin;
-
-#ifdef ARRAY_VARS
-extern int declare_builtin __P((WORD_LIST *));
-#endif
-
-#define READONLY_OR_EXPORT \
- (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
-
-$BUILTIN export
-$FUNCTION export_builtin
-$SHORT_DOC export [-fn] [name[=value] ...] or export -p
-Set export attribute for shell variables.
-
-Marks each NAME for automatic export to the environment of subsequently
-executed commands. If VALUE is supplied, assign VALUE before exporting.
-
-Options:
- -f refer to shell functions
- -n remove the export property from each NAME
- -p display a list of all exported variables and functions
-
-An argument of `--' disables further option processing.
-
-Exit Status:
-Returns success unless an invalid option is given or NAME is invalid.
-$END
-
-/* For each variable name in LIST, make that variable appear in the
- environment passed to simple commands. If there is no LIST, then
- print all such variables. An argument of `-n' says to remove the
- exported attribute from variables named in LIST. An argument of
- -f indicates that the names present in LIST refer to functions. */
-int
-export_builtin (list)
- register WORD_LIST *list;
-{
- return (set_or_show_attributes (list, att_exported, 0));
-}
-
-$BUILTIN readonly
-$FUNCTION readonly_builtin
-$SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
-Mark shell variables as unchangeable.
-
-Mark each NAME as read-only; the values of these NAMEs may not be
-changed by subsequent assignment. If VALUE is supplied, assign VALUE
-before marking as read-only.
-
-Options:
- -a refer to indexed array variables
- -A refer to associative array variables
- -f refer to shell functions
- -p display a list of all readonly variables or functions, depending on
- whether or not the -f option is given
-
-An argument of `--' disables further option processing.
-
-Exit Status:
-Returns success unless an invalid option is given or NAME is invalid.
-$END
-
-/* For each variable name in LIST, make that variable readonly. Given an
- empty LIST, print out all existing readonly variables. */
-int
-readonly_builtin (list)
- register WORD_LIST *list;
-{
- return (set_or_show_attributes (list, att_readonly, 0));
-}
-
-#if defined (ARRAY_VARS)
-# define ATTROPTS "aAfnp"
-#else
-# define ATTROPTS "fnp"
-#endif
-
-/* For each variable name in LIST, make that variable have the specified
- ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
- remaining names in LIST (doesn't work for readonly). */
-int
-set_or_show_attributes (list, attribute, nodefs)
- register WORD_LIST *list;
- int attribute, nodefs;
-{
- register SHELL_VAR *var;
- int assign, undo, any_failed, assign_error, opt;
- int functions_only, arrays_only, assoc_only;
- int aflags;
- char *name;
-#if defined (ARRAY_VARS)
- WORD_LIST *nlist, *tlist;
- WORD_DESC *w;
-#endif
-
- functions_only = arrays_only = assoc_only = 0;
- undo = any_failed = assign_error = 0;
- /* Read arguments from the front of the list. */
- reset_internal_getopt ();
- while ((opt = internal_getopt (list, ATTROPTS)) != -1)
- {
- switch (opt)
- {
- case 'n':
- undo = 1;
- break;
- case 'f':
- functions_only = 1;
- break;
-#if defined (ARRAY_VARS)
- case 'a':
- arrays_only = 1;
- break;
- case 'A':
- assoc_only = 1;
- break;
-#endif
- case 'p':
- break;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
-
- if (list)
- {
- if (attribute & att_exported)
- array_needs_making = 1;
-
- /* Cannot undo readonly status, silently disallowed. */
- if (undo && (attribute & att_readonly))
- attribute &= ~att_readonly;
-
- while (list)
- {
- name = list->word->word;
-
- if (functions_only) /* xxx -f name */
- {
- var = find_function (name);
- if (var == 0)
- {
- builtin_error (_("%s: not a function"), name);
- any_failed++;
- }
- else if (exportable_function_name (name) == 0)
- {
- builtin_error (_("%s: cannot export"), name);
- any_failed++;
- }
- else
- SETVARATTR (var, attribute, undo);
-
- list = list->next;
- continue;
- }
-
- /* xxx [-np] name[=value] */
- assign = assignment (name, 0);
-
- aflags = 0;
- if (assign)
- {
- name[assign] = '\0';
- if (name[assign - 1] == '+')
- {
- aflags |= ASS_APPEND;
- name[assign - 1] = '\0';
- }
- }
-
- if (legal_identifier (name) == 0)
- {
- sh_invalidid (name);
- if (assign)
- assign_error++;
- else
- any_failed++;
- list = list->next;
- continue;
- }
-
- if (assign) /* xxx [-np] name=value */
- {
- name[assign] = '=';
- if (aflags & ASS_APPEND)
- name[assign - 1] = '+';
-#if defined (ARRAY_VARS)
- /* Let's try something here. Turn readonly -a xxx=yyy into
- declare -ra xxx=yyy and see what that gets us. */
- if (arrays_only || assoc_only)
- {
- tlist = list->next;
- list->next = (WORD_LIST *)NULL;
- w = arrays_only ? make_word ("-ra") : make_word ("-rA");
- nlist = make_word_list (w, list);
- opt = declare_builtin (nlist);
- if (opt != EXECUTION_SUCCESS)
- assign_error++;
- list->next = tlist;
- dispose_word (w);
- free (nlist);
- }
- else
-#endif
- /* This word has already been expanded once with command
- and parameter expansion. Call do_assignment_no_expand (),
- which does not do command or parameter substitution. If
- the assignment is not performed correctly, flag an error. */
- if (do_assignment_no_expand (name) == 0)
- assign_error++;
- name[assign] = '\0';
- if (aflags & ASS_APPEND)
- name[assign - 1] = '\0';
- }
-
- set_var_attribute (name, attribute, undo);
- list = list->next;
- }
- }
- else
- {
- SHELL_VAR **variable_list;
- register int i;
-
- if ((attribute & att_function) || functions_only)
- {
- variable_list = all_shell_functions ();
- if (attribute != att_function)
- attribute &= ~att_function; /* so declare -xf works, for example */
- }
- else
- variable_list = all_shell_variables ();
-
-#if defined (ARRAY_VARS)
- if (attribute & att_array)
- {
- arrays_only++;
- if (attribute != att_array)
- attribute &= ~att_array;
- }
- else if (attribute & att_assoc)
- {
- assoc_only++;
- if (attribute != att_assoc)
- attribute &= ~att_assoc;
- }
-#endif
-
- if (variable_list)
- {
- for (i = 0; var = variable_list[i]; i++)
- {
-#if defined (ARRAY_VARS)
- if (arrays_only && array_p (var) == 0)
- continue;
- else if (assoc_only && assoc_p (var) == 0)
- continue;
-#endif
- if ((var->attributes & attribute))
- {
- show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
- if (any_failed = sh_chkwrite (any_failed))
- break;
- }
- }
- free (variable_list);
- }
- }
-
- return (assign_error ? EX_BADASSIGN
- : ((any_failed == 0) ? EXECUTION_SUCCESS
- : EXECUTION_FAILURE));
-}
-
-/* Show all variable variables (v == 1) or functions (v == 0) with
- attributes. */
-int
-show_all_var_attributes (v, nodefs)
- int v, nodefs;
-{
- SHELL_VAR **variable_list, *var;
- int any_failed;
- register int i;
-
- variable_list = v ? all_shell_variables () : all_shell_functions ();
- if (variable_list == 0)
- return (EXECUTION_SUCCESS);
-
- for (i = any_failed = 0; var = variable_list[i]; i++)
- {
- show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
- if (any_failed = sh_chkwrite (any_failed))
- break;
- }
- free (variable_list);
- return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
-}
-
-/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
- don't show function definitions along with the name. If PATTR is
- non-zero, it indicates we're being called from `export' or `readonly'.
- In POSIX mode, this prints the name of the calling builtin (`export'
- or `readonly') instead of `declare', and doesn't print function defs
- when called by `export' or `readonly'. */
-int
-show_var_attributes (var, pattr, nodefs)
- SHELL_VAR *var;
- int pattr, nodefs;
-{
- char flags[16], *x;
- int i;
-
- i = 0;
-
- /* pattr == 0 means we are called from `declare'. */
- if (pattr == 0 || posixly_correct == 0)
- {
-#if defined (ARRAY_VARS)
- if (array_p (var))
- flags[i++] = 'a';
-
- if (assoc_p (var))
- flags[i++] = 'A';
-#endif
-
- if (function_p (var))
- flags[i++] = 'f';
-
- if (integer_p (var))
- flags[i++] = 'i';
-
- if (nameref_p (var))
- flags[i++] = 'n';
-
- if (readonly_p (var))
- flags[i++] = 'r';
-
- if (trace_p (var))
- flags[i++] = 't';
-
- if (exported_p (var))
- flags[i++] = 'x';
-
- if (capcase_p (var))
- flags[i++] = 'c';
-
- if (lowercase_p (var))
- flags[i++] = 'l';
-
- if (uppercase_p (var))
- flags[i++] = 'u';
- }
- else
- {
-#if defined (ARRAY_VARS)
- if (array_p (var))
- flags[i++] = 'a';
-
- if (assoc_p (var))
- flags[i++] = 'A';
-#endif
-
- if (function_p (var))
- flags[i++] = 'f';
- }
-
- flags[i] = '\0';
-
- /* If we're printing functions with definitions, print the function def
- first, then the attributes, instead of printing output that can't be
- reused as input to recreate the current state. */
- if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
- {
- printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
- nodefs++;
- if (pattr == 0 && i == 1 && flags[0] == 'f')
- return 0; /* don't print `declare -f name' */
- }
-
- if (pattr == 0 || posixly_correct == 0)
- printf ("declare -%s ", i ? flags : "-");
- else if (i)
- printf ("%s -%s ", this_command_name, flags);
- else
- printf ("%s ", this_command_name);
-
-#if defined (ARRAY_VARS)
- if (invisible_p (var) && (array_p (var) || assoc_p (var)))
- printf ("%s\n", var->name);
- else if (array_p (var))
- print_array_assignment (var, 1);
- else if (assoc_p (var))
- print_assoc_assignment (var, 1);
- else
-#endif
- /* force `readonly' and `export' to not print out function definitions
- when in POSIX mode. */
- if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
- printf ("%s\n", var->name);
- else if (function_p (var))
- printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
- else if (invisible_p (var) || var_isset (var) == 0)
- printf ("%s\n", var->name);
- else
- {
- x = sh_double_quote (value_cell (var));
- printf ("%s=%s\n", var->name, x);
- free (x);
- }
- return (0);
-}
-
-int
-show_name_attributes (name, nodefs)
- char *name;
- int nodefs;
-{
- SHELL_VAR *var;
-
-#if 0
- var = find_variable_tempenv (name);
-#else
- var = find_variable_noref (name);
-#endif
-
- if (var /* && invisible_p (var) == 0 */) /* XXX bash-4.4/bash-5.0 */
- {
- show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
- return (0);
- }
- else
- return (1);
-}
-
-int
-show_func_attributes (name, nodefs)
- char *name;
- int nodefs;
-{
- SHELL_VAR *var;
-
- var = find_function (name);
-
- if (var)
- {
- show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
- return (0);
- }
- else
- return (1);
-}
-
-void
-set_var_attribute (name, attribute, undo)
- char *name;
- int attribute, undo;
-{
- SHELL_VAR *var, *tv, *v;
- char *tvalue;
-
- if (undo)
- var = find_variable (name);
- else
- {
- tv = find_tempenv_variable (name);
- /* XXX -- need to handle case where tv is a temp variable in a
- function-scope context, since function_env has been merged into
- the local variables table. */
- if (tv && tempvar_p (tv))
- {
- tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
-
- var = bind_variable (tv->name, tvalue, 0);
- var->attributes |= tv->attributes & ~att_tempvar;
- /* This avoids an error message when propagating a read-only var
- later on. */
- if (var->context == 0 && (attribute & att_readonly))
- {
- /* Don't bother to set the `propagate to the global variables
- table' flag if we've just bound the variable in that table */
- v = find_global_variable (tv->name);
- if (v != var)
- VSETATTR (tv, att_propagate);
- }
- else
- VSETATTR (tv, att_propagate);
- if (var->context != 0)
- VSETATTR (var, att_propagate);
- SETVARATTR (tv, attribute, undo); /* XXX */
-
- stupidly_hack_special_variables (tv->name);
-
- free (tvalue);
- }
- else
- {
- var = find_variable_notempenv (name);
- if (var == 0)
- {
- var = bind_variable (name, (char *)NULL, 0);
- if (no_invisible_vars == 0)
- VSETATTR (var, att_invisible);
- }
- else if (var->context != 0)
- VSETATTR (var, att_propagate);
- }
- }
-
- if (var)
- SETVARATTR (var, attribute, undo);
-
- if (var && (exported_p (var) || (attribute & att_exported)))
- array_needs_making++; /* XXX */
-}
+++ /dev/null
-/* copy_command.c -- copy a COMMAND structure. This is needed
- primarily for making function definitions, but I'm not sure
- that anyone else will need it. */
-
-/* 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/>.
-*/
-
-#include "config.h"
-
-#include "bashtypes.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-
-#include "shell.h"
-
-static PATTERN_LIST *copy_case_clause __P((PATTERN_LIST *));
-static PATTERN_LIST *copy_case_clauses __P((PATTERN_LIST *));
-static FOR_COM *copy_for_command __P((FOR_COM *));
-#if defined (ARITH_FOR_COMMAND)
-static ARITH_FOR_COM *copy_arith_for_command __P((ARITH_FOR_COM *));
-#endif
-static GROUP_COM *copy_group_command __P((GROUP_COM *));
-static SUBSHELL_COM *copy_subshell_command __P((SUBSHELL_COM *));
-static COPROC_COM *copy_coproc_command __P((COPROC_COM *));
-static CASE_COM *copy_case_command __P((CASE_COM *));
-static WHILE_COM *copy_while_command __P((WHILE_COM *));
-static IF_COM *copy_if_command __P((IF_COM *));
-#if defined (DPAREN_ARITHMETIC)
-static ARITH_COM *copy_arith_command __P((ARITH_COM *));
-#endif
-#if defined (COND_COMMAND)
-static COND_COM *copy_cond_command __P((COND_COM *));
-#endif
-static SIMPLE_COM *copy_simple_command __P((SIMPLE_COM *));
-
-WORD_DESC *
-copy_word (w)
- WORD_DESC *w;
-{
- WORD_DESC *new_word;
-
- new_word = make_bare_word (w->word);
- new_word->flags = w->flags;
- return (new_word);
-}
-
-/* Copy the chain of words in LIST. Return a pointer to
- the new chain. */
-WORD_LIST *
-copy_word_list (list)
- WORD_LIST *list;
-{
- WORD_LIST *new_list;
-
- for (new_list = (WORD_LIST *)NULL; list; list = list->next)
- new_list = make_word_list (copy_word (list->word), new_list);
-
- return (REVERSE_LIST (new_list, WORD_LIST *));
-}
-
-static PATTERN_LIST *
-copy_case_clause (clause)
- PATTERN_LIST *clause;
-{
- PATTERN_LIST *new_clause;
-
- new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
- new_clause->patterns = copy_word_list (clause->patterns);
- new_clause->action = copy_command (clause->action);
- new_clause->flags = clause->flags;
- return (new_clause);
-}
-
-static PATTERN_LIST *
-copy_case_clauses (clauses)
- PATTERN_LIST *clauses;
-{
- PATTERN_LIST *new_list, *new_clause;
-
- for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next)
- {
- new_clause = copy_case_clause (clauses);
- new_clause->next = new_list;
- new_list = new_clause;
- }
- return (REVERSE_LIST (new_list, PATTERN_LIST *));
-}
-
-/* Copy a single redirect. */
-REDIRECT *
-copy_redirect (redirect)
- REDIRECT *redirect;
-{
- REDIRECT *new_redirect;
-
- new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT));
-#if 0
- FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT)));
-#else
- *new_redirect = *redirect; /* let the compiler do the fast structure copy */
-#endif
-
- if (redirect->rflags & REDIR_VARASSIGN)
- new_redirect->redirector.filename = copy_word (redirect->redirector.filename);
-
- switch (redirect->instruction)
- {
- case r_reading_until:
- case r_deblank_reading_until:
- if (redirect->here_doc_eof)
- new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
- else
- new_redirect->here_doc_eof = 0;
- /*FALLTHROUGH*/
- case r_reading_string:
- case r_appending_to:
- case r_output_direction:
- case r_input_direction:
- case r_inputa_direction:
- case r_err_and_out:
- case r_append_err_and_out:
- case r_input_output:
- case r_output_force:
- case r_duplicating_input_word:
- case r_duplicating_output_word:
- case r_move_input_word:
- case r_move_output_word:
- new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename);
- break;
- case r_duplicating_input:
- case r_duplicating_output:
- case r_move_input:
- case r_move_output:
- case r_close_this:
- break;
- }
- return (new_redirect);
-}
-
-REDIRECT *
-copy_redirects (list)
- REDIRECT *list;
-{
- REDIRECT *new_list, *temp;
-
- for (new_list = (REDIRECT *)NULL; list; list = list->next)
- {
- temp = copy_redirect (list);
- temp->next = new_list;
- new_list = temp;
- }
- return (REVERSE_LIST (new_list, REDIRECT *));
-}
-
-static FOR_COM *
-copy_for_command (com)
- FOR_COM *com;
-{
- FOR_COM *new_for;
-
- new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM));
- new_for->flags = com->flags;
- new_for->line = com->line;
- new_for->name = copy_word (com->name);
- new_for->map_list = copy_word_list (com->map_list);
- new_for->action = copy_command (com->action);
- return (new_for);
-}
-
-#if defined (ARITH_FOR_COMMAND)
-static ARITH_FOR_COM *
-copy_arith_for_command (com)
- ARITH_FOR_COM *com;
-{
- ARITH_FOR_COM *new_arith_for;
-
- new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
- new_arith_for->flags = com->flags;
- new_arith_for->line = com->line;
- new_arith_for->init = copy_word_list (com->init);
- new_arith_for->test = copy_word_list (com->test);
- new_arith_for->step = copy_word_list (com->step);
- new_arith_for->action = copy_command (com->action);
- return (new_arith_for);
-}
-#endif /* ARITH_FOR_COMMAND */
-
-static GROUP_COM *
-copy_group_command (com)
- GROUP_COM *com;
-{
- GROUP_COM *new_group;
-
- new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
- new_group->command = copy_command (com->command);
- return (new_group);
-}
-
-static SUBSHELL_COM *
-copy_subshell_command (com)
- SUBSHELL_COM *com;
-{
- SUBSHELL_COM *new_subshell;
-
- new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
- new_subshell->command = copy_command (com->command);
- new_subshell->flags = com->flags;
- return (new_subshell);
-}
-
-static COPROC_COM *
-copy_coproc_command (com)
- COPROC_COM *com;
-{
- COPROC_COM *new_coproc;
-
- new_coproc = (COPROC_COM *)xmalloc (sizeof (COPROC_COM));
- new_coproc->name = savestring (com->name);
- new_coproc->command = copy_command (com->command);
- new_coproc->flags = com->flags;
- return (new_coproc);
-}
-
-static CASE_COM *
-copy_case_command (com)
- CASE_COM *com;
-{
- CASE_COM *new_case;
-
- new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM));
- new_case->flags = com->flags;
- new_case->line = com->line;
- new_case->word = copy_word (com->word);
- new_case->clauses = copy_case_clauses (com->clauses);
- return (new_case);
-}
-
-static WHILE_COM *
-copy_while_command (com)
- WHILE_COM *com;
-{
- WHILE_COM *new_while;
-
- new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
- new_while->flags = com->flags;
- new_while->test = copy_command (com->test);
- new_while->action = copy_command (com->action);
- return (new_while);
-}
-
-static IF_COM *
-copy_if_command (com)
- IF_COM *com;
-{
- IF_COM *new_if;
-
- new_if = (IF_COM *)xmalloc (sizeof (IF_COM));
- new_if->flags = com->flags;
- new_if->test = copy_command (com->test);
- new_if->true_case = copy_command (com->true_case);
- new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case;
- return (new_if);
-}
-
-#if defined (DPAREN_ARITHMETIC)
-static ARITH_COM *
-copy_arith_command (com)
- ARITH_COM *com;
-{
- ARITH_COM *new_arith;
-
- new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
- new_arith->flags = com->flags;
- new_arith->exp = copy_word_list (com->exp);
- new_arith->line = com->line;
-
- return (new_arith);
-}
-#endif
-
-#if defined (COND_COMMAND)
-static COND_COM *
-copy_cond_command (com)
- COND_COM *com;
-{
- COND_COM *new_cond;
-
- new_cond = (COND_COM *)xmalloc (sizeof (COND_COM));
- new_cond->flags = com->flags;
- new_cond->line = com->line;
- new_cond->type = com->type;
- new_cond->op = com->op ? copy_word (com->op) : com->op;
- new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL;
- new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL;
-
- return (new_cond);
-}
-#endif
-
-static SIMPLE_COM *
-copy_simple_command (com)
- SIMPLE_COM *com;
-{
- SIMPLE_COM *new_simple;
-
- new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
- new_simple->flags = com->flags;
- new_simple->words = copy_word_list (com->words);
- new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL;
- new_simple->line = com->line;
- return (new_simple);
-}
-
-FUNCTION_DEF *
-copy_function_def_contents (old, new_def)
- FUNCTION_DEF *old, *new_def;
-{
- new_def->name = copy_word (old->name);
- new_def->command = old->command ? copy_command (old->command) : old->command;
- new_def->flags = old->flags;
- new_def->line = old->line;
- new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file;
- return (new_def);
-}
-
-FUNCTION_DEF *
-copy_function_def (com)
- FUNCTION_DEF *com;
-{
- FUNCTION_DEF *new_def;
-
- new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
- new_def = copy_function_def_contents (com, new_def);
- return (new_def);
-}
-
-/* Copy the command structure in COMMAND. Return a pointer to the
- copy. Don't you forget to dispose_command () on this pointer
- later! */
-COMMAND *
-copy_command (command)
- COMMAND *command;
-{
- COMMAND *new_command;
-
- if (command == NULL)
- return (command);
-
- new_command = (COMMAND *)xmalloc (sizeof (COMMAND));
- FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND));
- new_command->flags = command->flags;
- new_command->line = command->line;
-
- if (command->redirects)
- new_command->redirects = copy_redirects (command->redirects);
-
- switch (command->type)
- {
- case cm_for:
- new_command->value.For = copy_for_command (command->value.For);
- break;
-
-#if defined (ARITH_FOR_COMMAND)
- case cm_arith_for:
- new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor);
- break;
-#endif
-
-#if defined (SELECT_COMMAND)
- case cm_select:
- new_command->value.Select =
- (SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select);
- break;
-#endif
-
- case cm_group:
- new_command->value.Group = copy_group_command (command->value.Group);
- break;
-
- case cm_subshell:
- new_command->value.Subshell = copy_subshell_command (command->value.Subshell);
- break;
-
- case cm_coproc:
- new_command->value.Coproc = copy_coproc_command (command->value.Coproc);
- break;
-
- case cm_case:
- new_command->value.Case = copy_case_command (command->value.Case);
- break;
-
- case cm_until:
- case cm_while:
- new_command->value.While = copy_while_command (command->value.While);
- break;
-
- case cm_if:
- new_command->value.If = copy_if_command (command->value.If);
- break;
-
-#if defined (DPAREN_ARITHMETIC)
- case cm_arith:
- new_command->value.Arith = copy_arith_command (command->value.Arith);
- break;
-#endif
-
-#if defined (COND_COMMAND)
- case cm_cond:
- new_command->value.Cond = copy_cond_command (command->value.Cond);
- break;
-#endif
-
- case cm_simple:
- new_command->value.Simple = copy_simple_command (command->value.Simple);
- break;
-
- case cm_connection:
- {
- CONNECTION *new_connection;
-
- new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION));
- new_connection->connector = command->value.Connection->connector;
- new_connection->first = copy_command (command->value.Connection->first);
- new_connection->second = copy_command (command->value.Connection->second);
- new_command->value.Connection = new_connection;
- break;
- }
-
- case cm_function_def:
- new_command->value.Function_def = copy_function_def (command->value.Function_def);
- break;
- }
- return (new_command);
-}
+++ /dev/null
-# This file is a shell script that caches the results of configure
-# tests for CYGWIN32 so they don't need to be done when cross-compiling.
-
-# AC_FUNC_GETPGRP should also define GETPGRP_VOID
-ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'}
-# AC_FUNC_SETVBUF_REVERSED should not define anything else
-ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
-# on CYGWIN32, system calls do not restart
-ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}
-bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'}
-
-# these may be necessary, but they are currently commented out
-#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'}
-ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'}
-ac_cv_sizeof_int=${ac_cv_sizeof_int='4'}
-ac_cv_sizeof_long=${ac_cv_sizeof_long='4'}
-ac_cv_sizeof_double=${ac_cv_sizeof_double='8'}
-
-bash_cv_dup2_broken=${bash_cv_dup2_broken='no'}
-bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'}
-bash_cv_type_rlimit=${bash_cv_type_rlimit='long'}
-bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'}
-bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'}
-bash_cv_sys_siglist=${bash_cv_sys_siglist='no'}
-bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'}
-bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'}
-bash_cv_printf_declared=${bash_cv_printf_declared='yes'}
-bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'}
-bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'}
-bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'}
-bash_cv_job_control_missing=${bash_cv_job_control_missing='present'}
-bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'}
-bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'}
-bash_cv_mail_dir=${bash_cv_mail_dir='unknown'}
-bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'}
-
-bash_cv_type_int32_t=${bash_cv_type_int32_t='int'}
-bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'}
-
-ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'}
-
-# end of cross-build/cygwin32.cache
+++ /dev/null
-This is the Bash FAQ, version 3.24, for Bash version 2.05b.
-
-This document contains a set of frequently-asked questions concerning
-Bash, the GNU Bourne-Again Shell. Bash is a freely-available command
-interpreter with advanced features for both interactive use and shell
-programming.
-
-Another good source of basic information about shells is the collection
-of FAQ articles periodically posted to comp.unix.shell.
-
-Questions and comments concerning this document should be sent to
-chet@po.cwru.edu.
-
-This document is available for anonymous FTP with the URL
-
-ftp://ftp.cwru.edu/pub/bash/FAQ
-
-The Bash home page is http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html
-
-----------
-Contents:
-
-Section A: The Basics
-
-A1) What is it?
-A2) What's the latest version?
-A3) Where can I get it?
-A4) On what machines will bash run?
-A5) Will bash run on operating systems other than Unix?
-A6) How can I build bash with gcc?
-A7) How can I make bash my login shell?
-A8) I just changed my login shell to bash, and now I can't FTP into my
- machine. Why not?
-A9) What's the `POSIX 1003.2 standard'?
-A10) What is the bash `posix mode'?
-
-Section B: The latest version
-
-B1) What's new in version 2.05b?
-B2) Are there any user-visible incompatibilities between bash-2.05b and
- bash-1.14.7?
-
-Section C: Differences from other Unix shells
-
-C1) How does bash differ from sh, the Bourne shell?
-C2) How does bash differ from the Korn shell, version ksh88?
-C3) Which new features in ksh-93 are not in bash, and which are?
-
-Section D: Why does bash do some things differently than other Unix shells?
-
-D1) Why does bash run a different version of `command' than
- `which command' says it will?
-D2) Why doesn't bash treat brace expansions exactly like csh?
-D3) Why doesn't bash have csh variable modifiers?
-D4) How can I make my csh aliases work when I convert to bash?
-D5) How can I pipe standard output and standard error from one command to
- another, like csh does with `|&'?
-D6) Now that I've converted from ksh to bash, are there equivalents to
- ksh features like autoloaded functions and the `whence' command?
-
-Section E: Why does bash do certain things the way it does?
-
-E1) Why is the bash builtin `test' slightly different from /bin/test?
-E2) Why does bash sometimes say `Broken pipe'?
-E3) When I have terminal escape sequences in my prompt, why does bash
- wrap lines at the wrong column?
-E4) If I pipe the output of a command into `read variable', why doesn't
- the output show up in $variable when the read command finishes?
-E5) I have a bunch of shell scripts that use backslash-escaped characters
- in arguments to `echo'. Bash doesn't interpret these characters. Why
- not, and how can I make it understand them?
-E6) Why doesn't a while or for loop get suspended when I type ^Z?
-E7) What about empty for loops in Makefiles?
-E8) Why does the arithmetic evaluation code complain about `08'?
-E9) Why does the pattern matching expression [A-Z]* match files beginning
- with every letter except `z'?
-E10) Why does `cd //' leave $PWD as `//'?
-E11) If I resize my xterm while another program is running, why doesn't bash
- notice the change?
-
-Section F: Things to watch out for on certain Unix versions
-
-F1) Why can't I use command line editing in my `cmdtool'?
-F2) I built bash on Solaris 2. Why do globbing expansions and filename
- completion chop off the first few characters of each filename?
-F3) Why does bash dump core after I interrupt username completion or
- `~user' tilde expansion on a machine running NIS?
-F4) I'm running SVR4.2. Why is the line erased every time I type `@'?
-F5) Why does bash report syntax errors when my C News scripts use a
- redirection before a subshell command?
-F6) Why can't I use vi-mode editing on Red Hat Linux 6.1?
-F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on
- HP/UX 11.x?
-
-Section G: How can I get bash to do certain common things?
-
-G1) How can I get bash to read and display eight-bit characters?
-G2) How do I write a function `x' to replace builtin command `x', but
- still invoke the command from within the function?
-G3) How can I find the value of a shell variable whose name is the value
- of another shell variable?
-G4) How can I make the bash `time' reserved word print timing output that
- looks like the output from my system's /usr/bin/time?
-G5) How do I get the current directory into my prompt?
-G6) How can I rename "*.foo" to "*.bar"?
-G7) How can I translate a filename from uppercase to lowercase?
-G8) How can I write a filename expansion (globbing) pattern that will match
- all files in the current directory except "." and ".."?
-
-Section H: Where do I go from here?
-
-H1) How do I report bugs in bash, and where should I look for fixes and
- advice?
-H2) What kind of bash documentation is there?
-H3) What's coming in future versions?
-H4) What's on the bash `wish list'?
-H5) When will the next release appear?
-
-----------
-Section A: The Basics
-
-A1) What is it?
-
-Bash is a Unix command interpreter (shell). It is an implementation of
-the Posix 1003.2 shell standard, and resembles the Korn and System V
-shells.
-
-Bash contains a number of enhancements over those shells, both
-for interactive use and shell programming. Features geared
-toward interactive use include command line editing, command
-history, job control, aliases, and prompt expansion. Programming
-features include additional variable expansions, shell
-arithmetic, and a number of variables and options to control
-shell behavior.
-
-Bash was originally written by Brian Fox of the Free Software
-Foundation. The current developer and maintainer is Chet Ramey
-of Case Western Reserve University.
-
-A2) What's the latest version?
-
-The latest version is 2.05b, first made available on Wednesday, 17
-July, 2002.
-
-A3) Where can I get it?
-
-Bash is the GNU project's shell, and so is available from the
-master GNU archive site, ftp.gnu.org, and its mirrors. The
-latest version is also available for FTP from ftp.cwru.edu.
-The following URLs tell how to get version 2.05b:
-
-ftp://ftp.gnu.org/pub/gnu/bash/bash-2.05b.tar.gz
-ftp://ftp.cwru.edu/pub/bash/bash-2.05b.tar.gz
-
-Formatted versions of the documentation are available with the URLs:
-
-ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-2.05b.tar.gz
-ftp://ftp.cwru.edu/pub/bash/bash-doc-2.05b.tar.gz
-
-A4) On what machines will bash run?
-
-Bash has been ported to nearly every version of UNIX. All you
-should have to do to build it on a machine for which a port
-exists is to type `configure' and then `make'. The build process
-will attempt to discover the version of UNIX you have and tailor
-itself accordingly, using a script created by GNU autoconf.
-
-More information appears in the file `INSTALL' in the distribution.
-
-The Bash web page (http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html)
-explains how to obtain binary versions of bash for most of the major
-commercial Unix systems.
-
-A5) Will bash run on operating systems other than Unix?
-
-Configuration specifics for Unix-like systems such as QNX and
-LynxOS are included in the distribution. Bash-2.05 and later
-versions should compile and run on Minix 2.0 (patches were
-contributed), but I don't believe anyone has built bash-2.x on
-earlier Minix versions yet.
-
-Bash has been ported to versions of Windows implementing the Win32
-programming interface. This includes Windows 95 and Windows NT.
-The port was done by Cygnus Solutions as part of their CYGWIN
-project. For more information about the project, look at the URLs
-
-http://www.cygwin.com/
-http://sourceware.cygnus.com/cygwin
-
-Cygnus originally ported bash-1.14.7, and that port was part of their
-early GNU-Win32 (the original name) releases. Cygnus has also done a
-port of bash-2.05 to the CYGWIN environment, and it is available as
-part of their current release.
-
-Bash-2.05b should require no local Cygnus changes to build and run under
-CYGWIN.
-
-The Cygnus port works only on Intel machines. There is a port of bash
-(I don't know which version) to the alpha/NT environment available from
-
-ftp://ftp.gnustep.org//pub/win32/bash-alpha-nt-1.01.tar.gz
-
-DJ Delorie has a port of bash-2.x which runs under MS-DOS, as part
-of the DJGPP project. For more information on the project, see
-
-http://www.delorie.com/djgpp/
-
-I have been told that the original DJGPP port was done by Daisuke Aoyama.
-
-Mark Elbrecht <snowball3@bigfoot.com> has sent me notice that bash-2.04
-is available for DJGPP V2. The files are available as:
-
-ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204b.zip binary
-ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204d.zip documentation
-ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh204s.zip source
-
-Mark has begun to work with bash-2.05, but I don't know the status.
-
-Ports of bash-1.12 and bash-2.0 are available for OS/2 from
-
-ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash_112.zip
-ftp://hobbes.nmsu.edu/pub/os2/util/shell/bash-2.0(253).zip
-
-I haven't looked at either, but the second appears to be a binary-only
-distribution. Beware.
-
-I have received word that Bash (I'm not sure which version, but I
-believe that it's at least bash-2.02.1) is the standard shell on
-BeOS.
-
-A6) How can I build bash with gcc?
-
-Bash configures to use gcc by default if it is available. Read the
-file INSTALL in the distribution for more information.
-
-A7) How can I make bash my login shell?
-
-Some machines let you use `chsh' to change your login shell. Other
-systems use `passwd -s' or `passwd -e'. If one of these works for
-you, that's all you need. Note that many systems require the full
-pathname to a shell to appear in /etc/shells before you can make it
-your login shell. For this, you may need the assistance of your
-friendly local system administrator.
-
-If you cannot do this, you can still use bash as your login shell, but
-you need to perform some tricks. The basic idea is to add a command
-to your login shell's startup file to replace your login shell with
-bash.
-
-For example, if your login shell is csh or tcsh, and you have installed
-bash in /usr/gnu/bin/bash, add the following line to ~/.login:
-
- if ( -f /usr/gnu/bin/bash ) exec /usr/gnu/bin/bash --login
-
-(the `--login' tells bash that it is a login shell).
-
-It's not a good idea to put this command into ~/.cshrc, because every
-csh you run without the `-f' option, even ones started to run csh scripts,
-reads that file. If you must put the command in ~/.cshrc, use something
-like
-
- if ( $?prompt ) exec /usr/gnu/bin/bash --login
-
-to ensure that bash is exec'd only when the csh is interactive.
-
-If your login shell is sh or ksh, you have to do two things.
-
-First, create an empty file in your home directory named `.bash_profile'.
-The existence of this file will prevent the exec'd bash from trying to
-read ~/.profile, and re-execing itself over and over again. ~/.bash_profile
-is the first file bash tries to read initialization commands from when
-it is invoked as a login shell.
-
-Next, add a line similar to the above to ~/.profile:
-
- [ -f /usr/gnu/bin/bash ] && [ -x /usr/gnu/bin/bash ] && \
- exec /usr/gnu/bin/bash --login
-
-This will cause login shells to replace themselves with bash running as
-a login shell. Once you have this working, you can copy your initialization
-code from ~/.profile to ~/.bash_profile.
-
-I have received word that the recipe supplied above is insufficient for
-machines running CDE. CDE has a maze of twisty little startup files, all
-slightly different.
-
-If you cannot change your login shell in the password file to bash, you
-will have to (apparently) live with CDE using the shell in the password
-file to run its startup scripts. If you have changed your shell to bash,
-there is code in the CDE startup files (on Solaris, at least) that attempts
-to do the right thing. It is, however, often broken, and may require that
-you use the $BASH_ENV trick described below.
-
-`dtterm' claims to use $SHELL as the default program to start, so if you
-can change $SHELL in the CDE startup files, you should be able to use bash
-in your terminal windows.
-
-Setting DTSOURCEPROFILE in ~/.dtprofile will cause the `Xsession' program
-to read your login shell's startup files. You may be able to use bash for
-the rest of the CDE programs by setting SHELL to bash in ~/.dtprofile as
-well, but I have not tried this.
-
-You can use the above `exec' recipe to start bash when not logging in with
-CDE by testing the value of the DT variable:
-
- if [ -n "$DT" ]; then
- [ -f /usr/gnu/bin/bash ] && exec /usr/gnu/bin/bash --login
- fi
-
-If CDE starts its shells non-interactively during login, the login shell
-startup files (~/.profile, ~/.bash_profile) will not be sourced at login.
-To get around this problem, append a line similar to the following to your
-~/.dtprofile:
-
- BASH_ENV=${HOME}/.bash_profile ; export BASH_ENV
-
-and add the following line to the beginning of ~/.bash_profile:
-
- unset BASH_ENV
-
-A8) I just changed my login shell to bash, and now I can't FTP into my
- machine. Why not?
-
-You must add the full pathname to bash to the file /etc/shells. As
-noted in the answer to the previous question, many systems require
-this before you can make bash your login shell.
-
-Most versions of ftpd use this file to prohibit `special' users
-such as `uucp' and `news' from using FTP.
-
-A9) What's the `POSIX 1003.2 standard'?
-
-POSIX is a name originally coined by Richard Stallman for a
-family of open system standards based on UNIX. There are a
-number of aspects of UNIX under consideration for
-standardization, from the basic system services at the system
-call and C library level to applications and tools to system
-administration and management. Each area of standardization is
-assigned to a working group in the 1003 series.
-
-The POSIX Shell and Utilities standard has been developed by IEEE
-Working Group 1003.2 (POSIX.2). It concentrates on the command
-interpreter interface and utility programs commonly executed from
-the command line or by other programs. An initial version of the
-standard has been approved and published by the IEEE, and work is
-currently underway to update it.
-
-Bash is concerned with the aspects of the shell's behavior
-defined by POSIX.2. The shell command language has of course
-been standardized, including the basic flow control and program
-execution constructs, I/O redirection and pipelining, argument
-handling, variable expansion, and quoting.
-
-The `special' builtins, which must be implemented as part of the
-shell to provide the desired functionality, are specified as
-being part of the shell; examples of these are `eval' and
-`export'. Other utilities appear in the sections of POSIX.2 not
-devoted to the shell which are commonly (and in some cases must
-be) implemented as builtin commands, such as `read' and `test'.
-POSIX.2 also specifies aspects of the shell's interactive
-behavior as part of the UPE, including job control and command
-line editing. Only vi-style line editing commands have been
-standardized; emacs editing commands were left out due to
-objections.
-
-The Open Group has made an older version of its Single Unix
-Specification (version 2), which is very similar to POSIX.2,
-available on the web at
-
-http://www.opengroup.org/onlinepubs/007908799/
-
-The Single Unix Specification, version 3, is available on the web at
-
-http://www.opengroup.org/onlinepubs/007904975/
-
-A10) What is the bash `posix mode'?
-
-Although bash is an implementation of the POSIX.2 shell
-specification, there are areas where the bash default behavior
-differs from that spec. The bash `posix mode' changes the bash
-behavior in these areas so that it obeys the spec more closely.
-
-Posix mode is entered by starting bash with the --posix or
-'-o posix' option or executing `set -o posix' after bash is running.
-
-The specific aspects of bash which change when posix mode is
-active are listed in the file POSIX in the bash distribution.
-They are also listed in a section in the Bash Reference Manual
-(from which that file is generated).
-
-Section B: The latest version
-
-B1) What's new in version 2.05b?
-
-The raison d'etre for bash-2.05b is to make a second intermediate
-release containing the first of the new features to be available
-in bash-3.0 and get feedback on those features before proceeding.
-The major new feature is multibyte character support in both Bash
-and Readline.
-
-Bash-2.05b contains the following new features (see the manual page for
-complete descriptions and the CHANGES and NEWS files in the bash-2.05b
-distribution):
-
-o support for multibyte characters has been added to both bash and readline
-
-o the DEBUG trap is now run *before* simple commands, ((...)) commands,
- [[...]] conditional commands, and for ((...)) loops
-
-o the shell now performs arithmetic in the largest integer size the machine
- supports (intmax_t)
-
-o there is a new \D{...} prompt expansion; passes the `...' to strftime(3)
- and inserts the result into the expanded prompt
-
-o there is a new `here-string' redirection operator: <<< word
-
-o when displaying variables, function attributes and definitions are shown
- separately, allowing them to be re-used as input (attempting to re-use
- the old output would result in syntax errors).
-
-o `read' has a new `-u fd' option to read from a specified file descriptor
-
-o the bash debugger in examples/bashdb has been modified to work with the
- new DEBUG trap semantics, the command set has been made more gdb-like,
- and the changes to $LINENO make debugging functions work better
-
-o the expansion of $LINENO inside a shell function is only relative to the
- function start if the shell is interactive -- if the shell is running a
- script, $LINENO expands to the line number in the script. This is as
- POSIX-2001 requires
-
-
-A short feature history dating from Bash-2.0:
-
-Bash-2.05a introduced the following new features:
-
-o The `printf' builtin has undergone major work
-
-o There is a new read-only `shopt' option: login_shell, which is set by
- login shells and unset otherwise
-
-o New `\A' prompt string escape sequence; expanding to time in 24-hour
- HH:MM format
-
-o New `-A group/-g' option to complete and compgen; goes group name
- completion
-
-o New [+-]O invocation option to set and unset `shopt' options at startup
-
-o ksh-like `ERR' trap
-
-o `for' loops now allow empty word lists after the `in' reserved word
-
-o new `hard' and `soft' arguments for the `ulimit' builtin
-
-o Readline can be configured to place the user at the same point on the line
- when retrieving commands from the history list
-
-o Readline can be configured to skip `hidden' files (filenames with a leading
- `.' on Unix) when performing completion
-
-Bash-2.05 introduced the following new features:
-
-o This version has once again reverted to using locales and strcoll(3) when
- processing pattern matching bracket expressions, as POSIX requires.
-o Added a new `--init-file' invocation argument as a synonym for `--rcfile',
- per the new GNU coding standards.
-o The /dev/tcp and /dev/udp redirections now accept service names as well as
- port numbers.
-o `complete' and `compgen' now take a `-o value' option, which controls some
- of the aspects of that compspec. Valid values are:
-
- default - perform bash default completion if programmable
- completion produces no matches
- dirnames - perform directory name completion if programmable
- completion produces no matches
- filenames - tell readline that the compspec produces filenames,
- so it can do things like append slashes to
- directory names and suppress trailing spaces
-o A new loadable builtin, realpath, which canonicalizes and expands symlinks
- in pathname arguments.
-o When `set' is called without options, it prints function defintions in a
- way that allows them to be reused as input. This affects `declare' and
- `declare -p' as well. This only happens when the shell is not in POSIX
- mode, since POSIX.2 forbids this behavior.
-
-Bash-2.04 introduced the following new features:
-
-o Programmable word completion with the new `complete' and `compgen' builtins;
- examples are provided in examples/complete/complete-examples
-o `history' has a new `-d' option to delete a history entry
-o `bind' has a new `-x' option to bind key sequences to shell commands
-o The prompt expansion code has new `\j' and `\l' escape sequences
-o The `no_empty_cmd_completion' shell option, if enabled, inhibits
- command completion when TAB is typed on an empty line
-o `help' has a new `-s' option to print a usage synopsis
-o New arithmetic operators: var++, var--, ++var, --var, expr1,expr2 (comma)
-o New ksh93-style arithmetic for command:
- for ((expr1 ; expr2; expr3 )); do list; done
-o `read' has new options: `-t', `-n', `-d', `-s'
-o The redirection code handles several filenames specially: /dev/fd/N,
- /dev/stdin, /dev/stdout, /dev/stderr
-o The redirection code now recognizes /dev/tcp/HOST/PORT and
- /dev/udp/HOST/PORT and tries to open a TCP or UDP socket, respectively,
- to the specified port on the specified host
-o The ${!prefix*} expansion has been implemented
-o A new FUNCNAME variable, which expands to the name of a currently-executing
- function
-o The GROUPS variable is no longer readonly
-o A new shopt `xpg_echo' variable, to control the behavior of echo with
- respect to backslash-escape sequences at runtime
-o The NON_INTERACTIVE_LOGIN_SHELLS #define has returned
-
-The version of Readline released with Bash-2.04, Readline-4.1, had several
-new features as well:
-
-o Parentheses matching is always compiled into readline, and controllable
- with the new `blink-matching-paren' variable
-o The history-search-forward and history-search-backward functions now leave
- point at the end of the line when the search string is empty, like
- reverse-search-history, and forward-search-history
-o A new function for applications: rl_on_new_line_with_prompt()
-o New variables for applications: rl_already_prompted, and rl_gnu_readline_p
-
-
-Bash-2.03 had very few new features, in keeping with the convention
-that odd-numbered releases provide mainly bug fixes. A number of new
-features were added to Readline, mostly at the request of the Cygnus
-folks.
-
-A new shopt option, `restricted_shell', so that startup files can test
- whether or not the shell was started in restricted mode
-Filename generation is now performed on the words between ( and ) in
- compound array assignments (this is really a bug fix)
-OLDPWD is now auto-exported, as POSIX.2 requires
-ENV and BASH_ENV are read-only variables in a restricted shell
-Bash may now be linked against an already-installed Readline library,
- as long as the Readline library is version 4 or newer
-All shells begun with the `--login' option will source the login shell
- startup files, even if the shell is not interactive
-
-There were lots of changes to the version of the Readline library released
-along with Bash-2.03. For a complete list of the changes, read the file
-CHANGES in the Bash-2.03 distribution.
-
-Bash-2.02 contained the following new features:
-
-a new version of malloc (based on the old GNU malloc code in previous
- bash versions) that is more page-oriented, more conservative
- with memory usage, does not `orphan' large blocks when they
- are freed, is usable on 64-bit machines, and has allocation
- checking turned on unconditionally
-POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.)
-POSIX.2-style globbing equivalence classes
-POSIX.2-style globbing collating symbols
-the ksh [[...]] extended conditional command
-the ksh egrep-style extended pattern matching operators
-a new `printf' builtin
-the ksh-like $(<filename) command substitution, which is equivalent to
- $(cat filename)
-new tilde prefixes that expand to directories from the directory stack
-new `**' arithmetic operator to do exponentiation
-case-insensitive globbing (filename expansion)
-menu completion a la tcsh
-`magic-space' history expansion function like tcsh
-the readline inputrc `language' has a new file inclusion directive ($include)
-
-Bash-2.01 contained only a few new features:
-
-new `GROUPS' builtin array variable containing the user's group list
-new bindable readline commands: history-and-alias-expand-line and
- alias-expand-line
-
-Bash-2.0 contained extensive changes and new features from bash-1.14.7.
-Here's a short list:
-
-new `time' reserved word to time pipelines, shell builtins, and
- shell functions
-one-dimensional arrays with a new compound assignment statement,
- appropriate expansion constructs and modifications to some
- of the builtins (read, declare, etc.) to use them
-new quoting syntaxes for ANSI-C string expansion and locale-specific
- string translation
-new expansions to do substring extraction, pattern replacement, and
- indirect variable expansion
-new builtins: `disown' and `shopt'
-new variables: HISTIGNORE, SHELLOPTS, PIPESTATUS, DIRSTACK, GLOBIGNORE,
- MACHTYPE, BASH_VERSINFO
-special handling of many unused or redundant variables removed
- (e.g., $notify, $glob_dot_filenames, $no_exit_on_failed_exec)
-dynamic loading of new builtin commands; many loadable examples provided
-new prompt expansions: \a, \e, \n, \H, \T, \@, \v, \V
-history and aliases available in shell scripts
-new readline variables: enable-keypad, mark-directories, input-meta,
- visible-stats, disable-completion, comment-begin
-new readline commands to manipulate the mark and operate on the region
-new readline emacs mode commands and bindings for ksh-88 compatibility
-updated and extended builtins
-new DEBUG trap
-expanded (and now documented) restricted shell mode
-
-implementation stuff:
-autoconf-based configuration
-nearly all of the bugs reported since version 1.14 have been fixed
-most builtins converted to use builtin `getopt' for consistency
-most builtins use -p option to display output in a reusable form
- (for consistency)
-grammar tighter and smaller (66 reduce-reduce conflicts gone)
-lots of code now smaller and faster
-test suite greatly expanded
-
-B2) Are there any user-visible incompatibilities between bash-2.05b and
- bash-1.14.7?
-
-There are a few incompatibilities between version 1.14.7 and version 2.05b.
-They are detailed in the file COMPAT in the bash distribution. That file
-is not meant to be all-encompassing; send mail to bash-maintainers@gnu.org
-if if you find something that's not mentioned there.
-
-Section C: Differences from other Unix shells
-
-C1) How does bash differ from sh, the Bourne shell?
-
-This is a non-comprehensive list of features that differentiate bash
-from the SVR4.2 shell. The bash manual page explains these more
-completely.
-
-Things bash has that sh does not:
- long invocation options
- [+-]O invocation option
- -l invocation option
- `!' reserved word to invert pipeline return value
- `time' reserved word to time pipelines and shell builtins
- the `function' reserved word
- the `select' compound command and reserved word
- arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done
- new $'...' and $"..." quoting
- the $(...) form of command substitution
- the $(<filename) form of command substitution, equivalent to
- $(cat filename)
- the ${#param} parameter value length operator
- the ${!param} indirect parameter expansion operator
- the ${!param*} prefix expansion operator
- the ${param:offset[:length]} parameter substring operator
- the ${param/pat[/string]} parameter pattern substitution operator
- expansions to perform substring removal (${p%[%]w}, ${p#[#]w})
- expansion of positional parameters beyond $9 with ${num}
- variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, REPLY,
- TIMEFORMAT, PPID, PWD, OLDPWD, SHLVL, RANDOM, SECONDS,
- LINENO, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE, HOSTNAME,
- ENV, PS3, PS4, DIRSTACK, PIPESTATUS, HISTSIZE, HISTFILE,
- HISTFILESIZE, HISTCONTROL, HISTIGNORE, GLOBIGNORE, GROUPS,
- PROMPT_COMMAND, FCEDIT, FIGNORE, IGNOREEOF, INPUTRC,
- SHELLOPTS, OPTERR, HOSTFILE, TMOUT, FUNCNAME, histchars,
- auto_resume
- DEBUG trap
- ERR trap
- variable arrays with new compound assignment syntax
- redirections: <>, &>, >|, <<<, [n]<&word-, [n]>&word-
- prompt string special char translation and variable expansion
- auto-export of variables in initial environment
- command search finds functions before builtins
- bash return builtin will exit a file sourced with `.'
- builtins: cd -/-L/-P, exec -l/-c/-a, echo -e/-E, hash -d/-l/-p/-t.
- export -n/-f/-p/name=value, pwd -L/-P,
- read -e/-p/-a/-t/-n/-d/-s/-u,
- readonly -a/-f/name=value, trap -l, set +o,
- set -b/-m/-o option/-h/-p/-B/-C/-H/-P,
- unset -f/-v, ulimit -m/-p/-u,
- type -a/-p/-t/-f/-P, suspend -f, kill -n,
- test -o optname/s1 == s2/s1 < s2/s1 > s2/-nt/-ot/-ef/-O/-G/-S
- bash reads ~/.bashrc for interactive shells, $ENV for non-interactive
- bash restricted shell mode is more extensive
- bash allows functions and variables with the same name
- brace expansion
- tilde expansion
- arithmetic expansion with $((...)) and `let' builtin
- the `[[...]]' extended conditional command
- process substitution
- aliases and alias/unalias builtins
- local variables in functions and `local' builtin
- readline and command-line editing with programmable completion
- command history and history/fc builtins
- csh-like history expansion
- other new bash builtins: bind, command, compgen, complete, builtin,
- declare/typeset, dirs, enable, fc, help,
- history, logout, popd, pushd, disown, shopt,
- printf
- exported functions
- filename generation when using output redirection (command >a*)
- POSIX.2-style globbing character classes
- POSIX.2-style globbing equivalence classes
- POSIX.2-style globbing collating symbols
- egrep-like extended pattern matching operators
- case-insensitive pattern matching and globbing
- variable assignments preceding commands affect only that command,
- even for builtins and functions
- posix mode
- redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr,
- /dev/tcp/host/port, /dev/udp/host/port
-
-Things sh has that bash does not:
- uses variable SHACCT to do shell accounting
- includes `stop' builtin (bash can use alias stop='kill -s STOP')
- `newgrp' builtin
- turns on job control if called as `jsh'
- $TIMEOUT (like bash $TMOUT)
- `^' is a synonym for `|'
- new SVR4.2 sh builtins: mldmode, priv
-
-Implementation differences:
- redirection to/from compound commands causes sh to create a subshell
- bash does not allow unbalanced quotes; sh silently inserts them at EOF
- bash does not mess with signal 11
- sh sets (euid, egid) to (uid, gid) if -p not supplied and uid < 100
- bash splits only the results of expansions on IFS, using POSIX.2
- field splitting rules; sh splits all words on IFS
- sh does not allow MAILCHECK to be unset (?)
- sh does not allow traps on SIGALRM or SIGCHLD
- bash allows multiple option arguments when invoked (e.g. -x -v);
- sh allows only a single option argument (`sh -x -v' attempts
- to open a file named `-v', and, on SunOS 4.1.4, dumps core.
- On Solaris 2.4 and earlier versions, sh goes into an infinite
- loop.)
- sh exits a script if any builtin fails; bash exits only if one of
- the POSIX.2 `special' builtins fails
-
-C2) How does bash differ from the Korn shell, version ksh88?
-
-Things bash has or uses that ksh88 does not:
- long invocation options
- [-+]O invocation option
- -l invocation option
- `!' reserved word
- arithmetic for command: for ((expr1 ; expr2; expr3 )); do list; done
- arithmetic in largest machine-supported size (intmax_t)
- posix mode and posix conformance
- command hashing
- tilde expansion for assignment statements that look like $PATH
- process substitution with named pipes if /dev/fd is not available
- the ${!param} indirect parameter expansion operator
- the ${!param*} prefix expansion operator
- the ${param:offset[:length]} parameter substring operator
- the ${param/pat[/string]} parameter pattern substitution operator
- variables: BASH, BASH_VERSION, BASH_VERSINFO, UID, EUID, SHLVL,
- TIMEFORMAT, HISTCMD, HOSTTYPE, OSTYPE, MACHTYPE,
- HISTFILESIZE, HISTIGNORE, HISTCONTROL, PROMPT_COMMAND,
- IGNOREEOF, FIGNORE, INPUTRC, HOSTFILE, DIRSTACK,
- PIPESTATUS, HOSTNAME, OPTERR, SHELLOPTS, GLOBIGNORE,
- GROUPS, FUNCNAME, histchars, auto_resume
- prompt expansion with backslash escapes and command substitution
- redirection: &> (stdout and stderr), <<<, [n]<&word-, [n]>&word-
- more extensive and extensible editing and programmable completion
- builtins: bind, builtin, command, declare, dirs, echo -e/-E, enable,
- exec -l/-c/-a, fc -s, export -n/-f/-p, hash, help, history,
- jobs -x/-r/-s, kill -s/-n/-l, local, logout, popd, pushd,
- read -e/-p/-a/-t/-n/-d/-s, readonly -a/-n/-f/-p,
- set -o braceexpand/-o histexpand/-o interactive-comments/
- -o notify/-o physical/-o posix/-o hashall/-o onecmd/
- -h/-B/-C/-b/-H/-P, set +o, suspend, trap -l, type,
- typeset -a/-F/-p, ulimit -u, umask -S, alias -p, shopt,
- disown, printf, complete, compgen
- `!' csh-style history expansion
- POSIX.2-style globbing character classes
- POSIX.2-style globbing equivalence classes
- POSIX.2-style globbing collating symbols
- egrep-like extended pattern matching operators
- case-insensitive pattern matching and globbing
- `**' arithmetic operator to do exponentiation
- redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr
- arrays of unlimited size
- TMOUT is default timeout for `read' and `select'
-
-Things ksh88 has or uses that bash does not:
- tracked aliases (alias -t)
- variables: ERRNO, FPATH, EDITOR, VISUAL
- co-processes (|&, >&p, <&p)
- weirdly-scoped functions
- typeset +f to list all function names without definitions
- text of command history kept in a file, not memory
- builtins: alias -x, cd old new, fc -e -, newgrp, print,
- read -p/-s/var?prompt, set -A/-o gmacs/
- -o bgnice/-o markdirs/-o nolog/-o trackall/-o viraw/-s,
- typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-l/-u/-t, whence
- using environment to pass attributes of exported variables
- arithmetic evaluation done on arguments to some builtins
- reads .profile from $PWD when invoked as login shell
-
-Implementation differences:
- ksh runs last command of a pipeline in parent shell context
- bash has brace expansion by default (ksh88 compile-time option)
- bash has fixed startup file for all interactive shells; ksh reads $ENV
- bash has exported functions
- bash command search finds functions before builtins
- bash waits for all commands in pipeline to exit before returning status
- emacs-mode editing has some slightly different key bindings
-
-C3) Which new features in ksh-93 are not in bash, and which are?
-
-New things in ksh-93 not in bash-2.05b:
- associative arrays
- floating point arithmetic and variables
- math library functions
- ${!name[sub]} name of subscript for associative array
- `.' is allowed in variable names to create a hierarchical namespace
- more extensive compound assignment syntax
- discipline functions
- `sleep' and `getconf' builtins (bash has loadable versions)
- typeset -n and `nameref' variables
- KEYBD trap
- variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, .sh.version,
- .sh.name, .sh.subscript, .sh.value, .sh.match, HISTEDIT
- backreferences in pattern matching (\N)
- `&' operator in pattern lists for matching
- print -f (bash uses printf)
- `fc' has been renamed to `hist'
- `.' can execute shell functions
- exit statuses between 0 and 255
- set -o pipefail
- `+=' variable assignment operator
- FPATH and PATH mixing
- getopts -a
- -I invocation option
- DEBUG trap now executed before each simple command, instead of after
- printf %H, %P, %T, %Z modifiers, output base for %d
- lexical scoping for local variables in `ksh' functions
- no scoping for local variables in `POSIX' functions
-
-New things in ksh-93 present in bash-2.05b:
- [n]<&word- and [n]>&word- redirections (combination dup and close)
- for (( expr1; expr2; expr3 )) ; do list; done - arithmetic for command
- ?:, ++, --, `expr1 , expr2' arithmetic operators
- expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]},
- ${!param*}
- compound array assignment
- the `!' reserved word
- loadable builtins -- but ksh uses `builtin' while bash uses `enable'
- `command', `builtin', `disown' builtins
- new $'...' and $"..." quoting
- FIGNORE (but bash uses GLOBIGNORE), HISTCMD
- set -o notify/-C
- changes to kill builtin
- read -A (bash uses read -a)
- read -t/-d
- trap -p
- exec -c/-a
- `.' restores the positional parameters when it completes
- POSIX.2 `test'
- umask -S
- unalias -a
- command and arithmetic substitution performed on PS1, PS4, and ENV
- command name completion
- ENV processed only for interactive shells
-
-Section D: Why does bash do some things differently than other Unix shells?
-
-D1) Why does bash run a different version of `command' than
- `which command' says it will?
-
-On many systems, `which' is actually a csh script that assumes
-you're running csh. In tcsh, `which' and its cousin `where'
-are builtins. On other Unix systems, `which' is a perl script
-that uses the PATH environment variable.
-
-The csh script version reads the csh startup files from your
-home directory and uses those to determine which `command' will
-be invoked. Since bash doesn't use any of those startup files,
-there's a good chance that your bash environment differs from
-your csh environment. The bash `type' builtin does everything
-`which' does, and will report correct results for the running
-shell. If you're really wedded to the name `which', try adding
-the following function definition to your .bashrc:
-
- which()
- {
- builtin type "$@"
- }
-
-If you're moving from tcsh and would like to bring `where' along
-as well, use this function:
-
- where()
- {
- builtin type -a "$@"
- }
-
-D2) Why doesn't bash treat brace expansions exactly like csh?
-
-The only difference between bash and csh brace expansion is that
-bash requires a brace expression to contain at least one unquoted
-comma if it is to be expanded. Any brace-surrounded word not
-containing an unquoted comma is left unchanged by the brace
-expansion code. This affords the greatest degree of sh
-compatibility.
-
-Bash, ksh, zsh, and pd-ksh all implement brace expansion this way.
-
-D3) Why doesn't bash have csh variable modifiers?
-
-Posix has specified a more powerful, albeit somewhat more cryptic,
-mechanism cribbed from ksh, and bash implements it.
-
-${parameter%word}
- Remove smallest suffix pattern. The WORD is expanded to produce
- a pattern. It then expands to the value of PARAMETER, with the
- smallest portion of the suffix matched by the pattern deleted.
-
- x=file.c
- echo ${x%.c}.o
- -->file.o
-
-${parameter%%word}
-
- Remove largest suffix pattern. The WORD is expanded to produce
- a pattern. It then expands to the value of PARAMETER, with the
- largest portion of the suffix matched by the pattern deleted.
-
- x=posix/src/std
- echo ${x%%/*}
- -->posix
-
-${parameter#word}
- Remove smallest prefix pattern. The WORD is expanded to produce
- a pattern. It then expands to the value of PARAMETER, with the
- smallest portion of the prefix matched by the pattern deleted.
-
- x=$HOME/src/cmd
- echo ${x#$HOME}
- -->/src/cmd
-
-${parameter##word}
- Remove largest prefix pattern. The WORD is expanded to produce
- a pattern. It then expands to the value of PARAMETER, with the
- largest portion of the prefix matched by the pattern deleted.
-
- x=/one/two/three
- echo ${x##*/}
- -->three
-
-
-Given
- a=/a/b/c/d
- b=b.xxx
-
- csh bash result
- --- ---- ------
- $a:h ${a%/*} /a/b/c
- $a:t ${a##*/} d
- $b:r ${b%.*} b
- $b:e ${b##*.} xxx
-
-
-D4) How can I make my csh aliases work when I convert to bash?
-
-Bash uses a different syntax to support aliases than csh does.
-The details can be found in the documentation. We have provided
-a shell script which does most of the work of conversion for you;
-this script can be found in ./examples/misc/aliasconv.sh. Here is
-how you use it:
-
-Start csh in the normal way for you. (e.g., `csh')
-
-Pipe the output of `alias' through `aliasconv.sh', saving the
-results into `bash_aliases':
-
- alias | bash aliasconv.sh >bash_aliases
-
-Edit `bash_aliases', carefully reading through any created
-functions. You will need to change the names of some csh specific
-variables to the bash equivalents. The script converts $cwd to
-$PWD, $term to $TERM, $home to $HOME, $user to $USER, and $prompt
-to $PS1. You may also have to add quotes to avoid unwanted
-expansion.
-
-For example, the csh alias:
-
- alias cd 'cd \!*; echo $cwd'
-
-is converted to the bash function:
-
- cd () { command cd "$@"; echo $PWD ; }
-
-The only thing that needs to be done is to quote $PWD:
-
- cd () { command cd "$@"; echo "$PWD" ; }
-
-Merge the edited file into your ~/.bashrc.
-
-There is an additional, more ambitious, script in
-examples/misc/cshtobash that attempts to convert your entire csh
-environment to its bash equivalent. This script can be run as
-simply `cshtobash' to convert your normal interactive
-environment, or as `cshtobash ~/.login' to convert your login
-environment.
-
-D5) How can I pipe standard output and standard error from one command to
- another, like csh does with `|&'?
-
-Use
- command 2>&1 | command2
-
-The key is to remember that piping is performed before redirection, so
-file descriptor 1 points to the pipe when it is duplicated onto file
-descriptor 2.
-
-D6) Now that I've converted from ksh to bash, are there equivalents to
- ksh features like autoloaded functions and the `whence' command?
-
-There are features in ksh-88 and ksh-93 that do not have direct bash
-equivalents. Most, however, can be emulated with very little trouble.
-
-ksh-88 feature Bash equivalent
--------------- ---------------
-compiled-in aliases set up aliases in .bashrc; some ksh aliases are
- bash builtins (hash, history, type)
-coprocesses named pipe pairs (one for read, one for write)
-typeset +f declare -F
-cd, print, whence function substitutes in examples/functions/kshenv
-autoloaded functions examples/functions/autoload is the same as typeset -fu
-read var?prompt read -p prompt var
-
-ksh-93 feature Bash equivalent
--------------- ---------------
-sleep, getconf Bash has loadable versions in examples/loadables
-${.sh.version} $BASH_VERSION
-print -f printf
-hist alias hist=fc
-$HISTEDIT $FCEDIT
-
-Section E: How can I get bash to do certain things, and why does bash do
- things the way it does?
-
-E1) Why is the bash builtin `test' slightly different from /bin/test?
-
-The specific example used here is [ ! x -o x ], which is false.
-
-Bash's builtin `test' implements the Posix.2 spec, which can be
-summarized as follows (the wording is due to David Korn):
-
-Here is the set of rules for processing test arguments.
-
- 0 Args: False
- 1 Arg: True iff argument is not null.
- 2 Args: If first arg is !, True iff second argument is null.
- If first argument is unary, then true if unary test is true
- Otherwise error.
- 3 Args: If second argument is a binary operator, do binary test of $1 $3
- If first argument is !, negate two argument test of $2 $3
- If first argument is `(' and third argument is `)', do the
- one-argument test of the second argument.
- Otherwise error.
- 4 Args: If first argument is !, negate three argument test of $2 $3 $4.
- Otherwise unspecified
- 5 or more Args: unspecified. (Historical shells would use their
- current algorithm).
-
-The operators -a and -o are considered binary operators for the purpose
-of the 3 Arg case.
-
-As you can see, the test becomes (not (x or x)), which is false.
-
-E2) Why does bash sometimes say `Broken pipe'?
-
-If a sequence of commands appears in a pipeline, and one of the
-reading commands finishes before the writer has finished, the
-writer receives a SIGPIPE signal. Many other shells special-case
-SIGPIPE as an exit status in the pipeline and do not report it.
-For example, in:
-
- ps -aux | head
-
-`head' can finish before `ps' writes all of its output, and ps
-will try to write on a pipe without a reader. In that case, bash
-will print `Broken pipe' to stderr when ps is killed by a
-SIGPIPE.
-
-You can build a version of bash that will not report SIGPIPE errors
-by uncommenting the definition of DONT_REPORT_SIGPIPE in the file
-config-top.h.
-
-E3) When I have terminal escape sequences in my prompt, why does bash
- wrap lines at the wrong column?
-
-Readline, the line editing library that bash uses, does not know
-that the terminal escape sequences do not take up space on the
-screen. The redisplay code assumes, unless told otherwise, that
-each character in the prompt is a `printable' character that
-takes up one character position on the screen.
-
-You can use the bash prompt expansion facility (see the PROMPTING
-section in the manual page) to tell readline that sequences of
-characters in the prompt strings take up no screen space.
-
-Use the \[ escape to begin a sequence of non-printing characters,
-and the \] escape to signal the end of such a sequence.
-
-E4) If I pipe the output of a command into `read variable', why doesn't
- the output show up in $variable when the read command finishes?
-
-This has to do with the parent-child relationship between Unix
-processes. It affects all commands run in pipelines, not just
-simple calls to `read'. For example, piping a command's output
-into a `while' loop that repeatedly calls `read' will result in
-the same behavior.
-
-Each element of a pipeline runs in a separate process, a child of
-the shell running the pipeline. A subprocess cannot affect its
-parent's environment. When the `read' command sets the variable
-to the input, that variable is set only in the subshell, not the
-parent shell. When the subshell exits, the value of the variable
-is lost.
-
-Many pipelines that end with `read variable' can be converted
-into command substitutions, which will capture the output of
-a specified command. The output can then be assigned to a
-variable:
-
- grep ^gnu /usr/lib/news/active | wc -l | read ngroup
-
-can be converted into
-
- ngroup=$(grep ^gnu /usr/lib/news/active | wc -l)
-
-This does not, unfortunately, work to split the text among
-multiple variables, as read does when given multiple variable
-arguments. If you need to do this, you can either use the
-command substitution above to read the output into a variable
-and chop up the variable using the bash pattern removal
-expansion operators or use some variant of the following
-approach.
-
-Say /usr/local/bin/ipaddr is the following shell script:
-
-#! /bin/sh
-host `hostname` | awk '/address/ {print $NF}'
-
-Instead of using
-
- /usr/local/bin/ipaddr | read A B C D
-
-to break the local machine's IP address into separate octets, use
-
- OIFS="$IFS"
- IFS=.
- set -- $(/usr/local/bin/ipaddr)
- IFS="$OIFS"
- A="$1" B="$2" C="$3" D="$4"
-
-Beware, however, that this will change the shell's positional
-parameters. If you need them, you should save them before doing
-this.
-
-This is the general approach -- in most cases you will not need to
-set $IFS to a different value.
-
-Some other user-supplied alternatives include:
-
-read A B C D << HERE
- $(IFS=.; echo $(/usr/local/bin/ipaddr))
-HERE
-
-and, where process substitution is available,
-
-read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr))
-
-E5) I have a bunch of shell scripts that use backslash-escaped characters
- in arguments to `echo'. Bash doesn't interpret these characters. Why
- not, and how can I make it understand them?
-
-This is the behavior of echo on most Unix System V machines.
-
-The bash builtin `echo' is modeled after the 9th Edition
-Research Unix version of `echo'. It does not interpret
-backslash-escaped characters in its argument strings by default;
-it requires the use of the -e option to enable the
-interpretation. The System V echo provides no way to disable the
-special characters; the bash echo has a -E option to disable
-them.
-
-There is a configuration option that will make bash behave like
-the System V echo and interpret things like `\t' by default. Run
-configure with the --enable-xpg-echo-default option to turn this
-on. Be aware that this will cause some of the tests run when you
-type `make tests' to fail.
-
-There is a shell option, `xpg_echo', settable with `shopt', that will
-change the behavior of echo at runtime. Enabling this option turns
-on expansion of backslash-escape sequences.
-
-E6) Why doesn't a while or for loop get suspended when I type ^Z?
-
-This is a consequence of how job control works on Unix. The only
-thing that can be suspended is the process group. This is a single
-command or pipeline of commands that the shell forks and executes.
-
-When you run a while or for loop, the only thing that the shell forks
-and executes are any commands in the while loop test and commands in
-the loop bodies. These, therefore, are the only things that can be
-suspended when you type ^Z.
-
-If you want to be able to stop the entire loop, you need to put it
-within parentheses, which will force the loop into a subshell that
-may be stopped (and subsequently restarted) as a single unit.
-
-E7) What about empty for loops in Makefiles?
-
-It's fairly common to see constructs like this in automatically-generated
-Makefiles:
-
-SUBDIRS = @SUBDIRS@
-
- ...
-
-subdirs-clean:
- for d in ${SUBDIRS}; do \
- ( cd $$d && ${MAKE} ${MFLAGS} clean ) \
- done
-
-When SUBDIRS is empty, this results in a command like this being passed to
-bash:
-
- for d in ; do
- ( cd $d && ${MAKE} ${MFLAGS} clean )
- done
-
-In versions of bash before bash-2.05a, this was a syntax error. If the
-reserved word `in' was present, a word must follow it before the semicolon
-or newline. The language in the manual page referring to the list of words
-being empty referred to the list after it is expanded. These versions of
-bash required that there be at least one word following the `in' when the
-construct was parsed.
-
-The idiomatic Makefile solution is something like:
-
-SUBDIRS = @SUBDIRS@
-
-subdirs-clean:
- subdirs=$SUBDIRS ; for d in $$subdirs; do \
- ( cd $$d && ${MAKE} ${MFLAGS} clean ) \
- done
-
-The latest drafts of the updated POSIX standard have changed this: the
-word list is no longer required. Bash versions 2.05a and later accept
-the new syntax.
-
-E8) Why does the arithmetic evaluation code complain about `08'?
-
-The bash arithmetic evaluation code (used for `let', $(()), (()), and in
-other places), interprets a leading `0' in numeric constants as denoting
-an octal number, and a leading `0x' as denoting hexadecimal. This is
-in accordance with the POSIX.2 spec, section 2.9.2.1, which states that
-arithmetic constants should be handled as signed long integers as defined
-by the ANSI/ISO C standard.
-
-The POSIX.2 interpretation committee has confirmed this:
-
-http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-173.html
-
-E9) Why does the pattern matching expression [A-Z]* match files beginning
- with every letter except `z'?
-
-Bash-2.03, Bash-2.05 and later versions honor the current locale setting
-when processing ranges within pattern matching bracket expressions ([A-Z]).
-This is what POSIX.2 and SUSv3/XPG6 specify.
-
-The behavior of the matcher in bash-2.05 and later versions depends on the
-current LC_COLLATE setting. Setting this variable to `C' or `POSIX' will
-result in the traditional behavior ([A-Z] matches all uppercase ASCII
-characters). Many other locales, including the en_US locale (the default
-on many US versions of Linux) collate the upper and lower case letters like
-this:
-
- AaBb...Zz
-
-which means that [A-Z] matches every letter except `z'. Others collate like
-
- aAbBcC...zZ
-
-which means that [A-Z] matches every letter except `a'.
-
-The portable way to specify upper case letters is [:upper:] instead of
-A-Z; lower case may be specified as [:lower:] instead of a-z.
-
-Look at the manual pages for setlocale(3), strcoll(3), and, if it is
-present, locale(1). If you have locale(1), you can use it to find
-your current locale information even if you do not have any of the
-LC_ variables set.
-
-My advice is to put
-
- export LC_COLLATE=C
-
-into /etc/profile and inspect any shell scripts run from cron for
-constructs like [A-Z]. This will prevent things like
-
- rm [A-Z]*
-
-from removing every file in the current directory except those beginning
-with `z' and still allow individual users to change the collation order.
-Users may put the above command into their own profiles as well, of course.
-
-E10) Why does `cd //' leave $PWD as `//'?
-
-POSIX.2, in its description of `cd', says that *three* or more leading
-slashes may be replaced with a single slash when canonicalizing the
-current working directory.
-
-This is, I presume, for historical compatibility. Certain versions of
-Unix, and early network file systems, used paths of the form
-//hostname/path to access `path' on server `hostname'.
-
-E11) If I resize my xterm while another program is running, why doesn't bash
- notice the change?
-
-This is another issue that deals with job control.
-
-The kernel maintains a notion of a current terminal process group. Members
-of this process group (processes whose process group ID is equal to the
-current terminal process group ID) receive terminal-generated signals like
-SIGWINCH. (For more details, see the JOB CONTROL section of the bash
-man page.)
-
-If a terminal is resized, the kernel sends SIGWINCH to each member of
-the terminal's current process group (the `foreground' process group).
-
-When bash is running with job control enabled, each pipeline (which may be
-a single command) is run in its own process group, different from bash's
-process group. This foreground process group receives the SIGWINCH; bash
-does not. Bash has no way of knowing that the terminal has been resized.
-
-There is a `checkwinsize' option, settable with the `shopt' builtin, that
-will cause bash to check the window size and adjust its idea of the
-terminal's dimensions each time a process stops or exits and returns control
-of the terminal to bash. Enable it with `shopt -s checkwinsize'.
-
-Section F: Things to watch out for on certain Unix versions
-
-F1) Why can't I use command line editing in my `cmdtool'?
-
-The problem is `cmdtool' and bash fighting over the input. When
-scrolling is enabled in a cmdtool window, cmdtool puts the tty in
-`raw mode' to permit command-line editing using the mouse for
-applications that cannot do it themselves. As a result, bash and
-cmdtool each try to read keyboard input immediately, with neither
-getting enough of it to be useful.
-
-This mode also causes cmdtool to not implement many of the
-terminal functions and control sequences appearing in the
-`sun-cmd' termcap entry. For a more complete explanation, see
-that file examples/suncmd.termcap in the bash distribution.
-
-`xterm' is a better choice, and gets along with bash much more
-smoothly.
-
-If you must use cmdtool, you can use the termcap description in
-examples/suncmd.termcap. Set the TERMCAP variable to the terminal
-description contained in that file, i.e.
-
-TERMCAP='Mu|sun-cmd:am:bs:km:pt:li#34:co#80:cl=^L:ce=\E[K:cd=\E[J:rs=\E[s:'
-
-Then export TERMCAP and start a new cmdtool window from that shell.
-The bash command-line editing should behave better in the new
-cmdtool. If this works, you can put the assignment to TERMCAP
-in your bashrc file.
-
-F2) I built bash on Solaris 2. Why do globbing expansions and filename
- completion chop off the first few characters of each filename?
-
-This is the consequence of building bash on SunOS 5 and linking
-with the libraries in /usr/ucblib, but using the definitions
-and structures from files in /usr/include.
-
-The actual conflict is between the dirent structure in
-/usr/include/dirent.h and the struct returned by the version of
-`readdir' in libucb.a (a 4.3-BSD style `struct direct').
-
-Make sure you've got /usr/ccs/bin ahead of /usr/ucb in your $PATH
-when configuring and building bash. This will ensure that you
-use /usr/ccs/bin/cc or acc instead of /usr/ucb/cc and that you
-link with libc before libucb.
-
-If you have installed the Sun C compiler, you may also need to
-put /usr/ccs/bin and /opt/SUNWspro/bin into your $PATH before
-/usr/ucb.
-
-F3) Why does bash dump core after I interrupt username completion or
- `~user' tilde expansion on a machine running NIS?
-
-This is a famous and long-standing bug in the SunOS YP (sorry, NIS)
-client library, which is part of libc.
-
-The YP library code keeps static state -- a pointer into the data
-returned from the server. When YP initializes itself (setpwent),
-it looks at this pointer and calls free on it if it's non-null.
-So far, so good.
-
-If one of the YP functions is interrupted during getpwent (the
-exact function is interpretwithsave()), and returns NULL, the
-pointer is freed without being reset to NULL, and the function
-returns. The next time getpwent is called, it sees that this
-pointer is non-null, calls free, and the bash free() blows up
-because it's being asked to free freed memory.
-
-The traditional Unix mallocs allow memory to be freed multiple
-times; that's probably why this has never been fixed. You can
-run configure with the `--without-gnu-malloc' option to use
-the C library malloc and avoid the problem.
-
-F4) I'm running SVR4.2. Why is the line erased every time I type `@'?
-
-The `@' character is the default `line kill' character in most
-versions of System V, including SVR4.2. You can change this
-character to whatever you want using `stty'. For example, to
-change the line kill character to control-u, type
-
- stty kill ^U
-
-where the `^' and `U' can be two separate characters.
-
-F5) Why does bash report syntax errors when my C News scripts use a
- redirection before a subshell command?
-
-The actual command in question is something like
-
- < file ( command )
-
-According to the grammar given in the POSIX.2 standard, this construct
-is, in fact, a syntax error. Redirections may only precede `simple
-commands'. A subshell construct such as the above is one of the shell's
-`compound commands'. A redirection may only follow a compound command.
-
-This affects the mechanical transformation of commands that use `cat'
-to pipe a file into a command (a favorite Useless-Use-Of-Cat topic on
-comp.unix.shell). While most commands of the form
-
- cat file | command
-
-can be converted to `< file command', shell control structures such as
-loops and subshells require `command < file'.
-
-The file CWRU/sh-redir-hack in the bash-2.05a distribution is an
-(unofficial) patch to parse.y that will modify the grammar to
-support this construct. It will not apply with `patch'; you must
-modify parse.y by hand. Note that if you apply this, you must
-recompile with -DREDIRECTION_HACK. This introduces a large
-number of reduce/reduce conflicts into the shell grammar.
-
-F6) Why can't I use vi-mode editing on Red Hat Linux 6.1?
-
-The short answer is that Red Hat screwed up.
-
-The long answer is that they shipped an /etc/inputrc that only works
-for emacs mode editing, and then screwed all the vi users by setting
-INPUTRC to /etc/inputrc in /etc/profile.
-
-The short fix is to do one of the following: remove or rename
-/etc/inputrc, set INPUTRC=~/.inputrc in ~/.bashrc (or .bash_profile,
-but make sure you export it if you do), remove the assignment to
-INPUTRC from /etc/profile, add
-
- set keymap emacs
-
-to the beginning of /etc/inputrc, or bracket the key bindings in
-/etc/inputrc with these lines
-
- $if mode=emacs
- [...]
- $endif
-
-F7) Why do bash-2.05a and bash-2.05b fail to compile `printf.def' on
- HP/UX 11.x?
-
-HP/UX's support for long double is imperfect at best.
-
-GCC will support it without problems, but the HP C library functions
-like strtold(3) and printf(3) don't actually work with long doubles.
-HP implemented a `long_double' type as a 4-element array of 32-bit
-ints, and that is what the library functions use. The ANSI C
-`long double' type is a 128-bit floating point scalar.
-
-The easiest fix, until HP fixes things up, is to edit the generated
-config.h and #undef the HAVE_LONG_DOUBLE line. After doing that,
-the compilation should complete successfully.
-
-Section G: How can I get bash to do certain common things?
-
-G1) How can I get bash to read and display eight-bit characters?
-
-This is a process requiring several steps.
-
-First, you must ensure that the `physical' data path is a full eight
-bits. For xterms, for example, the `vt100' resources `eightBitInput'
-and `eightBitOutput' should be set to `true'.
-
-Once you have set up an eight-bit path, you must tell the kernel and
-tty driver to leave the eighth bit of characters alone when processing
-keyboard input. Use `stty' to do this:
-
- stty cs8 -istrip -parenb
-
-For old BSD-style systems, you can use
-
- stty pass8
-
-You may also need
-
- stty even odd
-
-Finally, you need to tell readline that you will be inputting and
-displaying eight-bit characters. You use readline variables to do
-this. These variables can be set in your .inputrc or using the bash
-`bind' builtin. Here's an example using `bind':
-
- bash$ bind 'set convert-meta off'
- bash$ bind 'set meta-flag on'
- bash$ bind 'set output-meta on'
-
-The `set' commands between the single quotes may also be placed
-in ~/.inputrc.
-
-G2) How do I write a function `x' to replace builtin command `x', but
- still invoke the command from within the function?
-
-This is why the `command' and `builtin' builtins exist. The
-`command' builtin executes the command supplied as its first
-argument, skipping over any function defined with that name. The
-`builtin' builtin executes the builtin command given as its first
-argument directly.
-
-For example, to write a function to replace `cd' that writes the
-hostname and current directory to an xterm title bar, use
-something like the following:
-
- cd()
- {
- builtin cd "$@" && xtitle "$HOST: $PWD"
- }
-
-This could also be written using `command' instead of `builtin';
-the version above is marginally more efficient.
-
-G3) How can I find the value of a shell variable whose name is the value
- of another shell variable?
-
-Versions of Bash newer than Bash-2.0 support this directly. You can use
-
- ${!var}
-
-For example, the following sequence of commands will echo `z':
-
- var1=var2
- var2=z
- echo ${!var1}
-
-For sh compatibility, use the `eval' builtin. The important
-thing to remember is that `eval' expands the arguments you give
-it again, so you need to quote the parts of the arguments that
-you want `eval' to act on.
-
-For example, this expression prints the value of the last positional
-parameter:
-
- eval echo \"\$\{$#\}\"
-
-The expansion of the quoted portions of this expression will be
-deferred until `eval' runs, while the `$#' will be expanded
-before `eval' is executed. In versions of bash later than bash-2.0,
-
- echo ${!#}
-
-does the same thing.
-
-This is not the same thing as ksh93 `nameref' variables, though the syntax
-is similar. I may add namerefs in a future bash version.
-
-G4) How can I make the bash `time' reserved word print timing output that
- looks like the output from my system's /usr/bin/time?
-
-The bash command timing code looks for a variable `TIMEFORMAT' and
-uses its value as a format string to decide how to display the
-timing statistics.
-
-The value of TIMEFORMAT is a string with `%' escapes expanded in a
-fashion similar in spirit to printf(3). The manual page explains
-the meanings of the escape sequences in the format string.
-
-If TIMEFORMAT is not set, bash acts as if the following assignment had
-been performed:
-
- TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
-
-The POSIX.2 default time format (used by `time -p command') is
-
- TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S'
-
-The BSD /usr/bin/time format can be emulated with:
-
- TIMEFORMAT=$'\t%1R real\t%1U user\t%1S sys'
-
-The System V /usr/bin/time format can be emulated with:
-
- TIMEFORMAT=$'\nreal\t%1R\nuser\t%1U\nsys\t%1S'
-
-The ksh format can be emulated with:
-
- TIMEFORMAT=$'\nreal\t%2lR\nuser\t%2lU\nsys\t%2lS'
-
-G5) How do I get the current directory into my prompt?
-
-Bash provides a number of backslash-escape sequences which are expanded
-when the prompt string (PS1 or PS2) is displayed. The full list is in
-the manual page.
-
-The \w expansion gives the full pathname of the current directory, with
-a tilde (`~') substituted for the current value of $HOME. The \W
-expansion gives the basename of the current directory. To put the full
-pathname of the current directory into the path without any tilde
-subsitution, use $PWD. Here are some examples:
-
- PS1='\w$ ' # current directory with tilde
- PS1='\W$ ' # basename of current directory
- PS1='$PWD$ ' # full pathname of current directory
-
-The single quotes are important in the final example to prevent $PWD from
-being expanded when the assignment to PS1 is performed.
-
-G6) How can I rename "*.foo" to "*.bar"?
-
-Use the pattern removal functionality described in D3. The following `for'
-loop will do the trick:
-
- for f in *.foo; do
- mv $f ${f%foo}bar
- done
-
-G7) How can I translate a filename from uppercase to lowercase?
-
-The script examples/functions/lowercase, originally written by John DuBois,
-will do the trick. The converse is left as an exercise.
-
-G8) How can I write a filename expansion (globbing) pattern that will match
- all files in the current directory except "." and ".."?
-
-You must have set the `extglob' shell option using `shopt -s extglob' to use
-this:
-
- echo .!(.|) *
-
-A solution that works without extended globbing is given in the Unix Shell
-FAQ, posted periodically to comp.unix.shell.
-
-Section H: Where do I go from here?
-
-H1) How do I report bugs in bash, and where should I look for fixes and
- advice?
-
-Use the `bashbug' script to report bugs. It is built and
-installed at the same time as bash. It provides a standard
-template for reporting a problem and automatically includes
-information about your configuration and build environment.
-
-`bashbug' sends its reports to bug-bash@gnu.org, which
-is a large mailing list gatewayed to the usenet newsgroup gnu.bash.bug.
-
-Bug fixes, answers to questions, and announcements of new releases
-are all posted to gnu.bash.bug. Discussions concerning bash features
-and problems also take place there.
-
-To reach the bash maintainers directly, send mail to
-bash-maintainers@gnu.org.
-
-H2) What kind of bash documentation is there?
-
-First, look in the doc directory in the bash distribution. It should
-contain at least the following files:
-
-bash.1 an extensive, thorough Unix-style manual page
-builtins.1 a manual page covering just bash builtin commands
-bashref.texi a reference manual in GNU tex`info format
-bashref.info an info version of the reference manual
-FAQ this file
-article.ms text of an article written for The Linux Journal
-readline.3 a man page describing readline
-
-Postscript, HTML, and ASCII files created from the above source are
-available in the documentation distribution.
-
-There is additional documentation available for anonymous FTP from host
-ftp.cwru.edu in the `pub/bash' directory.
-
-Cameron Newham and Bill Rosenblatt have written a book on bash, published
-by O'Reilly and Associates. The book is based on Bill Rosenblatt's Korn
-Shell book. The title is ``Learning the Bash Shell'', and the ISBN number
-is 1-56592-147-X. Look for it in fine bookstores near you. This book
-covers bash-1.14, but has an appendix describing some of the new features
-in bash-2.0.
-
-A second edition of this book is available, published in January, 1998.
-The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores
-or on the web.
-
-The GNU Bash Reference Manual has been published as a printed book by
-Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Feb 2003). It covers
-bash-2.0 and is available from most online bookstores (see
-http://www.network-theory.co.uk/bash/manual/ for details). The publisher
-will donate $1 to the Free Software Foundation for each copy sold.
-
-H3) What's coming in future versions?
-
-These are features I hope to include in a future version of bash.
-
-a better bash debugger (a minimally-tested version is included with bash-2.05b)
-associative arrays
-co-processes, but with a new-style syntax that looks like function declaration
-
-H4) What's on the bash `wish list' for future versions?
-
-These are features that may or may not appear in a future version of bash.
-
-breaking some of the shell functionality into embeddable libraries
-a module system like zsh's, using dynamic loading like builtins
-better internationalization using GNU `gettext'
-date-stamped command history
-a bash programmer's guide with a chapter on creating loadable builtins
-a better loadable interface to perl with access to the shell builtins and
- variables (contributions gratefully accepted)
-ksh93-like `nameref' variables
-ksh93-like `+=' variable assignment operator
-ksh93-like `xx.yy' variables (including some of the .sh.* variables) and
- associated disipline functions
-Some of the new ksh93 pattern matching operators, like backreferencing
-
-H5) When will the next release appear?
-
-The next version will appear sometime in 2002. Never make predictions.
-
-
-This document is Copyright 1995-2003 by Chester Ramey.
-
-Permission is hereby granted, without written agreement and
-without license or royalty fees, to use, copy, and distribute
-this document for any purpose, provided that the above copyright
-notice appears in all copies of this document and that the
-contents of this document remain unaltered.
+++ /dev/null
-#
-# Simple makefile for the sample loadable builtins
-#
-# Copyright (C) 1996 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
-
-# Include some boilerplate Gnu makefile definitions.
-prefix = @prefix@
-
-exec_prefix = @exec_prefix@
-bindir = @bindir@
-libdir = @libdir@
-infodir = @infodir@
-includedir = @includedir@
-
-topdir = @top_srcdir@
-BUILD_DIR = @BUILD_DIR@
-srcdir = @srcdir@
-VPATH = .:@srcdir@
-
-@SET_MAKE@
-CC = @CC@
-RM = rm -f
-
-SHELL = @MAKE_SHELL@
-
-host_os = @host_os@
-host_cpu = @host_cpu@
-host_vendor = @host_vendor@
-
-CFLAGS = @CFLAGS@
-LOCAL_CFLAGS = @LOCAL_CFLAGS@
-DEFS = @DEFS@
-LOCAL_DEFS = @LOCAL_DEFS@
-
-CPPFLAGS = @CPPFLAGS@
-
-BASHINCDIR = ${topdir}/include
-
-LIBBUILD = ${BUILD_DIR}/lib
-
-INTL_LIBSRC = ${topdir}/lib/intl
-INTL_BUILDDIR = ${LIBBUILD}/intl
-INTL_INC = @INTL_INC@
-LIBINTL_H = @LIBINTL_H@
-
-CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
-
-#
-# These values are generated for configure by ${topdir}/support/shobj-conf.
-# If your system is not supported by that script, but includes facilities for
-# dynamic loading of shared objects, please update the script and send the
-# changes to bash-maintainers@gnu.org.
-#
-SHOBJ_CC = @SHOBJ_CC@
-SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
-SHOBJ_LD = @SHOBJ_LD@
-SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
-SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
-SHOBJ_LIBS = @SHOBJ_LIBS@
-SHOBJ_STATUS = @SHOBJ_STATUS@
-
-INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
- -I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
- -I$(BUILD_DIR)/builtins $(INTL_INC)
-
-.c.o:
- $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
-
-
-ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
- tty pathchk tee head mkdir rmdir printenv id whoami \
- uname sync push ln unlink cut realpath getconf strftime
-OTHERPROG = necho hello cat
-
-all: $(SHOBJ_STATUS)
-
-supported: $(ALLPROG)
-others: $(OTHERPROG)
-
-unsupported:
- @echo "Your system (${host_os}) is not supported by the"
- @echo "${topdir}/support/shobj-conf script."
- @echo "If your operating system provides facilities for dynamic"
- @echo "loading of shared objects using the dlopen(3) interface,"
- @echo "please update the script and re-run configure.
- @echo "Please send the changes you made to bash-maintainers@gnu.org"
- @echo "for inclusion in future bash releases."
-
-everything: supported others
-
-print: print.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
-
-necho: necho.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
-
-getconf: getconf.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
-
-hello: hello.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
-
-truefalse: truefalse.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
-
-sleep: sleep.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
-
-finfo: finfo.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
-
-cat: cat.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
-
-logname: logname.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
-
-basename: basename.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
-
-dirname: dirname.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
-
-tty: tty.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
-
-pathchk: pathchk.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
-
-tee: tee.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
-
-mkdir: mkdir.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
-
-rmdir: rmdir.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
-
-head: head.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
-
-printenv: printenv.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
-
-id: id.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
-
-whoami: whoami.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
-
-uname: uname.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
-
-sync: sync.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
-
-push: push.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
-
-ln: ln.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
-
-unlink: unlink.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
-
-cut: cut.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
-
-realpath: realpath.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
-
-strftime: strftime.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
-
-# pushd is a special case. We use the same source that the builtin version
-# uses, with special compilation options.
-#
-pushd.c: ${topdir}/builtins/pushd.def
- $(RM) $@
- ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
-
-pushd.o: pushd.c
- $(RM) $@
- $(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
-
-pushd: pushd.o
- $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
-
-clean:
- $(RM) $(ALLPROG) $(OTHERPROG) *.o
- -( cd perl && ${MAKE} ${MFLAGS} $@ )
-
-mostlyclean: clean
- -( cd perl && ${MAKE} ${MFLAGS} $@ )
-
-distclean maintainer-clean: clean
- $(RM) Makefile pushd.c
- -( cd perl && ${MAKE} ${MFLAGS} $@ )
-
-print.o: print.c
-truefalse.o: truefalse.c
-sleep.o: sleep.c
-finfo.o: finfo.c
-logname.o: logname.c
-basename.o: basename.c
-dirname.o: dirname.c
-tty.o: tty.c
-pathchk.o: pathchk.c
-tee.o: tee.c
-head.o: head.c
-rmdir.o: rmdir.c
-necho.o: necho.c
-getconf.o: getconf.c
-hello.o: hello.c
-cat.o: cat.c
-printenv.o: printenv.c
-id.o: id.c
-whoami.o: whoami.c
-uname.o: uname.c
-sync.o: sync.c
-push.o: push.c
-mkdir.o: mkdir.c
-realpath.o: realpath.c
-strftime.o: strftime.c
+++ /dev/null
-/* 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;
-
-int evalnest = 0; /* bash-4.4/bash-5.0 */
-int evalnest_max = EVALNEST_MAX;
-
-int sourcenest = 0;
-int sourcenest_max = SOURCENEST_MAX;
-
-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);
- exec_result = EXECUTION_SUCCESS;
- invert = 0; /* async commands always succeed */
- }
- 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 ();
-
-#if 0 /* XXX - bash-4.4 or bash-5.0 */
- /* Undo redirections before running exit trap on the way out of
- set -e. Report by Mark Farrell 5/19/2014 */
- if (exit_immediately_on_error && signal_is_trapped (0) &&
- unwind_protect_tag_on_stack ("saved-redirects"))
- run_unwind_frame ("saved-redirects");
-#endif
-
- 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);
- if (asynchronous)
- invert = 0; /* XXX */
-
- 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; /* XXX */
- 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)
- if (INVALID_JOB (lastpipe_jid) == 0)
- {
- append_process (savestring (the_printed_command_except_trap), dollar_dollar_pid, exec_result, lastpipe_jid);
- lstdin = wait_for (lastpid);
- }
- else
- lstdin = wait_for_single_pid (lastpid); /* checks bgpids list */
-#else
- lstdin = wait_for (lastpid);
-#endif
-
-#if defined (JOB_CONTROL)
- /* If wait_for removes the job from the jobs table, use result of last
- command as pipeline's exit status as usual. The jobs list can get
- frozen and unfrozen at inconvenient times if there are multiple pipelines
- running simultaneously. */
- if (INVALID_JOB (lastpipe_jid) == 0)
- exec_result = job_exit_status (lastpipe_jid);
- else if (pipefail_opt)
- exec_result = exec_result | lstdin; /* XXX */
- /* otherwise we use exec_result */
-
-#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 (asynchronous)
- {
- exec_result = EXECUTION_SUCCESS;
- invert = 0;
- }
-
- 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);
- 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->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; /* XXX */
- 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;
- }
- }
-
- if (subshell == 0 && builtin == eval_builtin)
- {
- if (evalnest_max > 0 && evalnest >= evalnest_max)
- {
- internal_error (_("eval: maximum eval nesting level exceeded (%d)"), evalnest);
- evalnest = 0;
- jump_to_top_level (DISCARD);
- }
- unwind_protect_int (evalnest);
- /* The test for subshell == 0 above doesn't make a difference */
- evalnest++; /* execute_subshell_builtin_or_function sets this to 0 */
- }
- else if (subshell == 0 && builtin == source_builtin)
- {
- if (sourcenest_max > 0 && sourcenest >= sourcenest_max)
- {
- internal_error (_("%s: maximum source nesting level exceeded (%d)"), this_command_name, sourcenest);
- sourcenest = 0;
- jump_to_top_level (DISCARD);
- }
- unwind_protect_int (sourcenest);
- /* The test for subshell == 0 above doesn't make a difference */
- sourcenest++; /* execute_subshell_builtin_or_function sets this to 0 */
- }
-
-
- /* `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 (builtin == eval_builtin)
- evalnest = 0;
- else if (builtin == source_builtin)
- sourcenest = 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; /* XXX */
-
- 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 */
- pathname = printable_filename (pathname, 0);
- 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 = evalnest = sourcenest = 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)
- {
- /* make sure this is set correctly for file_error/report_error */
- last_command_exit_value = (i == ENOENT) ? EX_NOTFOUND : EX_NOEXEC; /* XXX Posix.2 says that exit status is 126 */
- 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 (last_command_exit_value);
- }
-
- /* 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 */
-
- clear_fifo_list (); /* pipe fds are what they are now */
-
- 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
-/* general.c -- Stuff that is used by all files. */
-
-/* Copyright (C) 1987-2011 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "config.h"
-
-#include "bashtypes.h"
-#if defined (HAVE_SYS_PARAM_H)
-# include <sys/param.h>
-#endif
-#include "posixstat.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "filecntl.h"
-#include "bashansi.h"
-#include <stdio.h>
-#include "chartypes.h"
-#include <errno.h>
-
-#include "bashintl.h"
-
-#include "shell.h"
-#include "test.h"
-#include "trap.h"
-
-#include <tilde/tilde.h>
-
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-extern int expand_aliases;
-extern int interactive_comments;
-extern int check_hashed_filenames;
-extern int source_uses_path;
-extern int source_searches_cwd;
-extern int posixly_correct;
-
-static char *bash_special_tilde_expansions __P((char *));
-static int unquoted_tilde_word __P((const char *));
-static void initialize_group_array __P((void));
-
-/* A standard error message to use when getcwd() returns NULL. */
-const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
-
-/* Do whatever is necessary to initialize `Posix mode'. */
-void
-posix_initialize (on)
- int on;
-{
- /* Things that should be turned on when posix mode is enabled. */
- if (on != 0)
- {
- interactive_comments = source_uses_path = expand_aliases = 1;
- source_searches_cwd = 0;
- }
-
- /* Things that should be turned on when posix mode is disabled. */
- if (on == 0)
- {
- source_searches_cwd = 1;
- expand_aliases = interactive_shell;
- }
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to convert to and from and display non-standard types */
-/* */
-/* **************************************************************** */
-
-#if defined (RLIMTYPE)
-RLIMTYPE
-string_to_rlimtype (s)
- char *s;
-{
- RLIMTYPE ret;
- int neg;
-
- ret = 0;
- neg = 0;
- while (s && *s && whitespace (*s))
- s++;
- if (s && (*s == '-' || *s == '+'))
- {
- neg = *s == '-';
- s++;
- }
- for ( ; s && *s && DIGIT (*s); s++)
- ret = (ret * 10) + TODIGIT (*s);
- return (neg ? -ret : ret);
-}
-
-void
-print_rlimtype (n, addnl)
- RLIMTYPE n;
- int addnl;
-{
- char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
-
- p = s + sizeof(s);
- *--p = '\0';
-
- if (n < 0)
- {
- do
- *--p = '0' - n % 10;
- while ((n /= 10) != 0);
-
- *--p = '-';
- }
- else
- {
- do
- *--p = '0' + n % 10;
- while ((n /= 10) != 0);
- }
-
- printf ("%s%s", p, addnl ? "\n" : "");
-}
-#endif /* RLIMTYPE */
-
-/* **************************************************************** */
-/* */
-/* Input Validation Functions */
-/* */
-/* **************************************************************** */
-
-/* Return non-zero if all of the characters in STRING are digits. */
-int
-all_digits (string)
- char *string;
-{
- register char *s;
-
- for (s = string; *s; s++)
- if (DIGIT (*s) == 0)
- return (0);
-
- return (1);
-}
-
-/* Return non-zero if the characters pointed to by STRING constitute a
- valid number. Stuff the converted number into RESULT if RESULT is
- not null. */
-int
-legal_number (string, result)
- const char *string;
- intmax_t *result;
-{
- intmax_t value;
- char *ep;
-
- if (result)
- *result = 0;
-
- if (string == 0)
- return 0;
-
- errno = 0;
- value = strtoimax (string, &ep, 10);
- if (errno || ep == string)
- return 0; /* errno is set on overflow or underflow */
-
- /* Skip any trailing whitespace, since strtoimax does not. */
- while (whitespace (*ep))
- ep++;
-
- /* If *string is not '\0' but *ep is '\0' on return, the entire string
- is valid. */
- if (*string && *ep == '\0')
- {
- if (result)
- *result = value;
- /* The SunOS4 implementation of strtol() will happily ignore
- overflow conditions, so this cannot do overflow correctly
- on those systems. */
- return 1;
- }
-
- return (0);
-}
-
-/* Return 1 if this token is a legal shell `identifier'; that is, it consists
- solely of letters, digits, and underscores, and does not begin with a
- digit. */
-int
-legal_identifier (name)
- char *name;
-{
- register char *s;
- unsigned char c;
-
- if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
- return (0);
-
- for (s = name + 1; (c = *s) != 0; s++)
- {
- if (legal_variable_char (c) == 0)
- return (0);
- }
- return (1);
-}
-
-/* Make sure that WORD is a valid shell identifier, i.e.
- does not contain a dollar sign, nor is quoted in any way. Nor
- does it consist of all digits. If CHECK_WORD is non-zero,
- the word is checked to ensure that it consists of only letters,
- digits, and underscores. */
-int
-check_identifier (word, check_word)
- WORD_DESC *word;
- int check_word;
-{
- if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
- {
- internal_error (_("`%s': not a valid identifier"), word->word);
- return (0);
- }
- else if (check_word && legal_identifier (word->word) == 0)
- {
- internal_error (_("`%s': not a valid identifier"), word->word);
- return (0);
- }
- else
- return (1);
-}
-
-/* Return 1 if STRING is a function name that the shell will import from
- the environment. Currently we reject attempts to import shell functions
- containing slashes, beginning with newlines or containing blanks. In
- Posix mode, we require that STRING be a valid shell identifier. Not
- used yet. */
-int
-importable_function_name (string, len)
- char *string;
- size_t len;
-{
- if (absolute_program (string)) /* don't allow slash */
- return 0;
- if (*string == '\n') /* can't start with a newline */
- return 0;
- if (shellblank (*string) || shellblank(string[len-1]))
- return 0;
- return (posixly_correct ? legal_identifier (string) : 1);
-}
-
-int
-exportable_function_name (string)
- char *string;
-{
- if (absolute_program (name))
- return 0;
- if (mbschr (string, '=') != 0)
- return 0;
- return 1;
-}
-
-/* Return 1 if STRING comprises a valid alias name. The shell accepts
- essentially all characters except those which must be quoted to the
- parser (which disqualifies them from alias expansion anyway) and `/'. */
-int
-legal_alias_name (string, flags)
- char *string;
- int flags;
-{
- register char *s;
-
- for (s = string; *s; s++)
- if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
- return 0;
- return 1;
-}
-
-/* Returns non-zero if STRING is an assignment statement. The returned value
- is the index of the `=' sign. */
-int
-assignment (string, flags)
- const char *string;
- int flags;
-{
- register unsigned char c;
- register int newi, indx;
-
- c = string[indx = 0];
-
-#if defined (ARRAY_VARS)
- if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
-#else
- if (legal_variable_starter (c) == 0)
-#endif
- return (0);
-
- while (c = string[indx])
- {
- /* The following is safe. Note that '=' at the start of a word
- is not an assignment statement. */
- if (c == '=')
- return (indx);
-
-#if defined (ARRAY_VARS)
- if (c == '[')
- {
- newi = skipsubscript (string, indx, 0);
- if (string[newi++] != ']')
- return (0);
- if (string[newi] == '+' && string[newi+1] == '=')
- return (newi + 1);
- return ((string[newi] == '=') ? newi : 0);
- }
-#endif /* ARRAY_VARS */
-
- /* Check for `+=' */
- if (c == '+' && string[indx+1] == '=')
- return (indx + 1);
-
- /* Variable names in assignment statements may contain only letters,
- digits, and `_'. */
- if (legal_variable_char (c) == 0)
- return (0);
-
- indx++;
- }
- return (0);
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to manage files and file descriptors */
-/* */
-/* **************************************************************** */
-
-/* A function to unset no-delay mode on a file descriptor. Used in shell.c
- to unset it on the fd passed as stdin. Should be called on stdin if
- readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
-
-#if !defined (O_NDELAY)
-# if defined (FNDELAY)
-# define O_NDELAY FNDELAY
-# endif
-#endif /* O_NDELAY */
-
-/* Make sure no-delay mode is not set on file descriptor FD. */
-int
-sh_unset_nodelay_mode (fd)
- int fd;
-{
- int flags, bflags;
-
- if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
- return -1;
-
- bflags = 0;
-
- /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
- and O_NDELAY is defined. */
-#ifdef O_NONBLOCK
- bflags |= O_NONBLOCK;
-#endif
-
-#ifdef O_NDELAY
- bflags |= O_NDELAY;
-#endif
-
- if (flags & bflags)
- {
- flags &= ~bflags;
- return (fcntl (fd, F_SETFL, flags));
- }
-
- return 0;
-}
-
-/* Return 1 if file descriptor FD is valid; 0 otherwise. */
-int
-sh_validfd (fd)
- int fd;
-{
- return (fcntl (fd, F_GETFD, 0) >= 0);
-}
-
-int
-fd_ispipe (fd)
- int fd;
-{
- errno = 0;
- if (lseek ((fd), 0L, SEEK_CUR) < 0)
- return (errno == ESPIPE);
- return 0;
-}
-
-/* There is a bug in the NeXT 2.1 rlogind that causes opens
- of /dev/tty to fail. */
-
-#if defined (__BEOS__)
-/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
- into a no-op. This should probably go away in the future. */
-# undef O_NONBLOCK
-# define O_NONBLOCK 0
-#endif /* __BEOS__ */
-
-void
-check_dev_tty ()
-{
- int tty_fd;
- char *tty;
-
- tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
-
- if (tty_fd < 0)
- {
- tty = (char *)ttyname (fileno (stdin));
- if (tty == 0)
- return;
- tty_fd = open (tty, O_RDWR|O_NONBLOCK);
- }
- if (tty_fd >= 0)
- close (tty_fd);
-}
-
-/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
- expensive. If non-NULL STP1 and STP2 point to stat structures
- corresponding to PATH1 and PATH2, respectively. */
-int
-same_file (path1, path2, stp1, stp2)
- char *path1, *path2;
- struct stat *stp1, *stp2;
-{
- struct stat st1, st2;
-
- if (stp1 == NULL)
- {
- if (stat (path1, &st1) != 0)
- return (0);
- stp1 = &st1;
- }
-
- if (stp2 == NULL)
- {
- if (stat (path2, &st2) != 0)
- return (0);
- stp2 = &st2;
- }
-
- return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
-}
-
-/* Move FD to a number close to the maximum number of file descriptors
- allowed in the shell process, to avoid the user stepping on it with
- redirection and causing us extra work. If CHECK_NEW is non-zero,
- we check whether or not the file descriptors are in use before
- duplicating FD onto them. MAXFD says where to start checking the
- file descriptors. If it's less than 20, we get the maximum value
- available from getdtablesize(2). */
-int
-move_to_high_fd (fd, check_new, maxfd)
- int fd, check_new, maxfd;
-{
- int script_fd, nfds, ignore;
-
- if (maxfd < 20)
- {
- nfds = getdtablesize ();
- if (nfds <= 0)
- nfds = 20;
- if (nfds > HIGH_FD_MAX)
- nfds = HIGH_FD_MAX; /* reasonable maximum */
- }
- else
- nfds = maxfd;
-
- for (nfds--; check_new && nfds > 3; nfds--)
- if (fcntl (nfds, F_GETFD, &ignore) == -1)
- break;
-
- if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
- {
- if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
- close (fd);
- return (script_fd);
- }
-
- /* OK, we didn't find one less than our artificial maximum; return the
- original file descriptor. */
- return (fd);
-}
-
-/* Return non-zero if the characters from SAMPLE are not all valid
- characters to be found in the first line of a shell script. We
- check up to the first newline, or SAMPLE_LEN, whichever comes first.
- All of the characters must be printable or whitespace. */
-
-int
-check_binary_file (sample, sample_len)
- char *sample;
- int sample_len;
-{
- register int i;
- unsigned char c;
-
- for (i = 0; i < sample_len; i++)
- {
- c = sample[i];
- if (c == '\n')
- return (0);
- if (c == '\0')
- return (1);
- }
-
- return (0);
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to manipulate pipes */
-/* */
-/* **************************************************************** */
-
-int
-sh_openpipe (pv)
- int *pv;
-{
- int r;
-
- if ((r = pipe (pv)) < 0)
- return r;
-
- pv[0] = move_to_high_fd (pv[0], 1, 64);
- pv[1] = move_to_high_fd (pv[1], 1, 64);
-
- return 0;
-}
-
-int
-sh_closepipe (pv)
- int *pv;
-{
- if (pv[0] >= 0)
- close (pv[0]);
-
- if (pv[1] >= 0)
- close (pv[1]);
-
- pv[0] = pv[1] = -1;
- return 0;
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to inspect pathnames */
-/* */
-/* **************************************************************** */
-
-int
-file_exists (fn)
- char *fn;
-{
- struct stat sb;
-
- return (stat (fn, &sb) == 0);
-}
-
-int
-file_isdir (fn)
- char *fn;
-{
- struct stat sb;
-
- return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
-}
-
-int
-file_iswdir (fn)
- char *fn;
-{
- return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
-}
-
-/* Return 1 if STRING is "." or "..", optionally followed by a directory
- separator */
-int
-path_dot_or_dotdot (string)
- const char *string;
-{
- if (string == 0 || *string == '\0' || *string != '.')
- return (0);
-
- /* string[0] == '.' */
- if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2])))
- return (1);
-
- return (0);
-}
-
-/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
- to decide whether or not to look up a directory name in $CDPATH. */
-int
-absolute_pathname (string)
- const char *string;
-{
- if (string == 0 || *string == '\0')
- return (0);
-
- if (ABSPATH(string))
- return (1);
-
- if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
- return (1);
-
- if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
- return (1);
-
- return (0);
-}
-
-/* Return 1 if STRING is an absolute program name; it is absolute if it
- contains any slashes. This is used to decide whether or not to look
- up through $PATH. */
-int
-absolute_program (string)
- const char *string;
-{
- return ((char *)mbschr (string, '/') != (char *)NULL);
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to manipulate pathnames */
-/* */
-/* **************************************************************** */
-
-/* Turn STRING (a pathname) into an absolute pathname, assuming that
- DOT_PATH contains the symbolic location of `.'. This always
- returns a new string, even if STRING was an absolute pathname to
- begin with. */
-char *
-make_absolute (string, dot_path)
- char *string, *dot_path;
-{
- char *result;
-
- if (dot_path == 0 || ABSPATH(string))
-#ifdef __CYGWIN__
- {
- char pathbuf[PATH_MAX + 1];
-
- cygwin_conv_to_full_posix_path (string, pathbuf);
- result = savestring (pathbuf);
- }
-#else
- result = savestring (string);
-#endif
- else
- result = sh_makepath (dot_path, string, 0);
-
- return (result);
-}
-
-/* Return the `basename' of the pathname in STRING (the stuff after the
- last '/'). If STRING is `/', just return it. */
-char *
-base_pathname (string)
- char *string;
-{
- char *p;
-
-#if 0
- if (absolute_pathname (string) == 0)
- return (string);
-#endif
-
- if (string[0] == '/' && string[1] == 0)
- return (string);
-
- p = (char *)strrchr (string, '/');
- return (p ? ++p : string);
-}
-
-/* Return the full pathname of FILE. Easy. Filenames that begin
- with a '/' are returned as themselves. Other filenames have
- the current working directory prepended. A new string is
- returned in either case. */
-char *
-full_pathname (file)
- char *file;
-{
- char *ret;
-
- file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
-
- if (ABSPATH(file))
- return (file);
-
- ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
- free (file);
-
- return (ret);
-}
-
-/* A slightly related function. Get the prettiest name of this
- directory possible. */
-static char tdir[PATH_MAX];
-
-/* Return a pretty pathname. If the first part of the pathname is
- the same as $HOME, then replace that with `~'. */
-char *
-polite_directory_format (name)
- char *name;
-{
- char *home;
- int l;
-
- home = get_string_value ("HOME");
- l = home ? strlen (home) : 0;
- if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
- {
- strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
- tdir[0] = '~';
- tdir[sizeof(tdir) - 1] = '\0';
- return (tdir);
- }
- else
- return (name);
-}
-
-/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to
- keep any tilde prefix and PROMPT_DIRTRIM trailing directory components
- and replace the intervening characters with `...' */
-char *
-trim_pathname (name, maxlen)
- char *name;
- int maxlen;
-{
- int nlen, ndirs;
- intmax_t nskip;
- char *nbeg, *nend, *ntail, *v;
-
- if (name == 0 || (nlen = strlen (name)) == 0)
- return name;
- nend = name + nlen;
-
- v = get_string_value ("PROMPT_DIRTRIM");
- if (v == 0 || *v == 0)
- return name;
- if (legal_number (v, &nskip) == 0 || nskip <= 0)
- return name;
-
- /* Skip over tilde prefix */
- nbeg = name;
- if (name[0] == '~')
- for (nbeg = name; *nbeg; nbeg++)
- if (*nbeg == '/')
- {
- nbeg++;
- break;
- }
- if (*nbeg == 0)
- return name;
-
- for (ndirs = 0, ntail = nbeg; *ntail; ntail++)
- if (*ntail == '/')
- ndirs++;
- if (ndirs < nskip)
- return name;
-
- for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--)
- {
- if (*ntail == '/')
- nskip--;
- if (nskip == 0)
- break;
- }
- if (ntail == nbeg)
- return name;
-
- /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */
- nlen = ntail - nbeg;
- if (nlen <= 3)
- return name;
-
- *nbeg++ = '.';
- *nbeg++ = '.';
- *nbeg++ = '.';
-
- nlen = nend - ntail;
- memmove (nbeg, ntail, nlen);
- nbeg[nlen] = '\0';
-
- return name;
-}
-
-/* Return a printable representation of FN without special characters. The
- caller is responsible for freeing memory if this returns something other
- than its argument. If FLAGS is non-zero, we are printing for portable
- re-input and should single-quote filenames appropriately. */
-char *
-printable_filename (fn, flags)
- char *fn;
- int flags;
-{
- char *newf;
-
- if (ansic_shouldquote (fn))
- newf = ansic_quote (fn, 0, NULL);
- else if (flags && sh_contains_shell_metas (fn))
- newf = sh_single_quote (fn);
- else
- newf = fn;
-
- return newf;
-}
-
-/* Given a string containing units of information separated by colons,
- return the next one pointed to by (P_INDEX), or NULL if there are no more.
- Advance (P_INDEX) to the character after the colon. */
-char *
-extract_colon_unit (string, p_index)
- char *string;
- int *p_index;
-{
- int i, start, len;
- char *value;
-
- if (string == 0)
- return (string);
-
- len = strlen (string);
- if (*p_index >= len)
- return ((char *)NULL);
-
- i = *p_index;
-
- /* Each call to this routine leaves the index pointing at a colon if
- there is more to the path. If I is > 0, then increment past the
- `:'. If I is 0, then the path has a leading colon. Trailing colons
- are handled OK by the `else' part of the if statement; an empty
- string is returned in that case. */
- if (i && string[i] == ':')
- i++;
-
- for (start = i; string[i] && string[i] != ':'; i++)
- ;
-
- *p_index = i;
-
- if (i == start)
- {
- if (string[i])
- (*p_index)++;
- /* Return "" in the case of a trailing `:'. */
- value = (char *)xmalloc (1);
- value[0] = '\0';
- }
- else
- value = substring (string, start, i);
-
- return (value);
-}
-
-/* **************************************************************** */
-/* */
-/* Tilde Initialization and Expansion */
-/* */
-/* **************************************************************** */
-
-#if defined (PUSHD_AND_POPD)
-extern char *get_dirstack_from_string __P((char *));
-#endif
-
-static char **bash_tilde_prefixes;
-static char **bash_tilde_prefixes2;
-static char **bash_tilde_suffixes;
-static char **bash_tilde_suffixes2;
-
-/* If tilde_expand hasn't been able to expand the text, perhaps it
- is a special shell expansion. This function is installed as the
- tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
- If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
- directory stack. */
-static char *
-bash_special_tilde_expansions (text)
- char *text;
-{
- char *result;
-
- result = (char *)NULL;
-
- if (text[0] == '+' && text[1] == '\0')
- result = get_string_value ("PWD");
- else if (text[0] == '-' && text[1] == '\0')
- result = get_string_value ("OLDPWD");
-#if defined (PUSHD_AND_POPD)
- else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
- result = get_dirstack_from_string (text);
-#endif
-
- return (result ? savestring (result) : (char *)NULL);
-}
-
-/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
- well as handling special tilde prefixes; `:~" and `=~' are indications
- that we should do tilde expansion. */
-void
-tilde_initialize ()
-{
- static int times_called = 0;
-
- /* Tell the tilde expander that we want a crack first. */
- tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
-
- /* Tell the tilde expander about special strings which start a tilde
- expansion, and the special strings that end one. Only do this once.
- tilde_initialize () is called from within bashline_reinitialize (). */
- if (times_called++ == 0)
- {
- bash_tilde_prefixes = strvec_create (3);
- bash_tilde_prefixes[0] = "=~";
- bash_tilde_prefixes[1] = ":~";
- bash_tilde_prefixes[2] = (char *)NULL;
-
- bash_tilde_prefixes2 = strvec_create (2);
- bash_tilde_prefixes2[0] = ":~";
- bash_tilde_prefixes2[1] = (char *)NULL;
-
- tilde_additional_prefixes = bash_tilde_prefixes;
-
- bash_tilde_suffixes = strvec_create (3);
- bash_tilde_suffixes[0] = ":";
- bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
- bash_tilde_suffixes[2] = (char *)NULL;
-
- tilde_additional_suffixes = bash_tilde_suffixes;
-
- bash_tilde_suffixes2 = strvec_create (2);
- bash_tilde_suffixes2[0] = ":";
- bash_tilde_suffixes2[1] = (char *)NULL;
- }
-}
-
-/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
- at the beginning of the word, followed by all of the characters preceding
- the first unquoted slash in the word, or all the characters in the word
- if there is no slash...If none of the characters in the tilde-prefix are
- quoted, the characters in the tilde-prefix following the tilde shell be
- treated as a possible login name. */
-
-#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
-
-static int
-unquoted_tilde_word (s)
- const char *s;
-{
- const char *r;
-
- for (r = s; TILDE_END(*r) == 0; r++)
- {
- switch (*r)
- {
- case '\\':
- case '\'':
- case '"':
- return 0;
- }
- }
- return 1;
-}
-
-/* Find the end of the tilde-prefix starting at S, and return the tilde
- prefix in newly-allocated memory. Return the length of the string in
- *LENP. FLAGS tells whether or not we're in an assignment context --
- if so, `:' delimits the end of the tilde prefix as well. */
-char *
-bash_tilde_find_word (s, flags, lenp)
- const char *s;
- int flags, *lenp;
-{
- const char *r;
- char *ret;
- int l;
-
- for (r = s; *r && *r != '/'; r++)
- {
- /* Short-circuit immediately if we see a quote character. Even though
- POSIX says that `the first unquoted slash' (or `:') terminates the
- tilde-prefix, in practice, any quoted portion of the tilde prefix
- will cause it to not be expanded. */
- if (*r == '\\' || *r == '\'' || *r == '"')
- {
- ret = savestring (s);
- if (lenp)
- *lenp = 0;
- return ret;
- }
- else if (flags && *r == ':')
- break;
- }
- l = r - s;
- ret = xmalloc (l + 1);
- strncpy (ret, s, l);
- ret[l] = '\0';
- if (lenp)
- *lenp = l;
- return ret;
-}
-
-/* Tilde-expand S by running it through the tilde expansion library.
- ASSIGN_P is 1 if this is a variable assignment, so the alternate
- tilde prefixes should be enabled (`=~' and `:~', see above). If
- ASSIGN_P is 2, we are expanding the rhs of an assignment statement,
- so `=~' is not valid. */
-char *
-bash_tilde_expand (s, assign_p)
- const char *s;
- int assign_p;
-{
- int old_immed, old_term, r;
- char *ret;
-
- old_immed = interrupt_immediately;
- old_term = terminate_immediately;
- /* We want to be able to interrupt tilde expansion. Ordinarily, we can just
- jump to top_level, but we don't want to run any trap commands in a signal
- handler context. We might be able to get away with just checking for
- things like SIGINT and SIGQUIT. */
- if (any_signals_trapped () < 0)
- interrupt_immediately = 1;
- terminate_immediately = 1;
-
- tilde_additional_prefixes = assign_p == 0 ? (char **)0
- : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
- if (assign_p == 2)
- tilde_additional_suffixes = bash_tilde_suffixes2;
-
- r = (*s == '~') ? unquoted_tilde_word (s) : 1;
- ret = r ? tilde_expand (s) : savestring (s);
-
- interrupt_immediately = old_immed;
- terminate_immediately = old_term;
-
- QUIT;
-
- return (ret);
-}
-
-/* **************************************************************** */
-/* */
-/* Functions to manipulate and search the group list */
-/* */
-/* **************************************************************** */
-
-static int ngroups, maxgroups;
-
-/* The set of groups that this user is a member of. */
-static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
-
-#if !defined (NOGROUP)
-# define NOGROUP (gid_t) -1
-#endif
-
-static void
-initialize_group_array ()
-{
- register int i;
-
- if (maxgroups == 0)
- maxgroups = getmaxgroups ();
-
- ngroups = 0;
- group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
-
-#if defined (HAVE_GETGROUPS)
- ngroups = getgroups (maxgroups, group_array);
-#endif
-
- /* If getgroups returns nothing, or the OS does not support getgroups(),
- make sure the groups array includes at least the current gid. */
- if (ngroups == 0)
- {
- group_array[0] = current_user.gid;
- ngroups = 1;
- }
-
- /* If the primary group is not in the groups array, add it as group_array[0]
- and shuffle everything else up 1, if there's room. */
- for (i = 0; i < ngroups; i++)
- if (current_user.gid == (gid_t)group_array[i])
- break;
- if (i == ngroups && ngroups < maxgroups)
- {
- for (i = ngroups; i > 0; i--)
- group_array[i] = group_array[i - 1];
- group_array[0] = current_user.gid;
- ngroups++;
- }
-
- /* If the primary group is not group_array[0], swap group_array[0] and
- whatever the current group is. The vast majority of systems should
- not need this; a notable exception is Linux. */
- if (group_array[0] != current_user.gid)
- {
- for (i = 0; i < ngroups; i++)
- if (group_array[i] == current_user.gid)
- break;
- if (i < ngroups)
- {
- group_array[i] = group_array[0];
- group_array[0] = current_user.gid;
- }
- }
-}
-
-/* Return non-zero if GID is one that we have in our groups list. */
-int
-#if defined (__STDC__) || defined ( _MINIX)
-group_member (gid_t gid)
-#else
-group_member (gid)
- gid_t gid;
-#endif /* !__STDC__ && !_MINIX */
-{
-#if defined (HAVE_GETGROUPS)
- register int i;
-#endif
-
- /* Short-circuit if possible, maybe saving a call to getgroups(). */
- if (gid == current_user.gid || gid == current_user.egid)
- return (1);
-
-#if defined (HAVE_GETGROUPS)
- if (ngroups == 0)
- initialize_group_array ();
-
- /* In case of error, the user loses. */
- if (ngroups <= 0)
- return (0);
-
- /* Search through the list looking for GID. */
- for (i = 0; i < ngroups; i++)
- if (gid == (gid_t)group_array[i])
- return (1);
-#endif
-
- return (0);
-}
-
-char **
-get_group_list (ngp)
- int *ngp;
-{
- static char **group_vector = (char **)NULL;
- register int i;
-
- if (group_vector)
- {
- if (ngp)
- *ngp = ngroups;
- return group_vector;
- }
-
- if (ngroups == 0)
- initialize_group_array ();
-
- if (ngroups <= 0)
- {
- if (ngp)
- *ngp = 0;
- return (char **)NULL;
- }
-
- group_vector = strvec_create (ngroups);
- for (i = 0; i < ngroups; i++)
- group_vector[i] = itos (group_array[i]);
-
- if (ngp)
- *ngp = ngroups;
- return group_vector;
-}
-
-int *
-get_group_array (ngp)
- int *ngp;
-{
- int i;
- static int *group_iarray = (int *)NULL;
-
- if (group_iarray)
- {
- if (ngp)
- *ngp = ngroups;
- return (group_iarray);
- }
-
- if (ngroups == 0)
- initialize_group_array ();
-
- if (ngroups <= 0)
- {
- if (ngp)
- *ngp = 0;
- return (int *)NULL;
- }
-
- group_iarray = (int *)xmalloc (ngroups * sizeof (int));
- for (i = 0; i < ngroups; i++)
- group_iarray[i] = (int)group_array[i];
-
- if (ngp)
- *ngp = ngroups;
- return group_iarray;
-}
+++ /dev/null
-/* general.h -- defines that everybody likes to use. */
-
-/* Copyright (C) 1993-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/>.
-*/
-
-#if !defined (_GENERAL_H_)
-#define _GENERAL_H_
-
-#include "stdc.h"
-
-#include "bashtypes.h"
-#include "chartypes.h"
-
-#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE)
-# if defined (HAVE_SYS_TIME_H)
-# include <sys/time.h>
-# endif
-# include <sys/resource.h>
-#endif
-
-#if defined (HAVE_STRING_H)
-# include <string.h>
-#else
-# include <strings.h>
-#endif /* !HAVE_STRING_H */
-
-#if defined (HAVE_LIMITS_H)
-# include <limits.h>
-#endif
-
-#include "xmalloc.h"
-
-/* NULL pointer type. */
-#if !defined (NULL)
-# if defined (__STDC__)
-# define NULL ((void *) 0)
-# else
-# define NULL 0x0
-# endif /* !__STDC__ */
-#endif /* !NULL */
-
-/* Hardly used anymore */
-#define pointer_to_int(x) (int)((char *)x - (char *)0)
-
-#if defined (alpha) && defined (__GNUC__) && !defined (strchr) && !defined (__STDC__)
-extern char *strchr (), *strrchr ();
-#endif
-
-#if !defined (strcpy) && (defined (HAVE_DECL_STRCPY) && !HAVE_DECL_STRCPY)
-extern char *strcpy __P((char *, const char *));
-#endif
-
-#if !defined (savestring)
-# define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
-#endif
-
-#ifndef member
-# define member(c, s) ((c) ? ((char *)mbschr ((s), (c)) != (char *)NULL) : 0)
-#endif
-
-#ifndef whitespace
-#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
-#endif
-
-#ifndef CHAR_MAX
-# ifdef __CHAR_UNSIGNED__
-# define CHAR_MAX 0xff
-# else
-# define CHAR_MAX 0x7f
-# endif
-#endif
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
-
-/* Nonzero if the integer type T is signed. */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-
-/* Bound on length of the string representing an integer value of type T.
- Subtract one for the sign bit if T is signed;
- 302 / 1000 is log10 (2) rounded up;
- add one for integer division truncation;
- add one more for a minus sign if t is signed. */
-#define INT_STRLEN_BOUND(t) \
- ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
- + 1 + TYPE_SIGNED (t))
-
-
-/* Define exactly what a legal shell identifier consists of. */
-#define legal_variable_starter(c) (ISALPHA(c) || (c == '_'))
-#define legal_variable_char(c) (ISALNUM(c) || c == '_')
-
-/* Definitions used in subst.c and by the `read' builtin for field
- splitting. */
-#define spctabnl(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
-
-/* All structs which contain a `next' field should have that field
- as the first field in the struct. This means that functions
- can be written to handle the general case for linked lists. */
-typedef struct g_list {
- struct g_list *next;
-} GENERIC_LIST;
-
-/* Here is a generic structure for associating character strings
- with integers. It is used in the parser for shell tokenization. */
-typedef struct {
- char *word;
- int token;
-} STRING_INT_ALIST;
-
-/* A macro to avoid making an unneccessary function call. */
-#define REVERSE_LIST(list, type) \
- ((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \
- : (type)(list))
-
-#if __GNUC__ > 1
-# define FASTCOPY(s, d, n) __builtin_memcpy ((d), (s), (n))
-#else /* !__GNUC__ */
-# if !defined (HAVE_BCOPY)
-# if !defined (HAVE_MEMMOVE)
-# define FASTCOPY(s, d, n) memcpy ((d), (s), (n))
-# else
-# define FASTCOPY(s, d, n) memmove ((d), (s), (n))
-# endif /* !HAVE_MEMMOVE */
-# else /* HAVE_BCOPY */
-# define FASTCOPY(s, d, n) bcopy ((s), (d), (n))
-# endif /* HAVE_BCOPY */
-#endif /* !__GNUC__ */
-
-/* String comparisons that possibly save a function call each. */
-#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
-#define STREQN(a, b, n) ((n == 0) ? (1) \
- : ((a)[0] == (b)[0] && strncmp(a, b, n) == 0))
-
-/* More convenience definitions that possibly save system or libc calls. */
-#define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
-#define FREE(s) do { if (s) free (s); } while (0)
-#define MEMBER(c, s) (((c) && c == (s)[0] && !(s)[1]) || (member(c, s)))
-
-/* A fairly hairy macro to check whether an allocated string has more room,
- and to resize it using xrealloc if it does not.
- STR is the string (char *)
- CIND is the current index into the string (int)
- ROOM is the amount of additional room we need in the string (int)
- CSIZE is the currently-allocated size of STR (int)
- SINCR is how much to increment CSIZE before calling xrealloc (int) */
-
-#define RESIZE_MALLOCED_BUFFER(str, cind, room, csize, sincr) \
- do { \
- if ((cind) + (room) >= csize) \
- { \
- while ((cind) + (room) >= csize) \
- csize += (sincr); \
- str = xrealloc (str, csize); \
- } \
- } while (0)
-
-/* Function pointers can be declared as (Function *)foo. */
-#if !defined (_FUNCTION_DEF)
-# define _FUNCTION_DEF
-typedef int Function ();
-typedef void VFunction ();
-typedef char *CPFunction (); /* no longer used */
-typedef char **CPPFunction (); /* no longer used */
-#endif /* _FUNCTION_DEF */
-
-#ifndef SH_FUNCTION_TYPEDEF
-# define SH_FUNCTION_TYPEDEF
-
-/* Shell function typedefs with prototypes */
-/* `Generic' function pointer typedefs */
-
-typedef int sh_intfunc_t __P((int));
-typedef int sh_ivoidfunc_t __P((void));
-typedef int sh_icpfunc_t __P((char *));
-typedef int sh_icppfunc_t __P((char **));
-typedef int sh_iptrfunc_t __P((PTR_T));
-
-typedef void sh_voidfunc_t __P((void));
-typedef void sh_vintfunc_t __P((int));
-typedef void sh_vcpfunc_t __P((char *));
-typedef void sh_vcppfunc_t __P((char **));
-typedef void sh_vptrfunc_t __P((PTR_T));
-
-typedef int sh_wdesc_func_t __P((WORD_DESC *));
-typedef int sh_wlist_func_t __P((WORD_LIST *));
-
-typedef int sh_glist_func_t __P((GENERIC_LIST *));
-
-typedef char *sh_string_func_t __P((char *)); /* like savestring, et al. */
-
-typedef int sh_msg_func_t __P((const char *, ...)); /* printf(3)-like */
-typedef void sh_vmsg_func_t __P((const char *, ...)); /* printf(3)-like */
-
-/* Specific function pointer typedefs. Most of these could be done
- with #defines. */
-typedef void sh_sv_func_t __P((char *)); /* sh_vcpfunc_t */
-typedef void sh_free_func_t __P((PTR_T)); /* sh_vptrfunc_t */
-typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */
-
-typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */
-
-typedef int sh_assign_func_t __P((const char *));
-typedef int sh_wassign_func_t __P((WORD_DESC *, int));
-
-typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */
-
-#endif /* SH_FUNCTION_TYPEDEF */
-
-#define NOW ((time_t) time ((time_t *) 0))
-
-/* Some defines for calling file status functions. */
-#define FS_EXISTS 0x1
-#define FS_EXECABLE 0x2
-#define FS_EXEC_PREFERRED 0x4
-#define FS_EXEC_ONLY 0x8
-#define FS_DIRECTORY 0x10
-#define FS_NODIRS 0x20
-#define FS_READABLE 0x40
-
-/* Default maximum for move_to_high_fd */
-#define HIGH_FD_MAX 256
-
-/* The type of function passed as the fourth argument to qsort(3). */
-#ifdef __STDC__
-typedef int QSFUNC (const void *, const void *);
-#else
-typedef int QSFUNC ();
-#endif
-
-/* Some useful definitions for Unix pathnames. Argument convention:
- x == string, c == character */
-
-#if !defined (__CYGWIN__)
-# define ABSPATH(x) ((x)[0] == '/')
-# define RELPATH(x) ((x)[0] != '/')
-#else /* __CYGWIN__ */
-# define ABSPATH(x) (((x)[0] && ISALPHA((unsigned char)(x)[0]) && (x)[1] == ':') || ISDIRSEP((x)[0]))
-# define RELPATH(x) (ABSPATH(x) == 0)
-#endif /* __CYGWIN__ */
-
-#define ROOTEDPATH(x) (ABSPATH(x))
-
-#define DIRSEP '/'
-#if !defined (__CYGWIN__)
-# define ISDIRSEP(c) ((c) == '/')
-#else
-# define ISDIRSEP(c) ((c) == '/' || (c) == '\\')
-#endif /* __CYGWIN__ */
-#define PATHSEP(c) (ISDIRSEP(c) || (c) == 0)
-
-#if 0
-/* Declarations for functions defined in xmalloc.c */
-extern PTR_T xmalloc __P((size_t));
-extern PTR_T xrealloc __P((void *, size_t));
-extern void xfree __P((void *));
-#endif
-
-/* Declarations for functions defined in general.c */
-extern void posix_initialize __P((int));
-
-#if defined (RLIMTYPE)
-extern RLIMTYPE string_to_rlimtype __P((char *));
-extern void print_rlimtype __P((RLIMTYPE, int));
-#endif
-
-extern int all_digits __P((char *));
-extern int legal_number __P((const char *, intmax_t *));
-extern int legal_identifier __P((char *));
-extern int importable_function_name __P((char *, size_t));
-extern int check_identifier __P((WORD_DESC *, int));
-extern int legal_alias_name __P((char *, int));
-extern int assignment __P((const char *, int));
-
-extern int sh_unset_nodelay_mode __P((int));
-extern int sh_validfd __P((int));
-extern int fd_ispipe __P((int));
-extern void check_dev_tty __P((void));
-extern int move_to_high_fd __P((int, int, int));
-extern int check_binary_file __P((char *, int));
-
-#ifdef _POSIXSTAT_H_
-extern int same_file __P((char *, char *, struct stat *, struct stat *));
-#endif
-
-extern int sh_openpipe __P((int *));
-extern int sh_closepipe __P((int *));
-
-extern int file_exists __P((char *));
-extern int file_isdir __P((char *));
-extern int file_iswdir __P((char *));
-extern int path_dot_or_dotdot __P((const char *));
-extern int absolute_pathname __P((const char *));
-extern int absolute_program __P((const char *));
-
-extern char *make_absolute __P((char *, char *));
-extern char *base_pathname __P((char *));
-extern char *full_pathname __P((char *));
-extern char *polite_directory_format __P((char *));
-extern char *trim_pathname __P((char *, int));
-extern char *printable_filename __P((char *, int));
-
-extern char *extract_colon_unit __P((char *, int *));
-
-extern void tilde_initialize __P((void));
-extern char *bash_tilde_find_word __P((const char *, int, int *));
-extern char *bash_tilde_expand __P((const char *, int));
-
-extern int group_member __P((gid_t));
-extern char **get_group_list __P((int *));
-extern int *get_group_array __P((int *));
-
-#endif /* _GENERAL_H_ */
+++ /dev/null
-/* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
-
- Copyright (C) 2010 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne-Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <config.h>
-
-#include "bashtypes.h"
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashansi.h"
-#include "shmbutil.h"
-
-#include "stdc.h"
-
-#ifndef LPAREN
-# define LPAREN '('
-#endif
-#ifndef RPAREN
-# define RPAREN ')'
-#endif
-
-#if defined (HANDLE_MULTIBYTE)
-#define WLPAREN L'('
-#define WRPAREN L')'
-
-/* 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));
-
-/* Return 1 of the first character of WSTRING could match the first
- character of pattern WPAT. Wide character version. */
-int
-match_pattern_wchar (wpat, wstring)
- wchar_t *wpat, *wstring;
-{
- wchar_t wc;
-
- if (*wstring == 0)
- return (0);
-
- switch (wc = *wpat++)
- {
- default:
- return (*wstring == wc);
- case L'\\':
- return (*wstring == *wpat);
- case L'?':
- return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
- case L'*':
- return (1);
- case L'+':
- case L'!':
- case L'@':
- return (*wpat == WLPAREN ? 1 : (*wstring == wc));
- case L'[':
- return (*wstring != L'\0');
- }
-}
-
-int
-wmatchlen (wpat, wmax)
- wchar_t *wpat;
- size_t wmax;
-{
- wchar_t wc;
- int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
-
- if (*wpat == 0)
- return (0);
-
- matlen = in_cclass = in_collsym = in_equiv = 0;
- while (wc = *wpat++)
- {
- switch (wc)
- {
- default:
- matlen++;
- break;
- case L'\\':
- if (*wpat == 0)
- return ++matlen;
- else
- {
- matlen++;
- wpat++;
- }
- break;
- case L'?':
- if (*wpat == WLPAREN)
- return (matlen = -1); /* XXX for now */
- else
- matlen++;
- break;
- case L'*':
- return (matlen = -1);
- case L'+':
- case L'!':
- case L'@':
- if (*wpat == WLPAREN)
- return (matlen = -1); /* XXX for now */
- else
- matlen++;
- break;
- case L'[':
- /* scan for ending `]', skipping over embedded [:...:] */
- bracklen = 1;
- wc = *wpat++;
- do
- {
- if (wc == 0)
- {
- wpat--; /* back up to NUL */
- matlen += bracklen;
- goto bad_bracket;
- }
- else if (wc == L'\\')
- {
- /* *wpat == backslash-escaped character */
- bracklen++;
- /* If the backslash or backslash-escape ends the string,
- bail. The ++wpat skips over the backslash escape */
- if (*wpat == 0 || *++wpat == 0)
- {
- matlen += bracklen;
- goto bad_bracket;
- }
- }
- else if (wc == L'[' && *wpat == L':') /* character class */
- {
- wpat++;
- bracklen++;
- in_cclass = 1;
- }
- else if (in_cclass && wc == L':' && *wpat == L']')
- {
- wpat++;
- bracklen++;
- in_cclass = 0;
- }
- else if (wc == L'[' && *wpat == L'.') /* collating symbol */
- {
- wpat++;
- bracklen++;
- if (*wpat == L']') /* right bracket can appear as collating symbol */
- {
- wpat++;
- bracklen++;
- }
- in_collsym = 1;
- }
- else if (in_collsym && wc == L'.' && *wpat == L']')
- {
- wpat++;
- bracklen++;
- in_collsym = 0;
- }
- else if (wc == L'[' && *wpat == L'=') /* equivalence class */
- {
- wpat++;
- bracklen++;
- if (*wpat == L']') /* right bracket can appear as equivalence class */
- {
- wpat++;
- bracklen++;
- }
- in_equiv = 1;
- }
- else if (in_equiv && wc == L'=' && *wpat == L']')
- {
- wpat++;
- bracklen++;
- in_equiv = 0;
- }
- else
- bracklen++;
- }
- while ((wc = *wpat++) != L']');
- matlen++; /* bracket expression can only match one char */
-bad_bracket:
- break;
- }
- }
-
- return matlen;
-}
-#endif
-
-int
-extglob_pattern_p (pat)
- char *pat;
-{
- switch (pat[0])
- {
- case '*':
- case '+':
- case '!':
- case '@':
- case '?':
- return (pat[1] == LPAREN);
- default:
- return 0;
- }
-
- return 0;
-}
-
-/* Return 1 of the first character of STRING could match the first
- character of pattern PAT. Used to avoid n2 calls to strmatch(). */
-int
-match_pattern_char (pat, string)
- char *pat, *string;
-{
- char c;
-
- if (*string == 0)
- return (0);
-
- switch (c = *pat++)
- {
- default:
- return (*string == c);
- case '\\':
- return (*string == *pat);
- case '?':
- return (*pat == LPAREN ? 1 : (*string != '\0'));
- case '*':
- return (1);
- case '+':
- case '!':
- case '@':
- return (*pat == LPAREN ? 1 : (*string == c));
- case '[':
- return (*string != '\0');
- }
-}
-
-int
-umatchlen (pat, max)
- char *pat;
- size_t max;
-{
- char c;
- int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
-
- if (*pat == 0)
- return (0);
-
- matlen = in_cclass = in_collsym = in_equiv = 0;
- while (c = *pat++)
- {
- switch (c)
- {
- default:
- matlen++;
- break;
- case '\\':
- if (*pat == 0)
- return ++matlen;
- else
- {
- matlen++;
- pat++;
- }
- break;
- case '?':
- if (*pat == LPAREN)
- return (matlen = -1); /* XXX for now */
- else
- matlen++;
- break;
- case '*':
- return (matlen = -1);
- case '+':
- case '!':
- case '@':
- if (*pat == LPAREN)
- return (matlen = -1); /* XXX for now */
- else
- matlen++;
- break;
- case '[':
- /* scan for ending `]', skipping over embedded [:...:] */
- bracklen = 1;
- c = *pat++;
- do
- {
- if (c == 0)
- {
- pat--; /* back up to NUL */
- matlen += bracklen;
- goto bad_bracket;
- }
- else if (c == '\\')
- {
- /* *pat == backslash-escaped character */
- bracklen++;
- /* If the backslash or backslash-escape ends the string,
- bail. The ++pat skips over the backslash escape */
- if (*pat == 0 || *++pat == 0)
- {
- matlen += bracklen;
- goto bad_bracket;
- }
- }
- else if (c == '[' && *pat == ':') /* character class */
- {
- pat++;
- bracklen++;
- in_cclass = 1;
- }
- else if (in_cclass && c == ':' && *pat == ']')
- {
- pat++;
- bracklen++;
- in_cclass = 0;
- }
- else if (c == '[' && *pat == '.') /* collating symbol */
- {
- pat++;
- bracklen++;
- if (*pat == ']') /* right bracket can appear as collating symbol */
- {
- pat++;
- bracklen++;
- }
- in_collsym = 1;
- }
- else if (in_collsym && c == '.' && *pat == ']')
- {
- pat++;
- bracklen++;
- in_collsym = 0;
- }
- else if (c == '[' && *pat == '=') /* equivalence class */
- {
- pat++;
- bracklen++;
- if (*pat == ']') /* right bracket can appear as equivalence class */
- {
- pat++;
- bracklen++;
- }
- in_equiv = 1;
- }
- else if (in_equiv && c == '=' && *pat == ']')
- {
- pat++;
- bracklen++;
- in_equiv = 0;
- }
- else
- bracklen++;
- }
- while ((c = *pat++) != ']');
- matlen++; /* bracket expression can only match one char */
-bad_bracket:
- break;
- }
- }
-
- return matlen;
-}
-
-/* Skip characters in PAT and return the final occurrence of DIRSEP. This
- is only called when extended_glob is set, so we have to skip over extglob
- patterns x(...) */
-char *
-glob_dirscan (pat, dirsep)
- char *pat;
- int dirsep;
-{
- char *p, *d, *pe, *se;
-
- d = pe = se = 0;
- for (p = pat; p && *p; p++)
- {
- if (extglob_pattern_p (p))
- {
- if (se == 0)
- se = p + strlen (p) - 1;
- pe = glob_patscan (p + 2, se, 0);
- if (pe == 0)
- continue;
- else if (*pe == 0)
- break;
- p = pe - 1; /* will do increment above */
- continue;
- }
- if (*p == dirsep)
- d = p;
- }
- return d;
-}
+++ /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
-/* make_cmd.c -- Functions for making instances of the various
- parser constructs. */
-
-/* Copyright (C) 1989-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/>.
-*/
-
-#include "config.h"
-
-#include <stdio.h>
-#include "bashtypes.h"
-#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif
-#include "filecntl.h"
-#include "bashansi.h"
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashintl.h"
-
-#include "parser.h"
-#include "syntax.h"
-#include "command.h"
-#include "general.h"
-#include "error.h"
-#include "flags.h"
-#include "make_cmd.h"
-#include "dispose_cmd.h"
-#include "variables.h"
-#include "subst.h"
-#include "input.h"
-#include "ocache.h"
-#include "externs.h"
-
-#if defined (JOB_CONTROL)
-#include "jobs.h"
-#endif
-
-#include "shmbutil.h"
-
-extern int line_number, current_command_line_count, parser_state;
-extern int last_command_exit_value;
-
-/* Object caching */
-sh_obj_cache_t wdcache = {0, 0, 0};
-sh_obj_cache_t wlcache = {0, 0, 0};
-
-#define WDCACHESIZE 60
-#define WLCACHESIZE 60
-
-static COMMAND *make_for_or_select __P((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int));
-#if defined (ARITH_FOR_COMMAND)
-static WORD_LIST *make_arith_for_expr __P((char *));
-#endif
-static COMMAND *make_until_or_while __P((enum command_type, COMMAND *, COMMAND *));
-
-void
-cmd_init ()
-{
- ocache_create (wdcache, WORD_DESC, WDCACHESIZE);
- ocache_create (wlcache, WORD_LIST, WLCACHESIZE);
-}
-
-WORD_DESC *
-alloc_word_desc ()
-{
- WORD_DESC *temp;
-
- ocache_alloc (wdcache, WORD_DESC, temp);
- temp->flags = 0;
- temp->word = 0;
- return temp;
-}
-
-WORD_DESC *
-make_bare_word (string)
- const char *string;
-{
- WORD_DESC *temp;
-
- temp = alloc_word_desc ();
-
- if (*string)
- temp->word = savestring (string);
- else
- {
- temp->word = (char *)xmalloc (1);
- temp->word[0] = '\0';
- }
-
- return (temp);
-}
-
-WORD_DESC *
-make_word_flags (w, string)
- WORD_DESC *w;
- const char *string;
-{
- register int i;
- size_t slen;
- DECLARE_MBSTATE;
-
- i = 0;
- slen = strlen (string);
- while (i < slen)
- {
- switch (string[i])
- {
- case '$':
- w->flags |= W_HASDOLLAR;
- break;
- case '\\':
- break; /* continue the loop */
- case '\'':
- case '`':
- case '"':
- w->flags |= W_QUOTED;
- break;
- }
-
- ADVANCE_CHAR (string, slen, i);
- }
-
- return (w);
-}
-
-WORD_DESC *
-make_word (string)
- const char *string;
-{
- WORD_DESC *temp;
-
- temp = make_bare_word (string);
- return (make_word_flags (temp, string));
-}
-
-WORD_DESC *
-make_word_from_token (token)
- int token;
-{
- char tokenizer[2];
-
- tokenizer[0] = token;
- tokenizer[1] = '\0';
-
- return (make_word (tokenizer));
-}
-
-WORD_LIST *
-make_word_list (word, wlink)
- WORD_DESC *word;
- WORD_LIST *wlink;
-{
- WORD_LIST *temp;
-
- ocache_alloc (wlcache, WORD_LIST, temp);
-
- temp->word = word;
- temp->next = wlink;
- return (temp);
-}
-
-COMMAND *
-make_command (type, pointer)
- enum command_type type;
- SIMPLE_COM *pointer;
-{
- COMMAND *temp;
-
- temp = (COMMAND *)xmalloc (sizeof (COMMAND));
- temp->type = type;
- temp->value.Simple = pointer;
- temp->value.Simple->flags = temp->flags = 0;
- temp->redirects = (REDIRECT *)NULL;
- return (temp);
-}
-
-COMMAND *
-command_connect (com1, com2, connector)
- COMMAND *com1, *com2;
- int connector;
-{
- CONNECTION *temp;
-
- temp = (CONNECTION *)xmalloc (sizeof (CONNECTION));
- temp->connector = connector;
- temp->first = com1;
- temp->second = com2;
- return (make_command (cm_connection, (SIMPLE_COM *)temp));
-}
-
-static COMMAND *
-make_for_or_select (type, name, map_list, action, lineno)
- enum command_type type;
- WORD_DESC *name;
- WORD_LIST *map_list;
- COMMAND *action;
- int lineno;
-{
- FOR_COM *temp;
-
- temp = (FOR_COM *)xmalloc (sizeof (FOR_COM));
- temp->flags = 0;
- temp->name = name;
- temp->line = lineno;
- temp->map_list = map_list;
- temp->action = action;
- return (make_command (type, (SIMPLE_COM *)temp));
-}
-
-COMMAND *
-make_for_command (name, map_list, action, lineno)
- WORD_DESC *name;
- WORD_LIST *map_list;
- COMMAND *action;
- int lineno;
-{
- return (make_for_or_select (cm_for, name, map_list, action, lineno));
-}
-
-COMMAND *
-make_select_command (name, map_list, action, lineno)
- WORD_DESC *name;
- WORD_LIST *map_list;
- COMMAND *action;
- int lineno;
-{
-#if defined (SELECT_COMMAND)
- return (make_for_or_select (cm_select, name, map_list, action, lineno));
-#else
- last_command_exit_value = 2;
- return ((COMMAND *)NULL);
-#endif
-}
-
-#if defined (ARITH_FOR_COMMAND)
-static WORD_LIST *
-make_arith_for_expr (s)
- char *s;
-{
- WORD_LIST *result;
- WORD_DESC *wd;
-
- if (s == 0 || *s == '\0')
- return ((WORD_LIST *)NULL);
- wd = make_word (s);
- wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */
-#if defined (PROCESS_SUBSTITUTION)
- wd->flags |= W_NOPROCSUB; /* no process substitution */
-#endif
- result = make_word_list (wd, (WORD_LIST *)NULL);
- return result;
-}
-#endif
-
-/* Note that this function calls dispose_words on EXPRS, since it doesn't
- use the word list directly. We free it here rather than at the caller
- because no other function in this file requires that the caller free
- any arguments. */
-COMMAND *
-make_arith_for_command (exprs, action, lineno)
- WORD_LIST *exprs;
- COMMAND *action;
- int lineno;
-{
-#if defined (ARITH_FOR_COMMAND)
- ARITH_FOR_COM *temp;
- WORD_LIST *init, *test, *step;
- char *s, *t, *start;
- int nsemi, i;
-
- init = test = step = (WORD_LIST *)NULL;
- /* Parse the string into the three component sub-expressions. */
- start = t = s = exprs->word->word;
- for (nsemi = 0; ;)
- {
- /* skip whitespace at the start of each sub-expression. */
- while (whitespace (*s))
- s++;
- start = s;
- /* skip to the semicolon or EOS */
- i = skip_to_delim (start, 0, ";", SD_NOJMP|SD_NOPROCSUB);
- s = start + i;
-
- t = (i > 0) ? substring (start, 0, i) : (char *)NULL;
-
- nsemi++;
- switch (nsemi)
- {
- case 1:
- init = make_arith_for_expr (t);
- break;
- case 2:
- test = make_arith_for_expr (t);
- break;
- case 3:
- step = make_arith_for_expr (t);
- break;
- }
-
- FREE (t);
- if (*s == '\0')
- break;
- s++; /* skip over semicolon */
- }
-
- if (nsemi != 3)
- {
- if (nsemi < 3)
- parser_error (lineno, _("syntax error: arithmetic expression required"));
- else
- parser_error (lineno, _("syntax error: `;' unexpected"));
- parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word);
- free (init);
- free (test);
- free (step);
- last_command_exit_value = 2;
- return ((COMMAND *)NULL);
- }
-
- temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
- temp->flags = 0;
- temp->line = lineno;
- temp->init = init ? init : make_arith_for_expr ("1");
- temp->test = test ? test : make_arith_for_expr ("1");
- temp->step = step ? step : make_arith_for_expr ("1");
- temp->action = action;
-
- dispose_words (exprs);
- return (make_command (cm_arith_for, (SIMPLE_COM *)temp));
-#else
- dispose_words (exprs);
- last_command_exit_value = 2;
- return ((COMMAND *)NULL);
-#endif /* ARITH_FOR_COMMAND */
-}
-
-COMMAND *
-make_group_command (command)
- COMMAND *command;
-{
- GROUP_COM *temp;
-
- temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
- temp->command = command;
- return (make_command (cm_group, (SIMPLE_COM *)temp));
-}
-
-COMMAND *
-make_case_command (word, clauses, lineno)
- WORD_DESC *word;
- PATTERN_LIST *clauses;
- int lineno;
-{
- CASE_COM *temp;
-
- temp = (CASE_COM *)xmalloc (sizeof (CASE_COM));
- temp->flags = 0;
- temp->line = lineno;
- temp->word = word;
- temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *);
- return (make_command (cm_case, (SIMPLE_COM *)temp));
-}
-
-PATTERN_LIST *
-make_pattern_list (patterns, action)
- WORD_LIST *patterns;
- COMMAND *action;
-{
- PATTERN_LIST *temp;
-
- temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
- temp->patterns = REVERSE_LIST (patterns, WORD_LIST *);
- temp->action = action;
- temp->next = NULL;
- temp->flags = 0;
- return (temp);
-}
-
-COMMAND *
-make_if_command (test, true_case, false_case)
- COMMAND *test, *true_case, *false_case;
-{
- IF_COM *temp;
-
- temp = (IF_COM *)xmalloc (sizeof (IF_COM));
- temp->flags = 0;
- temp->test = test;
- temp->true_case = true_case;
- temp->false_case = false_case;
- return (make_command (cm_if, (SIMPLE_COM *)temp));
-}
-
-static COMMAND *
-make_until_or_while (which, test, action)
- enum command_type which;
- COMMAND *test, *action;
-{
- WHILE_COM *temp;
-
- temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
- temp->flags = 0;
- temp->test = test;
- temp->action = action;
- return (make_command (which, (SIMPLE_COM *)temp));
-}
-
-COMMAND *
-make_while_command (test, action)
- COMMAND *test, *action;
-{
- return (make_until_or_while (cm_while, test, action));
-}
-
-COMMAND *
-make_until_command (test, action)
- COMMAND *test, *action;
-{
- return (make_until_or_while (cm_until, test, action));
-}
-
-COMMAND *
-make_arith_command (exp)
- WORD_LIST *exp;
-{
-#if defined (DPAREN_ARITHMETIC)
- COMMAND *command;
- ARITH_COM *temp;
-
- command = (COMMAND *)xmalloc (sizeof (COMMAND));
- command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
-
- temp->flags = 0;
- temp->line = line_number;
- temp->exp = exp;
-
- command->type = cm_arith;
- command->redirects = (REDIRECT *)NULL;
- command->flags = 0;
-
- return (command);
-#else
- last_command_exit_value = 2;
- return ((COMMAND *)NULL);
-#endif
-}
-
-#if defined (COND_COMMAND)
-struct cond_com *
-make_cond_node (type, op, left, right)
- int type;
- WORD_DESC *op;
- struct cond_com *left, *right;
-{
- COND_COM *temp;
-
- temp = (COND_COM *)xmalloc (sizeof (COND_COM));
- temp->flags = 0;
- temp->line = line_number;
- temp->type = type;
- temp->op = op;
- temp->left = left;
- temp->right = right;
-
- return (temp);
-}
-#endif
-
-COMMAND *
-make_cond_command (cond_node)
- COND_COM *cond_node;
-{
-#if defined (COND_COMMAND)
- COMMAND *command;
-
- command = (COMMAND *)xmalloc (sizeof (COMMAND));
- command->value.Cond = cond_node;
-
- command->type = cm_cond;
- command->redirects = (REDIRECT *)NULL;
- command->flags = 0;
- command->line = cond_node ? cond_node->line : 0;
-
- return (command);
-#else
- last_command_exit_value = 2;
- return ((COMMAND *)NULL);
-#endif
-}
-
-COMMAND *
-make_bare_simple_command ()
-{
- COMMAND *command;
- SIMPLE_COM *temp;
-
- command = (COMMAND *)xmalloc (sizeof (COMMAND));
- command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
-
- temp->flags = 0;
- temp->line = line_number;
- temp->words = (WORD_LIST *)NULL;
- temp->redirects = (REDIRECT *)NULL;
-
- command->type = cm_simple;
- command->redirects = (REDIRECT *)NULL;
- command->flags = 0;
-
- return (command);
-}
-
-/* Return a command which is the connection of the word or redirection
- in ELEMENT, and the command * or NULL in COMMAND. */
-COMMAND *
-make_simple_command (element, command)
- ELEMENT element;
- COMMAND *command;
-{
- /* If we are starting from scratch, then make the initial command
- structure. Also note that we have to fill in all the slots, since
- malloc doesn't return zeroed space. */
- if (command == 0)
- {
- command = make_bare_simple_command ();
- parser_state |= PST_REDIRLIST;
- }
-
- if (element.word)
- {
- command->value.Simple->words = make_word_list (element.word, command->value.Simple->words);
- parser_state &= ~PST_REDIRLIST;
- }
- else if (element.redirect)
- {
- REDIRECT *r = element.redirect;
- /* Due to the way <> is implemented, there may be more than a single
- redirection in element.redirect. We just follow the chain as far
- as it goes, and hook onto the end. */
- while (r->next)
- r = r->next;
- r->next = command->value.Simple->redirects;
- command->value.Simple->redirects = element.redirect;
- }
-
- return (command);
-}
-
-/* Because we are Bourne compatible, we read the input for this
- << or <<- redirection now, from wherever input is coming from.
- We store the input read into a WORD_DESC. Replace the text of
- the redirectee.word with the new input text. If <<- is on,
- then remove leading TABS from each line. */
-void
-make_here_document (temp, lineno)
- REDIRECT *temp;
- int lineno;
-{
- int kill_leading, redir_len;
- char *redir_word, *document, *full_line;
- int document_index, document_size, delim_unquoted;
-
- if (temp->instruction != r_deblank_reading_until &&
- temp->instruction != r_reading_until)
- {
- internal_error (_("make_here_document: bad instruction type %d"), temp->instruction);
- return;
- }
-
- kill_leading = temp->instruction == r_deblank_reading_until;
-
- document = (char *)NULL;
- document_index = document_size = 0;
-
- /* Quote removal is the only expansion performed on the delimiter
- for here documents, making it an extremely special case. */
- redir_word = string_quote_removal (temp->redirectee.filename->word, 0);
-
- /* redirection_expand will return NULL if the expansion results in
- multiple words or no words. Check for that here, and just abort
- this here document if it does. */
- if (redir_word)
- redir_len = strlen (redir_word);
- else
- {
- temp->here_doc_eof = (char *)xmalloc (1);
- temp->here_doc_eof[0] = '\0';
- goto document_done;
- }
-
- free (temp->redirectee.filename->word);
- temp->here_doc_eof = redir_word;
-
- /* Read lines from wherever lines are coming from.
- For each line read, if kill_leading, then kill the
- leading tab characters.
- If the line matches redir_word exactly, then we have
- manufactured the document. Otherwise, add the line to the
- list of lines in the document. */
-
- /* If the here-document delimiter was quoted, the lines should
- be read verbatim from the input. If it was not quoted, we
- need to perform backslash-quoted newline removal. */
- delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0;
- while (full_line = read_secondary_line (delim_unquoted))
- {
- register char *line;
- int len;
-
- line = full_line;
- line_number++;
-
- /* If set -v is in effect, echo the line read. read_secondary_line/
- read_a_line leaves the newline at the end, so don't print another. */
- if (echo_input_at_read)
- fprintf (stderr, "%s", line);
-
- if (kill_leading && *line)
- {
- /* Hack: To be compatible with some Bourne shells, we
- check the word before stripping the whitespace. This
- is a hack, though. */
- if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
- goto document_done;
-
- while (*line == '\t')
- line++;
- }
-
- if (*line == 0)
- continue;
-
- if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
- goto document_done;
-
- len = strlen (line);
- if (len + document_index >= document_size)
- {
- document_size = document_size ? 2 * (document_size + len) : len + 2;
- document = (char *)xrealloc (document, document_size);
- }
-
- /* len is guaranteed to be > 0 because of the check for line
- being an empty string before the call to strlen. */
- FASTCOPY (line, document + document_index, len);
- document_index += len;
- }
-
- if (full_line == 0)
- internal_warning (_("here-document at line %d delimited by end-of-file (wanted `%s')"), lineno, redir_word);
-
-document_done:
- if (document)
- document[document_index] = '\0';
- else
- {
- document = (char *)xmalloc (1);
- document[0] = '\0';
- }
- temp->redirectee.filename->word = document;
-}
-
-/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION.
- INSTRUCTION is the instruction type, SOURCE is a file descriptor,
- and DEST is a file descriptor or a WORD_DESC *. */
-REDIRECT *
-make_redirection (source, instruction, dest_and_filename, flags)
- REDIRECTEE source;
- enum r_instruction instruction;
- REDIRECTEE dest_and_filename;
- int flags;
-{
- REDIRECT *temp;
- WORD_DESC *w;
- int wlen;
- intmax_t lfd;
-
- temp = (REDIRECT *)xmalloc (sizeof (REDIRECT));
-
- /* First do the common cases. */
- temp->redirector = source;
- temp->redirectee = dest_and_filename;
- temp->instruction = instruction;
- temp->flags = 0;
- temp->rflags = flags;
- temp->next = (REDIRECT *)NULL;
-
- switch (instruction)
- {
-
- case r_output_direction: /* >foo */
- case r_output_force: /* >| foo */
- case r_err_and_out: /* &>filename */
- temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
- break;
-
- case r_appending_to: /* >>foo */
- case r_append_err_and_out: /* &>> filename */
- temp->flags = O_APPEND | O_WRONLY | O_CREAT;
- break;
-
- case r_input_direction: /* <foo */
- case r_inputa_direction: /* foo & makes this. */
- temp->flags = O_RDONLY;
- break;
-
- case r_input_output: /* <>foo */
- temp->flags = O_RDWR | O_CREAT;
- break;
-
- case r_deblank_reading_until: /* <<-foo */
- case r_reading_until: /* << foo */
- case r_reading_string: /* <<< foo */
- case r_close_this: /* <&- */
- case r_duplicating_input: /* 1<&2 */
- case r_duplicating_output: /* 1>&2 */
- break;
-
- /* the parser doesn't pass these. */
- case r_move_input: /* 1<&2- */
- case r_move_output: /* 1>&2- */
- case r_move_input_word: /* 1<&$foo- */
- case r_move_output_word: /* 1>&$foo- */
- break;
-
- /* The way the lexer works we have to do this here. */
- case r_duplicating_input_word: /* 1<&$foo */
- case r_duplicating_output_word: /* 1>&$foo */
- w = dest_and_filename.filename;
- wlen = strlen (w->word) - 1;
- if (w->word[wlen] == '-') /* Yuck */
- {
- w->word[wlen] = '\0';
- if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd)
- {
- dispose_word (w);
- temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output;
- temp->redirectee.dest = lfd;
- }
- else
- temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word;
- }
-
- break;
-
- default:
- programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction);
- abort ();
- break;
- }
- return (temp);
-}
-
-COMMAND *
-make_function_def (name, command, lineno, lstart)
- WORD_DESC *name;
- COMMAND *command;
- int lineno, lstart;
-{
- FUNCTION_DEF *temp;
-#if defined (ARRAY_VARS)
- SHELL_VAR *bash_source_v;
- ARRAY *bash_source_a;
-#endif
-
- temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
- temp->command = command;
- temp->name = name;
- temp->line = lineno;
- temp->flags = 0;
- command->line = lstart;
-
- /* Information used primarily for debugging. */
- temp->source_file = 0;
-#if defined (ARRAY_VARS)
- GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
- if (bash_source_a && array_num_elements (bash_source_a) > 0)
- temp->source_file = array_reference (bash_source_a, 0);
-#endif
-#if defined (DEBUGGER)
- bind_function_def (name->word, temp);
-#endif
-
- temp->source_file = temp->source_file ? savestring (temp->source_file) : 0;
- return (make_command (cm_function_def, (SIMPLE_COM *)temp));
-}
-
-COMMAND *
-make_subshell_command (command)
- COMMAND *command;
-{
- SUBSHELL_COM *temp;
-
- temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
- temp->command = command;
- temp->flags = CMD_WANT_SUBSHELL;
- return (make_command (cm_subshell, (SIMPLE_COM *)temp));
-}
-
-COMMAND *
-make_coproc_command (name, command)
- char *name;
- COMMAND *command;
-{
- COPROC_COM *temp;
-
- temp = (COPROC_COM *)xmalloc (sizeof (COPROC_COM));
- temp->name = savestring (name);
- temp->command = command;
- temp->flags = CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL;
- return (make_command (cm_coproc, (SIMPLE_COM *)temp));
-}
-
-/* Reverse the word list and redirection list in the simple command
- has just been parsed. It seems simpler to do this here the one
- time then by any other method that I can think of. */
-COMMAND *
-clean_simple_command (command)
- COMMAND *command;
-{
- if (command->type != cm_simple)
- command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0);
- else
- {
- command->value.Simple->words =
- REVERSE_LIST (command->value.Simple->words, WORD_LIST *);
- command->value.Simple->redirects =
- REVERSE_LIST (command->value.Simple->redirects, REDIRECT *);
- }
-
- parser_state &= ~PST_REDIRLIST;
- return (command);
-}
-
-/* The Yacc grammar productions have a problem, in that they take a
- list followed by an ampersand (`&') and do a simple command connection,
- making the entire list effectively asynchronous, instead of just
- the last command. This means that when the list is executed, all
- the commands have stdin set to /dev/null when job control is not
- active, instead of just the last. This is wrong, and needs fixing
- up. This function takes the `&' and applies it to the last command
- in the list. This is done only for lists connected by `;'; it makes
- `;' bind `tighter' than `&'. */
-COMMAND *
-connect_async_list (command, command2, connector)
- COMMAND *command, *command2;
- int connector;
-{
- COMMAND *t, *t1, *t2;
-
- t1 = command;
- t = command->value.Connection->second;
-
- if (!t || (command->flags & CMD_WANT_SUBSHELL) ||
- command->value.Connection->connector != ';')
- {
- t = command_connect (command, command2, connector);
- return t;
- }
-
- /* This is just defensive programming. The Yacc precedence rules
- will generally hand this function a command where t points directly
- to the command we want (e.g. given a ; b ; c ; d &, t1 will point
- to the `a ; b ; c' list and t will be the `d'). We only want to do
- this if the list is not being executed as a unit in the background
- with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's
- the only way to tell. */
- while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection &&
- t->value.Connection->connector == ';')
- {
- t1 = t;
- t = t->value.Connection->second;
- }
- /* Now we have t pointing to the last command in the list, and
- t1->value.Connection->second == t. */
- t2 = command_connect (t, command2, connector);
- t1->value.Connection->second = t2;
- return command;
-}
+++ /dev/null
-/* print_command -- A way to make readable commands from a command tree. */
-
-/* Copyright (C) 1989-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/>.
-*/
-
-#include "config.h"
-
-#include <stdio.h>
-
-#if defined (HAVE_UNISTD_H)
-# ifdef _MINIX
-# include <sys/types.h>
-# endif
-# include <unistd.h>
-#endif
-
-#if defined (PREFER_STDARG)
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#include "bashansi.h"
-#include "bashintl.h"
-
-#include "shell.h"
-#include "flags.h"
-#include <y.tab.h> /* use <...> so we pick it up from the build directory */
-
-#include "shmbutil.h"
-
-#include "builtins/common.h"
-
-#if !HAVE_DECL_PRINTF
-extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */
-#endif
-
-extern int indirection_level;
-
-static int indentation;
-static int indentation_amount = 4;
-
-#if defined (PREFER_STDARG)
-typedef void PFUNC __P((const char *, ...));
-
-static void cprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
-static void xprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
-#else
-#define PFUNC VFunction
-static void cprintf ();
-static void xprintf ();
-#endif
-
-static void reset_locals __P((void));
-static void newline __P((char *));
-static void indent __P((int));
-static void semicolon __P((void));
-static void the_printed_command_resize __P((int));
-
-static void make_command_string_internal __P((COMMAND *));
-static void _print_word_list __P((WORD_LIST *, char *, PFUNC *));
-static void command_print_word_list __P((WORD_LIST *, char *));
-static void print_case_clauses __P((PATTERN_LIST *));
-static void print_redirection_list __P((REDIRECT *));
-static void print_redirection __P((REDIRECT *));
-static void print_heredoc_header __P((REDIRECT *));
-static void print_heredoc_body __P((REDIRECT *));
-static void print_heredocs __P((REDIRECT *));
-static void print_deferred_heredocs __P((const char *));
-
-static void print_for_command __P((FOR_COM *));
-#if defined (ARITH_FOR_COMMAND)
-static void print_arith_for_command __P((ARITH_FOR_COM *));
-#endif
-#if defined (SELECT_COMMAND)
-static void print_select_command __P((SELECT_COM *));
-#endif
-static void print_group_command __P((GROUP_COM *));
-static void print_case_command __P((CASE_COM *));
-static void print_while_command __P((WHILE_COM *));
-static void print_until_command __P((WHILE_COM *));
-static void print_until_or_while __P((WHILE_COM *, char *));
-static void print_if_command __P((IF_COM *));
-#if defined (COND_COMMAND)
-static void print_cond_node __P((COND_COM *));
-#endif
-static void print_function_def __P((FUNCTION_DEF *));
-
-#define PRINTED_COMMAND_INITIAL_SIZE 64
-#define PRINTED_COMMAND_GROW_SIZE 128
-
-char *the_printed_command = (char *)NULL;
-int the_printed_command_size = 0;
-int command_string_index = 0;
-
-int xtrace_fd = -1;
-FILE *xtrace_fp = 0;
-
-#define CHECK_XTRACE_FP xtrace_fp = (xtrace_fp ? xtrace_fp : stderr)
-
-/* shell expansion characters: used in print_redirection_list */
-#define EXPCHAR(c) ((c) == '{' || (c) == '~' || (c) == '$' || (c) == '`')
-
-#define PRINT_DEFERRED_HEREDOCS(x) \
- do { \
- if (deferred_heredocs) \
- print_deferred_heredocs (x); \
- } while (0)
-
-/* Non-zero means the stuff being printed is inside of a function def. */
-static int inside_function_def;
-static int skip_this_indent;
-static int was_heredoc;
-static int printing_connection;
-static REDIRECT *deferred_heredocs;
-
-/* The depth of the group commands that we are currently printing. This
- includes the group command that is a function body. */
-static int group_command_nesting;
-
-/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */
-static char *indirection_string = 0;
-static int indirection_stringsiz = 0;
-
-/* Print COMMAND (a command tree) on standard output. */
-void
-print_command (command)
- COMMAND *command;
-{
- command_string_index = 0;
- printf ("%s", make_command_string (command));
-}
-
-/* Make a string which is the printed representation of the command
- tree in COMMAND. We return this string. However, the string is
- not consed, so you have to do that yourself if you want it to
- remain around. */
-char *
-make_command_string (command)
- COMMAND *command;
-{
- command_string_index = was_heredoc = 0;
- deferred_heredocs = 0;
- make_command_string_internal (command);
- return (the_printed_command);
-}
-
-/* The internal function. This is the real workhorse. */
-static void
-make_command_string_internal (command)
- COMMAND *command;
-{
- char s[3];
-
- if (command == 0)
- cprintf ("");
- else
- {
- if (skip_this_indent)
- skip_this_indent--;
- else
- indent (indentation);
-
- if (command->flags & CMD_TIME_PIPELINE)
- {
- cprintf ("time ");
- if (command->flags & CMD_TIME_POSIX)
- cprintf ("-p ");
- }
-
- if (command->flags & CMD_INVERT_RETURN)
- cprintf ("! ");
-
- switch (command->type)
- {
- case cm_for:
- print_for_command (command->value.For);
- break;
-
-#if defined (ARITH_FOR_COMMAND)
- case cm_arith_for:
- print_arith_for_command (command->value.ArithFor);
- break;
-#endif
-
-#if defined (SELECT_COMMAND)
- case cm_select:
- print_select_command (command->value.Select);
- break;
-#endif
-
- case cm_case:
- print_case_command (command->value.Case);
- break;
-
- case cm_while:
- print_while_command (command->value.While);
- break;
-
- case cm_until:
- print_until_command (command->value.While);
- break;
-
- case cm_if:
- print_if_command (command->value.If);
- break;
-
-#if defined (DPAREN_ARITHMETIC)
- case cm_arith:
- print_arith_command (command->value.Arith->exp);
- break;
-#endif
-
-#if defined (COND_COMMAND)
- case cm_cond:
- print_cond_command (command->value.Cond);
- break;
-#endif
-
- case cm_simple:
- print_simple_command (command->value.Simple);
- break;
-
- case cm_connection:
-
- skip_this_indent++;
- printing_connection++;
- make_command_string_internal (command->value.Connection->first);
-
- switch (command->value.Connection->connector)
- {
- case '&':
- case '|':
- {
- char c = command->value.Connection->connector;
-
- s[0] = ' ';
- s[1] = c;
- s[2] = '\0';
-
- print_deferred_heredocs (s);
-
- if (c != '&' || command->value.Connection->second)
- {
- cprintf (" ");
- skip_this_indent++;
- }
- }
- break;
-
- case AND_AND:
- print_deferred_heredocs (" && ");
- if (command->value.Connection->second)
- skip_this_indent++;
- break;
-
- case OR_OR:
- print_deferred_heredocs (" || ");
- if (command->value.Connection->second)
- skip_this_indent++;
- break;
-
- case ';':
- if (deferred_heredocs == 0)
- {
- if (was_heredoc == 0)
- cprintf (";");
- else
- was_heredoc = 0;
- }
- else
- print_deferred_heredocs (inside_function_def ? "" : ";");
-
- if (inside_function_def)
- cprintf ("\n");
- else
- {
- cprintf (" ");
- if (command->value.Connection->second)
- skip_this_indent++;
- }
- break;
-
- default:
- cprintf (_("print_command: bad connector `%d'"),
- command->value.Connection->connector);
- break;
- }
-
- make_command_string_internal (command->value.Connection->second);
- PRINT_DEFERRED_HEREDOCS ("");
- printing_connection--;
- break;
-
- case cm_function_def:
- print_function_def (command->value.Function_def);
- break;
-
- case cm_group:
- print_group_command (command->value.Group);
- break;
-
- case cm_subshell:
- cprintf ("( ");
- skip_this_indent++;
- make_command_string_internal (command->value.Subshell->command);
- PRINT_DEFERRED_HEREDOCS ("");
- cprintf (" )");
- break;
-
- case cm_coproc:
- cprintf ("coproc %s ", command->value.Coproc->name);
- skip_this_indent++;
- make_command_string_internal (command->value.Coproc->command);
- break;
-
- default:
- command_error ("print_command", CMDERR_BADTYPE, command->type, 0);
- break;
- }
-
-
- if (command->redirects)
- {
- cprintf (" ");
- print_redirection_list (command->redirects);
- }
- }
-}
-
-static void
-_print_word_list (list, separator, pfunc)
- WORD_LIST *list;
- char *separator;
- PFUNC *pfunc;
-{
- WORD_LIST *w;
-
- for (w = list; w; w = w->next)
- (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
-}
-
-void
-print_word_list (list, separator)
- WORD_LIST *list;
- char *separator;
-{
- _print_word_list (list, separator, xprintf);
-}
-
-void
-xtrace_set (fd, fp)
- int fd;
- FILE *fp;
-{
- if (fd >= 0 && sh_validfd (fd) == 0)
- {
- internal_error (_("xtrace_set: %d: invalid file descriptor"), fd);
- return;
- }
- if (fp == 0)
- {
- internal_error (_("xtrace_set: NULL file pointer"));
- return;
- }
- if (fd >= 0 && fileno (fp) != fd)
- internal_warning (_("xtrace fd (%d) != fileno xtrace fp (%d)"), fd, fileno (fp));
-
- xtrace_fd = fd;
- xtrace_fp = fp;
-}
-
-void
-xtrace_init ()
-{
- xtrace_set (-1, stderr);
-}
-
-void
-xtrace_reset ()
-{
- if (xtrace_fd >= 0 && xtrace_fp)
- {
- fflush (xtrace_fp);
- fclose (xtrace_fp);
- }
- else if (xtrace_fd >= 0)
- close (xtrace_fd);
-
- xtrace_fd = -1;
- xtrace_fp = stderr;
-}
-
-void
-xtrace_fdchk (fd)
- int fd;
-{
- if (fd == xtrace_fd)
- xtrace_reset ();
-}
-
-/* Return a string denoting what our indirection level is. */
-
-char *
-indirection_level_string ()
-{
- register int i, j;
- char *ps4;
- char ps4_firstc[MB_LEN_MAX+1];
- int ps4_firstc_len, ps4_len, ineed, old;
-
- ps4 = get_string_value ("PS4");
- if (indirection_string == 0)
- indirection_string = xmalloc (indirection_stringsiz = 100);
- indirection_string[0] = '\0';
-
- if (ps4 == 0 || *ps4 == '\0')
- return (indirection_string);
-
- old = change_flag ('x', FLAG_OFF);
- ps4 = decode_prompt_string (ps4);
- if (old)
- change_flag ('x', FLAG_ON);
-
- if (ps4 == 0 || *ps4 == '\0')
- return (indirection_string);
-
-#if defined (HANDLE_MULTIBYTE)
- ps4_len = strnlen (ps4, MB_CUR_MAX);
- ps4_firstc_len = MBLEN (ps4, ps4_len);
- if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || ps4_firstc_len < 0)
- {
- ps4_firstc[0] = ps4[0];
- ps4_firstc[ps4_firstc_len = 1] = '\0';
- }
- else
- memcpy (ps4_firstc, ps4, ps4_firstc_len);
-#else
- ps4_firstc[0] = ps4[0];
- ps4_firstc[ps4_firstc_len = 1] = '\0';
-#endif
-
- /* Dynamically resize indirection_string so we have room for everything
- and we don't have to truncate ps4 */
- ineed = (ps4_firstc_len * indirection_level) + strlen (ps4);
- if (ineed > indirection_stringsiz - 1)
- {
- indirection_stringsiz = ineed + 1;
- indirection_string = xrealloc (indirection_string, indirection_stringsiz);
- }
-
- for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < indirection_stringsiz - 1; i += ps4_firstc_len, j++)
- {
- if (ps4_firstc_len == 1)
- indirection_string[i] = ps4_firstc[0];
- else
- memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len);
- }
-
- for (j = ps4_firstc_len; *ps4 && ps4[j] && i < indirection_stringsiz - 1; i++, j++)
- indirection_string[i] = ps4[j];
-
- indirection_string[i] = '\0';
- free (ps4);
- return (indirection_string);
-}
-
-void
-xtrace_print_assignment (name, value, assign_list, xflags)
- char *name, *value;
- int assign_list, xflags;
-{
- char *nval;
-
- CHECK_XTRACE_FP;
-
- if (xflags)
- fprintf (xtrace_fp, "%s", indirection_level_string ());
-
- /* VALUE should not be NULL when this is called. */
- if (*value == '\0' || assign_list)
- nval = value;
- else if (sh_contains_shell_metas (value))
- nval = sh_single_quote (value);
- else if (ansic_shouldquote (value))
- nval = ansic_quote (value, 0, (int *)0);
- else
- nval = value;
-
- if (assign_list)
- fprintf (xtrace_fp, "%s=(%s)\n", name, nval);
- else
- fprintf (xtrace_fp, "%s=%s\n", name, nval);
-
- if (nval != value)
- FREE (nval);
-
- fflush (xtrace_fp);
-}
-
-/* A function to print the words of a simple command when set -x is on. */
-void
-xtrace_print_word_list (list, xtflags)
- WORD_LIST *list;
- int xtflags;
-{
- WORD_LIST *w;
- char *t, *x;
-
- CHECK_XTRACE_FP;
-
- if (xtflags)
- fprintf (xtrace_fp, "%s", indirection_level_string ());
-
- for (w = list; w; w = w->next)
- {
- t = w->word->word;
- if (t == 0 || *t == '\0')
- fprintf (xtrace_fp, "''%s", w->next ? " " : "");
- else if (sh_contains_shell_metas (t))
- {
- x = sh_single_quote (t);
- fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
- free (x);
- }
- else if (ansic_shouldquote (t))
- {
- x = ansic_quote (t, 0, (int *)0);
- fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
- free (x);
- }
- else
- fprintf (xtrace_fp, "%s%s", t, w->next ? " " : "");
- }
- fprintf (xtrace_fp, "\n");
- fflush (xtrace_fp);
-}
-
-static void
-command_print_word_list (list, separator)
- WORD_LIST *list;
- char *separator;
-{
- _print_word_list (list, separator, cprintf);
-}
-
-void
-print_for_command_head (for_command)
- FOR_COM *for_command;
-{
- cprintf ("for %s in ", for_command->name->word);
- command_print_word_list (for_command->map_list, " ");
-}
-
-void
-xtrace_print_for_command_head (for_command)
- FOR_COM *for_command;
-{
- CHECK_XTRACE_FP;
- fprintf (xtrace_fp, "%s", indirection_level_string ());
- fprintf (xtrace_fp, "for %s in ", for_command->name->word);
- xtrace_print_word_list (for_command->map_list, 0);
-}
-
-static void
-print_for_command (for_command)
- FOR_COM *for_command;
-{
- print_for_command_head (for_command);
- cprintf (";");
- newline ("do\n");
-
- indentation += indentation_amount;
- make_command_string_internal (for_command->action);
- PRINT_DEFERRED_HEREDOCS ("");
- semicolon ();
- indentation -= indentation_amount;
-
- newline ("done");
-}
-
-#if defined (ARITH_FOR_COMMAND)
-static void
-print_arith_for_command (arith_for_command)
- ARITH_FOR_COM *arith_for_command;
-{
- cprintf ("for ((");
- command_print_word_list (arith_for_command->init, " ");
- cprintf ("; ");
- command_print_word_list (arith_for_command->test, " ");
- cprintf ("; ");
- command_print_word_list (arith_for_command->step, " ");
- cprintf ("))");
- newline ("do\n");
- indentation += indentation_amount;
- make_command_string_internal (arith_for_command->action);
- PRINT_DEFERRED_HEREDOCS ("");
- semicolon ();
- indentation -= indentation_amount;
- newline ("done");
-}
-#endif /* ARITH_FOR_COMMAND */
-
-#if defined (SELECT_COMMAND)
-void
-print_select_command_head (select_command)
- SELECT_COM *select_command;
-{
- cprintf ("select %s in ", select_command->name->word);
- command_print_word_list (select_command->map_list, " ");
-}
-
-void
-xtrace_print_select_command_head (select_command)
- SELECT_COM *select_command;
-{
- CHECK_XTRACE_FP;
- fprintf (xtrace_fp, "%s", indirection_level_string ());
- fprintf (xtrace_fp, "select %s in ", select_command->name->word);
- xtrace_print_word_list (select_command->map_list, 0);
-}
-
-static void
-print_select_command (select_command)
- SELECT_COM *select_command;
-{
- print_select_command_head (select_command);
-
- cprintf (";");
- newline ("do\n");
- indentation += indentation_amount;
- make_command_string_internal (select_command->action);
- PRINT_DEFERRED_HEREDOCS ("");
- semicolon ();
- indentation -= indentation_amount;
- newline ("done");
-}
-#endif /* SELECT_COMMAND */
-
-static void
-print_group_command (group_command)
- GROUP_COM *group_command;
-{
- group_command_nesting++;
- cprintf ("{ ");
-
- if (inside_function_def == 0)
- skip_this_indent++;
- else
- {
- /* This is a group command { ... } inside of a function
- definition, and should be printed as a multiline group
- command, using the current indentation. */
- cprintf ("\n");
- indentation += indentation_amount;
- }
-
- make_command_string_internal (group_command->command);
- PRINT_DEFERRED_HEREDOCS ("");
-
- if (inside_function_def)
- {
- cprintf ("\n");
- indentation -= indentation_amount;
- indent (indentation);
- }
- else
- {
- semicolon ();
- cprintf (" ");
- }
-
- cprintf ("}");
-
- group_command_nesting--;
-}
-
-void
-print_case_command_head (case_command)
- CASE_COM *case_command;
-{
- cprintf ("case %s in ", case_command->word->word);
-}
-
-void
-xtrace_print_case_command_head (case_command)
- CASE_COM *case_command;
-{
- CHECK_XTRACE_FP;
- fprintf (xtrace_fp, "%s", indirection_level_string ());
- fprintf (xtrace_fp, "case %s in\n", case_command->word->word);
-}
-
-static void
-print_case_command (case_command)
- CASE_COM *case_command;
-{
- print_case_command_head (case_command);
-
- if (case_command->clauses)
- print_case_clauses (case_command->clauses);
- newline ("esac");
-}
-
-static void
-print_case_clauses (clauses)
- PATTERN_LIST *clauses;
-{
- indentation += indentation_amount;
- while (clauses)
- {
- newline ("");
- command_print_word_list (clauses->patterns, " | ");
- cprintf (")\n");
- indentation += indentation_amount;
- make_command_string_internal (clauses->action);
- indentation -= indentation_amount;
- PRINT_DEFERRED_HEREDOCS ("");
- if (clauses->flags & CASEPAT_FALLTHROUGH)
- newline (";&");
- else if (clauses->flags & CASEPAT_TESTNEXT)
- newline (";;&");
- else
- newline (";;");
- clauses = clauses->next;
- }
- indentation -= indentation_amount;
-}
-
-static void
-print_while_command (while_command)
- WHILE_COM *while_command;
-{
- print_until_or_while (while_command, "while");
-}
-
-static void
-print_until_command (while_command)
- WHILE_COM *while_command;
-{
- print_until_or_while (while_command, "until");
-}
-
-static void
-print_until_or_while (while_command, which)
- WHILE_COM *while_command;
- char *which;
-{
- cprintf ("%s ", which);
- skip_this_indent++;
- make_command_string_internal (while_command->test);
- PRINT_DEFERRED_HEREDOCS ("");
- semicolon ();
- cprintf (" do\n"); /* was newline ("do\n"); */
- indentation += indentation_amount;
- make_command_string_internal (while_command->action);
- PRINT_DEFERRED_HEREDOCS ("");
- indentation -= indentation_amount;
- semicolon ();
- newline ("done");
-}
-
-static void
-print_if_command (if_command)
- IF_COM *if_command;
-{
- cprintf ("if ");
- skip_this_indent++;
- make_command_string_internal (if_command->test);
- semicolon ();
- cprintf (" then\n");
- indentation += indentation_amount;
- make_command_string_internal (if_command->true_case);
- PRINT_DEFERRED_HEREDOCS ("");
- indentation -= indentation_amount;
-
- if (if_command->false_case)
- {
- semicolon ();
- newline ("else\n");
- indentation += indentation_amount;
- make_command_string_internal (if_command->false_case);
- PRINT_DEFERRED_HEREDOCS ("");
- indentation -= indentation_amount;
- }
- semicolon ();
- newline ("fi");
-}
-
-#if defined (DPAREN_ARITHMETIC)
-void
-print_arith_command (arith_cmd_list)
- WORD_LIST *arith_cmd_list;
-{
- cprintf ("((");
- command_print_word_list (arith_cmd_list, " ");
- cprintf ("))");
-}
-#endif
-
-#if defined (COND_COMMAND)
-static void
-print_cond_node (cond)
- COND_COM *cond;
-{
- if (cond->flags & CMD_INVERT_RETURN)
- cprintf ("! ");
-
- if (cond->type == COND_EXPR)
- {
- cprintf ("( ");
- print_cond_node (cond->left);
- cprintf (" )");
- }
- else if (cond->type == COND_AND)
- {
- print_cond_node (cond->left);
- cprintf (" && ");
- print_cond_node (cond->right);
- }
- else if (cond->type == COND_OR)
- {
- print_cond_node (cond->left);
- cprintf (" || ");
- print_cond_node (cond->right);
- }
- else if (cond->type == COND_UNARY)
- {
- cprintf ("%s", cond->op->word);
- cprintf (" ");
- print_cond_node (cond->left);
- }
- else if (cond->type == COND_BINARY)
- {
- print_cond_node (cond->left);
- cprintf (" ");
- cprintf ("%s", cond->op->word);
- cprintf (" ");
- print_cond_node (cond->right);
- }
- else if (cond->type == COND_TERM)
- {
- cprintf ("%s", cond->op->word); /* need to add quoting here */
- }
-}
-
-void
-print_cond_command (cond)
- COND_COM *cond;
-{
- cprintf ("[[ ");
- print_cond_node (cond);
- cprintf (" ]]");
-}
-
-#ifdef DEBUG
-void
-debug_print_word_list (s, list, sep)
- char *s;
- WORD_LIST *list;
- char *sep;
-{
- WORD_LIST *w;
-
- if (s)
- fprintf (stderr, "%s: ", s);
- for (w = list; w; w = w->next)
- fprintf (stderr, "%s%s", w->word->word, w->next ? sep : "");
- fprintf (stderr, "\n");
-}
-
-void
-debug_print_cond_command (cond)
- COND_COM *cond;
-{
- fprintf (stderr, "DEBUG: ");
- command_string_index = 0;
- print_cond_command (cond);
- fprintf (stderr, "%s\n", the_printed_command);
-}
-#endif
-
-void
-xtrace_print_cond_term (type, invert, op, arg1, arg2)
- int type, invert;
- WORD_DESC *op;
- char *arg1, *arg2;
-{
- CHECK_XTRACE_FP;
- command_string_index = 0;
- fprintf (xtrace_fp, "%s", indirection_level_string ());
- fprintf (xtrace_fp, "[[ ");
- if (invert)
- fprintf (xtrace_fp, "! ");
-
- if (type == COND_UNARY)
- {
- fprintf (xtrace_fp, "%s ", op->word);
- fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
- }
- else if (type == COND_BINARY)
- {
- fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
- fprintf (xtrace_fp, " %s ", op->word);
- fprintf (xtrace_fp, "%s", (arg2 && *arg2) ? arg2 : "''");
- }
-
- fprintf (xtrace_fp, " ]]\n");
-
- fflush (xtrace_fp);
-}
-#endif /* COND_COMMAND */
-
-#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
-/* A function to print the words of an arithmetic command when set -x is on. */
-void
-xtrace_print_arith_cmd (list)
- WORD_LIST *list;
-{
- WORD_LIST *w;
-
- CHECK_XTRACE_FP;
- fprintf (xtrace_fp, "%s", indirection_level_string ());
- fprintf (xtrace_fp, "(( ");
- for (w = list; w; w = w->next)
- fprintf (xtrace_fp, "%s%s", w->word->word, w->next ? " " : "");
- fprintf (xtrace_fp, " ))\n");
-
- fflush (xtrace_fp);
-}
-#endif
-
-void
-print_simple_command (simple_command)
- SIMPLE_COM *simple_command;
-{
- command_print_word_list (simple_command->words, " ");
-
- if (simple_command->redirects)
- {
- cprintf (" ");
- print_redirection_list (simple_command->redirects);
- }
-}
-
-static void
-print_heredocs (heredocs)
- REDIRECT *heredocs;
-{
- REDIRECT *hdtail;
-
- cprintf (" ");
- for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
- {
- print_redirection (hdtail);
- cprintf ("\n");
- }
- was_heredoc = 1;
-}
-
-/* Print heredocs that are attached to the command before the connector
- represented by CSTRING. The parsing semantics require us to print the
- here-doc delimiters, then the connector (CSTRING), then the here-doc
- bodies. We don't print the connector if it's a `;', but we use it to
- note not to print an extra space after the last heredoc body and
- newline. */
-static void
-print_deferred_heredocs (cstring)
- const char *cstring;
-{
- REDIRECT *hdtail;
-
- for (hdtail = deferred_heredocs; hdtail; hdtail = hdtail->next)
- {
- cprintf (" ");
- print_heredoc_header (hdtail);
- }
- if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
- cprintf ("%s", cstring);
- if (deferred_heredocs)
- cprintf ("\n");
- for (hdtail = deferred_heredocs; hdtail; hdtail = hdtail->next)
- {
- print_heredoc_body (hdtail);
- cprintf ("\n");
- }
- if (deferred_heredocs)
- {
- if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
- cprintf (" "); /* make sure there's at least one space */
- dispose_redirects (deferred_heredocs);
- was_heredoc = 1;
- }
- deferred_heredocs = (REDIRECT *)NULL;
-}
-
-static void
-print_redirection_list (redirects)
- REDIRECT *redirects;
-{
- REDIRECT *heredocs, *hdtail, *newredir;
- char *rw;
-
- heredocs = (REDIRECT *)NULL;
- hdtail = heredocs;
-
- was_heredoc = 0;
- while (redirects)
- {
- /* Defer printing the here documents until we've printed the
- rest of the redirections. */
- if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
- {
- newredir = copy_redirect (redirects);
- newredir->next = (REDIRECT *)NULL;
- if (heredocs)
- {
- hdtail->next = newredir;
- hdtail = newredir;
- }
- else
- hdtail = heredocs = newredir;
- }
- else if (redirects->instruction == r_duplicating_output_word && (redirects->flags & REDIR_VARASSIGN) == 0 && redirects->redirector.dest == 1)
- {
- /* Temporarily translate it as the execution code does. */
- rw = redirects->redirectee.filename->word;
- if (rw && *rw != '-' && DIGIT (*rw) == 0 && EXPCHAR (*rw) == 0)
- redirects->instruction = r_err_and_out;
- print_redirection (redirects);
- redirects->instruction = r_duplicating_output_word;
- }
- else
- print_redirection (redirects);
-
- redirects = redirects->next;
- if (redirects)
- cprintf (" ");
- }
-
- /* Now that we've printed all the other redirections (on one line),
- print the here documents. */
- if (heredocs && printing_connection)
- deferred_heredocs = heredocs;
- else if (heredocs)
- {
- print_heredocs (heredocs);
- dispose_redirects (heredocs);
- }
-}
-
-static void
-print_heredoc_header (redirect)
- REDIRECT *redirect;
-{
- int kill_leading;
- char *x;
-
- kill_leading = redirect->instruction == r_deblank_reading_until;
-
- /* Here doc header */
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redirect->redirector.filename->word);
- else if (redirect->redirector.dest != 0)
- cprintf ("%d", redirect->redirector.dest);
-
- /* If the here document delimiter is quoted, single-quote it. */
- if (redirect->redirectee.filename->flags & W_QUOTED)
- {
- x = sh_single_quote (redirect->here_doc_eof);
- cprintf ("<<%s%s", kill_leading ? "-" : "", x);
- free (x);
- }
- else
- cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof);
-}
-
-static void
-print_heredoc_body (redirect)
- REDIRECT *redirect;
-{
- /* Here doc body */
- cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof);
-}
-
-static void
-print_redirection (redirect)
- REDIRECT *redirect;
-{
- int redirector, redir_fd;
- WORD_DESC *redirectee, *redir_word;
-
- redirectee = redirect->redirectee.filename;
- redir_fd = redirect->redirectee.dest;
-
- redir_word = redirect->redirector.filename;
- redirector = redirect->redirector.dest;
-
- switch (redirect->instruction)
- {
- case r_input_direction:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 0)
- cprintf ("%d", redirector);
- cprintf ("< %s", redirectee->word);
- break;
-
- case r_output_direction:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 1)
- cprintf ("%d", redirector);
- cprintf ("> %s", redirectee->word);
- break;
-
- case r_inputa_direction: /* Redirection created by the shell. */
- cprintf ("&");
- break;
-
- case r_output_force:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 1)
- cprintf ("%d", redirector);
- cprintf (">| %s", redirectee->word);
- break;
-
- case r_appending_to:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 1)
- cprintf ("%d", redirector);
- cprintf (">> %s", redirectee->word);
- break;
-
- case r_input_output:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 1)
- cprintf ("%d", redirector);
- cprintf ("<> %s", redirectee->word);
- break;
-
- case r_deblank_reading_until:
- case r_reading_until:
- print_heredoc_header (redirect);
- cprintf ("\n");
- print_heredoc_body (redirect);
- break;
-
- case r_reading_string:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}", redir_word->word);
- else if (redirector != 0)
- cprintf ("%d", redirector);
-#if 0
- /* Don't need to check whether or not to requote, since original quotes
- are still intact. The only thing that has happened is that $'...'
- has been replaced with 'expanded ...'. */
- if (ansic_shouldquote (redirect->redirectee.filename->word))
- {
- char *x;
- x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0);
- cprintf ("<<< %s", x);
- free (x);
- }
- else
-#endif
- cprintf ("<<< %s", redirect->redirectee.filename->word);
- break;
-
- case r_duplicating_input:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}<&%d", redir_word->word, redir_fd);
- else
- cprintf ("%d<&%d", redirector, redir_fd);
- break;
-
- case r_duplicating_output:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}>&%d", redir_word->word, redir_fd);
- else
- cprintf ("%d>&%d", redirector, redir_fd);
- break;
-
- case r_duplicating_input_word:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}<&%s", redir_word->word, redirectee->word);
- else
- cprintf ("%d<&%s", redirector, redirectee->word);
- break;
-
- case r_duplicating_output_word:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}>&%s", redir_word->word, redirectee->word);
- else
- cprintf ("%d>&%s", redirector, redirectee->word);
- break;
-
- case r_move_input:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}<&%d-", redir_word->word, redir_fd);
- else
- cprintf ("%d<&%d-", redirector, redir_fd);
- break;
-
- case r_move_output:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}>&%d-", redir_word->word, redir_fd);
- else
- cprintf ("%d>&%d-", redirector, redir_fd);
- break;
-
- case r_move_input_word:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}<&%s-", redir_word->word, redirectee->word);
- else
- cprintf ("%d<&%s-", redirector, redirectee->word);
- break;
-
- case r_move_output_word:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}>&%s-", redir_word->word, redirectee->word);
- else
- cprintf ("%d>&%s-", redirector, redirectee->word);
- break;
-
- case r_close_this:
- if (redirect->rflags & REDIR_VARASSIGN)
- cprintf ("{%s}>&-", redir_word->word);
- else
- cprintf ("%d>&-", redirector);
- break;
-
- case r_err_and_out:
- cprintf ("&> %s", redirectee->word);
- break;
-
- case r_append_err_and_out:
- cprintf ("&>> %s", redirectee->word);
- break;
- }
-}
-
-static void
-reset_locals ()
-{
- inside_function_def = 0;
- indentation = 0;
- printing_connection = 0;
- deferred_heredocs = 0;
-}
-
-static void
-print_function_def (func)
- FUNCTION_DEF *func;
-{
- COMMAND *cmdcopy;
- REDIRECT *func_redirects;
-
- func_redirects = NULL;
- /* When in posix mode, print functions as posix specifies them. */
- if (posixly_correct == 0)
- cprintf ("function %s () \n", func->name->word);
- else
- cprintf ("%s () \n", func->name->word);
- add_unwind_protect (reset_locals, 0);
-
- indent (indentation);
- cprintf ("{ \n");
-
- inside_function_def++;
- indentation += indentation_amount;
-
- cmdcopy = copy_command (func->command);
- if (cmdcopy->type == cm_group)
- {
- func_redirects = cmdcopy->redirects;
- cmdcopy->redirects = (REDIRECT *)NULL;
- }
- make_command_string_internal (cmdcopy->type == cm_group
- ? cmdcopy->value.Group->command
- : cmdcopy);
- /* XXX - PRINT_DEFERRED_HEREDOCS (""); ? */
-
- remove_unwind_protect ();
- indentation -= indentation_amount;
- inside_function_def--;
-
- if (func_redirects)
- { /* { */
- newline ("} ");
- print_redirection_list (func_redirects);
- cmdcopy->redirects = func_redirects;
- }
- else
- newline ("}");
-
- dispose_command (cmdcopy);
-}
-
-/* Return the string representation of the named function.
- NAME is the name of the function.
- COMMAND is the function body. It should be a GROUP_COM.
- flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line.
- flags&FUNC_EXTERNAL means convert from internal to external form
- */
-char *
-named_function_string (name, command, flags)
- char *name;
- COMMAND *command;
- int flags;
-{
- char *result;
- int old_indent, old_amount;
- COMMAND *cmdcopy;
- REDIRECT *func_redirects;
-
- old_indent = indentation;
- old_amount = indentation_amount;
- command_string_index = was_heredoc = 0;
- deferred_heredocs = 0;
-
- if (name && *name)
- cprintf ("%s ", name);
-
- cprintf ("() ");
-
- if ((flags & FUNC_MULTILINE) == 0)
- {
- indentation = 1;
- indentation_amount = 0;
- }
- else
- {
- cprintf ("\n");
- indentation += indentation_amount;
- }
-
- inside_function_def++;
-
- cprintf ((flags & FUNC_MULTILINE) ? "{ \n" : "{ ");
-
- cmdcopy = copy_command (command);
- /* Take any redirections specified in the function definition (which should
- apply to the function as a whole) and save them for printing later. */
- func_redirects = (REDIRECT *)NULL;
- if (cmdcopy->type == cm_group)
- {
- func_redirects = cmdcopy->redirects;
- cmdcopy->redirects = (REDIRECT *)NULL;
- }
- make_command_string_internal (cmdcopy->type == cm_group
- ? cmdcopy->value.Group->command
- : cmdcopy);
- /* XXX - PRINT_DEFERRED_HEREDOCS (""); ? */
-
- indentation = old_indent;
- indentation_amount = old_amount;
- inside_function_def--;
-
- if (func_redirects)
- { /* { */
- newline ("} ");
- print_redirection_list (func_redirects);
- cmdcopy->redirects = func_redirects;
- }
- else
- newline ("}");
-
- result = the_printed_command;
-
- if ((flags & FUNC_MULTILINE) == 0)
- {
-#if 0
- register int i;
- for (i = 0; result[i]; i++)
- if (result[i] == '\n')
- {
- strcpy (result + i, result + i + 1);
- --i;
- }
-#else
- if (result[2] == '\n') /* XXX -- experimental */
- memmove (result + 2, result + 3, strlen (result) - 2);
-
-#endif
- }
-
- dispose_command (cmdcopy);
-
- if (flags & FUNC_EXTERNAL)
- result = remove_quoted_escapes (result);
-
- return (result);
-}
-
-static void
-newline (string)
- char *string;
-{
- cprintf ("\n");
- indent (indentation);
- if (string && *string)
- cprintf ("%s", string);
-}
-
-static char *indentation_string;
-static int indentation_size;
-
-static void
-indent (amount)
- int amount;
-{
- register int i;
-
- RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
-
- for (i = 0; amount > 0; amount--)
- indentation_string[i++] = ' ';
- indentation_string[i] = '\0';
- cprintf ("%s", indentation_string);
-}
-
-static void
-semicolon ()
-{
- if (command_string_index > 0 &&
- (the_printed_command[command_string_index - 1] == '&' ||
- the_printed_command[command_string_index - 1] == '\n'))
- return;
- cprintf (";");
-}
-
-/* How to make the string. */
-static void
-#if defined (PREFER_STDARG)
-cprintf (const char *control, ...)
-#else
-cprintf (control, va_alist)
- const char *control;
- va_dcl
-#endif
-{
- register const char *s;
- char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (int) + 1];
- int digit_arg, arg_len, c;
- va_list args;
-
- SH_VA_START (args, control);
-
- arg_len = strlen (control);
- the_printed_command_resize (arg_len + 1);
-
- char_arg[1] = '\0';
- s = control;
- while (s && *s)
- {
- c = *s++;
- argp = (char *)NULL;
- if (c != '%' || !*s)
- {
- char_arg[0] = c;
- argp = char_arg;
- arg_len = 1;
- }
- else
- {
- c = *s++;
- switch (c)
- {
- case '%':
- char_arg[0] = c;
- argp = char_arg;
- arg_len = 1;
- break;
-
- case 's':
- argp = va_arg (args, char *);
- arg_len = strlen (argp);
- break;
-
- case 'd':
- /* Represent an out-of-range file descriptor with an out-of-range
- integer value. We can do this because the only use of `%d' in
- the calls to cprintf is to output a file descriptor number for
- a redirection. */
- digit_arg = va_arg (args, int);
- if (digit_arg < 0)
- {
- sprintf (intbuf, "%u", (unsigned)-1);
- argp = intbuf;
- }
- else
- argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
- arg_len = strlen (argp);
- break;
-
- case 'c':
- char_arg[0] = va_arg (args, int);
- argp = char_arg;
- arg_len = 1;
- break;
-
- default:
- programming_error (_("cprintf: `%c': invalid format character"), c);
- /*NOTREACHED*/
- }
- }
-
- if (argp && arg_len)
- {
- the_printed_command_resize (arg_len + 1);
- FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
- command_string_index += arg_len;
- }
- }
-
- va_end (args);
-
- the_printed_command[command_string_index] = '\0';
-}
-
-/* Ensure that there is enough space to stuff LENGTH characters into
- THE_PRINTED_COMMAND. */
-static void
-the_printed_command_resize (length)
- int length;
-{
- if (the_printed_command == 0)
- {
- the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
- the_printed_command = (char *)xmalloc (the_printed_command_size);
- command_string_index = 0;
- }
- else if ((command_string_index + length) >= the_printed_command_size)
- {
- int new;
- new = command_string_index + length + 1;
-
- /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
- new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
- the_printed_command_size = new;
-
- the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size);
- }
-}
-
-#if defined (HAVE_VPRINTF)
-/* ``If vprintf is available, you may assume that vfprintf and vsprintf are
- also available.'' */
-
-static void
-#if defined (PREFER_STDARG)
-xprintf (const char *format, ...)
-#else
-xprintf (format, va_alist)
- const char *format;
- va_dcl
-#endif
-{
- va_list args;
-
- SH_VA_START (args, format);
-
- vfprintf (stdout, format, args);
- va_end (args);
-}
-
-#else
-
-static void
-xprintf (format, arg1, arg2, arg3, arg4, arg5)
- const char *format;
-{
- printf (format, arg1, arg2, arg3, arg4, arg5);
-}
-
-#endif /* !HAVE_VPRINTF */
+++ /dev/null
-/* shell.c -- GNU's idea of the POSIX shell specification. */
-
-/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
- Birthdate:
- Sunday, January 10th, 1988.
- Initial author: Brian Fox
-*/
-#define INSTALL_DEBUG_MODE
-
-#include "config.h"
-
-#include "bashtypes.h"
-#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
-# include <sys/file.h>
-#endif
-#include "posixstat.h"
-#include "posixtime.h"
-#include "bashansi.h"
-#include <stdio.h>
-#include <signal.h>
-#include <errno.h>
-#include "filecntl.h"
-#include <pwd.h>
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashintl.h"
-
-#define NEED_SH_SETLINEBUF_DECL /* used in externs.h */
-
-#include "shell.h"
-#include "flags.h"
-#include "trap.h"
-#include "mailcheck.h"
-#include "builtins.h"
-#include "builtins/common.h"
-
-#if defined (JOB_CONTROL)
-#include "jobs.h"
-#endif /* JOB_CONTROL */
-
-#include "input.h"
-#include "execute_cmd.h"
-#include "findcmd.h"
-
-#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS)
-# include <malloc/shmalloc.h>
-#endif
-
-#if defined (HISTORY)
-# include "bashhist.h"
-# include <readline/history.h>
-#endif
-
-#if defined (READLINE)
-# include <readline/readline.h>
-# include "bashline.h"
-#endif
-
-#include <tilde/tilde.h>
-#include <glob/strmatch.h>
-
-#if defined (__OPENNT)
-# include <opennt/opennt.h>
-#endif
-
-#if !defined (HAVE_GETPW_DECLS)
-extern struct passwd *getpwuid ();
-#endif /* !HAVE_GETPW_DECLS */
-
-#if !defined (errno)
-extern int errno;
-#endif
-
-#if defined (NO_MAIN_ENV_ARG)
-extern char **environ; /* used if no third argument to main() */
-#endif
-
-extern char *dist_version, *release_status;
-extern int patch_level, build_version;
-extern int shell_level;
-extern int subshell_environment;
-extern int running_in_background;
-extern int last_command_exit_value;
-extern int line_number;
-extern int expand_aliases;
-extern int array_needs_making;
-extern int gnu_error_format;
-extern char *primary_prompt, *secondary_prompt;
-extern char *this_command_name;
-
-/* Non-zero means that this shell has already been run; i.e. you should
- call shell_reinitialize () if you need to start afresh. */
-int shell_initialized = 0;
-
-COMMAND *global_command = (COMMAND *)NULL;
-
-/* Information about the current user. */
-struct user_info current_user =
-{
- (uid_t)-1, (uid_t)-1, (gid_t)-1, (gid_t)-1,
- (char *)NULL, (char *)NULL, (char *)NULL
-};
-
-/* The current host's name. */
-char *current_host_name = (char *)NULL;
-
-/* Non-zero means that this shell is a login shell.
- Specifically:
- 0 = not login shell.
- 1 = login shell from getty (or equivalent fake out)
- -1 = login shell from "--login" (or -l) flag.
- -2 = both from getty, and from flag.
- */
-int login_shell = 0;
-
-/* Non-zero means that at this moment, the shell is interactive. In
- general, this means that the shell is at this moment reading input
- from the keyboard. */
-int interactive = 0;
-
-/* Non-zero means that the shell was started as an interactive shell. */
-int interactive_shell = 0;
-
-/* Non-zero means to send a SIGHUP to all jobs when an interactive login
- shell exits. */
-int hup_on_exit = 0;
-
-/* Non-zero means to list status of running and stopped jobs at shell exit */
-int check_jobs_at_exit = 0;
-
-/* Non-zero means to change to a directory name supplied as a command name */
-int autocd = 0;
-
-/* Tells what state the shell was in when it started:
- 0 = non-interactive shell script
- 1 = interactive
- 2 = -c command
- 3 = wordexp evaluation
- This is a superset of the information provided by interactive_shell.
-*/
-int startup_state = 0;
-
-/* Special debugging helper. */
-int debugging_login_shell = 0;
-
-/* The environment that the shell passes to other commands. */
-char **shell_environment;
-
-/* Non-zero when we are executing a top-level command. */
-int executing = 0;
-
-/* The number of commands executed so far. */
-int current_command_number = 1;
-
-/* Non-zero is the recursion depth for commands. */
-int indirection_level = 0;
-
-/* The name of this shell, as taken from argv[0]. */
-char *shell_name = (char *)NULL;
-
-/* time in seconds when the shell was started */
-time_t shell_start_time;
-
-/* Are we running in an emacs shell window? */
-int running_under_emacs;
-
-/* Do we have /dev/fd? */
-#ifdef HAVE_DEV_FD
-int have_devfd = HAVE_DEV_FD;
-#else
-int have_devfd = 0;
-#endif
-
-/* The name of the .(shell)rc file. */
-static char *bashrc_file = DEFAULT_BASHRC;
-
-/* Non-zero means to act more like the Bourne shell on startup. */
-static int act_like_sh;
-
-/* Non-zero if this shell is being run by `su'. */
-static int su_shell;
-
-/* Non-zero if we have already expanded and sourced $ENV. */
-static int sourced_env;
-
-/* Is this shell running setuid? */
-static int running_setuid;
-
-/* Values for the long-winded argument names. */
-static int debugging; /* Do debugging things. */
-static int no_rc; /* Don't execute ~/.bashrc */
-static int no_profile; /* Don't execute .profile */
-static int do_version; /* Display interesting version info. */
-static int make_login_shell; /* Make this shell be a `-bash' shell. */
-static int want_initial_help; /* --help option */
-
-int debugging_mode = 0; /* In debugging mode with --debugger */
-#if defined (READLINE)
-int no_line_editing = 0; /* non-zero -> don't do fancy line editing. */
-#else
-int no_line_editing = 1; /* can't have line editing without readline */
-#endif
-int dump_translatable_strings; /* Dump strings in $"...", don't execute. */
-int dump_po_strings; /* Dump strings in $"..." in po format */
-int wordexp_only = 0; /* Do word expansion only */
-int protected_mode = 0; /* No command substitution with --wordexp */
-
-#if defined (STRICT_POSIX)
-int posixly_correct = 1; /* Non-zero means posix.2 superset. */
-#else
-int posixly_correct = 0; /* Non-zero means posix.2 superset. */
-#endif
-
-/* Some long-winded argument names. These are obviously new. */
-#define Int 1
-#define Charp 2
-static const struct {
- const char *name;
- int type;
- int *int_value;
- char **char_value;
-} long_args[] = {
- { "debug", Int, &debugging, (char **)0x0 },
-#if defined (DEBUGGER)
- { "debugger", Int, &debugging_mode, (char **)0x0 },
-#endif
- { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 },
- { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 },
- { "help", Int, &want_initial_help, (char **)0x0 },
- { "init-file", Charp, (int *)0x0, &bashrc_file },
- { "login", Int, &make_login_shell, (char **)0x0 },
- { "noediting", Int, &no_line_editing, (char **)0x0 },
- { "noprofile", Int, &no_profile, (char **)0x0 },
- { "norc", Int, &no_rc, (char **)0x0 },
- { "posix", Int, &posixly_correct, (char **)0x0 },
-#if defined (WORDEXP_OPTION)
- { "protected", Int, &protected_mode, (char **)0x0 },
-#endif
- { "rcfile", Charp, (int *)0x0, &bashrc_file },
-#if defined (RESTRICTED_SHELL)
- { "restricted", Int, &restricted, (char **)0x0 },
-#endif
- { "verbose", Int, &echo_input_at_read, (char **)0x0 },
- { "version", Int, &do_version, (char **)0x0 },
-#if defined (WORDEXP_OPTION)
- { "wordexp", Int, &wordexp_only, (char **)0x0 },
-#endif
- { (char *)0x0, Int, (int *)0x0, (char **)0x0 }
-};
-
-/* These are extern so execute_simple_command can set them, and then
- longjmp back to main to execute a shell script, instead of calling
- main () again and resulting in indefinite, possibly fatal, stack
- growth. */
-procenv_t subshell_top_level;
-int subshell_argc;
-char **subshell_argv;
-char **subshell_envp;
-
-char *exec_argv0;
-
-#if defined (BUFFERED_INPUT)
-/* The file descriptor from which the shell is reading input. */
-int default_buffered_input = -1;
-#endif
-
-/* The following two variables are not static so they can show up in $-. */
-int read_from_stdin; /* -s flag supplied */
-int want_pending_command; /* -c flag supplied */
-
-/* This variable is not static so it can be bound to $BASH_EXECUTION_STRING */
-char *command_execution_string; /* argument to -c option */
-
-int malloc_trace_at_exit = 0;
-
-static int shell_reinitialized = 0;
-
-static FILE *default_input;
-
-static STRING_INT_ALIST *shopt_alist;
-static int shopt_ind = 0, shopt_len = 0;
-
-static int parse_long_options __P((char **, int, int));
-static int parse_shell_options __P((char **, int, int));
-static int bind_args __P((char **, int, int, int));
-
-static void start_debugger __P((void));
-
-static void add_shopt_to_alist __P((char *, int));
-static void run_shopt_alist __P((void));
-
-static void execute_env_file __P((char *));
-static void run_startup_files __P((void));
-static int open_shell_script __P((char *));
-static void set_bash_input __P((void));
-static int run_one_command __P((char *));
-#if defined (WORDEXP_OPTION)
-static int run_wordexp __P((char *));
-#endif
-
-static int uidget __P((void));
-
-static void init_interactive __P((void));
-static void init_noninteractive __P((void));
-static void init_interactive_script __P((void));
-
-static void set_shell_name __P((char *));
-static void shell_initialize __P((void));
-static void shell_reinitialize __P((void));
-
-static void show_shell_usage __P((FILE *, int));
-
-#ifdef __CYGWIN__
-static void
-_cygwin32_check_tmp ()
-{
- struct stat sb;
-
- if (stat ("/tmp", &sb) < 0)
- internal_warning (_("could not find /tmp, please create!"));
- else
- {
- if (S_ISDIR (sb.st_mode) == 0)
- internal_warning (_("/tmp must be a valid directory name"));
- }
-}
-#endif /* __CYGWIN__ */
-
-#if defined (NO_MAIN_ENV_ARG)
-/* systems without third argument to main() */
-int
-main (argc, argv)
- int argc;
- char **argv;
-#else /* !NO_MAIN_ENV_ARG */
-int
-main (argc, argv, env)
- int argc;
- char **argv, **env;
-#endif /* !NO_MAIN_ENV_ARG */
-{
- register int i;
- int code, old_errexit_flag;
-#if defined (RESTRICTED_SHELL)
- int saverst;
-#endif
- volatile int locally_skip_execution;
- volatile int arg_index, top_level_arg_index;
-#ifdef __OPENNT
- char **env;
-
- env = environ;
-#endif /* __OPENNT */
-
- USE_VAR(argc);
- USE_VAR(argv);
- USE_VAR(env);
- USE_VAR(code);
- USE_VAR(old_errexit_flag);
-#if defined (RESTRICTED_SHELL)
- USE_VAR(saverst);
-#endif
-
- /* Catch early SIGINTs. */
- code = setjmp_nosigs (top_level);
- if (code)
- exit (2);
-
- xtrace_init ();
-
-#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS)
-# if 1
- malloc_set_register (1);
-# endif
-#endif
-
- check_dev_tty ();
-
-#ifdef __CYGWIN__
- _cygwin32_check_tmp ();
-#endif /* __CYGWIN__ */
-
- /* Wait forever if we are debugging a login shell. */
- while (debugging_login_shell) sleep (3);
-
- set_default_locale ();
-
- running_setuid = uidget ();
-
- if (getenv ("POSIXLY_CORRECT") || getenv ("POSIX_PEDANTIC"))
- posixly_correct = 1;
-
-#if defined (USE_GNU_MALLOC_LIBRARY)
- mcheck (programming_error, (void (*) ())0);
-#endif /* USE_GNU_MALLOC_LIBRARY */
-
- if (setjmp (subshell_top_level))
- {
- argc = subshell_argc;
- argv = subshell_argv;
- env = subshell_envp;
- sourced_env = 0;
- }
-
- shell_reinitialized = 0;
-
- /* Initialize `local' variables for all `invocations' of main (). */
- arg_index = 1;
- if (arg_index > argc)
- arg_index = argc;
- command_execution_string = (char *)NULL;
- want_pending_command = locally_skip_execution = read_from_stdin = 0;
- default_input = stdin;
-#if defined (BUFFERED_INPUT)
- default_buffered_input = -1;
-#endif
-
- /* Fix for the `infinite process creation' bug when running shell scripts
- from startup files on System V. */
- login_shell = make_login_shell = 0;
-
- /* If this shell has already been run, then reinitialize it to a
- vanilla state. */
- if (shell_initialized || shell_name)
- {
- /* Make sure that we do not infinitely recurse as a login shell. */
- if (*shell_name == '-')
- shell_name++;
-
- shell_reinitialize ();
- if (setjmp_nosigs (top_level))
- exit (2);
- }
-
- shell_environment = env;
- set_shell_name (argv[0]);
- shell_start_time = NOW; /* NOW now defined in general.h */
-
- /* Parse argument flags from the input line. */
-
- /* Find full word arguments first. */
- arg_index = parse_long_options (argv, arg_index, argc);
-
- if (want_initial_help)
- {
- show_shell_usage (stdout, 1);
- exit (EXECUTION_SUCCESS);
- }
-
- if (do_version)
- {
- show_shell_version (1);
- exit (EXECUTION_SUCCESS);
- }
-
- /* All done with full word options; do standard shell option parsing.*/
- this_command_name = shell_name; /* for error reporting */
- arg_index = parse_shell_options (argv, arg_index, argc);
-
- /* If user supplied the "--login" (or -l) flag, then set and invert
- LOGIN_SHELL. */
- if (make_login_shell)
- {
- login_shell++;
- login_shell = -login_shell;
- }
-
- set_login_shell ("login_shell", login_shell != 0);
-
- if (dump_po_strings)
- dump_translatable_strings = 1;
-
- if (dump_translatable_strings)
- read_but_dont_execute = 1;
-
- if (running_setuid && privileged_mode == 0)
- disable_priv_mode ();
-
- /* Need to get the argument to a -c option processed in the
- above loop. The next arg is a command to execute, and the
- following args are $0...$n respectively. */
- if (want_pending_command)
- {
- command_execution_string = argv[arg_index];
- if (command_execution_string == 0)
- {
- report_error (_("%s: option requires an argument"), "-c");
- exit (EX_BADUSAGE);
- }
- arg_index++;
- }
- this_command_name = (char *)NULL;
-
- cmd_init(); /* initialize the command object caches */
-
- /* First, let the outside world know about our interactive status.
- A shell is interactive if the `-i' flag was given, or if all of
- the following conditions are met:
- no -c command
- no arguments remaining or the -s flag given
- standard input is a terminal
- standard error is a terminal
- Refer to Posix.2, the description of the `sh' utility. */
-
- if (forced_interactive || /* -i flag */
- (!command_execution_string && /* No -c command and ... */
- wordexp_only == 0 && /* No --wordexp and ... */
- ((arg_index == argc) || /* no remaining args or... */
- read_from_stdin) && /* -s flag with args, and */
- isatty (fileno (stdin)) && /* Input is a terminal and */
- isatty (fileno (stderr)))) /* error output is a terminal. */
- init_interactive ();
- else
- init_noninteractive ();
-
- /*
- * Some systems have the bad habit of starting login shells with lots of open
- * file descriptors. For instance, most systems that have picked up the
- * pre-4.0 Sun YP code leave a file descriptor open each time you call one
- * of the getpw* functions, and it's set to be open across execs. That
- * means one for login, one for xterm, one for shelltool, etc. There are
- * also systems that open persistent FDs to other agents or files as part
- * of process startup; these need to be set to be close-on-exec.
- */
- if (login_shell && interactive_shell)
- {
- for (i = 3; i < 20; i++)
- SET_CLOSE_ON_EXEC (i);
- }
-
- /* If we're in a strict Posix.2 mode, turn on interactive comments,
- alias expansion in non-interactive shells, and other Posix.2 things. */
- if (posixly_correct)
- {
- bind_variable ("POSIXLY_CORRECT", "y", 0);
- sv_strict_posix ("POSIXLY_CORRECT");
- }
-
- /* Now we run the shopt_alist and process the options. */
- if (shopt_alist)
- run_shopt_alist ();
-
- /* From here on in, the shell must be a normal functioning shell.
- Variables from the environment are expected to be set, etc. */
- shell_initialize ();
-
- set_default_lang ();
- set_default_locale_vars ();
-
- /*
- * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm)
- * M-x shell -> TERM=dumb EMACS=t (no line editing)
- * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing)
- */
- if (interactive_shell)
- {
- char *term, *emacs;
-
- term = get_string_value ("TERM");
- emacs = get_string_value ("EMACS");
-
- /* Not sure any emacs terminal emulator sets TERM=emacs any more */
- no_line_editing |= term && (STREQ (term, "emacs"));
- no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb");
-
- /* running_under_emacs == 2 for `eterm' */
- running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5));
- running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term");
-
- if (running_under_emacs)
- gnu_error_format = 1;
- }
-
- top_level_arg_index = arg_index;
- old_errexit_flag = exit_immediately_on_error;
-
- /* Give this shell a place to longjmp to before executing the
- startup files. This allows users to press C-c to abort the
- lengthy startup. */
- code = setjmp (top_level);
- if (code)
- {
- if (code == EXITPROG || code == ERREXIT)
- exit_shell (last_command_exit_value);
- else
- {
-#if defined (JOB_CONTROL)
- /* Reset job control, since run_startup_files turned it off. */
- set_job_control (interactive_shell);
-#endif
- /* Reset value of `set -e', since it's turned off before running
- the startup files. */
- exit_immediately_on_error += old_errexit_flag;
- locally_skip_execution++;
- }
- }
-
- arg_index = top_level_arg_index;
-
- /* Execute the start-up scripts. */
-
- if (interactive_shell == 0)
- {
- unbind_variable ("PS1");
- unbind_variable ("PS2");
- interactive = 0;
-#if 0
- /* This has already been done by init_noninteractive */
- expand_aliases = posixly_correct;
-#endif
- }
- else
- {
- change_flag ('i', FLAG_ON);
- interactive = 1;
- }
-
-#if defined (RESTRICTED_SHELL)
- /* Set restricted_shell based on whether the basename of $0 indicates that
- the shell should be restricted or if the `-r' option was supplied at
- startup. */
- restricted_shell = shell_is_restricted (shell_name);
-
- /* If the `-r' option is supplied at invocation, make sure that the shell
- is not in restricted mode when running the startup files. */
- saverst = restricted;
-itrace("main: set saverst = %d", saverst);
- restricted = 0;
-#endif
-
- /* The startup files are run with `set -e' temporarily disabled. */
- if (locally_skip_execution == 0 && running_setuid == 0)
- {
- old_errexit_flag = exit_immediately_on_error;
- exit_immediately_on_error = 0;
-
- run_startup_files ();
- exit_immediately_on_error += old_errexit_flag;
- }
-
- /* If we are invoked as `sh', turn on Posix mode. */
- if (act_like_sh)
- {
- bind_variable ("POSIXLY_CORRECT", "y", 0);
- sv_strict_posix ("POSIXLY_CORRECT");
- }
-
-#if defined (RESTRICTED_SHELL)
- /* Turn on the restrictions after executing the startup files. This
- means that `bash -r' or `set -r' invoked from a startup file will
- turn on the restrictions after the startup files are executed. */
- restricted = saverst || restricted;
- if (shell_reinitialized == 0)
- maybe_make_restricted (shell_name);
-#endif /* RESTRICTED_SHELL */
-
-#if defined (WORDEXP_OPTION)
- if (wordexp_only)
- {
- startup_state = 3;
- last_command_exit_value = run_wordexp (argv[arg_index]);
- exit_shell (last_command_exit_value);
- }
-#endif
-
- if (command_execution_string)
- {
- arg_index = bind_args (argv, arg_index, argc, 0);
- startup_state = 2;
-
- if (debugging_mode)
- start_debugger ();
-
-#if defined (ONESHOT)
- executing = 1;
- run_one_command (command_execution_string);
- exit_shell (last_command_exit_value);
-#else /* ONESHOT */
- with_input_from_string (command_execution_string, "-c");
- goto read_and_execute;
-#endif /* !ONESHOT */
- }
-
- /* Get possible input filename and set up default_buffered_input or
- default_input as appropriate. */
- if (arg_index != argc && read_from_stdin == 0)
- {
- open_shell_script (argv[arg_index]);
- arg_index++;
- }
- else if (interactive == 0)
- /* In this mode, bash is reading a script from stdin, which is a
- pipe or redirected file. */
-#if defined (BUFFERED_INPUT)
- default_buffered_input = fileno (stdin); /* == 0 */
-#else
- setbuf (default_input, (char *)NULL);
-#endif /* !BUFFERED_INPUT */
-
- set_bash_input ();
-
- /* Bind remaining args to $1 ... $n */
- arg_index = bind_args (argv, arg_index, argc, 1);
-
- if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && dollar_vars[1])
- start_debugger ();
-
- /* Do the things that should be done only for interactive shells. */
- if (interactive_shell)
- {
- /* Set up for checking for presence of mail. */
- reset_mail_timer ();
- init_mail_dates ();
-
-#if defined (HISTORY)
- /* Initialize the interactive history stuff. */
- bash_initialize_history ();
- /* Don't load the history from the history file if we've already
- saved some lines in this session (e.g., by putting `history -s xx'
- into one of the startup files). */
- if (shell_initialized == 0 && history_lines_this_session == 0)
- load_history ();
-#endif /* HISTORY */
-
- /* Initialize terminal state for interactive shells after the
- .bash_profile and .bashrc are interpreted. */
- get_tty_state ();
- }
-
-#if !defined (ONESHOT)
- read_and_execute:
-#endif /* !ONESHOT */
-
- shell_initialized = 1;
-
- /* Read commands until exit condition. */
- reader_loop ();
- exit_shell (last_command_exit_value);
-}
-
-static int
-parse_long_options (argv, arg_start, arg_end)
- char **argv;
- int arg_start, arg_end;
-{
- int arg_index, longarg, i;
- char *arg_string;
-
- arg_index = arg_start;
- while ((arg_index != arg_end) && (arg_string = argv[arg_index]) &&
- (*arg_string == '-'))
- {
- longarg = 0;
-
- /* Make --login equivalent to -login. */
- if (arg_string[1] == '-' && arg_string[2])
- {
- longarg = 1;
- arg_string++;
- }
-
- for (i = 0; long_args[i].name; i++)
- {
- if (STREQ (arg_string + 1, long_args[i].name))
- {
- if (long_args[i].type == Int)
- *long_args[i].int_value = 1;
- else if (argv[++arg_index] == 0)
- {
- report_error (_("%s: option requires an argument"), long_args[i].name);
- exit (EX_BADUSAGE);
- }
- else
- *long_args[i].char_value = argv[arg_index];
-
- break;
- }
- }
- if (long_args[i].name == 0)
- {
- if (longarg)
- {
- report_error (_("%s: invalid option"), argv[arg_index]);
- show_shell_usage (stderr, 0);
- exit (EX_BADUSAGE);
- }
- break; /* No such argument. Maybe flag arg. */
- }
-
- arg_index++;
- }
-
- return (arg_index);
-}
-
-static int
-parse_shell_options (argv, arg_start, arg_end)
- char **argv;
- int arg_start, arg_end;
-{
- int arg_index;
- int arg_character, on_or_off, next_arg, i;
- char *o_option, *arg_string;
-
- arg_index = arg_start;
- while (arg_index != arg_end && (arg_string = argv[arg_index]) &&
- (*arg_string == '-' || *arg_string == '+'))
- {
- /* There are flag arguments, so parse them. */
- next_arg = arg_index + 1;
-
- /* A single `-' signals the end of options. From the 4.3 BSD sh.
- An option `--' means the same thing; this is the standard
- getopt(3) meaning. */
- if (arg_string[0] == '-' &&
- (arg_string[1] == '\0' ||
- (arg_string[1] == '-' && arg_string[2] == '\0')))
- return (next_arg);
-
- i = 1;
- on_or_off = arg_string[0];
- while (arg_character = arg_string[i++])
- {
- switch (arg_character)
- {
- case 'c':
- want_pending_command = 1;
- break;
-
- case 'l':
- make_login_shell = 1;
- break;
-
- case 's':
- read_from_stdin = 1;
- break;
-
- case 'o':
- o_option = argv[next_arg];
- if (o_option == 0)
- {
- list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1);
- break;
- }
- if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS)
- exit (EX_BADUSAGE);
- next_arg++;
- break;
-
- case 'O':
- /* Since some of these can be overridden by the normal
- interactive/non-interactive shell initialization or
- initializing posix mode, we save the options and process
- them after initialization. */
- o_option = argv[next_arg];
- if (o_option == 0)
- {
- shopt_listopt (o_option, (on_or_off == '-') ? 0 : 1);
- break;
- }
- add_shopt_to_alist (o_option, on_or_off);
- next_arg++;
- break;
-
- case 'D':
- dump_translatable_strings = 1;
- break;
-
- default:
- if (change_flag (arg_character, on_or_off) == FLAG_ERROR)
- {
- report_error (_("%c%c: invalid option"), on_or_off, arg_character);
- show_shell_usage (stderr, 0);
- exit (EX_BADUSAGE);
- }
- }
- }
- /* Can't do just a simple increment anymore -- what about
- "bash -abouo emacs ignoreeof -hP"? */
- arg_index = next_arg;
- }
-
- return (arg_index);
-}
-
-/* Exit the shell with status S. */
-void
-exit_shell (s)
- int s;
-{
- fflush (stdout); /* XXX */
- fflush (stderr);
-
-#if defined (READLINE)
- if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
- (*rl_deprep_term_function) ();
-#endif
-
- /* Do trap[0] if defined. Allow it to override the exit status
- passed to us. */
- if (signal_is_trapped (0))
- s = run_exit_trap ();
-
-#if defined (PROCESS_SUBSTITUTION)
- unlink_fifo_list ();
-#endif /* PROCESS_SUBSTITUTION */
-
-#if defined (HISTORY)
- if (remember_on_history)
- maybe_save_shell_history ();
-#endif /* HISTORY */
-
-#if defined (COPROCESS_SUPPORT)
- coproc_flush ();
-#endif
-
-#if defined (JOB_CONTROL)
- /* If the user has run `shopt -s huponexit', hangup all jobs when we exit
- an interactive login shell. ksh does this unconditionally. */
- if (interactive_shell && login_shell && hup_on_exit)
- hangup_all_jobs ();
-
- /* If this shell is interactive, or job control is active, terminate all
- stopped jobs and restore the original terminal process group. Don't do
- this if we're in a subshell and calling exit_shell after, for example,
- a failed word expansion. We want to do this even if the shell is not
- interactive because we set the terminal's process group when job control
- is enabled regardless of the interactive status. */
- if (subshell_environment == 0)
- end_job_control ();
-#endif /* JOB_CONTROL */
-
- /* Always return the exit status of the last command to our parent. */
- sh_exit (s);
-}
-
-/* A wrapper for exit that (optionally) can do other things, like malloc
- statistics tracing. */
-void
-sh_exit (s)
- int s;
-{
-#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC)
- if (malloc_trace_at_exit)
- trace_malloc_stats (get_name_for_error (), (char *)NULL);
-#endif
-
- exit (s);
-}
-
-/* Exit a subshell, which includes calling the exit trap. We don't want to
- do any more cleanup, since a subshell is created as an exact copy of its
- parent. */
-void
-subshell_exit (s)
- int s;
-{
- fflush (stdout);
- fflush (stderr);
-
- /* Do trap[0] if defined. Allow it to override the exit status
- passed to us. */
- if (signal_is_trapped (0))
- s = run_exit_trap ();
-
- sh_exit (s);
-}
-
-/* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey
- the Posix.2 startup file rules: $ENV is expanded, and if the file it
- names exists, that file is sourced. The Posix.2 rules are in effect
- for interactive shells only. (section 4.56.5.3) */
-
-/* Execute ~/.bashrc for most shells. Never execute it if
- ACT_LIKE_SH is set, or if NO_RC is set.
-
- If the executable file "/usr/gnu/src/bash/foo" contains:
-
- #!/usr/gnu/bin/bash
- echo hello
-
- then:
-
- COMMAND EXECUTE BASHRC
- --------------------------------
- bash -c foo NO
- bash foo NO
- foo NO
- rsh machine ls YES (for rsh, which calls `bash -c')
- rsh machine foo YES (for shell started by rsh) NO (for foo!)
- echo ls | bash NO
- login NO
- bash YES
-*/
-
-static void
-execute_env_file (env_file)
- char *env_file;
-{
- char *fn;
-
- if (env_file && *env_file)
- {
- fn = expand_string_unsplit_to_string (env_file, Q_DOUBLE_QUOTES);
- if (fn && *fn)
- maybe_execute_file (fn, 1);
- FREE (fn);
- }
-}
-
-static void
-run_startup_files ()
-{
-#if defined (JOB_CONTROL)
- int old_job_control;
-#endif
- int sourced_login, run_by_ssh;
-
- /* get the rshd/sshd case out of the way first. */
- if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 &&
- act_like_sh == 0 && command_execution_string)
- {
-#ifdef SSH_SOURCE_BASHRC
- run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
- (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
-#else
- run_by_ssh = 0;
-#endif
-
- /* If we were run by sshd or we think we were run by rshd, execute
- ~/.bashrc if we are a top-level shell. */
- if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
- {
-#ifdef SYS_BASHRC
-# if defined (__OPENNT)
- maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
-# else
- maybe_execute_file (SYS_BASHRC, 1);
-# endif
-#endif
- maybe_execute_file (bashrc_file, 1);
- return;
- }
- }
-
-#if defined (JOB_CONTROL)
- /* Startup files should be run without job control enabled. */
- old_job_control = interactive_shell ? set_job_control (0) : 0;
-#endif
-
- sourced_login = 0;
-
- /* A shell begun with the --login (or -l) flag that is not in posix mode
- runs the login shell startup files, no matter whether or not it is
- interactive. If NON_INTERACTIVE_LOGIN_SHELLS is defined, run the
- startup files if argv[0][0] == '-' as well. */
-#if defined (NON_INTERACTIVE_LOGIN_SHELLS)
- if (login_shell && posixly_correct == 0)
-#else
- if (login_shell < 0 && posixly_correct == 0)
-#endif
- {
- /* We don't execute .bashrc for login shells. */
- no_rc++;
-
- /* Execute /etc/profile and one of the personal login shell
- initialization files. */
- if (no_profile == 0)
- {
- maybe_execute_file (SYS_PROFILE, 1);
-
- if (act_like_sh) /* sh */
- maybe_execute_file ("~/.profile", 1);
- else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
- (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */
- maybe_execute_file ("~/.profile", 1);
- }
-
- sourced_login = 1;
- }
-
- /* A non-interactive shell not named `sh' and not in posix mode reads and
- executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd'
- and `-su' as the name of the shell, we want to read the startup files.
- No other non-interactive shells read any startup files. */
- if (interactive_shell == 0 && !(su_shell && login_shell))
- {
- if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 &&
- sourced_env++ == 0)
- execute_env_file (get_string_value ("BASH_ENV"));
- return;
- }
-
- /* Interactive shell or `-su' shell. */
- if (posixly_correct == 0) /* bash, sh */
- {
- if (login_shell && sourced_login++ == 0)
- {
- /* We don't execute .bashrc for login shells. */
- no_rc++;
-
- /* Execute /etc/profile and one of the personal login shell
- initialization files. */
- if (no_profile == 0)
- {
- maybe_execute_file (SYS_PROFILE, 1);
-
- if (act_like_sh) /* sh */
- maybe_execute_file ("~/.profile", 1);
- else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
- (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */
- maybe_execute_file ("~/.profile", 1);
- }
- }
-
- /* bash */
- if (act_like_sh == 0 && no_rc == 0)
- {
-#ifdef SYS_BASHRC
-# if defined (__OPENNT)
- maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
-# else
- maybe_execute_file (SYS_BASHRC, 1);
-# endif
-#endif
- maybe_execute_file (bashrc_file, 1);
- }
- /* sh */
- else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0)
- execute_env_file (get_string_value ("ENV"));
- }
- else /* bash --posix, sh --posix */
- {
- /* bash and sh */
- if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0)
- execute_env_file (get_string_value ("ENV"));
- }
-
-#if defined (JOB_CONTROL)
- set_job_control (old_job_control);
-#endif
-}
-
-#if defined (RESTRICTED_SHELL)
-/* Return 1 if the shell should be a restricted one based on NAME or the
- value of `restricted'. Don't actually do anything, just return a
- boolean value. */
-int
-shell_is_restricted (name)
- char *name;
-{
- char *temp;
-
- if (restricted)
- return 1;
- temp = base_pathname (name);
- if (*temp == '-')
- temp++;
- return (STREQ (temp, RESTRICTED_SHELL_NAME));
-}
-
-/* Perhaps make this shell a `restricted' one, based on NAME. If the
- basename of NAME is "rbash", then this shell is restricted. The
- name of the restricted shell is a configurable option, see config.h.
- In a restricted shell, PATH, SHELL, ENV, and BASH_ENV are read-only
- and non-unsettable.
- Do this also if `restricted' is already set to 1; maybe the shell was
- started with -r. */
-int
-maybe_make_restricted (name)
- char *name;
-{
- char *temp;
-
- temp = base_pathname (name);
- if (*temp == '-')
- temp++;
- if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME)))
- {
- set_var_read_only ("PATH");
- set_var_read_only ("SHELL");
- set_var_read_only ("ENV");
- set_var_read_only ("BASH_ENV");
- restricted = 1;
- }
- return (restricted);
-}
-#endif /* RESTRICTED_SHELL */
-
-/* Fetch the current set of uids and gids and return 1 if we're running
- setuid or setgid. */
-static int
-uidget ()
-{
- uid_t u;
-
- u = getuid ();
- if (current_user.uid != u)
- {
- FREE (current_user.user_name);
- FREE (current_user.shell);
- FREE (current_user.home_dir);
- current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL;
- }
- current_user.uid = u;
- current_user.gid = getgid ();
- current_user.euid = geteuid ();
- current_user.egid = getegid ();
-
- /* See whether or not we are running setuid or setgid. */
- return (current_user.uid != current_user.euid) ||
- (current_user.gid != current_user.egid);
-}
-
-void
-disable_priv_mode ()
-{
- int e;
-
- if (setuid (current_user.uid) < 0)
- {
- e = errno;
- sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid);
-#if defined (EXIT_ON_SETUID_FAILURE)
- if (e == EAGAIN)
- exit (e);
-#endif
- }
- if (setgid (current_user.gid) < 0)
- sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid);
-
- current_user.euid = current_user.uid;
- current_user.egid = current_user.gid;
-}
-
-#if defined (WORDEXP_OPTION)
-static int
-run_wordexp (words)
- char *words;
-{
- int code, nw, nb;
- WORD_LIST *wl, *tl, *result;
-
- code = setjmp_nosigs (top_level);
-
- if (code != NOT_JUMPED)
- {
- switch (code)
- {
- /* Some kind of throw to top_level has occurred. */
- case FORCE_EOF:
- return last_command_exit_value = 127;
- case ERREXIT:
- case EXITPROG:
- return last_command_exit_value;
- case DISCARD:
- return last_command_exit_value = 1;
- default:
- command_error ("run_wordexp", CMDERR_BADJUMP, code, 0);
- }
- }
-
- /* Run it through the parser to get a list of words and expand them */
- if (words && *words)
- {
- with_input_from_string (words, "--wordexp");
- if (parse_command () != 0)
- return (126);
- if (global_command == 0)
- {
- printf ("0\n0\n");
- return (0);
- }
- if (global_command->type != cm_simple)
- return (126);
- wl = global_command->value.Simple->words;
- if (protected_mode)
- for (tl = wl; tl; tl = tl->next)
- tl->word->flags |= W_NOCOMSUB|W_NOPROCSUB;
- result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0;
- }
- else
- result = (WORD_LIST *)0;
-
- last_command_exit_value = 0;
-
- if (result == 0)
- {
- printf ("0\n0\n");
- return (0);
- }
-
- /* Count up the number of words and bytes, and print them. Don't count
- the trailing NUL byte. */
- for (nw = nb = 0, wl = result; wl; wl = wl->next)
- {
- nw++;
- nb += strlen (wl->word->word);
- }
- printf ("%u\n%u\n", nw, nb);
- /* Print each word on a separate line. This will have to be changed when
- the interface to glibc is completed. */
- for (wl = result; wl; wl = wl->next)
- printf ("%s\n", wl->word->word);
-
- return (0);
-}
-#endif
-
-#if defined (ONESHOT)
-/* Run one command, given as the argument to the -c option. Tell
- parse_and_execute not to fork for a simple command. */
-static int
-run_one_command (command)
- char *command;
-{
- int code;
-
- code = setjmp_nosigs (top_level);
-
- if (code != NOT_JUMPED)
- {
-#if defined (PROCESS_SUBSTITUTION)
- unlink_fifo_list ();
-#endif /* PROCESS_SUBSTITUTION */
- switch (code)
- {
- /* Some kind of throw to top_level has occurred. */
- case FORCE_EOF:
- return last_command_exit_value = 127;
- case ERREXIT:
- case EXITPROG:
- return last_command_exit_value;
- case DISCARD:
- return last_command_exit_value = 1;
- default:
- command_error ("run_one_command", CMDERR_BADJUMP, code, 0);
- }
- }
- return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST));
-}
-#endif /* ONESHOT */
-
-static int
-bind_args (argv, arg_start, arg_end, start_index)
- char **argv;
- int arg_start, arg_end, start_index;
-{
- register int i;
- WORD_LIST *args;
-
- for (i = arg_start, args = (WORD_LIST *)NULL; i < arg_end; i++)
- args = make_word_list (make_word (argv[i]), args);
- if (args)
- {
- args = REVERSE_LIST (args, WORD_LIST *);
- if (start_index == 0) /* bind to $0...$n for sh -c command */
- {
- /* Posix.2 4.56.3 says that the first argument after sh -c command
- becomes $0, and the rest of the arguments become $1...$n */
- shell_name = savestring (args->word->word);
- FREE (dollar_vars[0]);
- dollar_vars[0] = savestring (args->word->word);
- remember_args (args->next, 1);
- push_args (args->next); /* BASH_ARGV and BASH_ARGC */
- }
- else /* bind to $1...$n for shell script */
- {
- remember_args (args, 1);
- push_args (args); /* BASH_ARGV and BASH_ARGC */
- }
-
- dispose_words (args);
- }
-
- return (i);
-}
-
-void
-unbind_args ()
-{
- remember_args ((WORD_LIST *)NULL, 1);
- pop_args (); /* Reset BASH_ARGV and BASH_ARGC */
-}
-
-static void
-start_debugger ()
-{
-#if defined (DEBUGGER) && defined (DEBUGGER_START_FILE)
- int old_errexit;
-
- old_errexit = exit_immediately_on_error;
- exit_immediately_on_error = 0;
-
- maybe_execute_file (DEBUGGER_START_FILE, 1);
- function_trace_mode = 1;
-
- exit_immediately_on_error += old_errexit;
-#endif
-}
-
-static int
-open_shell_script (script_name)
- char *script_name;
-{
- int fd, e, fd_is_tty;
- char *filename, *path_filename, *t;
- char sample[80];
- int sample_len;
- struct stat sb;
-#if defined (ARRAY_VARS)
- SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
- ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
-#endif
-
- filename = savestring (script_name);
-
- fd = open (filename, O_RDONLY);
- if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0))
- {
- e = errno;
- /* If it's not in the current directory, try looking through PATH
- for it. */
- path_filename = find_path_file (script_name);
- if (path_filename)
- {
- free (filename);
- filename = path_filename;
- fd = open (filename, O_RDONLY);
- }
- else
- errno = e;
- }
-
- if (fd < 0)
- {
- e = errno;
- file_error (filename);
- exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
- }
-
- free (dollar_vars[0]);
- dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (script_name);
- if (exec_argv0)
- {
- free (exec_argv0);
- exec_argv0 = (char *)NULL;
- }
-
-#if defined (ARRAY_VARS)
- GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
- GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
- GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
-
- array_push (bash_source_a, filename);
- if (bash_lineno_a)
- {
- t = itos (executing_line_number ());
- array_push (bash_lineno_a, t);
- free (t);
- }
- array_push (funcname_a, "main");
-#endif
-
-#ifdef HAVE_DEV_FD
- fd_is_tty = isatty (fd);
-#else
- fd_is_tty = 0;
-#endif
-
- /* Only do this with non-tty file descriptors we can seek on. */
- if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1))
- {
- /* Check to see if the `file' in `bash file' is a binary file
- according to the same tests done by execute_simple_command (),
- and report an error and exit if it is. */
- sample_len = read (fd, sample, sizeof (sample));
- if (sample_len < 0)
- {
- e = errno;
- if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode))
- internal_error (_("%s: is a directory"), filename);
- else
- {
- errno = e;
- file_error (filename);
- }
- exit (EX_NOEXEC);
- }
- else if (sample_len > 0 && (check_binary_file (sample, sample_len)))
- {
- internal_error (_("%s: cannot execute binary file"), filename);
- exit (EX_BINARY_FILE);
- }
- /* Now rewind the file back to the beginning. */
- lseek (fd, 0L, 0);
- }
-
- /* Open the script. But try to move the file descriptor to a randomly
- large one, in the hopes that any descriptors used by the script will
- not match with ours. */
- fd = move_to_high_fd (fd, 1, -1);
-
-#if defined (BUFFERED_INPUT)
- default_buffered_input = fd;
- SET_CLOSE_ON_EXEC (default_buffered_input);
-#else /* !BUFFERED_INPUT */
- default_input = fdopen (fd, "r");
-
- if (default_input == 0)
- {
- file_error (filename);
- exit (EX_NOTFOUND);
- }
-
- SET_CLOSE_ON_EXEC (fd);
- if (fileno (default_input) != fd)
- SET_CLOSE_ON_EXEC (fileno (default_input));
-#endif /* !BUFFERED_INPUT */
-
- /* Just about the only way for this code to be executed is if something
- like `bash -i /dev/stdin' is executed. */
- if (interactive_shell && fd_is_tty)
- {
- dup2 (fd, 0);
- close (fd);
- fd = 0;
-#if defined (BUFFERED_INPUT)
- default_buffered_input = 0;
-#else
- fclose (default_input);
- default_input = stdin;
-#endif
- }
- else if (forced_interactive && fd_is_tty == 0)
- /* But if a script is called with something like `bash -i scriptname',
- we need to do a non-interactive setup here, since we didn't do it
- before. */
- init_interactive_script ();
-
- free (filename);
- return (fd);
-}
-
-/* Initialize the input routines for the parser. */
-static void
-set_bash_input ()
-{
- /* Make sure the fd from which we are reading input is not in
- no-delay mode. */
-#if defined (BUFFERED_INPUT)
- if (interactive == 0)
- sh_unset_nodelay_mode (default_buffered_input);
- else
-#endif /* !BUFFERED_INPUT */
- sh_unset_nodelay_mode (fileno (stdin));
-
- /* with_input_from_stdin really means `with_input_from_readline' */
- if (interactive && no_line_editing == 0)
- with_input_from_stdin ();
-#if defined (BUFFERED_INPUT)
- else if (interactive == 0)
- with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]);
-#endif /* BUFFERED_INPUT */
- else
- with_input_from_stream (default_input, dollar_vars[0]);
-}
-
-/* Close the current shell script input source and forget about it. This is
- extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO
- is non-zero, we close default_buffered_input even if it's the standard
- input (fd 0). */
-void
-unset_bash_input (check_zero)
- int check_zero;
-{
-#if defined (BUFFERED_INPUT)
- if ((check_zero && default_buffered_input >= 0) ||
- (check_zero == 0 && default_buffered_input > 0))
- {
- close_buffered_fd (default_buffered_input);
- default_buffered_input = bash_input.location.buffered_fd = -1;
- bash_input.type = st_none; /* XXX */
- }
-#else /* !BUFFERED_INPUT */
- if (default_input)
- {
- fclose (default_input);
- default_input = (FILE *)NULL;
- }
-#endif /* !BUFFERED_INPUT */
-}
-
-
-#if !defined (PROGRAM)
-# define PROGRAM "bash"
-#endif
-
-static void
-set_shell_name (argv0)
- char *argv0;
-{
- /* Here's a hack. If the name of this shell is "sh", then don't do
- any startup files; just try to be more like /bin/sh. */
- shell_name = argv0 ? base_pathname (argv0) : PROGRAM;
-
- if (argv0 && *argv0 == '-')
- {
- if (*shell_name == '-')
- shell_name++;
- login_shell = 1;
- }
-
- if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
- act_like_sh++;
- if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0')
- su_shell++;
-
- shell_name = argv0 ? argv0 : PROGRAM;
- FREE (dollar_vars[0]);
- dollar_vars[0] = savestring (shell_name);
-
- /* A program may start an interactive shell with
- "execl ("/bin/bash", "-", NULL)".
- If so, default the name of this shell to our name. */
- if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1]))
- shell_name = PROGRAM;
-}
-
-static void
-init_interactive ()
-{
- expand_aliases = interactive_shell = startup_state = 1;
- interactive = 1;
-}
-
-static void
-init_noninteractive ()
-{
-#if defined (HISTORY)
- bash_history_reinit (0);
-#endif /* HISTORY */
- interactive_shell = startup_state = interactive = 0;
- expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */
- no_line_editing = 1;
-#if defined (JOB_CONTROL)
- /* Even if the shell is not interactive, enable job control if the -i or
- -m option is supplied at startup. */
- set_job_control (forced_interactive||jobs_m_flag);
-#endif /* JOB_CONTROL */
-}
-
-static void
-init_interactive_script ()
-{
- init_noninteractive ();
- expand_aliases = interactive_shell = startup_state = 1;
-}
-
-void
-get_current_user_info ()
-{
- struct passwd *entry;
-
- /* Don't fetch this more than once. */
- if (current_user.user_name == 0)
- {
-#if defined (__TANDEM)
- entry = getpwnam (getlogin ());
-#else
- entry = getpwuid (current_user.uid);
-#endif
- if (entry)
- {
- current_user.user_name = savestring (entry->pw_name);
- current_user.shell = (entry->pw_shell && entry->pw_shell[0])
- ? savestring (entry->pw_shell)
- : savestring ("/bin/sh");
- current_user.home_dir = savestring (entry->pw_dir);
- }
- else
- {
- current_user.user_name = _("I have no name!");
- current_user.user_name = savestring (current_user.user_name);
- current_user.shell = savestring ("/bin/sh");
- current_user.home_dir = savestring ("/");
- }
- endpwent ();
- }
-}
-
-/* Do whatever is necessary to initialize the shell.
- Put new initializations in here. */
-static void
-shell_initialize ()
-{
- char hostname[256];
-
- /* Line buffer output for stderr and stdout. */
- if (shell_initialized == 0)
- {
- sh_setlinebuf (stderr);
- sh_setlinebuf (stdout);
- }
-
- /* Sort the array of shell builtins so that the binary search in
- find_shell_builtin () works correctly. */
- initialize_shell_builtins ();
-
- /* Initialize the trap signal handlers before installing our own
- signal handlers. traps.c:restore_original_signals () is responsible
- for restoring the original default signal handlers. That function
- is called when we make a new child. */
- initialize_traps ();
- initialize_signals (0);
-
- /* It's highly unlikely that this will change. */
- if (current_host_name == 0)
- {
- /* Initialize current_host_name. */
- if (gethostname (hostname, 255) < 0)
- current_host_name = "??host??";
- else
- current_host_name = savestring (hostname);
- }
-
- /* Initialize the stuff in current_user that comes from the password
- file. We don't need to do this right away if the shell is not
- interactive. */
- if (interactive_shell)
- get_current_user_info ();
-
- /* Initialize our interface to the tilde expander. */
- tilde_initialize ();
-
- /* Initialize internal and environment variables. Don't import shell
- functions from the environment if we are running in privileged or
- restricted mode or if the shell is running setuid. */
-#if defined (RESTRICTED_SHELL)
- initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid);
-#else
- initialize_shell_variables (shell_environment, privileged_mode||running_setuid);
-#endif
-
- /* Initialize the data structures for storing and running jobs. */
- initialize_job_control (jobs_m_flag);
-
- /* Initialize input streams to null. */
- initialize_bash_input ();
-
- initialize_flags ();
-
- /* Initialize the shell options. Don't import the shell options
- from the environment variables $SHELLOPTS or $BASHOPTS if we are
- running in privileged or restricted mode or if the shell is running
- setuid. */
-#if defined (RESTRICTED_SHELL)
- initialize_shell_options (privileged_mode||restricted||running_setuid);
- initialize_bashopts (privileged_mode||restricted||running_setuid);
-#else
- initialize_shell_options (privileged_mode||running_setuid);
- initialize_bashopts (privileged_mode||running_setuid);
-#endif
-}
-
-/* Function called by main () when it appears that the shell has already
- had some initialization performed. This is supposed to reset the world
- back to a pristine state, as if we had been exec'ed. */
-static void
-shell_reinitialize ()
-{
- /* The default shell prompts. */
- primary_prompt = PPROMPT;
- secondary_prompt = SPROMPT;
-
- /* Things that get 1. */
- current_command_number = 1;
-
- /* We have decided that the ~/.bashrc file should not be executed
- for the invocation of each shell script. If the variable $ENV
- (or $BASH_ENV) is set, its value is used as the name of a file
- to source. */
- no_rc = no_profile = 1;
-
- /* Things that get 0. */
- login_shell = make_login_shell = interactive = executing = 0;
- debugging = do_version = line_number = last_command_exit_value = 0;
- forced_interactive = interactive_shell = 0;
- subshell_environment = running_in_background = 0;
- expand_aliases = 0;
-
- /* XXX - should we set jobs_m_flag to 0 here? */
-
-#if defined (HISTORY)
- bash_history_reinit (0);
-#endif /* HISTORY */
-
-#if defined (RESTRICTED_SHELL)
- restricted = 0;
-#endif /* RESTRICTED_SHELL */
-
- /* Ensure that the default startup file is used. (Except that we don't
- execute this file for reinitialized shells). */
- bashrc_file = DEFAULT_BASHRC;
-
- /* Delete all variables and functions. They will be reinitialized when
- the environment is parsed. */
- delete_all_contexts (shell_variables);
- delete_all_variables (shell_functions);
-
- reinit_special_variables ();
-
-#if defined (READLINE)
- bashline_reinitialize ();
-#endif
-
- shell_reinitialized = 1;
-}
-
-static void
-show_shell_usage (fp, extra)
- FILE *fp;
- int extra;
-{
- int i;
- char *set_opts, *s, *t;
-
- if (extra)
- fprintf (fp, _("GNU bash, version %s-(%s)\n"), shell_version_string (), MACHTYPE);
- fprintf (fp, _("Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n"),
- shell_name, shell_name);
- fputs (_("GNU long options:\n"), fp);
- for (i = 0; long_args[i].name; i++)
- fprintf (fp, "\t--%s\n", long_args[i].name);
-
- fputs (_("Shell options:\n"), fp);
- fputs (_("\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n"), fp);
-
- for (i = 0, set_opts = 0; shell_builtins[i].name; i++)
- if (STREQ (shell_builtins[i].name, "set"))
- set_opts = savestring (shell_builtins[i].short_doc);
- if (set_opts)
- {
- s = strchr (set_opts, '[');
- if (s == 0)
- s = set_opts;
- while (*++s == '-')
- ;
- t = strchr (s, ']');
- if (t)
- *t = '\0';
- fprintf (fp, _("\t-%s or -o option\n"), s);
- free (set_opts);
- }
-
- if (extra)
- {
- fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name);
- fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name);
- fprintf (fp, _("Use the `bashbug' command to report bugs.\n"));
- }
-}
-
-static void
-add_shopt_to_alist (opt, on_or_off)
- char *opt;
- int on_or_off;
-{
- if (shopt_ind >= shopt_len)
- {
- shopt_len += 8;
- shopt_alist = (STRING_INT_ALIST *)xrealloc (shopt_alist, shopt_len * sizeof (shopt_alist[0]));
- }
- shopt_alist[shopt_ind].word = opt;
- shopt_alist[shopt_ind].token = on_or_off;
- shopt_ind++;
-}
-
-static void
-run_shopt_alist ()
-{
- register int i;
-
- for (i = 0; i < shopt_ind; i++)
- if (shopt_setopt (shopt_alist[i].word, (shopt_alist[i].token == '-')) != EXECUTION_SUCCESS)
- exit (EX_BADUSAGE);
- free (shopt_alist);
- shopt_alist = 0;
- shopt_ind = shopt_len = 0;
-}
+++ /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
-# normal operation
-foo()
-{
- echo exportfunc ok 1
-}
-export -f foo
-${THIS_SH} -c foo
-unset -f foo
-foo-a ()
-{
- echo exportfunc ok 2
-}
-export -f foo-a
-${THIS_SH} -c 'foo-a'
-
-# CVE-2014-6271
-
-env -i BASH_FUNC_foo%%='() { echo cve6271 ok; } ; echo BAD' ${THIS_SH} -c foo 2>/dev/null
-
-# CVE-2014-7169
-
-rm -f cve7169-bad
-env -i BASH_FUNC_X%%='() { (a)=>\' ${THIS_SH} -c cve7169-bad 2>/dev/null
-: < cve7169-bad
-rm -f cve7169-bad
-
-echo cve7169-bad2 > bar
-rm -f cve7169-bad2
-eval 'X() { (a)>\' ; . ./bar 2>/dev/null
-: < cve7169-bad2
-rm -f cve7169-bad2 bar
-
-# CVE-2014-7186
-${THIS_SH} ./exportfunc1.sub
-
-# CVE-2014-7187
-${THIS_SH} ./exportfunc2.sub
-
-# CVE-2014-6277
-
-env BASH_FUNC_foo%%="() { 000(){>0;}&000(){ 0;}<<0 0" ${THIS_SH} -c foo 2>/dev/null
-env BASH_FUNC_foo%%="() { 000(){>0;}&000(){ 0;}<<`perl -e '{print "A"x100000}'` 0" ${THIS_SH} -c foo 2>/dev/null
-${THIS_SH} -c "f(){ x(){ _;}; x(){ _;}<<a;}"
-
-# CVE-2014-6278
-
-env 'BASH_FUNC_FOO%%=() { 0;}>r[0${$(}0 {>"$(id >/dev/tty)"; }' ${THIS_SH} -c : 2>/dev/null
-
-rm -f HELLO_WORLD
-env BASH_FUNC_FOO%%='() { 0;}>r[0${$(}0 {>HELLO_WORLD; }' ${THIS_SH} -c : 2>/dev/null
-: < HELLO_WORLD
-
-env BASH_FUNC_x%%='() { _;}>_[$($())] { echo vuln;}' ${THIS_SH} -c : 2>/dev/null
-
-env -i BASH_FUNC_x%%='() { _; } >_[${ $() }] { id; }' ${THIS_SH} -c : 2>/dev/null
-
-env BASH_FUNC_x%%=$'() { _;}>_[$($())]\n{ echo vuln;}' ${THIS_SH} -c : 2>/dev/null
-eval 'x() { _;}>_[$($())] { echo vuln;}' 2>/dev/null
-
-eval 'foo() { _; } >_[${ $() }] ;{ echo eval ok; }'
-
-# other tests fixed in bash43-030 concerning function name transformation
-env $'BASH_FUNC_\nfoo%%=() { echo transform-1; }' ${THIS_SH} -c foo 2>/dev/null
-env $'BASH_FUNC_foo\n%%=() { echo transform-2; }' ${THIS_SH} -c foo 2>/dev/null
-env $'BASH_FUNC_ foo %%=() { echo transform-3; }' ${THIS_SH} -c foo 2>/dev/null
-
-unset -f foo
-env $'BASH_FUNC_#badname%%'=$'() { :; }\nfoo () { echo transform-4; } ' ${THIS_SH} -c 'foo' 2>/dev/null
+++ /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
+++ /dev/null
-/* trap.c -- Not the trap command, but useful functions for manipulating
- those objects. The trap command is in builtins/trap.def. */
-
-/* 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 (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashtypes.h"
-#include "bashansi.h"
-
-#include <stdio.h>
-#include <errno.h>
-
-#include "bashintl.h"
-
-#include <signal.h>
-
-#include "trap.h"
-
-#include "shell.h"
-#include "flags.h"
-#include "input.h" /* for save_token_state, restore_token_state */
-#include "jobs.h"
-#include "signames.h"
-#include "builtins.h"
-#include "builtins/common.h"
-#include "builtins/builtext.h"
-
-#if defined (READLINE)
-# include <readline/readline.h>
-# include "bashline.h"
-#endif
-
-#ifndef errno
-extern int errno;
-#endif
-
-/* Flags which describe the current handling state of a signal. */
-#define SIG_INHERITED 0x0 /* Value inherited from parent. */
-#define SIG_TRAPPED 0x1 /* Currently trapped. */
-#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */
-#define SIG_SPECIAL 0x4 /* Treat this signal specially. */
-#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */
-#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */
-#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */
-#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */
-
-#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP)
-
-/* An array of such flags, one for each signal, describing what the
- shell will do with a signal. DEBUG_TRAP == NSIG; some code below
- assumes this. */
-static int sigmodes[BASH_NSIG];
-
-static void free_trap_command __P((int));
-static void change_signal __P((int, char *));
-
-static int _run_trap_internal __P((int, char *));
-
-static void free_trap_string __P((int));
-static void reset_signal __P((int));
-static void restore_signal __P((int));
-static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *));
-
-/* Variables used here but defined in other files. */
-extern int last_command_exit_value;
-extern int line_number;
-
-extern int sigalrm_seen;
-extern procenv_t alrmbuf;
-
-extern volatile int from_return_trap;
-
-extern char *this_command_name;
-extern sh_builtin_func_t *this_shell_builtin;
-extern procenv_t wait_intr_buf;
-extern int return_catch_flag, return_catch_value;
-extern int subshell_level;
-extern WORD_LIST *subst_assign_varlist;
-
-/* The list of things to do originally, before we started trapping. */
-SigHandler *original_signals[NSIG];
-
-/* For each signal, a slot for a string, which is a command to be
- executed when that signal is received. The slot can also contain
- DEFAULT_SIG, which means do whatever you were going to do before
- you were so rudely interrupted, or IGNORE_SIG, which says ignore
- this signal. */
-char *trap_list[BASH_NSIG];
-
-/* A bitmap of signals received for which we have trap handlers. */
-int pending_traps[NSIG];
-
-/* Set to the number of the signal we're running the trap for + 1.
- Used in execute_cmd.c and builtins/common.c to clean up when
- parse_and_execute does not return normally after executing the
- trap command (e.g., when `return' is executed in the trap command). */
-int running_trap;
-
-/* Set to last_command_exit_value before running a trap. */
-int trap_saved_exit_value;
-
-/* The (trapped) signal received while executing in the `wait' builtin */
-int wait_signal_received;
-
-int trapped_signal_received;
-
-#define GETORIGSIG(sig) \
- do { \
- original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \
- set_signal_handler (sig, original_signals[sig]); \
- if (original_signals[sig] == SIG_IGN) \
- sigmodes[sig] |= SIG_HARD_IGNORE; \
- } while (0)
-
-#define SETORIGSIG(sig,handler) \
- do { \
- original_signals[sig] = handler; \
- if (original_signals[sig] == SIG_IGN) \
- sigmodes[sig] |= SIG_HARD_IGNORE; \
- } while (0)
-
-#define GET_ORIGINAL_SIGNAL(sig) \
- if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
- GETORIGSIG(sig)
-
-void
-initialize_traps ()
-{
- register int i;
-
- initialize_signames();
-
- trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
- sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED;
- original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
-
- for (i = 1; i < NSIG; i++)
- {
- pending_traps[i] = 0;
- trap_list[i] = (char *)DEFAULT_SIG;
- sigmodes[i] = SIG_INHERITED; /* XXX - only set, not used */
- original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
- }
-
- /* Show which signals are treated specially by the shell. */
-#if defined (SIGCHLD)
- GETORIGSIG (SIGCHLD);
- sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
-#endif /* SIGCHLD */
-
- GETORIGSIG (SIGINT);
- sigmodes[SIGINT] |= SIG_SPECIAL;
-
-#if defined (__BEOS__)
- /* BeOS sets SIGINT to SIG_IGN! */
- original_signals[SIGINT] = SIG_DFL;
- sigmodes[SIGINT] &= ~SIG_HARD_IGNORE;
-#endif
-
- GETORIGSIG (SIGQUIT);
- sigmodes[SIGQUIT] |= SIG_SPECIAL;
-
- if (interactive)
- {
- GETORIGSIG (SIGTERM);
- sigmodes[SIGTERM] |= SIG_SPECIAL;
- }
-}
-
-#ifdef DEBUG
-/* Return a printable representation of the trap handler for SIG. */
-static char *
-trap_handler_string (sig)
- int sig;
-{
- if (trap_list[sig] == (char *)DEFAULT_SIG)
- return "DEFAULT_SIG";
- else if (trap_list[sig] == (char *)IGNORE_SIG)
- return "IGNORE_SIG";
- else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
- return "IMPOSSIBLE_TRAP_HANDLER";
- else if (trap_list[sig])
- return trap_list[sig];
- else
- return "NULL";
-}
-#endif
-
-/* Return the print name of this signal. */
-char *
-signal_name (sig)
- int sig;
-{
- char *ret;
-
- /* on cygwin32, signal_names[sig] could be null */
- ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL)
- ? _("invalid signal number")
- : signal_names[sig];
-
- return ret;
-}
-
-/* Turn a string into a signal number, or a number into
- a signal number. If STRING is "2", "SIGINT", or "INT",
- then (int)2 is returned. Return NO_SIG if STRING doesn't
- contain a valid signal descriptor. */
-int
-decode_signal (string, flags)
- char *string;
- int flags;
-{
- intmax_t sig;
- char *name;
-
- if (legal_number (string, &sig))
- return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG);
-
- /* A leading `SIG' may be omitted. */
- for (sig = 0; sig < BASH_NSIG; sig++)
- {
- name = signal_names[sig];
- if (name == 0 || name[0] == '\0')
- continue;
-
- /* Check name without the SIG prefix first case sensitively or
- insensitively depending on whether flags includes DSIG_NOCASE */
- if (STREQN (name, "SIG", 3))
- {
- name += 3;
-
- if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
- return ((int)sig);
- else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
- return ((int)sig);
- /* If we can't use the `SIG' prefix to match, punt on this
- name now. */
- else if ((flags & DSIG_SIGPREFIX) == 0)
- continue;
- }
-
- /* Check name with SIG prefix case sensitively or insensitively
- depending on whether flags includes DSIG_NOCASE */
- name = signal_names[sig];
- if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0)
- return ((int)sig);
- else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0)
- return ((int)sig);
- }
-
- return (NO_SIG);
-}
-
-/* Non-zero when we catch a trapped signal. */
-static int catch_flag;
-
-void
-run_pending_traps ()
-{
- register int sig;
- int old_exit_value;
- WORD_LIST *save_subst_varlist;
- sh_parser_state_t pstate;
-#if defined (ARRAY_VARS)
- ARRAY *ps;
-#endif
-
- if (catch_flag == 0) /* simple optimization */
- return;
-
- if (running_trap > 0)
- {
-#if defined (DEBUG)
- internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
-#endif
-#if 0
- return; /* no recursive trap invocations */
-#else
- ;
-#endif
- }
-
- catch_flag = trapped_signal_received = 0;
-
- /* Preserve $? when running trap. */
- trap_saved_exit_value = old_exit_value = last_command_exit_value;
-#if defined (ARRAY_VARS)
- ps = save_pipestatus_array ();
-#endif
-
- for (sig = 1; sig < NSIG; sig++)
- {
- /* XXX this could be made into a counter by using
- while (pending_traps[sig]--) instead of the if statement. */
- if (pending_traps[sig])
- {
- if (running_trap == sig+1)
- /*continue*/;
-
- running_trap = sig + 1;
-
- if (sig == SIGINT)
- {
- pending_traps[sig] = 0; /* XXX */
- run_interrupt_trap ();
- CLRINTERRUPT;
- }
-#if defined (JOB_CONTROL) && defined (SIGCHLD)
- else if (sig == SIGCHLD &&
- trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER &&
- (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
- {
- sigmodes[SIGCHLD] |= SIG_INPROGRESS;
- run_sigchld_trap (pending_traps[sig]); /* use as counter */
- sigmodes[SIGCHLD] &= ~SIG_INPROGRESS;
- }
- else if (sig == SIGCHLD &&
- trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER &&
- (sigmodes[SIGCHLD] & SIG_INPROGRESS) != 0)
- {
- /* This can happen when run_pending_traps is called while
- running a SIGCHLD trap handler. */
- running_trap = 0;
- /* want to leave pending_traps[SIGCHLD] alone here */
- continue; /* XXX */
- }
- else if (sig == SIGCHLD && (sigmodes[SIGCHLD] & SIG_INPROGRESS))
- {
- /* whoops -- print warning? */
- running_trap = 0; /* XXX */
- /* want to leave pending_traps[SIGCHLD] alone here */
- continue;
- }
-#endif
- else if (trap_list[sig] == (char *)DEFAULT_SIG ||
- trap_list[sig] == (char *)IGNORE_SIG ||
- trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER)
- {
- /* This is possible due to a race condition. Say a bash
- process has SIGTERM trapped. A subshell is spawned
- using { list; } & and the parent does something and kills
- the subshell with SIGTERM. It's possible for the subshell
- to set pending_traps[SIGTERM] to 1 before the code in
- execute_cmd.c eventually calls restore_original_signals
- to reset the SIGTERM signal handler in the subshell. The
- next time run_pending_traps is called, pending_traps[SIGTERM]
- will be 1, but the trap handler in trap_list[SIGTERM] will
- be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG).
- Unless we catch this, the subshell will dump core when
- trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is
- usually 0x0. */
- internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"),
- sig, trap_list[sig]);
- if (trap_list[sig] == (char *)DEFAULT_SIG)
- {
- internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig));
- kill (getpid (), sig);
- }
- }
- else
- {
- /* XXX - should we use save_parser_state/restore_parser_state? */
- save_parser_state (&pstate);
- save_subst_varlist = subst_assign_varlist;
- subst_assign_varlist = 0;
-
-#if defined (JOB_CONTROL)
- save_pipeline (1); /* XXX only provides one save level */
-#endif
- /* XXX - set pending_traps[sig] = 0 here? */
- pending_traps[sig] = 0;
- evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
-#if defined (JOB_CONTROL)
- restore_pipeline (1);
-#endif
-
- subst_assign_varlist = save_subst_varlist;
- restore_parser_state (&pstate);
- }
-
- pending_traps[sig] = 0; /* XXX - move before evalstring? */
- running_trap = 0;
- }
- }
-
-#if defined (ARRAY_VARS)
- restore_pipestatus_array (ps);
-#endif
- last_command_exit_value = old_exit_value;
-}
-
-sighandler
-trap_handler (sig)
- int sig;
-{
- int oerrno;
-
- if ((sigmodes[sig] & SIG_TRAPPED) == 0)
- {
-#if defined (DEBUG)
- internal_warning ("trap_handler: signal %d: signal not trapped", sig);
-#endif
- SIGRETURN (0);
- }
-
-itrace("trap_handler: received %d", sig);
- if ((sig >= NSIG) ||
- (trap_list[sig] == (char *)DEFAULT_SIG) ||
- (trap_list[sig] == (char *)IGNORE_SIG))
- programming_error (_("trap_handler: bad signal %d"), sig);
- else
- {
- oerrno = errno;
-#if defined (MUST_REINSTALL_SIGHANDLERS)
-# if defined (JOB_CONTROL) && defined (SIGCHLD)
- if (sig != SIGCHLD)
-# endif /* JOB_CONTROL && SIGCHLD */
- set_signal_handler (sig, trap_handler);
-#endif /* MUST_REINSTALL_SIGHANDLERS */
-
- catch_flag = 1;
- pending_traps[sig]++;
-
- trapped_signal_received = sig;
-
- if (this_shell_builtin && (this_shell_builtin == wait_builtin))
- {
- wait_signal_received = sig;
- if (interrupt_immediately)
- longjmp (wait_intr_buf, 1);
- }
-
-#if defined (READLINE)
- /* Set the event hook so readline will call it after the signal handlers
- finish executing, so if this interrupted character input we can get
- quick response. */
- if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0)
- bashline_set_event_hook ();
-#endif
-
- if (interrupt_immediately)
- run_pending_traps ();
-
- errno = oerrno;
- }
-
- SIGRETURN (0);
-}
-
-int
-first_pending_trap ()
-{
- register int i;
-
- for (i = 1; i < NSIG; i++)
- if (pending_traps[i])
- return i;
- return -1;
-}
-
-int
-any_signals_trapped ()
-{
- register int i;
-
- for (i = 1; i < NSIG; i++)
- if (sigmodes[i] & SIG_TRAPPED)
- return i;
- return -1;
-}
-
-void
-check_signals ()
-{
- CHECK_ALRM; /* set by the read builtin */
- QUIT;
-}
-
-/* Convenience functions the rest of the shell can use */
-void
-check_signals_and_traps ()
-{
- check_signals ();
-
- run_pending_traps ();
-}
-
-#if defined (JOB_CONTROL) && defined (SIGCHLD)
-
-#ifdef INCLUDE_UNUSED
-/* Make COMMAND_STRING be executed when SIGCHLD is caught. */
-void
-set_sigchld_trap (command_string)
- char *command_string;
-{
- set_signal (SIGCHLD, command_string);
-}
-#endif
-
-/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD
- is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel
- to make sure that a SIGCHLD trap handler run via run_sigchld_trap can
- reset the disposition to the default and not have the original signal
- accidentally restored, undoing the user's command. */
-void
-maybe_set_sigchld_trap (command_string)
- char *command_string;
-{
- if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER)
- set_signal (SIGCHLD, command_string);
-}
-
-/* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used
- as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether
- or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */
-void
-set_impossible_sigchld_trap ()
-{
- restore_default_signal (SIGCHLD);
- change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER);
- sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */
-}
-
-/* Act as if we received SIGCHLD NCHILD times and increment
- pending_traps[SIGCHLD] by that amount. This allows us to still run the
- SIGCHLD trap once for each exited child. */
-void
-queue_sigchld_trap (nchild)
- int nchild;
-{
- if (nchild > 0)
- {
- catch_flag = 1;
- pending_traps[SIGCHLD] += nchild;
- trapped_signal_received = SIGCHLD;
- }
-}
-#endif /* JOB_CONTROL && SIGCHLD */
-
-void
-set_debug_trap (command)
- char *command;
-{
- set_signal (DEBUG_TRAP, command);
-}
-
-void
-set_error_trap (command)
- char *command;
-{
- set_signal (ERROR_TRAP, command);
-}
-
-void
-set_return_trap (command)
- char *command;
-{
- set_signal (RETURN_TRAP, command);
-}
-
-#ifdef INCLUDE_UNUSED
-void
-set_sigint_trap (command)
- char *command;
-{
- set_signal (SIGINT, command);
-}
-#endif
-
-/* Reset the SIGINT handler so that subshells that are doing `shellsy'
- things, like waiting for command substitution or executing commands
- in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
-SigHandler *
-set_sigint_handler ()
-{
- if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
- return ((SigHandler *)SIG_IGN);
-
- else if (sigmodes[SIGINT] & SIG_IGNORED)
- return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
-
- else if (sigmodes[SIGINT] & SIG_TRAPPED)
- return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
-
- /* The signal is not trapped, so set the handler to the shell's special
- interrupt handler. */
- else if (interactive) /* XXX - was interactive_shell */
- return (set_signal_handler (SIGINT, sigint_sighandler));
- else
- return (set_signal_handler (SIGINT, termsig_sighandler));
-}
-
-/* Return the correct handler for signal SIG according to the values in
- sigmodes[SIG]. */
-SigHandler *
-trap_to_sighandler (sig)
- int sig;
-{
- if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE))
- return (SIG_IGN);
- else if (sigmodes[sig] & SIG_TRAPPED)
- return (trap_handler);
- else
- return (SIG_DFL);
-}
-
-/* Set SIG to call STRING as a command. */
-void
-set_signal (sig, string)
- int sig;
- char *string;
-{
- sigset_t set, oset;
-
- if (SPECIAL_TRAP (sig))
- {
- change_signal (sig, savestring (string));
- if (sig == EXIT_TRAP && interactive == 0)
- initialize_terminating_signals ();
- return;
- }
-
- /* A signal ignored on entry to the shell cannot be trapped or reset, but
- no error is reported when attempting to do so. -- Posix.2 */
- if (sigmodes[sig] & SIG_HARD_IGNORE)
- return;
-
- /* Make sure we have original_signals[sig] if the signal has not yet
- been trapped. */
- if ((sigmodes[sig] & SIG_TRAPPED) == 0)
- {
- /* If we aren't sure of the original value, check it. */
- if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
- GETORIGSIG (sig);
- if (original_signals[sig] == SIG_IGN)
- return;
- }
-
- /* Only change the system signal handler if SIG_NO_TRAP is not set.
- The trap command string is changed in either case. The shell signal
- handlers for SIGINT and SIGCHLD run the user specified traps in an
- environment in which it is safe to do so. */
- if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
- {
- BLOCK_SIGNAL (sig, set, oset);
- change_signal (sig, savestring (string));
- set_signal_handler (sig, trap_handler);
- UNBLOCK_SIGNAL (oset);
- }
- else
- change_signal (sig, savestring (string));
-}
-
-static void
-free_trap_command (sig)
- int sig;
-{
- if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
- (trap_list[sig] != (char *)IGNORE_SIG) &&
- (trap_list[sig] != (char *)DEFAULT_SIG) &&
- (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
- free (trap_list[sig]);
-}
-
-/* If SIG has a string assigned to it, get rid of it. Then give it
- VALUE. */
-static void
-change_signal (sig, value)
- int sig;
- char *value;
-{
- if ((sigmodes[sig] & SIG_INPROGRESS) == 0)
- free_trap_command (sig);
- trap_list[sig] = value;
-
- sigmodes[sig] |= SIG_TRAPPED;
- if (value == (char *)IGNORE_SIG)
- sigmodes[sig] |= SIG_IGNORED;
- else
- sigmodes[sig] &= ~SIG_IGNORED;
- if (sigmodes[sig] & SIG_INPROGRESS)
- sigmodes[sig] |= SIG_CHANGED;
-}
-
-void
-get_original_signal (sig)
- int sig;
-{
- /* If we aren't sure the of the original value, then get it. */
- if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
- GETORIGSIG (sig);
-}
-
-void
-get_all_original_signals ()
-{
- register int i;
-
- for (i = 1; i < NSIG; i++)
- GET_ORIGINAL_SIGNAL (i);
-}
-
-void
-set_original_signal (sig, handler)
- int sig;
- SigHandler *handler;
-{
- if (sig > 0 && sig < NSIG && original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
- SETORIGSIG (sig, handler);
-}
-
-/* Restore the default action for SIG; i.e., the action the shell
- would have taken before you used the trap command. This is called
- from trap_builtin (), which takes care to restore the handlers for
- the signals the shell treats specially. */
-void
-restore_default_signal (sig)
- int sig;
-{
- if (SPECIAL_TRAP (sig))
- {
- if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) ||
- (sigmodes[sig] & SIG_INPROGRESS) == 0)
- free_trap_command (sig);
- trap_list[sig] = (char *)NULL;
- sigmodes[sig] &= ~SIG_TRAPPED;
- if (sigmodes[sig] & SIG_INPROGRESS)
- sigmodes[sig] |= SIG_CHANGED;
- return;
- }
-
- GET_ORIGINAL_SIGNAL (sig);
-
- /* A signal ignored on entry to the shell cannot be trapped or reset, but
- no error is reported when attempting to do so. Thanks Posix.2. */
- if (sigmodes[sig] & SIG_HARD_IGNORE)
- return;
-
- /* If we aren't trapping this signal, don't bother doing anything else. */
- /* We special-case SIGCHLD and IMPOSSIBLE_TRAP_HANDLER (see above) as a
- sentinel to determine whether or not disposition is reset to the default
- while the trap handler is executing. */
- if (((sigmodes[sig] & SIG_TRAPPED) == 0) &&
- (sig != SIGCHLD || (sigmodes[sig] & SIG_INPROGRESS) == 0 || trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
- return;
-
- /* Only change the signal handler for SIG if it allows it. */
- if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
- set_signal_handler (sig, original_signals[sig]);
-
- /* Change the trap command in either case. */
- change_signal (sig, (char *)DEFAULT_SIG);
-
- /* Mark the signal as no longer trapped. */
- sigmodes[sig] &= ~SIG_TRAPPED;
-}
-
-/* Make this signal be ignored. */
-void
-ignore_signal (sig)
- int sig;
-{
- if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0))
- {
- change_signal (sig, (char *)IGNORE_SIG);
- return;
- }
-
- GET_ORIGINAL_SIGNAL (sig);
-
- /* A signal ignored on entry to the shell cannot be trapped or reset.
- No error is reported when the user attempts to do so. */
- if (sigmodes[sig] & SIG_HARD_IGNORE)
- return;
-
- /* If already trapped and ignored, no change necessary. */
- if (sigmodes[sig] & SIG_IGNORED)
- return;
-
- /* Only change the signal handler for SIG if it allows it. */
- if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
- set_signal_handler (sig, SIG_IGN);
-
- /* Change the trap command in either case. */
- change_signal (sig, (char *)IGNORE_SIG);
-}
-
-/* Handle the calling of "trap 0". The only sticky situation is when
- the command to be executed includes an "exit". This is why we have
- to provide our own place for top_level to jump to. */
-int
-run_exit_trap ()
-{
- char *trap_command;
- int code, function_code, retval;
-#if defined (ARRAY_VARS)
- ARRAY *ps;
-#endif
-
- trap_saved_exit_value = last_command_exit_value;
-#if defined (ARRAY_VARS)
- ps = save_pipestatus_array ();
-#endif
- function_code = 0;
-
- /* Run the trap only if signal 0 is trapped and not ignored, and we are not
- currently running in the trap handler (call to exit in the list of
- commands given to trap 0). */
- if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
- (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
- {
- trap_command = savestring (trap_list[EXIT_TRAP]);
- sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
- sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
-
- retval = trap_saved_exit_value;
- running_trap = 1;
-
- code = setjmp_nosigs (top_level);
-
- /* If we're in a function, make sure return longjmps come here, too. */
- if (return_catch_flag)
- function_code = setjmp_nosigs (return_catch);
-
- if (code == 0 && function_code == 0)
- {
- reset_parser ();
- parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
- }
- else if (code == ERREXIT)
- retval = last_command_exit_value;
- else if (code == EXITPROG)
- retval = last_command_exit_value;
- else if (function_code != 0)
- retval = return_catch_value;
- else
- retval = trap_saved_exit_value;
-
- running_trap = 0;
-#if defined (ARRAY_VARS)
- array_dispose (ps);
-#endif
-
- return retval;
- }
-
-#if defined (ARRAY_VARS)
- restore_pipestatus_array (ps);
-#endif
- return (trap_saved_exit_value);
-}
-
-void
-run_trap_cleanup (sig)
- int sig;
-{
- sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
-}
-
-#define RECURSIVE_SIG(s) (SPECIAL_TRAP(s) == 0)
-
-/* Run a trap command for SIG. SIG is one of the signals the shell treats
- specially. Returns the exit status of the executed trap command list. */
-static int
-_run_trap_internal (sig, tag)
- int sig;
- char *tag;
-{
- char *trap_command, *old_trap;
- int trap_exit_value, *token_state;
- volatile int save_return_catch_flag, function_code;
- int flags;
- procenv_t save_return_catch;
- WORD_LIST *save_subst_varlist;
- sh_parser_state_t pstate;
-#if defined (ARRAY_VARS)
- ARRAY *ps;
-#endif
-
- trap_exit_value = function_code = 0;
- trap_saved_exit_value = last_command_exit_value;
- /* Run the trap only if SIG is trapped and not ignored, and we are not
- currently executing in the trap handler. */
- if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
- (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
-#if 0
- /* Uncomment this to allow some special signals to recursively execute
- trap handlers. */
- (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0))
-#else
- ((sigmodes[sig] & SIG_INPROGRESS) == 0))
-#endif
- {
- old_trap = trap_list[sig];
- sigmodes[sig] |= SIG_INPROGRESS;
- sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
- trap_command = savestring (old_trap);
-
- running_trap = sig + 1;
-
-#if defined (ARRAY_VARS)
- ps = save_pipestatus_array ();
-#endif
-
- save_parser_state (&pstate);
- save_subst_varlist = subst_assign_varlist;
- subst_assign_varlist = 0;
-
-#if defined (JOB_CONTROL)
- if (sig != DEBUG_TRAP) /* run_debug_trap does this */
- save_pipeline (1); /* XXX only provides one save level */
-#endif
-
- /* If we're in a function, make sure return longjmps come here, too. */
- save_return_catch_flag = return_catch_flag;
- if (return_catch_flag)
- {
- COPY_PROCENV (return_catch, save_return_catch);
- function_code = setjmp_nosigs (return_catch);
- }
-
- flags = SEVAL_NONINT|SEVAL_NOHIST;
- if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
- flags |= SEVAL_RESETLINE;
- if (function_code == 0)
- parse_and_execute (trap_command, tag, flags);
-
- trap_exit_value = last_command_exit_value;
-
-#if defined (JOB_CONTROL)
- if (sig != DEBUG_TRAP) /* run_debug_trap does this */
- restore_pipeline (1);
-#endif
-
- subst_assign_varlist = save_subst_varlist;
- restore_parser_state (&pstate);
-
-#if defined (ARRAY_VARS)
- restore_pipestatus_array (ps);
-#endif
-
- running_trap = 0;
- sigmodes[sig] &= ~SIG_INPROGRESS;
-
- if (sigmodes[sig] & SIG_CHANGED)
- {
-#if 0
- /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in
- the places where they can be changed using unwind-protects. For
- example, look at execute_cmd.c:execute_function(). */
- if (SPECIAL_TRAP (sig) == 0)
-#endif
- free (old_trap);
- sigmodes[sig] &= ~SIG_CHANGED;
- }
-
- if (save_return_catch_flag)
- {
- return_catch_flag = save_return_catch_flag;
- return_catch_value = trap_exit_value;
- COPY_PROCENV (save_return_catch, return_catch);
- if (function_code)
- {
-#if 0
- from_return_trap = sig == RETURN_TRAP;
-#endif
- longjmp (return_catch, 1);
- }
- }
- }
-
- return trap_exit_value;
-}
-
-int
-run_debug_trap ()
-{
- int trap_exit_value;
- pid_t save_pgrp;
- int save_pipe[2];
-
- /* XXX - question: should the DEBUG trap inherit the RETURN trap? */
- trap_exit_value = 0;
- if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0))
- {
-#if defined (JOB_CONTROL)
- save_pgrp = pipeline_pgrp;
- pipeline_pgrp = 0;
- save_pipeline (1);
-# if defined (PGRP_PIPE)
- save_pgrp_pipe (save_pipe, 1);
-# endif
- stop_making_children ();
-#endif
-
- trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
-
-#if defined (JOB_CONTROL)
- pipeline_pgrp = save_pgrp;
- restore_pipeline (1);
-# if defined (PGRP_PIPE)
- close_pgrp_pipe ();
- restore_pgrp_pipe (save_pipe);
-# endif
- if (pipeline_pgrp > 0)
- give_terminal_to (pipeline_pgrp, 1);
- notify_and_cleanup ();
-#endif
-
-#if defined (DEBUGGER)
- /* If we're in the debugger and the DEBUG trap returns 2 while we're in
- a function or sourced script, we force a `return'. */
- if (debugging_mode && trap_exit_value == 2 && return_catch_flag)
- {
- return_catch_value = trap_exit_value;
- longjmp (return_catch, 1);
- }
-#endif
- }
- return trap_exit_value;
-}
-
-void
-run_error_trap ()
-{
- if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0)
- _run_trap_internal (ERROR_TRAP, "error trap");
-}
-
-void
-run_return_trap ()
-{
- int old_exit_value;
-
-#if 0
- if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
- return;
-#endif
-
- if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
- {
- old_exit_value = last_command_exit_value;
- _run_trap_internal (RETURN_TRAP, "return trap");
- last_command_exit_value = old_exit_value;
- }
-}
-
-/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and
- declared here to localize the trap functions. */
-void
-run_interrupt_trap ()
-{
- _run_trap_internal (SIGINT, "interrupt trap");
-}
-
-/* Free all the allocated strings in the list of traps and reset the trap
- values to the default. Intended to be called from subshells that want
- to complete work done by reset_signal_handlers upon execution of a
- subsequent `trap' command that changes a signal's disposition. We need
- to make sure that we duplicate the behavior of
- reset_or_restore_signal_handlers and not change the disposition of signals
- that are set to be ignored. */
-void
-free_trap_strings ()
-{
- register int i;
-
- for (i = 0; i < BASH_NSIG; i++)
- {
- if (trap_list[i] != (char *)IGNORE_SIG)
- free_trap_string (i);
- }
- trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL;
-}
-
-/* Free a trap command string associated with SIG without changing signal
- disposition. Intended to be called from free_trap_strings() */
-static void
-free_trap_string (sig)
- int sig;
-{
- change_signal (sig, (char *)DEFAULT_SIG);
- sigmodes[sig] &= ~SIG_TRAPPED;
-}
-
-/* Reset the handler for SIG to the original value but leave the trap string
- in place. */
-static void
-reset_signal (sig)
- int sig;
-{
- set_signal_handler (sig, original_signals[sig]);
- sigmodes[sig] &= ~SIG_TRAPPED;
-}
-
-/* Set the handler signal SIG to the original and free any trap
- command associated with it. */
-static void
-restore_signal (sig)
- int sig;
-{
- set_signal_handler (sig, original_signals[sig]);
- change_signal (sig, (char *)DEFAULT_SIG);
- sigmodes[sig] &= ~SIG_TRAPPED;
-}
-
-static void
-reset_or_restore_signal_handlers (reset)
- sh_resetsig_func_t *reset;
-{
- register int i;
-
- /* Take care of the exit trap first */
- if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
- {
- sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
- if (reset != reset_signal)
- {
- free_trap_command (EXIT_TRAP);
- trap_list[EXIT_TRAP] = (char *)NULL;
- }
- }
-
- for (i = 1; i < NSIG; i++)
- {
- if (sigmodes[i] & SIG_TRAPPED)
- {
- if (trap_list[i] == (char *)IGNORE_SIG)
- set_signal_handler (i, SIG_IGN);
- else
- (*reset) (i);
- }
- else if (sigmodes[i] & SIG_SPECIAL)
- (*reset) (i);
- }
-
- /* Command substitution and other child processes don't inherit the
- debug, error, or return traps. If we're in the debugger, and the
- `functrace' or `errtrace' options have been set, then let command
- substitutions inherit them. Let command substitution inherit the
- RETURN trap if we're in the debugger and tracing functions. */
- if (function_trace_mode == 0)
- {
- sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED;
- sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
- }
- if (error_trace_mode == 0)
- sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
-}
-
-/* Reset trapped signals to their original values, but don't free the
- trap strings. Called by the command substitution code and other places
- that create a "subshell environment". */
-void
-reset_signal_handlers ()
-{
- reset_or_restore_signal_handlers (reset_signal);
-}
-
-/* Reset all trapped signals to their original values. Signals set to be
- ignored with trap '' SIGNAL should be ignored, so we make sure that they
- are. Called by child processes after they are forked. */
-void
-restore_original_signals ()
-{
- reset_or_restore_signal_handlers (restore_signal);
-}
-
-/* If a trap handler exists for signal SIG, then call it; otherwise just
- return failure. Returns 1 if it called the trap handler. */
-int
-maybe_call_trap_handler (sig)
- int sig;
-{
- /* Call the trap handler for SIG if the signal is trapped and not ignored. */
- if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
- {
- switch (sig)
- {
- case SIGINT:
- run_interrupt_trap ();
- break;
- case EXIT_TRAP:
- run_exit_trap ();
- break;
- case DEBUG_TRAP:
- run_debug_trap ();
- break;
- case ERROR_TRAP:
- run_error_trap ();
- break;
- default:
- trap_handler (sig);
- break;
- }
- return (1);
- }
- else
- return (0);
-}
-
-int
-signal_is_trapped (sig)
- int sig;
-{
- return (sigmodes[sig] & SIG_TRAPPED);
-}
-
-int
-signal_is_pending (sig)
- int sig;
-{
- return (pending_traps[sig]);
-}
-
-int
-signal_is_special (sig)
- int sig;
-{
- return (sigmodes[sig] & SIG_SPECIAL);
-}
-
-int
-signal_is_ignored (sig)
- int sig;
-{
- return (sigmodes[sig] & SIG_IGNORED);
-}
-
-int
-signal_is_hard_ignored (sig)
- int sig;
-{
- return (sigmodes[sig] & SIG_HARD_IGNORE);
-}
-
-void
-set_signal_hard_ignored (sig)
- int sig;
-{
- sigmodes[sig] |= SIG_HARD_IGNORE;
- original_signals[sig] = SIG_IGN;
-}
-
-void
-set_signal_ignored (sig)
- int sig;
-{
- original_signals[sig] = SIG_IGN;
-}
-
-int
-signal_in_progress (sig)
- int sig;
-{
- return (sigmodes[sig] & SIG_INPROGRESS);
-}
+++ /dev/null
-/* variables.c -- Functions for hacking shell variables. */
-
-/* Copyright (C) 1987-2014 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "config.h"
-
-#include "bashtypes.h"
-#include "posixstat.h"
-#include "posixtime.h"
-
-#if defined (__QNX__)
-# if defined (__QNXNTO__)
-# include <sys/netmgr.h>
-# else
-# include <sys/vc.h>
-# endif /* !__QNXNTO__ */
-#endif /* __QNX__ */
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include "chartypes.h"
-#if defined (HAVE_PWD_H)
-# include <pwd.h>
-#endif
-#include "bashansi.h"
-#include "bashintl.h"
-
-#define NEED_XTRACE_SET_DECL
-
-#include "shell.h"
-#include "flags.h"
-#include "execute_cmd.h"
-#include "findcmd.h"
-#include "mailcheck.h"
-#include "input.h"
-#include "hashcmd.h"
-#include "pathexp.h"
-#include "alias.h"
-#include "jobs.h"
-
-#include "version.h"
-
-#include "builtins/getopt.h"
-#include "builtins/common.h"
-#include "builtins/builtext.h"
-
-#if defined (READLINE)
-# include "bashline.h"
-# include <readline/readline.h>
-#else
-# include <tilde/tilde.h>
-#endif
-
-#if defined (HISTORY)
-# include "bashhist.h"
-# include <readline/history.h>
-#endif /* HISTORY */
-
-#if defined (PROGRAMMABLE_COMPLETION)
-# include "pcomplete.h"
-#endif
-
-#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */
-
-#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
-
-#define BASHFUNC_PREFIX "BASH_FUNC_"
-#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
-#define BASHFUNC_SUFFIX "()"
-#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
-
-/* flags for find_variable_internal */
-
-#define FV_FORCETEMPENV 0x01
-#define FV_SKIPINVISIBLE 0x02
-
-extern char **environ;
-
-/* Variables used here and defined in other files. */
-extern int posixly_correct;
-extern int line_number, line_number_base;
-extern int subshell_environment, indirection_level, subshell_level;
-extern int build_version, patch_level;
-extern int expanding_redir;
-extern int last_command_exit_value;
-extern char *dist_version, *release_status;
-extern char *shell_name;
-extern char *primary_prompt, *secondary_prompt;
-extern char *current_host_name;
-extern sh_builtin_func_t *this_shell_builtin;
-extern SHELL_VAR *this_shell_function;
-extern char *the_printed_command_except_trap;
-extern char *this_command_name;
-extern char *command_execution_string;
-extern time_t shell_start_time;
-extern int assigning_in_environment;
-extern int executing_builtin;
-extern int funcnest_max;
-
-#if defined (READLINE)
-extern int no_line_editing;
-extern int perform_hostname_completion;
-#endif
-
-/* The list of shell variables that the user has created at the global
- scope, or that came from the environment. */
-VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;
-
-/* The current list of shell variables, including function scopes */
-VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;
-
-/* The list of shell functions that the user has created, or that came from
- the environment. */
-HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;
-
-#if defined (DEBUGGER)
-/* The table of shell function definitions that the user defined or that
- came from the environment. */
-HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;
-#endif
-
-/* The current variable context. This is really a count of how deep into
- executing functions we are. */
-int variable_context = 0;
-
-/* The set of shell assignments which are made only in the environment
- for a single command. */
-HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;
-
-/* Set to non-zero if an assignment error occurs while putting variables
- into the temporary environment. */
-int tempenv_assign_error;
-
-/* Some funky variables which are known about specially. Here is where
- "$*", "$1", and all the cruft is kept. */
-char *dollar_vars[10];
-WORD_LIST *rest_of_args = (WORD_LIST *)NULL;
-
-/* The value of $$. */
-pid_t dollar_dollar_pid;
-
-/* Non-zero means that we have to remake EXPORT_ENV. */
-int array_needs_making = 1;
-
-/* The number of times BASH has been executed. This is set
- by initialize_variables (). */
-int shell_level = 0;
-
-/* An array which is passed to commands as their environment. It is
- manufactured from the union of the initial environment and the
- shell variables that are marked for export. */
-char **export_env = (char **)NULL;
-static int export_env_index;
-static int export_env_size;
-
-#if defined (READLINE)
-static int winsize_assignment; /* currently assigning to LINES or COLUMNS */
-#endif
-
-static HASH_TABLE *last_table_searched; /* hash_lookup sets this */
-
-/* Some forward declarations. */
-static void create_variable_tables __P((void));
-
-static void set_machine_vars __P((void));
-static void set_home_var __P((void));
-static void set_shell_var __P((void));
-static char *get_bash_name __P((void));
-static void initialize_shell_level __P((void));
-static void uidset __P((void));
-#if defined (ARRAY_VARS)
-static void make_vers_array __P((void));
-#endif
-
-static SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
-#if defined (ARRAY_VARS)
-static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));
-#endif
-static SHELL_VAR *get_self __P((SHELL_VAR *));
-
-#if defined (ARRAY_VARS)
-static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
-static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));
-#endif
-
-static SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));
-static SHELL_VAR *get_seconds __P((SHELL_VAR *));
-static SHELL_VAR *init_seconds_var __P((void));
-
-static int brand __P((void));
-static void sbrand __P((unsigned long)); /* set bash random number generator. */
-static void seedrand __P((void)); /* seed generator randomly */
-static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
-static SHELL_VAR *get_random __P((SHELL_VAR *));
-
-static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
-static SHELL_VAR *get_lineno __P((SHELL_VAR *));
-
-static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));
-static SHELL_VAR *get_subshell __P((SHELL_VAR *));
-
-static SHELL_VAR *get_bashpid __P((SHELL_VAR *));
-
-#if defined (HISTORY)
-static SHELL_VAR *get_histcmd __P((SHELL_VAR *));
-#endif
-
-#if defined (READLINE)
-static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));
-static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));
-#endif
-
-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
-static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));
-static SHELL_VAR *get_dirstack __P((SHELL_VAR *));
-#endif
-
-#if defined (ARRAY_VARS)
-static SHELL_VAR *get_groupset __P((SHELL_VAR *));
-
-static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));
-static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));
-static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *));
-# if defined (ALIAS)
-static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));
-static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));
-static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *));
-# endif
-#endif
-
-static SHELL_VAR *get_funcname __P((SHELL_VAR *));
-static SHELL_VAR *init_funcname_var __P((void));
-
-static void initialize_dynamic_variables __P((void));
-
-static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));
-static SHELL_VAR *new_shell_variable __P((const char *));
-static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));
-static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));
-
-static void dispose_variable_value __P((SHELL_VAR *));
-static void free_variable_hash_data __P((PTR_T));
-
-static VARLIST *vlist_alloc __P((int));
-static VARLIST *vlist_realloc __P((VARLIST *, int));
-static void vlist_add __P((VARLIST *, SHELL_VAR *, int));
-
-static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));
-
-static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));
-
-static SHELL_VAR **vapply __P((sh_var_map_func_t *));
-static SHELL_VAR **fapply __P((sh_var_map_func_t *));
-
-static int visible_var __P((SHELL_VAR *));
-static int visible_and_exported __P((SHELL_VAR *));
-static int export_environment_candidate __P((SHELL_VAR *));
-static int local_and_exported __P((SHELL_VAR *));
-static int variable_in_context __P((SHELL_VAR *));
-#if defined (ARRAY_VARS)
-static int visible_array_vars __P((SHELL_VAR *));
-#endif
-
-static SHELL_VAR *find_nameref_at_context __P((SHELL_VAR *, VAR_CONTEXT *));
-static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
-static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
-
-static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
-static void push_temp_var __P((PTR_T));
-static void propagate_temp_var __P((PTR_T));
-static void dispose_temporary_env __P((sh_free_func_t *));
-
-static inline char *mk_env_string __P((const char *, const char *, int));
-static char **make_env_array_from_var_list __P((SHELL_VAR **));
-static char **make_var_export_array __P((VAR_CONTEXT *));
-static char **make_func_export_array __P((void));
-static void add_temp_array_to_env __P((char **, int, int));
-
-static int n_shell_variables __P((void));
-static int set_context __P((SHELL_VAR *));
-
-static void push_func_var __P((PTR_T));
-static void push_exported_var __P((PTR_T));
-
-static inline int find_special_var __P((const char *));
-
-static void
-create_variable_tables ()
-{
- if (shell_variables == 0)
- {
- shell_variables = global_variables = new_var_context ((char *)NULL, 0);
- shell_variables->scope = 0;
- shell_variables->table = hash_create (0);
- }
-
- if (shell_functions == 0)
- shell_functions = hash_create (0);
-
-#if defined (DEBUGGER)
- if (shell_function_defs == 0)
- shell_function_defs = hash_create (0);
-#endif
-}
-
-/* Initialize the shell variables from the current environment.
- If PRIVMODE is nonzero, don't import functions from ENV or
- parse $SHELLOPTS. */
-void
-initialize_shell_variables (env, privmode)
- char **env;
- int privmode;
-{
- char *name, *string, *temp_string;
- int c, char_index, string_index, string_length, ro;
- SHELL_VAR *temp_var;
-
- create_variable_tables ();
-
- for (string_index = 0; string = env[string_index++]; )
- {
- char_index = 0;
- name = string;
- while ((c = *string++) && c != '=')
- ;
- if (string[-1] == '=')
- char_index = string - name - 1;
-
- /* If there are weird things in the environment, like `=xxx' or a
- string without an `=', just skip them. */
- if (char_index == 0)
- continue;
-
- /* ASSERT(name[char_index] == '=') */
- name[char_index] = '\0';
- /* Now, name = env variable name, string = env variable value, and
- char_index == strlen (name) */
-
- temp_var = (SHELL_VAR *)NULL;
-
- /* If exported function, define it now. Don't import functions from
- the environment in privileged mode. */
- if (privmode == 0 && read_but_dont_execute == 0 &&
- STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
- STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
- STREQN ("() {", string, 4))
- {
- size_t namelen;
- char *tname; /* desired imported function name */
-
- namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
-
- tname = name + BASHFUNC_PREFLEN; /* start of func name */
- tname[namelen] = '\0'; /* now tname == func name */
-
- string_length = strlen (string);
- temp_string = (char *)xmalloc (namelen + string_length + 2);
-
- memcpy (temp_string, tname, namelen);
- temp_string[namelen] = ' ';
- memcpy (temp_string + namelen + 1, string, string_length + 1);
-
- /* Don't import function names that are invalid identifiers from the
- environment, though we still allow them to be defined as shell
- variables. */
- if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
- parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
-
- if (temp_var = find_function (tname))
- {
- VSETATTR (temp_var, (att_exported|att_imported));
- array_needs_making = 1;
- }
- else
- {
- if (temp_var = bind_variable (name, string, 0))
- {
- VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- array_needs_making = 1;
- }
- last_command_exit_value = 1;
- report_error (_("error importing function definition for `%s'"), tname);
- }
-
- /* Restore original suffix */
- tname[namelen] = BASHFUNC_SUFFIX[0];
- }
-#if defined (ARRAY_VARS)
-# if ARRAY_EXPORT
- /* Array variables may not yet be exported. */
- else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
- {
- string_length = 1;
- temp_string = extract_array_assignment_list (string, &string_length);
- temp_var = assign_array_from_string (name, temp_string);
- FREE (temp_string);
- VSETATTR (temp_var, (att_exported | att_imported));
- array_needs_making = 1;
- }
-# endif /* ARRAY_EXPORT */
-#endif
-#if 0
- else if (legal_identifier (name))
-#else
- else
-#endif
- {
- ro = 0;
- if (posixly_correct && STREQ (name, "SHELLOPTS"))
- {
- temp_var = find_variable ("SHELLOPTS");
- ro = temp_var && readonly_p (temp_var);
- if (temp_var)
- VUNSETATTR (temp_var, att_readonly);
- }
- temp_var = bind_variable (name, string, 0);
- if (temp_var)
- {
- if (legal_identifier (name))
- VSETATTR (temp_var, (att_exported | att_imported));
- else
- VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
- if (ro)
- VSETATTR (temp_var, att_readonly);
- array_needs_making = 1;
- }
- }
-
- name[char_index] = '=';
- /* temp_var can be NULL if it was an exported function with a syntax
- error (a different bug, but it still shouldn't dump core). */
- if (temp_var && function_p (temp_var) == 0) /* XXX not yet */
- {
- CACHE_IMPORTSTR (temp_var, name);
- }
- }
-
- set_pwd ();
-
- /* Set up initial value of $_ */
- temp_var = set_if_not ("_", dollar_vars[0]);
-
- /* Remember this pid. */
- dollar_dollar_pid = getpid ();
-
- /* Now make our own defaults in case the vars that we think are
- important are missing. */
- temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);
-#if 0
- set_auto_export (temp_var); /* XXX */
-#endif
-
- temp_var = set_if_not ("TERM", "dumb");
-#if 0
- set_auto_export (temp_var); /* XXX */
-#endif
-
-#if defined (__QNX__)
- /* set node id -- don't import it from the environment */
- {
- char node_name[22];
-# if defined (__QNXNTO__)
- netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));
-# else
- qnx_nidtostr (getnid (), node_name, sizeof (node_name));
-# endif
- temp_var = bind_variable ("NODE", node_name, 0);
- set_auto_export (temp_var);
- }
-#endif
-
- /* set up the prompts. */
- if (interactive_shell)
- {
-#if defined (PROMPT_STRING_DECODE)
- set_if_not ("PS1", primary_prompt);
-#else
- if (current_user.uid == -1)
- get_current_user_info ();
- set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);
-#endif
- set_if_not ("PS2", secondary_prompt);
- }
- set_if_not ("PS4", "+ ");
-
- /* Don't allow IFS to be imported from the environment. */
- temp_var = bind_variable ("IFS", " \t\n", 0);
- setifs (temp_var);
-
- /* Magic machine types. Pretty convenient. */
- set_machine_vars ();
-
- /* Default MAILCHECK for interactive shells. Defer the creation of a
- default MAILPATH until the startup files are read, because MAIL
- names a mail file if MAILPATH is not set, and we should provide a
- default only if neither is set. */
- if (interactive_shell)
- {
- temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60");
- VSETATTR (temp_var, att_integer);
- }
-
- /* Do some things with shell level. */
- initialize_shell_level ();
-
- set_ppid ();
-
- /* Initialize the `getopts' stuff. */
- temp_var = bind_variable ("OPTIND", "1", 0);
- VSETATTR (temp_var, att_integer);
- getopts_reset (0);
- bind_variable ("OPTERR", "1", 0);
- sh_opterr = 1;
-
- if (login_shell == 1 && posixly_correct == 0)
- set_home_var ();
-
- /* Get the full pathname to THIS shell, and set the BASH variable
- to it. */
- name = get_bash_name ();
- temp_var = bind_variable ("BASH", name, 0);
- free (name);
-
- /* Make the exported environment variable SHELL be the user's login
- shell. Note that the `tset' command looks at this variable
- to determine what style of commands to output; if it ends in "csh",
- then C-shell commands are output, else Bourne shell commands. */
- set_shell_var ();
-
- /* Make a variable called BASH_VERSION which contains the version info. */
- bind_variable ("BASH_VERSION", shell_version_string (), 0);
-#if defined (ARRAY_VARS)
- make_vers_array ();
-#endif
-
- if (command_execution_string)
- bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
-
- /* Find out if we're supposed to be in Posix.2 mode via an
- environment variable. */
- temp_var = find_variable ("POSIXLY_CORRECT");
- if (!temp_var)
- temp_var = find_variable ("POSIX_PEDANTIC");
- if (temp_var && imported_p (temp_var))
- sv_strict_posix (temp_var->name);
-
-#if defined (HISTORY)
- /* Set history variables to defaults, and then do whatever we would
- do if the variable had just been set. Do this only in the case
- that we are remembering commands on the history list. */
- if (remember_on_history)
- {
- name = bash_tilde_expand (posixly_correct ? "~/.sh_history" : "~/.bash_history", 0);
-
- set_if_not ("HISTFILE", name);
- free (name);
- }
-#endif /* HISTORY */
-
- /* Seed the random number generator. */
- seedrand ();
-
- /* Handle some "special" variables that we may have inherited from a
- parent shell. */
- if (interactive_shell)
- {
- temp_var = find_variable ("IGNOREEOF");
- if (!temp_var)
- temp_var = find_variable ("ignoreeof");
- if (temp_var && imported_p (temp_var))
- sv_ignoreeof (temp_var->name);
- }
-
-#if defined (HISTORY)
- if (interactive_shell && remember_on_history)
- {
- sv_history_control ("HISTCONTROL");
- sv_histignore ("HISTIGNORE");
- sv_histtimefmt ("HISTTIMEFORMAT");
- }
-#endif /* HISTORY */
-
-#if defined (READLINE) && defined (STRICT_POSIX)
- /* POSIXLY_CORRECT will only be 1 here if the shell was compiled
- -DSTRICT_POSIX */
- if (interactive_shell && posixly_correct && no_line_editing == 0)
- rl_prefer_env_winsize = 1;
-#endif /* READLINE && STRICT_POSIX */
-
- /*
- * 24 October 2001
- *
- * I'm tired of the arguing and bug reports. Bash now leaves SSH_CLIENT
- * and SSH2_CLIENT alone. I'm going to rely on the shell_level check in
- * isnetconn() to avoid running the startup files more often than wanted.
- * That will, of course, only work if the user's login shell is bash, so
- * I've made that behavior conditional on SSH_SOURCE_BASHRC being defined
- * in config-top.h.
- */
-#if 0
- temp_var = find_variable ("SSH_CLIENT");
- if (temp_var && imported_p (temp_var))
- {
- VUNSETATTR (temp_var, att_exported);
- array_needs_making = 1;
- }
- temp_var = find_variable ("SSH2_CLIENT");
- if (temp_var && imported_p (temp_var))
- {
- VUNSETATTR (temp_var, att_exported);
- array_needs_making = 1;
- }
-#endif
-
- /* Get the user's real and effective user ids. */
- uidset ();
-
- temp_var = find_variable ("BASH_XTRACEFD");
- if (temp_var && imported_p (temp_var))
- sv_xtracefd (temp_var->name);
-
- /* Initialize the dynamic variables, and seed their values. */
- initialize_dynamic_variables ();
-}
-
-/* **************************************************************** */
-/* */
-/* Setting values for special shell variables */
-/* */
-/* **************************************************************** */
-
-static void
-set_machine_vars ()
-{
- SHELL_VAR *temp_var;
-
- temp_var = set_if_not ("HOSTTYPE", HOSTTYPE);
- temp_var = set_if_not ("OSTYPE", OSTYPE);
- temp_var = set_if_not ("MACHTYPE", MACHTYPE);
-
- temp_var = set_if_not ("HOSTNAME", current_host_name);
-}
-
-/* Set $HOME to the information in the password file if we didn't get
- it from the environment. */
-
-/* This function is not static so the tilde and readline libraries can
- use it. */
-char *
-sh_get_home_dir ()
-{
- if (current_user.home_dir == 0)
- get_current_user_info ();
- return current_user.home_dir;
-}
-
-static void
-set_home_var ()
-{
- SHELL_VAR *temp_var;
-
- temp_var = find_variable ("HOME");
- if (temp_var == 0)
- temp_var = bind_variable ("HOME", sh_get_home_dir (), 0);
-#if 0
- VSETATTR (temp_var, att_exported);
-#endif
-}
-
-/* Set $SHELL to the user's login shell if it is not already set. Call
- get_current_user_info if we haven't already fetched the shell. */
-static void
-set_shell_var ()
-{
- SHELL_VAR *temp_var;
-
- temp_var = find_variable ("SHELL");
- if (temp_var == 0)
- {
- if (current_user.shell == 0)
- get_current_user_info ();
- temp_var = bind_variable ("SHELL", current_user.shell, 0);
- }
-#if 0
- VSETATTR (temp_var, att_exported);
-#endif
-}
-
-static char *
-get_bash_name ()
-{
- char *name;
-
- if ((login_shell == 1) && RELPATH(shell_name))
- {
- if (current_user.shell == 0)
- get_current_user_info ();
- name = savestring (current_user.shell);
- }
- else if (ABSPATH(shell_name))
- name = savestring (shell_name);
- else if (shell_name[0] == '.' && shell_name[1] == '/')
- {
- /* Fast path for common case. */
- char *cdir;
- int len;
-
- cdir = get_string_value ("PWD");
- if (cdir)
- {
- len = strlen (cdir);
- name = (char *)xmalloc (len + strlen (shell_name) + 1);
- strcpy (name, cdir);
- strcpy (name + len, shell_name + 1);
- }
- else
- name = savestring (shell_name);
- }
- else
- {
- char *tname;
- int s;
-
- tname = find_user_command (shell_name);
-
- if (tname == 0)
- {
- /* Try the current directory. If there is not an executable
- there, just punt and use the login shell. */
- s = file_status (shell_name);
- if (s & FS_EXECABLE)
- {
- tname = make_absolute (shell_name, get_string_value ("PWD"));
- if (*shell_name == '.')
- {
- name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
- if (name == 0)
- name = tname;
- else
- free (tname);
- }
- else
- name = tname;
- }
- else
- {
- if (current_user.shell == 0)
- get_current_user_info ();
- name = savestring (current_user.shell);
- }
- }
- else
- {
- name = full_pathname (tname);
- free (tname);
- }
- }
-
- return (name);
-}
-
-void
-adjust_shell_level (change)
- int change;
-{
- char new_level[5], *old_SHLVL;
- intmax_t old_level;
- SHELL_VAR *temp_var;
-
- old_SHLVL = get_string_value ("SHLVL");
- if (old_SHLVL == 0 || *old_SHLVL == '\0' || legal_number (old_SHLVL, &old_level) == 0)
- old_level = 0;
-
- shell_level = old_level + change;
- if (shell_level < 0)
- shell_level = 0;
- else if (shell_level > 1000)
- {
- internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
- shell_level = 1;
- }
-
- /* We don't need the full generality of itos here. */
- if (shell_level < 10)
- {
- new_level[0] = shell_level + '0';
- new_level[1] = '\0';
- }
- else if (shell_level < 100)
- {
- new_level[0] = (shell_level / 10) + '0';
- new_level[1] = (shell_level % 10) + '0';
- new_level[2] = '\0';
- }
- else if (shell_level < 1000)
- {
- new_level[0] = (shell_level / 100) + '0';
- old_level = shell_level % 100;
- new_level[1] = (old_level / 10) + '0';
- new_level[2] = (old_level % 10) + '0';
- new_level[3] = '\0';
- }
-
- temp_var = bind_variable ("SHLVL", new_level, 0);
- set_auto_export (temp_var);
-}
-
-static void
-initialize_shell_level ()
-{
- adjust_shell_level (1);
-}
-
-/* If we got PWD from the environment, update our idea of the current
- working directory. In any case, make sure that PWD exists before
- checking it. It is possible for getcwd () to fail on shell startup,
- and in that case, PWD would be undefined. If this is an interactive
- login shell, see if $HOME is the current working directory, and if
- that's not the same string as $PWD, set PWD=$HOME. */
-
-void
-set_pwd ()
-{
- SHELL_VAR *temp_var, *home_var;
- char *temp_string, *home_string;
-
- home_var = find_variable ("HOME");
- home_string = home_var ? value_cell (home_var) : (char *)NULL;
-
- temp_var = find_variable ("PWD");
- if (temp_var && imported_p (temp_var) &&
- (temp_string = value_cell (temp_var)) &&
- same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- set_working_directory (temp_string);
- else if (home_string && interactive_shell && login_shell &&
- same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL))
- {
- set_working_directory (home_string);
- temp_var = bind_variable ("PWD", home_string, 0);
- set_auto_export (temp_var);
- }
- else
- {
- temp_string = get_working_directory ("shell-init");
- if (temp_string)
- {
- temp_var = bind_variable ("PWD", temp_string, 0);
- set_auto_export (temp_var);
- free (temp_string);
- }
- }
-
- /* According to the Single Unix Specification, v2, $OLDPWD is an
- `environment variable' and therefore should be auto-exported.
- Make a dummy invisible variable for OLDPWD, and mark it as exported. */
- temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
- VSETATTR (temp_var, (att_exported | att_invisible));
-}
-
-/* Make a variable $PPID, which holds the pid of the shell's parent. */
-void
-set_ppid ()
-{
- char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
- SHELL_VAR *temp_var;
-
- name = inttostr (getppid (), namebuf, sizeof(namebuf));
- temp_var = find_variable ("PPID");
- if (temp_var)
- VUNSETATTR (temp_var, (att_readonly | att_exported));
- temp_var = bind_variable ("PPID", name, 0);
- VSETATTR (temp_var, (att_readonly | att_integer));
-}
-
-static void
-uidset ()
-{
- char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
- register SHELL_VAR *v;
-
- b = inttostr (current_user.uid, buff, sizeof (buff));
- v = find_variable ("UID");
- if (v == 0)
- {
- v = bind_variable ("UID", b, 0);
- VSETATTR (v, (att_readonly | att_integer));
- }
-
- if (current_user.euid != current_user.uid)
- b = inttostr (current_user.euid, buff, sizeof (buff));
-
- v = find_variable ("EUID");
- if (v == 0)
- {
- v = bind_variable ("EUID", b, 0);
- VSETATTR (v, (att_readonly | att_integer));
- }
-}
-
-#if defined (ARRAY_VARS)
-static void
-make_vers_array ()
-{
- SHELL_VAR *vv;
- ARRAY *av;
- char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];
-
- unbind_variable ("BASH_VERSINFO");
-
- vv = make_new_array_variable ("BASH_VERSINFO");
- av = array_cell (vv);
- strcpy (d, dist_version);
- s = strchr (d, '.');
- if (s)
- *s++ = '\0';
- array_insert (av, 0, d);
- array_insert (av, 1, s);
- s = inttostr (patch_level, b, sizeof (b));
- array_insert (av, 2, s);
- s = inttostr (build_version, b, sizeof (b));
- array_insert (av, 3, s);
- array_insert (av, 4, release_status);
- array_insert (av, 5, MACHTYPE);
-
- VSETATTR (vv, att_readonly);
-}
-#endif /* ARRAY_VARS */
-
-/* Set the environment variables $LINES and $COLUMNS in response to
- a window size change. */
-void
-sh_set_lines_and_columns (lines, cols)
- int lines, cols;
-{
- char val[INT_STRLEN_BOUND(int) + 1], *v;
-
-#if defined (READLINE)
- /* If we are currently assigning to LINES or COLUMNS, don't do anything. */
- if (winsize_assignment)
- return;
-#endif
-
- v = inttostr (lines, val, sizeof (val));
- bind_variable ("LINES", v, 0);
-
- v = inttostr (cols, val, sizeof (val));
- bind_variable ("COLUMNS", v, 0);
-}
-
-/* **************************************************************** */
-/* */
-/* Printing variables and values */
-/* */
-/* **************************************************************** */
-
-/* Print LIST (a list of shell variables) to stdout in such a way that
- they can be read back in. */
-void
-print_var_list (list)
- register SHELL_VAR **list;
-{
- register int i;
- register SHELL_VAR *var;
-
- for (i = 0; list && (var = list[i]); i++)
- if (invisible_p (var) == 0)
- print_assignment (var);
-}
-
-/* Print LIST (a list of shell functions) to stdout in such a way that
- they can be read back in. */
-void
-print_func_list (list)
- register SHELL_VAR **list;
-{
- register int i;
- register SHELL_VAR *var;
-
- for (i = 0; list && (var = list[i]); i++)
- {
- printf ("%s ", var->name);
- print_var_function (var);
- printf ("\n");
- }
-}
-
-/* Print the value of a single SHELL_VAR. No newline is
- output, but the variable is printed in such a way that
- it can be read back in. */
-void
-print_assignment (var)
- SHELL_VAR *var;
-{
- if (var_isset (var) == 0)
- return;
-
- if (function_p (var))
- {
- printf ("%s", var->name);
- print_var_function (var);
- printf ("\n");
- }
-#if defined (ARRAY_VARS)
- else if (array_p (var))
- print_array_assignment (var, 0);
- else if (assoc_p (var))
- print_assoc_assignment (var, 0);
-#endif /* ARRAY_VARS */
- else
- {
- printf ("%s=", var->name);
- print_var_value (var, 1);
- printf ("\n");
- }
-}
-
-/* Print the value cell of VAR, a shell variable. Do not print
- the name, nor leading/trailing newline. If QUOTE is non-zero,
- and the value contains shell metacharacters, quote the value
- in such a way that it can be read back in. */
-void
-print_var_value (var, quote)
- SHELL_VAR *var;
- int quote;
-{
- char *t;
-
- if (var_isset (var) == 0)
- return;
-
- if (quote && posixly_correct == 0 && ansic_shouldquote (value_cell (var)))
- {
- t = ansic_quote (value_cell (var), 0, (int *)0);
- printf ("%s", t);
- free (t);
- }
- else if (quote && sh_contains_shell_metas (value_cell (var)))
- {
- t = sh_single_quote (value_cell (var));
- printf ("%s", t);
- free (t);
- }
- else
- printf ("%s", value_cell (var));
-}
-
-/* Print the function cell of VAR, a shell variable. Do not
- print the name, nor leading/trailing newline. */
-void
-print_var_function (var)
- SHELL_VAR *var;
-{
- char *x;
-
- if (function_p (var) && var_isset (var))
- {
- x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
- printf ("%s", x);
- }
-}
-
-/* **************************************************************** */
-/* */
-/* Dynamic Variables */
-/* */
-/* **************************************************************** */
-
-/* DYNAMIC VARIABLES
-
- These are variables whose values are generated anew each time they are
- referenced. These are implemented using a pair of function pointers
- in the struct variable: assign_func, which is called from bind_variable
- and, if arrays are compiled into the shell, some of the functions in
- arrayfunc.c, and dynamic_value, which is called from find_variable.
-
- assign_func is called from bind_variable_internal, if
- bind_variable_internal discovers that the variable being assigned to
- has such a function. The function is called as
- SHELL_VAR *temp = (*(entry->assign_func)) (entry, value, ind)
- and the (SHELL_VAR *)temp is returned as the value of bind_variable. It
- is usually ENTRY (self). IND is an index for an array variable, and
- unused otherwise.
-
- dynamic_value is called from find_variable_internal to return a `new'
- value for the specified dynamic varible. If this function is NULL,
- the variable is treated as a `normal' shell variable. If it is not,
- however, then this function is called like this:
- tempvar = (*(var->dynamic_value)) (var);
-
- Sometimes `tempvar' will replace the value of `var'. Other times, the
- shell will simply use the string value. Pretty object-oriented, huh?
-
- Be warned, though: if you `unset' a special variable, it loses its
- special meaning, even if you subsequently set it.
-
- The special assignment code would probably have been better put in
- subst.c: do_assignment_internal, in the same style as
- stupidly_hack_special_variables, but I wanted the changes as
- localized as possible. */
-
-#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
- do \
- { \
- v = bind_variable (var, (val), 0); \
- v->dynamic_value = gfunc; \
- v->assign_func = afunc; \
- } \
- while (0)
-
-#define INIT_DYNAMIC_ARRAY_VAR(var, gfunc, afunc) \
- do \
- { \
- v = make_new_array_variable (var); \
- v->dynamic_value = gfunc; \
- v->assign_func = afunc; \
- } \
- while (0)
-
-#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \
- do \
- { \
- v = make_new_assoc_variable (var); \
- v->dynamic_value = gfunc; \
- v->assign_func = afunc; \
- } \
- while (0)
-
-static SHELL_VAR *
-null_assign (self, value, unused, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t unused;
- char *key;
-{
- return (self);
-}
-
-#if defined (ARRAY_VARS)
-static SHELL_VAR *
-null_array_assign (self, value, ind, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t ind;
- char *key;
-{
- return (self);
-}
-#endif
-
-/* Degenerate `dynamic_value' function; just returns what's passed without
- manipulation. */
-static SHELL_VAR *
-get_self (self)
- SHELL_VAR *self;
-{
- return (self);
-}
-
-#if defined (ARRAY_VARS)
-/* A generic dynamic array variable initializer. Initialize array variable
- NAME with dynamic value function GETFUNC and assignment function SETFUNC. */
-static SHELL_VAR *
-init_dynamic_array_var (name, getfunc, setfunc, attrs)
- char *name;
- sh_var_value_func_t *getfunc;
- sh_var_assign_func_t *setfunc;
- int attrs;
-{
- SHELL_VAR *v;
-
- v = find_variable (name);
- if (v)
- return (v);
- INIT_DYNAMIC_ARRAY_VAR (name, getfunc, setfunc);
- if (attrs)
- VSETATTR (v, attrs);
- return v;
-}
-
-static SHELL_VAR *
-init_dynamic_assoc_var (name, getfunc, setfunc, attrs)
- char *name;
- sh_var_value_func_t *getfunc;
- sh_var_assign_func_t *setfunc;
- int attrs;
-{
- SHELL_VAR *v;
-
- v = find_variable (name);
- if (v)
- return (v);
- INIT_DYNAMIC_ASSOC_VAR (name, getfunc, setfunc);
- if (attrs)
- VSETATTR (v, attrs);
- return v;
-}
-#endif
-
-/* The value of $SECONDS. This is the number of seconds since shell
- invocation, or, the number of seconds since the last assignment + the
- value of the last assignment. */
-static intmax_t seconds_value_assigned;
-
-static SHELL_VAR *
-assign_seconds (self, value, unused, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t unused;
- char *key;
-{
- if (legal_number (value, &seconds_value_assigned) == 0)
- seconds_value_assigned = 0;
- shell_start_time = NOW;
- return (self);
-}
-
-static SHELL_VAR *
-get_seconds (var)
- SHELL_VAR *var;
-{
- time_t time_since_start;
- char *p;
-
- time_since_start = NOW - shell_start_time;
- p = itos(seconds_value_assigned + time_since_start);
-
- FREE (value_cell (var));
-
- VSETATTR (var, att_integer);
- var_setvalue (var, p);
- return (var);
-}
-
-static SHELL_VAR *
-init_seconds_var ()
-{
- SHELL_VAR *v;
-
- v = find_variable ("SECONDS");
- if (v)
- {
- if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
- seconds_value_assigned = 0;
- }
- INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
- return v;
-}
-
-/* The random number seed. You can change this by setting RANDOM. */
-static unsigned long rseed = 1;
-static int last_random_value;
-static int seeded_subshell = 0;
-
-/* A linear congruential random number generator based on the example
- one in the ANSI C standard. This one isn't very good, but a more
- complicated one is overkill. */
-
-/* Returns a pseudo-random number between 0 and 32767. */
-static int
-brand ()
-{
- /* From "Random number generators: good ones are hard to find",
- Park and Miller, Communications of the ACM, vol. 31, no. 10,
- October 1988, p. 1195. filtered through FreeBSD */
- long h, l;
-
- /* Can't seed with 0. */
- if (rseed == 0)
- rseed = 123459876;
- h = rseed / 127773;
- l = rseed % 127773;
- rseed = 16807 * l - 2836 * h;
-#if 0
- if (rseed < 0)
- rseed += 0x7fffffff;
-#endif
- return ((unsigned int)(rseed & 32767)); /* was % 32768 */
-}
-
-/* Set the random number generator seed to SEED. */
-static void
-sbrand (seed)
- unsigned long seed;
-{
- rseed = seed;
- last_random_value = 0;
-}
-
-static void
-seedrand ()
-{
- struct timeval tv;
-
- gettimeofday (&tv, NULL);
- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ());
-}
-
-static SHELL_VAR *
-assign_random (self, value, unused, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t unused;
- char *key;
-{
- sbrand (strtoul (value, (char **)NULL, 10));
- if (subshell_environment)
- seeded_subshell = getpid ();
- return (self);
-}
-
-int
-get_random_number ()
-{
- int rv, pid;
-
- /* Reset for command and process substitution. */
- pid = getpid ();
- if (subshell_environment && seeded_subshell != pid)
- {
- seedrand ();
- seeded_subshell = pid;
- }
-
- do
- rv = brand ();
- while (rv == last_random_value);
- return rv;
-}
-
-static SHELL_VAR *
-get_random (var)
- SHELL_VAR *var;
-{
- int rv;
- char *p;
-
- rv = get_random_number ();
- last_random_value = rv;
- p = itos (rv);
-
- FREE (value_cell (var));
-
- VSETATTR (var, att_integer);
- var_setvalue (var, p);
- return (var);
-}
-
-static SHELL_VAR *
-assign_lineno (var, value, unused, key)
- SHELL_VAR *var;
- char *value;
- arrayind_t unused;
- char *key;
-{
- intmax_t new_value;
-
- if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- new_value = 0;
- line_number = line_number_base = new_value;
- return var;
-}
-
-/* Function which returns the current line number. */
-static SHELL_VAR *
-get_lineno (var)
- SHELL_VAR *var;
-{
- char *p;
- int ln;
-
- ln = executing_line_number ();
- p = itos (ln);
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
-}
-
-static SHELL_VAR *
-assign_subshell (var, value, unused, key)
- SHELL_VAR *var;
- char *value;
- arrayind_t unused;
- char *key;
-{
- intmax_t new_value;
-
- if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
- new_value = 0;
- subshell_level = new_value;
- return var;
-}
-
-static SHELL_VAR *
-get_subshell (var)
- SHELL_VAR *var;
-{
- char *p;
-
- p = itos (subshell_level);
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
-}
-
-static SHELL_VAR *
-get_bashpid (var)
- SHELL_VAR *var;
-{
- int pid;
- char *p;
-
- pid = getpid ();
- p = itos (pid);
-
- FREE (value_cell (var));
- VSETATTR (var, att_integer|att_readonly);
- var_setvalue (var, p);
- return (var);
-}
-
-static SHELL_VAR *
-get_bash_command (var)
- SHELL_VAR *var;
-{
- char *p;
-
- if (the_printed_command_except_trap)
- p = savestring (the_printed_command_except_trap);
- else
- {
- p = (char *)xmalloc (1);
- p[0] = '\0';
- }
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
-}
-
-#if defined (HISTORY)
-static SHELL_VAR *
-get_histcmd (var)
- SHELL_VAR *var;
-{
- char *p;
-
- p = itos (history_number ());
- FREE (value_cell (var));
- var_setvalue (var, p);
- return (var);
-}
-#endif
-
-#if defined (READLINE)
-/* When this function returns, VAR->value points to malloced memory. */
-static SHELL_VAR *
-get_comp_wordbreaks (var)
- SHELL_VAR *var;
-{
- /* If we don't have anything yet, assign a default value. */
- if (rl_completer_word_break_characters == 0 && bash_readline_initialized == 0)
- enable_hostname_completion (perform_hostname_completion);
-
- FREE (value_cell (var));
- var_setvalue (var, savestring (rl_completer_word_break_characters));
-
- return (var);
-}
-
-/* When this function returns, rl_completer_word_break_characters points to
- malloced memory. */
-static SHELL_VAR *
-assign_comp_wordbreaks (self, value, unused, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t unused;
- char *key;
-{
- if (rl_completer_word_break_characters &&
- rl_completer_word_break_characters != rl_basic_word_break_characters)
- free (rl_completer_word_break_characters);
-
- rl_completer_word_break_characters = savestring (value);
- return self;
-}
-#endif /* READLINE */
-
-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
-static SHELL_VAR *
-assign_dirstack (self, value, ind, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t ind;
- char *key;
-{
- set_dirstack_element (ind, 1, value);
- return self;
-}
-
-static SHELL_VAR *
-get_dirstack (self)
- SHELL_VAR *self;
-{
- ARRAY *a;
- WORD_LIST *l;
-
- l = get_directory_stack (0);
- a = array_from_word_list (l);
- array_dispose (array_cell (self));
- dispose_words (l);
- var_setarray (self, a);
- return self;
-}
-#endif /* PUSHD AND POPD && ARRAY_VARS */
-
-#if defined (ARRAY_VARS)
-/* We don't want to initialize the group set with a call to getgroups()
- unless we're asked to, but we only want to do it once. */
-static SHELL_VAR *
-get_groupset (self)
- SHELL_VAR *self;
-{
- register int i;
- int ng;
- ARRAY *a;
- static char **group_set = (char **)NULL;
-
- if (group_set == 0)
- {
- group_set = get_group_list (&ng);
- a = array_cell (self);
- for (i = 0; i < ng; i++)
- array_insert (a, i, group_set[i]);
- }
- return (self);
-}
-
-static SHELL_VAR *
-build_hashcmd (self)
- SHELL_VAR *self;
-{
- HASH_TABLE *h;
- int i;
- char *k, *v;
- BUCKET_CONTENTS *item;
-
- h = assoc_cell (self);
- if (h)
- assoc_dispose (h);
-
- if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
- {
- var_setvalue (self, (char *)NULL);
- return self;
- }
-
- h = assoc_create (hashed_filenames->nbuckets);
- for (i = 0; i < hashed_filenames->nbuckets; i++)
- {
- for (item = hash_items (i, hashed_filenames); item; item = item->next)
- {
- k = savestring (item->key);
- v = pathdata(item)->path;
- assoc_insert (h, k, v);
- }
- }
-
- var_setvalue (self, (char *)h);
- return self;
-}
-
-static SHELL_VAR *
-get_hashcmd (self)
- SHELL_VAR *self;
-{
- build_hashcmd (self);
- return (self);
-}
-
-static SHELL_VAR *
-assign_hashcmd (self, value, ind, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t ind;
- char *key;
-{
- phash_insert (key, value, 0, 0);
- return (build_hashcmd (self));
-}
-
-#if defined (ALIAS)
-static SHELL_VAR *
-build_aliasvar (self)
- SHELL_VAR *self;
-{
- HASH_TABLE *h;
- int i;
- char *k, *v;
- BUCKET_CONTENTS *item;
-
- h = assoc_cell (self);
- if (h)
- assoc_dispose (h);
-
- if (aliases == 0 || HASH_ENTRIES (aliases) == 0)
- {
- var_setvalue (self, (char *)NULL);
- return self;
- }
-
- h = assoc_create (aliases->nbuckets);
- for (i = 0; i < aliases->nbuckets; i++)
- {
- for (item = hash_items (i, aliases); item; item = item->next)
- {
- k = savestring (item->key);
- v = ((alias_t *)(item->data))->value;
- assoc_insert (h, k, v);
- }
- }
-
- var_setvalue (self, (char *)h);
- return self;
-}
-
-static SHELL_VAR *
-get_aliasvar (self)
- SHELL_VAR *self;
-{
- build_aliasvar (self);
- return (self);
-}
-
-static SHELL_VAR *
-assign_aliasvar (self, value, ind, key)
- SHELL_VAR *self;
- char *value;
- arrayind_t ind;
- char *key;
-{
- add_alias (key, value);
- return (build_aliasvar (self));
-}
-#endif /* ALIAS */
-
-#endif /* ARRAY_VARS */
-
-/* If ARRAY_VARS is not defined, this just returns the name of any
- currently-executing function. If we have arrays, it's a call stack. */
-static SHELL_VAR *
-get_funcname (self)
- SHELL_VAR *self;
-{
-#if ! defined (ARRAY_VARS)
- char *t;
- if (variable_context && this_shell_function)
- {
- FREE (value_cell (self));
- t = savestring (this_shell_function->name);
- var_setvalue (self, t);
- }
-#endif
- return (self);
-}
-
-void
-make_funcname_visible (on_or_off)
- int on_or_off;
-{
- SHELL_VAR *v;
-
- v = find_variable ("FUNCNAME");
- if (v == 0 || v->dynamic_value == 0)
- return;
-
- if (on_or_off)
- VUNSETATTR (v, att_invisible);
- else
- VSETATTR (v, att_invisible);
-}
-
-static SHELL_VAR *
-init_funcname_var ()
-{
- SHELL_VAR *v;
-
- v = find_variable ("FUNCNAME");
- if (v)
- return v;
-#if defined (ARRAY_VARS)
- INIT_DYNAMIC_ARRAY_VAR ("FUNCNAME", get_funcname, null_array_assign);
-#else
- INIT_DYNAMIC_VAR ("FUNCNAME", (char *)NULL, get_funcname, null_assign);
-#endif
- VSETATTR (v, att_invisible|att_noassign);
- return v;
-}
-
-static void
-initialize_dynamic_variables ()
-{
- SHELL_VAR *v;
-
- v = init_seconds_var ();
-
- INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
- INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);
-
- INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
- VSETATTR (v, att_integer);
- INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
- VSETATTR (v, att_integer);
-
- INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
- VSETATTR (v, att_integer|att_readonly);
-
-#if defined (HISTORY)
- INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
- VSETATTR (v, att_integer);
-#endif
-
-#if defined (READLINE)
- INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
-#endif
-
-#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
- v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
-#endif /* PUSHD_AND_POPD && ARRAY_VARS */
-
-#if defined (ARRAY_VARS)
- v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
-
-# if defined (DEBUGGER)
- v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
- v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
-# endif /* DEBUGGER */
- v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
- v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);
-
- v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
-# if defined (ALIAS)
- v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
-# endif
-#endif
-
- v = init_funcname_var ();
-}
-
-/* **************************************************************** */
-/* */
-/* Retrieving variables and values */
-/* */
-/* **************************************************************** */
-
-/* How to get a pointer to the shell variable or function named NAME.
- HASHED_VARS is a pointer to the hash table containing the list
- of interest (either variables or functions). */
-
-static SHELL_VAR *
-hash_lookup (name, hashed_vars)
- const char *name;
- HASH_TABLE *hashed_vars;
-{
- BUCKET_CONTENTS *bucket;
-
- bucket = hash_search (name, hashed_vars, 0);
- /* If we find the name in HASHED_VARS, set LAST_TABLE_SEARCHED to that
- table. */
- if (bucket)
- last_table_searched = hashed_vars;
- return (bucket ? (SHELL_VAR *)bucket->data : (SHELL_VAR *)NULL);
-}
-
-SHELL_VAR *
-var_lookup (name, vcontext)
- const char *name;
- VAR_CONTEXT *vcontext;
-{
- VAR_CONTEXT *vc;
- SHELL_VAR *v;
-
- v = (SHELL_VAR *)NULL;
- for (vc = vcontext; vc; vc = vc->down)
- if (v = hash_lookup (name, vc->table))
- break;
-
- return v;
-}
-
-/* Look up the variable entry named NAME. If SEARCH_TEMPENV is non-zero,
- then also search the temporarily built list of exported variables.
- The lookup order is:
- temporary_env
- shell_variables list
-*/
-
-SHELL_VAR *
-find_variable_internal (name, flags)
- const char *name;
- int flags;
-{
- SHELL_VAR *var;
- int search_tempenv, force_tempenv;
- VAR_CONTEXT *vc;
-
- var = (SHELL_VAR *)NULL;
-
- force_tempenv = (flags & FV_FORCETEMPENV);
-
- /* If explicitly requested, first look in the temporary environment for
- the variable. This allows constructs such as "foo=x eval 'echo $foo'"
- to get the `exported' value of $foo. This happens if we are executing
- a function or builtin, or if we are looking up a variable in a
- "subshell environment". */
- search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);
-
- if (search_tempenv && temporary_env)
- var = hash_lookup (name, temporary_env);
-
- if (var == 0)
- {
- if ((flags & FV_SKIPINVISIBLE) == 0)
- var = var_lookup (name, shell_variables);
- else
- {
- /* essentially var_lookup expanded inline so we can check for
- att_invisible */
- for (vc = shell_variables; vc; vc = vc->down)
- {
- var = hash_lookup (name, vc->table);
- if (var && invisible_p (var))
- var = 0;
- if (var)
- break;
- }
- }
- }
-
- if (var == 0)
- return ((SHELL_VAR *)NULL);
-
- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
-}
-
-/* Look up and resolve the chain of nameref variables starting at V all the
- way to NULL or non-nameref. */
-SHELL_VAR *
-find_variable_nameref (v)
- SHELL_VAR *v;
-{
- int level, flags;
- char *newname;
- SHELL_VAR *orig, *oldv;
-
- level = 0;
- orig = v;
- while (v && nameref_p (v))
- {
- level++;
- if (level > NAMEREF_MAX)
- return ((SHELL_VAR *)0); /* error message here? */
- newname = nameref_cell (v);
- if (newname == 0 || *newname == '\0')
- return ((SHELL_VAR *)0);
- oldv = v;
- flags = 0;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (newname, flags);
- if (v == orig || v == oldv)
- {
- internal_warning (_("%s: circular name reference"), orig->name);
- return ((SHELL_VAR *)0);
- }
- }
- return v;
-}
-
-/* Resolve the chain of nameref variables for NAME. XXX - could change later */
-SHELL_VAR *
-find_variable_last_nameref (name)
- const char *name;
-{
- SHELL_VAR *v, *nv;
- char *newname;
- int level, flags;
-
- nv = v = find_variable_noref (name);
- level = 0;
- while (v && nameref_p (v))
- {
- level++;
- if (level > NAMEREF_MAX)
- return ((SHELL_VAR *)0); /* error message here? */
- newname = nameref_cell (v);
- if (newname == 0 || *newname == '\0')
- return ((SHELL_VAR *)0);
- nv = v;
- flags = 0;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (newname, flags);
- }
- return nv;
-}
-
-/* Resolve the chain of nameref variables for NAME. XXX - could change later */
-SHELL_VAR *
-find_global_variable_last_nameref (name)
- const char *name;
-{
- SHELL_VAR *v, *nv;
- char *newname;
- int level;
-
- nv = v = find_global_variable_noref (name);
- level = 0;
- while (v && nameref_p (v))
- {
- level++;
- if (level > NAMEREF_MAX)
- return ((SHELL_VAR *)0); /* error message here? */
- newname = nameref_cell (v);
- if (newname == 0 || *newname == '\0')
- return ((SHELL_VAR *)0);
- nv = v;
- v = find_global_variable_noref (newname);
- }
- return nv;
-}
-
-static SHELL_VAR *
-find_nameref_at_context (v, vc)
- SHELL_VAR *v;
- VAR_CONTEXT *vc;
-{
- SHELL_VAR *nv, *nv2;
- VAR_CONTEXT *nvc;
- char *newname;
- int level;
-
- nv = v;
- level = 1;
- while (nv && nameref_p (nv))
- {
- level++;
- if (level > NAMEREF_MAX)
- return ((SHELL_VAR *)NULL);
- newname = nameref_cell (nv);
- if (newname == 0 || *newname == '\0')
- return ((SHELL_VAR *)NULL);
- nv2 = hash_lookup (newname, vc->table);
- if (nv2 == 0)
- break;
- nv = nv2;
- }
- return nv;
-}
-
-/* Do nameref resolution from the VC, which is the local context for some
- function or builtin, `up' the chain to the global variables context. If
- NVCP is not NULL, return the variable context where we finally ended the
- nameref resolution (so the bind_variable_internal can use the correct
- variable context and hash table). */
-static SHELL_VAR *
-find_variable_nameref_context (v, vc, nvcp)
- SHELL_VAR *v;
- VAR_CONTEXT *vc;
- VAR_CONTEXT **nvcp;
-{
- SHELL_VAR *nv, *nv2;
- VAR_CONTEXT *nvc;
-
- /* Look starting at the current context all the way `up' */
- for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- {
- nv2 = find_nameref_at_context (nv, nvc);
- if (nv2 == 0)
- continue;
- nv = nv2;
- if (*nvcp)
- *nvcp = nvc;
- if (nameref_p (nv) == 0)
- break;
- }
- return (nameref_p (nv) ? (SHELL_VAR *)NULL : nv);
-}
-
-/* Do nameref resolution from the VC, which is the local context for some
- function or builtin, `up' the chain to the global variables context. If
- NVCP is not NULL, return the variable context where we finally ended the
- nameref resolution (so the bind_variable_internal can use the correct
- variable context and hash table). */
-static SHELL_VAR *
-find_variable_last_nameref_context (v, vc, nvcp)
- SHELL_VAR *v;
- VAR_CONTEXT *vc;
- VAR_CONTEXT **nvcp;
-{
- SHELL_VAR *nv, *nv2;
- VAR_CONTEXT *nvc;
-
- /* Look starting at the current context all the way `up' */
- for (nv = v, nvc = vc; nvc; nvc = nvc->down)
- {
- nv2 = find_nameref_at_context (nv, nvc);
- if (nv2 == 0)
- continue;
- nv = nv2;
- if (*nvcp)
- *nvcp = nvc;
- }
- return (nameref_p (nv) ? nv : (SHELL_VAR *)NULL);
-}
-
-/* Find a variable, forcing a search of the temporary environment first */
-SHELL_VAR *
-find_variable_tempenv (name)
- const char *name;
-{
- SHELL_VAR *var;
-
- var = find_variable_internal (name, FV_FORCETEMPENV);
- if (var && nameref_p (var))
- var = find_variable_nameref (var);
- return (var);
-}
-
-/* Find a variable, not forcing a search of the temporary environment first */
-SHELL_VAR *
-find_variable_notempenv (name)
- const char *name;
-{
- SHELL_VAR *var;
-
- var = find_variable_internal (name, 0);
- if (var && nameref_p (var))
- var = find_variable_nameref (var);
- return (var);
-}
-
-SHELL_VAR *
-find_global_variable (name)
- const char *name;
-{
- SHELL_VAR *var;
-
- var = var_lookup (name, global_variables);
- if (var && nameref_p (var))
- var = find_variable_nameref (var);
-
- if (var == 0)
- return ((SHELL_VAR *)NULL);
-
- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
-}
-
-SHELL_VAR *
-find_global_variable_noref (name)
- const char *name;
-{
- SHELL_VAR *var;
-
- var = var_lookup (name, global_variables);
-
- if (var == 0)
- return ((SHELL_VAR *)NULL);
-
- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
-}
-
-SHELL_VAR *
-find_shell_variable (name)
- const char *name;
-{
- SHELL_VAR *var;
-
- var = var_lookup (name, shell_variables);
- if (var && nameref_p (var))
- var = find_variable_nameref (var);
-
- if (var == 0)
- return ((SHELL_VAR *)NULL);
-
- return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
-}
-
-/* Look up the variable entry named NAME. Returns the entry or NULL. */
-SHELL_VAR *
-find_variable (name)
- const char *name;
-{
- SHELL_VAR *v;
- int flags;
-
- last_table_searched = 0;
- flags = 0;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (name, flags);
- if (v && nameref_p (v))
- v = find_variable_nameref (v);
- return v;
-}
-
-/* Find the first instance of NAME in the variable context chain; return first
- one found without att_invisible set; return 0 if no non-invisible instances
- found. */
-SHELL_VAR *
-find_variable_no_invisible (name)
- const char *name;
-{
- SHELL_VAR *v;
- int flags;
-
- last_table_searched = 0;
- flags = FV_SKIPINVISIBLE;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (name, flags);
- if (v && nameref_p (v))
- v = find_variable_nameref (v);
- return v;
-}
-
-/* Find the first instance of NAME in the variable context chain; return first
- one found even if att_invisible set. */
-SHELL_VAR *
-find_variable_for_assignment (name)
- const char *name;
-{
- SHELL_VAR *v;
- int flags;
-
- last_table_searched = 0;
- flags = 0;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (name, flags);
- if (v && nameref_p (v))
- v = find_variable_nameref (v);
- return v;
-}
-
-SHELL_VAR *
-find_variable_noref (name)
- const char *name;
-{
- SHELL_VAR *v;
- int flags;
-
- flags = 0;
- if (expanding_redir == 0 && (assigning_in_environment || executing_builtin))
- flags |= FV_FORCETEMPENV;
- v = find_variable_internal (name, flags);
- return v;
-}
-
-/* Look up the function entry whose name matches STRING.
- Returns the entry or NULL. */
-SHELL_VAR *
-find_function (name)
- const char *name;
-{
- return (hash_lookup (name, shell_functions));
-}
-
-/* Find the function definition for the shell function named NAME. Returns
- the entry or NULL. */
-FUNCTION_DEF *
-find_function_def (name)
- const char *name;
-{
-#if defined (DEBUGGER)
- return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs));
-#else
- return ((FUNCTION_DEF *)0);
-#endif
-}
-
-/* Return the value of VAR. VAR is assumed to have been the result of a
- lookup without any subscript, if arrays are compiled into the shell. */
-char *
-get_variable_value (var)
- SHELL_VAR *var;
-{
- if (var == 0)
- return ((char *)NULL);
-#if defined (ARRAY_VARS)
- else if (array_p (var))
- return (array_reference (array_cell (var), 0));
- else if (assoc_p (var))
- return (assoc_reference (assoc_cell (var), "0"));
-#endif
- else
- return (value_cell (var));
-}
-
-/* Return the string value of a variable. Return NULL if the variable
- doesn't exist. Don't cons a new string. This is a potential memory
- leak if the variable is found in the temporary environment. Since
- functions and variables have separate name spaces, returns NULL if
- var_name is a shell function only. */
-char *
-get_string_value (var_name)
- const char *var_name;
-{
- SHELL_VAR *var;
-
- var = find_variable (var_name);
- return ((var) ? get_variable_value (var) : (char *)NULL);
-}
-
-/* This is present for use by the tilde and readline libraries. */
-char *
-sh_get_env_value (v)
- const char *v;
-{
- return get_string_value (v);
-}
-
-/* **************************************************************** */
-/* */
-/* Creating and setting variables */
-/* */
-/* **************************************************************** */
-
-/* Set NAME to VALUE if NAME has no value. */
-SHELL_VAR *
-set_if_not (name, value)
- char *name, *value;
-{
- SHELL_VAR *v;
-
- if (shell_variables == 0)
- create_variable_tables ();
-
- v = find_variable (name);
- if (v == 0)
- v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0);
- return (v);
-}
-
-/* Create a local variable referenced by NAME. */
-SHELL_VAR *
-make_local_variable (name)
- const char *name;
-{
- SHELL_VAR *new_var, *old_var;
- VAR_CONTEXT *vc;
- int was_tmpvar;
- char *tmp_value;
-
- /* local foo; local foo; is a no-op. */
- old_var = find_variable (name);
- if (old_var && local_p (old_var) && old_var->context == variable_context)
- return (old_var);
-
- was_tmpvar = old_var && tempvar_p (old_var);
- /* If we're making a local variable in a shell function, the temporary env
- has already been merged into the function's variable context stack. We
- can assume that a temporary var in the same context appears in the same
- VAR_CONTEXT and can safely be returned without creating a new variable
- (which results in duplicate names in the same VAR_CONTEXT->table */
- /* We can't just test tmpvar_p because variables in the temporary env given
- to a shell function appear in the function's local variable VAR_CONTEXT
- but retain their tempvar attribute. We want temporary variables that are
- found in temporary_env, hence the test for last_table_searched, which is
- set in hash_lookup and only (so far) checked here. */
- if (was_tmpvar && old_var->context == variable_context && last_table_searched != temporary_env)
- {
- VUNSETATTR (old_var, att_invisible); /* XXX */
- return (old_var);
- }
- if (was_tmpvar)
- tmp_value = value_cell (old_var);
-
- for (vc = shell_variables; vc; vc = vc->down)
- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- break;
-
- if (vc == 0)
- {
- internal_error (_("make_local_variable: no function context at current scope"));
- return ((SHELL_VAR *)NULL);
- }
- else if (vc->table == 0)
- vc->table = hash_create (TEMPENV_HASH_BUCKETS);
-
- /* Since this is called only from the local/declare/typeset code, we can
- call builtin_error here without worry (of course, it will also work
- for anything that sets this_command_name). Variables with the `noassign'
- attribute may not be made local. The test against old_var's context
- level is to disallow local copies of readonly global variables (since I
- believe that this could be a security hole). Readonly copies of calling
- function local variables are OK. */
- if (old_var && (noassign_p (old_var) ||
- (readonly_p (old_var) && old_var->context == 0)))
- {
- if (readonly_p (old_var))
- sh_readonly (name);
- else if (noassign_p (old_var))
- builtin_error (_("%s: variable may not be assigned value"), name);
-#if 0
- /* Let noassign variables through with a warning */
- if (readonly_p (old_var))
-#endif
- return ((SHELL_VAR *)NULL);
- }
-
- if (old_var == 0)
- new_var = make_new_variable (name, vc->table);
- else
- {
- new_var = make_new_variable (name, vc->table);
-
- /* If we found this variable in one of the temporary environments,
- inherit its value. Watch to see if this causes problems with
- things like `x=4 local x'. XXX - see above for temporary env
- variables with the same context level as variable_context */
- /* XXX - we should only do this if the variable is not an array. */
- if (was_tmpvar)
- var_setvalue (new_var, savestring (tmp_value));
-
- new_var->attributes = exported_p (old_var) ? att_exported : 0;
- }
-
- vc->flags |= VC_HASLOCAL;
-
- new_var->context = variable_context;
- VSETATTR (new_var, att_local);
-
- if (ifsname (name))
- setifs (new_var);
-
- if (was_tmpvar == 0 && no_invisible_vars == 0)
- VSETATTR (new_var, att_invisible); /* XXX */
- return (new_var);
-}
-
-/* Create a new shell variable with name NAME. */
-static SHELL_VAR *
-new_shell_variable (name)
- const char *name;
-{
- SHELL_VAR *entry;
-
- entry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
-
- entry->name = savestring (name);
- var_setvalue (entry, (char *)NULL);
- CLEAR_EXPORTSTR (entry);
-
- entry->dynamic_value = (sh_var_value_func_t *)NULL;
- entry->assign_func = (sh_var_assign_func_t *)NULL;
-
- entry->attributes = 0;
-
- /* Always assume variables are to be made at toplevel!
- make_local_variable has the responsibility of changing the
- variable context. */
- entry->context = 0;
-
- return (entry);
-}
-
-/* Create a new shell variable with name NAME and add it to the hash table
- TABLE. */
-static SHELL_VAR *
-make_new_variable (name, table)
- const char *name;
- HASH_TABLE *table;
-{
- SHELL_VAR *entry;
- BUCKET_CONTENTS *elt;
-
- entry = new_shell_variable (name);
-
- /* Make sure we have a shell_variables hash table to add to. */
- if (shell_variables == 0)
- create_variable_tables ();
-
- elt = hash_insert (savestring (name), table, HASH_NOSRCH);
- elt->data = (PTR_T)entry;
-
- return entry;
-}
-
-#if defined (ARRAY_VARS)
-SHELL_VAR *
-make_new_array_variable (name)
- char *name;
-{
- SHELL_VAR *entry;
- ARRAY *array;
-
- entry = make_new_variable (name, global_variables->table);
- array = array_create ();
-
- var_setarray (entry, array);
- VSETATTR (entry, att_array);
- return entry;
-}
-
-SHELL_VAR *
-make_local_array_variable (name, assoc_ok)
- char *name;
- int assoc_ok;
-{
- SHELL_VAR *var;
- ARRAY *array;
-
- var = make_local_variable (name);
- if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
- return var;
-
- array = array_create ();
-
- dispose_variable_value (var);
- var_setarray (var, array);
- VSETATTR (var, att_array);
- return var;
-}
-
-SHELL_VAR *
-make_new_assoc_variable (name)
- char *name;
-{
- SHELL_VAR *entry;
- HASH_TABLE *hash;
-
- entry = make_new_variable (name, global_variables->table);
- hash = assoc_create (0);
-
- var_setassoc (entry, hash);
- VSETATTR (entry, att_assoc);
- return entry;
-}
-
-SHELL_VAR *
-make_local_assoc_variable (name)
- char *name;
-{
- SHELL_VAR *var;
- HASH_TABLE *hash;
-
- var = make_local_variable (name);
- if (var == 0 || assoc_p (var))
- return var;
-
- dispose_variable_value (var);
- hash = assoc_create (0);
-
- var_setassoc (var, hash);
- VSETATTR (var, att_assoc);
- return var;
-}
-#endif
-
-char *
-make_variable_value (var, value, flags)
- SHELL_VAR *var;
- char *value;
- int flags;
-{
- char *retval, *oval;
- intmax_t lval, rval;
- int expok, olen, op;
-
- /* If this variable has had its type set to integer (via `declare -i'),
- then do expression evaluation on it and store the result. The
- functions in expr.c (evalexp()) and bind_int_variable() are responsible
- for turning off the integer flag if they don't want further
- evaluation done. */
- if (integer_p (var))
- {
- if (flags & ASS_APPEND)
- {
- oval = value_cell (var);
- lval = evalexp (oval, &expok); /* ksh93 seems to do this */
- if (expok == 0)
- {
- top_level_cleanup ();
- jump_to_top_level (DISCARD);
- }
- }
- rval = evalexp (value, &expok);
- if (expok == 0)
- {
- top_level_cleanup ();
- jump_to_top_level (DISCARD);
- }
- /* This can be fooled if the variable's value changes while evaluating
- `rval'. We can change it if we move the evaluation of lval to here. */
- if (flags & ASS_APPEND)
- rval += lval;
- retval = itos (rval);
- }
-#if defined (CASEMOD_ATTRS)
- else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
- {
- if (flags & ASS_APPEND)
- {
- oval = get_variable_value (var);
- if (oval == 0) /* paranoia */
- oval = "";
- olen = STRLEN (oval);
- retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- strcpy (retval, oval);
- if (value)
- strcpy (retval+olen, value);
- }
- else if (*value)
- retval = savestring (value);
- else
- {
- retval = (char *)xmalloc (1);
- retval[0] = '\0';
- }
- op = capcase_p (var) ? CASE_CAPITALIZE
- : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
- oval = sh_modcase (retval, (char *)0, op);
- free (retval);
- retval = oval;
- }
-#endif /* CASEMOD_ATTRS */
- else if (value)
- {
- if (flags & ASS_APPEND)
- {
- oval = get_variable_value (var);
- if (oval == 0) /* paranoia */
- oval = "";
- olen = STRLEN (oval);
- retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
- strcpy (retval, oval);
- if (value)
- strcpy (retval+olen, value);
- }
- else if (*value)
- retval = savestring (value);
- else
- {
- retval = (char *)xmalloc (1);
- retval[0] = '\0';
- }
- }
- else
- retval = (char *)NULL;
-
- return retval;
-}
-
-/* Bind a variable NAME to VALUE in the HASH_TABLE TABLE, which may be the
- temporary environment (but usually is not). */
-static SHELL_VAR *
-bind_variable_internal (name, value, table, hflags, aflags)
- const char *name;
- char *value;
- HASH_TABLE *table;
- int hflags, aflags;
-{
- char *newval;
- SHELL_VAR *entry;
-
- entry = (hflags & HASH_NOSRCH) ? (SHELL_VAR *)NULL : hash_lookup (name, table);
- /* Follow the nameref chain here if this is the global variables table */
- if (entry && nameref_p (entry) && (invisible_p (entry) == 0) && table == global_variables->table)
- {
- entry = find_global_variable (entry->name);
- /* Let's see if we have a nameref referencing a variable that hasn't yet
- been created. */
- if (entry == 0)
- entry = find_variable_last_nameref (name); /* XXX */
- if (entry == 0) /* just in case */
- return (entry);
- }
-
- /* The first clause handles `declare -n ref; ref=x;' */
- if (entry && invisible_p (entry) && nameref_p (entry))
- goto assign_value;
- else if (entry && nameref_p (entry))
- {
- newval = nameref_cell (entry);
-#if defined (ARRAY_VARS)
- /* declare -n foo=x[2] */
- if (valid_array_reference (newval))
- /* XXX - should it be aflags? */
- entry = assign_array_element (newval, make_variable_value (entry, value, 0), aflags);
- else
-#endif
- {
- entry = make_new_variable (newval, table);
- var_setvalue (entry, make_variable_value (entry, value, 0));
- }
- }
- else if (entry == 0)
- {
- entry = make_new_variable (name, table);
- var_setvalue (entry, make_variable_value (entry, value, 0)); /* XXX */
- }
- else if (entry->assign_func) /* array vars have assign functions now */
- {
- INVALIDATE_EXPORTSTR (entry);
- newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value;
- if (assoc_p (entry))
- entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
- else if (array_p (entry))
- entry = (*(entry->assign_func)) (entry, newval, 0, 0);
- else
- entry = (*(entry->assign_func)) (entry, newval, -1, 0);
- if (newval != value)
- free (newval);
- return (entry);
- }
- else
- {
-assign_value:
- if (readonly_p (entry) || noassign_p (entry))
- {
- if (readonly_p (entry))
- err_readonly (name);
- return (entry);
- }
-
- /* Variables which are bound are visible. */
- VUNSETATTR (entry, att_invisible);
-
-#if defined (ARRAY_VARS)
- if (assoc_p (entry) || array_p (entry))
- newval = make_array_variable_value (entry, 0, "0", value, aflags);
- else
-#endif
-
- newval = make_variable_value (entry, value, aflags); /* XXX */
-
- /* Invalidate any cached export string */
- INVALIDATE_EXPORTSTR (entry);
-
-#if defined (ARRAY_VARS)
- /* XXX -- this bears looking at again -- XXX */
- /* If an existing array variable x is being assigned to with x=b or
- `read x' or something of that nature, silently convert it to
- x[0]=b or `read x[0]'. */
- if (assoc_p (entry))
- {
- assoc_insert (assoc_cell (entry), savestring ("0"), newval);
- free (newval);
- }
- else if (array_p (entry))
- {
- array_insert (array_cell (entry), 0, newval);
- free (newval);
- }
- else
-#endif
- {
- FREE (value_cell (entry));
- var_setvalue (entry, newval);
- }
- }
-
- if (mark_modified_vars)
- VSETATTR (entry, att_exported);
-
- if (exported_p (entry))
- array_needs_making = 1;
-
- return (entry);
-}
-
-/* Bind a variable NAME to VALUE. This conses up the name
- and value strings. If we have a temporary environment, we bind there
- first, then we bind into shell_variables. */
-
-SHELL_VAR *
-bind_variable (name, value, flags)
- const char *name;
- char *value;
- int flags;
-{
- SHELL_VAR *v, *nv;
- VAR_CONTEXT *vc, *nvc;
- int level;
-
- if (shell_variables == 0)
- create_variable_tables ();
-
- /* If we have a temporary environment, look there first for the variable,
- and, if found, modify the value there before modifying it in the
- shell_variables table. This allows sourced scripts to modify values
- given to them in a temporary environment while modifying the variable
- value that the caller sees. */
- if (temporary_env)
- bind_tempenv_variable (name, value);
-
- /* XXX -- handle local variables here. */
- for (vc = shell_variables; vc; vc = vc->down)
- {
- if (vc_isfuncenv (vc) || vc_isbltnenv (vc))
- {
- v = hash_lookup (name, vc->table);
- nvc = vc;
- if (v && nameref_p (v))
- {
- nv = find_variable_nameref_context (v, vc, &nvc);
- if (nv == 0)
- {
- nv = find_variable_last_nameref_context (v, vc, &nvc);
- if (nv && nameref_p (nv))
- {
- /* If this nameref variable doesn't have a value yet,
- set the value. Otherwise, assign using the value as
- normal. */
- if (nameref_cell (nv) == 0)
- return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
-#if defined (ARRAY_VARS)
- else if (valid_array_reference (nameref_cell (nv)))
- return (assign_array_element (nameref_cell (nv), value, flags));
- else
-#endif
- return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
- }
- else
- v = nv;
- }
- else
- v = nv;
- }
- if (v)
- return (bind_variable_internal (v->name, value, nvc->table, 0, flags));
- }
- }
- /* bind_variable_internal will handle nameref resolution in this case */
- return (bind_variable_internal (name, value, global_variables->table, 0, flags));
-}
-
-SHELL_VAR *
-bind_global_variable (name, value, flags)
- const char *name;
- char *value;
- int flags;
-{
- SHELL_VAR *v, *nv;
- VAR_CONTEXT *vc, *nvc;
- int level;
-
- if (shell_variables == 0)
- create_variable_tables ();
-
- /* bind_variable_internal will handle nameref resolution in this case */
- return (bind_variable_internal (name, value, global_variables->table, 0, flags));
-}
-
-/* Make VAR, a simple shell variable, have value VALUE. Once assigned a
- value, variables are no longer invisible. This is a duplicate of part
- of the internals of bind_variable. If the variable is exported, or
- all modified variables should be exported, mark the variable for export
- and note that the export environment needs to be recreated. */
-SHELL_VAR *
-bind_variable_value (var, value, aflags)
- SHELL_VAR *var;
- char *value;
- int aflags;
-{
- char *t;
- int invis;
-
- invis = invisible_p (var);
- VUNSETATTR (var, att_invisible);
-
- if (var->assign_func)
- {
- /* If we're appending, we need the old value, so use
- make_variable_value */
- t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
- (*(var->assign_func)) (var, t, -1, 0);
- if (t != value && t)
- free (t);
- }
- else
- {
- t = make_variable_value (var, value, aflags);
-#if defined (ARRAY_VARS)
- if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t) == 0)))
-#else
- if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0))
-#endif
- {
- free (t);
- if (invis)
- VSETATTR (var, att_invisible); /* XXX */
- return ((SHELL_VAR *)NULL);
- }
- FREE (value_cell (var));
- var_setvalue (var, t);
- }
-
- INVALIDATE_EXPORTSTR (var);
-
- if (mark_modified_vars)
- VSETATTR (var, att_exported);
-
- if (exported_p (var))
- array_needs_making = 1;
-
- return (var);
-}
-
-/* Bind/create a shell variable with the name LHS to the RHS.
- This creates or modifies a variable such that it is an integer.
-
- This used to be in expr.c, but it is here so that all of the
- variable binding stuff is localized. Since we don't want any
- recursive evaluation from bind_variable() (possible without this code,
- since bind_variable() calls the evaluator for variables with the integer
- attribute set), we temporarily turn off the integer attribute for each
- variable we set here, then turn it back on after binding as necessary. */
-
-SHELL_VAR *
-bind_int_variable (lhs, rhs)
- char *lhs, *rhs;
-{
- register SHELL_VAR *v;
- int isint, isarr, implicitarray;
-
- isint = isarr = implicitarray = 0;
-#if defined (ARRAY_VARS)
- if (valid_array_reference (lhs))
- {
- isarr = 1;
- v = array_variable_part (lhs, (char **)0, (int *)0);
- }
- else
-#endif
- v = find_variable (lhs);
-
- if (v)
- {
- isint = integer_p (v);
- VUNSETATTR (v, att_integer);
-#if defined (ARRAY_VARS)
- if (array_p (v) && isarr == 0)
- implicitarray = 1;
-#endif
- }
-
-#if defined (ARRAY_VARS)
- if (isarr)
- v = assign_array_element (lhs, rhs, 0);
- else if (implicitarray)
- v = bind_array_variable (lhs, 0, rhs, 0);
- else
-#endif
- v = bind_variable (lhs, rhs, 0);
-
- if (v && isint)
- VSETATTR (v, att_integer);
-
- VUNSETATTR (v, att_invisible);
-
- return (v);
-}
-
-SHELL_VAR *
-bind_var_to_int (var, val)
- char *var;
- intmax_t val;
-{
- char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
-
- p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
- return (bind_int_variable (var, p));
-}
-
-/* Do a function binding to a variable. You pass the name and
- the command to bind to. This conses the name and command. */
-SHELL_VAR *
-bind_function (name, value)
- const char *name;
- COMMAND *value;
-{
- SHELL_VAR *entry;
-
- entry = find_function (name);
- if (entry == 0)
- {
- BUCKET_CONTENTS *elt;
-
- elt = hash_insert (savestring (name), shell_functions, HASH_NOSRCH);
- entry = new_shell_variable (name);
- elt->data = (PTR_T)entry;
- }
- else
- INVALIDATE_EXPORTSTR (entry);
-
- if (var_isset (entry))
- dispose_command (function_cell (entry));
-
- if (value)
- var_setfunc (entry, copy_command (value));
- else
- var_setfunc (entry, 0);
-
- VSETATTR (entry, att_function);
-
- if (mark_modified_vars)
- VSETATTR (entry, att_exported);
-
- VUNSETATTR (entry, att_invisible); /* Just to be sure */
-
- if (exported_p (entry))
- array_needs_making = 1;
-
-#if defined (PROGRAMMABLE_COMPLETION)
- set_itemlist_dirty (&it_functions);
-#endif
-
- return (entry);
-}
-
-#if defined (DEBUGGER)
-/* Bind a function definition, which includes source file and line number
- information in addition to the command, into the FUNCTION_DEF hash table.*/
-void
-bind_function_def (name, value)
- const char *name;
- FUNCTION_DEF *value;
-{
- FUNCTION_DEF *entry;
- BUCKET_CONTENTS *elt;
- COMMAND *cmd;
-
- entry = find_function_def (name);
- if (entry)
- {
- dispose_function_def_contents (entry);
- entry = copy_function_def_contents (value, entry);
- }
- else
- {
- cmd = value->command;
- value->command = 0;
- entry = copy_function_def (value);
- value->command = cmd;
-
- elt = hash_insert (savestring (name), shell_function_defs, HASH_NOSRCH);
- elt->data = (PTR_T *)entry;
- }
-}
-#endif /* DEBUGGER */
-
-/* Add STRING, which is of the form foo=bar, to the temporary environment
- HASH_TABLE (temporary_env). The functions in execute_cmd.c are
- responsible for moving the main temporary env to one of the other
- temporary environments. The expansion code in subst.c calls this. */
-int
-assign_in_env (word, flags)
- WORD_DESC *word;
- int flags;
-{
- int offset, aflags;
- char *name, *temp, *value;
- SHELL_VAR *var;
- const char *string;
-
- string = word->word;
-
- aflags = 0;
- offset = assignment (string, 0);
- name = savestring (string);
- value = (char *)NULL;
-
- if (name[offset] == '=')
- {
- name[offset] = 0;
-
- /* don't ignore the `+' when assigning temporary environment */
- if (name[offset - 1] == '+')
- {
- name[offset - 1] = '\0';
- aflags |= ASS_APPEND;
- }
-
- var = find_variable (name);
- if (var && (readonly_p (var) || noassign_p (var)))
- {
- if (readonly_p (var))
- err_readonly (name);
- free (name);
- return (0);
- }
-
- temp = name + offset + 1;
- value = expand_assignment_string_to_string (temp, 0);
-
- if (var && (aflags & ASS_APPEND))
- {
- temp = make_variable_value (var, value, aflags);
- FREE (value);
- value = temp;
- }
- }
-
- if (temporary_env == 0)
- temporary_env = hash_create (TEMPENV_HASH_BUCKETS);
-
- var = hash_lookup (name, temporary_env);
- if (var == 0)
- var = make_new_variable (name, temporary_env);
- else
- FREE (value_cell (var));
-
- if (value == 0)
- {
- value = (char *)xmalloc (1); /* like do_assignment_internal */
- value[0] = '\0';
- }
-
- var_setvalue (var, value);
- var->attributes |= (att_exported|att_tempvar);
- var->context = variable_context; /* XXX */
-
- INVALIDATE_EXPORTSTR (var);
- var->exportstr = mk_env_string (name, value, 0);
-
- array_needs_making = 1;
-
- if (flags)
- stupidly_hack_special_variables (name);
-
- if (echo_command_at_execute)
- /* The Korn shell prints the `+ ' in front of assignment statements,
- so we do too. */
- xtrace_print_assignment (name, value, 0, 1);
-
- free (name);
- return 1;
-}
-
-/* **************************************************************** */
-/* */
-/* Copying variables */
-/* */
-/* **************************************************************** */
-
-#ifdef INCLUDE_UNUSED
-/* Copy VAR to a new data structure and return that structure. */
-SHELL_VAR *
-copy_variable (var)
- SHELL_VAR *var;
-{
- SHELL_VAR *copy = (SHELL_VAR *)NULL;
-
- if (var)
- {
- copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));
-
- copy->attributes = var->attributes;
- copy->name = savestring (var->name);
-
- if (function_p (var))
- var_setfunc (copy, copy_command (function_cell (var)));
-#if defined (ARRAY_VARS)
- else if (array_p (var))
- var_setarray (copy, array_copy (array_cell (var)));
- else if (assoc_p (var))
- var_setassoc (copy, assoc_copy (assoc_cell (var)));
-#endif
- else if (nameref_cell (var)) /* XXX - nameref */
- var_setref (copy, savestring (nameref_cell (var)));
- else if (value_cell (var)) /* XXX - nameref */
- var_setvalue (copy, savestring (value_cell (var)));
- else
- var_setvalue (copy, (char *)NULL);
-
- copy->dynamic_value = var->dynamic_value;
- copy->assign_func = var->assign_func;
-
- copy->exportstr = COPY_EXPORTSTR (var);
-
- copy->context = var->context;
- }
- return (copy);
-}
-#endif
-
-/* **************************************************************** */
-/* */
-/* Deleting and unsetting variables */
-/* */
-/* **************************************************************** */
-
-/* Dispose of the information attached to VAR. */
-static void
-dispose_variable_value (var)
- SHELL_VAR *var;
-{
- if (function_p (var))
- dispose_command (function_cell (var));
-#if defined (ARRAY_VARS)
- else if (array_p (var))
- array_dispose (array_cell (var));
- else if (assoc_p (var))
- assoc_dispose (assoc_cell (var));
-#endif
- else if (nameref_p (var))
- FREE (nameref_cell (var));
- else
- FREE (value_cell (var));
-}
-
-void
-dispose_variable (var)
- SHELL_VAR *var;
-{
- if (var == 0)
- return;
-
- if (nofree_p (var) == 0)
- dispose_variable_value (var);
-
- FREE_EXPORTSTR (var);
-
- free (var->name);
-
- if (exported_p (var))
- array_needs_making = 1;
-
- free (var);
-}
-
-/* Unset the shell variable referenced by NAME. Unsetting a nameref variable
- unsets the variable it resolves to but leaves the nameref alone. */
-int
-unbind_variable (name)
- const char *name;
-{
- SHELL_VAR *v, *nv;
- int r;
-
- v = var_lookup (name, shell_variables);
- nv = (v && nameref_p (v)) ? find_variable_nameref (v) : (SHELL_VAR *)NULL;
-
- r = nv ? makunbound (nv->name, shell_variables) : makunbound (name, shell_variables);
- return r;
-}
-
-/* Unbind NAME, where NAME is assumed to be a nameref variable */
-int
-unbind_nameref (name)
- const char *name;
-{
- SHELL_VAR *v;
-
- v = var_lookup (name, shell_variables);
- if (v && nameref_p (v))
- return makunbound (name, shell_variables);
- return 0;
-}
-
-/* Unset the shell function named NAME. */
-int
-unbind_func (name)
- const char *name;
-{
- BUCKET_CONTENTS *elt;
- SHELL_VAR *func;
-
- elt = hash_remove (name, shell_functions, 0);
-
- if (elt == 0)
- return -1;
-
-#if defined (PROGRAMMABLE_COMPLETION)
- set_itemlist_dirty (&it_functions);
-#endif
-
- func = (SHELL_VAR *)elt->data;
- if (func)
- {
- if (exported_p (func))
- array_needs_making++;
- dispose_variable (func);
- }
-
- free (elt->key);
- free (elt);
-
- return 0;
-}
-
-#if defined (DEBUGGER)
-int
-unbind_function_def (name)
- const char *name;
-{
- BUCKET_CONTENTS *elt;
- FUNCTION_DEF *funcdef;
-
- elt = hash_remove (name, shell_function_defs, 0);
-
- if (elt == 0)
- return -1;
-
- funcdef = (FUNCTION_DEF *)elt->data;
- if (funcdef)
- dispose_function_def (funcdef);
-
- free (elt->key);
- free (elt);
-
- return 0;
-}
-#endif /* DEBUGGER */
-
-int
-delete_var (name, vc)
- const char *name;
- VAR_CONTEXT *vc;
-{
- BUCKET_CONTENTS *elt;
- SHELL_VAR *old_var;
- VAR_CONTEXT *v;
-
- for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- if (elt = hash_remove (name, v->table, 0))
- break;
-
- if (elt == 0)
- return (-1);
-
- old_var = (SHELL_VAR *)elt->data;
- free (elt->key);
- free (elt);
-
- dispose_variable (old_var);
- return (0);
-}
-
-/* Make the variable associated with NAME go away. HASH_LIST is the
- hash table from which this variable should be deleted (either
- shell_variables or shell_functions).
- Returns non-zero if the variable couldn't be found. */
-int
-makunbound (name, vc)
- const char *name;
- VAR_CONTEXT *vc;
-{
- BUCKET_CONTENTS *elt, *new_elt;
- SHELL_VAR *old_var;
- VAR_CONTEXT *v;
- char *t;
-
- for (elt = (BUCKET_CONTENTS *)NULL, v = vc; v; v = v->down)
- if (elt = hash_remove (name, v->table, 0))
- break;
-
- if (elt == 0)
- return (-1);
-
- old_var = (SHELL_VAR *)elt->data;
-
- if (old_var && exported_p (old_var))
- array_needs_making++;
-
- /* If we're unsetting a local variable and we're still executing inside
- the function, just mark the variable as invisible. The function
- eventually called by pop_var_context() will clean it up later. This
- must be done so that if the variable is subsequently assigned a new
- value inside the function, the `local' attribute is still present.
- We also need to add it back into the correct hash table. */
- if (old_var && local_p (old_var) && variable_context == old_var->context)
- {
- if (nofree_p (old_var))
- var_setvalue (old_var, (char *)NULL);
-#if defined (ARRAY_VARS)
- else if (array_p (old_var))
- array_dispose (array_cell (old_var));
- else if (assoc_p (old_var))
- assoc_dispose (assoc_cell (old_var));
-#endif
- else if (nameref_p (old_var))
- FREE (nameref_cell (old_var));
- else
- FREE (value_cell (old_var));
- /* Reset the attributes. Preserve the export attribute if the variable
- came from a temporary environment. Make sure it stays local, and
- make it invisible. */
- old_var->attributes = (exported_p (old_var) && tempvar_p (old_var)) ? att_exported : 0;
- VSETATTR (old_var, att_local);
- VSETATTR (old_var, att_invisible);
- var_setvalue (old_var, (char *)NULL);
- INVALIDATE_EXPORTSTR (old_var);
-
- new_elt = hash_insert (savestring (old_var->name), v->table, 0);
- new_elt->data = (PTR_T)old_var;
- stupidly_hack_special_variables (old_var->name);
-
- free (elt->key);
- free (elt);
- return (0);
- }
-
- /* Have to save a copy of name here, because it might refer to
- old_var->name. If so, stupidly_hack_special_variables will
- reference freed memory. */
- t = savestring (name);
-
- free (elt->key);
- free (elt);
-
- dispose_variable (old_var);
- stupidly_hack_special_variables (t);
- free (t);
-
- return (0);
-}
-
-/* Get rid of all of the variables in the current context. */
-void
-kill_all_local_variables ()
-{
- VAR_CONTEXT *vc;
-
- for (vc = shell_variables; vc; vc = vc->down)
- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- break;
- if (vc == 0)
- return; /* XXX */
-
- if (vc->table && vc_haslocals (vc))
- {
- delete_all_variables (vc->table);
- hash_dispose (vc->table);
- }
- vc->table = (HASH_TABLE *)NULL;
-}
-
-static void
-free_variable_hash_data (data)
- PTR_T data;
-{
- SHELL_VAR *var;
-
- var = (SHELL_VAR *)data;
- dispose_variable (var);
-}
-
-/* Delete the entire contents of the hash table. */
-void
-delete_all_variables (hashed_vars)
- HASH_TABLE *hashed_vars;
-{
- hash_flush (hashed_vars, free_variable_hash_data);
-}
-
-/* **************************************************************** */
-/* */
-/* Setting variable attributes */
-/* */
-/* **************************************************************** */
-
-#define FIND_OR_MAKE_VARIABLE(name, entry) \
- do \
- { \
- entry = find_variable (name); \
- if (!entry) \
- { \
- entry = bind_variable (name, "", 0); \
- if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
- } \
- } \
- while (0)
-
-/* Make the variable associated with NAME be readonly.
- If NAME does not exist yet, create it. */
-void
-set_var_read_only (name)
- char *name;
-{
- SHELL_VAR *entry;
-
- FIND_OR_MAKE_VARIABLE (name, entry);
- VSETATTR (entry, att_readonly);
-}
-
-#ifdef INCLUDE_UNUSED
-/* Make the function associated with NAME be readonly.
- If NAME does not exist, we just punt, like auto_export code below. */
-void
-set_func_read_only (name)
- const char *name;
-{
- SHELL_VAR *entry;
-
- entry = find_function (name);
- if (entry)
- VSETATTR (entry, att_readonly);
-}
-
-/* Make the variable associated with NAME be auto-exported.
- If NAME does not exist yet, create it. */
-void
-set_var_auto_export (name)
- char *name;
-{
- SHELL_VAR *entry;
-
- FIND_OR_MAKE_VARIABLE (name, entry);
- set_auto_export (entry);
-}
-
-/* Make the function associated with NAME be auto-exported. */
-void
-set_func_auto_export (name)
- const char *name;
-{
- SHELL_VAR *entry;
-
- entry = find_function (name);
- if (entry)
- set_auto_export (entry);
-}
-#endif
-
-/* **************************************************************** */
-/* */
-/* Creating lists of variables */
-/* */
-/* **************************************************************** */
-
-static VARLIST *
-vlist_alloc (nentries)
- int nentries;
-{
- VARLIST *vlist;
-
- vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
- vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
- vlist->list_size = nentries;
- vlist->list_len = 0;
- vlist->list[0] = (SHELL_VAR *)NULL;
-
- return vlist;
-}
-
-static VARLIST *
-vlist_realloc (vlist, n)
- VARLIST *vlist;
- int n;
-{
- if (vlist == 0)
- return (vlist = vlist_alloc (n));
- if (n > vlist->list_size)
- {
- vlist->list_size = n;
- vlist->list = (SHELL_VAR **)xrealloc (vlist->list, (vlist->list_size + 1) * sizeof (SHELL_VAR *));
- }
- return vlist;
-}
-
-static void
-vlist_add (vlist, var, flags)
- VARLIST *vlist;
- SHELL_VAR *var;
- int flags;
-{
- register int i;
-
- for (i = 0; i < vlist->list_len; i++)
- if (STREQ (var->name, vlist->list[i]->name))
- break;
- if (i < vlist->list_len)
- return;
-
- if (i >= vlist->list_size)
- vlist = vlist_realloc (vlist, vlist->list_size + 16);
-
- vlist->list[vlist->list_len++] = var;
- vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
-}
-
-/* Map FUNCTION over the variables in VAR_HASH_TABLE. Return an array of the
- variables for which FUNCTION returns a non-zero value. A NULL value
- for FUNCTION means to use all variables. */
-SHELL_VAR **
-map_over (function, vc)
- sh_var_map_func_t *function;
- VAR_CONTEXT *vc;
-{
- VAR_CONTEXT *v;
- VARLIST *vlist;
- SHELL_VAR **ret;
- int nentries;
-
- for (nentries = 0, v = vc; v; v = v->down)
- nentries += HASH_ENTRIES (v->table);
-
- if (nentries == 0)
- return (SHELL_VAR **)NULL;
-
- vlist = vlist_alloc (nentries);
-
- for (v = vc; v; v = v->down)
- flatten (v->table, function, vlist, 0);
-
- ret = vlist->list;
- free (vlist);
- return ret;
-}
-
-SHELL_VAR **
-map_over_funcs (function)
- sh_var_map_func_t *function;
-{
- VARLIST *vlist;
- SHELL_VAR **ret;
-
- if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
- return ((SHELL_VAR **)NULL);
-
- vlist = vlist_alloc (HASH_ENTRIES (shell_functions));
-
- flatten (shell_functions, function, vlist, 0);
-
- ret = vlist->list;
- free (vlist);
- return ret;
-}
-
-/* Flatten VAR_HASH_TABLE, applying FUNC to each member and adding those
- elements for which FUNC succeeds to VLIST->list. FLAGS is reserved
- for future use. Only unique names are added to VLIST. If FUNC is
- NULL, each variable in VAR_HASH_TABLE is added to VLIST. If VLIST is
- NULL, FUNC is applied to each SHELL_VAR in VAR_HASH_TABLE. If VLIST
- and FUNC are both NULL, nothing happens. */
-static void
-flatten (var_hash_table, func, vlist, flags)
- HASH_TABLE *var_hash_table;
- sh_var_map_func_t *func;
- VARLIST *vlist;
- int flags;
-{
- register int i;
- register BUCKET_CONTENTS *tlist;
- int r;
- SHELL_VAR *var;
-
- if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
- return;
-
- for (i = 0; i < var_hash_table->nbuckets; i++)
- {
- for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
- {
- var = (SHELL_VAR *)tlist->data;
-
- r = func ? (*func) (var) : 1;
- if (r && vlist)
- vlist_add (vlist, var, flags);
- }
- }
-}
-
-void
-sort_variables (array)
- SHELL_VAR **array;
-{
- qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
-}
-
-static int
-qsort_var_comp (var1, var2)
- SHELL_VAR **var1, **var2;
-{
- int result;
-
- if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
- result = strcmp ((*var1)->name, (*var2)->name);
-
- return (result);
-}
-
-/* Apply FUNC to each variable in SHELL_VARIABLES, adding each one for
- which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
-static SHELL_VAR **
-vapply (func)
- sh_var_map_func_t *func;
-{
- SHELL_VAR **list;
-
- list = map_over (func, shell_variables);
- if (list /* && posixly_correct */)
- sort_variables (list);
- return (list);
-}
-
-/* Apply FUNC to each variable in SHELL_FUNCTIONS, adding each one for
- which FUNC succeeds to an array of SHELL_VAR *s. Returns the array. */
-static SHELL_VAR **
-fapply (func)
- sh_var_map_func_t *func;
-{
- SHELL_VAR **list;
-
- list = map_over_funcs (func);
- if (list /* && posixly_correct */)
- sort_variables (list);
- return (list);
-}
-
-/* Create a NULL terminated array of all the shell variables. */
-SHELL_VAR **
-all_shell_variables ()
-{
- return (vapply ((sh_var_map_func_t *)NULL));
-}
-
-/* Create a NULL terminated array of all the shell functions. */
-SHELL_VAR **
-all_shell_functions ()
-{
- return (fapply ((sh_var_map_func_t *)NULL));
-}
-
-static int
-visible_var (var)
- SHELL_VAR *var;
-{
- return (invisible_p (var) == 0);
-}
-
-SHELL_VAR **
-all_visible_functions ()
-{
- return (fapply (visible_var));
-}
-
-SHELL_VAR **
-all_visible_variables ()
-{
- return (vapply (visible_var));
-}
-
-/* Return non-zero if the variable VAR is visible and exported. Array
- variables cannot be exported. */
-static int
-visible_and_exported (var)
- SHELL_VAR *var;
-{
- return (invisible_p (var) == 0 && exported_p (var));
-}
-
-/* Candidate variables for the export environment are either valid variables
- with the export attribute or invalid variables inherited from the initial
- environment and simply passed through. */
-static int
-export_environment_candidate (var)
- SHELL_VAR *var;
-{
- return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
-}
-
-/* Return non-zero if VAR is a local variable in the current context and
- is exported. */
-static int
-local_and_exported (var)
- SHELL_VAR *var;
-{
- return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context && exported_p (var));
-}
-
-SHELL_VAR **
-all_exported_variables ()
-{
- return (vapply (visible_and_exported));
-}
-
-SHELL_VAR **
-local_exported_variables ()
-{
- return (vapply (local_and_exported));
-}
-
-static int
-variable_in_context (var)
- SHELL_VAR *var;
-{
- return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context);
-}
-
-SHELL_VAR **
-all_local_variables ()
-{
- VARLIST *vlist;
- SHELL_VAR **ret;
- VAR_CONTEXT *vc;
-
- vc = shell_variables;
- for (vc = shell_variables; vc; vc = vc->down)
- if (vc_isfuncenv (vc) && vc->scope == variable_context)
- break;
-
- if (vc == 0)
- {
- internal_error (_("all_local_variables: no function context at current scope"));
- return (SHELL_VAR **)NULL;
- }
- if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
- return (SHELL_VAR **)NULL;
-
- vlist = vlist_alloc (HASH_ENTRIES (vc->table));
-
- flatten (vc->table, variable_in_context, vlist, 0);
-
- ret = vlist->list;
- free (vlist);
- if (ret)
- sort_variables (ret);
- return ret;
-}
-
-#if defined (ARRAY_VARS)
-/* Return non-zero if the variable VAR is visible and an array. */
-static int
-visible_array_vars (var)
- SHELL_VAR *var;
-{
- return (invisible_p (var) == 0 && array_p (var));
-}
-
-SHELL_VAR **
-all_array_variables ()
-{
- return (vapply (visible_array_vars));
-}
-#endif /* ARRAY_VARS */
-
-char **
-all_variables_matching_prefix (prefix)
- const char *prefix;
-{
- SHELL_VAR **varlist;
- char **rlist;
- int vind, rind, plen;
-
- plen = STRLEN (prefix);
- varlist = all_visible_variables ();
- for (vind = 0; varlist && varlist[vind]; vind++)
- ;
- if (varlist == 0 || vind == 0)
- return ((char **)NULL);
- rlist = strvec_create (vind + 1);
- for (vind = rind = 0; varlist[vind]; vind++)
- {
- if (plen == 0 || STREQN (prefix, varlist[vind]->name, plen))
- rlist[rind++] = savestring (varlist[vind]->name);
- }
- rlist[rind] = (char *)0;
- free (varlist);
-
- return rlist;
-}
-
-/* **************************************************************** */
-/* */
-/* Managing temporary variable scopes */
-/* */
-/* **************************************************************** */
-
-/* Make variable NAME have VALUE in the temporary environment. */
-static SHELL_VAR *
-bind_tempenv_variable (name, value)
- const char *name;
- char *value;
-{
- SHELL_VAR *var;
-
- var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;
-
- if (var)
- {
- FREE (value_cell (var));
- var_setvalue (var, savestring (value));
- INVALIDATE_EXPORTSTR (var);
- }
-
- return (var);
-}
-
-/* Find a variable in the temporary environment that is named NAME.
- Return the SHELL_VAR *, or NULL if not found. */
-SHELL_VAR *
-find_tempenv_variable (name)
- const char *name;
-{
- return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
-}
-
-char **tempvar_list;
-int tvlist_ind;
-
-/* Push the variable described by (SHELL_VAR *)DATA down to the next
- variable context from the temporary environment. */
-static void
-push_temp_var (data)
- PTR_T data;
-{
- SHELL_VAR *var, *v;
- HASH_TABLE *binding_table;
-
- var = (SHELL_VAR *)data;
-
- binding_table = shell_variables->table;
- if (binding_table == 0)
- {
- if (shell_variables == global_variables)
- /* shouldn't happen */
- binding_table = shell_variables->table = global_variables->table = hash_create (0);
- else
- binding_table = shell_variables->table = hash_create (TEMPENV_HASH_BUCKETS);
- }
-
- v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, 0);
-
- /* XXX - should we set the context here? It shouldn't matter because of how
- assign_in_env works, but might want to check. */
- if (binding_table == global_variables->table) /* XXX */
- var->attributes &= ~(att_tempvar|att_propagate);
- else
- {
- var->attributes |= att_propagate;
- if (binding_table == shell_variables->table)
- shell_variables->flags |= VC_HASTMPVAR;
- }
- v->attributes |= var->attributes;
-
- if (find_special_var (var->name) >= 0)
- tempvar_list[tvlist_ind++] = savestring (var->name);
-
- dispose_variable (var);
-}
-
-static void
-propagate_temp_var (data)
- PTR_T data;
-{
- SHELL_VAR *var;
-
- var = (SHELL_VAR *)data;
- if (tempvar_p (var) && (var->attributes & att_propagate))
- push_temp_var (data);
- else
- {
- if (find_special_var (var->name) >= 0)
- tempvar_list[tvlist_ind++] = savestring (var->name);
- dispose_variable (var);
- }
-}
-
-/* Free the storage used in the hash table for temporary
- environment variables. PUSHF is a function to be called
- to free each hash table entry. It takes care of pushing variables
- to previous scopes if appropriate. PUSHF stores names of variables
- that require special handling (e.g., IFS) on tempvar_list, so this
- function can call stupidly_hack_special_variables on all the
- variables in the list when the temporary hash table is destroyed. */
-static void
-dispose_temporary_env (pushf)
- sh_free_func_t *pushf;
-{
- int i;
-
- tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
- tempvar_list[tvlist_ind = 0] = 0;
-
- hash_flush (temporary_env, pushf);
- hash_dispose (temporary_env);
- temporary_env = (HASH_TABLE *)NULL;
-
- tempvar_list[tvlist_ind] = 0;
-
- array_needs_making = 1;
-
-#if 0
- sv_ifs ("IFS"); /* XXX here for now -- check setifs in assign_in_env */
-#endif
- for (i = 0; i < tvlist_ind; i++)
- stupidly_hack_special_variables (tempvar_list[i]);
-
- strvec_dispose (tempvar_list);
- tempvar_list = 0;
- tvlist_ind = 0;
-}
-
-void
-dispose_used_env_vars ()
-{
- if (temporary_env)
- {
- dispose_temporary_env (propagate_temp_var);
- maybe_make_export_env ();
- }
-}
-
-/* Take all of the shell variables in the temporary environment HASH_TABLE
- and make shell variables from them at the current variable context. */
-void
-merge_temporary_env ()
-{
- if (temporary_env)
- dispose_temporary_env (push_temp_var);
-}
-
-/* **************************************************************** */
-/* */
-/* Creating and manipulating the environment */
-/* */
-/* **************************************************************** */
-
-static inline char *
-mk_env_string (name, value, isfunc)
- const char *name, *value;
- int isfunc;
-{
- size_t name_len, value_len;
- char *p, *q;
-
- name_len = strlen (name);
- value_len = STRLEN (value);
-
- /* If we are exporting a shell function, construct the encoded function
- name. */
- if (isfunc && value)
- {
- p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
- q = p;
- memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
- q += BASHFUNC_PREFLEN;
- memcpy (q, name, name_len);
- q += name_len;
- memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
- q += BASHFUNC_SUFFLEN;
- }
- else
- {
- p = (char *)xmalloc (2 + name_len + value_len);
- memcpy (p, name, name_len);
- q = p + name_len;
- }
-
- q[0] = '=';
- if (value && *value)
- memcpy (q + 1, value, value_len + 1);
- else
- q[1] = '\0';
-
- return (p);
-}
-
-#ifdef DEBUG
-/* Debugging */
-static int
-valid_exportstr (v)
- SHELL_VAR *v;
-{
- char *s;
-
- s = v->exportstr;
- if (s == 0)
- {
- internal_error (_("%s has null exportstr"), v->name);
- return (0);
- }
- if (legal_variable_starter ((unsigned char)*s) == 0)
- {
- internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- return (0);
- }
- for (s = v->exportstr + 1; s && *s; s++)
- {
- if (*s == '=')
- break;
- if (legal_variable_char ((unsigned char)*s) == 0)
- {
- internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
- return (0);
- }
- }
- if (*s != '=')
- {
- internal_error (_("no `=' in exportstr for %s"), v->name);
- return (0);
- }
- return (1);
-}
-#endif
-
-static char **
-make_env_array_from_var_list (vars)
- SHELL_VAR **vars;
-{
- register int i, list_index;
- register SHELL_VAR *var;
- char **list, *value;
-
- list = strvec_create ((1 + strvec_len ((char **)vars)));
-
-#define USE_EXPORTSTR (value == var->exportstr)
-
- for (i = 0, list_index = 0; var = vars[i]; i++)
- {
-#if defined (__CYGWIN__)
- /* We don't use the exportstr stuff on Cygwin at all. */
- INVALIDATE_EXPORTSTR (var);
-#endif
- if (var->exportstr)
- value = var->exportstr;
- else if (function_p (var))
- value = named_function_string ((char *)NULL, function_cell (var), 0);
-#if defined (ARRAY_VARS)
- else if (array_p (var))
-# if ARRAY_EXPORT
- value = array_to_assignment_string (array_cell (var));
-# else
- continue; /* XXX array vars cannot yet be exported */
-# endif /* ARRAY_EXPORT */
- else if (assoc_p (var))
-# if 0
- value = assoc_to_assignment_string (assoc_cell (var));
-# else
- continue; /* XXX associative array vars cannot yet be exported */
-# endif
-#endif
- else
- value = value_cell (var);
-
- if (value)
- {
- /* Gee, I'd like to get away with not using savestring() if we're
- using the cached exportstr... */
- list[list_index] = USE_EXPORTSTR ? savestring (value)
- : mk_env_string (var->name, value, function_p (var));
-
- if (USE_EXPORTSTR == 0)
- SAVE_EXPORTSTR (var, list[list_index]);
-
- list_index++;
-#undef USE_EXPORTSTR
-
-#if 0 /* not yet */
-#if defined (ARRAY_VARS)
- if (array_p (var) || assoc_p (var))
- free (value);
-#endif
-#endif
- }
- }
-
- list[list_index] = (char *)NULL;
- return (list);
-}
-
-/* Make an array of assignment statements from the hash table
- HASHED_VARS which contains SHELL_VARs. Only visible, exported
- variables are eligible. */
-static char **
-make_var_export_array (vcxt)
- VAR_CONTEXT *vcxt;
-{
- char **list;
- SHELL_VAR **vars;
-
-#if 0
- vars = map_over (visible_and_exported, vcxt);
-#else
- vars = map_over (export_environment_candidate, vcxt);
-#endif
-
- if (vars == 0)
- return (char **)NULL;
-
- list = make_env_array_from_var_list (vars);
-
- free (vars);
- return (list);
-}
-
-static char **
-make_func_export_array ()
-{
- char **list;
- SHELL_VAR **vars;
-
- vars = map_over_funcs (visible_and_exported);
- if (vars == 0)
- return (char **)NULL;
-
- list = make_env_array_from_var_list (vars);
-
- free (vars);
- return (list);
-}
-
-/* Add ENVSTR to the end of the exported environment, EXPORT_ENV. */
-#define add_to_export_env(envstr,do_alloc) \
-do \
- { \
- if (export_env_index >= (export_env_size - 1)) \
- { \
- export_env_size += 16; \
- export_env = strvec_resize (export_env, export_env_size); \
- environ = export_env; \
- } \
- export_env[export_env_index++] = (do_alloc) ? savestring (envstr) : envstr; \
- export_env[export_env_index] = (char *)NULL; \
- } while (0)
-
-/* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the
- array with the same left-hand side. Return the new EXPORT_ENV. */
-char **
-add_or_supercede_exported_var (assign, do_alloc)
- char *assign;
- int do_alloc;
-{
- register int i;
- int equal_offset;
-
- equal_offset = assignment (assign, 0);
- if (equal_offset == 0)
- return (export_env);
-
- /* If this is a function, then only supersede the function definition.
- We do this by including the `=() {' in the comparison, like
- initialize_shell_variables does. */
- if (assign[equal_offset + 1] == '(' &&
- strncmp (assign + equal_offset + 2, ") {", 3) == 0) /* } */
- equal_offset += 4;
-
- for (i = 0; i < export_env_index; i++)
- {
- if (STREQN (assign, export_env[i], equal_offset + 1))
- {
- free (export_env[i]);
- export_env[i] = do_alloc ? savestring (assign) : assign;
- return (export_env);
- }
- }
- add_to_export_env (assign, do_alloc);
- return (export_env);
-}
-
-static void
-add_temp_array_to_env (temp_array, do_alloc, do_supercede)
- char **temp_array;
- int do_alloc, do_supercede;
-{
- register int i;
-
- if (temp_array == 0)
- return;
-
- for (i = 0; temp_array[i]; i++)
- {
- if (do_supercede)
- export_env = add_or_supercede_exported_var (temp_array[i], do_alloc);
- else
- add_to_export_env (temp_array[i], do_alloc);
- }
-
- free (temp_array);
-}
-
-/* Make the environment array for the command about to be executed, if the
- array needs making. Otherwise, do nothing. If a shell action could
- change the array that commands receive for their environment, then the
- code should `array_needs_making++'.
-
- The order to add to the array is:
- temporary_env
- list of var contexts whose head is shell_variables
- shell_functions
-
- This is the shell variable lookup order. We add only new variable
- names at each step, which allows local variables and variables in
- the temporary environments to shadow variables in the global (or
- any previous) scope.
-*/
-
-static int
-n_shell_variables ()
-{
- VAR_CONTEXT *vc;
- int n;
-
- for (n = 0, vc = shell_variables; vc; vc = vc->down)
- n += HASH_ENTRIES (vc->table);
- return n;
-}
-
-int
-chkexport (name)
- char *name;
-{
- SHELL_VAR *v;
-
- v = find_variable (name);
- if (v && exported_p (v))
- {
- array_needs_making = 1;
- maybe_make_export_env ();
- return 1;
- }
- return 0;
-}
-
-void
-maybe_make_export_env ()
-{
- register char **temp_array;
- int new_size;
- VAR_CONTEXT *tcxt;
-
- if (array_needs_making)
- {
- if (export_env)
- strvec_flush (export_env);
-
- /* Make a guess based on how many shell variables and functions we
- have. Since there will always be array variables, and array
- variables are not (yet) exported, this will always be big enough
- for the exported variables and functions. */
- new_size = n_shell_variables () + HASH_ENTRIES (shell_functions) + 1 +
- HASH_ENTRIES (temporary_env);
- if (new_size > export_env_size)
- {
- export_env_size = new_size;
- export_env = strvec_resize (export_env, export_env_size);
- environ = export_env;
- }
- export_env[export_env_index = 0] = (char *)NULL;
-
- /* Make a dummy variable context from the temporary_env, stick it on
- the front of shell_variables, call make_var_export_array on the
- whole thing to flatten it, and convert the list of SHELL_VAR *s
- to the form needed by the environment. */
- if (temporary_env)
- {
- tcxt = new_var_context ((char *)NULL, 0);
- tcxt->table = temporary_env;
- tcxt->down = shell_variables;
- }
- else
- tcxt = shell_variables;
-
- temp_array = make_var_export_array (tcxt);
- if (temp_array)
- add_temp_array_to_env (temp_array, 0, 0);
-
- if (tcxt != shell_variables)
- free (tcxt);
-
-#if defined (RESTRICTED_SHELL)
- /* Restricted shells may not export shell functions. */
- temp_array = restricted ? (char **)0 : make_func_export_array ();
-#else
- temp_array = make_func_export_array ();
-#endif
- if (temp_array)
- add_temp_array_to_env (temp_array, 0, 0);
-
- array_needs_making = 0;
- }
-}
-
-/* This is an efficiency hack. PWD and OLDPWD are auto-exported, so
- we will need to remake the exported environment every time we
- change directories. `_' is always put into the environment for
- every external command, so without special treatment it will always
- cause the environment to be remade.
-
- If there is no other reason to make the exported environment, we can
- just update the variables in place and mark the exported environment
- as no longer needing a remake. */
-void
-update_export_env_inplace (env_prefix, preflen, value)
- char *env_prefix;
- int preflen;
- char *value;
-{
- char *evar;
-
- evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
- strcpy (evar, env_prefix);
- if (value)
- strcpy (evar + preflen, value);
- export_env = add_or_supercede_exported_var (evar, 0);
-}
-
-/* We always put _ in the environment as the name of this command. */
-void
-put_command_name_into_env (command_name)
- char *command_name;
-{
- update_export_env_inplace ("_=", 2, command_name);
-}
-
-/* **************************************************************** */
-/* */
-/* Managing variable contexts */
-/* */
-/* **************************************************************** */
-
-/* Allocate and return a new variable context with NAME and FLAGS.
- NAME can be NULL. */
-
-VAR_CONTEXT *
-new_var_context (name, flags)
- char *name;
- int flags;
-{
- VAR_CONTEXT *vc;
-
- vc = (VAR_CONTEXT *)xmalloc (sizeof (VAR_CONTEXT));
- vc->name = name ? savestring (name) : (char *)NULL;
- vc->scope = variable_context;
- vc->flags = flags;
-
- vc->up = vc->down = (VAR_CONTEXT *)NULL;
- vc->table = (HASH_TABLE *)NULL;
-
- return vc;
-}
-
-/* Free a variable context and its data, including the hash table. Dispose
- all of the variables. */
-void
-dispose_var_context (vc)
- VAR_CONTEXT *vc;
-{
- FREE (vc->name);
-
- if (vc->table)
- {
- delete_all_variables (vc->table);
- hash_dispose (vc->table);
- }
-
- free (vc);
-}
-
-/* Set VAR's scope level to the current variable context. */
-static int
-set_context (var)
- SHELL_VAR *var;
-{
- return (var->context = variable_context);
-}
-
-/* Make a new variable context with NAME and FLAGS and a HASH_TABLE of
- temporary variables, and push it onto shell_variables. This is
- for shell functions. */
-VAR_CONTEXT *
-push_var_context (name, flags, tempvars)
- char *name;
- int flags;
- HASH_TABLE *tempvars;
-{
- VAR_CONTEXT *vc;
-
- vc = new_var_context (name, flags);
- vc->table = tempvars;
- if (tempvars)
- {
- /* Have to do this because the temp environment was created before
- variable_context was incremented. */
- flatten (tempvars, set_context, (VARLIST *)NULL, 0);
- vc->flags |= VC_HASTMPVAR;
- }
- vc->down = shell_variables;
- shell_variables->up = vc;
-
- return (shell_variables = vc);
-}
-
-static void
-push_func_var (data)
- PTR_T data;
-{
- SHELL_VAR *var, *v;
-
- var = (SHELL_VAR *)data;
-
- if (tempvar_p (var) && (posixly_correct || (var->attributes & att_propagate)))
- {
- /* Make sure we have a hash table to store the variable in while it is
- being propagated down to the global variables table. Create one if
- we have to */
- if ((vc_isfuncenv (shell_variables) || vc_istempenv (shell_variables)) && shell_variables->table == 0)
- shell_variables->table = hash_create (0);
- /* XXX - should we set v->context here? */
- v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- if (shell_variables == global_variables)
- var->attributes &= ~(att_tempvar|att_propagate);
- else
- shell_variables->flags |= VC_HASTMPVAR;
- v->attributes |= var->attributes;
- }
- else
- stupidly_hack_special_variables (var->name); /* XXX */
-
- dispose_variable (var);
-}
-
-/* Pop the top context off of VCXT and dispose of it, returning the rest of
- the stack. */
-void
-pop_var_context ()
-{
- VAR_CONTEXT *ret, *vcxt;
-
- vcxt = shell_variables;
- if (vc_isfuncenv (vcxt) == 0)
- {
- internal_error (_("pop_var_context: head of shell_variables not a function context"));
- return;
- }
-
- if (ret = vcxt->down)
- {
- ret->up = (VAR_CONTEXT *)NULL;
- shell_variables = ret;
- if (vcxt->table)
- hash_flush (vcxt->table, push_func_var);
- dispose_var_context (vcxt);
- }
- else
- internal_error (_("pop_var_context: no global_variables context"));
-}
-
-/* Delete the HASH_TABLEs for all variable contexts beginning at VCXT, and
- all of the VAR_CONTEXTs except GLOBAL_VARIABLES. */
-void
-delete_all_contexts (vcxt)
- VAR_CONTEXT *vcxt;
-{
- VAR_CONTEXT *v, *t;
-
- for (v = vcxt; v != global_variables; v = t)
- {
- t = v->down;
- dispose_var_context (v);
- }
-
- delete_all_variables (global_variables->table);
- shell_variables = global_variables;
-}
-
-/* **************************************************************** */
-/* */
-/* Pushing and Popping temporary variable scopes */
-/* */
-/* **************************************************************** */
-
-VAR_CONTEXT *
-push_scope (flags, tmpvars)
- int flags;
- HASH_TABLE *tmpvars;
-{
- return (push_var_context ((char *)NULL, flags, tmpvars));
-}
-
-static void
-push_exported_var (data)
- PTR_T data;
-{
- SHELL_VAR *var, *v;
-
- var = (SHELL_VAR *)data;
-
- /* If a temp var had its export attribute set, or it's marked to be
- propagated, bind it in the previous scope before disposing it. */
- /* XXX - This isn't exactly right, because all tempenv variables have the
- export attribute set. */
-#if 0
- if (exported_p (var) || (var->attributes & att_propagate))
-#else
- if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
-#endif
- {
- var->attributes &= ~att_tempvar; /* XXX */
- v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
- if (shell_variables == global_variables)
- var->attributes &= ~att_propagate;
- v->attributes |= var->attributes;
- }
- else
- stupidly_hack_special_variables (var->name); /* XXX */
-
- dispose_variable (var);
-}
-
-void
-pop_scope (is_special)
- int is_special;
-{
- VAR_CONTEXT *vcxt, *ret;
-
- vcxt = shell_variables;
- if (vc_istempscope (vcxt) == 0)
- {
- internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
- return;
- }
-
- ret = vcxt->down;
- if (ret)
- ret->up = (VAR_CONTEXT *)NULL;
-
- shell_variables = ret;
-
- /* Now we can take care of merging variables in VCXT into set of scopes
- whose head is RET (shell_variables). */
- FREE (vcxt->name);
- if (vcxt->table)
- {
- if (is_special)
- hash_flush (vcxt->table, push_func_var);
- else
- hash_flush (vcxt->table, push_exported_var);
- hash_dispose (vcxt->table);
- }
- free (vcxt);
-
- sv_ifs ("IFS"); /* XXX here for now */
-}
-
-/* **************************************************************** */
-/* */
-/* Pushing and Popping function contexts */
-/* */
-/* **************************************************************** */
-
-static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
-static int dollar_arg_stack_slots;
-static int dollar_arg_stack_index;
-
-/* XXX - we might want to consider pushing and popping the `getopts' state
- when we modify the positional parameters. */
-void
-push_context (name, is_subshell, tempvars)
- char *name; /* function name */
- int is_subshell;
- HASH_TABLE *tempvars;
-{
- if (is_subshell == 0)
- push_dollar_vars ();
- variable_context++;
- push_var_context (name, VC_FUNCENV, tempvars);
-}
-
-/* Only called when subshell == 0, so we don't need to check, and can
- unconditionally pop the dollar vars off the stack. */
-void
-pop_context ()
-{
- pop_dollar_vars ();
- variable_context--;
- pop_var_context ();
-
- sv_ifs ("IFS"); /* XXX here for now */
-}
-
-/* Save the existing positional parameters on a stack. */
-void
-push_dollar_vars ()
-{
- if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
- {
- dollar_arg_stack = (WORD_LIST **)
- xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
- * sizeof (WORD_LIST *));
- }
- dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args ();
- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
-}
-
-/* Restore the positional parameters from our stack. */
-void
-pop_dollar_vars ()
-{
- if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- return;
-
- remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
- dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
- set_dollar_vars_unchanged ();
-}
-
-void
-dispose_saved_dollar_vars ()
-{
- if (!dollar_arg_stack || dollar_arg_stack_index == 0)
- return;
-
- dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
- dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
-}
-
-/* Manipulate the special BASH_ARGV and BASH_ARGC variables. */
-
-void
-push_args (list)
- WORD_LIST *list;
-{
-#if defined (ARRAY_VARS) && defined (DEBUGGER)
- SHELL_VAR *bash_argv_v, *bash_argc_v;
- ARRAY *bash_argv_a, *bash_argc_a;
- WORD_LIST *l;
- arrayind_t i;
- char *t;
-
- GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
-
- for (l = list, i = 0; l; l = l->next, i++)
- array_push (bash_argv_a, l->word->word);
-
- t = itos (i);
- array_push (bash_argc_a, t);
- free (t);
-#endif /* ARRAY_VARS && DEBUGGER */
-}
-
-/* Remove arguments from BASH_ARGV array. Pop top element off BASH_ARGC
- array and use that value as the count of elements to remove from
- BASH_ARGV. */
-void
-pop_args ()
-{
-#if defined (ARRAY_VARS) && defined (DEBUGGER)
- SHELL_VAR *bash_argv_v, *bash_argc_v;
- ARRAY *bash_argv_a, *bash_argc_a;
- ARRAY_ELEMENT *ce;
- intmax_t i;
-
- GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
- GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
-
- ce = array_shift (bash_argc_a, 1, 0);
- if (ce == 0 || legal_number (element_value (ce), &i) == 0)
- i = 0;
-
- for ( ; i > 0; i--)
- array_pop (bash_argv_a);
- array_dispose_element (ce);
-#endif /* ARRAY_VARS && DEBUGGER */
-}
-
-/*************************************************
- * *
- * Functions to manage special variables *
- * *
- *************************************************/
-
-/* Extern declarations for variables this code has to manage. */
-extern int eof_encountered, eof_encountered_limit, ignoreeof;
-
-#if defined (READLINE)
-extern int hostname_list_initialized;
-#endif
-
-/* An alist of name.function for each special variable. Most of the
- functions don't do much, and in fact, this would be faster with a
- switch statement, but by the end of this file, I am sick of switch
- statements. */
-
-#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
-
-/* This table will be sorted with qsort() the first time it's accessed. */
-struct name_and_function {
- char *name;
- sh_sv_func_t *function;
-};
-
-static struct name_and_function special_vars[] = {
- { "BASH_COMPAT", sv_shcompat },
- { "BASH_XTRACEFD", sv_xtracefd },
-
-#if defined (JOB_CONTROL)
- { "CHILD_MAX", sv_childmax },
-#endif
-
-#if defined (READLINE)
-# if defined (STRICT_POSIX)
- { "COLUMNS", sv_winsize },
-# endif
- { "COMP_WORDBREAKS", sv_comp_wordbreaks },
-#endif
-
- { "FUNCNEST", sv_funcnest },
-
- { "GLOBIGNORE", sv_globignore },
-
-#if defined (HISTORY)
- { "HISTCONTROL", sv_history_control },
- { "HISTFILESIZE", sv_histsize },
- { "HISTIGNORE", sv_histignore },
- { "HISTSIZE", sv_histsize },
- { "HISTTIMEFORMAT", sv_histtimefmt },
-#endif
-
-#if defined (__CYGWIN__)
- { "HOME", sv_home },
-#endif
-
-#if defined (READLINE)
- { "HOSTFILE", sv_hostfile },
-#endif
-
- { "IFS", sv_ifs },
- { "IGNOREEOF", sv_ignoreeof },
-
- { "LANG", sv_locale },
- { "LC_ALL", sv_locale },
- { "LC_COLLATE", sv_locale },
- { "LC_CTYPE", sv_locale },
- { "LC_MESSAGES", sv_locale },
- { "LC_NUMERIC", sv_locale },
- { "LC_TIME", sv_locale },
-
-#if defined (READLINE) && defined (STRICT_POSIX)
- { "LINES", sv_winsize },
-#endif
-
- { "MAIL", sv_mail },
- { "MAILCHECK", sv_mail },
- { "MAILPATH", sv_mail },
-
- { "OPTERR", sv_opterr },
- { "OPTIND", sv_optind },
-
- { "PATH", sv_path },
- { "POSIXLY_CORRECT", sv_strict_posix },
-
-#if defined (READLINE)
- { "TERM", sv_terminal },
- { "TERMCAP", sv_terminal },
- { "TERMINFO", sv_terminal },
-#endif /* READLINE */
-
- { "TEXTDOMAIN", sv_locale },
- { "TEXTDOMAINDIR", sv_locale },
-
-#if defined (HAVE_TZSET)
- { "TZ", sv_tz },
-#endif
-
-#if defined (HISTORY) && defined (BANG_HISTORY)
- { "histchars", sv_histchars },
-#endif /* HISTORY && BANG_HISTORY */
-
- { "ignoreeof", sv_ignoreeof },
-
- { (char *)0, (sh_sv_func_t *)0 }
-};
-
-#define N_SPECIAL_VARS (sizeof (special_vars) / sizeof (special_vars[0]) - 1)
-
-static int
-sv_compare (sv1, sv2)
- struct name_and_function *sv1, *sv2;
-{
- int r;
-
- if ((r = sv1->name[0] - sv2->name[0]) == 0)
- r = strcmp (sv1->name, sv2->name);
- return r;
-}
-
-static inline int
-find_special_var (name)
- const char *name;
-{
- register int i, r;
-
- for (i = 0; special_vars[i].name; i++)
- {
- r = special_vars[i].name[0] - name[0];
- if (r == 0)
- r = strcmp (special_vars[i].name, name);
- if (r == 0)
- return i;
- else if (r > 0)
- /* Can't match any of rest of elements in sorted list. Take this out
- if it causes problems in certain environments. */
- break;
- }
- return -1;
-}
-
-/* The variable in NAME has just had its state changed. Check to see if it
- is one of the special ones where something special happens. */
-void
-stupidly_hack_special_variables (name)
- char *name;
-{
- static int sv_sorted = 0;
- int i;
-
- if (sv_sorted == 0) /* shouldn't need, but it's fairly cheap. */
- {
- qsort (special_vars, N_SPECIAL_VARS, sizeof (special_vars[0]),
- (QSFUNC *)sv_compare);
- sv_sorted = 1;
- }
-
- i = find_special_var (name);
- if (i != -1)
- (*(special_vars[i].function)) (name);
-}
-
-/* Special variables that need hooks to be run when they are unset as part
- of shell reinitialization should have their sv_ functions run here. */
-void
-reinit_special_variables ()
-{
-#if defined (READLINE)
- sv_comp_wordbreaks ("COMP_WORDBREAKS");
-#endif
- sv_globignore ("GLOBIGNORE");
- sv_opterr ("OPTERR");
-}
-
-void
-sv_ifs (name)
- char *name;
-{
- SHELL_VAR *v;
-
- v = find_variable ("IFS");
- setifs (v);
-}
-
-/* What to do just after the PATH variable has changed. */
-void
-sv_path (name)
- char *name;
-{
- /* hash -r */
- phash_flush ();
-}
-
-/* What to do just after one of the MAILxxxx variables has changed. NAME
- is the name of the variable. This is called with NAME set to one of
- MAIL, MAILCHECK, or MAILPATH. */
-void
-sv_mail (name)
- char *name;
-{
- /* If the time interval for checking the files has changed, then
- reset the mail timer. Otherwise, one of the pathname vars
- to the users mailbox has changed, so rebuild the array of
- filenames. */
- if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
- reset_mail_timer ();
- else
- {
- free_mail_files ();
- remember_mail_dates ();
- }
-}
-
-void
-sv_funcnest (name)
- char *name;
-{
- SHELL_VAR *v;
- intmax_t num;
-
- v = find_variable (name);
- if (v == 0)
- funcnest_max = 0;
- else if (legal_number (value_cell (v), &num) == 0)
- funcnest_max = 0;
- else
- funcnest_max = num;
-}
-
-/* What to do when GLOBIGNORE changes. */
-void
-sv_globignore (name)
- char *name;
-{
- if (privileged_mode == 0)
- setup_glob_ignore (name);
-}
-
-#if defined (READLINE)
-void
-sv_comp_wordbreaks (name)
- char *name;
-{
- SHELL_VAR *sv;
-
- sv = find_variable (name);
- if (sv == 0)
- reset_completer_word_break_chars ();
-}
-
-/* What to do just after one of the TERMxxx variables has changed.
- If we are an interactive shell, then try to reset the terminal
- information in readline. */
-void
-sv_terminal (name)
- char *name;
-{
- if (interactive_shell && no_line_editing == 0)
- rl_reset_terminal (get_string_value ("TERM"));
-}
-
-void
-sv_hostfile (name)
- char *name;
-{
- SHELL_VAR *v;
-
- v = find_variable (name);
- if (v == 0)
- clear_hostname_list ();
- else
- hostname_list_initialized = 0;
-}
-
-#if defined (STRICT_POSIX)
-/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values
- found in the initial environment) to override the terminal size reported by
- the kernel. */
-void
-sv_winsize (name)
- char *name;
-{
- SHELL_VAR *v;
- intmax_t xd;
- int d;
-
- if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing)
- return;
-
- v = find_variable (name);
- if (v == 0 || var_isnull (v))
- rl_reset_screen_size ();
- else
- {
- if (legal_number (value_cell (v), &xd) == 0)
- return;
- winsize_assignment = 1;
- d = xd; /* truncate */
- if (name[0] == 'L') /* LINES */
- rl_set_screen_size (d, -1);
- else /* COLUMNS */
- rl_set_screen_size (-1, d);
- winsize_assignment = 0;
- }
-}
-#endif /* STRICT_POSIX */
-#endif /* READLINE */
-
-/* Update the value of HOME in the export environment so tilde expansion will
- work on cygwin. */
-#if defined (__CYGWIN__)
-sv_home (name)
- char *name;
-{
- array_needs_making = 1;
- maybe_make_export_env ();
-}
-#endif
-
-#if defined (HISTORY)
-/* What to do after the HISTSIZE or HISTFILESIZE variables change.
- If there is a value for this HISTSIZE (and it is numeric), then stifle
- the history. Otherwise, if there is NO value for this variable,
- unstifle the history. If name is HISTFILESIZE, and its value is
- numeric, truncate the history file to hold no more than that many
- lines. */
-void
-sv_histsize (name)
- char *name;
-{
- char *temp;
- intmax_t num;
- int hmax;
-
- temp = get_string_value (name);
-
- if (temp && *temp)
- {
- if (legal_number (temp, &num))
- {
- hmax = num;
- if (hmax < 0 && name[4] == 'S')
- unstifle_history (); /* unstifle history if HISTSIZE < 0 */
- else if (name[4] == 'S')
- {
- stifle_history (hmax);
- hmax = where_history ();
- if (history_lines_this_session > hmax)
- history_lines_this_session = hmax;
- }
- else if (hmax >= 0) /* truncate HISTFILE if HISTFILESIZE >= 0 */
- {
- history_truncate_file (get_string_value ("HISTFILE"), hmax);
- if (hmax <= history_lines_in_file)
- history_lines_in_file = hmax;
- }
- }
- }
- else if (name[4] == 'S')
- unstifle_history ();
-}
-
-/* What to do after the HISTIGNORE variable changes. */
-void
-sv_histignore (name)
- char *name;
-{
- setup_history_ignore (name);
-}
-
-/* What to do after the HISTCONTROL variable changes. */
-void
-sv_history_control (name)
- char *name;
-{
- char *temp;
- char *val;
- int tptr;
-
- history_control = 0;
- temp = get_string_value (name);
-
- if (temp == 0 || *temp == 0)
- return;
-
- tptr = 0;
- while (val = extract_colon_unit (temp, &tptr))
- {
- if (STREQ (val, "ignorespace"))
- history_control |= HC_IGNSPACE;
- else if (STREQ (val, "ignoredups"))
- history_control |= HC_IGNDUPS;
- else if (STREQ (val, "ignoreboth"))
- history_control |= HC_IGNBOTH;
- else if (STREQ (val, "erasedups"))
- history_control |= HC_ERASEDUPS;
-
- free (val);
- }
-}
-
-#if defined (BANG_HISTORY)
-/* Setting/unsetting of the history expansion character. */
-void
-sv_histchars (name)
- char *name;
-{
- char *temp;
-
- temp = get_string_value (name);
- if (temp)
- {
- history_expansion_char = *temp;
- if (temp[0] && temp[1])
- {
- history_subst_char = temp[1];
- if (temp[2])
- history_comment_char = temp[2];
- }
- }
- else
- {
- history_expansion_char = '!';
- history_subst_char = '^';
- history_comment_char = '#';
- }
-}
-#endif /* BANG_HISTORY */
-
-void
-sv_histtimefmt (name)
- char *name;
-{
- SHELL_VAR *v;
-
- if (v = find_variable (name))
- {
- if (history_comment_char == 0)
- history_comment_char = '#';
- }
- history_write_timestamps = (v != 0);
-}
-#endif /* HISTORY */
-
-#if defined (HAVE_TZSET)
-void
-sv_tz (name)
- char *name;
-{
- if (chkexport (name))
- tzset ();
-}
-#endif
-
-/* If the variable exists, then the value of it can be the number
- of times we actually ignore the EOF. The default is small,
- (smaller than csh, anyway). */
-void
-sv_ignoreeof (name)
- char *name;
-{
- SHELL_VAR *tmp_var;
- char *temp;
-
- eof_encountered = 0;
-
- tmp_var = find_variable (name);
- ignoreeof = tmp_var != 0;
- temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
- if (temp)
- eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
- set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
-}
-
-void
-sv_optind (name)
- char *name;
-{
- char *tt;
- int s;
-
- tt = get_string_value ("OPTIND");
- if (tt && *tt)
- {
- s = atoi (tt);
-
- /* According to POSIX, setting OPTIND=1 resets the internal state
- of getopt (). */
- if (s < 0 || s == 1)
- s = 0;
- }
- else
- s = 0;
- getopts_reset (s);
-}
-
-void
-sv_opterr (name)
- char *name;
-{
- char *tt;
-
- tt = get_string_value ("OPTERR");
- sh_opterr = (tt && *tt) ? atoi (tt) : 1;
-}
-
-void
-sv_strict_posix (name)
- char *name;
-{
- SET_INT_VAR (name, posixly_correct);
- posix_initialize (posixly_correct);
-#if defined (READLINE)
- if (interactive_shell)
- posix_readline_initialize (posixly_correct);
-#endif /* READLINE */
- set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
-}
-
-void
-sv_locale (name)
- char *name;
-{
- char *v;
- int r;
-
- v = get_string_value (name);
- if (name[0] == 'L' && name[1] == 'A') /* LANG */
- r = set_lang (name, v);
- else
- r = set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
-
-#if 1
- if (r == 0 && posixly_correct)
- last_command_exit_value = 1;
-#endif
-}
-
-#if defined (ARRAY_VARS)
-void
-set_pipestatus_array (ps, nproc)
- int *ps;
- int nproc;
-{
- SHELL_VAR *v;
- ARRAY *a;
- ARRAY_ELEMENT *ae;
- register int i;
- char *t, tbuf[INT_STRLEN_BOUND(int) + 1];
-
- v = find_variable ("PIPESTATUS");
- if (v == 0)
- v = make_new_array_variable ("PIPESTATUS");
- if (array_p (v) == 0)
- return; /* Do nothing if not an array variable. */
- a = array_cell (v);
-
- if (a == 0 || array_num_elements (a) == 0)
- {
- for (i = 0; i < nproc; i++) /* was ps[i] != -1, not i < nproc */
- {
- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- array_insert (a, i, t);
- }
- return;
- }
-
- /* Fast case */
- if (array_num_elements (a) == nproc && nproc == 1)
- {
- ae = element_forw (a->head);
- free (element_value (ae));
- ae->value = itos (ps[0]);
- }
- else if (array_num_elements (a) <= nproc)
- {
- /* modify in array_num_elements members in place, then add */
- ae = a->head;
- for (i = 0; i < array_num_elements (a); i++)
- {
- ae = element_forw (ae);
- free (element_value (ae));
- ae->value = itos (ps[i]);
- }
- /* add any more */
- for ( ; i < nproc; i++)
- {
- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- array_insert (a, i, t);
- }
- }
- else
- {
- /* deleting elements. it's faster to rebuild the array. */
- array_flush (a);
- for (i = 0; ps[i] != -1; i++)
- {
- t = inttostr (ps[i], tbuf, sizeof (tbuf));
- array_insert (a, i, t);
- }
- }
-}
-
-ARRAY *
-save_pipestatus_array ()
-{
- SHELL_VAR *v;
- ARRAY *a, *a2;
-
- v = find_variable ("PIPESTATUS");
- if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- return ((ARRAY *)NULL);
-
- a = array_cell (v);
- a2 = array_copy (array_cell (v));
-
- return a2;
-}
-
-void
-restore_pipestatus_array (a)
- ARRAY *a;
-{
- SHELL_VAR *v;
- ARRAY *a2;
-
- v = find_variable ("PIPESTATUS");
- /* XXX - should we still assign even if existing value is NULL? */
- if (v == 0 || array_p (v) == 0 || array_cell (v) == 0)
- return;
-
- a2 = array_cell (v);
- var_setarray (v, a);
-
- array_dispose (a2);
-}
-#endif
-
-void
-set_pipestatus_from_exit (s)
- int s;
-{
-#if defined (ARRAY_VARS)
- static int v[2] = { 0, -1 };
-
- v[0] = s;
- set_pipestatus_array (v, 1);
-#endif
-}
-
-void
-sv_xtracefd (name)
- char *name;
-{
- SHELL_VAR *v;
- char *t, *e;
- int fd;
- FILE *fp;
-
- v = find_variable (name);
- if (v == 0)
- {
- xtrace_reset ();
- return;
- }
-
- t = value_cell (v);
- if (t == 0 || *t == 0)
- xtrace_reset ();
- else
- {
- fd = (int)strtol (t, &e, 10);
- if (e != t && *e == '\0' && sh_validfd (fd))
- {
- fp = fdopen (fd, "w");
- if (fp == 0)
- internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
- else
- xtrace_set (fd, fp);
- }
- else
- internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
- }
-}
-
-#define MIN_COMPAT_LEVEL 31
-
-void
-sv_shcompat (name)
- char *name;
-{
- SHELL_VAR *v;
- char *val;
- int tens, ones, compatval;
-
- v = find_variable (name);
- if (v == 0)
- {
- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- set_compatibility_opts ();
- return;
- }
- val = value_cell (v);
- if (val == 0 || *val == '\0')
- {
- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- set_compatibility_opts ();
- return;
- }
- /* Handle decimal-like compatibility version specifications: 4.2 */
- if (isdigit (val[0]) && val[1] == '.' && isdigit (val[2]) && val[3] == 0)
- {
- tens = val[0] - '0';
- ones = val[2] - '0';
- compatval = tens*10 + ones;
- }
- /* Handle integer-like compatibility version specifications: 42 */
- else if (isdigit (val[0]) && isdigit (val[1]) && val[2] == 0)
- {
- tens = val[0] - '0';
- ones = val[1] - '0';
- compatval = tens*10 + ones;
- }
- else
- {
-compat_error:
- internal_error (_("%s: %s: compatibility value out of range"), name, val);
- shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
- set_compatibility_opts ();
- return;
- }
-
- if (compatval < MIN_COMPAT_LEVEL || compatval > DEFAULT_COMPAT_LEVEL)
- goto compat_error;
-
- shell_compatibility_level = compatval;
- set_compatibility_opts ();
-}
-
-#if defined (JOB_CONTROL)
-void
-sv_childmax (name)
- char *name;
-{
- char *tt;
- int s;
-
- tt = get_string_value (name);
- s = (tt && *tt) ? atoi (tt) : 0;
- set_maxchild (s);
-}
-#endif