diff options
author | Chet Ramey <chet.ramey@case.edu> | 2011-12-03 12:55:32 -0500 |
---|---|---|
committer | Chet Ramey <chet.ramey@case.edu> | 2011-12-03 12:55:32 -0500 |
commit | 762a763b05cd0a064c93530a4d8e18cbb40dcde3 (patch) | |
tree | cc6d374963efdea50ac96fbf89487460dda78579 | |
parent | 5ba8ff6eaac36dcbeea0c8af57632ec6432386a4 (diff) | |
download | bash-762a763b05cd0a064c93530a4d8e18cbb40dcde3.tar.gz |
commit bash-20040311 snapshot
42 files changed, 22212 insertions, 125 deletions
@@ -1,3 +1,23 @@ +This document details the changes between this version, bash-3.0-rc1, +and the previous version, bash-3.0-beta1. + +1. Changes to Bash + +a. Fixed a bug that caused incorrect behavior when referecing element 0 of + an array using $array, element 0 was unset, and `set -u' was enabled. + +b. System-specific changes for: SCO Unix 3.2, Tandem. + +c. Fixed a bug that caused inappropriate word splitting when a variable was + expanded within a double-quoted string that also included $@. + +d. Fixed a bug that caused `pwd' to not display anything in physical mode + when the file system had changed underneath the shell. + +e. Fixed a bug in the pre- and post- increment and decrement parsing in the + expression evaluator that caused errors when the operands and corresponding + operators were separated by whitespace. +------------------------------------------------------------------------------ This document details the changes between this version, bash-3.0-beta1, and the previous version, bash-3.0-alpha. diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 838baed0..8c53cee1 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -9234,3 +9234,71 @@ subst.c of just the escape characters if the expansion appears between double quotes or in a here-document (for simple variable expansions or expansions of positional parameters) + + 3/8 + --- +subst.c + - analogous changes to parameter_brace_expand_word to fix the same + quoting problem as on 3/4; fix callers to understand that the + value returned might be quoted now and should be dequoted if + necessary + - add a `quoted' argument to get_var_and_type, change callers + - change today's fix and fix from 3/4 to not call quote_string if the + value is "" (because quote_string turns that into CTLNUL\0) + + 3/9 + --- +builtins/cd.def + - resetpwd() now takes a `caller' argument so it can be used by pwd + as well as cd + - change pwd_builtin to call resetpwd() if sh_physpath() fails to + return a valid pathname + + 3/14 + ---- +expr.c + - reworked exp0 and readtok() to make post-increment and post-decrement + into real tokens, which may be separated from their accompanying + variables by whitesapce + - made analogous changes to readtok() to make pre-increment and + pre-decrement work when separated from their accompanying identifier + by whitespace + + 3/18 + ---- +lib/readline/misc.c + - in rl_maybe_unsave_line, don't force rl_replace_line to clear + the undo_list, since it might point directly at an undo list + from a history entry (to which we have no handle) + + 3/19 + ---- +lib/readline/display.c + - rl_save_prompt and rl_restore_prompt now save and restore the value + of prompt_physical_chars + - set prompt_physical_chars in rl_redisplay when expand_prompt has + not been called (e.g., when rl_display_prompt is set and is not + equal to rl_prompt, like when searching) + +lib/readline/histexpand.c + - don't call add_history in history_expand if the `:p' modifier is + supplied; leave that to the calling application. This means that + `history -p', for example, will not add anything to the history + list (as documented), nor will history expansions invoked by + emacs-mode M-C-e line editing + +config-bot.h + - check whether HAVE_DECL_SYS_SIGLIST is defined to 1 rather than just + defined, to work around newer versions of autoconf defining it to 0 + +config.h.in + - change default status of HAVE_MALLOC to #undef instead of #define + +bashhist.c + - extern declarations for rl_done and rl_dispatching + - don't call re_edit from pre_process_line unless rl_dispatcing is zero, + so we don't call it from something like shell-expand-line + - change pre_process_line to add an expanded history specification + that returned `print only' to the history list, since history_expand + no longer does it (and, when using readline, do it only when + rl_dispatching is zero) diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index a03188d6..a35dff82 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -9218,8 +9218,80 @@ expr.c - make the exponentiation operator (**) associative, so things like 2**3**4 work right (change `if' to `while') - 3/2 + 3/3 --- lib/sh/strftime.c - SCO Unix 3.2, like Solaris, requires that the system's `timezone' variable be declared as long + +lib/readline/{bind,histfile,input,parens}.c + - changes for Tandem (including `floss.h' (?)) + + 3/4 + --- +subst.c + - change param_expand to quote the entire expanded string instead + of just the escape characters if the expansion appears between + double quotes or in a here-document (for simple variable expansions + or expansions of positional parameters) + + 3/8 + --- +subst.c + - analogous changes to parameter_brace_expand_word to fix the same + quoting problem as on 3/4; fix callers to understand that the + value returned might be quoted now and should be dequoted if + necessary + - add a `quoted' argument to get_var_and_type, change callers + - change today's fix and fix from 3/4 to not call quote_string if the + value is "" (because quote_string turns that into CTLNUL\0) + + 3/9 + --- +builtins/cd.def + - resetpwd() now takes a `caller' argument so it can be used by pwd + as well as cd + - change pwd_builtin to call resetpwd() if sh_physpath() fails to + return a valid pathname + + 3/14 + ---- +expr.c + - reworked exp0 and readtok() to make post-increment and post-decrement + into real tokens, which may be separated from their accompanying + variables by whitesapce + - made analogous changes to readtok() to make pre-increment and + pre-decrement work when separated from their accompanying identifier + by whitespace + + 3/19 + ---- +lib/readline/display.c + - rl_save_prompt and rl_restore_prompt now save and restore the value + of prompt_physical_chars + - set prompt_physical_chars in rl_redisplay when expand_prompt has + not been called (e.g., when rl_display_prompt is set and is not + equal to rl_prompt, like when searching) + +lib/readline/histexpand.c + - don't call add_history in history_expand if the `:p' modifier is + supplied; leave that to the calling application. This means that + `history -p', for example, will not add anything to the history + list (as documented), nor will history expansions invoked by + emacs-mode M-C-e line editing + +config-bot.h + - check whether HAVE_DECL_SYS_SIGLIST is defined to 1 rather than just + defined, to work around newer versions of autoconf defining it to 0 + +config.h.in + - change default status of HAVE_MALLOC to #undef instead of #define + +bashhist.c + - extern declarations for rl_done and rl_dispatching + - don't call re_edit from pre_process_line unless rl_dispatcing is zero, + so we don't call it from something like shell-expand-line + - change pre_process_line to add an expanded history specification + that returned `print only' to the history list, since history_expand + no longer does it (and, when using readline, do it only when + rl_dispatching is zero) diff --git a/CWRU/changelog b/CWRU/changelog index d2d81b30..e52db56a 120000..100644 --- a/CWRU/changelog +++ b/CWRU/changelog @@ -1 +1,9285 @@ -CWRU.chlog
\ No newline at end of file + 4/9/2001 + -------- +[bash-2.05 released] + + 4/10 + ---- +redir.c + - check return value of fclose() in write_here_document() for error + returns; don't just rely on fwrite() failing + +support/bashbug.sh + - set TMPDIR to /tmp if it's null or unset + - use $TMPDIR in the TEMP tempfile name template + - fixed the call to `mktemp', if it exists, to make it more portable + +jobs.c + - if WCONTINUED is not defined, define it to 0 and add a define for + WIFCONTINUED(wstatus) which expands to 0 + - add WCONTINUED to the flags passed to waitpid(2) in waitchld() + - don't increment children_exited if waitpid's status is WIFCONTINUED, + since we don't want to call a SIGCHLD trap handler in this case + - in waitchld(), we set child->running to 1 if WIFCONTINUED(status) + is non-zero + - make sure pretty_print_job doesn't check for the core dump bit if + the process has been continued; it's only valid if the job is dead + - in set_job_status_and_cleanup, set the job to JRUNNING if job_state + is non-zero and the job was previously marked as JSTOPPED + +configure.in + - add -DBROKEN_DIRENT_D_INO to interix LOCAL_CFLAGS + +lib/glob/glob.c + - if BROKEN_DIRENT_D_INO is defined, define REAL_DIR_ENTRY to 1 + +jobs.c + - in kill_pid, we only need to block and unblock SIGCHLD if the + `group' argument is non-zero, since otherwise we just call `kill' + on the pid argument + +version.c + - update copyright date to 2001 + +bashline.c + - prog_complete_return needs to take a `const char *' as its first + argument + - history_completion_generator needs to take a `const char *' as + its first argument, and `text' needs to be a `const char *' + + 4/11 + ---- +redir.c + - fixed a weird typo in redir_special_open, case RF_DEVFD, added + call to all_digits before call to legal_number + - fixed do_redirection_internal to call legal_number instead of atol(3) + when translating r_duplicating_{in,out}put_word, so it handles + overflow better + - produce an error message in redirection_error for out-of-range + file descriptors + - change allocation strategy in redirection_error so we don't have to + malloc scratch memory if redirection_expand() fails + +jobs.h + - added defines for `running' member of a struct process + +general.c + - fix legal_number to return 0 when strtol(3) reports overflow or + underflow + +parse.y + - changed read_token_word to call legal_number instead of atoi(3) + +input.c + - return -1/EBADF from close_buffered_fd if fd is < 0 + +command.h + - fixed bogus comment about IS_DESCRIPTOR in description of the + REDIRECTEE struct + +print_cmd.c + - change cprintf's 'd' modifier code to display negative numbers as + an out-of-range value. We can do this only because the only use + of %d is to output file descriptor numbers in redirections + +support/mksignames.c + - need to include config.h to get a possible value for + UNUSABLE_RT_SIGNALS + + 4/16 + ---- +lib/readline/doc/rluser.texinfo + - corrected a small error in one description of M-DEL + + 4/17 + ---- +stringlib.c + - need to initialize `ind' before calls to RESIZE_MALLOCED_BUFFER + in strcreplace() + +support/bashversion.c + - new file, prints bash version information + +Makefile.in + - rules for building bashversion and linking it to version.o + + 4/24 + ---- +conftypes.h + - new file with HOSTTYPE, OSTYPE, MACHTYPE, etc. defines from + variables.h + +variables.h, version.c + - include conftypes.h + +patchlevel.h + - new file, contains define for PATCHLEVEL. Doing away with the old + scheme of having the information in configure.in + +version.c + - include patchlevel.h + +Makefile.in + - run bashversion -p to find patch level rather than have configure + substitute in a value + - pass -S ${top_srcdir} to support/mkversion.sh + +support/mkversion.sh + - don't put PATCHLEVEL define into version.h, but accept and ignore + a -p option + - take a new -S srcdir option + - find the patch level by parsing it out of patchlevel.h + +configure.in + - hard-code BASHVERS assignment instead of reading it from a file + - remove BASHPATCH; don't substitute it + +_distribution,_patchlevel + - removed + + 4/26 + ---- +shell.c + - call init_noninteractive() in open_shell_script if forced_interactive + is non-zero (the shell was started with -i) and fd_is_tty is 0 + (the script file is a real file, not something like /dev/stdin), + since it wasn't done earlier + +builtins/printf.def + - change for POSIX.2 compliance when conversion errors are encountered + when processing %d, %u, and floating point conversion operators + (print a warning message, return the value accumulated at the time + of the error -- which is always 0 -- and exit with a non-zero status) + +command.h + - added CMD_COMMAND_BUILTIN for use by the `command' builtin and the + code in execute_cmd.c + +builtins/command.def + - add CMD_COMMAND_BUILTIN to the created command's flags + + 5/1 + --- +configure.in + - add call to AC_C_CONST to test `const' compiler behavior + - add call to AC_C_INLINE to test `inline' compiler behavior + - add call to AC_C_STRINGIZE to test cpp #x stringizing operator + +config.h.in + - add `#undef const' for configure to substitute + - add `#undef inline' for configure to substitute + - add `#undef HAVE_STRINGIZE' for configure to substitute + +include/stdc.h + - remove code that defines or undefines `const' and `inline' + - change the __STRING macro to be defined depending on the value + of HAVE_STRINGIZE + +lib/malloc/malloc.c + - change the __STRING macro to be defined depending on the value + of HAVE_STRINGIZE + +lib/readline/{readline,rlprivate}.h + - moved rl_get_termcap to readline.h, making it a public function + +lib/readline/readline.h + - new #define, RL_READLINE_VERSION, hex-encoded library version + number, currently set to 0x0402 + - new public int variable, rl_readline_version + +lib/readline/readline.c + - #define RL_READLINE_VERSION if it is not already defined (which it + should be in readline.h) + - initialize rl_readline_version to RL_READLINE_VERSION + +lib/readline/doc/rltech.texinfo + - documented rl_get_termcap + - documented rl_readline_version + +jobs.c + - job_exit_status should return an int, not a WAIT (undetected + before because on most POSIX-like systems a WAIT is really an int) + +builtins/evalfile.c + - added FEVAL_REGFILE (file must be a regular file) to accepted + _evalfile flags + - fc_execute_file() adds FEVAL_REGFILE to _evalfile flags. This + means that startup files and files read with `.' no longer need + to be regular files + + 5/2 + --- + +lib/termcap/Makefile.in + - fix target for installed termcap library (normally unused) + +lib/tilde/Makefile.in + - fix install target to install in $(libdir) (normally unused) + +Makefile.in + - don't make $(man3dir) since there's nothing installed there + +Makefile.in,doc/Makefile.in + - change `man1ext' to `.1', `man3ext' to `.3' + - change appropriate install targets to use new values of man[13]ext + - use `test ...' instead of `[...]' + - add support for DESTDIR root installation prefix, for package + building (installdirs, install, install-strip, uninstall targets) + +builtins/common.c + - new function int get_exitstat(WORD_LIST *list) returns an eight-bit + exit status value for use in return, exit, logout builtins + +builtins/common.h + - extern declaration for get_exitstat() + +builtins/{exit,return}.def + - call get_exitstat where appropriate + +builtins/printf.def + - add support for "'" flag character as posix 1003.2-200x d6 says + - fix core dump when user-supplied field width or precision is 0 + - fix to printstr() to handle zero-length precision with `%b' format + specifier (printf '%.0b-%.0s\n' foo bar) + - fix to printstr() to treat a negative field width as a positive + field width with left-justification + - fix to mklong to avoid static buffers, which can always be overrun + by someone sufficiently motivated + +bashline.c + - change var in add_host_name to type `size_t' for passing to xrealloc + + 5/3 + --- +execute_cmd.c + - change restore_signal_mask to accept a sigset_t *, since a sigset_t + may not fit into a pointer, change call + +unwind_prot.c + - use a union UWP in restore_variable when restoring a variable whose + size is the same as sizeof(int), the reverse of the method used to + store it in unwind_protect_int + +builtins/printf.def + - use a #define LENMODS containing the length modifiers instead of + testing against each possible modifier character, save any mod + character found + - add support for ISO C99 length specifiers `j', `t', and `z' + - if `L' modifier is supplied with a floating point conversion char, + pass a `long double' to printf if HAVE_LONG_DOUBLE is defined + +configure.in,config.h.in + - call AC_C_LONG_DOUBLE to check for `long double'; define + HAVE_LONG_DOUBLE if supported + +bashline.c + - fix an inadvertantly-unclosed comment in attempt_shell_completion + - make set_saved_history return a value + - make dynamic_complete_history return a useful value + +{make_cmd,execute_cmd,shell,subst,trap,variables,input,unwind_prot,test, +pcomplete}.c + - removed some declared-but-unused variables + +builtins/{cd,enable,fc,set,setattr,type,umask,printf,complete}.def + - removed some declared-but-unused variables + +lib/sh/{zread,netopen}.c + - removed some declared-but-unused variables + +execute_cmd.c + - in execute_arith_command, use a long variable to hold the result + of evalexp(), since that's what it returns + +builtins/evalstring.c + - make cat_file return -1 on a read or write error + +lib/sh/stringlib.c + - make merge_stringlists() return the right value + + 5/7 + --- +pcomplete.c + - remove typo that caused empty declaration (;;) + +parse.y + - fix yyerror() to accept a single string argument; fix callers + +trap.c + - cast pointer to long instead of int when printing message with + internal_warning() in run_pending_traps() + +subst.c + - fix process_substitute to handle stdin being closed + +test.c + - change `while' to `if' in and() and or(), since the loop isn't + actually performed -- there's an unconditional `return' in the + loop body + - check for integer overflow of arguments to `-t' + +lib/sh/netopen.c + - change _getserv() to reject negative port/service numbers + +expr.c + - fix strlong() to not convert the base specification from long to + int before checking for overflow, since truncation on machines + where sizeof(int) != sizeof(long) may mask errors + +builtins/{jobs,kill,wait}.def + - use legal_number instead of atoi when converting strings to pid_t; + check for numeric overflow + +input.c + - fix for cygwin in b_fill_buffer -- off-by-one error when checking + buffer for \r\n termination + +general.h + - new #define INT_STRLEN_BOUND(t), computes max length of string + representing integer value of type T, possibly including a sign + character + - include <limits.h> if it's present + +{execute_cmd,findcmd,test}.c + - don't include <limits.h>, since general.h does it now + +{execute_cmd,lib/sh/itos,pcomplete,print_cmd,subst,variables}.c + - use INT_STRLEN_BOUND instead of static array sizes when converting + various strings to integer values + +shell.h + - struct fd_bitmap now uses an `int' size, since it's bounded by + the number of file descriptors, which must fit into an `int' + +execute_cmd.c + - FD_BITMAP_DEFAULT_SIZE is now 32, not 32L + - new_fd_bitmap takes an `int' size parameter, not a `long' + +execute_cmd.h + - change prototype for new_fd_bitmap() + +test.c + - fix test_stat to check for overflow when parsing the integer file + descriptor number; return ENOENT instead of EBADF for files that + are not open + +hashlib.c + - don't discard the upper 32 bits of the random value, if present + +lib/readline/shell.c + - use the same INT_STRLEN_BOUND mechanism to decide how much space to + allocated in sh_set_lines_and_columns + + 5/8 + --- +aclocal.m4 + - add check for libtinfo (termcap-specific portion of ncurses-5.2) to + BASH_CHECK_LIB_TERMCAP + - new macro, RL_LIB_READLINE_VERSION, checks version of installed + readline library and (optionally) writes version #defines to + config.h. Bash doesn't use the version defines + +configure.in + - call RL_LIB_READLINE_VERSION instead of support/rlvers.sh + +execute_cmd.c + - fix execute_shell_script and the WHITECHAR and STRINGCHAR macros + to check array bounds before indexing into the sample string + +unwind_prot.[ch] + - import new versions submitted by Paul Eggert <eggert@twinsun.com> + with a couple of changes for backwards compatibility, so the rest + of the source doesn't need to be changed yet + +jobs.c + - use unwind_protect_var on last_made_pid in run_sigchld_trap + +builtins/bind.def + - use unwind_protect_var on rl_outstream + +general.c + - rework print_rlimtype to use INT_STRLEN_BOUND and handle the + most negative number correctly + +expr.c + - `tokval' should have been a `long', since all arithmetic is done + as longs + +builtins/history.def + - consolidate tests for valid history position in one block to + avoid duplicate code and strings + +builtins/ulimit.def + - fix check for overflow when setting limit to work when int is 32 + bits and RLIMTYPE is 64 + +lib/sh/tmpfile.c + - don't truncate the result of time(3) to int; just use time_t, + since it's being assigned to an `unsigned long' + +mailcheck.c + - use legal_number instead of atoi in time_to_check_mail() to catch + more numeric errors; consolidate error checking in one block + - last_time_mail_checked should be a time_t + + 5/9 + --- +builtins/set.def + - recognize `set [-+]o nolog' if HISTORY is defined + +bashline.c + - new variable `dont_save_function_defs', set by `set -o nolog'; + currently ignored + +command.h + - the `dest' member of a REDIRECTEE is now an `int' + +parse.y,redir.c + - changed uses of `redir.test' (where redir is a REDIRECTEE) since + it's now an int + +lib/readline/rlstdc.h + - don't mess around with `const', rely on configure to supply a + proper definition if the compiler doesn't support it + +lib/tilde/tilde.h + - include <config.h> if HAVE_CONFIG_H is defined + - don't mess around with `const', rely on configure + +builtins/shopt.def + - new read-only `shopt' option, login_shell, non-zero if shell is a + login shell (as decided by shell.c) + - new function set_login_shell(), sets shopt private value of + login_shell + +builtins/common.h + - new extern declaration for set_login_shell + +shell.c + - call set_login_shell after setting value of login_shell (in + main() and set_shell_name()) + +parse.y + - added new `\A' prompt string escape sequence: time in 24-hour + HH:MM format + +configure.in, config.h.in + - check for <grp.h>, define HAVE_GRP_H if found + +builtins/complete.def + - add new `-A group/-g' option to complete group names + +pcomplete.h + - new define for CA_GROUP, used with group name completion + +pcomplete.c + - add code to support CA_GROUP group name completion + +bashline.c + - new function, bash_groupname_completion_function(), supports + programmable completion of group names + +bashline.h + - extern declaration for bash_groupname_completion_function + +lib/readline/bind.c + - new inputrc variable, `match-hidden-files', controls completion + matching files beginning with a `.' (on Unix) + +lib/readline/complete.c + - new variable, _rl_match_hidden_files, mirrors `match-hidden-files' + inputrc variable + +lib/readline/rlprivate.h + - extern declaration for _rl_match_hidden_files + +builtins/hash.def + - new `-t' option to list hash values for each filename argument + +builtins/read.def + - alarm(3) takes an `unsigned int' argument, not int + - check for arithmetic overflow with -t and -n options + +input.c + - check for read error before doing \r\n translation on cygwin in + b_fill_buffer + - reset bp->b_used to 0 instead of leaving it at -1 on read error + in b_fill_buffer + +builtins/shopt.def + - new functions, shopt_setopt(name, mode) and + shopt_listopt(name, mode) to give the rest of the shell an easy + interface + +builtins/common.h + - extern declarations for shopt_setopt and shopt_listopt + +shell.c + - new invocation options -O and +O, to list or set/unset shopt + options like +o/-o sets and unsets `set -o' options + +doc/{bash.1,bashref.texi} + - document `set -o nolog' + - document `login_shell' shopt option + - document new `\A' prompt string escape sequence + - document new `-t' option to `hash' + - document new `[+-]O' invocation option + +doc/bashref.texi + - add text to `Invoking Bash' section defining a login shell; text + taken from man page + +doc/bash.1, lib/readline/doc/rluser.texinfo + - documented new complete/compgen `-A group/-g' option + +lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 + - documented new `match-hidden-files' inputrc variable + + 5/10 + ---- +configure.in + - fix AC_CHECK_PROG(ar, ...) + - add AC_CHECK_TYPE for ssize_t + +config.h.in + - new #undef for ssize_t + +lib/sh/zread.c + - int -> ssize_t fixes to mirror modern declarations of read and write + - the `off' variable in zsyncfd should be an off_t since it computes + a file offset + - the local buffer `lbuf' is now char, since it's not nice to pass + unsigned char * to read(2), and the values from it are assigned to + a char anyway + - lind and lused are now size_t, since they index into a buffer + - set lused to 0 on read error + +lib/sh/zwrite.c + - change second argument to type `char *', since ISO C says you have + to pass a `char *' to `write' + +externs.h + - fix extern declarations of zread, zread1, zreadc, and zwrite + - prototype extern declaration of qsort_string_compare + - add extern declaration for history_delimiting_chars() from parse.y + +input.h + - b_used and b_inputp members ofr struct BSTREAM are now size_t + +builtins/evalstring.c + - the number of chars read with zread in cat_file should be assigned + to a variable of type ssize_t + +input.c + - the number of chars read with zread in b_fill_buffer should be + assigned to a variable of type ssize_t + - `localbuf' is now type char[], since POSIX says you shouldn't pass + unsigned char * to read(2) + - in getc_with_restart(), use a variable of type unsigned char to + get a value from the local buffer and return it + - in ungetc_with_restart, explicitly return the character arg passed + to avoid relying on localbuf being unsigned char + +subst.c + - the number of chars read with zread in read_comsub should be + assigned to a variable of type ssize_t + +mksyntax.c + - instead of casting to unsigned char * in addcstr, use a variable + of type unsigned char and let the compiler do the work + +parse.y + - instead of casting to unsigned char * in yy_readline_get, use a + variable of type unsigned char and let the compiler do the work + - ditto for yy_string_get and shell_getc (cast to unsigned char) + +subst.c + - instead of casting to unsigned char when assigning to ifscmap in + expand_word_internal, use a variable of type unsigned char and + let the compiler do the work + +lib/sh/strtrans.c + - instead of casting to unsigned char in ansic_quote, use a variable + of type unsigned char and let the compiler do the work + +builtins/evalstring.c + - remove extern declarations for zwrite and run_trap_cleanup; they're + in externs.h + - prototype cat_file forward declaration + +Makefile.in + - remove -I$(includedir) from INCLUDES and SUBDIR_INCLUDES + +aclocal.m4 + - change RL_LIB_READLINE_VERSION to set RL_PREFIX, RL_LIBDIR, + and RL_INCLUDEDIR to what it used to test the installed readline + library version for use by the caller + - change RL_LIB_READLINE_VERSION to not compute ac_cv_rl_prefix if + the caller has already assigned it a value + - rename _rl_prefix -> ac_cv_rl_prefix, _rl_libdir -> ac_cv_rl_libdir, + _rl_includedir -> ac_cv_rl_includedir + +configure.in + - change testing of whether to use the value of + $opt_with_installed_readline to be != no, to allow the user to + specify a prefix where the installed readline library may be found + - if --with-installed-readline=PREFIX is supplied, set ac_cv_rl_prefix + to PREFIX before calling RL_LIB_READLINE_VERSION + - if --with-installed-readline[=PREFIX] is supplied, don't set + RL_LIBDIR and RL_INCLUDEDIR; let RL_LIB_READLINE_VERSION take care + of it, set RL_INCLUDE=-I${RL_INCLUDEDIR} + - if --with-installed-readline[=PREFIX] is supplied, and we're + linking with the history library, assign $RL_LIBDIR to HIST_LIBDIR + so we use the same version of the installed readline and history + libraries + +Makefile.in, builtins/Makefile.in + - have configure substitute RL_INCLUDEDIR, set RL_INCLUDEDIR variable + +doc/bashref.texi + - updated description of --with-installed-readline configure option + +general.c + - moved QSFUNC typedef here from builtins/common.c + +{alias,bashline,variables,lib/sh/stringvec}.c + - cast fourth argument to qsort to (QSFUNC *) + +alias.c + - prototype forward declaration of qsort_alias_compare + +bashhist.c + - include <glob/glob.h> for extern declaration of glob_pattern_p + - remove extern declaration of history_delimiting_chars; it's now + in externs.h + - prototype forward declarations of histignore_item_func, + maybe_add_history, and bash_add_history + +bracecomp.c + - remove extern declaration for sh_backslash_quote; it's in externs.h + +braces.c + - remove extern declaration for extract_command_subst; it's in subst.h + - prototype forward declarations for expand_amble, array_concat, and + brace_gobbler + +error.c + - prototype extern declaration of give_terminal_to, fix bad call + +{execute_cmd,expr,findcmd,jobs,mailcheck,nojobs,pcomplete,print_cmd,redir, +shell}.c + - prototype all static forward function declarations + +pcomplete.c + - changed some function parameters to `const char *' to avoid discarding + const qualifier + +make_cmd.c + - make_bare_word, make_word_flags, and make_word now take a + `const char *' string argument + +make_cmd.h + - changed extern declarations for make_bare_word and make_word + +print_cmd.c + - cprintf now takes a `const char *' as its first argument, like + xprintf and printf + - the conditional define for xprintf should have been HAVE_VPRINTF, + not HAVE_VFPRINTF + +shell.c + - in isnetconn(), the return value of sizeof() is size_t + +aclocal.m4 + - add inclusion of stddef.h if STDC_HEADERS is defined to 1 in + BASH_CHECK_TYPE + +configure.in + - add a call to BASH_CHECK_TYPE for socklen_t (type of third argument + to getpeername(2)) + + 5/11 + ---- +lib/readline/bind.c + - make `useq' a char array to pass to rl_macro_bind in + rl_parse_and_bind + +lib/readline/{{bind,isearch}.c,rlprivate.h} + - _rl_isearch_terminators is now a char *, not unsigned char * + +{subst,variables,lib/sh/tmpfile}.c + - dollar_dollar_pid is now a `pid_t' instead of `int' + +variables.c + - sbrand() now takes an `unsigned long' to set the seed value + - changed last_random_value to type int, since it's always between + 0 and 32767 + - use strtoul to convert the value in assign_random instead of atoi + - take out casts in any arguments to sbrand() + - take out cast to int in call to inttostr in set_ppid() + +subst.c + - don't cast last_asynchronous_pid when passing to itos() + +{sig,subst}.c + - prototype all static forward function declarations + + 5/14 + ---- +{test,trap,variables}.c + - prototype all static forward function declarations + +variables.c + - free_variable_hash_data() now takes a PTR_T, a `generic pointer' + +builtins/{alias,bind,break,cd,complete,declare,enable,exit,fc,fg_bg,help, +history,jobs,pushd,read,set,trap,umask, + - prototype all static forward function declarations + +builtins/read.def + - reset_eol_delim now takes a `char *' arg, since that's what the + unwind_protect functions pass it, and it ignores its arguments + anyway + +lib/readline/{histsearch,input,kill,rltty,search,vi_mode}.c + - prototype all static forward function declarations + +lib/tilde/tilde.c + - prototype all static forward function declarations + - tilde_find_prefix, tilde_find_suffix, isolate_tilde_prefix, and + glue_prefix_and_suffix now take `const char *' arguments where + appropriate + +configure.in,config.h.in + - check for vsnprintf, define HAVE_VSNPRINTF if found + +lib/readline/display.c + - use vsnprintf() in rl_message if it's available; if we don't, at + least set the last character in msg_buf to 0 to avoid overrun -- + we really can't do anything about overflow at this point. if it's + available, this fixes buffer overflow problems in rl_message + + 5/15 + ---- +lib/readline/histexpand.c + - in get_history_word_specifier, allow any character to terminate + a `:first-' modifier, not just `:' and null. This is what csh + appears to do. This allows things like `!:0- xyzzy' to replace the + last argument with xyzzy + + 5/18 + ---- +configure.in, config.h.in + - check for <stdint.h>, define HAVE_STDINT_H if found + - check for intmax_t in <stdint.h>, define intmax_t as long if not + found + + 5/21 + ---- +builtins/kill.def + - change to use strerror() for error message when kill(2) fails + +aclocal.m4 + - new macro, BASH_C_LONG_LONG, check for `long long' + +configure.in, config.h.in + - call BASH_C_LONG_LONG, define HAVE_LONG_LONG if found + +lib/sh/snprintf.c + - new file, with implementations of snprintf, vsnprintf, asprintf, + and vasprintf, derived from inetutils version + +Makefile.in, lib/sh/Makefile.in + - add snprintf.c/snprintf.o + +configure.in, config.h.in + - add checks for snprintf, asprintf, vasprintf, with appropriate + cpp defines + +lib/readline/{rldefs,xmalloc}.h, lib/readline/xmalloc.c + - xmalloc and xrealloc now take `size_t' arguments, like their bash + counterparts + +externs.h,lib/sh/itos.c + - inttostr and itos now take `long' arguments + - inttostr takes a `size_t' argument for the buffer size + +{expr,lib/malloc/malloc,variables,general}.c + - fixed calls to itos() by removing casts, etc. + +subst.[ch] + - get_dollar_var_value now takes a long, not an int + - sub_append_number now takes a long, not an int + +subst.c + - in parameter_brace_expand_word, use a long and legal_number to + translate ${N}, to avoid overflow + - in parameter_brace_expand_length, use a long and legal_number to + translate ${#N}, to avoid overflow + - in do_array_element_assignment, array_expand_index, + array_value_internal, use arrayind_t instead of int + - let verify_substring_values take long * arguments for the return + value of evalexp() + - pass long * arguments to verify_substring_values in + parameter_brace_substring + - parameter_brace_expand_length now returns `long' + - parameter_brace_expand now uses a long variable for the return + value of parameter_brace_expand_length + - param_expand now uses a long variable for the return value from + evalexp + - array_length reference now returns an `arrayind_t', since it can + return the num_elements member of an array, which is of type + arrayind_t + +subst.h + - array_expand_index now returns an `arrayind_t' + +array.[ch] + - array_subrange now takes arrayind_t arguments, not `int' + - dup_array_subrange now uses arrayind_t local variable to do + array indexing + - use long to print array indices in print_element + +variables.c + - null_array_assign, assign_dirstack, bind_array_variable + now take arrayind_t arguments as array indices + - assign_array_var_from_word_list, assign_array_var_from_string, + unbind_array_element now use arrayind_t local variables for + array indexing + +variables.h + - change extern declaration of bind_array_variable + +builtins/common.[ch] + - get_numeric_arg now returns a `long', since it usually returns + the value of legal_number() + +builtins/{shift,break}.def + - use long variables for the return value of get_numeric_arg + +builtins/history.def + - convert string argument to int only if it's in range + +builtins/pushd.def + - set_dirstack_element and get_dirstack_element now take `long' + index arguments + - get_dirstack_index now takes a `long' index argument, since it's + passed the converted value from legal_number + +lib/sh/timeval.c + - in print_timeval, don't assume that the number of minutes fits into + an int, since it's just seconds/60. + +lib/sh/clock.c + - ditto for print_clock_t + + 5/22 + ---- +shell.c + - since the -O option settings may possibly be overridden by the + normal shell initialization or posix initialization, save the + invocation options on an alist (with add_shopt_to_alist) and + process them after basic initialization (with run_shopt_alist) + + 5/23 + ---- +trap.h + - new define, BASH_NSIG, all system signals plus special bash traps + +trap.c, builtins/trap.def + - use BASH_NSIG for array bounds and loops where appropriate + +trap.c + - change decode_signal to disallow numeric signal numbers above + NSIG -- this means you can only reference special traps like + DEBUG by name + - new SPECIAL_TRAP(s) macro to test whether s is one of the special + bash traps (currently DEBUG and EXIT) + - change reset_or_restore_signal_handlers so command substitution + doesn't inherit the debug trap (like ksh93), and child processes + don't have to rely on initialize_traps being run to get rid of + any debug trap + +support/mksignames.c + - add extra "ERR" signal name, value NSIG+1, allocate space for it + and write it out in signal_names[] + +trap.h + - new define: ERROR_TRAP == NSIG+1, change BASH_NSIG to NSIG+2 + - extern declarations for set_error_trap, run_error_trap + - new define: TRAP_STRING(s), expands to trap_list[s] if signal S + is trapped and not ignored, NULL otherwise + +trap.c + - add ERROR_TRAP to SPECIAL_TRAPS define + - initialize ERROR_TRAP stuff in initialize_traps + - new function: set_error_trap(command), sets the ERR trap string + - new function: run_error_trap(command), runs the ERR trap string + - set trap string for ERROR_TRAP to NULL in free_trap_strings + - change reset_or_restore_signal_handlers so child processes don't + inherit the ERR trap + - add case to call run_error_trap in maybe_call_trap_handler + +execute_cmd.c + - in execute_command_internal, keep track of ERR trap and call it if + necessary + - use TRAP_STRING to get the value of debug and error traps + - in execute_function, arrange things so the ERR trap is not inherited + by shell functions, and is saved and restored like the DEBUG trap + +doc/{bash.1,bashref.texi} + - documented new ERR trap + +tests/{trap.{tests,right},trap2.sub,trap2a.sub} + - added ERR trap tests + +subst.c + - on machines without /dev/fd, change the named pipe fifo list to a + list of structs containing pathname and proc information + - change unlink_fifo_list to kill the proc in the fifo list with + signal 0 and not remove the fifo if the proc is still alive. This + should fix the problem on those backward systems without /dev/fd + where fifos were removed when a job using process substitution was + suspended + + 5/24 + ---- +examples/loadables/getconf.h + - new file, with basic defines needed to make getconf work minimally + on POSIX systems without the necessary definitions + +examples/loadables/getconf.c + - replacement functions for confstr, sysconf, pathconf for systems + that lack them, providing a minimal posix interface + - heavily augmented getconf, now supports all POSIX.1-200x, + POSIX.2-200x, Solaris 7, AIX 4.2 getconf variables + + 5/29 + ---- +builtins/setattr.def + - make `readonly', `export', and `declare' print `invisible' variables + as just a command and variable name, without a value, when listing + all variables (as POSIX.2-200x d6 requires) + + 5/30 + ---- + +configure.in + - upgraded to autoconf-2.50 on main development machine, so require + autoconf-2.50 in preparation for using some if its new features + - call AC_C_PROTOTYPES + - remove call to AC_EXEEXT, which now does the wrong thing + - changed AC_INIT to new flavor + - added call to AC_CONFIG_SRCDIR + - AC_CONFIG_HEADER -> AC_CONFIG_HEADERS + - AC_RETSIGTYPE -> AC_TYPE_SIGNAL + +configure.in, aclocal.m4, config.h.in + - removed call to BASH_LARGE_FILE_SUPPORT, use AC_SYS_LARGEFILE + standard support, with new macros _FILE_OFFSET_BITS and + _LARGE_FILES + - removed definition of BASH_LARGE_FILE_SUPPORT + +doc/bashref.texi + - document new `--enable-largefile' configure option + +lib/readline/readline.c + - change rl_set_prompt to call rl_expand_prompt unconditionally, so + local_prompt and local_prompt_prefix get set correctly + + 6/6 + --- +lib/readline/complete.c + - don't append `/' or ` ' to a match when completing a symlink that + resolves to a directory, unless the match doesn't add anything + to the word. This means that a tab will complete the word up to + the full name, but not add anything, and a subsequent tab will add + a slash. Change to append_to_match; callers changed + +hashlib.c + - new function, hash_table_nentries (table), returns the number of + items in TABLE + +hashlib.h + - extern declaration for hash_table_nentries + +configure.in + - configure without bash malloc on openbsd; they claim it needs + eight-bit alignment (which the bash malloc provides, but...) + + 7/2 + --- +stringlib.c + - only call RESIZE_MALLOCED_BUFFER from strsub() if the replacement + string length is > 0, avoid possible hangs if replacement is null + +subst.c + - don't include input.h; no longer needed + +configure.in + - remove calls to AC_SYS_RESTARTABLE_SYSCALLS and + BASH_SYS_RESTARTABLE_SYSCALLS; the results are no longer used + +config.h.in + - remove define for HAVE_RESTARTABLE_SYSCALLS + +aclocal.m4 + - removed definition of BASH_SYS_RESTARTABLE_SYSCALLS; no longer used + +execute_cmd.c + - changed select command so `return' no longer terminates the select + command, so it can be used to return from an enclosing function. + This is as ksh (88 and 93) does it + +lib/readline/vi_mode.c + - fix trivial typo in declaration of vi_motion; `t' appears twice; + the second instance should be `T' + + 7/3 + --- +configure.in + - don't add -static to LDFLAGS on Solaris 2.x. This means that the + auxiliary programs will be built as dynamic executables, but that + should do no harm + + 7/5 + --- +lib/glob/fnmatch.c + - fix the code that processes **(pattern) to short-circuit if the + pattern is ill-formed or lacks a trailing `)' -- this fixes the + segfault on **(/*) + +Makefile.in, builtins/Makefile.in + - split CCFLAGS into CCFLAGS_FOR_BUILD and CFLAGS, to aid in + cross-compilation + - build programs that use $(CC_FOR_BUILD) using $(CCFLAGS_FOR_BUILD) + +configure.in, config.h.in + - check for getaddrinfo(3), define HAVE_GETADDRINFO if found + +lib/sh/netopen.c + - implemented a version of _netopen (_netopen6) that uses + getaddrinfo(3) if available, use if HAVE_GETADDRINFO is defined. + old _netopen is _netopen4; _netopen now calls either _netopen6 + or _netopen4 as appropriate + + 7/9 + --- +builtins/exit.def + - don't source ~/.bash_logout if subshell_environment is non-zero + +execute_command.c + - in execute_until_or_while, handle the case where `breaking' is + set in the loop test (e.g., by the job control code when a job + is stopped with SIGTSTP), but the return value from the test is + something that would cause the loop to break. Need to decrement + `breaking' in this case + + 7/10 + ---- +execute_cmd.c + - in execute_in_subshell, make sure a command of type cm_subshell + inherits its `enclosing' command's CMD_IGNORE_RETURN flag + +variables.c + - in maybe_make_export_env, don't allow restricted shells to put + exported functions in the export environment + + 7/11 + ---- +lib/glob/strmatch.h + - renamed old fnmatch.h + - changed guard #ifdef to _STRMATCH_H + - include system <fnmatch.h> if HAVE_LIBC_FNM_EXTMATCH is defined + +lib/glob/strmatch.c + - renamed old fnmatch.c + - include "strmatch.h" + - if HAVE_LIBC_FNM_EXTMATCH is defined, define a dummy version of + strmatch() that just calls fnmatch(3) + +lib/glob/glob.c + - include "strmatch.h" + - fnmatch -> strmatch + +Makefile.in, lib/glob/Makefile.in + - fnmatch -> strmatch + +{bashhist,execute_cmd,pathexp,pcomplete,shell,stringlib,subst,test}.c, +pathexp.h,builtins/help.def + - include <glob/strmatch.h> + - fnmatch -> strmatch + +execute_cmd.c + - broke the code that parses the interpreter name from a #! line + out from execute_shell_script to a new function, getinterp() + - call getinterp from execute_shell_script + - use return value from getinterp in error message about bad + #! interpreter in shell_execve + + 7/12 + ---- +lib/readline/isearch.c + - the last isearch string is now remembered in a new static variable, + last_isearch_string + - if ^R^R is typed, readline now searches for the remembered isearch + string, if one exists + + 7/24 + ---- +pcomplete.h + - extern declaration for completions_to_stringlist() + + 7/25 + ---- +builtins/complete.def + - make compgen handle -o default option + - make compgen return success only if sl->list_len is non-zero, + indicating that there are items on the list + + 7/31 + ---- +execute_cmd.c + - in execute_connection, force stdin to /dev/null for asynchronous + commands if job control is not active, not just if the shell is + running a shell script (since you can run `set -m' in a script) + +lib/readline/rltty.c + - make sure _rl_tty_restore_signals resets `tty_sigs_disabled' on + successful restoration of the terminal modes + - make sure _rl_tty_disable_signals turns off IXON so that ^S and + ^Q can be read by rl_quoted_insert + + 8/1 + --- +aclocal.m4 + - new check for FNM_EXTMATCH being defined in <fnmatch.h>, as Ullrich + Drepper intends to do for new versions of GNU libc + +config.h.in + - new definition for HAVE_LIBC_FNM_EXTMATCH + +configure.in + - check for fnmatch, but don't define anything in config.h + - call BASH_FUNC_FNMATCH_EXTMATCH to check for FNM_EXTMATCH + + 8/2 + --- +alias.h + - remove bogus extern declaration for xmalloc() + - include "stdc.h" + - add prototype declarations for all extern function declarations + +xmalloc.c,lib/readline/xmalloc.c + - fix xmalloc to return a PTR_T + - fix xrealloc to return a PTR_T and take a PTR_T as first argument + +include/ansi_stdlib.h + - extern declarations for malloc and realloc have them return PTR_T + +xmalloc.h + - new file, with extern declarations for functions in xmalloc.c + +general.h + - removed extern declarations for functions in xmalloc.c + - include xmalloc.h + +Makefile.in,builtins/Makefile.in + - update dependencies to include xmalloc.h + +parse.y,{alias,array,bashline,bracecomp,execute_cmd,findcmd,flags,general, +hashcmd,locale,mailcheck,make_cmd,pathexp,pcomplete,print_cmd,stringlib, +subst,unwind_prot,variables}.c +builtins/{common,evalfile}.c +builtins/{cd,command,enable,exec,printf,read,set}.def +lib/sh/{makepath,netopen,pathphys,setlinebuf,shquote,snprintf,stringlist, +strtrans,tmpfile}.c +lib/readline/{util,terminal,shell,readline,macro,kill,isearch,input, +histfile,histexpand,display,complete,bind}.c + - make sure all calls to xmalloc are cast to the right return value + +siglist.c + - include xmalloc.h + +parse.y,{alias,bashline,bracecomp,expr,make_cmd,nojobs,print_cmd,subst}.c +builtins/{fc,printf,read}.def +lib/sh/snprintf.c, lib/tilde/tilde.c +lib/readline/{bind,display,histexpand,isearch,macro,util,vi_mode}.c + - make sure all calls to xrealloc are cast to the right return value + +lib/sh/{netopen,setlinebuf,shquote,snprintf}.c, lib/tilde/tilde.c + - include xmalloc.h, remove extern declaration of xmalloc + +lib/readline/xmalloc.h + - xmalloc and xrealloc should return PTR_T + +lib/readline/rldefs.h + - don't include an extern declaration for xmalloc + + 8/7 + --- +support/shobj-conf + - fixed up commented-out stanzas for HP's unbundled C compiler on + HP/UX + +support/bashbug.sh + - force the subject to be changed from the default + +lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 + - document that transpose-words swaps the last two words on the line + if point is at the end of the line + + 8/9 + --- +stringlib.c + - fix possible infinite recursion problem with null pattern in + strsub() + +hashlib.c + - new function copy_hash_table to copy a hash table using a caller- + supplied function to copy item data (defaults to savestring()) + +hashlib.h + - new extern declaration for copy_hash_table + +builtins/declare.def + - changes so that declare [-a] var=value assigns `value' to element 0 + of array variable `var' like ksh93 + - change so that declare [-a] var[N]=value assigns `value' to element + N of array variable `var' like ksh93 + + 8/13 + ---- +arrayfunc.c + - new file, for miscellaneous array functions + +arrayfunc.h + - new file, extern declarations for functions in arrayfunc.c + +variables.c + - move convert_var_to_array, bind_array_variable, + assign_array_from_string, assign_array_var_from_word_list, + assign_array_var_from_string, quote_array_assignment_chars, + skipsubscript, unbind_array_element, print_array_assignment + to arrayfunc.c + +shell.h + - include arrayfunc.h after variables.h + +variables.h + - remove above extern function declarations moved to arrayfunc.h + - add extern declaration for var_lookup + +Makefile.in + - add arrayfunc.c, arrayfunc.h in appropriate places + - add arrayfunc.h to dependencies + +subst.c + - move valid_array_reference, array_expand_index, array_variable_part, + array_value_internal, array_value (now global), get_array_value, + do_array_element_assignment to arrayfunc.c + +subst.h + - extern declarations for functions above moved to arrayfunc.h + +arrayfunc.h + - extern declarations for above functions from subst.c + +subst.[ch] + - string_list_dollar_star and string_list_dollar_at are now global + functions + - quote_escapes is now a global function + +subst.c + - maybe_expand_string -> expand_string_if_necessary + - expand_string_to_string -> expand_string_to_string_internal + - new functions: expand_string_to_string and + expand_string_unsplit_to_string, which call + expand_string_to_string_internal with expand_string and + expand_string_unsplit as the FUNC arguments, respectively + +arrayfunc.c + - change array_expand_index to call expand_string_to_string instead + of maybe_expand_string + + 8/14 + ---- +shell.c + - in execute_env_file, call expand_string_unsplit_to_string + +mailcheck.c + - in check_mail, call expand_string_to_string + +variables.c + - in assign_in_env, call expand_string_unsplit_to_string + +arrayfunc.c + - new function, array_variable_name, splits an array reference into + a name (which is returned as a new string) and subscript + - change array_variable_part to just call array_variable_name and + look up the string returned with find_variable + - new function, find_or_make_array_variable (name, flags) which will + look up an array variable and convert a string variable to an + array if necessary. The FLAGS argument, if non-zero, says to + check the readonly and noassign attributes and fail if either is set + +builtins/read.def + - make `read -a aname' honor any readonly status of `aname' + - read -a now calls find_or_make_array_variable with FLAGS value 1 + +arrayfunc.[ch], subst.c, builtins/{declare,read}.def + - do_array_element_assignment -> assign_array_element + + 8/20 + ---- +parse.y + - changed `for' command grammar to allow missing word list after `IN' + token, like latest POSIX drafts require + +lib/sh/tmpfile.c + - in sh_mktmpname(), check for filenum == 0 and init to non-zero number + in this case. it can happen on arithmetic overflow + +support/mkversion.sh + - added `[0-9].[0-9][0-9][a-z]' as an acceptable value for a + distribution to allow for intermediate versions, like 2.05a + +support/config.guess + - removed the addition of the output of `/usr/bin/objformat' when + creating the canonical name on FreeBSD machines, so the canonical + name is once again `freebsd4.2' instead of `freebsdelf4.2' + + 8/22 + ---- +lib/readline/{rlstdc,history,keymaps,readline,rldefs,rlprivate,rlshell, +rltypedefs,xmalloc}.h +lib/readline/{bind,compat,complete,display,funmap,histexpand,histsearch, +input,isearch,kill,nls,parens,readline,rltty,search,shell,signals,vi_mode + - changed __P to PARAMS + +lib/tilde/tilde.[ch] + - changed __P to PARAMS + +{Makefile,configure}.in + - changed the version number to 2.05a + - changed the release status to `alpha1' + + 8/23 + ---- +support/shobj-conf + - support for building shared libraries on Darwin/MacOS X + +siglist.h + - extern declaration for strsignal() to compensate for lack of + a definition in some system include files + +jobs.c + - remove casts from strsignal() calls + +[bash-2.05a-alpha1 frozen] + + 8/27 + ---- +[bash-2.05a-alpha1 released] + + 8/27 + ---- +execute_cmd.c + - fix eval_arith_for_expr to handle the case where the expanded + word list is NULL, returning 0 in this case + +print_cmd.c + - in print_function_def, make sure that func_redirects is assigned + a value before being used + + 8/28 + ---- +alias.c + - include <ctype.h> for definition of isalpha() + +bashhist.h + - add prototypes for extern function declarations + +flags.c + - include bashhist.h for extern function declarations + +mksyntax.c + - include <unistd.h> if HAVE_UNISTD_H is defined in config.h + +parse.y + - include test.h for extern function declarations + +externs.h + - change extern declaration for setlinebuf to sh_setlinebuf + +stringlib.c + - include <glob/glob.h> for extern function declarations + +variables.h + - add function prototypes for all of the sv_* functions + +builtins/common.h + - add extern declarations for set_shellopts() and parse_shellopts() + from builtins/set.def + +variables.c + - include "hashcmd.h" for extern declaration for flush_hashed_filenames + - include "pathexp.h" for extern declaration for setup_glob_ignore + +lib/malloc/malloc.c + - cast to `long' instead of `int' in memalign for 64-bit machines + +{pcomplete,trap}.c + - changed printf escape sequences used to print pointers to %p + +lib/readline/undo.c + - include "xmalloc.h" for extern function declaration + +input.h + - add function prototypes to extern declarations for getc_with_restart + and ungetc_with_restart + +variables.[ch] + - changed type of `function' member of `struct name_and_function' to + `sv_func_t', which is defined and prototyped in variables.h + - map_over now takes an `sh_var_map_func_t *' + +shell.h + - start of a set of function pointer typedefs like those in + lib/readline/rltypedefs.h + +hashlib.[ch] + - second paramter to flush_hash_table is now an `sh_free_func_t *' + +trap.c + - parameter to reset_or_restore_signal_handlers is now an + `sh_resetsig_func_t *' + +pcomplete.h, pcomplib.c + - function pointer argument to print_all_compspecs is now an + `sh_csprint_func_t *' + - function pointer `list_getter' element of an `ITEMLIST' is now + prototyped with __P((...)) instead of using `Function *' + +jobs.[ch] + - `j_cleanup' member of a JOB is now an `sh_vptrfunc_t *' + +alias.c + - map_over_aliases now takes an `sh_alias_map_func_t *' + - free_alias_data now takes a `PTR_T' + +pathexp.c + - function pointer argument to ignore_globbed_names is now an + `sh_ignore_func_t *' + +bashline.c + - function pointer argument to _ignore_completion_names is now an + `sh_ignore_func_t *' + +pathexp.h,{bashhist,bashline.c + - `item_func' member of a `struct ignorevar' is now an + `sh_iv_item_func_t *' + +builtins/evalfile.c + - `errfunc' is now an `sh_vmsg_func_t *' + +jobs.c + - map_over_job now takes an `sh_job_map_func_t *' as its first argument + +array.[ch] + - function pointer argument to array_walk is now an + `sh_ae_map_func_t *' + +general.c + - tilde_expansion_preexpansion_hook has type `tilde_hook_func_t *', + and so the assignment in tilde_initialize doesn't need a cast + +list.c + - map_over_words now takes an `sh_icpfunc_t *' as its second argument + +input.h + - the `getter' and `ungetter' function pointer members of a + BASH_INPUT are now of types `sh_cget_func_t *' and + `sh_cunget_func_t *' respectively + - init_yy_io now takes an `sh_cget_func_t *' as its first argument and + an `sh_cunget_func_t *' as its second + +parse.y + - init_yy_io now takes an `sh_cget_func_t *' as its first argument and + an `sh_cunget_func_t *' as its second + - initialize_bash_input casts bash_input.getter and bash_input.ungetter + appropriately + +builtins/mkbuiltins.c + - make the extern function definitions written to builtext.h have + prototypes with __P((...)) + - include "stdc.h" + - change Function to mk_handler_func_t + - fixed comment_handler to take the right number of args + - prototyped all the handler functions with __P((...)) + +builtins.h + - the `function' member of a struct builtin is now of type + `sh_builtin_func_t *' + +builtins/common.[ch] + - last_shell_builtin, this_shell_builtin are now of type + `sh_builtin_func_t *' + - find_shell_builtin, builtin_address, find_special_builtin now return + `sh_builtin_func_t *' + +builtins/exit.def, {execute_cmd,jobs,nojobs,variables}.c, parse.y + - changed all declarations of last_shell_builtin and this_shell_builtin + +execute_cmd.c + - execute_builtin, execute_builtin_or_function, + execute_subshell_builtin_or_function now take an + `sh_builtin_func_t *' instead of a `Function *' for argument + - changed appropriate variables from `Function *' to + `sh_builtin_func_t *' + +builtins/{bind,builtin,enable,read,setattr}.def + - replaced uses of `Function *' in variable declarations with + appropriate types (sh_builtin_func_t * or rl_command_func_t *) + +builtins/set.def + - set_func and get_func members of binary_o_options are now of types + `setopt_set_func_t *' and `setopt_get_func_t *', which are + prototyped + +builtins/shopt.def + - set_func member of shopt_vars is now of type `shopt_set_func_t *' + +bashline.c + - enable_hostname_completion now returns `int' (the old value of + perform_hostname_completion) + +[The only use of Function and VFunction now is for unwind-protects] + + 9/4 + --- +lib/sh/getcwd.c + - use const define from config.h rather than `CONST' + - use PTR_T define from xmalloc.h rather than `PTR' + - include xmalloc.h for PTR_T + - remove PATH_MAX define, rely on value from maxpath.h + +{general,mailcheck}.c, lib/sh/{pathcanon,pathphys}.c + - don't include maxpath.h directly; it's already included by shell.h + +lib/sh/mailstat.c + - new `mailstat()' implementation, to stat a mailbox file for + mail checking. handles maildir-style mail directories with one + file per message and creates a dummy stat struct from them + +lib/sh/Makefile.in + - add mailstat.c and mailstat.o in the appropriate places + +lib/malloc/malloc.c + - augmented implementation with wrapper functions that pass in file + and line number information from cpp. currently unused, but a + placeholder for future debugging and use tracking + +lib/malloc/shmalloc.h + - new file, extern declarations for allocation wrapper functions for + use by the shell (and others, I guess) + +xmalloc.[ch] + - wrapper functions for xmalloc, xfree, xrealloc (sh_ prefixed) that + pass cpp line number information through to the malloc functions, + if USING_BASH_MALLOC is defined + + 9/5 + --- +lib/malloc/gmalloc.c + - removed; no longer part of distribution + +lib/malloc/Makefile.in + - removed references to gmalloc.[co] + +configure.in, doc/bashref.texi + - removed references to `--with-glibc-malloc' configure option + +{configure,Makefile}.in + - changed the way bash malloc is configured into the Makefile, making + it more like how readline is configured. If the bash malloc is + not configured in, nothing in lib/malloc will be built + + 9/6 + --- +lib/malloc/imalloc.h + - new file, some internal malloc definitions + +lib/malloc/mstats.h + - new file, definitions for malloc statistics structs and functions + +lib/malloc/trace.c + - new file, malloc tracing functions (currently just print messages + to stderr), code is #ifdef MALLOC_TRACE + +lib/malloc/stats.c + - new file, moved malloc stats code from malloc.c to here + +lib/malloc/malloc.c + - moved some definitions to imalloc.h + - moved stats code to stats.c + - malloc tracing calls added to internal_{malloc,realloc,free}, all + #ifdef MALLOC_TRACE + +lib/malloc/Makefile.in, Makefile.in + - added {imalloc,mstats}.h, {trace,stats}.c + +parse.y + - changed decode_prompt_string to save and restore $? + (last_command_exit_value) around calls to expand_prompt_string(), + so command substitutions in PS1, etc. don't change $? + +{array,subst}.c + - a couple more arrayind_t fixes from Paul Eggert + +configure.in + - remove redundant check for wait3(2) + +redir.h + - fixed a typo (stdin_redirs -> stdin_redirects) + + 9/10 + ---- +execute_cmd.c + - remove check for \n and \r from WHITESPACE macro, since those + chars are not whitespace as returned by the whitespace(c) macro + - getinterp now takes a `char *' as first arg, not unsigned char * + - execute_shell_script now takes a `char *' as first arg, not + unsigned char * + - fix typo in forward declaration for `initialize_subshell' + +general.[ch] + - check_binary_file now takes a (char *) argument, not unsigned char * + - pass unsigned char to isspace and isprint because of ISO C fuckup + - bash_tilde_expand now takes a `const char *' as its argument + +builtins/evalfile.c, shell.c + - buffer passed to check_binary_file is char, not unsigned char + +parse.y + - fix extern declaration for yyerror() + - yyerror now takes a `const char *' as first arg + +{error,jobs}.c + - fixes to printf-style functions to handle pids wider than an int + +lib/readline/{isearch,vi_mode}.c + - fix call to rl_message in rl_display_search (remove extra arg) + +variables.c + - fix missing argument to builtin_error in make_local_variable + +builtins/getopts.def + - since getopts takes no options, change while loop calling + internal_getopts to a simple `if' check + +builtins/printf.def + - since printf takes no options, change while loop calling + internal_getopts to a simple `if' check + +lib/readline/bind.c + - remove _SET_BELL macro, expand code inline + +lib/readline/input.c + - change _rl_input_available to use either select or FIONREAD, + but not both + +lib/readline/readline.c + - fix rl_digit_loop to remove unreachable code at end of loop + +{bashhist,bashline,expr,jobs,redir,shell}.c, builtins/fc.def, lib/sh/snprintf.c + - bracket unused functions with #ifdef INCLUDE_UNUSED/#endif + - remove some unused variables + +execute_cmd.c + - remove #ifdef'd code that allowed `return' to terminate a select + statement + +expr.c + - remove some extraneous tests from strlong() + +array.h + - arrayind_t is now a long, since shell arithmetic is performed as + longs + - remove second declaration of new_array_element + +builtins/printf.def + - in mklong, xrealloc cannot return NULL, so don't check for it + - remove some #if 0 code + - fix core dump triggered by a format specification with more than + one `*' + - remove `foundmod', since its value mirrors `modchar != 0' + - include "common.h" for builtin_{error,usage} declarations + +Makefile.in,builtins/Makefile.in + - updated some dependencies due to new include files + +pcomplete.c + - include "execute_cmd.h" for declaration of execute_shell_function + +arrayfunc.c + - include <stdio.h> for printf + - include "builtins/common.h" for builtin_error declaration + +builtins/evalstring.c + - include "../trap.h" for run_trap_cleanup declaration + +builtins/help.def + - include "common.h" instead of locally declaring builtin_error + and builtin_usage + +error.h + - add extern declaration for itrace() + - add prototype to extern declaration of get_name_for_error + - file_error now takes a `const char *' as first argument + +externs.h + - added prototype for sh_setlinebuf declaration, bracketed with + NEED_SH_SETLINEBUF_DECL so we don't need stdio.h everywhere + - add extern declaration for parse.y:return_EOF() + +shell.c + - add NEED_SH_SETLINEBUF_DECL before including shell.h + +lib/readline/callback.c + - include <stdlib.h> or "ansi_stdlib.h" for abort declaration + +quit.h + - remove declaration of throw_to_top_level + +subst.c + - remove unused extern declaration for getopts_reset + +lib/sh/netopen.c + - include <shell.h> for legal_number, etc. + - add prototype for inet_aton extern declaration + +lib/sh/clock.c + - include <stdc.h> for __P declaration + - add extern declaration for get_clk_tck + +support/mkversion.sh + - changed so that extern function declarations for functions in + version.c (moved from externs.h) are in the generated version.h + +shell.h + - include version.h + +version.c + - various `char *' version variables are now `const char *' + +general.h + - add prototype for same_file, bracketed with _POSIXSTAT_H + #ifdef, since that's what include/posixstat.h defines + +builtins/common.[ch] + - _evalfile, maybe_execute_file, source_file, and fc_execute_file + now take a `const char *' as their first argument + +eval.c + - removed extern declaration of yyparse; it's in externs.h + +parse.y + - added prototypes to static forward function declarations + - changed local `all_digits' variable in read_token_word () to + all_digit_token to avoid clash with all_digits() function in + general.c + +{bashhist,copy_cmd,make_cmd,hashlib,mailcheck}.c + - added prototypes for static function declarations + +shell.h + - add extern declarations for interactive, interactive_shell, + changed c files with extern declarations + +pcomplete.c + - changed it_init_aliases to avoid shadowing global variable + `aliases' + +bashline.c,pathexp.c,general.h + - sh_ignore_func_t is now a pointer to a function taking a + `const char *'; users changed + +configure.in + - test for <strings.h> + +config.h.in + - add #undef HAVE_STRINGS_H + +bashansi.h + - change like recommended in autoconf manual + + 9/11 + ---- +[a date which will live in infamy. prayers for the victims.] + +execute_cmd.c + - don't use an absolute index into abuf in mkfmt, use + sizeof(abuf) to compute last index + +builtins/common.c + - fix read_octal to do a better job of detecting overflow while + iterating through the string + +builtins/umask.def + - change octal-print mode to print 4 digits, like other shells + - cast umask to unsigned long to avoid problems on systems where + it's wider than an int (POSIX doesn't guarantee that mode_t is + no wider than an int, but real-world systems use int) + +builtins/printf.def + - mklong can never return NULL (it uses xrealloc), so the mainline + doesn't need to check for NULL returns + - new function, getldouble (long double *), to get long doubles + - mklong now takes a `char *' as its second argument, the modifier(s) + to use + - changed use of `modchar' to handle more than a single modifier + character + - changed to handle `long double' and `L' formats better, rather + than discarding long double information + - since printf now follows the POSIX.2 rules for conversion errors, + we can dispense with the status returns from the get* functions + - make the get* functions as similar in structure as possible, + removing type casts, etc. + +lib/sh/timeval.c,execute_cmd.c + - change some instances of `long' to `time_t', for systems where + a time_t is bigger than a long + +jobs.c + - include "posixtime.h" instead of <sys/time.h> + +config.h.in + - add defines for HAVE_DECL_CONFSTR, HAVE_DECL_STRTOLD, + HAVE_DECL_SBRK, HAVE_DECL_PRINTF + - remove defines for SBRK_DECLARED and PRINTF_DECLARED + - add _GNU_SOURCE define + +configure.in + - add AC_CHECK_DECLS for strtold, confstr, sbrk, printf + - remove call to BASH_FUNC_SBRK_DECLARED + - remove call to BASH_FUNC_PRINTF + +xmalloc.c, lib/malloc/malloc.c + - change check of SBRK_DECLARED to HAVE_SBRK_DECL + +print_cmd.c + - change PRINTF_DECLARED to HAVE_DECL_PRINTF + +builtins/evalstring.c, builtins/common.h + - parse_and_execute now takes a `const char *' as its second argument + +input.h,parse.y + - with_input_from_* functions now take a `const char *' as their + second argument + - init_yy_io now takes a `const char *' as its fourth argument + +parse.y,externs.h + - parse_string_to_word_list now takes a `const char *' as its second + argument + +tests/builtins.right + - change output to account for extra digit in umask output + +pcomplib.c + - free_progcomp now takes a PTR_T argument + +builtins/bashgetopt.h + - include <stdc.h> + - add prototypes to extern declarations + +builtins/shopt.def + - add prototypes to static function declarations + +builtins/{fc,umask,wait}.def, builtins/{bashgetopt,common}.c + - include <ctype.h> for isdigit macro (referenced by `digit(x)') + +lib/readline/complete.c + - added more static function declarations with prototypes + + 9/12 + ---- +lib/sh/tmpfile.c + - use `^' instead of `*' in sh_mktmpname to make filenames a bit + more random + +include/stdc.h,lib/readline/rldstdc.h + - add __attribute__ definition + +builtins/common.h + - add printf __attribute__ to declaration of builtin_error + +error.h + - add printf __attribute__ to declaration of programming_error, + report_error, parser_error, fatal_error, sys_error, internal_error, + internal_warning + +lib/readline/readline.h + - add printf __attribute__ to declaration of rl_message + +pcomplete.c + - add printf __attribute__ to declaration of debug_printf + +print_cmd.c + - add printf __attribute__ to declarations of cprintf, xprintf + +include/chartypes.h + - new file, includes <ctype.h> and defines macros that check for + safe (ascii) arguments before calling the regular ctype macros + +{alias,bashline,execute_cmd,expr,findcmd,general,locale,mksyntax,stringlib,subst,variables}.c +parse.y +builtins/{bashgetopt,common}.c +builtins/{fc,printf,umask,wait}.def +lib/glob/strmatch.c +lib/sh/{oslib,pathcanon,pathphys,snprintf,strcasecmp,strindex,stringvec,strtod,strtol,strtrans}.c +examples/loadables/{head,sleep}.c + - include "chartypes.h" or <chartypes.h> instead of <ctype.h> + +Makefile.in,{builtins,lib/{glob,sh}}/Makefile.in + - update dependencies to include chartypes.h + +lib/sh/inet_aton.c + - use `unsigned char' instead of `char' to pass to ctype.h functions + +lib/sh/netopen.c + - check for '0' <= host[0] <= '9' in _getaddr instead of using + isdigit + +subst.c,lib/sh/shquote.c + - change array subscripts into sh_syntaxtab from `char' to + `unsigned char' + +{alias,bashline,execute_cmd,expr,general,subst}.c, parse.y +builtins/{fc,printf,umask,wait}.def builtins/{bashgetopt,common}.c +lib/sh/{pathcanon,pathphys,snprintf,strcasecmp,strindex,strtod,strtol,strtrans}.c +examples/loadables/{head,sleep}.c + - change to use some of the new macros in chartypes.h + - remove old local macro definitions now provided by chartypes.h + +general.h + - remove definition of isletter, ISOCTAL, digit, digit_value + - change legal_variable_starter and legal_variable_char to use + chartypes.h macros + - change ABSPATH to use chartypes.h macros + +lib/readline/util.c + - change to use Paul Eggert's FUNCTION_FOR_MACRO define to define + function replacements for macros in chardefs.h + +lib/readline/chardefs.h + - added some of the same macros as in chartypes.h + - change _rl_lowercase_p, _rl_uppercase_p, _rl_digit_p, + _rl_to_upper, _rl_to_lower to use new IS* macros + - added _rl_isident macro from vi_mode.c:isident + +lib/readline/{bind,complete,nls}.c + - change to use some of the new macros from chardefs.h + +lib/readline/vi_mode.c + - isident -> _rl_isident + - remove local defines of macros in chardefs.h + +lib/sh/strtol.c + - updated to new version, modified from glibc 2.2.4 and sh-utils-2.0. + This one can do strtoll and strtoull, if necessary + + 9/13 + ---- +builtins/ulimit.def + - changed get_limit so it retrieves both hard and soft limits + instead of one or the other + - changed callers of get_limit + - changed getmaxvm to take soft limit, hard limit as arguments + - changed getmaxuprc to just take a single argument, the value + - changed calls to printone() to pass soft limit or hard limit + depending on `mode' instead of using old current_limit variable + - moved check for out-of-range limits in ulimit_internal into the + block that converts a string argument to a value of type rlim_t + - changed RESOURCE_LIMITS struct to break the description into a + description string and separate scale factor string + - changed print_all_limits to print a single error message if + get_limit fails, including limits[i].description now that the + scale factor has been removed from the description string + - removed DESCFMT define, since it's now used only in printone() + - changed printone to print the option character associated with a + particular limit if we're printing multiple limits + - changed calls to builtin_error to print the description associated + with a limit if setting or getting the limit fails + - added support for new POSIX 1003.1-200x rlim_t values: + RLIM_SAVED_CUR and RLIM_SAVED_MAX, which expand to the current + soft and hard limits, whatever they are + - changed printone to print `hard' or `soft' if the current limit is + RLIM_SAVED_MAX or RLIM_SAVED_CUR, respectively + - changed ulimit_internal to handle new `hard' and `soft' arguments + - changed help text do describe the special limit arguments `hard', + `soft', and `unlimited' + +doc/{bash.1,bashref.texi} + - documented new `hard' and `soft' limit arguments to `ulimit' + +hashlib.[ch] + - find_hash_item now takes a `const char *' is its first argument + - hash_string now takes a `const char *' is its first argument + - remove_hash_item now takes a `const char *' as its first argument + +pcomplib.c + - removed cast from first argument to find_hash_item in find_compspec + +general.[ch] + - absolute_program now takes a `const char *' as its argument + - absolute_pathname now takes a `const char *' as its argument + +lib/glob/glob.[ch] + - glob_pattern_p now takes a `const char *' as its argument + +bashline.c + - removed cast from first argument to absolute_program in + command_word_completion_function + - removed cast from first argument to glob_pattern_p in + attempt_shell_completion + +findcmd.[ch] + - find_absolute_program, find_user_command, find_path_file, + search_for_command, user_command_matches now take a + `const char *' as their first argument + - file_status, executable_file, is_directory, executable_or_directory + now take a `const char *' as their argument + - _find_user_command_internal, find_user_command_internal, + find_user_command_in_path + +lib/sh/makepath.c, externs.h + - changed sh_makepath so it takes `const char *' for its first + two arguments + +hashcmd.[ch] + - find_hashed_filename now takes a `const char *' as its first arg + - remove_hashed_filename now takes a `const char *' as its first arg + +variables.[ch] + - new_shell_variable, var_lookup, shell_var_from_env_string, + find_name_in_env_array, bind_function, makunbound, + bind_name_in_env_array, bind_tempenv_variable, bind_variable + now take a `const char *' as their first arg + - find_function, make_new_variable, find_tempenv_variable, + find_variable_internal, find_variable, set_func_read_only, + set_func_auto_export, all_variables_matching_prefix, assign_in_env, + assignment, kill_local_variable, make_local_variable, unbind_variable + now take a `const char *' as their arg + - mk_env_string now takes `const char *' arguments + +arrayfunc.[ch] + - skipsubscript now takes a `const char *' as its argument + + 9/17 + ---- +lib/readline/complete.c + - attempt to preserve case of what the user typed in + compute_lcd_of_matches if we're ignoring case in completion + +builtins/{let,pushd}.def,{execute_cmd,expr}.c + - change some 0L constants to 0 and let the compiler sort it out + + 9/18 + ---- +lib/malloc/alloca.c + - alloca now takes a `size_t' argument + +include/memalloc.h + - if we're providing an extern function declaration for alloca, + use `void *' and prototype if __STDC__ is defined + - if HAVE_ALLOCA_H is defined, but C_ALLOCA is defined, don't + define HAVE_ALLOCA + + 9/19 + ---- +subst.c + - do_assignment_internal, do_assignment, and do_assignment_no_expand + now take a `const char *' as their first argument + +general.h + - a `sh_assign_func_t' is now a function taking a `const char *' and + returning int + +hashcmd.c + - free_filename_data now takes a `PTR_T' argument to agree with the + typedef for `sh_free_func_t' + +lib/sh/snprintf.c + - use TYPE_MAXIMUM define like strtol.c instead of huge constants + + 9/20 + ---- +lib/sh/snprintf.c + - don't bother to compile the bulk of the body unless HAVE_SNPRINTF + or HAVE_ASPRINTF is not defined + + 9/24 + ---- +flags.c + - ignore `set -n' if the shell was started interactively + +lib/readline/readline.c + - initialize readline_echoing_p to 0; let the terminal-specific code + in rltty.c set it appropriately + +lib/malloc/malloc.c + - changed internal_memalign() slightly to avoid compiler warnings about + negating an unsigned variable (-alignment -> (~alignment + 1)) + + 9/27 + ---- +lib/readline/readline.c + - changed rl_newline to set _rl_history_saved_point appropriately + for the {previous,next}_history code + +lib/readline/rlprivate.h + - extern declaration for _rl_history_preserve_point + +lib/readline/bind.c + - new bindable variable, `history-preserve-point', sets value of + _rl_history_preserve_point + + 10/1 + ---- +lib/malloc/table.c + - new file, with a map of allocated (and freed) memory for debugging + multiple frees, etc. Indexed by hash on values returned by + malloc(); holds size, file and line number info for last alloc or + free and a couple of statistics pointers + +lib/malloc/malloc.c + - a few cleanups; added calls for registering allocations and frees + if MALLOC_REGISTER is defined + - replaced MALLOC_RETURN with explicit MALLOC_NOTRACE define + - reordered fields in `struct...minfo' in `union mhead' to restore + eight-byte alignment + - added explicit checks for underflow in free and realloc since + checking mh_magic2 is not sufficient to detect everything (it's + no longer the last field in the struct, and thus not the bytes + immediately preceding what's returned to the user) + - new function, xbotch, for printing file and line number info for + the failed assertion before calling botch() (programming_error()) + +configure.in + - replaced call to BASH_C_LONG_LONG with call to + AC_CHECK_TYPES([long long]) + - moved the C compiler tests before the tests for various + system types, so we can know whether we have `long long' + before testing for 64-bit types + - if we have `long long', check for sizeof(long long) and save value + +aclocal.m4 + - changed BASH_TYPE_BITS64_T to check `long long' before `long', but + after `double' + + 10/2 + ---- +lib/malloc/malloc.c + - made malloc and realloc both agree on the rounding for a request of + size N (round up to nearest multiple of 8 after adjusting for + malloc overhead); uses new ALLOCATED_BYTES macro + - realloc and free now use new IN_BUCKET macro for underflow checks + +execute_cmd.c + - fixed time_command() to use `time_t' instead of `long' to hold + time stamps + +lib/sh/clock.c + - clock_t_to_secs now takes a `time_t *' second argument + - fixed print_clock_t to call clock_t_to_secs with right arguments + +lib/sh/timeval.c + - fixed print_timeval to make `minutes' a `long' and make its + structure identical to print_clock_t + +redir.c + - changed redirection_error to check for EBADF and use the file + descriptor being redirected from in the error message if it + is >= 0 + +Makefile.in + - changed release status to `beta1' + +lib/glob/collsyms.h + - added a few ASCII symbols to the posix_collsyms array + + 10/3 + ---- +aclocal.m4 + - fixed typo in BASH_TYPE_BITS64_T + +configure.in + - added check for unsigned chars with AC_C_CHAR_UNSIGNED + +config.h.in + - added PROTOTYPES and __CHAR_UNSIGNED__ #defines + +general.h + - if CHAR_MAX is not define by <limits.h>, provide a definition + +builtins/printf.def + - change tescape() to mask \0 and \x escape sequences with 0xFF + - change tescape() to process at most two hex digits after a `\x' + +lib/sh/strtrans.c + - change strtrans() to mask \0 and \x escape sequences with 0xFF + - change strtrans() to process at most two hex digits after a `\x'. + This affects `echo -e' and $'...' processing + +lib/readline/bind.c + - changed rl_translate_keyseq() to process at most two hex digits + after a `\x' + +lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 + - changed documentation for key binding escape sequences to specify + that at most two hex digits after \x are translated + - changed documentation for key binding to specify that the result + of \nnn or \xhh escapes is an eight-bit value, not just ASCII + +doc/{bash.1,bashref.texi} + - changed documentation of $'...' to specify that at most two hex + digits after \x are translated + - changed `echo' documentation to specify that at most two hex + digits after \x are translated + - changed documentation for `echo' and $'...' to specify that the + result of \nnn or \xhh escapes is an eight-bit value, not just ASCII + + 10/4 + ---- +lib/malloc/malloc.c + - changed interface for xbotch to pass memory address and error code + as two additional arguments + - call mregister_describe_mem from xbotch to get the last allocation + or free before the botch + +configure.in + - call AC_CHECK_DECLS([strsignal]) + +config.h.in + - add HAVE_DECL_STRSIGNAL + +siglist.h + - make declaration of strsignal() dependent on !HAVE_DECL_STRSIGNAL + + 10/5 + ---- +support/texi2html + - upgraded to version 1.64 + + 10/9 + ---- +aclocal.m4 + - added check for `long long' to BASH_TYPE_PTRDIFF_T + +configure.in + - replaced call to BASH_HAVE_TIOCGWINSZ with AC_HEADER_TIOCGWINSZ + +aclocal.m4 + - replaced body of BASH_STRUCT_TERMIOS_LDISC with call to + AC_CHECK_MEMBER(struct termios.c_line, ...) + - replaced body of BASH_STRUCT_TERMIO_LDISC with call to + AC_CHECK_MEMBER(struct termios.c_line, ...) + +[bash-2.05a-beta1 frozen] + + 10/10 + ----- +lib/sh/snprintf.c + - fixed exponent() to not smash the trailing zeros in the fraction + when using %g or %G with an `alternate form' + - fixed exponent() to handle the optional precision with %g and %G + correctly (number of significant digits before the exponent) + + 10/11 + ----- +expr.c + - fixed strlong() to correct the values of `@' and `_' when + translating base-64 constants (64#@ == 62 and 64#_ == 64), for + compatibility with ksh + +lib/sh/itos.c + - added a slightly more flexible fmtlong() function that takes a + base argument and flags (for future use) + - rewrote itos and inttostr in terms of fmtlong + +lib/sh/fmtulong.c + - new file, converts unsigned long to string. hooks for `unsigned + long long' in the future. unused as yet + + 10/15 + ----- +lib/readline/rltty.c + - change the SET_SPECIAL macro to avoid possible (but highly + unlikely) negative array subscripts + +error.h + - add __attribute__ to extern declaration of itrace (even though the + function isn't defined in released versions of bash) + +bashansi.h + - include <strings.h> if HAVE_STRINGS_H is defined, to get any extra + function declarations provided therein + +copy_cmd.c + - fix typo in forward declaration for copy_arith_for_command + +lib/malloc/stats.c + - make the accumulators in _print_malloc_stats be `unsigned long' + instead of `int' + +externs.h, sig.h + - add `__noreturn__' gcc attribute to exit_shell and jump_to_top_level + declarations + +lib/sh/mailstat.c, support/bashversion.c + - include <bashansi.h> for some string function declarations + +lib/malloc/shmalloc.h + - added extern declarations of functions that do malloc debugging + +lib/readline/{isearch,readline,vi_mode}.c + - make sure we index into _rl_keymap with a non-negative index + +parse.y + - make sure we index into sh_syntaxtab with a non-negative index + +lib/readline/vi_mode.c + - bound the vi_mark_chars array with the number of characters between + 'a' and 'z' rather than using a fixed amount + - don't use _rl_lowercase_p when deciding whether the char read by + rl_vi_set_mark is a valid mark; just use 'a' <= char <= 'z' + +lib/readline/chardefs.h + - conditionally include memory.h and strings.h as in general.h + - replace ISASCII with IN_CTYPE_DOMAIN like other GNU software + - add defines for ISPRINT(c), ISLOWER(c) and ISUPPER(c) + - fix defines for _rl_lowercase_p, _rl_uppercase_p, _rl_digit_p, + _rl_pure_alphabetic, ALPHABETIC, _rl_to_upper, _rl_to_lower, + and _rl_isident to work on systems with signed chars + +include/chartypes.h + - replace ISASCII with IN_CTYPE_DOMAIN like other GNU software + +lib/sh/{strcasecmp,strtod,strtol}.c + - don't pass possibly-negative characters to tolower() or toupper() + +lib/glob/strmatch.c + - don't bother testing for isupper in FOLD; rely on TOLOWER macro + from <chartypes.h> to do it + - don't use local definitions of isblank, et al.; rely on macros + from <chartypes.h> + +lib/readline/{display,readline}.c, mksyntax.c + - use new ISPRINT macro instead of isprint() + +builtins/{kill.def,mkbuiltins.c},{error,execute_cmd,jobs,nojobs,subst}.c + - don't assume that a pid_t fits into an int for printing and other + uses + +variables.[ch] + - the unused put_gnu_argv_flags_into_env now takes a `long' pid + argument + +configure.in, config.h.in + - call AC_STRUCT_ST_BLOCKS, define HAVE_STRUCT_STAT_ST_BLOCKS if found + - check for strtoull(), define HAVE_STRTOULL if found + - check for uintmax_t, define to `unsigned long' if not found + +lib/sh/mailstat.c + - don't use st_blocks member of struct stat unless + HAVE_STRUCT_STAT_ST_BLOCKS is defined; otherwise use the st_nlink + field to return the total number of messages in a maildir-style + mail directory + +general.h,{alias,expr,general,subst,variables}.c +builtins/{printf,read}.def +lib/readline/{bind,complete,nls}.c +lib/sh/{pathcanon,pathphys,shquote,snprintf,strindex,strtod,strtol,strtrans}.c + - cast args to ctype macros to unsigned char for systems with signed + chars; other fixes for signed chars + +lib/sh/{fmtullong,strtoull.c} + - new files, more support for `long long' + +Makefile.in, lib/sh/Makefile.in + - make fmtullong.o and strtoull.o part of libsh + +lib/sh/itos.c + - remove local copy of fmtlong; use fmtulong instead + - new functions: uitos, uinttostr work on `unsigned long' + +lib/sh/snprintf.c + - fixes to make `unsigned long long' work (%llu) + - fixes to make unsigned formats not print the sign when given + an unsigned long that is greater than LONG_MAX + +externs.h + - extern declarations for fmtulong, fmtulloing, strtoull + - extern declarations for uitos, uinttostr + + 10/16 + ----- +configure.in + - move header checks before function checks + - move c compiler tests before header checks + - check for <inttypes.h> with BASH_HEADER_INTTYPES + - change type checks for intmax_t, uintmax_t to not attempt to + include <stdint.h> + - check for strtoimax, strtoumax, strtoll, strtol, strtoull, strtoul + with BASH_CHECK_DECL (for declarations in header files) and + AC_REPLACE_FUNCS (for availability and LIBOBJS substitution) + - remove check for have_long_long around sizeof check for long long + (since autoconf will give it a size of 0 if the type isn't found) + +config.h.in + - add a define for HAVE_INTTYPES_H + - add a define for HAVE_UNSIGNED_LONG_LONG + - add defines for HAVE_STRTOIMAX, HAVE_STRTOUMAX, HAVE_STRTOLL + +aclocal.m4 + - new func, BASH_HEADER_INTTYPES, which just calls AC_CHECK_HEADERS + on <inttypes.h>; separate so it can be AC_REQUIREd + - AC_REQUIRE([BASH_HEADER_INTTYPES]) in BASH_CHECK_TYPE + - include <inttypes.h> in BASH_CHECK_TYPE if HAVE_INTTYPES_H is + defined + - change AC_DEFINE to AC_DEFINE_UNQUOTED in BASH_CHECK_TYPE + - new `long long' checking macros: BASH_TYPE_LONG_LONG and + BASH_TYPE_UNSIGNED_LONG_LONG + - new BASH_CHECK_DECL + +lib/sh/{strto[iu]max,strtoll}.c, lib/sh/Makefile.in, Makefile.in + - new files + +externs.h + - extern declarations for strtoll, strtoimax, strtoumax + +lib/malloc/alloca.c + - include <bashtypes.h> for size_t + +builtins/printf.def + - new functions: getllong, getullong, getintmax, getuintmax; return + long long, unsigned long long, intmax_t, uintmax_t respectively + - builtin printf now handles `ll' and `j' length modifiers directly + +lib/sh/Makefile.in + - use LIBOBJS to decide whether or not the strto* functions are + needed + + 10/17 + ----- +configure.in + - call AC_REPLACE_FUNCS(rename) + - move getcwd, strpbrk, strcasecmp, strerror, strtod + from AC_CHECK_FUNCS to AC_REPLACE_FUNCS + - only call BASH_FUNC_GETCWD if $ac_func_getcwd == "yes" + - call BASH_CHECK_SYS_SIGLIST + - if we don't have vprintf but have _doprnt, call AC_LIBOBJ(vprint) + +lib/sh/Makefile.in + - remove rename, getcwd, inet_aton, strpbrk, strcasecmp, strerror, + strtod, vprint from OBJECTS; picked up from LIBOBJS + +aclocal.m4 + - change BASH_FUNC_GETCWD to call AC_LIBOBJ(getcwd) if the libc + getcwd(3) calls popen(3) + - change BASH_FUNC_INET_ATON to call AC_LIBOBJ(inet_aton) if it's + not found in libc or as a #define even with the special includes + - BASH_KERNEL_RLIMIT_CHECK -> BASH_CHECK_KERNEL_RLIMIT + - BASH_DEFAULT_MAILDIR -> BASH_SYS_DEFAULT_MAILDIR + - BASH_JOB_CONTROL_MISSING -> BASH_SYS_JOB_CONTROL_MISSING + - BASH_REINSTALL_SIGHANDLERS -> BASH_SYS_REINSTALL_SIGHANDLERS + - BASH_SIGNAL_CHECK -> BASH_SYS_SIGNAL_VINTAGE + - BASH_DUP2_CLOEXEC_CHECK -> BASH_FUNC_DUP2_CLOEXEC_CHECK + - BASH_PGRP_SYNC -> BASH_SYS_PGRP_SYNC + - BASH_RLIMIT_TYPE -> BASH_TYPE_RLIMIT + - BASH_FUNC_PRINTF -> BASH_DECL_PRINTF + - BASH_FUNC_SBRK_DECLARED -> BASH_DECL_SBRK + - BASH_MISC_SPEED_T -> BASH_CHECK_SPEED_T + - BASH_CHECK_SOCKLIB -> BASH_CHECK_LIB_SOCKET + - new macro, BASH_CHECK_SYS_SIGLIST, encapsulates all the checks for + sys_siglist, _sys_siglist, and strsignal(), sets SIGLIST_O to + siglist.o if appropriate + +Makefile.in + - use SIGLIST_O variable to decide whether or not we need siglist.o + +{execute_cmd,subst}.c + - change a couple of instances of ISDIGIT to DIGIT, where we really, + really only want ascii digits + +ansi_stdlib.h + - don't need a declaration for atol() + + 10/18 + ----- + +aclocal.m4 + - new macro, BASH_FUNC_PRINTF_A_FORMAT, checks for printf support + for %a, %A conversion specifiers, defines HAVE_PRINTF_A_FORMAT + if successful + +configure.in + - call AC_CHECK_FUNCS for isascii + - call BASH_FUNC_PRINTF_A_FORMAT + +config.h.in + - add a define for HAVE_ISASCII + - add a define for HAVE_PRINTF_A_FORMAT + +lib/sh/snprintf.c + - for long double output, fall back to sprintf using ldfallback() + function for floating point formats + - support %a, %A using dfallback() or ldfallback() if + HAVE_PRINTF_A_FORMAT is defined + - fix bug in vasprintf that returned wrong value in its first + argument if the buffer holding the result string got reallocated + - fixed PUT_CHAR macro to increment the counter even if we've + exceeded the buffer size, for the return value from + vsnprintf/snprintf + - fix vsnprintf_internal to not use counter < length as a loop + condition, but always process the entire format string (for + the return value from vsnprintf/snprintf) + +builtins/printf.def + - support %a, %A if HAVE_PRINTF_A_FORMAT is defined + +include/typemax.h + - new file, with the TYPE_MAXIMUM stuff that's duplicated in several + files in lib/sh + +lib/sh/{fmtulong,strtol,snprintf}.c + - include <typemax.h> instead of having the definitions in each file + +lib/sh/Makefile.in + - updated dependencies for typemax.h + + 10/22 + ----- +configure.in + - call AC_CHECK_FUNCS on ctype.h functions/macros that bash redefines + in chartypes.h + +config.h.in + - defines for HAVE_IS{ASCII,BLANK,GRAPH,PRINT,SPACE,XDIGIT} + +include/chartypes.h, lib/glob/strmatch.c, lib/readline/chardefs.h + - don't redefine some is* ctype macros/functions if HAVE_ISXXX is + defined (meaning that an appropriate function, but not a macro, + exists) + +lib/sh/strtrans.c + - new function, ansic_shouldquote, returns 1 if argument string + contains non-printing chars that should be quoted with $'...' + +externs.h + - new declaration for ansic_shouldquote() + +variables.c + - change print_var_value to ansi C quote the string if we're not in + posix mode and the variable's value contains non-printing chars, + to use the regular shell single quoting if the value contains + shell meta-characters, and to just output the string otherwise + +lib/sh/shquote.c + - add `break' to `case '~':' to avoid fallthrough and extra test + +doc/bashref.texi + - note that in POSIX mode, `set' displays variable values that + include nonprinting characters without quoting, unless they + contain shell metacharacters + +builtins/printf.def, lib/sh/snprintf.c + - handle `F' conversion specifier as equivalent to 'f' + +parse.y, {nojobs,variables}.c + - a couple of cleanups for when building a minimal configuration + +nojobs.c + - new function: stop_making_children(), just sets + already_making_children to 0 (like stop_pipeline) + +subst.c + - call stop_making_children from subst.c:command_substitute if + JOB_CONTROL is not defined. This fixes the bug where the wrong + process is waited for (and its status returned) when using + command substitution in a null command in a shell function + +builtins/printf.def + - new variable `tw' used to keep track of the total number of + characters written by a single call to `printf' -- to be + used for the `%n' conversion, which will be added later. It + gets reset each time we reuse the format string, which is what + ksh93 seems to do + + 10/23 + ----- +variables.c + - new function, bind_var_to_int (char *var, long val) + +variables.h + - extern declaration for bind_var_to_int + +lib/sh/netopen.c + - use gai_strerror() for error messages when getaddrinfo() fails + - use PF_INET if DEBUG is defined, since IPv6 doesn't work for me + +Makefile.in + - pass DEBUG=${DEBUG} down to makes in some subdirectories + +{builtins,lib/{glob,sh}}/Makefile.in + - append ${DEBUG} to LOCAL_CFLAGS value, passed by top-level Makefile + +builtins/printf.def + - added support for %n format conversion char (number of chars printed + so far from current format string) + + 10/24 + ----- +variables.c + - if posixly_correct is set, the default value of $MAILCHECK is 600 + - use legal_number instead of atoi in adjust_shell_level + - treat non-numeric assignments to SECONDS as 0 in assign_seconds + - new function, init_funcname_var; sets FUNCNAME as a dynamic variable + if it's not set in the initial environment + - new function, init_groups_var; sets GROUPS as a dynamic array + variable if it's not set in the initial environment + - new function, init_dirstack_var; sets DIRSTACK as a dynamic array + variable if it's not set in the initial environment + - new function, init_seconds_var; sets SECONDS as a dynamic + variable using any valid integer value in the initial environment + as the initial value, as if an assignment had been performed + - call init_funcname_var, init_groups_var, init_dirstack_var, + init_seconds_var from initialize_dynamic_variables + - non-numeric values assigned to LINENO are treated as 0 + - change initialize_shell_variables to not auto-export PATH or TERM + - change set_home_var to not auto-export HOME + - change set_shell_var to not auto-export SHELL + - broke the code that sets HOSTNAME, HOSTTYPE, MACHTYPE, OSTYPE + out into a separate function, set_machine_vars; none of those + variables are auto-exported + - bash no longer un-exports SSH_CLIENT or SSH2_CLIENT + +shell.c + - changed isnetconn() to check SSH_CLIENT and SSH2_CLIENT only if + SSH_SOURCE_BASHRC is defined in config-top.h + +config-top.h + - added a commented-out definition for SSH_SOURCE_BASHRC + + 10/25 + ----- + +Makefile.in + - changed RELSTATUS to `rc1' (release candidate 1) + + 10/29 + ----- +locale.c + - fixed an `=' vs. `==' typo in set_locale_var when parsing + LC_NUMERIC + +doc/{bash.1,bashref.texi} + - document what bash does with $POSIXLY_CORRECT + +doc/builtins.1 + - some updates + +builtins/psize.sh + - some mktemp(1) changes + +lib/readline/readline.c + - change rl_backward to check for rl_point < 0 and reset to 0 if so + +lib/readline/util.c + - don't compile in _rl_strpbrk if HAVE_STRPBRK is defined + +lib/readline/rlprivate.h + - remove extern declaration of _rl_strpbrk + +lib/readline/rldefs.h + - #define _rl_strpbrk as strpbrk if HAVE_STRPBRK is define, otherwise + add extern declaration of _rl_strpbrk from rlprivate.h + +{mailcheck,shell,variables}.c + - make sure to include posixtime.h to get any prototype for time(3) + in scope + +{array,eval,execute_cmd,mksyntax,subst}.c, parse.y +builtins/common.c +lib/sh/pathcanon.c + - a few changes as the result of `gcc -Wall' patches from solar + designer + +builtins/read.def, parse.y + - change some calls to free() to xfree() + +builtins/set.def + - make sure unset_builtin() resets unset_array to 0 each time through + the loop, because it's set (and used) depending on the current + argument + +shell.h + - new define, USE_VAR, to force the compiler to not put a particular + variable in a register -- helpful if registers are not restored + by setjmp/longjmp + +builtins/{evalfile.c,{read,wait}.def}, {eval,execute_cmd,shell,test}.c + - use USE_VAR for some variables + +subst.c + - fixed a case in expand_word_internal where a NULL pointer could + have been passed to free() (though free() should ignore it) + - fixed a case at the end of expand_word_internal where LIST could + have been used uninitialized (it makes gcc happy, though it + doesn't happen in practice) + +test.c + - give test_syntax_error(), beyond(), and integer_expected_error() + the `__noreturn__' attribute for gcc + +unwind_prot.c + - in clear_unwind_protect_list(), convert `flags' to `long' (via + assignment to a `long' variable) before casting to `char *', in + case pointers and longs are 64 bits and ints are 32 (makes no + difference on 32-bit machines) + + 10/30 + ----- +print_cmd.c + - fixed cprintf to avoid gcc warning about assigning const pointer + to non-const (discarding type qualifier) + +{make_cmd,pcomplete,test}.c,parse.y + - some minor changes to shut up gcc warnings + +lib/sh/tmpfile.c + - fixed sh_mktmpfp to avoid file descriptor leaks in the case that + sh_mktmpfd succeeds but fdopen fails for some reason + - change sh_mktmpfd to use the same scheme for computing `filenum' + as sh_mktmpname + - change get_sys_tmpdir to prefer P_tmpdir if P_tmpdir is defined + - changed sh_mktmpname and sh_mktmpfd to avoid trying to assign to + `nameroot' if `nameroot == 0' (duh) + - add code to sh_mktmpfd to use mkstemp(3) if USE_MKSTEMP is defined + - add code to sh_mktmpname to use mktemp(3) if USE_MKTEMP is defined + +support/{fixlinks,mkclone} + - use mktemp if it's available for the symlink test + - use $TMPDIR instead of hardcoding /tmp; default to /tmp + - use a better filename for the symlink test instead of `z' + +support/bashbug.sh + - more changes inspired by a patch from solar designer + +lib/malloc/Makefile.in + - new target `alloca', which builds libmalloc.a with alloca.o only + (for systems without alloca that are configured --without-bash-malloc) + +configure.in + - if we don't have a working alloca and are not configured to build + the bash malloc library, make a malloc library containing only + alloca.o + +aclocal.m4 + - slight change to RL_LIB_READLINE_VERSION to deal with minor version + numbers with a letter appended (like 4.2a) + + 10/31 + ----- +doc/{bash.1,bashref.texi} + - slight change to note that only interactive shells resend a SIGHUP + to all jobs before exiting + +externs.h + - declare strto[ui]max only if NEED_STRTOIMAX_DECL is defined. This + keeps picky compilers from choking because intmax_t is not defined + (MacOS X 10.1) + +builtins/printf.def + - #define NEED_STRTOIMAX_DECL before including shell.h + + 11/1 + ---- +general.c + - check in bash_tilde_expand() for an unquoted tilde-prefix; don't + bother passing the string to tilde_expand unless the prefix is + unquoted + +shell.c + - fix a problem with $LINENO when executing commands supplied with + the -c invocation option when ONESHOT is defined + +[bash-2.05a-rc1 frozen] + +builtins/printf.def + - fix the %n conversion to require that the variable name supplied + be a valid shell identifier + +variables.c + - improve random number generator slightly by using the upper 16 + bits of the running random number instead of the lower 16, which + are incrementally more random + + 11/2 + ---- +configure.in + - if RL_INCLUDEDIR ends up being /usr/include, don't put + -I$(RL_INCLUDEDIR) into CFLAGS + + 11/5 + ---- +doc/{bash.1,bashref.texi} + - correct description of POSIXLY_CORRECT to note that the shell enters + posix mode *before* the startup files are read if POSIXLY_CORRECT + is in the initial environment + +variables.c + - fix function prologues for init_dirstack_var and init_groups_var + to agree with caller (no arguments) + +jobs.c + - fix forward function declarations for pipe_read and pipe_close + +subst.c + - removed `inline' attribute from skip_double_quoted because it can + potentially be called recursively + +bashline.c + - quick fix to bashline.c:attempt_shell_completion programmable + completion code to just punt if the end of the command word found + by find_cmd_end is <= the start found by find_cmd_start (the bug + is probably in find_cmd_start -- fix later) + +pcomplete.c + - fix gen_matches_from_itemlist to return if the stringlist is null + after any cleaning or initialization, before trying to use it + - fix GEN_COMPS to only bother to try to append the STRINGLIST + returned by gen_matches_from_itemlist to `glist' if it's non-NULL + +lib/sh/stringlist.c + - make copy_stringlist return NULL if the STRINGLIST * passed as an + argument is NULL + - make append_stringlist call copy_stringlist only if M2 is non-NULL; + otherwise just return NULL if m1 is NULL + - make word_list_to_stringlist return 0 immediately if the passed + LIST argument is NULL + - make realloc_stringlist call alloc_stringlist if the passed + STRINGLIST argument (`sl') is 0, just like realloc calls malloc + +subst.c + - in skip_to_delim(), if we have an unclosed ${, and it's at the end + of the string (string[i] == '{', string[i+1] == '{' and + string[i+2] == 0, return si (i +2) immediately without bothering + to call extract_dollar_brace_string or extract_delimited_string + - in skip_to_delim(), if string[i] is 0 after a call to + extract_dollar_brace_string or extract_delimited_string (meaning we + have an unclosed ${ or other expansion, return i immediately without + doing a `continue' (which will increment i past the end of string) + - in split_at_delims, don't increment te by 1 if it's pointing to a + delimiter. this has the effect of skipping the first delimiter + char in a possibly multi-character delimiter, and ignoring + single-char delimiters like `>' + +configure.in + - use AC_CHECK_MEMBERS([struct stat.st_blocks]) instead of a call to + AC_STRUCT_ST_BLOCKS to avoid configure changing LIBOBJS if the test + fails + +general.c + - introduce two new variables: bash_tilde_{prefixes,suffixes}, set + to the additional prefixes and suffixes bash wants to pass to the + tilde expansion code (reserved for post-bash-2.05a fix) + +aclocal.m4 + - add missing `test' in BASH_CHECK_SYS_SIGLIST + + 11/7 + ---- +lib/readline/vi_mode.c + - fix rl_vi_goto_mark to explicitly check that the desired mark is + between 'a' and 'z', since some locales have lowercase letters + outside that range, which could cause a negative subscript + +include/chartypes.h + - remove superfluous `#undef ISASCII' + +lib/sh/strto[iu]max.c + - changes from Paul Eggert to work around buggy compilers and catch + configuration errors at compile time + +aclocal.m4 + - new macro, BASH_C_LONG_DOUBLE, identical to AC_C_LONG_DOUBLE but + with a fix for Irix 5.3 (not called, since I'm not sure it's the + right thing to do -- the C standard allows double and long double + to be the same size) + +lib/sh/snprintf.c + - only try to write the trailing NUL in vsnprintf_internal if + data->length is >= 0, since if it's not, we probably don't have + a buffer + +Makefile.in + - changed RELSTATUS to `release' + + 11/8 + ---- +lib/sh/strtol.c + - make sure chars passed to toupper are cast to unsigned + +unwind_prot.c + - change clear_unwind_protect_list to not require a cast from `int' + to `char *' + +lib/readline/chardefs.h + - make _rl_digit_p succeed only for ascii digits, since that's what + most callers assume + + 11/13 + ----- +doc/bashref.texi + - added `ERR' trap and [-+]O invocation option to section listing + differences from the Bourne shell + + 11/15 + ----- +[bash-2.05a released] + + 11/19 + ----- +include/stdc.h + - new define, INLINE, defined as `inline' for gcc and empty otherwise + +subst.c + - make skip_double_quoted, sub_append_string have INLINE attribute + +trap.c + - use BASH_NSIG as upper limit for signal names in signal_name() + +lib/readline/bind.c + - use RL_COMMENT_BEGIN_DEFAULT in output for rl-comment-begin value + +error.c + - fix sys_error to save value of errno around calls to fprintf + +doc/Makefile.in + - added rules to create PDF files from postscript and dvi input + +MANIFEST.doc + - added {article,bash,bashref,rose94}.pdf + +doc/bash.1 + - rearranged some `.PD 0' and `.TP' directives so man2html will + handle them better (shouldn't affect groff output) + +support/man2html.c + - small fix to handle quoted string arguments to directives like + `.BR' without mangling the output + + 11/20 + ----- +{arrayfunc,variables}.c + - changed calling sequence for dynamic array variable `assign' + functions to (SHELL_VAR *self, char *value, arrayind_t ind) + - changed calling sequence for dynamic variable assign functions + to the same as array variable assign_func. Now this can be + prototyped + +variables.h + - the assign_func member of a `struct variable' is now of type + `sh_var_assign_func_t', which is prototyped + - the dynamic_value member of a `struct variable' is now of type + `sh_var_value_func_t', which is prototyped + +variables.c + - changed to use `sh_var_assign_func_t' and `sh_var_value_func_t' + +builtins/cd.def + - when in posix mode, if the new directory name formed by PWD and + the argument passed by the user cannot be canonicalized, and the + -P option has not been supplied, return failure immediately + - if canonicalization failed, but the fallback to the directory + name specified by the user succeeds, reset the current working + directory + +lib/readline/{input.c,rlprivate.h} + - renamed rl_unget_char to _rl_unget_char; made library global + +lib/readline/{{bind,readline}.c,{keymaps,rlprivate}.h} + - support for `key subsequences'; allows a key sequence and a function + mapped to a subsequence of that key sequence. Primarily to allow + arrow keys to be bound in readline vi insert mode, while preserving + the ESC function to switch to command mode. + +lib/readline/{input.c,rlprivate.h} + - new function, _rl_input_queued(T), does a check with select or + FIONREAD with a timeout of `T' (which is generally 0) + +lib/readline/readline.c + - change _rl_dispatch_subseq to test for input in the queue if we + get ESC while in vi insertion mode if the keymap entry type for + ESC is ISKMAP. If _rl_input_queued returns non-zero, we assume + that an arrow key sequence has been pressed and go ahead with the + subsequence. If it returns zero, we assume that the user pressed + ESC to switch into command mode, and dispatch to that right away. + This avoids forcing the user to press another key before switching + into command mode + + 11/21 + ----- +lib/readline/readline.c + - bind common arrow key sequences in vi insertion keymap + +lib/readline/terminal.c + - bind termcap definition's arrow keys in vi insertion keymap + +lib/readline/bind.c + - check for rl_vi_movement_mode in _rl_bind_if_unbound, so + binding the arrow keys can work + +lib/readline/readline.c + - since _rl_bind_if_unbound does the check of what's currently + bound to the key sequence, the check in bind_arrow_keys_internal + was redundant + - bind_arrow_keys_internal now takes a Keymap argument and handles + saving and restoring _rl_keymap; changed bind_arrow_keys + accordingly + +builtins/fc.def + - fix from Paul Eggert to substitute the nearest history number in + range if an out-of-range value is supplied. POSIX requires this + +lib/sh/pathcanon.c + - fix from Corrina Vinschen for the special `cygdrive' prefix on + Cygwin + +bashhist.c + - split the history adding code into more pieces: + check_history_control (char *line) checks LINE against the value + of HISTCONTROL, returning 1 if LINE should be saved and 0 if not + + check_add_history (char *line) calls check_history_control and + history_should_ignore (line) and saves the line with + bash_add_history if the checks indicate that it should be saved + + maybe_add_history just calls check_add_history to set the value + of first_line_saved + +bashhist.h + - extern declaration for check_add_history() + +shell.c + - don't call load_history() from the interactive shell startup + code if history_lines_this_session is > 0, indicating that we've + already saved some lines in the history and that we probably + don't want to overwrite them + +builtins/history.def + - call check_add_history from push_history, so `history -s xx' + works even when in a compound command whose first line has not + been saved. (Caveat: in a compound command when the first + line has been saved, the line supplied to history -s will become + part of the compound command's history entry. Of course, the + delete_history call could remove the compound command from the + history entirely) + +bashline.c + - use sh_makepath instead of xmalloc/sprintf in + command_word_completion_function + +lib/readline/complete.c + - get_y_or_n now takes an int FOR_PAGER argument; caller changed + If FOR_PAGER is non-zero, get_y_or_n returns appropriate values + for a more-like pager: `newline' or `return' return 2; `q' or + `Q' return 0 + - there is now a mini internal more-like pager for displaying a + list of completions that exceeds the screen height (new function + _rl_internal_pager, called from rl_display_match_list) + + 11/24 + ----- +command.h + - new flag, W_TILDEEXP, says to do tilde expansion on an + assignment word + +execute_cmd.c + - fix_assignment_words now sets W_TILDEEXP for assignment word + arguments to `assignment builtins' + +general.c + - bash_tilde_expand now takes a second argument indicating whether + or not it's being invoked in an `assignment context' + +general.h + - change extern declaration for bash_tilde_expand + +{bashline,execute_cmd,findcmd,general,variables}.c +builtins/evalfile.c +lib/sh/makepath.c + - fix callers of bash_tilde_expand appropriately + +subst.c + - fix callers of bash_tilde_expansion appropriately + - add (currently commented-out) code that would tilde expand assignment + statement arguments to assignment builtins (W_TILDEEXP flag set) + even when the shell is in posix mode + +bashline.c + - fix attempt_shell_completion to turn off + rl_filename_completion_desired when doing command name completion, + so no slash gets appended to the name if there happens to be a + directory with the same name in the current directory + + 11/26 + ----- +lib/readline/rltech.texinfo + - a couple of additions to the rl_stuff_char description + +parse.y + - turn off echo_input_at_read in parse_string_to_word_list, so `set -v' + doesn't give extra lines of output when doing compound array + assignment + +subst.c + - fix split_at_delims to handle skipping over a `\n' if it's a + delimiter (use spctabnl(c) instead of whitespace(c)) + + 11/27 + ----- +support/config.{guess,sub} + - updated (with bash changes) to latest version from gnu.org + +sig.h + - add prototype for set_signal_handler declaration + +builtins/setattr.def + - add prototype to extern declaration of declare_builtin + +builtins/times.def + - add no_options call, since times takes no options + +lib/sh/spell.c + - add prototypes to forward declarations for midist and spdist + +lib/sh/strtrans.c + - add explicit int return type to ansic_shouldquote declaration + +lib/readline/rldefs.h, lib/readline/{macro,readline,util,undo}.c + - move define for SWAP to rldefs.h, removed from various C files + +lib/readline/vi_mode.c + - removed define for exchange(), changed to use SWAP instead + +lib/readline/bind.c + - added some static forward function declarations + - find_boolean_var, find_string_var now take a `const char *' argument + +lib/readline/signals.c + - added static forward declaration for rl_maybe_set_sighandler + +lib/readline/readline.c + - add some common key bindings for the HOME and END keys in + bind_arrow_keys_internal + +lib/readline/terminal.c + - fetch the `@7' termcap string; it's sent by the END key + - attempt to bind the terminal's END key to rl_end_of_line in + bind_termcap_arrow_keys; I don't know why I was using `kH' + instead of `@7' + +doc/builtins.1 + - remove `case', `for', `if', `until', `while' from NAME section; + those are not shell builtins + + 11/28 + ----- +stringlib.c + - new function, find_token_in_alist, takes a token value and an + ALIST argument, and returns the string correspoinding to the + token if found in the alist + +externs.h + - new extern declaration for find_token_in_alist() + +subst.c + - string_list_internal is no longer static + +subst.h + - new extern declaration for string_list_internal() + +parse.y + - new alist array of other tokens returned by read_token which are + not reserved words in word_token_alist[] + - reworked error reporting: new functions print_offending_line, + which prints the line containing the syntax error, + error_token_from_token, which takes the current token and tries to + figure out its textual representation, and error_token_from_text, + which does the old job of finding the bad token by analyzing the + text of shell_input_line at the current index + - report_syntax_error now tries to figure out the token that caused + the syntax error by first looking at current_token and falling + back to the old method of textual analysis if that fails + - report_syntax_error doesn't say the token resulting from the textual + analysis of the input line is an `unexpected token'; it just + says there is a `syntax error near xxx' + - changed conditional command error reporting to use the value + returned by error_token_from_token if it's not null instead of + just using the token value in the message, since current_token + ends up being set to -1, and the text of the message from + report_syntax_error might not be exactly right + - change parse_string_to_word_list to set current_token to the + offending token returned by read_token before calling yyerror() + to make the error reporting do the right thing + +aclocal.m4 + - fixed typo in BASH_CHECK_LIB_TERMCAP + +configure.in + - add check for isinf(3); define HAVE_ISINF_IN_LIBC if found + +config.h.in + - add define for HAVE_ISINF_IN_LIBC + +lib/sh/snprintf.c + - check for Inf and NaN, using isinf and isnan if they're found in + libc + - use the current locale for thousands separator and decimal point + - recognize "'" flag; not implemented yet + - fix for snprintf/vsnprintf with length of 0 and string argument of + 0 with non-zero length + +builtins/read.def + - TMOUT is now the default timeout for `read' (and select) if set, + like ksh93 when reading from the terminal + - edit_line (called by read -e) now just does readline's filename + completion by setting rl_attempted_completion_function to NULL, + since e.g., doing command completion for the first word on the + line wasn't really useful + +execute_cmd.c + - changed select_command to return failure status if select_query + returns NULL, indicating that read_builtin returned + EXECUTION_FAILURE + +doc/{bash.1,bashref.texi} + - documented new TMOUT behavior + - slight change to the description of the test `-ef' option + +doc/bashref.texi + - added item to posix mode section describing failure behavior of + cd when invoked in logical mode and the pathname formed by + combining $PWD and the directory argument does not refer to an + existing directory + + 11/29 + ----- +execute_cmd.c + - fix execute_function to call dispose_function_env after + merge_function_env if the shell is in posix mode (fixes debian + bash bug #117673) + +lib/readline/readline.c + - rl_forward -> rl_forward_char; rl_forward function for compatibility + - rl_backward -> rl_backward_char; rl_forward function for + compatibility + - new functions, rl_forward_byte, rl_backward_byte, for future use + +lib/readline/readline.h + - extern declarations for rl_forward_char, rl_backward_char, + rl_forward_byte, rl_backward_byte + +lib/readline/{emacs_keymap,funmap,vi_keymap,vi_mode + - rl_forward -> rl_forward_char + - rl_backward -> rl_backward_char + +lib/readline/funmap.c + - new bindable names, `backward-byte' and `forward-byte' + +aclocal.m4 + - new function, BASH_CHECK_MULTIBYTE, encapsulates checks for + multibyte code + +config.h.in + - add necessary defines for multibyte include files and functions + +configure.in + - add call to BASH_CHECK_MULTIBYTE + +config-bot.h + - add code to define HANDLE_MULTIBYTE if prerequisites are met + +lib/sh/xstrchr.c + - new file, xstrchr() is strchr(3) that handles multibyte characters + +bashhist.c + - first_line_saved -> current_command_first_line_saved; variable is + now global + +bashhist.h + - extern declaration for current_command_first_line_saved + + 11/30 + ----- +bashhist.c + - break the code that actually calls add_history out of + bash_add_history into a new function, really_add_history; + bash_add_history now calls really_add_history + - check_add_history takes a second `force' argument telling it + whether to call bash_add_history (force == 0) or really_add_history + (force != 0) + +builtins/history.def + - in push_history, call delete_last_history if the current command + has more than one line, the first line was saved, and + command-oriented history is active. This takes care of deleting + the right history element if `history -s' is used within a + compound or multiline command + - in push_history, call check_add_history with second argument of 1 + to skip check of current_command_line_count and add the arguments + to history -s as a single separate history entry + + 12/3 + ---- +lib/readline/complete.c + - append a slash to completed names which are symlinks to directories + if the new variable _rl_complete_mark_symlink_dirs is non-zero + +lib/readline/rlprivate.h + - extern declaration for _rl_complete_mark_symlink_dirs + +lib/readline/bind.c + - new bindable variable, `mark-symlinked-directories', mirrors the + value of _rl_complete_mark_symlink_dirs + +doc/bash.1, lib/readline/doc/{readline.3,rluser.texinfo} + - documented new `mark-symlinked-directories' variable + + 12/4 + ---- +variables.[ch] + - set_pipestatus_array now takes a second argument with the number + of processes in the array + - changed set_pipestatus_array to just modify the value in place if + the existing array has one element and the new array has one + element, and to modify existing values in place if new array has + more elements than existing array + +variables.c, jobs.c + - changed set_pipestatus_array callers + +jobs.c + - moved call to setjstatus() from set_job_status_and_cleanup to + wait_for, since set_job_status_and_cleanup is part of the SIGCHLD + signal handler call path, and race conditions accessing the + PIPESTATUS array will result for things like + + while true; do date; done | cat > /dev/null + + 12/5 + ---- +xmalloc.h + - don't redefine xmalloc, xrealloc, and xfree if DISABLE_MALLOC_WRAPPERS + is #defined + +config.h.in + - #undef for DISABLE_MALLOC_WRAPPERS + +configure.in + - define DISABLE_MALLOC_WRAPPERS if the --with-purify option is + supplied + +lib/malloc/trace.c + - new function, malloc_trace_bin(N), traces allocations and frees + to bucket N (uses the same type of bitmap as `busy') + +lib/malloc/table.c + - fix wraparound search problem in find_entry when searching for a + free entry when the table is full + + 12/6 + ---- +lib/malloc/table.c + - keep an `overflow bucket' around to use when the table is full, + so find_entry always returns a valid pointer when FIND_ALLOC + is set + - new static variable to keep a count of the number of MT_ALLOC + entries in the mem_table + +lib/sh/{oslib,clktck}.c + - if HAVE_LIMITS_H is defined, include <limits.h> + +lib/sh/oslib.c + - new function, getmaxgroups() returns max number of simultaneous + groups + - new function, getmaxchild(), returns max number of simultaneous + user processes + +general.c + - removed forest of #defines for getmaxgroups() + +externs.h + - new extern declaration for getmaxgroups() + - new extern declaration for getmaxchild() + - new extern declaration for isnetconn() + +lib/sh/netconn.c,shell.c + - new file, isnetconn() from shell.c moved here + +Makefile.in, lib/sh/Makefile.in + - necessary changes for netconn.c + +builtins/ulimit.def + - changed getmaxuprc() to just call getmaxchild() and massage the + return value appropriately + +{jobs,nojobs}.c + - use the value returned by getmaxchild() in + mark_dead_jobs_as_notified instead of static CHILD_MAX + +jobs.c + - new function, compact_jobs_list, removes some number of jobs from + the jobs table and reallocates the table, copying the jobs that + are left from the old table to the new. Compaction happens from + the beginning of the list and removes dead jobs, and we make sure + to keep the last CHILD_MAX jobs as POSIX.2 requires + - call compact_jobs_list from stop_pipeline if we're in a subshell, + there are no free jobs in the jobs table, and the jobs table is + at or above some maximum limit + +execute_cmd.c + - change eval_arith_for_expr to set this_command_name to `((' before + calling evalexp, since it might be changed by evaluating the + loop body between evalexp calls + +trap.c + - change reset_signal to turn off the SIG_TRAPPED flag for the + given signal, so shell builtins and functions running in command + substitutions don't run the signal handlers (traps are not supposed + to be inherited by command substitutions) + +parse.y + - changed parse_string_to_word_list to turn off alias expansion + while parsing the array assignment + + 12/9 + ---- +alias.c + - fix add_alias so that redefining an alias's value also resets the + EXPANDNEXT flag + + 12/10 + ----- +parse.y + - new function, token_is_assignment, called to check whether the text + before `=' makes up a valid assignment token before trying to parse + a compound assignment statement + - new function, parse_compound_assignment, to parse a compound + assignment statement instead of using parse_matched_pair; handles + comments and error reporting in the parser instead of waiting until + expansion time + - changed parse_compound_assignment and parse_string_to_word_list to + allow reserved words in compound array assignments + +lib/readline/doc/rltech.texinfo + - changed the documentation for rl_callback_read_char and + rl_callback_handler_remove to say what happens to the terminal + settings and what needs to be done to reset them + + 12/11 + ----- +bashline.c + - add emacs_edit_and_execute_command, bound to C-xC-e, like vi-mode + `v' command + - add bindable command name `edit-and-execute-command', bound to + run emacs_edit_and_execute_command() + +lib/glob/strmatch.c + - add support for ksh93-like [:word:] character class (isalnum + `_') + +doc/{bash.1,bashref.texi} + - add note to section describing lists to clarify that a sequence of + one or more newlines may be used to delimit a command, equivalent + to a semicolon + - document new [:word:] pattern matching character class + +doc/bash.1, lib/readline/doc/rluser.texinfo + - document `edit-and-execute-command' and its default emacs-mode + binding + +include/chartypes.h + - add defines for TOCTRL and UNCTRL if they're not already defined + +lib/readline/chardefs.h + - #undef UNCTRL if it's defined to avoid cpp redefinition warnings + +lib/sh/strtrans.c + - add \cX (Control-X) escape for $'...' to ansicstr() + - change ansic_quote() to allocate at least four chars for each char + in the string argument, to account for \0xx octal values + - change ansic_quote() to no longer call sprintf for non-printable + characters; just translate the string to octal directly + +print_cmd.c + - change xtrace_print_word_list to call ansic_quote() if + ansic_shouldquote() indicates that there are nonprinting characters + in a word + +builtins/type.def + - changed deprecated long option parsing to just replace the word + in the list with the equivalent short option (-type -> -t) instead + of removing words from the list + - changed describe_command to take a single flags argument instead + of two int args; changed caller + - type now has two new options: -f suppresses function lookup (like + command), and -P forces a PATH search for the name(s) + +builtins/common.h + - flags for describe_command are here + - changed extern declaration of describe_command + +builtins/command.def + - changed call to describe_command to use flags from common.h, and + the right number of arguments + +doc/{bash.1,bashref.texi} + - documented new -f and -P options to `type' + + 12/12 + ----- +lib/readline/rldefs.h + - fixed prototype for _rl_strnicmp + +execute_cmd.c + - select_query now takes a new argument, an int flag saying whether + or not to print the menu the first time through the loop. An + empty line in response to the prompt will always cause the menu + to be reprinted + - changed execute_select_command to cause select_query to reprint + the menu only if REPLY is set to NULL, if KSH_COMPATIBLE_SELECT + is defined + +config-top.h + - define KSH_COMPATIBLE_SELECT, with a comment about its meaning + +lib/readline/readline.c + - change rl_insert_comment to toggle if given an explicit numeric + argument: if the first characters on the line don't specify a + comment, insert one; if they do, delete the comment text + +doc/bash.1, lib/readline/doc/{readline.3,rluser.texinfo} + - documented new behavior of insert-comment with a numeric argument + + 12/13 + ----- +lib/malloc/watch.c + - new file, implements watchpoint functions + +lib/malloc/watch.h + - new file, define some `events' for watchpoints and extern function + and variable declarations for watchpoint code + +lib/malloc/imalloc.h + - #define MALLOC_WATCH if MALLOC_DEBUG is defined + - add __P define as in include/stdc.h if not already defined + +lib/malloc/malloc.c + - remove __P define, now in imalloc.h + - include watch.h if MALLOC_WATCH is defined + - added calls to _malloc_ckwatch in internal_malloc, internal_free, + and internal_realloc + +include/stdc.h + - augment __P define to allow prototypes if PROTOTYPES is defined + +lib/readline/rlstdc.h + - augment PARAMS define to allow prototypes if PROTOTYPES is defined + +lib/malloc/Makefile.in, Makefile.in + necessary changes to include watch.c in libmalloc + +lib/readline/readline.c + - fix rl_delete_text to make sure that the starting position is >= 0 + - _rl_init_line_state (called by readline via readline_initialize) + now sets rl_mark to 0 + - rl_get_{next,previous}_history set rl_mark to 0 if rl_point is at + the end of the line and rl_end otherwise in emacs mode + +lib/readline/kill.c + - rl_yank_nth_arg_internal and rl_paste_clipboard now set the mark + at point before calling rl_insert_text, like rl_yank + - rl_kill_full_line now resets rl_mark to 0 + - rl_kill_line and rl_backward_kill_line now set rl_mark to the + point after the kill in emacs mode + - rl_kill_word and rl_backward_kill_word now set rl_mark to the + point after the kill in emacs mode + - rl_unix_word_rubout and rl_unix_line_discard now set rl_mark to + the point after the kill in emacs mode + +lib/readline/search.c + - noninc_search saves and restores the mark, since it can be changed + while reading the search string + - noninc_dosearch sets the mark at the end of the line, making the + region bound the `inserted' text since rl_point is set to 0 + - rl_history_search_internal sets the mark at the end of the line, + for the same reason + +lib/readline/isearch.c + - rl_search_history now saves and restores the mark + - if no matching lines are found at all when doing an isearch, leave + point where it was instead of moving it to the end of the line + + 12/17 + ----- +lib/readline/rlmbutil.h + - new file, place for multi-byte character defines and extern + declarations + +lib/readline/{bind.c,readline.c,rlprivate.h} + - new bindable variable, `byte-oriented', tracks value of + rl_byte_oriented variable + +lib/readline/mbutil.c + - new file, with multibyte char utility functions + +lib/readline/{complete,display,readline,util,vi_mode}.c + - new code for multibyte characters, derived from IBM patch + + 12/18 + ----- +lib/sh/tmpfile.c + - include posixtime.h for time() extern declaration + +support/bashversion.c + - include <unistd.h> if it's available + +lib/readline/{histexpand,input,isearch,search}.c + - new code for multibyte characters, derived from IBM patch + +lib/readline/readline.h + - include rltypedefs.h + + 12/19 + ----- +lib/readline/complete.c + - slight change to mark-directories code to avoid adding a slash if + point is at the end of the line (rl_line_buffer[rl_point] == '\0') + and the previous character was a slash + - change printable_part to not return empty pathnames, which could + happen when completing filenames and a filename with a trailing + slash was passed as the argument. If the portion following the + trailing slash is NULL, ignore it and look for a previous slash. + If there's no previous slash, just return the filename argument + - new variable, rl_completion_mark_symlink_dirs, mirrors the value + of (user-settable with a variable) _rl_complete_mark_symlink_dirs + but may be modified by application-specific completion functions + when appropriate (set in rl_complete_internal and rl_menu_complete) + +lib/readline/readline.h + - extern declaration for rl_completion_mark_symlink_dirs + +pcomplete.c + - if one of the actions is CA_DIRECTORY, set + rl_completion_mark_symlink_dirs to indicate that we want the + trailing slash (might have to relax this) + +lib/readline/doc/rltech.texinfo + - documented rl_completion_mark_symlink_dirs variable + +lib/readline/doc/rluser.texinfo, doc/bash.1 + - documented the fact that `complete -d' and `complete -o dirnames' + force readline to append a slash to symlinks to directories + +builtins/enable.def + - changed enable_shell_builtin to disallow enabling disabled + builtins in a restricted shell + +doc/{bash.1,bashref.texi} + - documented new enable behavior in restricted shells + +doc/Makefile.in + - new rule to make an `RBASH' file documenting the restrictions + imposed by a restricted shell + +expr.c + - broke the code that evaluates variables and returns results out + of readtok() into a new function: expr_streval() + - expr_streval() now performs the standard unset variable error + behavior if `set -u' has been executed and it's asked to look + up an unset variable + - broke the code that frees up the expression context stack into + a new function: expr_unwind() + +variables.c + - fixed bind_int_variable so it handles array element assignment, + so expressions like `b[7]++' and `b[0] = 42' work right + - new function, get_variable_value, returns the string value of + the SHELL_VAR * passed as an argument + - get_string_value now calls get_variable_value with a non-null + result from find_variable + + 12/20 + ----- +lib/readline/rlmbutil.h, mbutil.c + - combined _rl_find_next_mbchar and _rl_find_next_nonzero_mbchar into + a single function + - combined _rl_find_prev_mbchar and _rl_find_prev_nonzero_mbchar into + a single function + +lib/readline/{display,readline,vi_mode}.c + - changed callers of _rl_find_next_mbchar and + _rl_find_next_nonzero_mbchar + +lib/readline/{complete,display,histexpand,readline,vi_mode}.c + - changed callers of _rl_find_prev_mbchar and + _rl_find_prev_nonzero_mbchar + + 12/20 + ----- +lib/sh/mktime.c + - new file, from glibc/gawk, compiled in if system doesn't have a + working mktime(3) + +lib/sh/strftime.c + - new file, from gawk, compiled in if system doesn't have a + working strftime(3) + +lib/sh/Makefile.in, Makefile.in + - changes for mktime.c, strftime.c + +configure.in + - call AC_FUNC_MKTIME, AC_STRUCT_TM, AC_STRUCT_TIMEZONE + - call AC_REPLACE_FUNC(strftime) + +config.h.in + - add defines for TM_IN_SYS_TIME, HAVE_TZSET, HAVE_TM_ZONE, + HAVE_STRUCT_TM_TM_ZONE, HAVE_STRFTIME + +externs.h + - provide an extern declaration for strftime if HAVE_STRFTIME is + not defined and NEED_STRFTIME_DECL is + +lib/tilde/tilde.h + - header files should not include <config.h> + +parse.y + - replace code in decode_prompt_string that chops up value returned + by ctime(3) with calls to strftime -- as a result, the expansion + of \@ has changed slightly (since it depends on the locale) + - added new \D{format} prompt string escape; `format' is passed to + strftime(3). Empty format is the same as `%X' (locale-specific + representation of the current time) + - combined cases for '\\', '\a', '\e', and '\r' in same case branch + in decode_prompt_string + +doc/{bash.1,bashref.texi} + - documented new \D{format} prompt string expansion + +builtins/printf.def + - use ISO C PRIdMAX instead of INTMAX_CONV + - pass length of format modifiers to mklong instead of computing it + with strlen() + +lib/sh/{fmtulong,fmtullong}.c + - changes from Paul Eggert to make more general + +arrayfunc.c + - when converting a variable to an array, make sure to unset the + dynamic_value and assign_func members of the struct variable, + since they're not valid anymore + + 12/27 + ----- +configure.in + - use AC_HELP_STRING in AC_ARG_WITH and AC_ARG_ENABLE + - remove AC_ARG_ENABLE for largefile, since AC_SYS_LARGEFILE adds + one + + 1/2/2002 + -------- +{alias,bashline,execute_cmd,general,shell,subst,variables,arrayfunc}.c,general.h + - changed some calls to strchr to calls to xstrchr for multibyte + characters + +include/shmbutil.h + - add extern declaration for xstrchr to avoid including externs.h + where it's not appropriate + +{braces,make_cmd,pathexp,subst,arrayfunc}.c, lib/sh/xstrchr.c + - include shmbutil.h + +{stringlib,subst}.c, {externs,subst}.h + - moved substring() from subst.c to stringlib.c, moved declaration + from subst.h to externs.h + +lib/sh/xmbsrtowcs.c + - new file, replacement function for mbsrtowcs + +lib/sh/Makefile.in + - add entries for xmbsrtowcs.c + +Makefile.in + - add dependencies on shmbutil.h to appropriate object files + +lib/glob/strmatch.c + - break character-class testing out into separate function: + is_cclass, in prep for multibyte changes + +{braces,make_cmd}.c + - changes for multibyte characters + +builtins/printf.def + - changes from Paul Eggert to just use intmax_t everywhere an + int/long/quad is needed and print with "%ld" if the number + fits in a long and %PRIdMAX otherwise + - remove getlong, getulong, getllong, getullong, since they're + no longer needed + - use a new type `floatmax_t' to print floating point numbers, the + widest-available floating point type (like `intmax_t'); new + function `getfloatmax' that calls strtold or strtod as appropriate + - remove getdouble, getldouble, since they're no longer needed + +lib/sh/fmtumax.c + - new file, string-to-[u]intmax_t conversion, just includes + fmtulong.c with the right defines + +Makefile.in, lib/sh/Makefile.in + - additions for fmtumax.c + +bashtypes.h + - include <inttypes.h> if it's available + +expr.c + - arithmetic is now in intmax_t instead of long + +externs.h + - extern declaration for fmtumax + - change extern declarations for evalexp, itos, inttostr, + uitos, uinttostr since they now return or use intmax_t instead + of long + +{execute_cmd,general,mailcheck,subst,variables}.c, parse.y +{array,general,subst,test,variables}.h +lib/sh/{itos,netopen}.c +builtins/{bashgetopt,common}.c, builtins/common.h +builtins/{break,fc,history,jobs,let,printf,pushd,read,shift,wait}.def + - changes for intmax_t shell arithmetic conversion + +doc/{bashref.texi,bash.1} + - documented long->intmax_t shell arithmetic conversion + +sig.c + - in initialize_terminating_signals, if we've already trapped a + terminating signal, don't reset the signal handler for it + + 1/3 + --- +{arrayfunc,pathexp}.c, parse.y + - changes for multibyte chars + +parse.y, lib/sh/strtrans.c + - moved ansiexpand from parse.y to lib/sh/strtrans.c + +parse.y, locale.c + - moved mk_msgstr and localeexpand from parse.y to locale.c + +parse.y + - new function, yy_input_name, returns name of input file from + bash_input.name + - broke the code that parses ((...)) constructs out of read_token + into a new function, parse_dparen() + +externs.h + - new extern declaration for ansiexpand(), mk_msgstr(), and + localeexpand() + +input.h + - new extern declaration for yy_input_name() + +{error,locale}.c + - use yy_input_name for error and other messages + +execute_cmd.c + - change shell_execve to make sure that the file is executable + before looking at the interpreter to find out why the execve() + failed (avoids misleading error message) + +lib/glob/glob.c + - move code that matches leading `.' and skips those filenames into + a separate function: skipname(), so there can be unibyte and + multibyte versions of that function + + 1/7 + --- +subst.c + - more changes for multibyte characters + +print_cmd.c + - change semicolon() so it doesn't output a `;' immediately after a + newline, since that results in a null command, which is a syntax + error + +variables.c + - fix indirection_level_string to turn off set -x while evaluating + PS4 + + 1/8 + --- +builtins/set.def + - make -o options into one struct, instead of separate structs for + option names corresponding to flags and non-flag option names. + This has the side effect of sorting the option names in output + +lib/glob/glob.c + - new function, mbskipname(), multibyte char version of skipname() + - removed all #ifndef SHELL code, this will never be used outside + the shell + +include/posixdir.h + - move REAL_DIR_ENTRY define here from lib/glob/glob.c + +lib/glob/glob_loop.c + - new file, included in glob.c for unibyte and multibyte versions of + glob_pattern_p + - added some forward static function declarations with prototypes + - more changes for multibyte character handling + +lib/glob/Makefile.in + - make glob.c depend on glob_loop.c + - changes for xmbsrtowcs.[co] + +lib/glob/xmbsrtowcs.c + - moved here from lib/sh, since the matching functions use it, and + libglob.a is linked after libsh.a + + 1/9 + --- +lib/glob/smatch.c + - new file, with strmatch (now xstrmatch) and associated functions, + with changes for multibyte chars + +lib/glob/sm_loop.c + - new file, included by smatch.c, with `generic' versions of matching + functions that are compiled twice: once each for single-byte and + multibyte characters + +lib/glob/strmatch.c + - strip out everything except strmatch(), which either calls fnmatch + (if HAVE_LIBC_FNM_EXTMATCH is defined) or xstrmatch + +lib/glob/collsyms.c + - changes for multibyte chars + +lib/glob/Makefile.in, Makefile.in + - changes for new source files + + 1/10 + ---- +lib/readline/complete.c + - new function, rl_completion_mode (rl_command_func_t *func), returns + the appropriate value to pass to rl_complete_internal depending on + FUNC and the value of `show-all-if-ambiguous'. This allows + application completion functions to present the same interface as + rl_complete + +lib/readline/readline.h + - new extern declaration for rl_completion_mode() + +lib/readline/doc/rltech.texinfo + - documented rl_completion_mode + +lib/readline/readline.[ch] + - bumped the version number to 4.3, changing the relevant cpp defines + +configure.in + - require that an installed readline version be at least readline-4.3 + +bashline.c + - converted bash-specific completion functions to use + rl_completion_mode instead of passing TAB unconditionally + +builtins/bashgetopt.c + - the `#' option specifier now means a required numeric argument, + not an optional one + +builtins/type.def + - when converting [-]-{path,type,all} to -[pta], don't bother + freeing and reallocating the option string; just change opt[1] + and null opt[2] + +lib/sh/snprintf.c + - support %ls/%S and %lc/%C for wide strings and characters, + respectively, if HANDLE_MULTIBYTE is defined + +mailcheck.c + - don't print a message about new mail if the file has not grown, + even if the access time is less than the modification time + + 1/14 + ---- +lib/readline/readline.c + - new function, rl_replace_line, to replace the readline line buffer + with the text supplied as an argument + - new function, rl_replace_from_history, replaces readline line + buffer with text from history entry passed as argument (undocumented, + not in readline.h because it requires a definition of + HIST_ENTRY for the prototype) + +lib/readline/readlne.h + - new extern declaration for rl_replace_line + +lib/readline/doc/rltech.texinfo + - documented rl_replace_line + +lib/readline/{isearch,readline,search}.c + - use rl_replace_line and rl_replace_from_history where appropriate + +lib/readline/readline.c + - broke the code that sets point after moving through the history + (_rl_history_preserve_point and _rl_history_saved_point) out + into a separate function, _rl_history_set_point() + +lib/readline/{complete.c,rlprivate.h} + - find_completion_word -> _rl_find_completion_word + - free_match_list -> _rl_free_match_list + +lib/readline/complete.c + - postprocess_matches and _rl_free_match_list now return immediately + if passed a null match list + +variables.c + - new function, find_local_variable, finds a local variable by name + at the current variable context + - in find_variable_internal, call find_local_variable before searching + any of the temporary environments if variable_context > 0 (meaning + we're in a shell function). This lets a local variable + override a variable whose value was passed in the `function + environment' + + 1/15 + ---- +variables.h, execute_cmd.c + - declare variables describing the temporary environments in + variables.h instead of in C files + +findcmd.c, builtins/setattr.def + - instead of calling find_tempenv_variable, use find_variable_internal + and check whether the returned SHELL_VAR * has the tempvar + attribute + +variables.c + - tentative change to lookup order in find_variable_internal so that + function local variables are found before variables in + function_env when executing a shell function + - change make_local_variable to handle making a local variable when + a variable with the same name already appears in one of the + temporary environments + - broke the body of make_var_array out into a new function: + static char **make_env_array_from_var_list (SHELL_VAR **vars) + - new function, make_var_array_internal, takes a hash table to look + in and a pointer to a mapping function and returns a char ** + environment-style list + - make_var_array now just calls make_var_array_internal + - new mapping function, local_and_exported, returns all local variables + in the current variable context with the export attribute set + - new function, make_local_export_array, returns an environment-style + char ** array of exported local variables in current context + - change environment creation order in maybe_make_export_env to + add variables to the environment in opposite order that + find_variable_internal uses. This means that local variables in + shell functions override variables with the same name in the + function_env + - change make_local_variable to set the initial value of the + variable it creates to NULL to make the `is set' and `is null' + tests that the expansion code does work right + - change make_local_variable to inherit the value of a variable with + the same name from the temporary enviroment + + 1/16 + ---- +Makefile.in + - link bashversion with buildversion.o instead of version.o, for + cross-compiling. version.o is for the target system; + buildversion.o is for the build system + +error.c + - add line numbers to internal_error() messages if the shell is + not interactive and running a shell script or a -c command + - report_error now prints non-zero line numbers for non-interactive + shells + +test.c + - test_syntax_error now calls builtin_error() instead of printing + its own messages + +builtins/common.c + - builtin_error now prints line numbers if a non-interactive shell + is running a shell script or a -c command + +print_cmd.c + - in cprintf, remove free_argp, since it's not used + +builtins/history.def + - make `history -n' increment the number of history lines in this + session by the number of lines read from the history file + +arrayfunc.c + - fix array_value_internal to expand the subscript even if the + variable is unset, so side effects produced by the arithmetic + evaluation will take place + +lib/readline/doc/{rluser,rltech}.texinfo + - some fixes for printing in @smallbook format from Brian + Youmans + + 1/17 + ---- +jobs.h + - new PRUNNING, PSTOPPED, PDEADPROC defines for PROCESSes, analogous + to RUNNING, STOPPED, and DEADJOB defines for jobs + +jobs.c + - use PS_RUNNING, PS_DONE, PS_STOPPED values for `running' field + of a PROCESS + - find_pipeline and find_job now take an additional flags argument + that, if non-zero, means to find only running processes; changed + all callers + - changed calls to find_pipeline and find_job made from waitchld + to find only running processes + - find_pipeline takes a third argument: an int *. If it looks in + the jobs list to find the pid, and the arg is non-null, it passes + the job index back to the caller. Used to avoid calls to + find_pipeline immediately followed by find_job with the same PID + +nojobs.c + - a couple of changes to make sure that set_pid_status is never + called with a pid argument of 0 or -1 + +trap.c + - change trap_handler to longjmp to wait_intr_buf (set by wait_builtin) + if a signal is received for which a trap has been set during + execution of the wait builtin (need to include builtins.h and + builtins/builtext.h and declare some extern variables for the + right things to check) + - new variable to keep track of which signal caused the longjmp to + wait_intr_buf, set by trap_handler (wait_signal_received) + +builtins/wait.def + - set the return value of wait when a longjmp(wait_intr_buf, 1) is + done to 128 + wait_signal_received + +{jobs,nojobs}.c + - set wait_signal_received to SIGINT in wait_sigint_handler before + the longjmp(wait_intr_buf, 1) + + 1/18 + ---- +bashline.c + - turn off rl_filename_completion_desired when completing a command + name with a single match only if the first char of that match is + not a `/' + - if there are multiple identical matches for a command name in + attempt_shell_completion, turn off rl_filename_completion_desired + if the first char is not a `/' to avoid readline appending a + slash if there's a directory with the same name in the current + directory + + 1/22 + ---- +lib/readline/complete.c + - new variable, _rl_page_completions, to control whether we want to + run the internal pager when listing completions (defaults to 1) + +lib/readline/rlprivate.h + - extern declaration for _rl_page_completions + +lib/readline/bind.c + - new bindable variable, `page-completions', controls value of + _rl_page_completions + +lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 + - documented `page-completions' variable + +Makefile.in + - use $(INSTALL_SCRIPT) instead of $(INSTALL_PROGRAM) to install + `bashbug' + +aclocal.m4 + - fix small quoting problem in RL_LIB_READLINE_VERSION macro + +lib/readline/terminal.c + - fetch and save terminal's `vs' and `ve' cursor control attributes + - fetch and save terminal's `kI' attribute (string sent by Insert) + - new function, _rl_set_cursor, sets cursor to normal (insert mode) + or very visible (overwrite mode) + +lib/readline/readline.c + - new global variable, rl_insert_mode + - new function to toggle overwrite mode, rl_overwrite_mode + - each new line starts in insert mode + - switching to vi mode or emacs mode resets to insert mode + - reset cursor to normal before returning line + - _rl_replace_text now returns the number of characters inserted, + the return value from rl_insert_text + - new function, _rl_insert_or_replace_text (const char *string, int insert), + either inserts STRING or replaces the number of chars in STRING + with STRING starting at rl_point, depending on value of INSERT + - renamed rl_insert to _rl_insert_char, rl_insert just calls + _rl_insert_char with the same arguments when in insert mode + - new function, _rl_overwrite_char, handles self-insert in overwrite + mode. Does multibyte chars by reading an entire multibyte character + before entering overwrite loop + - new function, _rl_overwrite_rubout, handles RUBOUT when in + overwrite mode, called from rl_rubout + - new function, _rl_rubout_char, old body of rl_rubout; rl_rubout + calls this when not in overwrite mode + +lib/readline/readline.h + - extern declarations for rl_insert_mode and rl_overwrite_mode() + +lib/readline/rldefs.h + - define constants for values of rl_insert_mode + +lib/readline/rlprivate.h + - extern declarations for _rl_set_cursor and _rl_set_insert_mode + - change type of _rl_replace_text to return int + - extern declarations for _rl_insert_char, _rl_rubout_char + +lib/readline/funmap.c + - new bindable name `overwrite-mode', bound to rl_overwrite_mode + +lib/readline/rlconf.h + - define CURSOR_MODE if you want the cursor to show insert or + overwrite mode (only available if both `vs' and `ve' capabilities + are present) + +lib/readline/{complete,parens,readline,search,vi_mode}.c + - change calls to rl_insert to _rl_insert_char + +lib/readline/{readline,search}.c + - change calls to rl_rubout to _rl_rubout_char to avoid overwrite + mode problems + +lib/readline/vi_mode.c + - fix rl_vi_overstrike to just call _rl_overwrite_char, which + handles multibyte chars + +lib/readline/doc/{rluser.texinfo,readline.3}, doc/bash.1 + - document new `overwrite-mode' command + + 1/23 + ---- +lib/readline/readline.c + - return 0 immediately from rl_insert_text if the string to insert + is NULL or "" + +bashline.c + - if a numeric argument is given to one of the bash-specific glob + pattern completion functions (including TAB), append a `*' to + the word before generating matches + - in attempt_shell_completion, when doing glob completion, only + set the match list to NULL if rl_completion_type == TAB and + there is more than one completion. This permits listing completions + with double tabs and displaying ambiguous completions + - new function, bash_glob_complete_word, appends a `*' to the word + to be completed and then globs it. It uses a new filename + quoting function (bash_glob_quote_filename) to avoid quoting + globbing characters in the filename if there are no matches or + multiple matches + +lib/readline/complete.c + - set completion_changed_buffer to 0 in rl_complete_internal if + no matches were produced by the completion generator function + - new variable, rl_completion_suppress_append, suppresses appending + of rl_completion_append_character. Settable by application + completion functions, always 0 when application completion + functions are called (set to 0 by rl_complete_internal and + rl_menu_complete) + - broke the code that assigns default values to readline completion + variables out of rl_complete_internal and rl_menu_complete into + a new function, set_completion_defaults (int what_to_do) + +lib/readline/readline.h + - extern declaration for rl_completion_suppress_append + +lib/readline/doc/rluser.texinfo, doc/bash.1 + - documented behavior of glob-expand-word and glob-list-expansions + when supplied a numeric argument + - documented glob-complete-word + +lib/readline/doc/rltech.texinfo + - documented rl_completion_suppress_append + + 1/24 + ---- +lib/readline/text.c + - new file, text and character handling functions from readline.c + +lib/readline/misc.c + - new file, miscellanous bindable functions and their supporting + code from readline.c + +Makefile.in, lib/readline/Makefile.in + - changes for text.c, misc.c + +lib/readline/bind.c + - change ISKMAP case of rl_invoking_keyseqs_in_map to output + ESC as "\M-" instead of "\e" -- it's closer to the documentation + - change _rl_get_keyname to output ESC as \e instead of \C-[ + (it's easier to understand) + +pcomplete.h + - new flag, COPT_NOSPACE + +builtins/complete.def + - new `-o nospace' option for complete and compgen (though it doesn't + really do anything for compgen, since that doesn't hand anything + off to readline) + +bashline.c + - if a programmable completion specifies COPT_NOSPACE, set + rl_completion_suppress_append = 1 + +lib/readline/doc/rluser.texinfo + - documented new `-o nospace' option to complete and compgen + +doc/{bash.1,bashref.texi} + - documented $'\cX' escape sequence (forgot to before) + + 1/28 + ---- +variables.c + - make_new_variable now takes the HASH_TABLE * as its second + argument; changed callers + - new function, bind_variable_in_table, takes the HASH_TABLE * as + its third paramter; bind_variable calls bind_variable_in_table + with shell_variables as third argument + +variables.h + - new struct var_context, variable context (per-scope -- global, + function local, etc.) + +variables.[ch],builtins/common.[ch] + - moved functions that push and pop a variable context from + builtins/common.c to variables.c; move extern function + declarations to variables.h + - new function, all_local_variables + - variable_in_context is now static, used only by all_local_variables + +variables.[ch],execute_cmd.c + - push_context now takes the function name as an argument for + future use + - push_context takes an indication of whether or not the function is + executing in a subshell and saves the positional parameters only + if not in a subshell + - new functions for managing a stack of variable contexts and + scopes: new_var_context, dispose_var_context, push_var_context, + pop_var_context, push_scope, pop_scope + +builtins/declare.def + - call all_local_variables instead of map_over (...) in declare_internal + - don't call make_local_variable if we're looking at functions + ((flags_on & att_function) != 0), since it's wasted + - make sure VAR is set to NULL if check for variable_context fails + and we didn't just create or fetch a local variable in + declare_internal + - in non-function branch of declare_internal, only call find_variable + if VAR is NULL -- if it's not null, we just created or fetched a + local variable and don't need to do it again + + 1/29 + ---- +variables.[ch] + - the temporary environments (temporary_env, builtin_env, function_env) + are now HASH_TABLEs instead of argv-style arrays of strings (this + is an intermediate step on the way to the new lcc-inspired symbol + table scope structure) + - new internal attribute for variables: att_propagate. This means + to propagate the value out of the temporary environment up the + (for now implicit) chain of variable scopes when the containing + temporary environment is deleted + +variables.c + - assign_in_env now adds to the HASH_TABLE temporary_env instead + of making environment-style strings in an array of strings + - changed the way the temporary environments are merged into the + shell variable table to account for the new HASH_TABLE temp + environments + - changed the way the export environment is created due to the new + structure of the temporary environments + - new function, bind_variable_internal (name, value, table), binds + NAME to have VALUE in TABLE without searching the temporary + environments + - removed: shell_var_from_env_string, bind_name_in_env_array + - variable_in_context now checks the att_local attribute and makes + sure the variable is not invisible + - local_and_exported now makes sure the variable is not invisible + +execute_cmd.c + - we no longer need to copy the temporary environment to function_env + or builtin_env, we can simply use variable assignments + +{findcmd,subst,variables}.c, builtins/{declare,setattr}.def + - since variables from the temporary environments are no longer turned + into SHELL_VARs on the fly, don't dispose the SHELL_VAR returned + by find_variable or find_variable_internal + - need to savestring() the value returned by find_variable if it has + the tempvar attribute before calling bind_variable on it, because + bind_variable will search and bind into the temporary environments + and will free the old value before binding the new. For temporary + environments, these two pointers will be the same, and + bind_tempenv_variable will end up using freed memory + +builtins/{declare,setattr}.def + - set the att_propagate attribute when exporting or making readonly + variables from the temp environment (i.e., `var=value declare -x var' + or `var=value export var' sets the propagate attribute on the entry + for `var' in the temporary environment HASH_TABLE) + +lib/readline/isearch.c + - ^W when reading isearch string yanks the current word out of the + current line into the search string, skipping the portion already + matched + - ^Y when reading isearch string yanks the rest of the current line + into the search string, skipping the portion already matched + + 1/30 + ---- +{print_cmd,variables}.c + - moved indirection_level_string() from variables.c to print_cmd.c + +{externs,variables}.h + - moved extern declaration of indirection_level_string to externs.h + +{general,variables}.c + - moved assignment() from variables.c to general.c + +{general,variables}.h + - moved extern declaration of assignment() to general.h + +{externs,input}.h + - moved extern declaration of decode_prompt_string to externs.h + +print_cmd.c + - include flags.h, don't include stdc.h + +variables.c + - moved some functions around to group functions better + - changed new_shell_variable to explicitly initialize each member + of the created struct variable instead of calling bzero() + - make_new_variable now just calls new_shell_variable instead + of duplicating what it does + - removed some code in bind_function that duplicated what + new_variable does on the newly-created SHELL_VAR + - since there are no local function variables (functions are always + made at the global scope), kill_all_local_variables() doesn't + need to consider functions + + 1/31 + ---- +variables.c + - sort the array of special variables + - short-circuit the search in stupidly_hack_special_variables if + the passed name can't be found in the rest of the array + (that is, if name[0] < special_vars[i].name[0]) + +lib/readline/history.c + - unstifle_history() was returning values exactly opposite of + the documentation + +lib/readline/doc/{hsuser.texinfo,history.3} + - clarified the unstifle_history() documentation a little + + 2/4 + --- +variables.c + - in bind_variable, don't call bind_tempenv_variable after a + find_tempenv_variable succeeds -- just change the value inline. + There's no reason to look it up twice + - change makunbound to only call stupidly_hack_special_variables + if we're not unsetting a function + +variables.[ch] + - new function, unbind_function, like makunbound but doesn't mess + with previous contexts or calling stupidly_hack_special_variables + +builtins/set.def + - change unset_builtin to call either unbind_func or unbind_variable + +builtins/getopts.def + - call unbind_variable(name) instead of makunbound(name, shell_variables) + + 2/5 + --- +lib/glob/sm_loop.c + - use malloc instead of xmalloc in BRACKMATCH and handle failures + +error.c + - add extern declaration of executing_line_number with prototype, + since execute_cmd.h can't be included without including other + files + +lib/readline/parens.c + - include <unistd.h> + +lib/malloc/stats.c + - include <unistd.h> + - add extern declaration of malloc_free_blocks() with prototype + +pathexp.c + - added some forward declarations with prototypes for static functions + +lib/readline/rlprivate.h + - removed declarations of rl_untranslate_keyseq, rl_discard_argument, + rl_stop_output, rl_alphabetic since they appear in readline.h + + 2/6 + --- +{arrayfunc,execute_cmd,pcomplete,shell}.c + - change calls to makunbound(name, shell_variables) to + unbind_variable (name) + + 2/7 + --- +builtins/getopt.c + - don't defer incrementing of OPTIND when an invalid option is + encountered until the next call to sh_getopt() -- what if OPTIND + is reset before that next call? This means that OPTIND is always + incremented to the next option to be handled when an option is + returned, whether it's valid or not. This is what POSIX-2002 + says to do. + +syntax.h + - new #define, CSUBSTOP + +mksyntax.c + - add "-=?+" with value CSUBSTOP to the syntax table. These are the + valid expansion operators OP in ${param[:]OPword} + +subst.c + - use table lookup for CSUBSTOP in VALID_PARAM_EXPAND_CHAR + - new flags for the string extraction functions: EX_NOALLOC. This + indicates that the functions are being used only to skip over + strings and the result won't be used, so the substring shouldn't + be allocated, copied, and freed + - new flag for string_extract: EX_VARNAME. This serves the same + purpose as the old `varname' parameter. parameter_brace_expand() + changed appropriately + - extract_delimited_string and extract_dollar_brace_string now take + an additional `flags' argument, which may include EX_NOALLOC + - changed callers of extract_delimited_string and + extract_dollar_brace_string appropriately + - string_extract now understands EX_NOALLOC; callers changed + - some smaller code cleanups + - converted char_is_quoted(), unclosed_pair(), and skip_to_delim() + to understand multibyte characters + + 2/11 + ---- +variables.[ch] + - moved to a symbol organization inspired by lcc. The basic structure + is no longer a HASH_TABLE, but a VAR_CONTEXT, which includes a hash + table as one of its members. VAR_CONTEXTs are linked together to do + variable scoping. One nice thing about this is that the entire + symbol table doesn't need to be searched at function scope exit to + remove local variables. Fixes problems with only one instance of + builtin_env and function_env, even though it really is a stack + - shell_variables is now a VAR_CONTEXT *, with a global_variables + variable that points to the bottom of the stack for fast access + - function-scope local variables (assignments specified on the command + line before a function call) and function-local variables (declared + with the `local' builtin) have been unified in the same variable + context, replacing function_env + - assignment statements preceding the `.' and `eval' builtins are now + a separate variable scope VAR_CONTEXT, replacing builtin_env + - temporary_env (a HASH_TABLE) is now the only separate environment + - changes to export environment creation, variable binding, variable + lookup, local variable propagation all changed to work with the + new symbol table/scope structure + - a SHELL_VAR no longer has a `prev_context' member; it's not needed + +execute_cmd.c + - changes to push_context calls to include any temporary variables in + temporary_env; pop_context takes care of propagating any temporary + variables if necessary + - calls to push_scope if `eval' or `.' is called with a list of + preceding variable assignments, and pop_scope called at end of + builtin's execution. pop_scope takes care of merging temporary + variables into the shell environment when appropriate + +builtins/{setattr,declare}.def + - changes to account for variable assignments preceding `local', + `export', `readonly', `declare', etc. to work with the new + variable scoping implementation + +shell.c + - since shell_variables is now a VAR_CONTEXT, call + delete_all_contexts() when the shell is reinitializing instead of + delete_all_variables() + +builtins/common.c + - new function, get_job_by_name(), used by execute_simple_command() + for the `auto_resume' stuff and get_job_spec() + +builtins/common.h + - new set of #defined constants for flags argument to + get_job_by_name() + + 2/12 + ---- +command.h + - new redirection operator: r_reading_string for `here strings' + +parse.y + - new token, LESS_LESS_LESS, for new redirection `here string' + operator: [N]<<< word + - recognize LESS_LESS_LESS and create the appropriate redirection + +{dispose_cmd,copy_cmd,make_cmd,print_cmd}.c + - recognize r_reading_string and do the right thing (dispose_redirects, + copy_redirect, print_redirection, and make_redirection, respectively) + +redir.c + - here_document_to_fd now takes the redirection operator as its + second argument + - new function, write_here_string, expands a here string and writes it + to the here document file descriptor + - here_document_to_fd calls write_here_string for r_reading_string + operator + - handle r_reading_string in do_redirection_internal() and + stdin_redirection() + + 2/18 + ---- +doc/{bash.1,bashref.texi} + - documented here strings + +{configure,Makefile}.in + - bumped version number up to bash-2.05b and the release status + to alpha1 + +expr.c + - make expr_streval understand that variables with the `invisible' + attribute are really unset, and accessing such a variable when + `set -u' is set should be an error + +variables.h + - new accessor macros: var_isset(var) and var_isnull(var), test + whether var->value is NULL + +{eval,subst,variables}.c, builtins/{declare,setattr}.def + - be more consistent about using value_cell(var) instead of + directly referencing var->value + - use var_isset and var_isnull where appropriate + +builtins/help.def + - augmented a couple of help strings with pointers to `info' and + `man -k' + + 2/14 + ---- +variables.h + - new macros to use when setting variable values directly instead of + through bind_variable and its siblings + +{arrayfunc,variables}.c + - use var_setarray and other lvalue macros instead of assigning to + var->value directly + +builtins/setattr.def + - change show_var_attributes to show function definitions separately + from function attributes. This allows the output of `declare -f' + (with other flags), `export -f', and `readonly -f' to be reused as + shell input, instead of the old + + declare -f[flags] func() + { + foo + } + + which has syntax errors. When in posix mode, `export -fp' and + `readonly -fp' still don't print function definitions + + 2/16 + ---- +parse.y + - comment out calls to discard_parser_constructs; no need to call + empty functions + + 2/18 + ---- +lib/sh/memset.c + - replacement function for memset(3) + +lib/sh/Makefile.in, Makefile.in + - additions for memset.c + +configure.in,config.h.in + - check for memset, define HAVE_MEMSET if found, add memset.o to + LIBOBJS if not + +lib/malloc/malloc.c + - removed zmemset(), replaced with calls to memset(3) + +{subst,execute_cmd,lib/sh/netopen}.c + - replaced calls to bzero with calls to memset + +subst.c + - word_split() now takes a second argument: the value of $IFS, so + it doesn't have to look up IFS every time + - word_list_split() now calls getifs() and passes the result to + each call to word_split() as its second arg + - do a quick scan for CTLNUL in remove_quoted_nulls before allocating + new string, copying old string to it, copying over original string + and freeing new string + +eval.c + - don't bother calling dispose_used_env_vars if temporary_env is NULL + +execute_cmd.c + - fix fix_assignment_words to only look up the builtin corresponding + to the first word if one of the words in the list is marked as + W_ASSIGNMENT + +hashlib.c + - renamed hash_string to hash_bucket, which better reflects what it + does + - extracted the portion of hash_bucket that computes the hash out + into a new hash_string() + - made new body of hash_bucket into a macro HASH_BUCKET; function + just calls the macro + - calls to hash_bucket in this file now call HASH_BUCKET macro + - in add_hash_item, just add a new item at the front of the appropriate + bucket list instead of at the end + +hashcmd.h + - reduced FILENAME_HASH_BUCKETS to 53 from 107 + + 2/19 + ---- +hashlib.[ch] + - find_hash_item, remove_hash_item, add_hash_item all take a new + third `flags' argument + - add_hash_item doesn't call find_hash_item if HASH_NOSRCH passed in + flags arg + - find_hash_item will create a new hash table entry if HASH_CREATE is + passed in flags arg + - new function, hash_walk, takes a pointer to a function and a table + and calls the function for each item in the table. If the function + returns < 0, the walk is terminated + - fixed flush_hash_table to set table->nentries to 0 after freeing + all entries + - BUCKET_CONTENTS now has a new `khash' member, what key hashes to; + set by HASH_BUCKET macro (which calls hash_string), assigned in + find_hash_item (HASH_CREATE) and add_hash_item + - find_hash_item and remove_hash_item check `khash' against the + hash of the string argument before calling strcmp + +{alias,hashlib,hashcmd,pcomplib,variables}.c + - changed all calls to {find,remove,add}_hash_item + +builtins/hash.def + - return immediately from print_hashed_commands if there are no + entries in the hash table (this eliminates need for `any_printed' + variable) + - change print_hashed_commands to use hash_walk + +alias.c + - short-circuit all_aliases and map_over_aliases if + HASH_ENTRIES(aliases) == 0 + - simplify map_over_aliases by just allocating enough room in the + returned list for all entries in the aliases hash table, instead + of doing the check and xrealloc + - add_alias now calls add_hash_item with HASH_NOSRCH argument + +pcomplete.h + - sh_csprint_func_t is no more; use hash_wfunc instead + +pcomplib.c + - short-circuit print_all_compspecs if HASH_ENTRIES(prog_completes) + is 0 + - print_all_compspecs now takes a `hash_wfunc *' argument + - print_all_compspecs now just calls hash_walk + +builtins/complete.def + - new function, print_compitem, takes a BUCKET_CONTENTS *, extracts + the right info, and calls print_one_completion + +variables.c + - short-circuit map_over_funcs if HASH_ENTRIES(shell_functions) == 0 + - short-circuit flatten if the passed table has no entries + - bind_variable_internal takes a new fourth argument: `hflags', + to pass to hash table functions + - make_new_variable now passes HASH_NOSRCH flag to add_hash_item + - set_if_not now calls bind_variable_internal and passes + HASH_NOSRCH as flags argument + - bind_function now calls add_hash_item with HASH_NOSRCH argument + - fixed make_local_variable: old_var == 0 && was_tmpvar can never + be true + - if we didn't find an old variable in make_local_variable, call + bind_variable_internal with HASH_NOSRCH argument + - fix push_temp_var to reset variable context to 0 if binding into + global_variables->table + +parse.y + - fix to parse_compound_assignment to avoid core dumps on empty + compound array assignments + +subst.c + - getifs() is now global so read_builtin can call it + +subst.h + - extern declaration for getifs() + + 2/20 + ---- +hashlib.c + - changed hash_string to use a better hash function + - changed HASH_BUCKET to use masking rather than modulus to hash a + string to a bucket -- HASH TABLES MUST NOW BE SIZED BY POWERS + OF TWO + +hashlib.h + - DEFAULT_HASH_BUCKETS is now 64 + +hashcmd.h + - FILENAME_HASH_BUCKETS is now 64 + +pcomplib.c + - COMPLETE_HASH_BUCKETS is now 32 + +variables.c + - TEMPENV_HASH_BUCKETS is now 4 + +alias.c + - new define, ALIAS_HASH_BUCKETS, set to 16, used to size alias table + +hashlib.c + - removed initialize_hash_table; folded code into make_hash_table + - fixed copy_bucket_array to copy the `khash' member of an item + - renamed functions to be more systematic and easier for me: + make_hash_table -> hash_create + hash_table_nentries -> hash_size + copy_hash_table -> hash_copy + find_hash_item -> hash_search + remove_hash_item -> hash_remove + add_hash_item -> hash_insert + flush_hash_table -> hash_flush + dispose_hash_table -> hash_dispose + print_table_stats -> hash_pstats + get_hash_bucket -> hash_items + - changed hash_search to short-circuit if table->nentries == 0 and + HASH_CREATE has not been passed in the flags argument + +{alias,variables,hashcmd,pcomplib}.c + - renamed calls to all renamed functions from hashlib.c + +builtins/kill.def + - don't drop a leading `-' in a pid argument + - call kill_pid with an explicit third argument of 1 if the pid + argument to kill is < -1, rather than rely on the behavior of + kill(2) + + 2/21 + ---- +subst.c + - quoted_strchr is no longer declared `inline' + - skip_double_quoted is no longer declared `inline' + - string_extract_double_quoted is no longer declared `inline' + +lib/readline/input.c + - rl_gather_tyi is now an `int' valued function; returns the number + of characters read (0 or 1) or -1 on error + - if rl_gather_tyi() returns -1 to rl_read_key(), set rl_done to 1 + and return a newline; something is wrong with the input fd + + 2/25 + ---- +variables.[ch] + - IFS is now a special variable + - new special var function, sv_ifs(), called when IFS is set or unset + - call setifs() when IFS is first set in initialize_shell_variables + - call setifs() from make_local_variable and assign_in_env if + appropriate + - if assign_in_env() is called with a var assignment like `VAR=', + make the value in the new SHELL_VAR created be "" like + do_assignment_internal does, since certain parts of the shell use + a NULL value as evidence that the variable is unset (though + attributes may have been assigned) + - if push_temp_var pushes something up to the global_variables table, + make sure that the context is set to 0 + - new function dispose_temporary_env, called by both + dispose_used_env_vars and merge_temporary_env with different `free + func' function pointers; calls sv_ifs after disposing the temporary + environment + - push_exported_var now calls bind_variable_internal instead of + bind_variable + - pop_scope and pop_context now call sv_ifs + +subst.[ch] + - new global variables used to keep track of IFS state, to avoid + having to call find_variable("IFS") all the time: + + ifs_var the SHELL_VAR for IFS + ifs_value ifs_var ? value_cell (ifs_var) : " \t\n" + ifs_cmap bitmap of characters in ifs_value + ifs_firstc first character in ifs_value + + - new function setifs(), sets the aforementioned ifs variables each + time IFS is set or unset, and at nested scope exit + - instead of calling getifs() from inside subst.c, use ifs_value + - getifs() now just returns ifs_value + - use ifs_firstc in string_list_dollar_star() + - only call member() in issep() if separators is more than one char + - don't cache a bitmap every time expand_word_internal() is called; + use ifs_cmap instead + - new macro, isifs(c), checks whether C is in ifs_cmap + +builtins/read.def + - use issep() and isifs() macros instead of looking at $IFS directly + +syntax.h + - make sure macros that access sh_syntaxtab cast the argument to + `unsigned char' before array access + - new macros: issyntype(c, type) and notsyntype(c, type), check + sh_syntaxtab[c] for a particular flag value `type' + + 2/26 + ---- +hashlib.h + - the `data' member of a `BUCKET_CONTENTS' is now a PTR_T + +{hashlib,alias,variables,hashcmd,pcomplib}.c + - removed some casts when assigning to and using `data' member of a + `BUCKET_CONTENTS' + +subst.c + - in split_at_delims, call make_word_list instead of allocating and + initializing a WORD_LIST * directly + +make_cmd.[ch] + - add_string_to_list is now just a macro that calls make_word_list + - make_simple_command now calls make_word_list instead of allocating + a WORD_LIST * directly + + 2/27 + ---- +copy_cmd.c + - copy_word now calls make_bare_word to allocate the copy + - copy_word_list now calls make_word_list to allocate the copy + +shell.h + - include `ocache.h' for simple object caching + - call cmd_init() to initialize the WORD_DESC and WORD_LIST object + caches + +{make,dispose}_cmd.c + - allocate WORD_DESC * and WORD_LIST * vars from their respective + ocaches, and return them to the cache when disposing + +jobs.c + - renamed old `waiting_for_job' variable to `queue_sigchld', which + better reflects its intent: sigchld_handler does not call waitchld + if `queue_sigchld' is non-zero, it simply increments the count of + waiting children + - cleanup_dead_jobs now just sets and clears queue_sigchld instead of + blocking and unblocking SIGCHLD; it calls waitchld at the end if + `sigchld' is non-zero, but that's not really necessary + - in setjstatus, only call xrealloc if `statsize' is less than the + number of processes passed -- no reason to do it if they're the + same + + 2/28 + ---- +sig.[ch] + - reinitialize_signals is no more; initialize_signals takes an + argument saying whether or not we are reinitializing + +builtins/exec.def + - reinitialize_signals() -> initialize_signals(1) + +test.c + - fix filecomp() to work right when one file has a non-positive + timestamp and the other file does not exist + +doc/{bash.1,bashref.texi} + - document what happens for test's -nt and -ot operators when one + file operand exists and the other does not + +jobs.c + - if we haven't messed with SIGTTOU, just manipulate queue_sigchld + in notify_of_job_status instead of calling sigprocmask() + - list_one_job now calls pretty_print_job directly instead of going + through print_job + - pretty_print_job now must be called with SIGCHLD blocked or held + instead of blocking SIGCHLD itself + - changed start_job so that it doesn't call UNBLOCK_CHILD and then + immediately call BLOCK_CHILD again (explicitly or via last_pid()), + call find_last_pid instead of last_pid and then UNBLOCK_CHILD + - changed wait_for_job the same way + - find_last_pid now takes a second argument: block; uses BLOCK_CHILD + if `block' is 1, not otherwise. Changed existing calls: + find_last_pid(j) -> find_last_pid(j, 0) + last_pid(j) -> find_last_pid(j, 1) + `last_pid()' is now gone + - rewrote wait_for_background_pids(); it was a little strange + +copy_cmd.c + - copy_if_command: don't copy null false_case commands + - copy_simple_command: don't copy a null redirection list + +subst.c + - in get_word_from_string and list_string, just check for " \t\n" + directly rather than calling strcmp + - in get_word_from_string and strip_trailing_ifs_whitespace, use + isifs() instead of issep(), since they're never called with + separators != $IFS + - change issep() to call isifs if separators is longer than one + character, since it's never called with anything but "", " ", + or $IFS + + 3/1 + --- +sig.h + - enclose the BLOCK_SIGNAL macro in a do {...} while (0) loop, at it + should have been all along + +lib/readline/doc/rltech.texinfo + - document that readline defaults to stdin/stdout if rl_instream/ + rl_outstream are NULL + +lib/readline/terminal.c + - if an application is using a custom redisplay function, + rl_resize_terminal just calls rl_forced_update_display to tell + (*rl_redisplay_func) to update the display, otherwise call + _rl_redisplay_after_sigwinch + +lib/readline/readline.c + - change readline_internal_setup() so the change to vi insertion mode + happens even if readline_echoing_p is 0 + - don't print the prompt to rl_outstream in readline_internal_setup + if we're not echoing and the caller has defined a custom redisplay + function -- let the redisplay function deal with it + +configure.in + - new option: --enable-mem-scramble, controls memory scrambling on + free() (on by default; only affects use of bash malloc) + +config.h.in + - new option MEMSCRAMBLE, controlled by --enable-mem-scramble + + 3/5 + --- +parse.y + - added ksh-like behavior of [...] to read_token_word: if a `[' is + seen in an assignment context and the previous characters in the + token form a valid identifier, parse the [...] with + parse_matched_pair to allow spaces (and newlines) in the subscript + +bashline.c + - new function bash_servicename_completion_function, for completing + service names from /etc/services + +bashline.h + - new extern declaration for bash_servicename_completion_function + +builtins/complete.def + - allow new `-s/-A service' option to complete and compgen builtins + +pcomplete.h + - new CA_SERVICE define, new ITEMLIST variable it_services + +pcomplete.c + - add callback to bash_servicename_completion_function to generate + list of matching service names for completion + +doc/bash.1,lib/readline/doc/rluser.texinfo + - documented new `-s/-A service' option to complete and compgen + + 3/6 + --- +builtins/read.def + - change hard-coded `0' to new variable `fd' (initially 0) in + preparation for adding `-u fd' option + +bashline.c + - bash_directory_completion_hook calls expand_prompt_string instead + of expand_string (it does the right thing). This keeps expansion + errors from causing a longjmp, which shouldn't happen because of + completion + - command_subst_completion_function was augmented very slightly to + do filename completion on a non-command-word in a command + substitution + - command_subst_completion_function now skips over the lcd that + rl_completion_matches puts in matches[0] if there is more than + one possible completion + + 3/7 + --- +builtins/read.def + - only add the unwind_protect to free `rlbuf' if `edit' is non-zero, + since we won't be using readline otherwise + +lib/sh/zread.c + - renamed zread1 -> zreadintr + +redir.c + - small change to redirection_error() to make a slightly better + guess about the invalid file descriptor if the redirection op is + r_duplicating_input or r_duplicating_output + +include/stdc.h + - new macro, SH_VA_START, to encapsulate the difference between + stdarg va_start and varargs va_start + +{error,pcomplete,print_cmd}.c,builtins/common.c,lib/sh/snprintf.c + - use SH_VA_START + + 3/8 + --- +builtins/read.def + - support for the ksh-like `-u fd' option + +general.c + - new function sh_validfd(fd), returns 1 if fd is a valid open file + descriptor + +general.h + - extern decl for sh_validfd + +bashline.c + - don't call posix_readline_initialize() from initialize_readline(); + sv_strict_posix() should already have taken care of it + + 3/11 + ---- +{error,pcomplete,print_cmd}.c, builtins/common.c + - removed non-varargs versions of functions + +builtins/printf.def + - if the string argument to %q has non-printing characters, call + ansic_quote to quote it rather than sh_backslash_quote + +variables.h + - new attribute: att_trace (and corresponding trace_p() macro). + Functions with this attribute will inherit the DEBUG trap. + Currently ignored for variables + +builtins/declare.def + - new `-t' option to declare/typeset toggle the `att_trace' attribute + +builtins/setattr.def + - check for att_trace and output `-t' flag in show_var_attributes + +execute_cmd.c + - if a function is being traced (it has the `-t' attribute set), + don't turn off the DEBUG trap when it executes + +doc/{bash.1,bashref.texi} + - document the new `-t' option to declare/typeset + + 3/12 + ---- +execute_cmd.c + - don't execute the debug trap in the `cm_simple:' case of + execute_command_internal; run it in execute_simple_command so we + get the line number information right when executing in a shell + function + - run a DEBUG trap before executing ((...)) arithmetic commands, + like ksh93 + - run a DEBUG trap before executing [[...]] conditional commands, + like ksh93 + +eval.c + - add a static forward declaration for alrm_catcher() + +general.c + - add static forward declarations for bash_special_tilde_expansions, + unquoted_tilde_word, initialize_group_array + +variables.h + - add extern declarations for sh_get_env_value, map_over_funcs, + local_exported_variables + +variables.c + - add static forward declarations for dispose_temporary_env, + make_func_export_array + +bashhist.c + - add static forward declaration for check_history_control + +configure.in + - add a call to AC_CHECK_DECLS for strcpy + +config.h.in + - add placeholder for HAVE_DECL_STRCPY define, set by configure + +general.h + - don't declare strcpy if HAVE_DECL_STRCPY is defined with a non-zero + value + +sig.h + - add prototype to typedef of SigHandler + +lib/readline/histlib.h + - removed extern declaration of strcpy() + - include string.h/strings.h directly in histlib.h instead of source + files + +lib/readline/{histexpand,histfile,history,histsearch}.c + - don't include string.h/strings.h now that histlib.h includes it + +lib/tilde/tilde.c + - removed extern declaration of strcpy(), rely on string.h/strings.h + +command.h + - four new redirection types: r_move_input, r_move_output, + r_move_input_word, r_move_output_word, for + [N]<&word- and [N]>&word- from ksh93 + +print_cmd.c + - changes to print r_move_input[_word] and r_move_output[_word] + +copy_cmd.c + - changes to copy r_move_input[_word] and r_move_output[_word] + +dispose_cmd.c + - changes to dispose r_move_input_word and r_move_output_word + +make_cmd.c + - changes to make r_move_input[_word] and r_move_output[_word] from + r_duplicating_{input,output}_word, which is how the new redirs + are passed by the parser + +redir.c + - changes to make r_move_input[_word] and r_move_output[_word] do + the right thing when executed + +builtins/read.def + - print an error message and return failure immediately if zread/zreadc + return < 0 + +doc/{bash.1,bashref.texi} + - documented new [n]<&word- and [n]>&word- redirections + + 3/13 + ---- +lib/readline/isearch.c + - enabled code to allow chars bound to rl_rubout to delete characters + from the incremental search string + +shell.c + - add `-l' invocation option to parse_shell_options; equivalent to + `--login' + - fixed set_login_shell to check first char of base pathname of argv0 + for `-', like other shells + - move the check for make_login_shell after the call to + parse_shell_options because the `-l' option might set it + +doc/{bash.1,bashref.texi} + - documented new `-l' invocation option + +array.c + - new function, array_shift, shifts an array left by a specified + number of elements + - array_walk is now compiled in by default + - array_to_assignment_string now takes a second argument: int quoted. + If non-zero, the result is single-quoted before being returned + - quoted_array_assignment_string has been removed + +array.[ch] + - renamed most of the array functions so that all have an array_ + prefix and are more systematically named + - array_slice now preserves the indicies from the original array + - change array_to_assign to use a static buffer for expanding the + array indices, instead of malloc/free + +{arrayfunc,subst,variables}.c, builtins/read.def + - changed calls to various array functions to use new names + +lib/sh/stringvec.c, externs.h + - renamed all of the functions to have a strvec_ prefix and to have + a more sensible name scheme + - strvec_search's arguments are now supplied in reverse order, so + the char **array is first, like the other functions + - new function, strvec_resize, xrealloc for strvecs + +{alias,array,bracecomp,braces,bashline,execute_cmd,findcmd,general,pathexp, +pcomplete,variables}.c +lib/sh/stringlist.c +builtins/{bind,complete,exec,getopts,pushd,set}.def + - change calls to all functions from lib/sh/stringvec.c + - use strvec_resize where appropriate + +externs.h + - only declare dup2() if HAVE_DUP2 is undefined or DUP2_BROKEN is + defined + +lib/readline/{macro,readline,util}.c, lib/readline/rlprivate.h + - _rl_defining_kbd_macro is gone, use RL_ISSTATE(RL_STATE_MACRODEF) + +lib/readline/readline.h + - new struct readline_state, encapsulates most of readline's internal + state in case you need reentrancy or nested calls to readline() + - extern declarations for rl_save_state, rl_restore_state + +lib/readline/readline.c + - add (undocumented) int rl_save_state (struct readline_state *), + int rl_restore_state (struct readline_state *) + + 3/14 + ---- +array.[ch] + - new function, array_rshift, shifts an array right by a specified + number of elements, optionally inserting a new element 0 + +examples/bashdb/bashdb + - new single-file version of bash debugger, originally modified from + version in bash-2.04 by Gary Vaughan (the old debugger still + appears in examples/obashdb). This version has a more gdb-like + command set + +examples/bashdb/bashdb.el + - new emacs bashdb debugger mode from Masatake YAMATO <jet@gyve.org> + +execute_cmd.c + - don't make $LINENO relative to function start unless the shell is + currently interactive -- this is what ksh93 does and what I + believe to be the intent of POSIX.2 (this required changing some + of the test checks because the output has changed) + - run the debug trap for each command in an arithmetic for expression, + like ksh93 does + +lib/readline/vi_mode.c + - redid rl_vi_subst (binding func for `s' and `S') in terms of + rl_vi_change_to: `S' == `cc' and `s' == `c '. This makes undo + work right + + 3/18 + ---- +hashlib.c + - fixed hash_walk to return if the item function returns < 0, instead + of breaking out of the current hash chain + +array.c + - fixed array_walk to return if the item function returns < 0, like + hash_walk + +lib/sh/stringlist.c, externs.h + - new function: strlist_walk, takes a stringlist and a pointer to an + item func. Like other _walk funcs, if item func returns < 0 the + walk is cancelled + - new function: strlist_flush, frees items in the contained list + with strvec_flush + - renamed functions to have a strlist_ prefix and be more systematic + +pcomplib.c,pcomplete.h + - removed redundant `progcomp_initialized' variable + - renamed functions to have `progcomp_' or `compspec_' prefixes + like the hash library + +{bashline,pcomplete}.c,builtins/complete.def + - fixed calls to stringlist functions to use new names + - fixed calls to functions in pcomplib.c to use new names + +pcomplete.c + - made the debugging code #ifdef DEBUG -- it should be mature enough + +builtins/hash.def,parse.y + - use REVERSE_LIST(x, t) instead of (t)reverse_list(x) + +list.c,{externs,general}.h + - renamed the list functions to have a list_ prefix, changed callers + +externs.h,{execute_cmd,stringlib,subst}.c,builtins/common.c,lib/sh/stringvec.c + - word_list_to_argv -> strvec_from_word_list + - argv_to_word_list -> strvec_to_word_list + - moved functions to lib/sh/stringvec.c + +lib/sh/stringvec.c + - changed name of second argument to strvec_from_word_list from `copy' + to `alloc' so the use of `copy' between strvec_from_word_list and + strvec_to_word_list isn't as confusing + - changed name and sense of second argument to + strvec_to_word_list from `copy' to `alloc' for the same reason -- + now both functions agree on semantics of second argument + +lib/sh/stringlist.c + - ditto for strlist_from_word_list and strlist_to_word_list + +subst.c + - changed callers of strvec_to_word_list + + 3/19 + ---- +builtins/hash.def + - added `-l' option to list table or individual targets in reusable + format + - added `-d' option to remove one or more names from the table of + hashed commands (provides `unhash' or `unalias -t' functionality) + +doc/{bash.1,bashref.texi} + - documented new `-l' and `-d' options to `hash' + +hashcmd.[ch] + - renamed functions to have a `phash_' prefix and follow new naming + convention + - phash_remove now returns an int: 1 if command not in hash table, + 0 if filename removed OK + +{findcmd,variables}.c, builtins/{hash,type}.def + - changed callers to use new names from hashcmd.c + +builtins/common.[ch] + - new function, sh_notfound(s), prints standard `not found' message + - new function, sh_invalidid(s), prints standard `invalid identifier' + message + - new function, sh_restricted(s), prints standard `restricted' message + for restricted shells + - new function, sh_invalidnum(s), prints standard `invalid number' + message + - renamed bad_option to sh_invalidopt, changed to print + `invalid option' instead of `unknown option' + - new function, sh_invalidoptname, prints standard `invalid option + name' for long options + - new function, sh_badjob (s), prints standard `no such job' message + - new function, sh_invalidsig (s), prints standard `invalid signal + specification' message + - new function, sh_nojobs (s), prints standard `no job control' message + - new function, sh_needarg (s), prints standard `option requires an + argument' message + - new function, sh_neednumarg (s), prints standard `numeric + argument required' message + - new function, sh_badpid(s), prints standard `not a pid...' message + - new function, sh_erange (s, desc) prints standard `out of range' + message, optionally using `desc' to say what the argument is + +builtins/{alias,command,declare,exec,hash,type}.def + - call sh_notfound() instead of calling builtin_error directly + +builtins/{declare,getopts,read,set,setattr}.def + - call sh_invalidid() instead of calling builtin_error directly + +builtins/{cd,command,enable,exec,hash,source}.def + - call sh_restricted() instead of calling builtin_error directly + +builtins/{printf,read,ulimit}.def, builtins/common.c + - call sh_invalidnum instead of calling builtin_error directly + +builtins/{complete,declare,pushd,set}.def, builtins/bashgetopt.c + - call sh_invalidopt instead of bad_option or builtin_error directly + +builtins/{complete,set,shopt}.def + - call sh_invalidoptname instead of builtin_error directly + +builtins/{fg_bg,jobs,kill,wait}.def + - call sh_badjob instead of calling builtin_error directly + +builtins/common.c, builtins/{kill,signal}.def + - call sh_invalidsig instead of calling builtin_error directly + +builtins/{fg_bg,suspend,wait}.def + - call sh_nojobs instead of calling builtin_error directly + +builtins/{common,bashgetopt}.c, builtins/{hash,kill}.def + - call sh_neednumarg and sh_needarg where required + +builtins/{kill,wait}.def + - call sh_badpid where required + +builtins/{break,fc,history,pushd,shift,ulimit,umask}.def + - call sh_erange where appropriate + +builtins/printf.def + - new static function, printf_erange, prints standard out-of-range + warning message + +builtins/set.def + - changed so that calls to sh_invalidopt always include the leading + `+' or `-' + +builtins/shopt.def + - changed SHOPT_ERROR macro to shopt_error function + +builtins/bind.def + - regularized error messages to `bind: object: error string' like + other error messages + +builtins.h + - the `short_doc' member of a `struct builtin' is now of type + `const char *' + - the strings in `long_doc' array of a struct builtin are now const + +builtins/mkbuiltins.c + - changes for new `const' members of struct builtin + + 3/20 + ---- +lib/readline/histfile.c + - use pointers instead of indexing into buffer when reading the + contents of the history file in read_history_range and + history_truncate_file + + 3/21 + ---- +lib/readline/histfile.c + - new file, with code to mmap the history file for reading and + writing (depends on HAVE_MMAP, currently nothing checks for that) + + 3/25 + ---- +error.[ch] + - new function, err_badarraysub(s), calls report_error with standard + `bad array subscript' message + - new function, err_unboundvar(s), calls report_error with standard + `unbound variable' message + - new function, err_readonly(s), calls report_error with standard + `readonly variable' message + +{arrayfunc,subst}.c + - call err_badarraysub where appropriate + +{expr,subst}.c + - call err_unboundvar where appropriate + +{arrayfunc,variables}.c + - call err_readonly where appropriate + +shell.c + - changed text of bad option error messages to be the same as that + printed for builtin errors + +builtins/common.c + - changed sh_invalidopt to print the invalid option before the rest + of the error message (required some tests to be modified) + - new function, sh_readonly, calls builtin_error with standard + `readonly variable' message + +variables.c,builtins/declare.def + - call sh_readonly where appropriate + +lib/sh/stringvec.c + - added strvec_remove (sv, s), removes S from SV and shuffles rest of + elements down 1 + +lib/sh/stringlist.c + - added strlist_remove(sl, s), just calls strvec_remove on the + component list + +externs.h + - new extern declarations for strvec_remove and strlist_remove + - fixed extern declaration for strvec_search; the arguments were + reversed (unimportant, it's not compiled into the shell) + +subst.c + - change param_expand to call quote_escapes on values retrieved when + expanding the positional parameters + - change parameter_brace_expand_word to quote escapes on values + retrieved when expanding the positional parameters + - fix parameter_brace_substring to quote escape characters on unquoted + substrings extracted from variable values (needed to separate case + VT_VARIABLE from VT_ARRAYMEMBER for this, since, because + get_var_and_type calls array_value for VT_ARRAYMEMBER, we need to + skip over quoted characters in an already-appropriately-quoted + string to find the substring we want) + - fix parameter_brace_substring to quote escape characters in the + value returned by pos_params when expanding subsets of the + positional parameters and not within double quotes (in which case + pos_params() quotes the string for us) + - fix parameter_brace_substring to quote escape characters in the + value returned by array_subrange when expanding subsets of an + array and not within double quotes (in which case + array_subrange() quotes the string for us) + - new function, quoted_strlen(s), does strlen(s) while skipping over + characters quoted with CTLESC (#ifdef INCLUDE_UNUSED, since it's + not used yet) + - changed pos_params() so it always returns a list whose members are + quoted strings if (quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) != 0 + +arrayfunc.c + - fix array_value to consistently call quote_escapes, even when a + non-array variable is being subscripted with element 0, in which + case we return the variable value + +lib/sh/strtrans.c + - make the for_echo parameter to ansicstr a `flags' parameter that + has its old `for echo' meaning if flags&1 is non-zero (which is + consistent with the old code) + - Added code to the `flags' parameter to ansicstr so that if flags&2 + is non-zero, CTLESC and CTLNUL are escaped with CTLESC in the + expanded string + - change ansiexpand() to call ansicstr with a `flags' parameter of 2 + + 3/26 + ---- +lib/readline/histfile.c + - when reading and writing the history file, use malloc instead of + xmalloc and handle failures gracefully, so the application doesn't + abort if the history file or history list is too big + + 3/27 + ---- +arrayfunc.c + - changed array_value_internal to take an additional `int *' + parameter, in which is returned the type of array indexing + performed (array[@] vs. array or array[index]) + - changed array_value and get_array_value to take a corresponding + extra parameter and pass it to array_value_internal + - changed array_value_internal to no longer return newly-allocated + memory or quote CTLESC and CTLNUL in the returned string if + `simple' array indexing (subscript not `@' or `*') is being + performed. This makes it more like a variable lookup + +arrayfunc.h + - changed prototypes for array_value and get_array_value + +expr.c + - added new parameter to call to get_array_value in expr_streval + - don't need to free memory returned by get_array_value any more + +subst.c + - quote_escapes now works with multibyte characters + - dequote_string now works with multibyte characters + - dequote_escapes is now needed, so it's compiled in, and it + now works with multibyte characters + - remove_quoted_escapes now just calls dequote_escapes and copies the + result over the argument string + - remove_quoted_nulls now returns its char * argument, parallels + remove_quoted_escapes + - parameter_brace_expand_word now passes the new argument to + array_value and quotes CTLESC and CTLNUL in the result if it's a + `simple' array expansion by calling quote_escapes + - get_var_and_type now returns VT_ARRAYMEMBER for references like + ${array} where `array' is an array variable (just like ${array[0]}). + Documented (in comment) that a VT_VARIABLE return value means that + quote_escapes has been called at some point + - changed callers of get_var_and_type to no longer free value if + VT_ARRAYMEMBER is returned as type + - changed parameter_brace_substring and parameter_brace_patsub to + call dequote_escapes on the value from get_var_and_type if the + type is VT_VARIABLE, since the substring and pattern substitution + code doesn't understand CTLESC quoting + - parameter_brace_substring no longer needs to call quoted_substring + for the VT_ARRAYMEMBER case + - changed parameter_brace_patsub to call quote_escapes on the result + of pat_subst for the VT_VARIABLE and VT_ARRAYMEMBER cases, and to + quote the returned string in the VT_ARRAYVAR and VT_POSPARAMS cases + if the `MATCH_QUOTED' flag isn't set (if it is, the pattern + substitution functions perform any necessary quoting) + - quoted_substring is no longer used; it's now #ifdef INCLUDE_UNUSED + +lib/malloc/mstats.h + - new member in _malstats: u_bits32_t bytesreq, the total number of + bytes requested by the caller via calls to malloc() and realloc() + +lib/malloc/stats.c + - print bytesreq member in _print_malloc_stats + - don't print statistics for buckets for which nmal == 0 (no mallocs) + +lib/malloc/malloc.c + - modified internal_malloc, internal_realloc to keep running total of + number of bytes requested by calling application + +shell.c + - sh_exit is now compiled in; exit_shell calls sh_exit + +error.c + - changed fatal_error, report_error, parser_error to call sh_exit + + 3/28 + ---- +subst.[ch] + - changed Q_NOQUOTE to Q_PATQUOTE; it makes the intent more clear + +subst.c + - moved code from parameter_brace_expand into a new function that + dispatches for pattern substitution: parameter_brace_remove_pattern + - changed structure of parameter_brace_remove_pattern to be like + parameter_brace_patsub and its ilk: call get_var_and_type to + isolate the variable name, move the pattern isolation code out of + the various *_remove_pattern functions into + parameter_brace_remove_pattern and pass the results to the various + functions, use a switch on the return value from get_var_and_type + to decide which function to call, regularized the arguments to the + separate pattern removal functions + - parameter_brace_remove_pattern now properly quotes escape chars in + the returned value + - changed get_var_and_type to call dequote_escapes on the `value' + parameter for case VT_VARIABLE and return the result in *valp, + so the calling functions don't have to do it themselves; changed + callers appropriately + - fixed getpattern() where it broke posix compliance: if you enclose + a pattern removal spec in double quotes, the outer double quotes + have no effect on the pattern (POSIX.1-200x 2.6.2). This uncovered + a bug in the test suite (!) + +pathexp.c + - fixed a problem with quote_string_for_globbing where it would change + consecutive CTLESC chars all to \ instead of changing every other + quoted char + + 3/31 + ---- +lib/malloc/{malloc,stats}.c + - moved declaration of _mstats to malloc.c so stats.o doesn't get + linked into the shell if the stats functions aren't called + + 4/2 + --- +lib/glob/smatch.c + - introduce `XCHAR' define, which is the type of arguments passed to + strcoll/strcmp/strlen and their wide-character equivalents, added + appropriate casts + - static arrays in single-byte version of rangecmp() are `char', not + `unsigned char', so compilers don't complain about calls to strcoll + +lib/glob/sm_loop.c + - casts for `XCHAR' and `XCHAR *' arguments to libc functions + - use prototype declaration for BRACKMATCH if `PROTOTYPES' is defined + to avoid problems with type promotion (unsigned char -> int) + +lib/glob/collsyms.h + - `name' member of struct _COLLSYM is now of type `XCHAR *', since + some compilers don't like `unsigned char *' initializers from + constant strings + +[bash-2.05b-alpha1 released] + + 4/3 + --- +builtins/{evalstring.c,common.h} + - new flag for parse_and_execute, SEVAL_NOFREE, means to not free + the argument string when finished + +lib/readline/text.c + - fixed a trivial typo in _rl_insert_char when reading multibyte + char sequences + - replace calls to ding() with rl_ding() + +include/chartypes.h + - remove SIGN_EXTEND_CHAR and TOASCII macros; they're unused + +make_cmd.c + - include dispose_cmd.h for extern function declarations + +lib/glob/glob.c + - include `shmbutil.h' and `xmalloc.h' for extern function declarations + +lib/glob/smatch.c + - include `xmalloc.h' for extern function declarations + +shell.c + - fix maybe_make_restricted to use its argument instead of global + `shell_name' + +version.c + - update copyright message to include this year + +lib/readline/display.c + - fixes from Jiro SEKIBA <jir@yamato.ibm.com> to fix autowrapping + when using multibyte characters + +lib/glob/sm_loop.c + - fixed a problem in BRACKMATCH where not enough memory was allocated + to hold a multibyte character when parsing POSIX.2 char class names + +support/config.{guess,sub} + - updated via patch from Paul Eggert with latest GNU additions + +variables.c + - var_lookup should use its `vcontext' argument instead of + unconditionally using `shell_variables' + + 4/4 + --- +builtins/bind.def,doc/{bash.1,bashref.texi} + - changed the usage summary and help text to make it clear that any + readline command that may appear in ~/.inputrc may be supplied as + one of the non-option arguments to `bind' + +builtins/mkbuiltins.c + - added support for `-H' option, which means to write long documentation + for each builtin to a separate file in the `helpfiles' directory + +builtins/Makefile.in + - new target `helpdoc', just creates long doc files in helpfiles + directory + +lib/sh/zcatfd.c + - new file, with zcatfd(int fd, int ofd, char *fn); dumps data from + FD to OFD + +Makefile.in,lib/sh/Makefile.in + - added zcatfd.c, zcatfd.o member of libsh.a + +builtins/evalstring.c + - changed cat_file to call zcatfd(fd, 1, fn) + +builtins/{shopt,colon}.def + - removed the $DOCNAME directive for `shopt', `true', and `false'; + just use the names + - changed $DOCNAME for `:' to just be `colon' instead of + `colon_builtin' + +builtins/reserved.def + - added help entries for ((, [[, `for ((' + +builtins/let.def + - add id++, id--, ++id, --id, ** to help text + + 4/8 + --- +builtins/bashgetopt.[ch] + - changed to allow options beginning with `+', enabled by a leading + `+' in the option string + - new variable, list_opttype, set to `-' or `+' + +builtins/{common.c,{builtin,eval,exit,fg_bg,let,printf,pushd,return,source,wait}.def + - changes to allow a `--' option for every builtin that accepts + operands but not options, as per posix.1-2001 + +builtins/{declare,setattr}.def + - use internal_getopt for parsing options, now that it supports `+' + +builtins/set.def + - use internal_getopt for initial option parse, now that it supports + a leading `+' + + +{configure,Makefile}.in, builtins/{Makefile.in,help.def,mkbuiltins.c} + - support for a new configure option, ``--enable-separate-helpfiles'', + moves the `long' help text to separate help files, installed by + default into ${datadir}/bash, one file per builtin. Off by + default -- it saves 47K, but it's only 47K, and it's in the text + segment + +flags.c + - build internal_getopt() option string argument from flags array at + runtime in shell.c + +shell.c + - new variable to control writing malloc stats at exit: + malloc_trace_at_exit, 0 by default + +lib/malloc/malloc.c + - heavily updated: + o partial page allocated on first call to malloc to make + subsequent sbrks page-aligned no longer wasted + o begin and end range guards are now the same value: the chunk + requested + o coalescing code was changed to attempt to coalesce first two + adjacent blocks on the free list; enabled by default + o blocks of size 32 are now candidates for larger block + splitting, since 32 is the most popular size + o blocks of size 32 are now candidates for smaller block + coalescing + o the IN_BUCKET check was changed to just make sure that the + size isn't too big for the bucket, since the `busy block' + checking code may increase the bucket by one or more, + meaning that the old check would fail and cause a panic when + a chunk allocated in such a way was freed + o bin sizes are now precomputed and looked up in an array + rather than being computed at runtime + o moved the _mstats declaration here to avoid the stats code + being linked in even when no stats functions were called + (only matters if MALLOC_DEBUG is defined) + o malloc now keeps track of the address of the top of the heap + and will return large chunks to the system with calls to + sbrk with a negative argument when freeing the top chunk. + Two thresholds: LESSCORE_FRC means to unconditionally return + memory to the system; LESSCORE_MIN means to return memory if + there's at least one block already on the free list + +lib/malloc/mstats.h + - stats struct now keeps track of number of block coalesces by bin, + and the number of times memory was returned to the system by bin + +lib/malloc/stats.c + - trace_malloc_stats now takes a second argument: the name of the file + to write to. The first `%p' in the template file name is replaced + by the pid + + 4/9 + --- +lib/malloc/imalloc.h + - added some macros derived from dlmalloc and glibc malloc to inline + memcpy and memset if the requested size is <= 32 bytes + +lib/malloc/malloc.c + - use MALLOC_MEMSET instead of memset in internal_{malloc,free} + +include/ocache.h + - use OC_MEMSET (variant of MALLOC_MEMSET) in ocache_free + +configure.in, config.h.in + - check for getservent(), define HAVE_GETSERVENT if found + +bashline.c + - punt immediately from bash_servicename_completion_function if + HAVE_GETSERVENT is not defined (cygwin seems to not define it) + - include "input.h" for extern save_token_state() and + restore_token_state() declarations + - change bash_execute_unix_command to call parse_and_execute with + SEVAL_NOHIST flag so the command doesn't get saved on the history + list + - change bash_execute_unix_command to save and restore the current + command line count and the token state (last_read_token, etc.). + Everything else is saved by either parse_and_execute directly or + the call it makes to push_stream(). The shell_input_line stuff + doesn't need to be saved and restored; it's not computed until + readline() returns + + 4/10 + ---- +lib/glob/glob.[ch] + - glob_filename and glob_vector now take an additional `flags' arg + - define GX_MARKDIRS as possible flag value for glob_filename and + glob_vector + +lib/sh/snprintf.c + - fixed some bugs with handling of `g' and `G' formats + - make sure numtoa returns the fractional part correctly when passed 0 + - implemented thousands grouping for `'' flag character + +lib/sh/rename.c + - a few changes to make it more bulletproof + + 4/11 + ---- +lib/glob/glob.c + - added the couple of dozen lines of code to glob_dir_to_array to + finish implementing GX_MARKDIRS + +builtins/set.def + - changed unset builtin so that it no longer considers unsetting an + unset variable or function to be an error + +lib/readline/display.c + - fix to rl_redisplay for a problem which caused display to be messed + up when the last line of a multi-line prompt (possibly containing + invisible characters) was longer than the screen width + + 4/15 + ---- +aclocal.m4 + - use AC_DEFINE_UNQUOTED in BASH_SYS_DEFAULT_MAIL_DIR instead of + enumerating all of the possible values and using AC_DEFINE + + 4/16 + ---- +Makefile.in, {builtins,support}/Makefile.in + - new variables, CFLAGS_FOR_BUILD and CPPFLAGS_FOR_BUILD, substituted + by `configure' + - changed CCFLAGS_FOR_BUILD to BASE_CCFLAGS, removing $(CPPFLAGS); + CCFLAGS and CCFLAGS_FOR_BUILD now include $(BASE_CCFLAGS) with + (possibly) different values for CPPFLAGS and CFLAGS + - GCC_LINT_CFLAGS now includes $(BASE_CCFLAGS) and $(CPPFLAGS) + instead of CCFLAGS_FOR_BUILD + - new variable, LDFLAGS_FOR_BUILD, right now equivalent to LDFLAGS + - remove $(CPPFLAGS) from recipes for buildversion, mksignames, and + mksyntax + +configure.in + - compute and substitute CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and + LDFLAGS_FOR_BUILD + - changed qnx to use LOCAL_LDFLAGS and LOCAL_LIBS instead of putting + everything in LOCAL_LDFLAGS + +builtins/Makefile.in + - remove $(PROFILE_FLAGS) from recipe for building `mkbuiltins' + - use LDFLAGS_FOR_BUILD instead of LDFLAGS in recipe for building + `mkbuiltins' + +Makefile.in + - use $(CC_FOR_BUILD) and $(CCFLAGS_FOR_BUILD) to build auxiliary + test programs (printenv, recho, zecho) + +support/Makefile.in + - use CC_FOR_BUILD and CCFLAGS_FOR_BUILD in recipe for building + `man2html' + +lib/tilde/Makefile.in + - substitute PROFILE_FLAGS, use PROFILE_FLAGS in $(CCFLAGS) + + 4/25 + ---- +Makefile.in, configure.in + - moved RELSTATUS to configure.in; configure substitutes it into + the generated Makefile + +lib/sh/snprintf.c + - fix wchars() to deal with systems where MB_CUR_MAX is not a + constant expression + + 5/2 + --- +lib/sh/shquote.c + - add `,' to list of chars that are backslash-quoted. It doesn't + hurt normal usage and prevents filenames with commas from being + inappropriately split by brace expansion after using + complete-into-braces + + 5/6 + --- +lib/sh/xstrchr.c + - we only need the check of MB_CUR_MAX and the slow code for a + few encodings, and even then only for a subset of the charset + +arrayfunc.c + - some speedups for skipsubscript and multibyte chars from Bruno Haible + +locale.c + - changed set_lang to call setlocale(LC_ALL, ...) if LC_ALL doesn't + already have a value, but doesn't change any shell variables + +include/shmbutil.h + - major speedups from Bruno Haible, mostly concerned with reducing + the number of strlen(3) calls + +subst.c + - change callers of macros in shmbutil.h to add extra argument as + necessary + - skip_single_quoted and skip_double_quoted take another argument: + the length of the string; mostly useful when using multibyte chars + - many speedups from precomputing string lengths at function start + - fixed a small bug in de_backslash in the midst of rewriting for + better efficiency + +{braces,make_cmd,pathexp}.c + - change callers of macros in shmbutil.h to add extra argument as + necessary + +pathexp.c + - fix a one-too-far problem with multibyte chars in + unquoted_glob_pattern_p + +braces.c + - brace_gobbler takes a new argument, the length of the passed string + - expand_amble takes a new argument, the length of the passed string + + 5/7 + --- +subst.c + - modified remove_quoted_nulls to eliminate the memory allocation and + do the copy in place using the same strategy as de_backslash + +lib/readline/{rldefs.h,complete.c} + - new define RL_QF_OTHER_QUOTE, so _rl_find_completion_word can note + that it found a quoting character other than \'" that appears in + rl_completer_quote_characters + + 5/9 + --- +jobs.c + - save and restore old value of jobs_list_frozen when calling trap + handlers from set_job_status_and_cleanup to avoid seg faults when + running recursive trap handlers + + 5/10 + ---- +builtins/common.h + - new #defines to use for value of changed_dollar_vars (provides + information about the caller who wants to blow away the old dollar + variables) + +builtins/common.c + - changed set_dollar_vars_changed to set changed_dollar_vars to one + of the ARGS_* values depending on the caller and environment + +builtins/source.def + - source restores the positional parameters unless the `set' builtin + was called to specify a new set while not executing a shell function + + 5/13 + ---- +POSIX + - new file, was in CWRU/POSIX.NOTES + +doc/{Makefile.in,Makefile} + - changed `posix' rule to modify ../POSIX + +doc/mkposix + - write to `POSIX' by default + +lib/sh/strtrans.c + - when ansicstr is parsing a format string for `echo -e' (or the + equivalent xpg_echo option is enabled), obey the POSIX-2001/SUSv3 + standard and accept 0-3 octal digits after a leading `0' + +doc/{bash.1,bashref.texi} + - updated `echo' description to note that up to three octal digits + are now accepted following `\0' + + 5/16 + ---- +doc/Makefile.in + - remove the generated documentation on `make distclean' if the + build directory and source directory are not the same + +Makefile.in + - descend into `support' subdirectory on a `make clean' and + `make distclean' + - remove parser-built, y.tab[ch] on a `make distclean' if the build + directory and source directory are not the same + +support/Makefile.in + - support various `clean' targets and remove man2html.o and man2html + +{configure,Makefile}.in + - move values for DEBUG and MALLOC_DEBUG into configure.in; on by + default for development versions; off by default for releases + (off for profiling, too) + + 5/21 + ---- +parse.y + - modified the grammar to allow a simple_list followed by yacc_EOF + to terminate a command. This fixes problems with things like + a backslash-newline at the end of an `eval'd string + - change handle_eof_input_unit() to reset the token state before + calling prompt_again(), in case the prompt to be evaluated contains + a command substitution + + 5/23 + ---- +lib/readline/vi_mode.c + - fix `r' command (rl_vi_change_char) when HANDLE_MULTIBYTE is defined + but MB_CUR_MAX == 1 + + 5/24 + ---- +lib/malloc/watch.c + - don't try to print `file' argument to _watch_warn if it's null + +lib/malloc/malloc.c + - changed guard checking code in internal_{malloc,free,realloc} to + access memory as (char *) and copy into a union instead of + casting and dereferencing a pointer to u_bits32_t, since that + results in unaligned accesses which will cause Sparcs to upchuck + + 5/30 + ---- +[bash-2.05b-beta1 released] + +lib/readline/text.c + - fixed a problem with rl_transpose_chars on systems supporting + multibyte characters with a locale that doesn't have any multibyte + chars + + 6/4 + --- +expr.c + - fix a/=0 and a%=0 to throw evaluation errors rather than core dumps + +lib/readline/display.c + - fix core dump when line wrapping a multibyte character (line + accidentally dropped from the original patch) + +lib/readline/mbutil.c + - fix reversed return value from _rl_is_mbchar_matched; fixes problem + with backward-char-search + + 6/10 + ---- +lib/sh/getenv.c + - fix getenv to not free value returned by find_tempenv_variable + - add setenv, putenv, unsetenv for completeness + + 6/12 + ---- +shell.c + - change init_noninteractive to init expand_aliases to the value of + posixly_correct + - don't initialize expand_aliases to posixly_correct anywhere else. + This allows the -O expand_aliases invocation option to work correctly + +general.c + - fix move_to_high_fd to not try the dup2 unless the fd loop results + in an fd > 3; just return the passed file descriptor otherwise + - use HIGH_FD_MAX, defined in general.h, instead of hard-coded 256 + as highest file descriptor to try + +subst.c + - in process_substitute, call move_to_high_fd with `maxfd' parameter + of -1 instead of 64, so move_to_high_fd will use its maximum + + 6/21 + ---- +lib/malloc/malloc.c + - don't bother calling MALLOC_MEMSET if the requested size is 0 + +builtins/setattr.def + - note in short doc that export and readonly can take assignment + statements as arguments + +error.c + - new function, error_prolog(), to capture common error message + prefix code (except for parser errors) + + 6/25 + ---- +aclocal.m4 + - add tests for standard-conforming declarations for putenv and + unsetenv in system header files + +{configure,config.h}.in + - call BASH_FUNC_STD_PUTENV and BASH_FUNC_STD_UNSETENV, define + HAVE_STD_GETENV and HAVE_STD_UNSETENV, respectively, if they + succeed + +lib/sh/getenv.c + - change putenv and unsetenv to take differing prototypes in + stdlib.h into account + + 6/27 + ---- +[bash-2.05b-beta2 released] + + 6/28 + ---- +builtins/common.c + - fix get_job_spec so that %N works when N is the size of the jobs + list (%8 means job 8, but the 7th member of the jobs array, so + it's OK if N == job_slots because the function returns N-1) + + 7/1 + --- +shell.c + - turn off line editing if $EMACS is set to `t' + + 7/10 + ---- +builtins/set.def + - remove mention of `-i' from long help doc, since it has no effect + + 7/17 + ---- +[bash-2.05b released] + + 7/18 + ---- + +lib/malloc/malloc.c + - make sure that the `free_return' label has a non-empty statement + to branch to + + 7/19 + ---- +locale.c + - only call setlocale() from set_lang() if HAVE_SETLOCALE is defined; + otherwise just return 0 + +lib/readline/mbutil.c + - only try to memset `ps' in _rl_get_char_len if it's non-NULL. Ditto + for _rl_adjust_point + + 7/23 + ---- +execute_cmd.c + - fix for executing_line_number() when compiling without conditional + commands, dparen arithmetic or the arithmetic for command + + + 7/24 + ---- +support/Makefile.in + - fix maintainer-clean, distclean, mostlyclean targets + +builtins/common.c + - fix bug in sh_nojobs where it doesn't pass the right number of args + to builtin_error + +bashline.c + - when using command completion and trying to avoid appending a slash + if there's a directory with the same name in the current directory, + use absolute_pathname() instead of just checking whether the first + char of the match is a slash to catch things like ./ and ../ + +examples/complete/bashcc-1.0.1.tar.gz + - a package of completions for Clear Case, from Richard S. Smith + (http://www.rssnet.org/bashcc.html) + +input.c + - fix check_bash_input to call sync_buffered_stream if the passed fd + is 0 and the shell is currently reading input from fd 0 -- all it + should cost is maybe an additional read system call, and it fixes + the bug where an input redirection to a builtin inside a script + which is being read from stdin causes the already-read-and-buffered + part of the script to be thrown away, e.g.: + + bash < x1 + + where x1 is + + hostname + read Input < t.in + echo $Input + echo xxx + +execute_cmd.c + - in initialize_subshell(), call unset_bash_input (0) to not mess with + fd 0 if that's where bash thinks it's reading input from. Fixes + bug reported by jg@cs.tu-berlin.de on 17 July 2002. Should be a way + to check whether or not the current fd 0 at the time of the call has + not been redirected, like in the bug report. Also might eventually + want to throw in a sync_buffered_stream if bash is reading input + from fd 0 in a non-interactive shell into a buffered stream, so the + stream is sync'd -- might be necessary for some uses + + 7/25 + ---- +lib/readline/signals.c + - make sure rl_catch_sigwinch is declared even if SIGWINCH is not + defined, so the readline state saving and restoring functions in + readline.c are always the same size even if SIGWINCH is not defined, + and undefined references don't occur when SIGWINCH is not defined + + 7/30 + ---- +bashline.c + - augment patch from 7/24 to not disable rl_filename_completion_desired + if the first char of the match is `~' + +lib/readline/bind.c + - when creating `shadow' keymaps `bound' to ANYOTHERKEY, don't bind + a key whose type is ISFUNC but whose function is the `fake' + rl_do_lowercase_version (fixes debian bash bug #154123) + +lib/readline/readline.c + - don't call _rl_vi_set_last from _rl_dispatch_subseq if + key == ANYOTHERKEY (when truncated to `sizeof(char)', it will be 0, + which strchr will find in `vi_textmod') + + 7/31 + ---- +lib/readline/input.c + - fix rl_gather_tyi to only slurp up one line of available input, even + if more than one line is available (fixes debian bash bug #144585) + + 8/3 + --- +bashline.c + - better fix for command completion problem -- test for directory + explicitly with test_for_directory before turning off + rl_filename_completion_desired, since that's the case we're trying + to protect against + + 8/5 + --- +include/shmbutil.h + - fix ADVANCE_CHAR macro to advance the string pointer if mbrlen + returns 0, indicating that the null wide character (wide string + terminator) was found (debian bash bug #155436) + +lib/readline/mbutil.c + - fix _rl_adjust_point to increment the string pointer if mbrlen + returns 0 + +support/shobj-conf + - fix for the `-install_name' value in SHLIB_XLDFLAGS assignment for + Darwin from the fink folks + + 8/6 + --- +builtins/exit.def + - broke code that runs ~/.bash_logout out into a separate function: + bash_logout() + +builtins/common.h + - extern declaration for bash_logout() + +eval.c + - call bash_logout() from alrm_catcher(), so timed-out login shells + run ~/.bash_logout before processing the exit trap + +lib/sh/strtrans.c + - implemented $'\x{hexdigits}' expansion from ksh93 + +configure.in + - define RECYCLES_PIDS in LOCAL_CFLAGS for cygwin; don't bother to + link with -luser32 + +examples/loadables/strftime.c + - new loadable builtin, interface to strftime(3) + + 8/7 + --- +parse.y + - parse_arith_cmd now takes a second argument, a flag saying whether + or not to add double quotes to a parsed arithmetic command; changed + callers + - changed parse_dparen so it tells parse_arith_cmd to not add the + double quotes and therefore doesn't need to remove them + - change parse_dparen to add W_NOGLOB|W_NOSPLIT|W_QUOTED flags to word + created when parsing (( ... )) arithmetic command, since the double + quotes are no longer added + +make_cmd.c + - in make_arith_for_expr, set the flags on the created word to + W_NOGLOB|W_NOSPLIT|W_QUOTED + +execute_cmd.c + - change execute_arith_command to expand the expression with + expand_words_no_vars, like the arithmetic for command code does + - fix execute_arith_command to handle the case where the expanded + expression results in a NULL word without crashing + +tests/{arith-for,cprint}.tests + - change expected output to account for no longer adding quotes to + ((...)) commands + + 8/8 + --- +print_cmd.c + - take out the space after printing the `((' and before printing the + `))' in print_arith_command, print_arith_for_command, and + xtrace_print_arith_cmd + +tests/{arith-for,cprint}.tests + - change expected output to account for no longer adding leading and + trailing spaces when printing ((...)) and arithmetic for commands + + 8/17 + ---- +subst.c + - fix issep() define to handle case where separators[0] == '\0', in + which case it always returns false + +lib/readline/histexpand.c + - fix off-by-one error in history_expand_internal when using the `g' + modifier that causes it to skip every other match when matching a + single character (reported by gjyun90@resl.auto.inha.ac.kr) + +doc/{bash.1,bashref.texi} + - make sure that the name=word form of argument to declare/typeset, + export, and readonly is documented in the description + + 8/30 + ---- +lib/readline/histexpand.c + - make history_expand_internal understand double quotes, because + single quotes are not special inside double quotes, according to + our shell-like quoting conventions. We don't want unmatched + single quotes inside double-quoted strings inhibiting history + expansion + - make `a' modifier equivalent to `g' modifier for compatibility with + the BSD csh + - add a `G' modifier that performs a given substitution once per word + (tokenized as the shell would do it) like the BSD csh `g' modifier + + 8/31 + ---- +braces.c + - when compiling for the shell, treat ${...} like \{...} instead of + trying to peek backward when we see a `{'. This makes it easier + to handle things like \${, which should be brace expanded because + the $ is quoted + + 9/7 + --- +aclocal.m4 + - redirect stdin from /dev/null in BASH_CHECK_DEV_FD before testing + the readability of /dev/fd/0, so we're dealing with a known quantity + + 9/11 + ---- +[prayers for the victims of 9/11/01] + +shell.c + - fix maybe_make_restricted to handle a restricted login shell with a + base pathname of `-rbash' and skip over any leading `-' + + 9/13 + ---- +builtins/evalstring.c + - in parse_and_execute, make sure we don't try to run unwind-protects + back to `pe_dispose' after a longjmp back to top_level if the + pe_dispose frame hasn't been initialized + +lib/readline/display.c + - fix problem with prompt overwriting previous output when the output + doesn't contain a newline in a multi-byte locale. This also should + fix the problem of bash slowing down drastically on long lines when + using a multi-byte locale, because it no longer tries to rewrite the + entire line each time. Patch from Jiro SEKIBA <jir@yamato.ibm.com> + +parse.y + - move the typedef for alias_t that is compiled in if ALIAS is not + defined up before the prototype for push_string, since that takes + an alias_t * parameter + +lib/readline/terminal.c + - bind the termcap description's left and right arrow keys to + rl_backward_char and rl_forward_char, respectively, instead of + rl_forward and rl_backward (which are just there for backwards + compatibility) + +aclocal.m4 + - when testing readability of /dev/stdin, redirect stdin from /dev/null + to make sure it's a readable file + + 9/17 + ---- +config-bot.h + - don't test __STDC__ when deciding whether or not to use stdarg.h; + just use it if it's present + +tests/read2.sub + - redirect from /dev/tty when using `read -t' + + 9/20 + ---- +builtins/history.def + - when reading `new' entries from the history file with `history -n', + fix increment of history_lines_this_session by taking any change + in history_base into account + +lib/sh/pathphys.c + - changes to sh_physpath to deal with pathnames that end up being + longer than PATH_MAX without dumping core + +lib/readline/doc/{history.3,hsuser.texinfo},doc/ bash.1 + - documented new `a' and `G' history modifiers + + 9/25 + ---- +lib/readline/misc.c + - when traversing the history list with arrow keys in vi insertion + mode, put the cursor at the end of the line (like in emacs mode) + +mksyntax.c + - don't try to use \a and \v unless __STDC__ is defined; use the + ascii integer equivalents otherwise + - include "config.h" in the generated syntax.c file for a possible + definition of `const' + +doc/{bash.1,bashref.texi} + - document the meaning of a null directory in $PATH + + 9/26 + ---- +parse.y + - fix set_line_mbstate to handle case where mbrlen() returns 0, + indicating the null wide character + - fix set_line_mbstate so we don't directly compare a char variable + to EOF, since char can (and is) unsigned on some machines + +bashline.c + - change bash_execute_unix_command to save a little bit more state: + last_shell_builtin, this_shell_builtin, last_command_exit_value + + 9/27 + ---- +execute_cmd.c + - tentative change to execute_simple_command to avoid freeing freed + memory in the case where bash forks early but still ends up calling + execute_disk_command, without passing newly-allocated memory to + make_child. This may fix the core dumps with the linux-from-scratch + folks + + 9/28 + ---- +Makefile.in,{builtins,lib/sh}/Makefile.in + - fix up dependencies, mostly on ${BUILD_DIR}/version.h, so that + parallel makes work with GNU and BSD makes + +shell.h + - new struct to save partial parsing state when doing things like + bash_execute_unix_command and other operations that execute + commands while a line is being entered and parsed + +parse.y + - new functions, save_parser_state() and restore_parser_state(), to + save and restore partial parsing state + +bashline.c + - change bash_execute_unix_command to call {save,restore}_parser_state + +builtins/jobs.def + - change execute_list_with_replacements to eliminate a run_unwind_frame + in favor of calling the cleanup explicitly and discarding the frame + +execute_cmd.c + - change execute_for_command to avoid a run_unwind_frame in the case + where the loop variable is readonly or otherwise not assignable + - change execute_select_command and execute_simple_command to use + discard_unwind_frame by running the cleanup code explicitly, instead + of using run_unwind_frame + - make sure execute_select_command decreases loop_level even on error + + 9/30 + ---- +doc/{bash.1,bashref.texi} + - fixed description of `unset' now that unsetting a previously-unset + variable is no longer an error + + 10/3 + ---- +{configure,config.h}.in + - augment check for strtold with additional check to detect the + horribly broken hp/ux 11.x implementation that returns `long_double'; + defines STRTOLD_BROKEN if so + +builtins/printf.def + - define floatmax_t as `double' if STRTOLD_BROKEN is defined + + 10/5 + ---- +lib/readline/keymaps.c + - don't automatically bind uppercase keys to rl_do_lowercase_version + in rl_make_bare_keymap + +lib/readline/readline.c + - explicitly check for ANYOTHERKEY binding to rl_do_lowercase_version + and dispatch to lowercase of key when a prefix is not matched + + 10/12 + ----- +bashline.c + - set COMP_WORDBREAKS in enable_hostname_completion to the value + of rl_completer_word_break_characters + +variables.c + - new special variable COMP_WORDBREAKS, controls the value of + rl_completer_word_break_characters + +variables.h + - new extern declaration for sv_comp_wordbreaks() + +subst.c + - change split_at_delims to behave more like shell word splitting if + the passed value for the delimiters is NULL, indicating that the + function is to use $IFS to split + +{execute_cmd,jobs,test,findcmd,input,make_cmd,redir,shell}.c +builtins/mkbuiltins.c,builtins/{fc,history,source,umask}.def +lib/sh/netconn.c +lib/termcap/termcap.c +lib/readline/histfile.c + - make sure all inclusions of <sys/file.h> are protected by + HAVE_SYS_FILE_H + +bashline.c + - don't turn off rl_filename_completion_desired in + attempt_shell_completion if the partial pathname contains a slash. + This still doesn't solve the problem of partial pathname completion + starting with a directory in the current directory without a + leading `./'. There's no way to tell the difference between that + and a file found in $PATH (which may contain `.') at the point that + attempt_shell_completion acts + + 10/18 + ----- +locale.c + - don't set lc_all to the default locale when LC_ALL is being unset + - new function, reset_locale_vars(), called to recompute the correct + locale variable values when LC_ALL is unset + - changed set_lang to not set LC_ALL, which it never should have been + doing in the first place, and to maintain a local variable `lang' + corresponding to $LANG + - change get_locale_var to use the precedence posix.2 specifies: + LC_ALL overrides individual variables; LANG, if set, is the default + - change set_locale_var to call get_locale_var to get the appropriate + value for the variable being set or unset + - call get_locale_var instead of using passed value in set_locale_var + to get the defaulting and precedence right + +lib/readline/nls.c + - new function, _rl_get_locale_var(), which does the same thing as + locale.c:get_locale_var(), with the right precedence and defaulting, + using sh_get_env_value to get the right bash variable values + - if HAVE_SETLOCALE is defined, _rl_init_eightbit first calls + _rl_get_locale_var to get the right value for LC_CTYPE, and uses + that in the call to setlocale. If _rl_get_locale_var returns NULL, + call setlocale() to get the current international environment, and, + finally, if that returns null, call setlocale with a second argument + of "" to force the implementation's `native' environment + +pcomplete.c + - change gen_wordlist_completions to dequote the text before comparing + it against the expanded word list + - changed gen_matches_from_itemlist to do the same thing + +bashline.c + - new global function, bash_dequote_word, calls bash_dequote_filename + on the text passed. Used by the programmable completion code + +lib/readline/histfile.c + - make sure that whenever read_history_range returns a non-zero value + that it sets errno to some useful value + + 10/19 + ----- +variables.c + - COMP_WORDBREAKS is now a dynamic variable, mirroring value of + rl_completer_word_break_characters. Makes sure that the variable + always points to dynamic memory if it's not null or the readline + default + +bashline.c + - change enable_hostname_completion to manage a dynamic value of + rl_completer_word_break_characters, since assignments to + COMP_WORDBREAKS can change its value unpredictably + +lib/readline/{complete.c,readline.h} + - rl_completer_word_break_characters no longer has `const' attribute + +bashline.c + - clean up necessary places due to rl_completer_word_break_characters + no longer being `const' + +doc/{bash.1,bashref.texi} + - document new COMP_WORDBREAKS variable + + 10/21 + ----- +print_cmd.c + - fix indirection_level_string to handle the case where the decoded + $PS4 is null without seg faulting + + 10/22 + ----- +builtins/shift.def + - make sure that there is actually an argument when reporting a shift + count that exceeds the number of positional paramters and + shift_verbose is enabled + +lib/readline/rltty.c + - change SET_SPECIAL to call a new function, set_special_char, since + it contains a block. It's called infrequently, so the performance + impact of making it a function should be negligible, and it helps + debugging + + 10/29 + ----- +bashline.c + - make sure the editor in VI_EDIT_COMMAND and EMACS_EDIT_COMMAND is + quoted; it might contain spaces (e.g., `emacs -nw') + +aclocal.m4 + - cache ac_cv_rl_version in RL_LIB_READLINE_VERSION macro + +configure.in + - change logic that sets RL_INCLUDEDIR so that it doesn't try to set + a bogus include path if the argument to --with-installed-readline + is `yes' -- helps with cross-compiling + +lib/readline/histexpand.c + - fix history_tokenize_word so that it handles <( and >( better + + 10/30 + ----- +redir.c + - fix write_here_string so it handles the case where `herestr' expands + to NULL without seg faulting + + 10/31 + ----- +mailcheck.c + - reverse logic flip from bash-2.05 that handled systems that don't + change the atime when the mailbox is accessed; make sure the file + is bigger before we report new mail. This is the case in the vast + majority of cases. Reported by jim@jtan.com + + 11/5 + ---- +parse.y + - change action for `for x; { list; }' and corresponding `select' + production to use \"$@\" instead of just $@, as it is with all the + other actions + + 11/9 + ---- +parse.y + - new flag for parse_matched_pair: P_DQUOTE, indicating that the + pair of characters being matched is between double quotes + - parse_matched_pair now passes P_DQUOTE down to recursive calls: + if the open char to be matched is a `"' or the passed-in flags + include P_DQUOTE, set the local `rflags' variable to P_DQUOTE and + pass `rflags' down to recursive calls + - if `rflags' includes P_DQUOTE, don't try to ansiexpand $'...' or + locale expand $"..."; consistent with other quoting constructs + + 11/11 + ----- +doc/{bash.1,bashref.texi} + - explicitly note that variables referenced in arithmetic expressions + without using `$' evaluate to 0 if they are null or unset + - note that a null variable value evaluates to 0 when used in an + arithmetic context, like when a variable with the `-i' attribute is + assigned a null value + - document the ${!prefix@} expansion as equivalent to ${!prefix*} + + 11/12 + ----- +doc/{bash.1,bashref.texi} + - note that the value of an arithmetic expression is as in C + - change the wording to note that `arithmetic evaluation' (not + arithmetic expansion, which has a different meaning) is performed + on the value assigned to a variable whose integer attribute is set + + 11/13 + ----- +execute_cmd.c + - fix execute_disk_command so it calls exit() after printing the error + message in a restricted shell context if the shell has already forked + (nofork != 0 && there are no pipes) + + 11/19 + ----- +builtins/type.def + - don't report on aliases unless expand_aliases is set and the parser + is performing alias expansion; changed tests/type.tests and + tests/type.right accordingly + + 11/25 + ----- +general.c + - fix for full pathnames including drive letters on cygwin from + Corinna (convert to posix-style paths, which the rest of the + code handles much better) + +lib/readline/text.c + - fixes to overwrite mode from jimmy@is-vn.bg: + o in _rl_overwrite_char, do the overwrite mode self-insert + as one group, even when overwriting more than 1 char + o in _rl_overwrite_char, do the insert before the delete so + that an undo positions the cursor on the character restored, + not to the right of it + o in _rl_overwrite_rubout, don't do rl_insert_char(' ') unless + rl_point < rl_end. Since overwrite-mode self-insert acts as + in insert-mode when at eol, make rubout behave like + insert-mode rubout + + 11/30 + ----- +lib/readline/misc.c + - call rl_replace_line with `1' as second parameter if we're going to + immediately overwrite the undo list + +lib/readline/search.c + - in make_history_line_current, use _rl_replace_text to make the line + replacement an undoable operation. Affects all non-incremental + search functions. + +parse.y + - make behavior introduced on 11/9 dependent on extended_quote + variable, controllable by extquote shopt option. Default setting is + on for backwards compatibility + +builtins/shopt.def + - new `extquote' option to control extended_quote variable + + 12/3 + ---- +jobs.c + - change message printed when attempting to put a background job in + the background with `bg' to include the job id and make the + statement declarative + + 12/10 + ----- +bashhist.h + - define explicit flag values for history_control + +variables.c + - change sv_history_control to use new flag values + - change sv_history_control to parse $HISTCONTROL as a colon-separated + list of values for the history_control variable + +bashhist.c + - change check_history_control to use new flag values and restructure + to remove case statement + - new function hc_erasedups(line); removes all entries matching LINE + from the history list + - call hc_erasedups() from check_add_history after we've determined + that we're saving the line + +doc/{bash.1,bashref.texi} + - documented new options available for $HISTCONTROL and that it can + be a colon-separated list of history control options + + 12/11 + ----- +subst.c + - fix pat_subst() to not increment `e' (pointer to the end of the + matched portion of the string) until after we're sure we're going + around the loop again; fixes problem with empty replacements for + a pattern that doesn't match (bug reported by Don Coleman + <don@coleman.org>) + + 12/17 + ----- +lib/readline/display.c + - fixes to multibyte redisplay from jir@yamato.ibm.com (Jiro SEKIBA): + o speed up calculation of first difference between old and new + lines in the common case + o don't try to see if we're in the middle of a multbyte char + in update_line (we'll see how this one works out) + + 12/18 + ----- +doc/bashref.texi + - make it clear that the `command-list' function definition may be + terminated by an ampersand before the closing brace + + 12/28 + ----- +redir.c + - set `expanding_redir' flag when expanding words in a redirection + +subst.c + - new function, exp_jump_to_top_level(), to do any word expansion + cleanup before a call to jump_to_top_level from within that file; + sets expanding_redir back to 0 before jump_to_top_level + +variables.c + - in find_variable(), don't call find_variable_internal with a second + parameter of 1 if expanding_redir is non-zero + - in find_variable_internal(), don't search the temporary env if + subshell_environment includes SUBSHELL_FORK (indicating a simple + command) and expanding_redir is non-zero + +parse.y + - increment line_number when we read a \<newline> pair + +array.c + - added array_unshift_element and array_shift_element (which just call + array_shift and array_rshift, respectively), for bash debugger + support + + 1/4/2003 + -------- +doc/{bash.1,bashref.texi} + - note in the section describing the execution environment passed to + children that subshells inherit shell functions marked for export + - note in the section describing shell functions the possibility + that exported functions may result in two entries in the environment + with the same name + +parse.y + - when pushing an alias expansion onto the pushed_string list, append + a space to the expanded definition to make the parser's lookahead + work without using the `mustpop' hack in shell_getc + + 1/8 + --- +shell.c + - change calls to exit() with EX_USAGE as a parameter to use + EX_BADUSAGE instead, since EX_USAGE is defined as 258 and is + technically out of range + + 1/14 + ---- +aclocal.m4 + - check for the termcap functions in libc first: if we don't have + to link in another library, let's not do it + - change the test for mbstate_t to use AC_TRY_COMPILE instead of + AC_TRY_RUN + +doc/{bash.1,bashref.texi} + - document that bash turns line editing off if environment variable + EMACS is set to `t' when it starts up + +doc/bash.1 + - minor change to give the ftp url for the latest version of bash in + the bug reports section + +lib/readline/histexpand.c + - in get_history_event, cast a couple of `const char *' variables to + `char *' in function call parameter lists to avoid compiler warnings + + 1/21 + ---- +builtins/cd.def + - change `cd -' so it prints the current working directory after a + successful chdir even when the shell is not interactive + + 1/31 + ---- +lib/readline/doc/rltech.texinfo + - clarified exactly what is meant by the term `application-specific + completion function', made its use consistent, and documented + what variables are changed before such a function is called + +lib/readline/input.c + - new function, _rl_pushed_input_available(), returns non-zero if + there are characters in the input queue managed by rl_get_char + and _rl_unget_char + +lib/readline/rlprivate.h + - new extern declaration for _rl_pushed_input_available + +lib/readline/callback.c + - change rl_callback_read_char to check _rl_pushed_input_available + and loop if there's something there, so characters don't languish + until more keyboard input is read + +execute_cmd.c + - new variable, last_command_exit_signal, non-zero if + last_command_exit_value result from wait_for was result of a signal + +nojobs.c + - keep track of whether or not a given pid was killed by a signal with + a new flag in the pid_list array + - new function int find_termsig_by_pid(pid_t pid) to get the + terminating signal, if any, for a particular pid + - new function int get_termsig(WAIT status) returns the terminating + signal corresponding to status + - set last_command_exit_signal in wait_for and the various wait_for_xx + functions + +jobs.c + - new functions, process_exit_signal and job_exit_signal, return the + signal that killed a given process or job, if a signal caused its + death + - set last_command_exit_signal in wait_for by calling job_exit_signal + or process_exit_signal appropriately + +subst.c + - don't resend SIGINT to ourselves unless last_command_exit_signal is + SIGINT and last_command_exit_value == 128 + SIGINT. This fixes the + $(exit 130) bug reported by Paul Jarc + +expr.c + - new function, expr_bind_variable, calls bind_int_variable and + then stupidly_hack_special_variables. This fixes the + `let OPTIND=1' bug + +bashline.c + - change history_and_alias_expand_line and shell_expand_line to call + history_expand_line_internal so calls to pre_process_line are + localized + - change history_expand_line_internal and cleanup_expansion_error to + temporarily turn off hist_verify before calling pre_process_line + to avoid the effects described by teirllm@dms.auburn.edu + +parse.y + - don't unconditionally turn off PST_ALEXPNEXT in push_string. This + fixes the multiple alias expansion bug reported by Paul Jarc. + +lib/readline/vi_mode.c + - change rl_vi_subst to push `l' instead of ` ' -- it should be + equivalent, but this has been reported to fix a problem in multibyte + locales + +lib/readline/readline.h + - new state flag value RL_STATE_TTYCSAVED, indicates that save_tty_chars + has been called. Since it's only used and visible internally, it's + undocumented + +lib/readline/rltty.h + - changed all of the members of _rl_tty_chars struct to `unsigned char' + +lib/readline/rltty.c + - set the RL_STATE_TTYCSAVED after save_tty_chars is called + - new function, rl_tty_unset_default_bindings(), resets bindings for + everything rl_tty_set_default_bindings() messes with back to + rl_insert, so rl_tty_set_default_bindings can be called again with + possible changes + - new function that does the bulk of the work for + rltty_set_default_bindings: _rl_bind_tty_special_chars() + - change prepare_terminal_settings so that it can track changes to the + terminal special chars made by stty(1): unset the bindings with + rl_tty_unset_default_bindings before calling save_tty_chars, and + _rl_tty_set_default_bindings after, with the new values from + get_tty_settings(). This implements a long-standing request, most + recently made by Tim Waugh of Red Hat. + +lib/readline/readline.h + - extern declaration for rl_tty_unset_default_bindings() + +lib/readline/readline.c + - new function, reset_default_bindings, calls + rl_tty_unset_default_bindings() to reset the terminal special chars + back to rl_insert and then read the new ones + +lib/readline/doc/rltech.texinfo + - documented rl_tty_unset_default_bindings() + + 2/1 + --- +[prayers and condolences to the families of the space shuttle crew members] + +aclocal.m4 + - add checks for mbrtowc and mbrlen in BASH_CHECK_MULTIBYTE + - new check, BASH_FUNC_CTYPE_NONASCII, checks whether or not the ctype + functions handle non-ascii characters correctly + +config.h.in + - add HAVE_MBRTOWC and HAVE_MBRLEN + - add NO_MULTIBYTE_SUPPORT for new configure argument + - add CTYPE_NON_ASCII + +config-bot.h, lib/readline/rlmbutil.h + - make sure that mbrtowc, mbrlen, and wcwidth are all present before + turning on HANDLE_MULTIBYTE + - turn off multibyte chars if NO_MULTIBYTE_SUPPORT is defined + +configure.in + - new argument --enable-multibyte (enabled by default), allows + multibyte support to be turned off even on systems that support it + +lib/readline/chardefs.h + - define NON_NEGATIVE as 1 if CTYPE_NON_ASCII is defined + + 2/3 + --- +config.h.in + - add HAVE_WCTOMB + +aclocal.m4 + - check for wctomb in BASH_CHECK_MULTIBYTE + + 2/4 + --- +lib/readline/vi_mode.c + - in _rl_vi_change_mbchar_case, make sure the result from wctomb() + is NULL-terminated before trying to insert it with rl_insert_text() + + 2/5 + --- +lib/readline/display.c + - fix to update_line to avoid problems on systems with multibyte + characters when moving between history lines when the new line + has more glyphs but fewer bytes (twaugh@redhat.com) + +lib/readline/vi_mode.c + - use wcrtomb() instead of wctomb() in _rl_vi_change_mbchar_case + +pcomplete.c + - fix init_itemlist_from_varlist to handle the case where the + `varlist' is NULL + +doc/{bash.1,bashref.texi} + - clarified when a simple command may fail without the shell exiting + when -e is set + + 2/13 + ---- +parse.y + - when bash is started with --nolineediting, ignore \[ and \] when + decoding the prompt string + +subst.c + - fix remove_quoted_nulls so that a string with a CTLESC appearing + after a CTLNUL (which was removed) does not leave characters in + the string inappropriately + + 2/14 + ---- +builtins/common.h + - new flag value for parse_and_execute(): SEVAL_RESETLINE, which + allows the caller to specify whether or not the internal idea + of the line number should be reset to 1 + +builtins/evalstring.c + - parse_and_execute() now tells push_string to reset the line + number only if the SEVAL_RESETLINE flag is set by the caller + + 2/15 + ---- +builtins/evalfile.c + - pass SEVAL_RESETLINE from _evalfile() to parse_and_execute() + +subst.c + - if the shell is currently interactive, pass SEVAL_RESETLINE to + parse_and_execute() when doing command substitution + +jobs.c + - add SEVAL_RESETLINE to parse_and_execute while running SIGCHLD trap + +command.h + - add `line' members to case_com, for_com, select_com + - rearranged order of members in some of the command structs, so + `flags' and `line' are first + - added a `source_file' member to the function_def struct; keeps + track of where the function was defined + +doc/Makefile.in + - add some new suffix rules: .dvi.ps + +doc/{bash.1,bashref.texi} + - added text to the description of the `trap' builtin tightening up + the language describing when the ERR trap will be run + +error.c + - if $BASH_SOURCE (internally-maintained) exists, use BASH_SOURCE[0] + in get_name_for_error if the shell is not interactive + +array.h + - new convenience defines: array_push and array_pop + +variables.c + - change get_funcname to return this_shell_function->name only if + arrays have not been compiled into the shell + - change init_funcname_var to initialize FUNCNAME as an array variable + if we have arrays + - new function: get_self(SHELL_VAR *self), a degenerate `dynamic_value' + function for dynamic variables + - new function: init_dynamic_array_var(), a generic dynamic array + variable initializer to handle the common case + - use init_dynamic_array_var() instead of explicit init_dirstack_var() + - use init_dynamic_array_var() instead of explicit init_groups_var() + - new dynamic array variables: BASH_ARGC, BASH_ARGV, BASH_SOURCE, + BASH_LINENO, initialized with init_dynamic_array_var + +shell.c + - initialize BASH_LINENO, BASH_SOURCE, FUNCNAME in open_shell_script + +{execute_cmd,trap}.c + - take out trap_line_number, since parse_and_execute doesn't reset the + line number any more when running the trap commands + +make_cmd.c + - augment make_function_def to get source file name and call + bind_function_def to save the entire FUNCTION_DEF + +variables.c + - new hash table: shell_function_defs, keeps table of shell function + definitions including source file and line number info corresponding + to shell_functions table + - new functions: find_function_def and bind_function_def to manage + the shell_function_defs hash table + - new function: unbind_function_def to remove a function definition + from the shell_function_defs table (right now uncalled) + +variables.h + - extern declaration for bind_function_def, find_function_def + - new extern declaration for unbind_function_def + +execute_cmd.c + - in function prologue and epilogue, push and pop FUNCNAME, + BASH_SOURCE, and BASH_LINENO information + +dispose_cmd.c + - broke the code that disposes a FUNCTION_DEF out into two new + functions: dispose_function_def and dispose_function_def_contents + +dispose_cmd.h + - new extern declarations for dispose_function_def_contents and + dispose_function_def + +copy_cmd.c + - move body of copy_function_def (other than allocating a new + FUNCTION_DEF) to copy_function_def_contents + - make sure to copy the new source_file member of a function_def in + copy_function_def_contents + - copy_function_def is no longer static, copy_function_def_contents + is not either + +command.h + - new extern declaration for copy_function_def_contents and + copy_function_def + +parse.y + - keep a stack of line numbers where case, select, and for commands + start, with a maximum nesting level of 128; increment when reading + word after `for', `select' or `case' in read_token_word; decrement + in grammar actions after parsing a complete for, arith_for, select, + or case command + - create for, case, arith_for, and select commands with an extra + line number (word_lineno[word_top]) argument + +make_cmd.c + - make_for_or_select, make_for_command, make_case_command, and + make_select_command all take an extra `line_number' argument + +make_cmd.h + - corresponding changes to extern declarations for those functions + + 2/16 + ---- +{execute_cmd,shell,variables}.c + - follow each call to remember_args with a call to push_args or + pop_args to manage the BASH_ARGV and BASH_ARGC arrays. Only set + when the shell is started to run shell script or runs a shell + function. Doesn't handle `set' or `shift' yet, nor `source'. + +execute_cmd.c + - keep track of the level of subshells with a new variable, manipulated + in execute_in_subshell + - set currently_executing_command in execute_command_internal(), + even if we're running a trap + - better line number management when executing simple commands, + conditional commands, for commands in execute_command_internal() + and the various functions that implement the commands + (execute_cond_command, execute_for_command, execute_etc.) + +variables.c + - new dynamic variable BASH_SUBSHELL, with new get_subshell and + assign_subshell functions to manipulate it + - new functions push_args (WORD_LIST *list) and pop_args (void) to + manage the BASH_ARGC and BASH_ARGV dynamic array variables + +variables.h + - new extern declarations for push_args and pop_args + +builtins/evalfile.c + - in _evalfile, do appropriate things to the FUNCNAME, BASH_ARGV, + BASH_ARGC, BASH_SOURCE, and BASH_LINENO variables + +support/mksignames.c + - add another fake signal for `trap'; make NSIG+2 == `RETURN' + +trap.c + - _run_trap_internal now returns an int: the exit value of the command + run as the result of the trap + - run_debug_trap now returns an int: the exit value of the command + run as the result of the trap + - RETURN is a new special trap + - new function: set_return_trap(char *command) interface for the rest + of the shell, like set_{debug,error}_trap + - new function: run_return_trap() + - command substitution and other child processes don't inherit the + return trap + +trap.h + - new extern declaration for set_return_trap() and run_return_trap + - new defines for RETURN_TRAP; increment BASH_NSIG + - change extern declaration for run_debug_trap() since it now returns + an int + +shell.c + - new invocation long option: --debugger, turns on debugging and + sets internal `debugging_mode' variable + +execute_cmd.c + - new code to save return trap when executing a shell function, so + shell functions don't inherit it + - run debug trap before binding the variable and running the action + list in a `for' command + - run debug trap before binding the selection variable and running + the query in a `select' command + - run debug trap before running matcher in a `case' command + +builtins/set.def + - new `set -o functrace' (set -T), causes DEBUG trap to be inherited + by shell functions + - new `set -o errtrace' (set -E), causes ERR trap to be inherited + by shell functions + +flags.c + - new flags -E and -T, control error_trace_mode and + function_trace_mode respectively + +flags.h + - new extern declarations for error_trace_mode and function_trace_mode + + 2/17 + ---- +doc/bashref.texi + - changed the `dircategory' as per Karl Berry's suggestion + +doc/texinfo.tex + - update to version of 2003/02/04 from texinfo.org + +support/texi2dvi + - update to version 1.14 from texinfo-4.5 distribution + + 2/20 + ---- +support/config.{guess,sub} + - update to versions of 2002/11/30 + +lib/readline/doc/manvers.texinfo + - renamed to version.texi to match other GNU software + - UPDATE-MONTH variable is now `UPDATED-MONTH' + +lib/readline/doc/{hist,rlman,rluserman}.texinfo + - include version.texi + +doc/version.texi + - new file, with standard stuff matching other GNU distributions + +{doc,lib/readline/doc}/Makefile.in + - include right stuff for `version.texi' + +lib/readline/doc/{rluserman,rlman,hist}.texinfo + - use @copying and @insertcopying and @ifnottex instead of @ifinfo + - add FDL as an appendix entitled `Copying This Manual' + +lib/readline/doc/{rltech,rluser,hstech,hsuser}.texi + - changed the suffix from `texinfo' to `texi' + +lib/readline/doc/{rlman,rluserman}.texinfo, doc/bashref.texi + - include rltech.texi,rluser.texi,hstech.texi, and hsuser.texi + +lib/readline/doc/Makefile.in,doc/Makefile.in + - made appropriate changes for {{rl,hs}tech,{rl,hs}user}.texi + +lib/readline/doc/{rlman,rluserman}.texinfo + - changed the suffix from `texinfo' to `texi' + +lib/readline/doc/hist.texinfo + - renamed to history.texi + + 2/25 + ---- +pathnames.h.in + - moved pathnames.h here so value of DEBUGGER_START_FILE can be + substituted by configure + +aclocal.m4 + - added AM_PATH_LISPDIR for debugger + +configure.in + - added some variables: `bashvers', `relstatus' to use info in more + than one place + - call AM_PATH_LISPDIR + - new option: --enable-debugger, sets DEBUGGER cpp option + - new option with AC_ARG_VAR: DEBUGGER_START_FILE + - make `pathnames.h' a file generated by configure + +Makefile.in + - add rule to create pathnames.h + +builtins/declare.def + - added extra line number and source file name to `declare -F' output + if `--debugger' is used at startup + +builtins/evalfile.c + - call run_return_trap from source_file before returning the result + from _evalfile() + +execute_cmd.c + - call run_return_trap in execute_function before restoring the old + context + +builtins/source.def + - arrange to save and restore DEBUG traps when sourcing files if + function_trace_mode (set -o functrace) is not set + +print_cmd.c + - broke print_for_command, print_select_command, print_case_command + into two functions each: one to print the `header' and one for + the body + - print_cond_command is no longer static + - print_arith_command now takes a WORD_LIST *, since it doesn't + actually do anything with the ARITH_COM it's passed except print + the enclosed WORD_LIST + - print_arith_command is no longer static + +externs.h + - extern declarations for print_{for,select,case}_command_head, + print_cond_command, print_arith_command + +{.,builtins,lib/sh}/Makefile.in + - corrected dependencies on pathnames.h, since it's now created in + the build directory + + 3/5 + --- +lib/glob/glob.c + - handle alloca() failing (it's supposed to return NULL) + - use malloc() (with its attendent bookkeeping) instead of alloca() + in glob_filename() + +subst.c + - check whether shell_glob_filename returns NULL in + glob_expand_word_list + - change parameter_brace_expand_rhs to handle cases like + ${a[2]:=value} by properly creating the array element instead of a + variable named `a[2]' (reported by <opengeometry@yahoo.ca>) + +variables.c + - change bind_int_variable to use valid_array_reference instead + of looking for `[' + +lib/readline/vi_mode.c + - check for `a' in _rl_vi_done_inserting so the text inserted by an + `a' command can be reinserted with a `.' + +lib/readline/readline.c + - when entering vi insertion mode in readline_internal_setup(), make + sure that _rl_vi_last_key_before_insert is set to `i' so that undo + groups and redo work better (reported by <opengeometry@yahoo.ca>) + +lib/glob/sm_loop.c + - handle ?(...) in a pattern immediately following a `*', instead of + ignoring the `(' and treating the `?' as a single-char match, as + long as FNM_EXTFLAG is set (reported by <anderson110@poptop.llnl.gov>) + +aclocal.m4 + - new test for presence of struct timezone, BASH_STRUCT_TIMEZONE + +config.h.in + - add HAVE_STRUCT_TIMEZONE + +configure.in + - call BASH_STRUCT_TIMEZONE + +execute_cmd.c + - don't try to use `struct timezone' in calls to gettimeofday unless + HAVE_STRUCT_TIMEZONE is defined; use (void *)NULL otherwise + + 3/20 + ---- +execute_cmd.c + - new variable, the_printed_command_except_trap, saves the command + being executed before a trap is executed, for the debugger + +trap.c + - if in debugging mode, let command substitutions and other child + processes inherit the DEBUG and ERR traps if the `functrace' + (which is really a bad name, given this semantic) or `errtrace' + options, respectively, have been set + +shell.c + - local_pending_command renamed to command_execution_string; no longer + static + +variables.c + - new dynamic variable, BASH_COMMAND, set to the command string + currently executing, or the one that caused a trap to execute + (mapped to the_printed_command_except_trap) + - new variable, BASH_EXECUTION_STRING, set to the argument to the + -c invocation option, if the shell was started that way + + 3/22 + ---- +execute_cmd.c + - changed execute_for_command, eval_arith_for_expr, + execute_select_command, execute_arith_command, execute_cond_command, + execute_simple_command to implement new DEBUG trap semantics + for the debugger: if the DEBUG trap commands return a non-zero + status and debugging_mode is non-zero, we skip the command to be + executed + +trap.c + - change run_debug_trap for the 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' + +shell.c + - new function, start_debugger(), that sources the debugger start file + and turns the debugger on + +builtins/shopt.def + - new settable option, `extdebug', turns on debugging_mode, as if + --debugger had been supplied at invocation (but does not source + debugger startup file) + +trap.c + - make sure that run_exit_trap arranges for `returns' to come back + there, too, so a `return' executed by an `exit' invoked within a + shell function behaves correctly + +support/shobj-conf + - change darwin/MacOS X stanza based on advice from mac os x developers + +lib/sh/mailstat.c + - set the atime member of the synthesized stat struct to 0 if `cur/' + is empty, rather than leaving it undefined + + 3/24 + ---- +builtins/caller.def + - new builtin to provide a call stack for the debugger + +builtins/evalfile.c + - added a second `flags' argument to source_file() + - new flag value for flags argument to _evalfile(): FEVAL_NOPUSHARGS. + If included in flags arg, it means to not manipulate the BASH_ARGV + and BASH_ARGC arrays + +builtins/common.h + - change prototype for source_file() + +builtins/source.def + - add flag value to call to source_file(): set to 1 if we replaced + the positional parameters + - add call to push_args if additional arguments supplied to the + source builtin + - add call to pop_args in maybe_pop_dollar_vars + +execute_cmd.c + - run the debug trap in execute_function so the debugger can stop + before the first command in a function body is executed + - modify subshell_level before executing a builtin or function in a + subshell + - print `for', `select', `case' command heads when set -x is enabled + +print_cmd.c + - `xtrace_print_word_list' now takes an additional flags argument, + which, if non-zero, says to print indirection_level_string() + - new functions to print for, select, and case command heads when + set -x is enabled + - add spaces after `((' and before `))' in xtrace_print_arith_command + +externs.h + - changed extern declaration for xtrace_print_word_list + - new declarations for xtrace_print_{for,case,select}_command_head() + +subst.c + - modify subshell_level when executing a command substitution + + 3/25 + ---- +execute_cmd.c + - use `line_number' in executing_line_number instead of looking into + the current command if it's a simple command; rearrange code to + make this simpler to compile in and out + - need to save and restore value of currently_executing_command around + calls to debug trap and return trap in execute_function + +make_cmd.c + - make sure make_arith_for_command() disposes the WORD_LIST * it is + passed, since nothing else does and it's not used directly + + 3/28 + ---- +Makefile.in + - fixed dependencies for `error.o' on shell.h and version.h -- makes + parallel makes (gmake -j 4) work correctly + +doc/{bash.1,bashref.texi} + - documented all new features added to support the debugger + + 4/1 + --- +lib/sh/shquote.c + - make sure CTLESC and CTLNUL characters are escaped with CTLESC + by sh_double_quote, sh_backslash_quote and + sh_backslash_quote_for_double_quotes + Fixes vulnerability reported by svdb@stack.nl + +shell.h + - new `pipestatus' member of sh_parser_state_t, to save and restore + $PIPESTATUS + +parse.y + - changes to save_parser_state and restore_parser_state to save and + restore $PIPESTATUS + +builtins/read.def + - add a call to word_list_remove_quoted_nulls before assigning the + word list read from standard input to an array variable. Fixes + bug reported by holzhey@ppprs1.phy.tu-dresden.de + + 4/3 + --- +execute_cmd.c + - in execute_null_command, if redirections are supplied, make sure + things like 3</etc/passwd are undone immediately, since they're + being done in the current shell + - functions now inherit the RETURN trap only if function tracing is + on for that function or globally + +lib/readline/misc.c + - in rl_replace_from_history, don't force rl_replace_line to clear + the undo_list, since it might point directly at an undo list + from a history entry (to which we have no handle) + + 4/4 + --- +trap.c + - initialize RETURN_TRAP stuff appropriately in initialize_traps() + - let command substitutions inherit the RETURN trap if we're in + the debugger and function tracing has been enabled + +redir.c + - do_redirections and do_redirection_internal now take a single + flags argument instead of multiple boolean flags + +redir.h + - new #defines for flags argument to do_redirection{s,_internal} + +execute_cmd.c + - change all calls to do_redirection to use new flag values + +parse.y + - new function, free_pushed_string_input(), an external interface to + clear the pushed_string list (alias expansion) + - new define SHOULD_PROMPT to say when it's OK to call prompt_again + (if the shell is currently interactive and is reading input from + the terminal or readline) + - make sure shell_getc and read_secondary_line only call prompt_again + if SHOULD_PROMPT evaluates to true + - prompt_again shouldn't do anything if the shell is currently in the + middle of expanding a multiline alias, since we won't be printing a + prompt anyway + +externs.h + - new extern declaration for free_pushed_string_input() + +execute_cmd.c + - command_substitute and process_substitute now call + free_pushed_string_input because they shouldn't deal with any + partial alias expansion the parent shell may have started + + 4/5 + --- +braces.c + - added {x..y} brace expansion, shorthand for {x,x+1,x+2,...,y}: + x, y can be integers or single characters; the sequence can be + ascending or descending; increment is always 1. Beware that + something like {a..A} can lead to non-letters. + + 4/7 + --- +subst.c + - change extract_delimited_string and extract_dollar_brace_string to + return NULL on an expansion error when no_longjmp_on_fatal_error + is set, so the calling functions don't assume that the expansion + was successful (primarily the prompt expansion and completion code) + +doc/{bash.1,bashref.texi} + - documented new sequence generation feature of brace expansion + + 4/8 + --- +lib/sh/strstr.c + - replacement for strstr(3), in case the C library doesn't provide it + +configure.in + - check for strstr, add to LIBOBJS if not found + +array.c + - array_walk now takes a third void * argument; it's passed to `func' + as its second argument + +array.h + - change sh_ae_map_func_t prototype to add void * second argument + + 4/10 + ---- +array.c + - new function: array_keys_to_word_list, returns a list of indices for + a given array + +array.h + - new extern declaration for array_keys_to_word_list + +arrayfunc.c +3 - new function: char *array_keys(), returns a string with keys for a + given array, with the appropriate quoting + +arrayfunc.h + - new extern declaration for array_keys + +subst.c + - code to implement ksh93-like ${!array[@]} expansion (array[*] works, + too), which expands to all the keys (indices) of ARRAY + +doc/{bash.1,bashref.texi} + - documented new ${!array[@]} expansion + + 4/19 + ---- +builtins/setattr.def + - remove any mention of the `-n' option from readonly builtin's short + and long documentation + +pcomplib.c + - fix progcomp_insert to increase the refcount on the `cs' argument + before calling hash_insert -- fixes the problem of multiple calls + to progcomp_insert with the same compspec + +doc/bash.1 + - add mention of characters that inhibit history expansion when found + immediately following an unquoted `!' + +bashline.c + - convert the code conditionally compiled in by the NO_FORCE_FIGNORE + #define to something runtime-tunable with the `force_fignore' + variable (opposite sense). force_fignore is 1 by default + +builtins/shopt.def + - new tunable `shopt' option: `force_fignore', controls force_fignore + variable and behavior of FIGNORE handling + +lib/readline/complete.c + - new variable, _rl_complete_show_unmodified, causes completer to list + possible completions if more than one completion and partial + completion cannot be done + - new value for what_to_do argument to rl_complete_internal, `@', + indicating that we want the show-unmodified behavior + - change rl_completion_type to return `@' when appropriate + +lib/readline/bind.c + - new bindable variable, show-all-if-unmodified, which controls value + of _rl_complete_show_unmodified + +lib/readline/rlprivate.h + - extern declaration for _rl_complete_show_unmodified + +lib/readline/doc/rluser.texi + - documented show-all-if-unmodified + +lib/readline/doc/rltech.texi + - documented new `@' value for second argument to rl_complete_internal + - documented new return value from rl_completion_type + + 4/22 + ---- +lib/readline/signals.c + - in rl_set_signal, set sa_flags to SA_RESTART for SIGWINCH, if we + have POSIX signals -- this is what most applications expect, and + they're not prepared to deal with EINTR + + 4/25 + ---- +bashline.c + - take out attempts to suppress readline filename completion when + attempting command completion and there is a directory with the + same name in the current directory. #if 0'd for now; maybe make + it conditional later + +error.c + - new variable, gnu_error_format, causes non-interactive errors with + line numbers to be printed in the `gnu style' (filename:lineno:) + instead of the `shell style' (filename: line lineno:) by + error_prolog and parser_error + +version.h,support/mkversion + - don't put extern function declarations into created version.h any + more + +version.c,externs.h + - add extern declarations for show_shell_version() and + shell_version_string(), since they're no longer in version.h + (this backs out change from 9/10/2001) + +shell.h + - don't include version.h + +Makefile.in + - remove unneeded dependencies on version.h -- only version.o + needs it now + +builtins/shopt.def + - new option `gnu_errfmt', changes error messages with line numbers + to use the `standard' gnu format + +pcomplete.h + - new COPT_BASHDEFAULT and COPT_PLUSDIRS defines + +bashline.c + - if the COPT_BASHDEFAULT flag is set, try the rest of the bash + default completions if a compspec with that flag set generates + no matches + - broke bash completions out into separate function: + bash_default_completion(const char *text, int start, int end, + int qc, int in_command_position); change attempt_shell_completion + to call it + +bashline.h + - new extern declaration for bash_default_completion + +builtins/complete.def + - added code to compgen to call bash_default_completion if a compspec + with the COPT_BASHDEFAULT flag set generates no matches from the + programmable completion options + +doc/{bash.1,bashref.texi} + - document new `gnu_errfmt' shopt option + +doc/bash.1,lib/readline/doc/rluser.texi + - document new `-o bashdefault' option to complete and compgen + + 4/26 + ---- +pcomplete.c + - if a compspec has the COPT_PLUSDIRS flag set, generate any + directory name completions and add them to the set of possible + completions as the last thing in gen_compspec_completions + +builtins/complete.def + - add new `-o plusdirs' option to complete and compgen; means to + do directory name completion in addition to other actions + specified by the compspec, and do it last + + 5/12 + ---- +copy_cmd.c + - fix copy_{for,select,case}_command to copy the line member + + 5/13 + ---- +lib/readline/rlmbutil.h,include/shmbutil.h + - new #define MB_INVALIDCH, evaluates to true if return value from + mbrtowc or mbrlen denotes an invalid multibyte character + - new #define MB_NULLWCH, evaluates to true if return value from + mbrtowc or mbrlen denotes a null multibyte character + +lib/readline/complete.c + - new function, fnwidth(), returns printed length of a filename, + correctly handling multibyte characters + - new function, fnprint(), displays a filename on rl_outstream + correctly handling multibyte characters + - use fnwidth() instead of simple strlen() for length calculations + in display_matches + +lib/readline/{display,mbutil}.c + - use MB_INVALIDCH and MB_NULLWCH as appropriate + + 5/21 + ---- +configure.in + - turn off the builtin malloc on GNU/FreeBSD systems (GNU userland, + FreeBSD kernel) + + 5/24 + ---- +pcomplete.c + - in programmable_completions, copy the compspec before using it to + generate the possible completions, allowing the completion for the + command to be changed by the compspec itself without causing a + core dump because the shell frees freed memory (reported by + marcus.harnish@gmx.net) + +parse.y + - in shell_getc, don't call notify_and_cleanup in an interactive shell + unless the shell is currently reading from the terminal and would + print a prompt. This fixes programmable completions printing job + notifications (reported by r.d.green@lancaster.ac.uk) + - use SHOULD_PROMPT macro consistently + +shell.c + - use get_string_value instead of getenv when looking up $TERM and + $EMACS to see whether the shell is running under emacs + - check for `TERM=dumb' as well as `EMACS=t' to decide whether or + not to turn off command-line editing in emacs shell windows + (reported by jik@kamens.brookline.ma.us) + + 5/28 + ---- +expr.c + - save and restore the `evalbuf' context, since evalexp can be + called recursively (e.g. a[b[c]]) + + 5/29 + ---- +builtins/common.c + - in display_signal_list, when displaying for `kill -l' in posix mode, + display signal names without the `SIG' prefix + +doc/bashref.texi + - documented changed to posix mode behavior of kill -l + +builtins/kill.def + - changed the error message printed when argument is not a pid or + job id + +doc/{bash.1,bashref.texi} + - fixed a slight inconsistency in the different sections describing + the `promptvars' option + +doc/Makefile.in + - new rule to create `bash.info' from `bashref.info' by running sed + to change the internal references. This makes the installed + bash.info work right + - make the install target install bash.info after it's been modified + from bashref.info + + 5/30 + ---- +builtins/cd.def + - after testing with ferror(), call clearerr if ferror() evaluates + to true + +execute_cmd.c + - call clearerr(stdout) after executing a builtin or function, + before restoring any redirections + +bashhist.c + - initialize history_comment_char in bash_history_initialize + +builtins/alias.def + - if posix mode is enabled, and the `-p' option is not supplied, don't + list aliases with a preceding `alias ', as POSIX.2 specifies + +doc/bashref.texi + - note new posix mode behavior of displaying alias names and values + - note new posix mode behavior of trap builtin not checking first + argument to be a possible signal specification + - note new posix mode behavior of `kill' not accepting signal names + with a leading `SIG' + +include/stdc.h,lib/readline/rlstdc.h + - don't check the __STRICT_ANSI__ define when deciding whether or not + to #undef __attribute__ + +trap.[ch] + - decode_signal and signal_object_p take an additional flags arg to + satisfy POSIX.2 signal name translation requirements + - change decode_signal to honor the new DSIG_NOCASE (match case- + insensitively) and DSIG_SIGPREFIX (allow signal specifications + with the `SIG' prefix) flags + +builtins/{common.c,{trap,kill}.def} + - change calls to decode_signal to add the new argument with + appropriate values. For kill, POSIX.2 says case-insensitive without + the `SIG' prefix. For trap, POSIX.2 says applications may decode + case-insensitively and with the SIG prefix + +builtins/trap.def + - when in posix mode, don't check for the first argument being a + possible signal spec and revert the signal handling to the + original disposition + + 6/1 + --- +shell.h + - new MATCH_STARSUB define, to tell the callers of the various pattern + substitution and removal functions that call string_list to treat + "$*" and "${array[*]}" appropriately +subst.c + - if get_var_and_type encounters an array variable subscripted by `*' + or `$*', return VT_STARSUB or'd into the variable type value + - callers of get_var_and_type check for VT_STARSUB in the returned type + this will fix problems with ${*...} not being separated with the + first character of $IFS when double-quoted + - in parameter_brace_patsub, set MATCH_STARSUB if VT_STARSUB is set by + get_var_and_type + - change pos_params_pat_subst to call string_list_dollar_star if + the match flags include MATCH_STARSUB + - change parameter_brace_substring to call array_subrange with an + additional argument indicating the character indexing the array + +array.c + - change array_patsub to join the modified array elements with the + first character of $IFS if MATCH_STARSUB is set in the match flags + passed in + - array_subrange now takes an additional argument indicating the + index type -- used to separate with first char of $IFS if the + index char is `*' and the expression is double-quoted + +array.h + - change prototype declaration of array_subrange to add additional arg + + 6/2 + --- +doc/FAQ + - merged in some updates about POSIX from Andrew Josey + + 6/3 + --- +bashjmp.h + - new value for jump_to_top_level: ERREXIT + +{eval,shell,subst,trap}.c,builtins/evalstring.c + - ERREXIT is (for now) equivalent to EXITPROG as a value from + jump_to_top_level + + 6/9 + --- +doc/bash.1,lib/readline/doc/readline.3 + - documented new `show-all-if-unmodified' readline variable + + 6/14 + ---- +lib/readline/history.c + - new function, histdata_t free_history_entry (HIST_ENTRY *h), + frees H and its line, returning the application-specific data + - use free_history_entry where appropriate + +lib/readline/history.h + - extern declaration for free_history_entry() + +lib/readline/doc/{history.3,hstech.texi} + - document free_history_entry + + 6/16 + ---- +lib/readline/readline.[ch] + - changed varions defines for readline/history library versions to 5.0 + +subst.c + - pass information about whether or not an indirectly-expanded variable + contains ${array[@]}, ${array[*]}, $@, or $* + - new function, chk_atstar, performs checks for ${array[@]}, + ${array[*]}, $@, or $* for the parameter_brace_expand* functions and + sets flags (passed as args) to the results + - call chk_atstar from parameter_brace_expand_indir and + parameter_brace_expand + + 6/28 + ---- +doc/{bash.1,bashref.texi} + - clarified that (...) commands are executed in a subshell environment + + 6/30 + ---- +lib/readline/bind.c + - fix a problem with parsing nested if statements in inputrc files + (fix from dimakar@yahoo.com) + + 7/3 + --- +{jobs,nojobs}.c + - fix places that use the return value from strsignal() to check + for NULL return values using a new function, j_strsignal() + +builtins/kill.def + - removed JOB_CONTROL restriction; kill is now available as a builtin + when the shell is built without job control + + 7/10 + ---- +jobs.c + - some systems have WIFCONTINUED but not WCONTINUED; separate the + #defines + + 7/14 + ---- +lib/readline/history.h + - new `timestamp' member of a HIST_ENTRY + - extern declarations for add_history_time and history_get_time + +lib/readline/doc/{history.3,hstech.texi} + - document add_history_time and history_get_time + +lib/readline/history.c + - implementations of history_get_time and add_history_time + - change add_history to initialize the timestamp information + - change free_history_entry to free the timestamp + - change replace_history_entry to duplicate the timestamp + - change history_total_bytes to add the memory taken by the time + stamps + +bashhist.c,builtins/history.def + - use free_history_entry where appropriate + +lib/readline/histfile.c + - changes to read_history_range to deal with new history file format + including timestamps + - changes to history_do_write to write out the timestamp information + - changes to history_truncate_file to understand the timestamp + information + + 7/22 + ---- +doc/{bash.1,bashref.texi} + - fixed function declaration documentation to specify that any compound + command may be used as the function body, not just a group command + + 7/23 + ---- +lib/readline/histfile.c + - don't allocate space for null timestamps in history_do_write, and + don't write out null timestamp entries + +parse.y + - fix CHECK_FOR_RESERVED_WORD to call time_command_acceptable() and + return TIME if the token is "time" and `time' is legal in that + context + + 7/29 + ---- +lib/sh/fmtulong.c + - include <inttypes.h> for possible definitions of intmax_t, uintmax_t + (reported by ro@techfak.uni-bielefeld.de) + + 7/30 + ---- +parse.y + - remove checking for `time' reserved word from special_case_tokens(); + use regular mechanism in CHECK_FOR_RESERVED_WORD. This allows `time' + to be aliased. (Reported by Glenn Morris + <gmorris+gmane@ast.cam.ac.uk>) + + 7/31 + ---- +lib/readline/history.h + - extern declaration for history_write_timestamps + +lib/readline/histfile.c + - don't write timestamps to the history file in history_do_write + unless history_write_timestamps is set to non-zero by the application + (set to 0 by default) + +lib/readline/doc/{hstech.texi,history.3} + - document history_write_timestamps + +variables.[ch] + - new special variable function, HISTTIMEFORMAT; special function + sets history_write_timestamps to 1 if HISTTIMEFORMAT is set + + 8/4 + --- +builtins/history.def + - added support for printing time stamps based on the value of the + HISTTIMEFORMAT variable when displaying history entries + +doc/{bash.1,bashref.texi} + - added description of new HISTTIMEFORMAT variable + + 8/5 + --- +config-top.h + - remove /usr/ucb from any default paths + +mailcheck.c + - make_default_mailpath now returns NULL if DEFAULT_MAIL_DIRECTORY + is not defined + - remember_mail_dates now returns if make_default_mailpath returns + NULL + +config-bot.h + - reorganized the sections; provide an explicit placeholder for + builders to #undef any feature defines they don't want that + configure creates for them, like the default mail path + + 8/9 + --- +config.h.in + - add HAVE_REGEX_H, HAVE_REGCOMP, HAVE_REGEXEC for detection of POSIX.2 + regular expression functions + - add COND_REGEXP define to enable and disable the =~ operator for + matching extended regular expressions in [[...]] commands + +configure.in + - new option, --enable-cond-regexp, enables =~ and code to perform + regular expression matching in [[...]] + +config-bot.h + - undef COND_REGEXP if the OS doesn't provide posix regexp support + +doc/bashref.texi + - documnent new --enable-cond-regexp option to configure + + 8/18 + ---- +support/shobj-conf + - support for shared objects on FreeBSD-gnu (from Robert Millan) + + 8/25 + ---- +lib/sh/shmatch.c + - new file, shell interface to posix extended regular expression + matching + +externs.h + - new extern declarations for functions in shmatch.c + +execute_cmd.c + - incorporate code into execute_cond_node that does extended regular + expression matching for the =~ operator + +parse.y + - add `=~' to the list of binary operators accepted by the conditional + command parser + +doc/{bash.1,bashref.texi} + - documented =~ conditional binary operator and the BASH_REMATCH + variable + + 8/27 + ---- +lib/readline/display.c + - take multibyte characters into account when looking for quoted + substrings on which to do completion (fix from jir@yamato.ibm.com) + +lib/readline/util.c + - fix typo in _rl_strpbrk + +lib/readline/rldefs.h + - use function version of _rl_strpbrk in multibyte locales, because + it understands to skip over special characters in multibyte + character sequences + + 8/28 + ---- +jobs.c + - in wait_for, check for window size changes if a job that exits due + to a signal or is stopped was in the foreground, not just if it's + the current job + + 9/10 + ---- +support/config.{guess,sub} + - add support to recognize FreeBSD running on the amd64 + +subst.c + - if the new `fail_glob_expansion' variable is non-zero, globbing that + fails to match anything causes an expansion error + +builtins/shopt.def + - new `failglob' expansion: if enabled, failed globs cause an error + +test/shopt.right + - take `failglob' into account + +doc/{bash.1,bashref.texi} + - documented new `failglob' option and its effects + + 9/12 + ---- +findcmd.c + - fix file_status to treat the mode bits and uid right -- in particular, + don't assume the `other' bits always apply. Bug reported by + <moseley@hank.org>; fix inspired by <carlo@alinoe.com> + +command.h + - new word flag: W_NOCOMSUB, meaning to not perform command + substitution on a word + +subst.c + - new flag for param_expand: PF_NOCOMSUB. If non-zero, $(...) + command substitutions are not expanded, but returned unchanged + - change expand_word_internal to pass through `` command substitutions + unchanged if (word->flags & W_NOCOMSUB) != 0 + - change expand_word_internal to pass PF_NOCOMSUB to param_expand + if (word->flags & W_NOCOMSUB) != 0 + +builtins/shopt.def + - rename set_interactive_comments to set_shellopts_after_change, which + more accurately reflects its purpose + +syntax.h + - add a define for isblank() in case the system doesn't provide one + +jobs.c + - change raw_job_exit_status to understand `pipefail', using the new + `pipefail_opt' variable + +flags.[ch] + - declare pipefail_opt + - reset pipefail_opt to 0 in reset_shell_flags + +builtins/set.def + - add `set -o pipefail' and document it in help output + +doc/{bash.1,bashref.texi} + - document `set -o pipefail' and the effect of the pipefail option + +mksyntax.c,syntax.h + - sh_syntaxtab is no longer `const' + - new generated variable, sh_syntabsiz, set to number of entries in + sh_syntaxtab, written to generated syntax.c + +locale.c + - new function, locale_setblanks(), sets each member of the current + locale's <blank> class to have the CSHBRK flag in sh_syntaxtab + + 9/17 + ---- +arrayfunc.c + - change convert_var_to_array to not set array[0] to a NULL value + (if the scalar variable had no value; e.g., after being created + with `local arrayvar') + +lib/readline/display.c + - save and restore the value of prompt_invis_chars_first_line in + rl_{save,restore}_prompt, and reinitialize it to 0 before printing + something in the message area + +lib/readline/bind.c + - new functions: rl_bind_keyseq_if_unbound_in_map(ks, func, kmap); + binds key sequence KS to function FUNC in keymap KMAP, and + rl_bind_keyseq_if_unbound (ks, func); binds key sequence KS to + function FUNC in the current keymap + +lib/readline/readline.h + - extern function declarations for rl_bind_keyseq_if_unbound_in_map and + rl_bind_keyseq_if_unbound + +lib/readline/{readline,terminal}.c + - _rl_bind_if_unbound -> rl_bind_keyseq_if_unbound + +lib/readline/{bind.c,rlprivate.h} + - remove _rl_bind_if_unbound + + 9/18 + ---- +lib/readline/doc/rltech.texi + - document rl_bind_keyseq_if_unbound and + rl_bind_keyseq_if_unbound_in_map + + 9/19 + ---- +lib/readline/bind.c + - new functions rl_bind_key_if_unbound_in_map and + rl_bind_key_if_unbound; analogous to (and implemented in terms of) + keyseq functions + - rl_bind_keyseq_in_map: a new function, equivalent to rl_set_key + (which remains for backwards compatibility); changed callers to + use it + - new function, rl_bind_keyseq, equivalent to rl_bind_keyseq_in_map + with a third argument of _rl_keymap + +lib/readline/readline.h + - extern declarations for rl_bind_key_if_unbound_in_map and + rl_bind_key_if_unbound + - extern declarations for rl_bind_keyseq_in_map and rl_bind_keyseq + +lib/readline/doc/rltech.texi + - document rl_bind_keyseq and rl_bind_keyseq_in_map + +configure.in + - require at least readline-5.0 + +config-bot.h + - define SYS_SIGLIST_DECLARED if it's not defined, but + HAVE_DECL_SYS_SIGLIST is, to deal with differences between + autoconf versions + +bashline.c + - use rl_bind_key_if_unbound_in_map when binding bash keybindings in + initialize_readline(), so inputrc files can override them + + 9/22 + ---- +lib/readline/histsearch.c + - do better bounds checking for history_offset and history_length in + history_search_internal + +builtins/history.def + - in delete_last_history(), make sure we don't leave the history + offset longer than the history length after calling delete_histent + + 9/23 + ---- +jobs.c + - small change to notify_of_job_status so job status messages get + printed even if the shell was started to run `-c command'. The + old behavior was intentional, but I cannot remember why, so we'll + try it the other way for a while (debian bash bug #211693) + + 9/24 + ---- +jobs.c + - slightly modify change from 9/23 so that jobs started to run + command substitutions don't print job status messages + + 9/25 + ---- +lib/readline/search.c + - when reading a non-incremental search string from the terminal, + use a separate undo list rather than chaining it to the undo list + from the rest of the line, since the whole undo list will get + freed when the search string is complete + +lib/readline/readline.h + - changed the defines guarding the stdarg prototype for rl_message to + match what's actually used in display.c, where it's defined + + 9/26 + ---- +[bash-3.0-alpha released] + + 9/29 + ---- +lib/sh/shmatch.c + - fix to build correctly when arrays are not compiled into the shell + +subst.c + - fix command substitution to run any exit trap defined in the + command substitution before returning; the exit trap is not inherited + from the calling shell + +lib/readline/shell.c + - change sh_set_lines_and_columns to free the memory allocated and + passed to setenv(), since setenv is specified by POSIX to allocate + new memory and copy its arguments + +jobs.c + - change logic in make_child so that every child process attempts to + set the terminal's process group to the pipeline's process group + when PGRP_PIPE is defined, just like when it's undefined. This is + reported to fix some tricky synchronization problems on Red Hat + Enterprise Linux 3. Fix from Ernie Petrides <petrides@redhat.com>. + + 9/30 + ---- +builtins/printf.def + - tescape no longer needs a `trans_squote' argument, since it's the + same as the `sawc' argument. The `sawc' argument now means to do + the %b argument processing if non-null + - fix processing of octal constants for %b arguments (\0 followed by + up to three octal digits) and other escape sequences (\ followed by + up to three octal digits) + - hex constants `\xHHH' are now allowed to contain any positive + number of digits; previously they were restricted to two [removed] + - allow two new escape sequences: \" and \?, for compatibility with + ksh93 and ANSI C + +doc/{bash.1,bashref.texi} + - documented processing that printf performs for arguments to %b + escape sequences + +lib/sh/strtrans.c + - add \" and \? to escape sequences recognized by `echo -e' + + 10/1 + ---- +version.c + - use snprintf instead of sprintf if configure tells us we have it + + 10/3 + ---- +subst.c + - in list_remove_pattern, take into account the fact that one of the + list elements may be NULL, and don't free the result of + remove_pattern() without checking + - in remove_pattern, return savestring(param) if *param == '\0', + since callers expect to free() non-null return values + + 10/4 + ---- +subst.c + - change verify_substring_values to make it clearer that the first + offset deals with array indices and the second deals with numbers + of elements, when doing array subranges with ${a[@]:e1:e2} + +array.c + - change array_subrange to make it explicit that the second offset + argument is a count of the desired number of elements, not an + ending index. This deals with sparse arrays correctly. + + 10/6 + ---- +variables.c + - fix memory leak in assign_in_env + + 10/8 + ---- +subst.c + - in parameter_brace_expand, check that the last characters are `]}' + before checking for ${!array[@]} + +execute_cmd.c,builtins/source.def + - push and pop the args (BASH_ARGV and BASH_ARGC) when executing a + shell function or sourcing a script only when in debugging mode + + 10/11 + ----- +arrayfunc.c + - make sure array_variable_name returns values for the SUBP and LENP + arguments if they're non-null, since callers expect to use them + even if the array subscript is bad + +error.c + - call exit_shell instead of sh_exit from parser_error and + report_error so the right things happen (running exit trap, doing + the right interactive cleanup, etc.) + +lib/readline/complete.c + - new variable, rl_completion_quote_character, set to any quote char + readline thinks it finds before any application completion + function is called + - new variable, rl_completion_suppress_quote, settable by an + application-specific completion function. If set to non-zero, the + completion code does not append a closing quote in append_to_match + +lib/readline/readline.h + - extern declarations for rl_completion_quote_character and + rl_completion_suppress_quote + +bashline.c + - set rl_completion_suppress_quote in command_subst_completion_function + because that would be inserted before any closing "`" or ")", which + is somewhat disconcerting + +lib/readline/doc/rltech.texi + - documented rl_completion_suppress_quote and + rl_completion_quote_character + + 10/13 + ----- +bashhist.c + - use sv_histchars instead of setting history_comment_char directly in + bash_initialize_history so assignments to $histchars made in + ~/.bashrc are honored + + 10/21 + ----- +trap.c + - make sure run_exit_trap sets `running_trap' appropriately + - new variable, trap_saved_exit_value, set to last_command_exit_value + before running any trap commands; available to the rest of the + shell; use trap_saved_exit_value to replace some function-local + variables + +builtins/exit.def + - if the shell is running the exit trap, and no argument is given + to `exit', use trap_saved_exit_value as the exit status instead + of the last command exit value (which could be the previous command + run in the exit trap), as required by POSIX.2 + + 10/25 + ----- +doc/{bash.1,bashref.texi} + - add `alias' to the list of documented `assignment statement' builtins + + 11/1 + ---- +doc/bash.1 + - remove the `.' from the sample $PATH value + +parse.y + - make sure parse_compound_assignment prompts with $PS2 if it reads + a newline while parsing the compound assignment statement. Bug + reported by Stephane Chazelas + - parse_string_to_word_list now takes a new second argument: `int flags' + - new parser state flag: PST_COMPASSIGN; indicates that the shell is + parsing a compound assignment statement + - parse_string_to_word_list turns on PST_COMPASSIGN if `flags' arg + has low bit set + - turn PST_COMPASSIGN on and off in parse_compound_assignment + +externs.h + - change prototype declaration for parse_string_to_word_list + +arrayfunc.c + - change call to parse_string_to_word_list to add new flags arg + +general.c + - assignment() takes a new `flags' second argument + - if `flags' is non-zero, accept `[' as a legal assignment statement + starter character (for parsing compound array assignments) + +general.h + - add new argument to prototype declaration for assignment() + +parse.y,{subst,variables}.c, builtins/{setattr,declare}.def + - change calls to assignment() (parse.y calls with flags == 1 when + parser_state inlcudes PST_COMPASSIGN) + +arrayfunc.c + - in assign_array_var_from_string(), don't treat an expanded word + of the form [ind]=value specially unless the W_ASSIGNMENT flag is + set. This means that words that are the result of expansions but + happen to have the same format as compound assignment statement + words will not be treated as such. For instance + + v='[12]=foobar' + a=( $v ) + + will result in a[0]='[12]=foobar' instead of a[12]=foobar. This + is closer to how `regular' assignment statements are treated and + compatible with ksh93. Bug reported by Stephane Chazelas + +shell.c + - new --protected argument, disables command substitution when used + with --wordexp (like --wordexp, it remains undocumented) + - change run_wordexp to turn on the W_NOCOMSUB flag in each word + to be expanded if protected_mode is set + + 11/7 + ---- +doc/{bash.1,bashref.texi} + - clarified the language concerning inherited signal dispositions and + when traps are run + +support/shobj-conf + - slight changes to the darwin (Mac OS X) stanza for MacOS X 10.3 + (for the readline shared library builds, which shares this script) + +lib/readline/histexpand.c + - change to make `^' behave as equivalent to word one, as csh does, + and as the documentation states + +lib/readline/display.c + - in update_line, make sure to use col_lendiff in all calculations + where the cursor position is concerned (like when calculating + the value of _rl_last_c_pos). Fixes bug reported by Andreas + Schwab + + 11/12 + ----- +trap.c + - make _run_trap_internal catch `return' builtin longjmps and clean + up before longjmping on to where the return was intended to go + (fixes bug with not turning off SIG_INPROGRESS flag when `return' + executed in trap command) + + 11/18 + ----- +builtins/cd.def + - in posix mode, set errno to ENOTDIR if canonicalization fails, + unless the canonicalization functions leave it set to ENOENT + + 11/25 + ----- +make_cmd.c + - in make_simple_command, don't blindly dereference element.redirect + +parse.y + - the list_terminator production now has an `int' value so it can be + used in other grammar productions + - add a rule that makes `time' on a line by itself time a null + command (this is iffy) + + 11/28 + ----- +subst.c + - change the pattern substitution code (${var//pat/rep}) to use the + same pattern expansion function (getpattern()) as the pattern + removal expansions. This has the effect of no longer performing + quote removal on the pattern before trying to match it. This + fixes an incompatibility with ksh93 reported on comp.unix.shell + +nojobs.c + - add replacement function for siginterrupt on the off chance that a + system has posix signals but lacks siginterrrupt + +lib/readline/display.c + - fix from Tim Waugh at Red Hat to speed up inserting characters into + long lines in a UTF-8 environment by optimizing the calculation of + the first difference between old and new lines by checking to see + whether the old line is a subset of the new + + 11/29 + ----- +lib/malloc/stats.c + - break code that opens file (and interprets %p) into separate function + _imalloc_fopen(char *s, char *fn, char *def, char *defbuf, size_t defsiz) + for use by rest of library + - default stats file is now `stats.PID' + +lib/malloc/trace.c + - new function, malloc_set_tracefn (char *s, char *fn), sets tracing + to the file named by FN (with %p interpolated as the pid), using + some default if FN is NULL + +lib/malloc/shmalloc.h + - new extern declaration for malloc_set_tracefn + + 12/4 + ---- +execute_cmd.c + - combined several common strings from do_piping() into one + dup_error() function + +builtins/common.[ch] + - new function, `sh_notbuiltin(s)' prints error message about s not + being a shell builtin + +builtins/{builtin,enable}.def + - call sh_notbuiltin instead of using literal string + +{arrayfunc,expr,error}.c + - use one string variable for `bad array subscript' error message; use + in calls to various error reporting functions + +Makefile.in + - add variables for localedir and the PACKAGE_* variables, auto-set + by configure + +configure.in + - un-cache values for gettext, textdomain, and bindtextdomain if they're + not in libc but in libintl so the right variables get set + +bashintl.h + - add necessary defines for marking strings to be translated using + gettext + +locale.c + - set textdomain and directory in set_default_locale + - don't call textdomain with the value of $TEXTDOMAIN, since we don't + want to override the default domain ("bash") + - don't call bindtextdomain unless default_domain already has a value + - when translating $"..." strings, use dgettext with the script's + default domain (value of $TEXTDOMAIN) + + 12/9 + ---- +builtins/mkbuiltins.c + - include "bashintl.h" in the generated "builtins.c" + +support/{config.rpath,mkinstalldirs} + - new files to support gettext i18n + +ABOUT-NLS + - new readme file for gettext internationalization + +po/{Makefile.in.in,Rules-quot,boldquot.sed,en@boldquot.header,en@quot.header,insert-header.sin,quot.sed,remove-potcdate.sin} +po/{POTFILES.in,bash.pot} + - new files for gettext + +lib/intl + - new directory, with libintl stuff from gettext + +aclocal.m4 + - add m4 files from gettext distribution needed by libintl + +configure.in + - create po/Makefile.in and lib/intl/Makefile in AC_OUTPUT + - add call to AM_GNU_GETTEXT to initialize gettext stuff + +Makefile.in + - use mkinstalldirs instead of mkdirs in the `installdirs' target + - changes for intl/ and po/ subdirectories in build and install + - changes to have libintl linked in, as determined by configure + - changes to have libintl built, just in case it's used (though I'd + rather not) + + 12/10 + ----- +config.h.in + - additional #defines required by the libintl library + - add ENABLE_NLS define for AM_GNU_GETTEXT + - take out defines for HAVE_{BINDTEXTDOMAIN,GETTEXT,TEXTDOMAIN} + +configure.in + - removed old tests for libintl and gettext/textdomain/bindtextdomain + +locale.c + - remove HAVE_GETTEXT code; we have gettext unconditionally now + +bashintl.h + - change to include "gettext.h" and remove the conditional code based + on whether or not gettext is present + + 12/16 + ----- +lib/readline/vi_mode.c + - fix problem with rl_vi_eWord that caused it to skip over the last + character of a word if invoked while point was on the next-to-last + character + + 12/18 + ----- +{arrayfunc,bashhist,bashline,error,eval,execute_cmd,expr,general,input,jobs}.c +{mailcheck,make_cmd,nojobs,pcomplete,pcomplib,print_cmd,redir,shell,sig}.c +{subst,test,trap,variables,version,xmalloc}.c +parse.y +builtins/{common,evalfile,getopt}.c +builtins/{bind,break,caller,cd,complete,declare,enable,exec,exit,fc,fg_bg}.def +builtins/{hash,help,history,jobs,kill,printf,pushd,read,return,set,setattr}.def +builtins/{shift,shopt,source,suspend,type,ulimit,umask}.def +lib/sh/{fmtulong,netopen}.c + - include "bashintl.h" for gettext defines + +Makefile.in + - add `-DBUILDTOOL' to CFLAGS for buildversion.o + +bashintl.h + - if `BUILDTOOL' is defined, define ENABLE_NLS to 0 so we don't have + to compile and link in the gettext stuff + +Makefile.in,lib/sh/Makefile.in,builtins/Makefile.in + - update dependencies on bashintl.h and include/gettext.h + + 12/19 + ----- +{arrayfunc,bashhist,bashline,error,eval,execute_cmd,expr,general,input,jobs}.c +{mailcheck,make_cmd,nojobs,pcomplete,pcomplib,print_cmd,redir,shell,sig}.c +{subst,test,trap,variables,version,xmalloc}.c +builtins/{common,evalfile,getopt}.c +builtins/{bind,break,caller,cd,complete,declare,enable,exec,exit,fc,fg_bg}.def +builtins/{hash,help,history,jobs,kill,let,printf,pushd,read,return,set}.def +builtins/{setattr,shift,shopt,source,suspend,type,ulimit,umask}.def +lib/sh/{fmtulong,netopen}.c +lib/malloc/{malloc,stats,table,watch}.c + - mark up strings in source files for gettext processing + +lib/malloc/imalloc.h + - include "bashintl.h" if SHELL is defined, otherwise make _(x) an + identity define + +lib/malloc/Makefile.in + - add dependencies on ${topdir}/bashintl.h and ${BASHINCDIR}/gettext.h + + 12/21 + ----- +bashline.c + - make sure we index into rl_line_buffer with indexes > 0 in + attempt_shell_completion + + 12/31 + ----- +Makefile.in + - descend into `po' and run make recursively for the various clean + targets + + 1/4 + --- +include/shmbutil.h + - two new macros: BACKUP_CHAR(str, strsize, i), which backs up one + multibyte character in STR starting at index I, and + BACKUP_CHAR_P(str, strsize, p), which backs up one multibyte + character in STR starting at P, which is a char * + + 1/6 + --- +pcomplete.c + - in pcomp_filename_completion_function, use the quote character + readline found (and assigned to rl_complete_quote_character) when + dequoting the filename by a completion call from readline (when + rl_dispatching != 0) + +bashline.c + - ditto for bash_directory_completion_matches + + 1/7 + --- +lib/readline/complete.c + - new variable, rl_completion_found_quote, set to non-zero value if + readline finds what it thinks is quoting in the word to be completed + +lib/readline/readline.h + - extern declaration for rl_completion_found_quote + + 1/8 + --- +lib/readline/doc/rltech.texi + - documented rl_completion_found_quote + +lib/readline/complete.c + - in compute_lcd_of_matches, if it looks like what the user typed was + dequoted before generating filename matches, dequote the user's + text again before figuring out the case-insensitive lcd + + 1/9 + --- +lib/readline/display.c + - fix from Edward Catmur <ed@catmur.co.uk> to logic that handles + invisible characters in prompt string. Original code was wrong + about local_prompt_prefix; it gave incorrect results when prompt + contained invisible characters after a line break + + 1/10 + ---- +subst.c + - new function, mb_substring(), does character (possibly multibyte) + oriented rather than strictly byte-oriented substring extraction. + The passed indices, rather than strictly indexing into the string, + indicate character positions that need to be calculated. From + Tim Waugh <twaugh@redhat.com> + - change parameter_brace_substring to use mb_substring if necessary + +included/shmbutil.h + - new define SADD_MBQCHAR_BODY, common code for adding a quoted + (preceded by CTLESC) multibyte character to an accumulating string + in the subst.c expansion code + +subst.c + - use SADD_MBQCHAR_BODY in expand_word_internal + - new static function, mb_getcharlens, allocates and returns an array + of character lengths for (possibly multibyte) characters in the + argument string + - change pattern matching operations to use while loops instead of + for loops to handle multibyte characters better (no more simple + increment or decrement) + - change pattern matching operations to use multibyte character + operations instead of simple increments and decrements. Don't + use BACKUP_CHAR_P -- use the mblen array instead, because that + avoids the N**2 behavior of having to count from the beginning + of the string each time you want to back up one character. Changes + to remove_pattern and match_pattern + + 1/12 + ---- +lib/readline/display.c + - make expand_prompt count multbyte characters in the prompt string + by using _rl_find_next_mbchar (and copying possibly more than one + byte) instead of a simple increment and single byte copy + + 1/13 + ---- +lib/readline/display.c + - expand_prompt takes a new reference argument -- it returns + the actual count of (possibly multibyte) characters displayed + on the screen + - don't short-circuit in expand_prompt unless we're not going to + be using any multibyte characters + - change calls to expand_prompt to pass an argument for the + number of physical characters the prompt occupies + (prompt_physical_chars) + - initialize `lpos' (the physical cursor position) from + prompt_physical_chars in rl_redisplay + +lib/readline/mbutil.c + - in _rl_find_prev_mbchar_internal, if mbrtowc returns -1 or -2, and + we assume that the character is a single-byte char, make sure we + update `prev' so it doesn't get lost. Fixes problems encountered + when a non-ascii char is the last char on the line and we're moving + back past it with ^B, and other display problems caused by the same + situation + + 1/15 + ---- +lib/readline/doc/rltech.texi + - document RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE in the + description of rl_expand_prompt() + + 1/20 + ---- +bashline.c + - in initialize_readline, make sure M-C-j and M-C-m are still bound to + vi-editing-mode before unbinding them -- they may have been rebound + in an inputrc + +variables.c + - in unbind_variable, unset attributes other than `local' and exported + (if the variable came from a temporary environment) when unsetting a + local variable inside a function + + 1/21 + ---- +configure.in + - add libintl build directory to the list of include directories if + it's being built (using INTL_BUILDDIR) + +Makefile.in,{builtins,lib/{sh,malloc}}/Makefile.in + - substitute LIBBUILD as ${BUILD_DIR}/${LIBSUBDIR} + - define INTL_BUILDDIR as ${LIBBUILD}/intl + +{builtins,lib/sh}/Makefile.in + - make sure INTL_INC is added to the list of include directories + - make sure INTL_LIBSRC is defined with the correct value + +{configure,Makefile,{builtins,lib/sh}/Makefile}.in + - substitute LIBINTL_H as ${INTL_BUILDDIR}/libintl.h + +Makefile.in,builtins/Makefile.iin + - all files depending on bashintl.h also depend on ${LIBINTL_H} + (which may be empty) + +Makefile.in + - make a rule telling how to build lib/intl/libintl.h if necessary + + 1/24 + ---- +builtins/read.def + - make sure that the array name supplied as an argument to -a is a + valid identifier + +parse.y + - make the \W expansion abbreviate $HOME with a ~ (seems to be more + useful) + +doc/{bash.1,bashref.texi} + - document new behavior of \W + +subst.c + - make sure parameter_brace_expand_rhs uses the first character of + $IFS when making the string to return from the expanded word + (which, in the case of "$@" or $@, contains multiple words that + need to be separated) + + 1/25 + ---- +builtins/common.c + - change get_job_spec to make `%' by itself or an empty argument + return NO_JOB + +jobs.h + - new possible value for a job spec return value: BAD_JOBSPEC + (for syntactically invalid specs, like the empty string) + +shell.c + - in open_shell_script, check to see whether or not we can find and + open the filename argument before setting dollar_vars[0] or + manipulating BASH_SOURCE, so the error messages come out better + +subst.c + - in string_list_internal, short-circuit right away to savestring() + if the list only has a single element + + 1/28 + ---- +lib/readline/rltypedefs.h + - new set of typedefs for functions returning char * with various + arguments (standard set) + +lib/readline/complete.c + - new function pointer, rl_completion_word_break_hook, called by + _rl_find_completion_word, used to set word break characters at + completion time, allowing them to be position-based + +lib/readline/doc/rltech.texi + - documented rl_completion_word_break_hook + +lib/readline/kill.c + - added new rl_unix_filename_rubout, which deletes one filename + component in a Unix pathname backward (delimiters are whitespace + and `/') + +lib/readline/readline.h + - extern declaration for rl_unix_filename_rubout + +lib/readline/funmap.c + - new bindable readline command `unix-filename-rubout' + +lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 + - documented `unix-filename-rubout' + + 1/29 + ---- +lib/readline/histexpand.c + - change history_tokenize_internal to handle non-whitespace delimiter + characters by creating separate fields (like the shell does when + splitting on $IFS) + + 1/30 + ---- +lib/glob/xmbsrtowcs.c + - new function, xdupmbstowcs, for convenience: calls xmbsrtowcs + while allocating memory for the new wide character string + - some small efficiency improvments to xmbsrtowcs + +include/shmbutil.h + - extern declaration for xdupmbstowcs + +lib/glob/strmatch.h + - include config.h for definition of HANDLE_MULTIBYTE + - remove the HAVE_LIBC_FNM_EXTMATCH tests + - new extern declaration for wcsmatch(whchar_t *, wchar_t *, int) + +configure.in + - remove call to BASH_FUNC_FNMATCH_EXTMATCH; it's no longer used + +lib/glob/smatch.c + - simplify xstrmatch() by using xdupmbstowcs() instead of inline code + +lib/glob/glob.c + - modify mbskipname() to avoid the use of alloca + - simplify mbskipname() by using xdupmbstowcs() instead of inline code + - simplify glob_pattern_p() by using xdupmbstowcs() instead of + inline code + - fix memory leak in wdequote_pathname + - simplify wdequote_pathname() by using xdupmbstowcs() instead of + inline code + +lib/glob/strmatch.c + - new function, wcsmatch(), `exported' wide-character equivalent of + strmatch() + +subst.c + - old match_pattern is now match_upattern + - match_pattern now either calls match_upattern or converts + mbstrings to wide chars and calls match_wpattern + - match_upattern reverted to old non-multibyte code + - new function: match_pattern_wchar, wide character version of + match_pattern_char + + 2/1 + --- +subst.c + - old remove_pattern is now remove_upattern + - remove_upattern reverted to old non-multibyte code (pre-Waugh patch) + - new multibyte version of remove_pattern: remove_wpattern + - remove_pattern now calls either remove_upattern or converts a + multibyte string to a wide character string and calls + remove_wpattern + - new function, wcsdup, wide-character version of strdup(3) + + 2/4 + --- +print_cmd.c + - temporarily translate a >&filename redirection from + r_duplicating_output_word to r_err_and_out (as the expansion code + in redir.c does) so it prints without a leading `1' (file + descriptor) + + 2/5 + --- +aclocal.m4 + - add a check for wcsdup to BASH_CHECK_MULTIBYTE + +config.h.in + - add HAVE_WCSDUP define + + 2/9 + --- +builtins/shift.def + - fix a call to sh_erange that possibly dereferences a NULL pointer + + 2/12 + ---- +general.c + - start at a general set of file property checking functions: + file_isdir(), file_iswdir() (is writable directory) + +general.h + - extern declarations for new functions + +lib/sh/tmpfile.c + - use file_iswdir() to make sure the temporary directory used for + here documents and other temp files is writable in get_sys_tmpdir() + + 2/17 + ---- +bashline.c + - fix conditional binding of emacs-mode M-~ -- there is a default + binding for it (rl_tilde_expand), so a straight call to + rl_bind_key_if_unbound_in_map doesn't do the right thing + + 2/27 + ---- +[bash-3.0-beta1 released] + + 2/29 + ---- +subst.c + - fixed expansion so referencing $a, when a is an array variable + without an element assigned to index 0, exits the shell when + `-u' is enabled + +expr.c + - make the exponentiation operator (**) associative, so things like + 2**3**4 work right (change `if' to `while') + + 3/3 + --- +lib/sh/strftime.c + - SCO Unix 3.2, like Solaris, requires that the system's `timezone' + variable be declared as long + +lib/readline/{bind,histfile,input,parens}.c + - changes for Tandem (including `floss.h' (?)) + + 3/4 + --- +subst.c + - change param_expand to quote the entire expanded string instead + of just the escape characters if the expansion appears between + double quotes or in a here-document (for simple variable expansions + or expansions of positional parameters) + + 3/8 + --- +subst.c + - analogous changes to parameter_brace_expand_word to fix the same + quoting problem as on 3/4; fix callers to understand that the + value returned might be quoted now and should be dequoted if + necessary + - add a `quoted' argument to get_var_and_type, change callers + - change today's fix and fix from 3/4 to not call quote_string if the + value is "" (because quote_string turns that into CTLNUL\0) + + 3/9 + --- +builtins/cd.def + - resetpwd() now takes a `caller' argument so it can be used by pwd + as well as cd + - change pwd_builtin to call resetpwd() if sh_physpath() fails to + return a valid pathname + + 3/14 + ---- +expr.c + - reworked exp0 and readtok() to make post-increment and post-decrement + into real tokens, which may be separated from their accompanying + variables by whitesapce + - made analogous changes to readtok() to make pre-increment and + pre-decrement work when separated from their accompanying identifier + by whitespace + + 3/19 + ---- +lib/readline/display.c + - rl_save_prompt and rl_restore_prompt now save and restore the value + of prompt_physical_chars + - set prompt_physical_chars in rl_redisplay when expand_prompt has + not been called (e.g., when rl_display_prompt is set and is not + equal to rl_prompt, like when searching) + +config-bot.h + - check whether HAVE_DECL_SYS_SIGLIST is defined to 1 rather than just + defined, to work around newer versions of autoconf defining it to 0 + +config.h.in + - change default status of HAVE_MALLOC to #undef instead of #define + +bashline.c + - in cleanup_expansion_error, make sure to_free is non-null before + freeing it diff --git a/CWRU/changelog~ b/CWRU/changelog~ new file mode 120000 index 00000000..d2d81b30 --- /dev/null +++ b/CWRU/changelog~ @@ -0,0 +1 @@ +CWRU.chlog
\ No newline at end of file @@ -682,6 +682,8 @@ 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/array.tests f tests/array.right f tests/array-at-star f @@ -708,6 +710,7 @@ tests/dbg-support2.right f tests/dbg-support2.tests f tests/dollar-at-star f tests/dollar-at1.sub f +tests/dollar-at2.sub f tests/dollar-star1.sub f tests/dollar.right f tests/dstack.tests f @@ -803,6 +806,7 @@ tests/read1.sub f tests/read2.sub f tests/read3.sub f tests/read4.sub f +tests/read5.sub f tests/redir.tests f tests/redir.right f tests/redir1.sub f diff --git a/autom4te.cache/requests b/autom4te.cache/requests index 506bce33..7c2bc7d2 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -15,96 +15,96 @@ 'configure.in' ], { - 'AC_FUNC_CLOSEDIR_VOID' => 1, - 'AC_FUNC_CHOWN' => 1, + 'AC_TYPE_MODE_T' => 1, + 'AC_FUNC_MMAP' => 1, 'AM_CONDITIONAL' => 1, - 'AC_FUNC_ALLOCA' => 1, - 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1, - 'AC_HEADER_SYS_WAIT' => 1, - 'AC_PROG_LN_S' => 1, - 'AC_CHECK_FUNCS' => 1, - 'AC_HEADER_DIRENT' => 1, - 'AC_HEADER_TIME' => 1, - 'AC_CONFIG_AUX_DIR' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AC_PROG_GCC_TRADITIONAL' => 1, - 'AM_AUTOMAKE_VERSION' => 1, 'AC_TYPE_OFF_T' => 1, - 'AC_FUNC_GETGROUPS' => 1, - 'AC_SUBST' => 1, - 'AC_LIBSOURCE' => 1, + 'AC_CONFIG_HEADERS' => 1, + 'AC_C_INLINE' => 1, + 'include' => 1, + 'AC_HEADER_DIRENT' => 1, + 'AC_FUNC_STRFTIME' => 1, + 'AC_TYPE_SIGNAL' => 1, + 'AC_FUNC_LSTAT' => 1, + 'AC_TYPE_PID_T' => 1, 'AC_CANONICAL_HOST' => 1, + 'AC_STRUCT_TM' => 1, 'AC_PROG_CXX' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_FUNC_OBSTACK' => 1, - 'AC_FUNC_STAT' => 1, - 'AM_GNU_GETTEXT' => 1, - 'AC_PROG_AWK' => 1, - 'AC_FUNC_MALLOC' => 1, + 'AC_DEFINE_TRACE_LITERAL' => 1, 'AC_FUNC_STRTOD' => 1, - 'AC_FUNC_MKTIME' => 1, - 'AC_CONFIG_FILES' => 1, + 'AC_CANONICAL_SYSTEM' => 1, + 'AC_HEADER_TIME' => 1, 'AC_STRUCT_TIMEZONE' => 1, - 'AC_FUNC_FORK' => 1, - 'AC_FUNC_STRFTIME' => 1, - 'AC_C_VOLATILE' => 1, - 'AC_FUNC_GETLOADAVG' => 1, - 'AC_TYPE_MODE_T' => 1, - 'm4_pattern_allow' => 1, - 'AC_FUNC_MMAP' => 1, - 'AC_PROG_RANLIB' => 1, - 'AC_HEADER_MAJOR' => 1, + 'AC_PROG_GCC_TRADITIONAL' => 1, 'AC_FUNC_ERROR_AT_LINE' => 1, - 'AC_FUNC_FSEEKO' => 1, - 'm4_pattern_forbid' => 1, - 'AC_PATH_X' => 1, - 'AC_TYPE_UID_T' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'AC_PROG_INSTALL' => 1, - 'AC_INIT' => 1, + 'AC_FUNC_STAT' => 1, + 'm4_pattern_allow' => 1, + 'AC_CONFIG_AUX_DIR' => 1, 'AC_CHECK_LIB' => 1, - 'AC_STRUCT_TM' => 1, - 'AC_FUNC_SETPGRP' => 1, 'AC_HEADER_STAT' => 1, - 'AC_FUNC_STRCOLL' => 1, - 'm4_include' => 1, - 'AC_STRUCT_ST_BLOCKS' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'AC_FUNC_REALLOC' => 1, - 'include' => 1, - 'AC_FUNC_MEMCMP' => 1, - 'AC_FUNC_VPRINTF' => 1, - 'AC_PROG_CPP' => 1, - 'AC_TYPE_PID_T' => 1, - 'AC_C_INLINE' => 1, + 'AC_FUNC_MALLOC' => 1, 'AC_FUNC_WAIT3' => 1, - 'AC_FUNC_GETPGRP' => 1, - 'AC_HEADER_STDC' => 1, - 'AC_FUNC_STRNLEN' => 1, - 'AC_FUNC_MBRTOWC' => 1, - 'AC_C_CONST' => 1, - 'AC_FUNC_SELECT_ARGTYPES' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AC_CHECK_MEMBERS' => 1, - 'AC_FUNC_STRERROR_R' => 1, - 'AC_CHECK_HEADERS' => 1, + 'AC_FUNC_CHOWN' => 1, + 'AC_CONFIG_FILES' => 1, + 'AC_CHECK_FUNCS' => 1, + 'AC_LIBSOURCE' => 1, 'AC_CHECK_TYPES' => 1, - 'AC_FUNC_GETMNTENT' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AC_CONFIG_SUBDIRS' => 1, + 'AC_PROG_INSTALL' => 1, 'AC_REPLACE_FNMATCH' => 1, - 'AC_FUNC_SETVBUF_REVERSED' => 1, - 'AC_CONFIG_HEADERS' => 1, + 'AC_FUNC_STRNLEN' => 1, + 'AC_FUNC_MKTIME' => 1, + 'AC_FUNC_VPRINTF' => 1, + 'AC_FUNC_STRCOLL' => 1, + 'AC_PROG_MAKE_SET' => 1, 'AC_PROG_YACC' => 1, - 'AC_TYPE_SIGNAL' => 1, 'AC_DECL_SYS_SIGLIST' => 1, - 'AC_CANONICAL_SYSTEM' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'AC_INIT' => 1, + 'AC_FUNC_REALLOC' => 1, + 'AC_FUNC_FORK' => 1, + 'AC_FUNC_SETPGRP' => 1, + 'AC_FUNC_STRERROR_R' => 1, + 'AC_HEADER_SYS_WAIT' => 1, 'AC_PROG_CC' => 1, - 'AC_TYPE_SIZE_T' => 1, - 'AC_FUNC_UTIME_NULL' => 1, + 'AC_CHECK_MEMBERS' => 1, 'AH_OUTPUT' => 1, + 'AC_HEADER_STDC' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_SUBST' => 1, + 'AC_FUNC_MBRTOWC' => 1, + 'AC_PROG_CPP' => 1, + 'AC_FUNC_FSEEKO' => 1, + 'AC_FUNC_UTIME_NULL' => 1, + 'AC_FUNC_CLOSEDIR_VOID' => 1, + 'AC_C_CONST' => 1, + 'AC_PATH_X' => 1, 'AC_PROG_LEX' => 1, - 'AC_FUNC_LSTAT' => 1, - 'AC_PROG_MAKE_SET' => 1 + 'AC_FUNC_ALLOCA' => 1, + 'AM_GNU_GETTEXT' => 1, + 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1, + 'm4_include' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'AC_HEADER_MAJOR' => 1, + 'AC_TYPE_UID_T' => 1, + 'AC_PROG_RANLIB' => 1, + 'AC_C_VOLATILE' => 1, + 'm4_pattern_forbid' => 1, + 'AM_PROG_CC_C_O' => 1, + 'AC_TYPE_SIZE_T' => 1, + 'AC_STRUCT_ST_BLOCKS' => 1, + 'AC_FUNC_GETMNTENT' => 1, + 'AC_FUNC_GETPGRP' => 1, + 'AC_PROG_AWK' => 1, + 'AC_FUNC_GETLOADAVG' => 1, + 'AC_PROG_LN_S' => 1, + 'AC_FUNC_SETVBUF_REVERSED' => 1, + 'AC_FUNC_MEMCMP' => 1, + 'AC_FUNC_SELECT_ARGTYPES' => 1, + 'AC_FUNC_GETGROUPS' => 1, + 'AC_CHECK_HEADERS' => 1, + 'AC_FUNC_OBSTACK' => 1 } ], 'Request' ) ); @@ -1,6 +1,6 @@ /* bashhist.c -- bash interface to the GNU history library. */ -/* Copyright (C) 1993 Free Software Foundation, Inc. +/* Copyright (C) 1993-2004 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -52,6 +52,7 @@ #if defined (READLINE) # include "bashline.h" +extern int rl_done, rl_dispatching; /* should really include readline.h */ #endif #if !defined (errno) @@ -444,12 +445,19 @@ pre_process_line (line, print_changes, addit) /* If there was an error, return NULL. */ if (expanded < 0 || expanded == 2) /* 2 == print only */ { +# if defined (READLINE) + if (expanded == 2 && rl_dispatching == 0 && *history_value) +# else + if (expanded == 2 && *history_value) +# endif /* !READLINE */ + maybe_add_history (history_value); + free (history_value); # if defined (READLINE) /* New hack. We can allow the user to edit the failed history expansion. */ - if (history_reediting && expanded < 0) + if (history_reediting && expanded < 0 && rl_done) re_edit (line); # endif /* READLINE */ return ((char *)NULL); diff --git a/bashhist.c~ b/bashhist.c~ new file mode 100644 index 00000000..fed0e062 --- /dev/null +++ b/bashhist.c~ @@ -0,0 +1,813 @@ +/* bashhist.c -- bash interface to the GNU history library. */ + +/* 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include "config.h" + +#if defined (HISTORY) + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "bashtypes.h" +#include <stdio.h> +#include <errno.h> +#include "bashansi.h" +#include "posixstat.h" +#include "filecntl.h" + +#include "bashintl.h" + +#include "shell.h" +#include "flags.h" +#include "input.h" +#include "parser.h" /* for the struct dstack stuff. */ +#include "pathexp.h" /* for the struct ignorevar stuff */ +#include "bashhist.h" /* matching prototypes and declarations */ +#include "builtins/common.h" + +#include <readline/history.h> +#include <glob/glob.h> +#include <glob/strmatch.h> + +#if defined (READLINE) +# include "bashline.h" +extern int rl_done, rl_dispatching; /* should really include readline.h */ +#endif + +#if !defined (errno) +extern int errno; +#endif + +static int histignore_item_func __P((struct ign *)); +static int check_history_control __P((char *)); +static void hc_erasedups __P((char *)); +static void really_add_history __P((char *)); + +static struct ignorevar histignore = +{ + "HISTIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *)histignore_item_func, +}; + +#define HIGN_EXPAND 0x01 + +/* Declarations of bash history variables. */ +/* Non-zero means to remember lines typed to the shell on the history + list. This is different than the user-controlled behaviour; this + becomes zero when we read lines from a file, for example. */ +int remember_on_history = 1; + +/* The number of lines that Bash has added to this history session. The + difference between the number of the top element in the history list + (offset from history_base) and the number of lines in the history file. + Appending this session's history to the history file resets this to 0. */ +int history_lines_this_session; + +/* The number of lines that Bash has read from the history file. */ +int history_lines_in_file; + +#if defined (BANG_HISTORY) +/* Non-zero means do no history expansion on this line, regardless + of what history_expansion says. */ +int history_expansion_inhibited; +#endif + +/* With the old default, every line was saved in the history individually. + I.e., if the user enters: + bash$ for i in a b c + > do + > echo $i + > done + Each line will be individually saved in the history. + bash$ history + 10 for i in a b c + 11 do + 12 echo $i + 13 done + 14 history + If the variable command_oriented_history is set, multiple lines + which form one command will be saved as one history entry. + bash$ for i in a b c + > do + > echo $i + > done + bash$ history + 10 for i in a b c + do + echo $i + done + 11 history + The user can then recall the whole command all at once instead + of just being able to recall one line at a time. + + This is now enabled by default. + */ +int command_oriented_history = 1; + +/* Set to 1 if the first line of a possibly-multi-line command was saved + in the history list. Managed by maybe_add_history(), but global so + the history-manipluating builtins can see it. */ +int current_command_first_line_saved = 0; + +/* Non-zero means to store newlines in the history list when using + command_oriented_history rather than trying to use semicolons. */ +int literal_history; + +/* Non-zero means to append the history to the history file at shell + exit, even if the history has been stifled. */ +int force_append_history; + +/* A nit for picking at history saving. Flags have the following values: + + Value == 0 means save all lines parsed by the shell on the history. + Value & HC_IGNSPACE means save all lines that do not start with a space. + Value & HC_IGNDUPS means save all lines that do not match the last + line saved. + Value & HC_ERASEDUPS means to remove all other matching lines from the + history list before saving the latest line. */ +int history_control; + +/* Set to 1 if the last command was added to the history list successfully + as a separate history entry; set to 0 if the line was ignored or added + to a previous entry as part of command-oriented-history processing. */ +int hist_last_line_added; + +#if defined (READLINE) +/* If non-zero, and readline is being used, the user is offered the + chance to re-edit a failed history expansion. */ +int history_reediting; + +/* If non-zero, and readline is being used, don't directly execute a + line with history substitution. Reload it into the editing buffer + instead and let the user further edit and confirm with a newline. */ +int hist_verify; + +#endif /* READLINE */ + +/* Non-zero means to not save function definitions in the history list. */ +int dont_save_function_defs; + +/* Variables declared in other files used here. */ +extern int current_command_line_count; + +extern struct dstack dstack; + +static int bash_history_inhibit_expansion __P((char *, int)); +#if defined (READLINE) +static void re_edit __P((char *)); +#endif +static int history_expansion_p __P((char *)); +static int shell_comment __P((char *)); +static int should_expand __P((char *)); +static HIST_ENTRY *last_history_entry __P((void)); +static char *expand_histignore_pattern __P((char *)); +static int history_should_ignore __P((char *)); + +/* Is the history expansion starting at string[i] one that should not + be expanded? */ +static int +bash_history_inhibit_expansion (string, i) + char *string; + int i; +{ + /* The shell uses ! as a pattern negation character in globbing [...] + expressions, so let those pass without expansion. */ + if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1)) + return (1); + /* The shell uses ! as the indirect expansion character, so let those + expansions pass as well. */ + else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' && + member ('}', string + i + 1)) + return (1); +#if defined (EXTENDED_GLOB) + else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2)) + return (1); +#endif + else + return (0); +} + +void +bash_initialize_history () +{ + history_quotes_inhibit_expansion = 1; + history_search_delimiter_chars = ";&()|<>"; + history_inhibit_expansion_function = bash_history_inhibit_expansion; + sv_histchars ("histchars"); +} + +void +bash_history_reinit (interact) + int interact; +{ +#if defined (BANG_HISTORY) + history_expansion = interact != 0; + history_expansion_inhibited = 1; +#endif + remember_on_history = interact != 0; + history_inhibit_expansion_function = bash_history_inhibit_expansion; +} + +void +bash_history_disable () +{ + remember_on_history = 0; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 1; +#endif +} + +void +bash_history_enable () +{ + remember_on_history = 1; +#if defined (BANG_HISTORY) + history_expansion_inhibited = 0; +#endif + history_inhibit_expansion_function = bash_history_inhibit_expansion; + sv_history_control ("HISTCONTROL"); + sv_histignore ("HISTIGNORE"); +} + +/* Load the history list from the history file. */ +void +load_history () +{ + char *hf; + struct stat buf; + + /* Truncate history file for interactive shells which desire it. + Note that the history file is automatically truncated to the + size of HISTSIZE if the user does not explicitly set the size + differently. */ + set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE")); + sv_histsize ("HISTFILESIZE"); + + /* Read the history in HISTFILE into the history list. */ + hf = get_string_value ("HISTFILE"); + + if (hf && *hf && stat (hf, &buf) == 0) + { + read_history (hf); + using_history (); + history_lines_in_file = where_history (); + } +} + +#ifdef INCLUDE_UNUSED +/* Write the existing history out to the history file. */ +void +save_history () +{ + char *hf; + struct stat buf; + + hf = get_string_value ("HISTFILE"); + if (hf && *hf && stat (hf, &buf) == 0) + { + /* Append only the lines that occurred this session to + the history file. */ + using_history (); + + if (history_lines_this_session < where_history () || force_append_history) + append_history (history_lines_this_session, hf); + else + write_history (hf); + + sv_histsize ("HISTFILESIZE"); + } +} +#endif + +int +maybe_append_history (filename) + char *filename; +{ + int fd, result; + struct stat buf; + + result = EXECUTION_SUCCESS; + if (history_lines_this_session && (history_lines_this_session < where_history ())) + { + /* If the filename was supplied, then create it if necessary. */ + if (stat (filename, &buf) == -1 && errno == ENOENT) + { + fd = open (filename, O_WRONLY|O_CREAT, 0600); + if (fd < 0) + { + builtin_error (_("%s: cannot create: %s"), filename, strerror (errno)); + return (EXECUTION_FAILURE); + } + close (fd); + } + result = append_history (history_lines_this_session, filename); + history_lines_in_file += history_lines_this_session; + history_lines_this_session = 0; + } + return (result); +} + +/* If this is an interactive shell, then append the lines executed + this session to the history file. */ +int +maybe_save_shell_history () +{ + int result; + char *hf; + struct stat buf; + + result = 0; + if (history_lines_this_session) + { + hf = get_string_value ("HISTFILE"); + + if (hf && *hf) + { + /* If the file doesn't exist, then create it. */ + if (stat (hf, &buf) == -1) + { + int file; + file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (file != -1) + close (file); + } + + /* Now actually append the lines if the history hasn't been + stifled. If the history has been stifled, rewrite the + history file. */ + using_history (); + if (history_lines_this_session <= where_history () || force_append_history) + { + result = append_history (history_lines_this_session, hf); + history_lines_in_file += history_lines_this_session; + } + else + { + result = write_history (hf); + history_lines_in_file = history_lines_this_session; + } + history_lines_this_session = 0; + + sv_histsize ("HISTFILESIZE"); + } + } + return (result); +} + +#if defined (READLINE) +/* Tell readline () that we have some text for it to edit. */ +static void +re_edit (text) + char *text; +{ + if (bash_input.type == st_stdin) + bash_re_edit (text); +} +#endif /* READLINE */ + +/* Return 1 if this line needs history expansion. */ +static int +history_expansion_p (line) + char *line; +{ + register char *s; + + for (s = line; *s; s++) + if (*s == history_expansion_char || *s == history_subst_char) + return 1; + return 0; +} + +/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then + print the results of expanding the line if there were any changes. + If there is an error, return NULL, otherwise the expanded line is + returned. If ADDIT is non-zero the line is added to the history + list after history expansion. ADDIT is just a suggestion; + REMEMBER_ON_HISTORY can veto, and does. + Right now this does history expansion. */ +char * +pre_process_line (line, print_changes, addit) + char *line; + int print_changes, addit; +{ + char *history_value; + char *return_value; + int expanded; + + return_value = line; + expanded = 0; + +# if defined (BANG_HISTORY) + /* History expand the line. If this results in no errors, then + add that line to the history if ADDIT is non-zero. */ + if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) + { + expanded = history_expand (line, &history_value); + + if (expanded) + { + if (print_changes) + { + if (expanded < 0) + internal_error ("%s", history_value); +#if defined (READLINE) + else if (hist_verify == 0 || expanded == 2) +#else + else +#endif + fprintf (stderr, "%s\n", history_value); + } + + /* If there was an error, return NULL. */ + if (expanded < 0 || expanded == 2) /* 2 == print only */ + { +# if defined (READLINE) + if (expanded == 2 && rl_dispatching == 0 && *history_value) +# else + if (expanded == 2 && *history_value) +# endif /* !READLINE */ + maybe_add_history (history_value); + + free (history_value); + +# if defined (READLINE) + /* New hack. We can allow the user to edit the + failed history expansion. */ + if (history_reediting && expanded < 0 && rl_done) + re_edit (line); +# endif /* READLINE */ + return ((char *)NULL); + } + +# if defined (READLINE) + if (hist_verify && expanded == 1) + { + re_edit (history_value); + return ((char *)NULL); + } +# endif + } + + /* Let other expansions know that return_value can be free'ed, + and that a line has been added to the history list. Note + that we only add lines that have something in them. */ + expanded = 1; + return_value = history_value; + } +# endif /* BANG_HISTORY */ + + if (addit && remember_on_history && *return_value) + maybe_add_history (return_value); + +#if 0 + if (expanded == 0) + return_value = savestring (line); +#endif + + return (return_value); +} + +/* Return 1 if the first non-whitespace character in LINE is a `#', indicating + * that the line is a shell comment. */ +static int +shell_comment (line) + char *line; +{ + char *p; + + for (p = line; p && *p && whitespace (*p); p++) + ; + return (p && *p == '#'); +} + +#ifdef INCLUDE_UNUSED +/* Remove shell comments from LINE. A `#' and anything after it is a comment. + This isn't really useful yet, since it doesn't handle quoting. */ +static char * +filter_comments (line) + char *line; +{ + char *p; + + for (p = line; p && *p && *p != '#'; p++) + ; + if (p && *p == '#') + *p = '\0'; + return (line); +} +#endif + +/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line + should be saved; 0 if it should be discarded. */ +static int +check_history_control (line) + char *line; +{ + HIST_ENTRY *temp; + int r; + + if (history_control == 0) + return 1; + + /* ignorespace or ignoreboth */ + if ((history_control & HC_IGNSPACE) && *line == ' ') + return 0; + + /* ignoredups or ignoreboth */ + if (history_control & HC_IGNDUPS) + { + using_history (); + temp = previous_history (); + + r = (temp == 0 || STREQ (temp->line, line) == 0); + + using_history (); + + if (r == 0) + return r; + } + + return 1; +} + +/* Remove all entries matching LINE from the history list. Triggered when + HISTCONTROL includes `erasedups'. */ +static void +hc_erasedups (line) + char *line; +{ + HIST_ENTRY *temp; + int r; + + using_history (); + while (temp = previous_history ()) + { + if (STREQ (temp->line, line)) + { + r = where_history (); + remove_history (r); + } + } + using_history (); +} + +/* Add LINE to the history list, handling possibly multi-line compound + commands. We note whether or not we save the first line of each command + (which is usually the entire command and history entry), and don't add + the second and subsequent lines of a multi-line compound command if we + didn't save the first line. We don't usually save shell comment lines in + compound commands in the history, because they could have the effect of + commenting out the rest of the command when the entire command is saved as + a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If + LITERAL_HISTORY is set, we're saving lines in the history with embedded + newlines, so it's OK to save comment lines. We also make sure to save + multiple-line quoted strings or other constructs. */ +void +maybe_add_history (line) + char *line; +{ + hist_last_line_added = 0; + + /* Don't use the value of history_control to affect the second + and subsequent lines of a multi-line command (old code did + this only when command_oriented_history is enabled). */ + if (current_command_line_count > 1) + { + if (current_command_first_line_saved && + (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0)) + bash_add_history (line); + return; + } + + /* This is the first line of a (possible multi-line) command. Note whether + or not we should save the first line and remember it. */ + current_command_first_line_saved = check_add_history (line, 0); +} + +/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the + history if it's OK. Used by `history -s' as well as maybe_add_history(). + Returns 1 if the line was saved in the history, 0 otherwise. */ +int +check_add_history (line, force) + char *line; + int force; +{ + if (check_history_control (line) && history_should_ignore (line) == 0) + { + /* We're committed to saving the line. If the user has requested it, + remove other matching lines from the history. */ + if (history_control & HC_ERASEDUPS) + hc_erasedups (line); + + if (force) + { + really_add_history (line); + using_history (); + } + else + bash_add_history (line); + return 1; + } + return 0; +} + +/* Add a line to the history list. + The variable COMMAND_ORIENTED_HISTORY controls the style of history + remembering; when non-zero, and LINE is not the first line of a + complete parser construct, append LINE to the last history line instead + of adding it as a new line. */ +void +bash_add_history (line) + char *line; +{ + int add_it, offset, curlen; + HIST_ENTRY *current, *old; + char *chars_to_add, *new_line; + + add_it = 1; + if (command_oriented_history && current_command_line_count > 1) + { + chars_to_add = literal_history ? "\n" : history_delimiting_chars (); + + using_history (); + current = previous_history (); + + if (current) + { + /* If the previous line ended with an escaped newline (escaped + with backslash, but otherwise unquoted), then remove the quoted + newline, since that is what happens when the line is parsed. */ + curlen = strlen (current->line); + + if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' && + current->line[curlen - 2] != '\\') + { + current->line[curlen - 1] = '\0'; + curlen--; + chars_to_add = ""; + } + + new_line = (char *)xmalloc (1 + + curlen + + strlen (line) + + strlen (chars_to_add)); + sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); + offset = where_history (); + old = replace_history_entry (offset, new_line, current->data); + free (new_line); + + if (old) + free_history_entry (old); + + add_it = 0; + } + } + + if (add_it) + really_add_history (line); + + using_history (); +} + +static void +really_add_history (line) + char *line; +{ + hist_last_line_added = 1; + add_history (line); + history_lines_this_session++; +} + +int +history_number () +{ + using_history (); + return (get_string_value ("HISTSIZE") ? history_base + where_history () : 1); +} + +static int +should_expand (s) + char *s; +{ + char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} + +static int +histignore_item_func (ign) + struct ign *ign; +{ + if (should_expand (ign->val)) + ign->flags |= HIGN_EXPAND; + return (0); +} + +void +setup_history_ignore (varname) + char *varname; +{ + setup_ignore_patterns (&histignore); +} + +static HIST_ENTRY * +last_history_entry () +{ + HIST_ENTRY *he; + + using_history (); + he = previous_history (); + using_history (); + return he; +} + +char * +last_history_line () +{ + HIST_ENTRY *he; + + he = last_history_entry (); + if (he == 0) + return ((char *)NULL); + return he->line; +} + +static char * +expand_histignore_pattern (pat) + char *pat; +{ + HIST_ENTRY *phe; + char *ret; + + phe = last_history_entry (); + + if (phe == (HIST_ENTRY *)0) + return (savestring (pat)); + + ret = strcreplace (pat, '&', phe->line, 1); + + return ret; +} + +/* Return 1 if we should not put LINE into the history according to the + patterns in HISTIGNORE. */ +static int +history_should_ignore (line) + char *line; +{ + register int i, match; + char *npat; + + if (histignore.num_ignores == 0) + return 0; + + for (i = match = 0; i < histignore.num_ignores; i++) + { + if (histignore.ignores[i].flags & HIGN_EXPAND) + npat = expand_histignore_pattern (histignore.ignores[i].val); + else + npat = histignore.ignores[i].val; + + match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH; + + if (histignore.ignores[i].flags & HIGN_EXPAND) + free (npat); + + if (match) + break; + } + + return match; +} +#endif /* HISTORY */ @@ -1765,7 +1765,7 @@ cleanup_expansion_error () hist_verify = old_verify; #endif if (to_free != rl_line_buffer) - free (to_free); + FREE (to_free); putc ('\r', rl_outstream); rl_forced_update_display (); } diff --git a/bashline.c~ b/bashline.c~ new file mode 100644 index 00000000..aa390999 --- /dev/null +++ b/bashline.c~ @@ -0,0 +1,2981 @@ +/* bashline.c -- Bash's interface to the readline library. */ + +/* Copyright (C) 1987-2004 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include "config.h" + +#if defined (READLINE) + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_GRP_H) +# include <grp.h> +#endif + +#if defined (HAVE_NETDB_H) +# include <netdb.h> +#endif + +#include <stdio.h> +#include "chartypes.h" +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "input.h" +#include "builtins.h" +#include "bashhist.h" +#include "bashline.h" +#include "execute_cmd.h" +#include "findcmd.h" +#include "pathexp.h" +#include "builtins/common.h" +#include <readline/rlconf.h> +#include <readline/readline.h> +#include <readline/history.h> + +#include <glob/glob.h> + +#if defined (ALIAS) +# include "alias.h" +#endif + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +/* These should agree with the defines for emacs_mode and vi_mode in + rldefs.h, even though that's not a public readline header file. */ +#ifndef EMACS_EDITING_MODE +# define NO_EDITING_MODE -1 +# define EMACS_EDITING_MODE 1 +# define VI_EDITING_MODE 0 +#endif + +#if defined (BRACE_COMPLETION) +extern int bash_brace_completion __P((int, int)); +#endif /* BRACE_COMPLETION */ + +/* Forward declarations */ + +/* Functions bound to keys in Readline for Bash users. */ +static int shell_expand_line __P((int, int)); +static int display_shell_version __P((int, int)); +static int operate_and_get_next __P((int, int)); + +static int bash_ignore_filenames __P((char **)); +static int bash_ignore_everything __P((char **)); + +#if defined (BANG_HISTORY) +static char *history_expand_line_internal __P((char *)); +static int history_expand_line __P((int, int)); +static int tcsh_magic_space __P((int, int)); +#endif /* BANG_HISTORY */ +#ifdef ALIAS +static int alias_expand_line __P((int, int)); +#endif +#if defined (BANG_HISTORY) && defined (ALIAS) +static int history_and_alias_expand_line __P((int, int)); +#endif + +/* Helper functions for Readline. */ +static int bash_directory_completion_hook __P((char **)); +static int filename_completion_ignore __P((char **)); +static int bash_push_line __P((void)); + +static void cleanup_expansion_error __P((void)); +static void maybe_make_readline_line __P((char *)); +static void set_up_new_line __P((char *)); + +static int check_redir __P((int)); +static char **attempt_shell_completion __P((const char *, int, int)); +static char *variable_completion_function __P((const char *, int)); +static char *hostname_completion_function __P((const char *, int)); +static char *command_subst_completion_function __P((const char *, int)); + +static void build_history_completion_array __P((void)); +static char *history_completion_generator __P((const char *, int)); +static int dynamic_complete_history __P((int, int)); + +static void initialize_hostname_list __P((void)); +static void add_host_name __P((char *)); +static void snarf_hosts_from_file __P((char *)); +static char **hostnames_matching __P((char *)); + +static void _ignore_completion_names __P((char **, sh_ignore_func_t *)); +static int name_is_acceptable __P((const char *)); +static int test_for_directory __P((const char *)); +static int return_zero __P((const char *)); + +static char *bash_dequote_filename __P((char *, int)); +static char *quote_word_break_chars __P((char *)); +static char *bash_quote_filename __P((char *, int, char *)); + +static int bash_execute_unix_command __P((int, int)); +static void init_unix_command_map __P((void)); +static int isolate_sequence __P((char *, int, int, int *)); + +static int set_saved_history __P((void)); + +#if defined (ALIAS) +static int posix_edit_macros __P((int, int)); +#endif + +#if defined (PROGRAMMABLE_COMPLETION) +static int find_cmd_start __P((int)); +static int find_cmd_end __P((int)); +static char *find_cmd_name __P((int)); +static char *prog_complete_return __P((const char *, int)); + +static char **prog_complete_matches; +#endif + +/* Variables used here but defined in other files. */ +#if defined (BANG_HISTORY) +extern int hist_verify; +#endif + +extern int current_command_line_count, last_command_exit_value; +extern int posixly_correct, no_symbolic_links; +extern char *current_prompt_string, *ps1_prompt; +extern STRING_INT_ALIST word_token_alist[]; +extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; + +/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual + completion functions which indicate what type of completion should be + done (at or before point) that can be bound to key sequences with + the readline library. */ +#define SPECIFIC_COMPLETION_FUNCTIONS + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int bash_specific_completion __P((int, rl_compentry_func_t *)); + +static int bash_complete_filename_internal __P((int)); +static int bash_complete_username_internal __P((int)); +static int bash_complete_hostname_internal __P((int)); +static int bash_complete_variable_internal __P((int)); +static int bash_complete_command_internal __P((int)); + +static int bash_complete_filename __P((int, int)); +static int bash_possible_filename_completions __P((int, int)); +static int bash_complete_username __P((int, int)); +static int bash_possible_username_completions __P((int, int)); +static int bash_complete_hostname __P((int, int)); +static int bash_possible_hostname_completions __P((int, int)); +static int bash_complete_variable __P((int, int)); +static int bash_possible_variable_completions __P((int, int)); +static int bash_complete_command __P((int, int)); +static int bash_possible_command_completions __P((int, int)); + +static char *glob_complete_word __P((const char *, int)); +static int bash_glob_completion_internal __P((int)); +static int bash_glob_complete_word __P((int, int)); +static int bash_glob_expand_word __P((int, int)); +static int bash_glob_list_expansions __P((int, int)); +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +static int edit_and_execute_command __P((int, int, int, char *)); +#if defined (VI_MODE) +static int vi_edit_and_execute_command __P((int, int)); +#endif +static int emacs_edit_and_execute_command __P((int, int)); + +/* Non-zero once initalize_readline () has been called. */ +int bash_readline_initialized = 0; + +/* If non-zero, we do hostname completion, breaking words at `@' and + trying to complete the stuff after the `@' from our own internal + host list. */ +int perform_hostname_completion = 1; + +/* If non-zero, we don't do command completion on an empty line. */ +int no_empty_command_completion; + +/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the + only possible matches. Set to 0 if you want to match filenames if they + are the only possible matches, even if FIGNORE says to. */ +int force_fignore = 1; + +static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; +static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; +/* )) */ + +static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; + +/* What kind of quoting is performed by bash_quote_filename: + COMPLETE_DQUOTE = double-quoting the filename + COMPLETE_SQUOTE = single_quoting the filename + COMPLETE_BSQUOTE = backslash-quoting special chars in the filename +*/ +#define COMPLETE_DQUOTE 1 +#define COMPLETE_SQUOTE 2 +#define COMPLETE_BSQUOTE 3 +static int completion_quoting_style = COMPLETE_BSQUOTE; + +/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. + Called when the shell is put into or out of `posix' mode. */ +void +posix_readline_initialize (on_or_off) + int on_or_off; +{ + if (on_or_off) + rl_variable_bind ("comment-begin", "#"); +#if defined (VI_MODE) + rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); +#endif +} + +/* When this function returns, rl_completer_word_break_characters points to + dynamically allocated memory. */ +int +enable_hostname_completion (on_or_off) + int on_or_off; +{ + int old_value; + char *at, *nv, *nval; + + old_value = perform_hostname_completion; + + if (on_or_off) + { + perform_hostname_completion = 1; + rl_special_prefixes = "$@"; + } + else + { + perform_hostname_completion = 0; + rl_special_prefixes = "$"; + } + + /* Now we need to figure out how to appropriately modify and assign + rl_completer_word_break_characters depending on whether we want + hostname completion on or off. */ + + /* If this is the first time this has been called + (bash_readline_initialized == 0), use the sames values as before, but + allocate new memory for rl_completer_word_break_characters. */ + + if (bash_readline_initialized == 0 && + (rl_completer_word_break_characters == 0 || + rl_completer_word_break_characters == rl_basic_word_break_characters)) + { + if (on_or_off) + rl_completer_word_break_characters = savestring (bash_completer_word_break_characters); + else + rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters); + } + else + { + /* See if we have anything to do. */ + at = strchr (rl_completer_word_break_characters, '@'); + if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) + return; + + /* We have something to do. Do it. */ + nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); + + if (on_or_off == 0) + { + /* Turn it off -- just remove `@' from word break chars. We want + to remove all occurrences of `@' from the char list, so we loop + rather than just copy the rest of the list over AT. */ + for (nv = nval, at = rl_completer_word_break_characters; *at; ) + if (*at != '@') + *nv++ = *at++; + else + at++; + *nv = '\0'; + } + else + { + nval[0] = '@'; + strcpy (nval + 1, rl_completer_word_break_characters); + } + + free (rl_completer_word_break_characters); + rl_completer_word_break_characters = nval; + } + + return (old_value); +} + +/* Called once from parse.y if we are going to use readline. */ +void +initialize_readline () +{ + rl_command_func_t *func; + char kseq[2]; + + if (bash_readline_initialized) + return; + + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bash"; + + /* Add bindable names before calling rl_initialize so they may be + referenced in the various inputrc files. */ + rl_add_defun ("shell-expand-line", shell_expand_line, -1); +#ifdef BANG_HISTORY + rl_add_defun ("history-expand-line", history_expand_line, -1); + rl_add_defun ("magic-space", tcsh_magic_space, -1); +#endif + +#ifdef ALIAS + rl_add_defun ("alias-expand-line", alias_expand_line, -1); +# ifdef BANG_HISTORY + rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); +# endif +#endif + + /* Backwards compatibility. */ + rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); + + rl_add_defun ("operate-and-get-next", operate_and_get_next, -1); + rl_add_defun ("display-shell-version", display_shell_version, -1); + rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); + +#if defined (BRACE_COMPLETION) + rl_add_defun ("complete-into-braces", bash_brace_completion, -1); +#endif + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_add_defun ("complete-filename", bash_complete_filename, -1); + rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); + rl_add_defun ("complete-username", bash_complete_username, -1); + rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); + rl_add_defun ("complete-hostname", bash_complete_hostname, -1); + rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); + rl_add_defun ("complete-variable", bash_complete_variable, -1); + rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); + rl_add_defun ("complete-command", bash_complete_command, -1); + rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); + rl_add_defun ("glob-complete-word", bash_glob_complete_word, -1); + rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); + rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); +#endif + + rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); + + /* Bind defaults before binding our custom shell keybindings. */ + if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) + rl_initialize (); + + /* Bind up our special shell functions. */ + rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); + +#ifdef BANG_HISTORY + rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); +#endif + + rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap); + rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); + + /* In Bash, the user can switch editing modes with "set -o [vi emacs]", + so it is not necessary to allow C-M-j for context switching. Turn + off this occasionally confusing behaviour. */ + kseq[0] = CTRL('J'); + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); + kseq[0] = CTRL('M'); + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); +#if defined (VI_MODE) + rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); +#endif + +#if defined (BRACE_COMPLETION) + rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/ +#endif /* BRACE_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); + + /* Have to jump through hoops here because there is a default binding for + M-~ (rl_tilde_expand) */ + kseq[0] = '~'; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tilde_expand) + rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); + + rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); + rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + + rl_bind_key_if_unbound_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = attempt_shell_completion; + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ + rl_directory_completion_hook = bash_directory_completion_hook; + + /* Tell the filename completer we want a chance to ignore some names. */ + rl_ignore_some_completions_function = filename_completion_ignore; + + /* Bind C-xC-e to invoke emacs and run result as commands. */ + rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); +#if defined (VI_MODE) + rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +# if defined (ALIAS) + rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); +# endif +#endif + + rl_completer_quote_characters = "'\""; + + /* This sets rl_completer_word_break_characters and rl_special_prefixes + to the appropriate values, depending on whether or not hostname + completion is enabled. */ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ + rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{"; /*}*/ + rl_filename_quoting_function = bash_quote_filename; + rl_filename_dequoting_function = bash_dequote_filename; + rl_char_is_quoted_p = char_is_quoted; + +#if 0 + /* This is superfluous and makes it impossible to use tab completion in + vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() + should already have called posix_readline_initialize() when + posixly_correct was set. */ + if (posixly_correct) + posix_readline_initialize (1); +#endif + + bash_readline_initialized = 1; +} + +/* On Sun systems at least, rl_attempted_completion_function can end up + getting set to NULL, and rl_completion_entry_function set to do command + word completion if Bash is interrupted while trying to complete a command + word. This just resets all the completion functions to the right thing. + It's called from throw_to_top_level(). */ +void +bashline_reinitialize () +{ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = NULL; + rl_directory_completion_hook = bash_directory_completion_hook; + rl_ignore_some_completions_function = filename_completion_ignore; +} + +/* Contains the line to push into readline. */ +static char *push_to_readline = (char *)NULL; + +/* Push the contents of push_to_readline into the + readline buffer. */ +static int +bash_push_line () +{ + if (push_to_readline) + { + rl_insert_text (push_to_readline); + free (push_to_readline); + push_to_readline = (char *)NULL; + rl_startup_hook = old_rl_startup_hook; + } + return 0; +} + +/* Call this to set the initial text for the next line to read + from readline. */ +int +bash_re_edit (line) + char *line; +{ + FREE (push_to_readline); + + push_to_readline = savestring (line); + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = bash_push_line; + + return (0); +} + +static int +display_shell_version (count, c) + int count, c; +{ + rl_crlf (); + show_shell_version (0); + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); + return 0; +} + +/* **************************************************************** */ +/* */ +/* Readline Stuff */ +/* */ +/* **************************************************************** */ + +/* If the user requests hostname completion, then simply build a list + of hosts, and complete from that forever more, or at least until + HOSTFILE is unset. */ + +/* THIS SHOULD BE A STRINGLIST. */ +/* The kept list of hostnames. */ +static char **hostname_list = (char **)NULL; + +/* The physical size of the above list. */ +static int hostname_list_size; + +/* The number of hostnames in the above list. */ +static int hostname_list_length; + +/* Whether or not HOSTNAME_LIST has been initialized. */ +int hostname_list_initialized = 0; + +/* Initialize the hostname completion table. */ +static void +initialize_hostname_list () +{ + char *temp; + + temp = get_string_value ("HOSTFILE"); + if (temp == 0) + temp = get_string_value ("hostname_completion_file"); + if (temp == 0) + temp = DEFAULT_HOSTS_FILE; + + snarf_hosts_from_file (temp); + + if (hostname_list) + hostname_list_initialized++; +} + +/* Add NAME to the list of hosts. */ +static void +add_host_name (name) + char *name; +{ + if (hostname_list_length + 2 > hostname_list_size) + { + hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); + hostname_list = strvec_resize (hostname_list, hostname_list_size); + } + + hostname_list[hostname_list_length++] = savestring (name); + hostname_list[hostname_list_length] = (char *)NULL; +} + +#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) + +static void +snarf_hosts_from_file (filename) + char *filename; +{ + FILE *file; + char *temp, buffer[256], name[256]; + register int i, start; + + file = fopen (filename, "r"); + if (file == 0) + return; + + while (temp = fgets (buffer, 255, file)) + { + /* Skip to first character. */ + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) + ; + + /* If comment or blank line, ignore. */ + if (buffer[i] == '\0' || buffer[i] == '#') + continue; + + /* If `preprocessor' directive, do the include. */ + if (strncmp (buffer + i, "$include ", 9) == 0) + { + char *incfile, *t; + + /* Find start of filename. */ + for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) + ; + + /* Find end of filename. */ + for (t = incfile; *t && cr_whitespace (*t) == 0; t++) + ; + + *t = '\0'; + + snarf_hosts_from_file (incfile); + continue; + } + + /* Skip internet address if present. */ + if (DIGIT (buffer[i])) + for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); + + /* Gobble up names. Each name is separated with whitespace. */ + while (buffer[i]) + { + for (; cr_whitespace (buffer[i]); i++) + ; + if (buffer[i] == '\0' || buffer[i] == '#') + break; + + /* Isolate the current word. */ + for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) + ; + if (i == start) + continue; + strncpy (name, buffer + start, i - start); + name[i - start] = '\0'; + add_host_name (name); + } + } + fclose (file); +} + +/* Return the hostname list. */ +char ** +get_hostname_list () +{ + if (hostname_list_initialized == 0) + initialize_hostname_list (); + return (hostname_list); +} + +void +clear_hostname_list () +{ + register int i; + + if (hostname_list_initialized == 0) + return; + for (i = 0; i < hostname_list_length; i++) + free (hostname_list[i]); + hostname_list_length = 0; +} + +/* Return a NULL terminated list of hostnames which begin with TEXT. + Initialize the hostname list the first time if neccessary. + The array is malloc ()'ed, but not the individual strings. */ +static char ** +hostnames_matching (text) + char *text; +{ + register int i, len, nmatch, rsize; + char **result; + + if (hostname_list_initialized == 0) + initialize_hostname_list (); + + if (hostname_list_initialized == 0) + return ((char **)NULL); + + /* Special case. If TEXT consists of nothing, then the whole list is + what is desired. */ + if (*text == '\0') + { + result = strvec_create (1 + hostname_list_length); + for (i = 0; i < hostname_list_length; i++) + result[i] = hostname_list[i]; + result[i] = (char *)NULL; + return (result); + } + + /* Scan until found, or failure. */ + len = strlen (text); + result = (char **)NULL; + for (i = nmatch = rsize = 0; i < hostname_list_length; i++) + { + if (STREQN (text, hostname_list[i], len) == 0) + continue; + + /* OK, it matches. Add it to the list. */ + if (nmatch >= (rsize - 1)) + { + rsize = (rsize + 16) - (rsize % 16); + result = strvec_resize (result, rsize); + } + + result[nmatch++] = hostname_list[i]; + } + if (nmatch) + result[nmatch] = (char *)NULL; + return (result); +} + +/* The equivalent of the Korn shell C-o operate-and-get-next-history-line + editing command. */ +static int saved_history_line_to_use = -1; + +static int +set_saved_history () +{ + if (saved_history_line_to_use >= 0) + rl_get_previous_history (history_length - saved_history_line_to_use, 0); + saved_history_line_to_use = -1; + rl_startup_hook = old_rl_startup_hook; + return (0); +} + +static int +operate_and_get_next (count, c) + int count, c; +{ + int where; + + /* Accept the current line. */ + rl_newline (1, c); + + /* Find the current line, and find the next line to use. */ + where = where_history (); + + if ((history_is_stifled () && (history_length >= history_max_entries)) || + (where >= history_length - 1)) + saved_history_line_to_use = where; + else + saved_history_line_to_use = where + 1; + + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = set_saved_history; + + return 0; +} + +/* This vi mode command causes VI_EDIT_COMMAND to be run on the current + command being entered (if no explicit argument is given), otherwise on + a command from the history file. */ + +#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" +#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" + +static int +edit_and_execute_command (count, c, editing_mode, edit_command) + int count, c, editing_mode; + char *edit_command; +{ + char *command; + int r, cclc, rrs; + + rrs = rl_readline_state; + cclc = current_command_line_count; + + /* Accept the current line. */ + rl_newline (1, c); + + if (rl_explicit_arg) + { + command = (char *)xmalloc (strlen (edit_command) + 8); + sprintf (command, "%s %d", edit_command, count); + } + else + { + /* Take the command we were just editing, add it to the history file, + then call fc to operate on it. We have to add a dummy command to + the end of the history because fc ignores the last command (assumes + it's supposed to deal with the command before the `fc'). */ + using_history (); + bash_add_history (rl_line_buffer); + bash_add_history (""); + history_lines_this_session++; + using_history (); + command = savestring (edit_command); + } + + /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the + temporary file should be placed into the history. We don't do that + yet. */ + r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); + + current_command_line_count = cclc; + + /* Now erase the contents of the current line and undo the effects of the + rl_accept_line() above. We don't even want to make the text we just + executed available for undoing. */ + rl_line_buffer[0] = '\0'; /* XXX */ + rl_point = rl_end = 0; + rl_done = 0; + rl_readline_state = rrs; + + rl_forced_update_display (); + + return r; +} + +#if defined (VI_MODE) +static int +vi_edit_and_execute_command (count, c) + int count, c; +{ + return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); +} +#endif /* VI_MODE */ + +static int +emacs_edit_and_execute_command (count, c) + int count, c; +{ + return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); +} + +#if defined (ALIAS) +static int +posix_edit_macros (count, key) + int count, key; +{ + int c; + char alias_name[3], *alias_value, *macro; + + c = rl_read_key (); + alias_name[0] = '_'; + alias_name[1] = c; + alias_name[2] = '\0'; + + alias_value = get_alias_value (alias_name); + if (alias_value && *alias_value) + { + macro = savestring (alias_value); + rl_push_macro_input (macro); + } + return 0; +} +#endif + +/* **************************************************************** */ +/* */ +/* How To Do Shell Completion */ +/* */ +/* **************************************************************** */ + +#define COMMAND_SEPARATORS ";|&{(`" +/* )} */ + +static int +check_redir (ti) + int ti; +{ + register int this_char, prev_char; + + /* Handle the two character tokens `>&', `<&', and `>|'. + We are not in a command position after one of these. */ + this_char = rl_line_buffer[ti]; + prev_char = rl_line_buffer[ti - 1]; + + if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || + (this_char == '|' && prev_char == '>')) + return (1); + else if ((this_char == '{' && prev_char == '$') || /* } */ + (char_is_quoted (rl_line_buffer, ti))) + return (1); + return (0); +} + +#if defined (PROGRAMMABLE_COMPLETION) +/* + * XXX - because of the <= start test, and setting os = s+1, this can + * potentially return os > start. This is probably not what we want to + * happen, but fix later after 2.05a-release. + */ +static int +find_cmd_start (start) + int start; +{ + register int s, os; + + os = 0; + while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS)) <= start) && + rl_line_buffer[s]) + os = s+1; + return os; +} + +static int +find_cmd_end (end) + int end; +{ + register int e; + + e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS); + return e; +} + +static char * +find_cmd_name (start) + int start; +{ + char *name; + register int s, e; + + for (s = start; whitespace (rl_line_buffer[s]); s++) + ; + + /* skip until a shell break character */ + e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n"); + + name = substring (rl_line_buffer, s, e); + + return (name); +} + +static char * +prog_complete_return (text, matchnum) + const char *text; + int matchnum; +{ + static int ind; + + if (matchnum == 0) + ind = 0; + + if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) + return (char *)NULL; + return (prog_complete_matches[ind++]); +} + +#endif /* PROGRAMMABLE_COMPLETION */ + +/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are + at START and END. Return an array of matches, or NULL if none. */ +static char ** +attempt_shell_completion (text, start, end) + const char *text; + int start, end; +{ + int in_command_position, ti, saveti, qc; + char **matches, *command_separator_chars; + + command_separator_chars = COMMAND_SEPARATORS; + matches = (char **)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + /* Determine if this could be a command word. It is if it appears at + the start of the line (ignoring preceding whitespace), or if it + appears after a character that separates commands. It cannot be a + command word if we aren't at the top-level prompt. */ + ti = start - 1; + saveti = qc = -1; + + while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) + ti--; + +#if 1 + /* If this is an open quote, maybe we're trying to complete a quoted + command name. */ + if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) + { + qc = rl_line_buffer[ti]; + saveti = ti--; + while (ti > -1 && (whitespace (rl_line_buffer[ti]))) + ti--; + } +#endif + + in_command_position = 0; + if (ti < 0) + { + /* Only do command completion at the start of a line when we + are prompting at the top level. */ + if (current_prompt_string == ps1_prompt) + in_command_position++; + } + else if (member (rl_line_buffer[ti], command_separator_chars)) + { + in_command_position++; + + if (check_redir (ti) == 1) + in_command_position = 0; + } + else + { + /* This still could be in command position. It is possible + that all of the previous words on the line are variable + assignments. */ + } + + /* Check that we haven't incorrectly flagged a closed command substitution + as indicating we're in a command position. */ + if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && + *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) + in_command_position = 0; + + /* Special handling for command substitution. If *TEXT is a backquote, + it can be the start or end of an old-style command substitution, or + unmatched. If it's unmatched, both calls to unclosed_pair will + succeed. */ + if (*text == '`' && + (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && + unclosed_pair (rl_line_buffer, end, "`")))) + matches = rl_completion_matches (text, command_subst_completion_function); + +#if defined (PROGRAMMABLE_COMPLETION) + /* Attempt programmable completion. */ + if (!matches && in_command_position == 0 && prog_completion_enabled && + (progcomp_size () > 0) && current_prompt_string == ps1_prompt) + { + int s, e, foundcs; + char *n; + + /* XXX - don't free the members */ + if (prog_complete_matches) + free (prog_complete_matches); + prog_complete_matches = (char **)NULL; + + s = find_cmd_start (start); + e = find_cmd_end (end); + n = find_cmd_name (s); + if (e > s) + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + else + foundcs = 0; + FREE (n); + /* XXX - if we found a COMPSPEC for the command, just return whatever + the programmable completion code returns, and disable the default + filename completion that readline will do unless the COPT_DEFAULT + option has been set with the `-o default' option to complete. */ + if (foundcs) + { + /* If the user specified that the compspec returns filenames, make + sure that readline knows it. */ + if (foundcs & COPT_FILENAMES) + rl_filename_completion_desired = 1; + /* If the user doesn't want a space appended, tell readline. */ + if (foundcs & COPT_NOSPACE) + rl_completion_suppress_append = 1; + /* Turn what the programmable completion code returns into what + readline wants. I should have made compute_lcd_of_matches + external... */ + matches = rl_completion_matches (text, prog_complete_return); + if ((foundcs & COPT_DEFAULT) == 0) + rl_attempted_completion_over = 1; /* no default */ + if (matches || ((foundcs & COPT_BASHDEFAULT) == 0)) + return (matches); + } + } +#endif + + if (matches == 0) + matches = bash_default_completion (text, start, end, qc, in_command_position); + + return matches; +} + +char ** +bash_default_completion (text, start, end, qc, in_command_position) + const char *text; + int start, end, qc, in_command_position; +{ + char **matches; + + matches = (char **)NULL; + + /* New posix-style command substitution or variable name? */ + if (!matches && *text == '$') + { + if (qc != '\'' && text[1] == '(') /* ) */ + matches = rl_completion_matches (text, command_subst_completion_function); + else + matches = rl_completion_matches (text, variable_completion_function); + } + + /* If the word starts in `~', and there is no slash in the word, then + try completing this word as a username. */ + if (!matches && *text == '~' && !xstrchr (text, '/')) + matches = rl_completion_matches (text, rl_username_completion_function); + + /* Another one. Why not? If the word starts in '@', then look through + the world of known hostnames for completion first. */ + if (!matches && perform_hostname_completion && *text == '@') + matches = rl_completion_matches (text, hostname_completion_function); + + /* And last, (but not least) if this word is in a command position, then + complete over possible command names, including aliases, functions, + and command names. */ + if (!matches && in_command_position) + { + if (start == 0 && end == 0 && text[0] == '\0' && no_empty_command_completion) + { + matches = (char **)NULL; + rl_ignore_some_completions_function = bash_ignore_everything; + } + else + { +#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) + + matches = rl_completion_matches (text, command_word_completion_function); + + /* If we are attempting command completion and nothing matches, we + do not want readline to perform filename completion for us. We + still want to be able to complete partial pathnames, so set the + completion ignore function to something which will remove + filenames and leave directories in the match list. */ + if (matches == (char **)NULL) + rl_ignore_some_completions_function = bash_ignore_filenames; +#if 0 + else if (matches[1] == 0 && CMD_IS_DIR(matches[0])) + /* Turn off rl_filename_completion_desired so readline doesn't + append a slash if there is a directory with the same name + in the current directory, or other filename-specific things. + If the name begins with a slash, we're either completing a + full pathname or a directory pathname, and readline won't be + looking in the current directory anyway, so there's no + conflict. */ + rl_filename_completion_desired = 0; + else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) + /* There are multiple instances of the same match (duplicate + completions haven't yet been removed). In this case, all of + the matches will be the same, and the duplicate removal code + will distill them all down to one. We turn off + rl_filename_completion_desired for the same reason as above. + Remember: we only care if there's eventually a single unique + completion. If there are multiple completions this won't + make a difference and the problem won't occur. */ + rl_filename_completion_desired = 0; +#endif + } + } + + /* This could be a globbing pattern, so try to expand it using pathname + expansion. */ + if (!matches && glob_pattern_p (text)) + { + matches = rl_completion_matches (text, glob_complete_word); + /* A glob expression that matches more than one filename is problematic. + If we match more than one filename, punt. */ + if (matches && matches[1] && rl_completion_type == TAB) + { + strvec_dispose (matches); + matches = (char **)0; + } + } + + return (matches); +} + +/* This is the function to call when the word to complete is in a position + where a command word can be found. It grovels $PATH, looking for commands + that match. It also scans aliases, function names, and the shell_builtin + table. */ +char * +command_word_completion_function (hint_text, state) + const char *hint_text; + int state; +{ + static char *hint = (char *)NULL; + static char *path = (char *)NULL; + static char *val = (char *)NULL; + static char *filename_hint = (char *)NULL; + static int path_index, hint_len, istate; + static int mapping_over, local_index; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; +#if defined (ALIAS) + static alias_t **alias_list = (alias_t **)NULL; +#endif /* ALIAS */ + + /* We have to map over the possibilities for command words. If we have + no state, then make one just for that purpose. */ + if (!state) + { + if (hint) + free (hint); + + mapping_over = 0; + val = (char *)NULL; + + /* If this is an absolute program name, do not check it against + aliases, reserved words, functions or builtins. We must check + whether or not it is unique, and, if so, whether that filename + is executable. */ + if (absolute_program (hint_text)) + { + /* Perform tilde expansion on what's passed, so we don't end up + passing filenames with tildes directly to stat(). */ + if (*hint_text == '~') + hint = bash_tilde_expand (hint_text, 0); + else + hint = savestring (hint_text); + hint_len = strlen (hint); + + if (filename_hint) + free (filename_hint); + filename_hint = savestring (hint); + + mapping_over = 4; + istate = 0; + goto inner; + } + + hint = savestring (hint_text); + hint_len = strlen (hint); + + path = get_string_value ("PATH"); + path_index = 0; + + /* Initialize the variables for each type of command word. */ + local_index = 0; + + if (varlist) + free (varlist); + + varlist = all_visible_functions (); + +#if defined (ALIAS) + if (alias_list) + free (alias_list); + + alias_list = all_aliases (); +#endif /* ALIAS */ + } + + /* mapping_over says what we are currently hacking. Note that every case + in this list must fall through when there are no more possibilities. */ + + switch (mapping_over) + { + case 0: /* Aliases come first. */ +#if defined (ALIAS) + while (alias_list && alias_list[local_index]) + { + register char *alias; + + alias = alias_list[local_index++]->name; + + if (STREQN (alias, hint, hint_len)) + return (savestring (alias)); + } +#endif /* ALIAS */ + local_index = 0; + mapping_over++; + + case 1: /* Then shell reserved words. */ + { + while (word_token_alist[local_index].word) + { + register char *reserved_word; + + reserved_word = word_token_alist[local_index++].word; + + if (STREQN (reserved_word, hint, hint_len)) + return (savestring (reserved_word)); + } + local_index = 0; + mapping_over++; + } + + case 2: /* Then function names. */ + while (varlist && varlist[local_index]) + { + register char *varname; + + varname = varlist[local_index++]->name; + + if (STREQN (varname, hint, hint_len)) + return (savestring (varname)); + } + local_index = 0; + mapping_over++; + + case 3: /* Then shell builtins. */ + for (; local_index < num_shell_builtins; local_index++) + { + /* Ignore it if it doesn't have a function pointer or if it + is not currently enabled. */ + if (!shell_builtins[local_index].function || + (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) + continue; + + if (STREQN (shell_builtins[local_index].name, hint, hint_len)) + { + int i = local_index++; + + return (savestring (shell_builtins[i].name)); + } + } + local_index = 0; + mapping_over++; + } + + /* Repeatedly call filename_completion_function while we have + members of PATH left. Question: should we stat each file? + Answer: we call executable_file () on each file. */ + outer: + + istate = (val != (char *)NULL); + + if (!istate) + { + char *current_path; + + /* Get the next directory from the path. If there is none, then we + are all done. */ + if (!path || !path[path_index] || + (current_path = extract_colon_unit (path, &path_index)) == 0) + return ((char *)NULL); + + if (*current_path == 0) + { + free (current_path); + current_path = savestring ("."); + } + + if (*current_path == '~') + { + char *t; + + t = bash_tilde_expand (current_path, 0); + free (current_path); + current_path = t; + } + + if (filename_hint) + free (filename_hint); + + filename_hint = sh_makepath (current_path, hint, 0); + + free (current_path); + } + + inner: + val = rl_filename_completion_function (filename_hint, istate); + istate = 1; + + if (val == 0) + { + /* If the hint text is an absolute program, then don't bother + searching through PATH. */ + if (absolute_program (hint)) + return ((char *)NULL); + + goto outer; + } + else + { + int match, freetemp; + char *temp; + + if (absolute_program (hint)) + { + match = strncmp (val, hint, hint_len) == 0; + /* If we performed tilde expansion, restore the original + filename. */ + if (*hint_text == '~') + { + int l, tl, vl; + vl = strlen (val); + tl = strlen (hint_text); + l = vl - hint_len; /* # of chars added */ + temp = (char *)xmalloc (l + 2 + tl); + strcpy (temp, hint_text); + strcpy (temp + tl, val + vl - l); + } + else + temp = savestring (val); + freetemp = 1; + } + else + { + temp = strrchr (val, '/'); + + if (temp) + { + temp++; + freetemp = match = strncmp (temp, hint, hint_len) == 0; + if (match) + temp = savestring (temp); + } + else + freetemp = match = 0; + } + + /* If we have found a match, and it is an executable file or a + directory name, return it. */ + if (match && executable_or_directory (val)) + { + free (val); + val = ""; /* So it won't be NULL. */ + return (temp); + } + else + { + if (freetemp) + free (temp); + free (val); + goto inner; + } + } +} + +/* Completion inside an unterminated command substitution. */ +static char * +command_subst_completion_function (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static const char *orig_start; + static char *filename_text = (char *)NULL; + static int cmd_index, start_len; + char *value; + + if (state == 0) + { + if (filename_text) + free (filename_text); + orig_start = text; + if (*text == '`') + text++; + else if (*text == '$' && text[1] == '(') /* ) */ + text += 2; + /* If the text was quoted, suppress any quote character that the + readline completion code would insert. */ + rl_completion_suppress_quote = 1; + start_len = text - orig_start; + filename_text = savestring (text); + if (matches) + free (matches); + + /* + * At this point we can entertain the idea of re-parsing + * `filename_text' into a (possibly incomplete) command name and + * arguments, and doing completion based on that. This is + * currently very rudimentary, but it is a small improvement. + */ + for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) + if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) + break; + if (value <= filename_text) + matches = rl_completion_matches (filename_text, command_word_completion_function); + else + { + value++; + start_len += value - filename_text; + if (whitespace (value[-1])) + matches = rl_completion_matches (value, rl_filename_completion_function); + else + matches = rl_completion_matches (value, command_word_completion_function); + } + + /* If there is more than one match, rl_completion_matches has already + put the lcd in matches[0]. Skip over it. */ + cmd_index = matches && matches[0] && matches[1]; + } + + if (!matches || !matches[cmd_index]) + { + rl_filename_quoting_desired = 0; /* disable quoting */ + return ((char *)NULL); + } + else + { + value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); + + if (start_len == 1) + value[0] = *orig_start; + else + strncpy (value, orig_start, start_len); + + strcpy (value + start_len, matches[cmd_index]); + + cmd_index++; + return (value); + } +} + +/* Okay, now we write the entry_function for variable completion. */ +static char * +variable_completion_function (text, state) + const char *text; + int state; +{ + static char **varlist = (char **)NULL; + static int varlist_index; + static char *varname = (char *)NULL; + static int namelen; + static int first_char, first_char_loc; + + if (!state) + { + if (varname) + free (varname); + + first_char_loc = 0; + first_char = text[0]; + + if (first_char == '$') + first_char_loc++; + + if (text[first_char_loc] == '{') + first_char_loc++; + + varname = savestring (text + first_char_loc); + + namelen = strlen (varname); + if (varlist) + strvec_dispose (varlist); + + varlist = all_variables_matching_prefix (varname); + varlist_index = 0; + } + + if (!varlist || !varlist[varlist_index]) + { + return ((char *)NULL); + } + else + { + char *value; + + value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); + + if (first_char_loc) + { + value[0] = first_char; + if (first_char_loc == 2) + value[1] = '{'; + } + + strcpy (value + first_char_loc, varlist[varlist_index]); + if (first_char_loc == 2) + strcat (value, "}"); + + varlist_index++; + return (value); + } +} + +/* How about a completion function for hostnames? */ +static char * +hostname_completion_function (text, state) + const char *text; + int state; +{ + static char **list = (char **)NULL; + static int list_index = 0; + static int first_char, first_char_loc; + + /* If we don't have any state, make some. */ + if (state == 0) + { + FREE (list); + + list = (char **)NULL; + + first_char_loc = 0; + first_char = *text; + + if (first_char == '@') + first_char_loc++; + + list = hostnames_matching ((char *)text+first_char_loc); + list_index = 0; + } + + if (list && list[list_index]) + { + char *t; + + t = (char *)xmalloc (2 + strlen (list[list_index])); + *t = first_char; + strcpy (t + first_char_loc, list[list_index]); + list_index++; + return (t); + } + + return ((char *)NULL); +} + +/* + * A completion function for service names from /etc/services (or wherever). + */ +char * +bash_servicename_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) + return ((char *)NULL); +#else + static char *sname = (char *)NULL; + static struct servent *srvent; + static int snamelen, firstc; + char *value; + char **alist, *aentry; + int afound; + + if (state == 0) + { + FREE (sname); + firstc = *text; + + sname = savestring (text); + snamelen = strlen (sname); + setservent (0); + } + + while (srvent = getservent ()) + { + afound = 0; + if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) + break; + /* Not primary, check aliases */ + for (alist = srvent->s_aliases; aentry = *alist; alist++) + { + if (STREQN (sname, aentry, snamelen)) + { + afound = 1; + break; + } + } + + if (afound) + break; + } + + if (srvent == 0) + { + endservent (); + return ((char *)NULL); + } + + value = afound ? savestring (aentry) : savestring (srvent->s_name); + return value; +#endif +} + +/* + * A completion function for group names from /etc/group (or wherever). + */ +char * +bash_groupname_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) + return ((char *)NULL); +#else + static char *gname = (char *)NULL; + static struct group *grent; + static int gnamelen; + char *value; + + if (state == 0) + { + FREE (gname); + gname = savestring (text); + gnamelen = strlen (gname); + + setgrent (); + } + + while (grent = getgrent ()) + { + if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) + break; + } + + if (grent == 0) + { + endgrent (); + return ((char *)NULL); + } + + value = savestring (grent->gr_name); + return (value); +#endif +} + +/* Functions to perform history and alias expansions on the current line. */ + +#if defined (BANG_HISTORY) +/* Perform history expansion on the current line. If no history expansion + is done, pre_process_line() returns what it was passed, so we need to + allocate a new line here. */ +static char * +history_expand_line_internal (line) + char *line; +{ + char *new_line; + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; + new_line = pre_process_line (line, 0, 0); + hist_verify = old_verify; + + return (new_line == line) ? savestring (line) : new_line; +} +#endif + +/* There was an error in expansion. Let the preprocessor print + the error here. */ +static void +cleanup_expansion_error () +{ + char *to_free; +#if defined (BANG_HISTORY) + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; +#endif + + fprintf (rl_outstream, "\r\n"); + to_free = pre_process_line (rl_line_buffer, 1, 0); +#if defined (BANG_HISTORY) + hist_verify = old_verify; +#endif + if (to_free != rl_line_buffer) + free (to_free); + putc ('\r', rl_outstream); + rl_forced_update_display (); +} + +/* If NEW_LINE differs from what is in the readline line buffer, add an + undo record to get from the readline line buffer contents to the new + line and make NEW_LINE the current readline line. */ +static void +maybe_make_readline_line (new_line) + char *new_line; +{ + if (strcmp (new_line, rl_line_buffer) != 0) + { + rl_point = rl_end; + + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + rl_delete_text (0, rl_point); + rl_point = rl_end = rl_mark = 0; + rl_insert_text (new_line); + rl_add_undo (UNDO_END, 0, 0, 0); + } +} + +/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ +static void +set_up_new_line (new_line) + char *new_line; +{ + int old_point, at_end; + + old_point = rl_point; + at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } +} + +#if defined (ALIAS) +/* Expand aliases in the current readline line. */ +static int +alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = alias_expand (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} +#endif + +#if defined (BANG_HISTORY) +/* History expand the line. */ +static int +history_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* Expand history substitutions in the current line and then insert a + space (hopefully close to where we were before). */ +static int +tcsh_magic_space (count, ignore) + int count, ignore; +{ + int dist_from_end, old_point; + + old_point = rl_point; + dist_from_end = rl_end - rl_point; + if (history_expand_line (count, ignore) == 0) + { + /* Try a simple heuristic from Stephen Gildea <gildea@intouchsys.com>. + This works if all expansions were before rl_point or if no expansions + were performed. */ + rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; + rl_insert (1, ' '); + return (0); + } + else + return (1); +} +#endif + +/* History and alias expand the line. */ +static int +history_and_alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* History and alias expand the line, then perform the shell word + expansions by calling expand_string. This can't use set_up_new_line() + because we want the variable expansions as a separate undo'able + set of operations. */ +static int +shell_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + WORD_LIST *expanded_string; + + new_line = history_expand_line_internal (rl_line_buffer); + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* If there is variable expansion to perform, do that as a separate + operation to be undone. */ + new_line = savestring (rl_line_buffer); + expanded_string = expand_string (new_line, 0); + FREE (new_line); + if (expanded_string == 0) + { + new_line = (char *)xmalloc (1); + new_line[0] = '\0'; + } + else + { + new_line = string_list (expanded_string); + dispose_words (expanded_string); + } + + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } + return 0; + } + else + { + cleanup_expansion_error (); + return 1; + } +} + +/* If FIGNORE is set, then don't match files with the given suffixes when + completing filenames. If only one of the possibilities has an acceptable + suffix, delete the others, else just return and let the completer + signal an error. It is called by the completer when real + completions are done on filenames by the completer's internal + function, not for completion lists (M-?) and not on "other" + completion types, such as hostnames or commands. */ + +static struct ignorevar fignore = +{ + "FIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *) 0, +}; + +static void +_ignore_completion_names (names, name_func) + char **names; + sh_ignore_func_t *name_func; +{ + char **newnames; + int idx, nidx; + char **oldnames; + int oidx; + + /* If there is only one completion, see if it is acceptable. If it is + not, free it up. In any case, short-circuit and return. This is a + special case because names[0] is not the prefix of the list of names + if there is only one completion; it is the completion itself. */ + if (names[1] == (char *)0) + { + if (force_fignore) + if ((*name_func) (names[0]) == 0) + { + free (names[0]); + names[0] = (char *)NULL; + } + + return; + } + + /* Allocate space for array to hold list of pointers to matching + filenames. The pointers are copied back to NAMES when done. */ + for (nidx = 1; names[nidx]; nidx++) + ; + newnames = strvec_create (nidx + 1); + + if (force_fignore == 0) + { + oldnames = strvec_create (nidx - 1); + oidx = 0; + } + + newnames[0] = names[0]; + for (idx = nidx = 1; names[idx]; idx++) + { + if ((*name_func) (names[idx])) + newnames[nidx++] = names[idx]; + else if (force_fignore == 0) + oldnames[oidx++] = names[idx]; + else + free (names[idx]); + } + + newnames[nidx] = (char *)NULL; + + /* If none are acceptable then let the completer handle it. */ + if (nidx == 1) + { + if (force_fignore) + { + free (names[0]); + names[0] = (char *)NULL; + } + else + free (oldnames); + + free (newnames); + return; + } + + if (force_fignore == 0) + { + while (oidx) + free (oldnames[--oidx]); + free (oldnames); + } + + /* If only one is acceptable, copy it to names[0] and return. */ + if (nidx == 2) + { + free (names[0]); + names[0] = newnames[1]; + names[1] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names back to NAMES, set the new array end, + and return. */ + for (nidx = 1; newnames[nidx]; nidx++) + names[nidx] = newnames[nidx]; + names[nidx] = (char *)NULL; + free (newnames); +} + +static int +name_is_acceptable (name) + const char *name; +{ + struct ign *p; + int nlen; + + for (nlen = strlen (name), p = fignore.ignores; p->val; p++) + { + if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) + return (0); + } + + return (1); +} + +#if 0 +static int +ignore_dot_names (name) + char *name; +{ + return (name[0] != '.'); +} +#endif + +static int +filename_completion_ignore (names) + char **names; +{ +#if 0 + if (glob_dot_filenames == 0) + _ignore_completion_names (names, ignore_dot_names); +#endif + + setup_ignore_patterns (&fignore); + + if (fignore.num_ignores == 0) + return 0; + + _ignore_completion_names (names, name_is_acceptable); + + return 0; +} + +/* Return 1 if NAME is a directory. */ +static int +test_for_directory (name) + const char *name; +{ + struct stat finfo; + char *fn; + + fn = bash_tilde_expand (name, 0); + if (stat (fn, &finfo) != 0) + { + free (fn); + return 0; + } + free (fn); + return (S_ISDIR (finfo.st_mode)); +} + +/* Remove files from NAMES, leaving directories. */ +static int +bash_ignore_filenames (names) + char **names; +{ + _ignore_completion_names (names, test_for_directory); + return 0; +} + +static int +return_zero (name) + const char *name; +{ + return 0; +} + +static int +bash_ignore_everything (names) + char **names; +{ + _ignore_completion_names (names, return_zero); + return 0; +} + +/* Handle symbolic link references and other directory name + expansions while hacking completion. */ +static int +bash_directory_completion_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int return_value, should_expand_dirname; + WORD_LIST *wl; + + return_value = should_expand_dirname = 0; + local_dirname = *dirname; + +#if 0 + should_expand_dirname = xstrchr (local_dirname, '$') || xstrchr (local_dirname, '`'); +#else + if (xstrchr (local_dirname, '$')) + should_expand_dirname = 1; + else + { + t = xstrchr (local_dirname, '`'); + if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) + should_expand_dirname = 1; + } +#endif + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0); /* does the right thing */ + if (wl) + { + *dirname = string_list (wl); + /* Tell the completer to replace the directory name only if we + actually expanded something. */ + return_value = STREQ (local_dirname, *dirname) == 0; + free (local_dirname); + free (new_dirname); + dispose_words (wl); + local_dirname = *dirname; + } + else + { + free (new_dirname); + free (local_dirname); + *dirname = (char *)xmalloc (1); + **dirname = '\0'; + return 1; + } + } + + if (!no_symbolic_links && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return 1; + } + len1 = strlen (temp1); + if (temp1[len1 - 1] == '/') + { + len2 = strlen (temp2); + temp2 = (char *)xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } + free (local_dirname); + *dirname = temp2; + free (temp1); + } + return (return_value); +} + +static char **history_completion_array = (char **)NULL; +static int harry_size; +static int harry_len; + +static void +build_history_completion_array () +{ + register int i, j; + HIST_ENTRY **hlist; + char **tokens; + + /* First, clear out the current dynamic history completion list. */ + if (harry_size) + { + strvec_dispose (history_completion_array); + history_completion_array = (char **)NULL; + harry_size = 0; + harry_len = 0; + } + + /* Next, grovel each line of history, making each shell-sized token + a separate entry in the history_completion_array. */ + hlist = history_list (); + + if (hlist) + { + for (i = 0; hlist[i]; i++) + { + /* Separate each token, and place into an array. */ + tokens = history_tokenize (hlist[i]->line); + + for (j = 0; tokens && tokens[j]; j++) + { + if (harry_len + 2 > harry_size) + history_completion_array = strvec_resize (history_completion_array, harry_size += 10); + + history_completion_array[harry_len++] = tokens[j]; + history_completion_array[harry_len] = (char *)NULL; + } + free (tokens); + } + + /* Sort the complete list of tokens. */ + qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); + } +} + +static char * +history_completion_generator (hint_text, state) + const char *hint_text; + int state; +{ + static int local_index, len; + static const char *text; + + /* If this is the first call to the generator, then initialize the + list of strings to complete over. */ + if (state == 0) + { + local_index = 0; + build_history_completion_array (); + text = hint_text; + len = strlen (text); + } + + while (history_completion_array && history_completion_array[local_index]) + { + if (strncmp (text, history_completion_array[local_index++], len) == 0) + return (savestring (history_completion_array[local_index - 1])); + } + return ((char *)NULL); +} + +static int +dynamic_complete_history (count, key) + int count, key; +{ + int r; + + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + rl_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + + /* XXX - use rl_completion_mode here? */ + if (rl_last_func == dynamic_complete_history) + r = rl_complete_internal ('?'); + else + r = rl_complete_internal (TAB); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + return r; +} + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int +bash_complete_username (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal (rl_completion_mode (bash_complete_username)); +} + +static int +bash_possible_username_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal ('?'); +} + +static int +bash_complete_username_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, rl_username_completion_function); +} + +static int +bash_complete_filename (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal (rl_completion_mode (bash_complete_filename)); +} + +static int +bash_possible_filename_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal ('?'); +} + +static int +bash_complete_filename_internal (what_to_do) + int what_to_do; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_icppfunc_t *orig_dir_func; + /*const*/ char *orig_rl_completer_word_break_characters; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_dir_func = rl_directory_completion_hook; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; + rl_completion_entry_function = rl_filename_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_directory_completion_hook = (rl_icppfunc_t *)NULL; + rl_completer_word_break_characters = " \t\n\"\'"; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_directory_completion_hook = orig_dir_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + + return r; +} + +static int +bash_complete_hostname (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal (rl_completion_mode (bash_complete_hostname)); +} + +static int +bash_possible_hostname_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal ('?'); +} + +static int +bash_complete_variable (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal (rl_completion_mode (bash_complete_variable)); +} + +static int +bash_possible_variable_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal ('?'); +} + +static int +bash_complete_command (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal (rl_completion_mode (bash_complete_command)); +} + +static int +bash_possible_command_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal ('?'); +} + +static int +bash_complete_hostname_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, hostname_completion_function); +} + +static int +bash_complete_variable_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, variable_completion_function); +} + +static int +bash_complete_command_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, command_word_completion_function); +} + +static char *globtext; +static char *globorig; + +static char * +glob_complete_word (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static int ind; + int glen; + char *ret; + + if (state == 0) + { + rl_filename_completion_desired = 1; + FREE (matches); + if (globorig != globtext) + FREE (globorig); + FREE (globtext); + + if (rl_explicit_arg) + { + globorig = savestring (text); + glen = strlen (text); + globtext = (char *)xmalloc (glen + 2); + strcpy (globtext, text); + globtext[glen] = '*'; + globtext[glen+1] = '\0'; + } + else + globtext = globorig = savestring (text); + + matches = shell_glob_filename (globtext); + if (GLOB_FAILED (matches)) + matches = (char **)NULL; + ind = 0; + } + + ret = matches ? matches[ind] : (char *)NULL; + ind++; + return ret; +} + +static int +bash_glob_completion_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, glob_complete_word); +} + +/* A special quoting function so we don't end up quoting globbing characters + in the word if there are no matches or multiple matches. */ +static char * +bash_glob_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) + return (savestring (s)); + else + return (bash_quote_filename (s, rtype, qcp)); +} + +static int +bash_glob_complete_word (count, key) + int count, key; +{ + int r; + rl_quote_func_t *orig_quoting_function; + + rl_explicit_arg = 1; /* force `*' append */ + orig_quoting_function = rl_filename_quoting_function; + rl_filename_quoting_function = bash_glob_quote_filename; + + r = bash_glob_completion_internal (rl_completion_mode (bash_glob_complete_word)); + + rl_filename_quoting_function = orig_quoting_function; + return r; +} + +static int +bash_glob_expand_word (count, key) + int count, key; +{ + return bash_glob_completion_internal ('*'); +} + +static int +bash_glob_list_expansions (count, key) + int count, key; +{ + return bash_glob_completion_internal ('?'); +} + +static int +bash_specific_completion (what_to_do, generator) + int what_to_do; + rl_compentry_func_t *generator; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + rl_completion_entry_function = generator; + rl_attempted_completion_function = NULL; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + + return r; +} + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +/* Filename quoting for completion. */ +/* A function to strip unquoted quote characters (single quotes, double + quotes, and backslashes). It allows single quotes to appear + within double quotes, and vice versa. It should be smarter. */ +static char * +bash_dequote_filename (text, quote_char) + char *text; + int quote_char; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = (char *)xmalloc (l + 1); + for (quoted = quote_char, p = text, r = ret; p && *p; p++) + { + /* Allow backslash-quoted characters to pass through unscathed. */ + if (*p == '\\') + { + *r++ = *++p; + if (*p == '\0') + break; + continue; + } + /* Close quote. */ + if (quoted && *p == quoted) + { + quoted = 0; + continue; + } + /* Open quote. */ + if (quoted == 0 && (*p == '\'' || *p == '"')) + { + quoted = *p; + continue; + } + *r++ = *p; + } + *r = '\0'; + return ret; +} + +/* Quote characters that the readline completion code would treat as + word break characters with backslashes. Pass backslash-quoted + characters through without examination. */ +static char * +quote_word_break_chars (text) + char *text; +{ + char *ret, *r, *s; + int l; + + l = strlen (text); + ret = (char *)xmalloc ((2 * l) + 1); + for (s = text, r = ret; *s; s++) + { + /* Pass backslash-quoted characters through, including the backslash. */ + if (*s == '\\') + { + *r++ = '\\'; + *r++ = *++s; + if (*s == '\0') + break; + continue; + } + /* OK, we have an unquoted character. Check its presence in + rl_completer_word_break_characters. */ + if (xstrchr (rl_completer_word_break_characters, *s)) + *r++ = '\\'; + *r++ = *s; + } + *r = '\0'; + return ret; +} + +/* Quote a filename using double quotes, single quotes, or backslashes + depending on the value of completion_quoting_style. If we're + completing using backslashes, we need to quote some additional + characters (those that readline treats as word breaks), so we call + quote_word_break_chars on the result. This returns newly-allocated + memory. */ +static char * +bash_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + char *rtext, *mtext, *ret; + int rlen, cs; + + rtext = (char *)NULL; + + /* If RTYPE == MULT_MATCH, it means that there is + more than one match. In this case, we do not add + the closing quote or attempt to perform tilde + expansion. If RTYPE == SINGLE_MATCH, we try + to perform tilde expansion, because single and double + quotes inhibit tilde expansion by the shell. */ + + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH) + mtext = bash_tilde_expand (s, 0); + + cs = completion_quoting_style; + /* Might need to modify the default completion style based on *qcp, + since it's set to any user-provided opening quote. We also change + to single-quoting if there is no user-provided opening quote and + the word being completed contains newlines, since those are not + quoted correctly using backslashes (a backslash-newline pair is + special to the shell parser). */ + if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && xstrchr (mtext, '\n')) + cs = COMPLETE_SQUOTE; + else if (*qcp == '"') + cs = COMPLETE_DQUOTE; + else if (*qcp == '\'') + cs = COMPLETE_SQUOTE; +#if defined (BANG_HISTORY) + else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && xstrchr (mtext, '!')) + cs = COMPLETE_BSQUOTE; + + if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && xstrchr (mtext, '!')) + { + cs = COMPLETE_BSQUOTE; + *qcp = '\0'; + } +#endif + + switch (cs) + { + case COMPLETE_DQUOTE: + rtext = sh_double_quote (mtext); + break; + case COMPLETE_SQUOTE: + rtext = sh_single_quote (mtext); + break; + case COMPLETE_BSQUOTE: + rtext = sh_backslash_quote (mtext); + break; + } + + if (mtext != s) + free (mtext); + + /* We may need to quote additional characters: those that readline treats + as word breaks that are not quoted by backslash_quote. */ + if (rtext && cs == COMPLETE_BSQUOTE) + { + mtext = quote_word_break_chars (rtext); + free (rtext); + rtext = mtext; + } + + /* Leave the opening quote intact. The readline completion code takes + care of avoiding doubled opening quotes. */ + rlen = strlen (rtext); + ret = (char *)xmalloc (rlen + 1); + strcpy (ret, rtext); + + /* If there are multiple matches, cut off the closing quote. */ + if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) + ret[rlen - 1] = '\0'; + free (rtext); + return ret; +} + +/* Support for binding readline key sequences to Unix commands. */ +static Keymap cmd_xmap; + +static int +bash_execute_unix_command (count, key) + int count; /* ignored */ + int key; +{ + Keymap ckmap; /* current keymap */ + Keymap xkmap; /* unix command executing keymap */ + register int i; + char *cmd; + sh_parser_state_t ps; + + /* First, we need to find the right command to execute. This is tricky, + because we might have already indirected into another keymap. */ + ckmap = rl_get_keymap (); + if (ckmap != rl_executing_keymap) + { + /* bogus. we have to search. only handle one level of indirection. */ + for (i = 0; i < KEYMAP_SIZE; i++) + { + if (ckmap[i].type == ISKMAP && (Keymap)ckmap[i].function == rl_executing_keymap) + break; + } + if (i < KEYMAP_SIZE) + xkmap = (Keymap)cmd_xmap[i].function; + else + { + rl_crlf (); + internal_error (_("bash_execute_unix_command: cannot find keymap for command")); + rl_forced_update_display (); + return 1; + } + } + else + xkmap = cmd_xmap; + + cmd = (char *)xkmap[key].function; + + if (cmd == 0) + { + rl_ding (); + return 1; + } + + rl_crlf (); /* move to a new line */ + + save_parser_state (&ps); + + cmd = savestring (cmd); + parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST); + + restore_parser_state (&ps); + + /* and restore the readline buffer and display after command execution. */ + rl_forced_update_display (); + return 0; +} + +static void +init_unix_command_map () +{ + cmd_xmap = rl_make_bare_keymap (); +} + +static int +isolate_sequence (string, ind, need_dquote, startp) + char *string; + int ind, need_dquote, *startp; +{ + register int i; + int c, passc, delim; + + for (i = ind; string[i] && whitespace (string[i]); i++) + ; + /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ + if (need_dquote && string[i] != '"') + { + builtin_error (_("%s: first non-whitespace character is not `\"'"), string); + return -1; + } + + /* We can have delimited strings even if NEED_DQUOTE == 0, like the command + string to bind the key sequence to. */ + delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; + + if (startp) + *startp = delim ? ++i : i; + + for (passc = 0; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + if (c == '\\') + { + passc++; + continue; + } + if (c == delim) + break; + } + + if (delim && string[i] != delim) + { + builtin_error (_("no closing `%c' in %s"), delim, string); + return -1; + } + + return i; +} + +int +bind_keyseq_to_unix_command (line) + char *line; +{ + Keymap kmap; + char *kseq, *value; + int i, kstart; + + if (cmd_xmap == 0) + init_unix_command_map (); + + kmap = rl_get_keymap (); + + /* We duplicate some of the work done by rl_parse_and_bind here, but + this code only has to handle `"keyseq": ["]command["]' and can + generate an error for anything else. */ + i = isolate_sequence (line, 0, 1, &kstart); + if (i < 0) + return -1; + + /* Create the key sequence string to pass to rl_generic_bind */ + kseq = substring (line, kstart, i); + + for ( ; line[i] && line[i] != ':'; i++) + ; + if (line[i] != ':') + { + builtin_error (_("%s: missing colon separator"), line); + return -1; + } + + i = isolate_sequence (line, i + 1, 0, &kstart); + if (i < 0) + return -1; + + /* Create the value string containing the command to execute. */ + value = substring (line, kstart, i); + + /* Save the command to execute and the key sequence in the CMD_XMAP */ + rl_generic_bind (ISMACR, kseq, value, cmd_xmap); + + /* and bind the key sequence in the current keymap to a function that + understands how to execute from CMD_XMAP */ + rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap); + + return 0; +} + +/* Used by the programmable completion code. Complete TEXT as a filename, + but return only directories as matches. Dequotes the filename before + attempting to find matches. */ +char ** +bash_directory_completion_matches (text) + const char *text; +{ + char **m1; + char *dfn; + int qc; + +#if 0 + qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; +#else + qc = rl_dispatching ? rl_completion_quote_character : 0; +#endif + dfn = bash_dequote_filename ((char *)text, qc); + m1 = rl_completion_matches (dfn, rl_filename_completion_function); + free (dfn); + + if (m1 == 0 || m1[0] == 0) + return m1; + /* We don't bother recomputing the lcd of the matches, because it will just + get thrown away by the programmable completion code and recomputed + later. */ + (void)bash_ignore_filenames (m1); + return m1; +} + +char * +bash_dequote_text (text) + const char *text; +{ + char *dtxt; + int qc; + + qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; + dtxt = bash_dequote_filename ((char *)text, qc); + return (dtxt); +} +#endif /* READLINE */ diff --git a/builtins/cd.def b/builtins/cd.def index 68449e9c..10cbe988 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -122,13 +122,14 @@ bindpwd (no_symlinks) /* Call get_working_directory to reset the value of the_current_working_directory () */ static char * -resetpwd () +resetpwd (caller) + char *caller; { char *tdir; FREE (the_current_working_directory); the_current_working_directory = (char *)NULL; - tdir = get_working_directory ("cd"); + tdir = get_working_directory (caller); return (tdir); } @@ -337,6 +338,12 @@ pwd_builtin (list) directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd) : get_working_directory ("pwd"); + + /* Try again using getcwd() if canonicalization fails (for instance, if + the file system has changed state underneath bash). */ + if (tcwd && directory == 0) + directory = resetpwd ("pwd"); + #undef tcwd if (directory) @@ -416,7 +423,7 @@ change_to_directory (newdir, nolinks) /* If canonicalization failed, but the chdir succeeded, reset the shell's idea of the_current_working_directory. */ if (canon_failed) - resetpwd (); + resetpwd ("cd"); else { FREE (the_current_working_directory); @@ -439,7 +446,7 @@ change_to_directory (newdir, nolinks) verbatim. If we succeed, reinitialize the_current_working_directory. */ if (chdir (newdir) == 0) { - tdir = resetpwd (); + tdir = resetpwd ("cd"); FREE (tdir); return (1); diff --git a/config-bot.h b/config-bot.h index 06e107c6..18946872 100644 --- a/config-bot.h +++ b/config-bot.h @@ -56,7 +56,7 @@ #endif /* backwards compatibility between different autoconf versions */ -#if defined (HAVE_DECL_SYS_SIGLIST) && !defined (SYS_SIGLIST_DECLARED) +#if HAVE_DECL_SYS_SIGLIST && !defined (SYS_SIGLIST_DECLARED) # define SYS_SIGLIST_DECLARED #endif diff --git a/config-bot.h~ b/config-bot.h~ new file mode 100644 index 00000000..06e107c6 --- /dev/null +++ b/config-bot.h~ @@ -0,0 +1,181 @@ +/* config-bot.h */ +/* modify settings or make new ones based on what autoconf tells us. */ + +/* Copyright (C) 1989-2002 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/*********************************************************/ +/* Modify or set defines based on the configure results. */ +/*********************************************************/ + +#if !defined (HAVE_VPRINTF) && defined (HAVE_DOPRNT) +# define USE_VFPRINTF_EMULATION +# define HAVE_VPRINTF +#endif + +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_GETRLIMIT) +# define HAVE_RESOURCE +#endif + +#if !defined (GETPGRP_VOID) +# define HAVE_BSD_PGRP +#endif + +/* Try this without testing __STDC__ for the time being. */ +#if defined (HAVE_STDARG_H) +# define PREFER_STDARG +# define USE_VARARGS +#else +# if defined (HAVE_VARARGS_H) +# define PREFER_VARARGS +# define USE_VARARGS +# endif +#endif + +#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && defined (HAVE_NETINET_IN_H) +# define HAVE_NETWORK +#endif + +#if defined (HAVE_REGEX_H) && defined (HAVE_REGCOMP) && defined (HAVE_REGEXEC) +# define HAVE_POSIX_REGEXP +#endif + +/* backwards compatibility between different autoconf versions */ +#if defined (HAVE_DECL_SYS_SIGLIST) && !defined (SYS_SIGLIST_DECLARED) +# define SYS_SIGLIST_DECLARED +#endif + +/***********************************************************************/ +/* Unset defines based on what configure reports as missing or broken. */ +/***********************************************************************/ + +/* Ultrix botches type-ahead when switching from canonical to + non-canonical mode, at least through version 4.3 */ +#if !defined (HAVE_TERMIOS_H) || !defined (HAVE_TCGETATTR) || defined (ultrix) +# define TERMIOS_MISSING +#endif + +/* If we have a getcwd(3), but it calls popen(), #undef HAVE_GETCWD so + the replacement in getcwd.c will be built. */ +#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) +# undef HAVE_GETCWD +#endif + +#if !defined (HAVE_DEV_FD) && defined (NAMED_PIPES_MISSING) +# undef PROCESS_SUBSTITUTION +#endif + +#if defined (JOB_CONTROL_MISSING) +# undef JOB_CONTROL +#endif + +#if defined (STRCOLL_BROKEN) +# undef HAVE_STRCOLL +#endif + +#if !defined (HAVE_POSIX_REGEXP) +# undef COND_REGEXP +#endif + +/* If the shell is called by this name, it will become restricted. */ +#if defined (RESTRICTED_SHELL) +# define RESTRICTED_SHELL_NAME "rbash" +#endif + +/***********************************************************/ +/* Make sure feature defines have necessary prerequisites. */ +/***********************************************************/ + +/* BANG_HISTORY requires HISTORY. */ +#if defined (BANG_HISTORY) && !defined (HISTORY) +# define HISTORY +#endif /* BANG_HISTORY && !HISTORY */ + +#if defined (READLINE) && !defined (HISTORY) +# define HISTORY +#endif + +#if defined (PROGRAMMABLE_COMPLETION) && !defined (READLINE) +# undef PROGRAMMABLE_COMPLETION +#endif + +#if !defined (V9_ECHO) +# undef DEFAULT_ECHO_TO_XPG +#endif + +#if !defined (PROMPT_STRING_DECODE) +# undef PPROMPT +# define PPROMPT "$ " +#endif + +/************************************************/ +/* check multibyte capability for I18N code */ +/************************************************/ + +/* For platforms which support the ISO C amendement 1 functionality we + support user defined character classes. */ +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ +#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) +# include <wchar.h> +# include <wctype.h> +# if defined (HAVE_MBSRTOWCS) && defined (HAVE_MBRTOWC) && defined (HAVE_MBRLEN) && defined (HAVE_WCWIDTH) + /* system is supposed to support XPG5 */ +# define HANDLE_MULTIBYTE 1 +# endif +#endif + +/* If we don't want multibyte chars even on a system that supports them, let + the configuring user turn multibyte support off. */ +#if defined (NO_MULTIBYTE_SUPPORT) +# undef HANDLE_MULTIBYTE +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) +# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) +# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) +# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) +# define mbstate_t int +#endif + +/* Make sure MB_LEN_MAX is at least 16 (some systems define + MB_LEN_MAX as 1) */ +#ifdef HANDLE_MULTIBYTE +# include <limits.h> +# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) +# undef MB_LEN_MAX +# endif +# if !defined (MB_LEN_MAX) +# define MB_LEN_MAX 16 +# endif +#endif + +/************************************************/ +/* end of multibyte capability checks for I18N */ +/************************************************/ + +/******************************************************************/ +/* Placeholder for builders to #undef any unwanted features from */ +/* config-top.h or created by configure (such as the default mail */ +/* file for mail checking). */ +/******************************************************************/ + +/* If you don't want bash to provide a default mail file to check. */ +/* #undef DEFAULT_MAIL_DIRECTORY */ diff --git a/config.h.in b/config.h.in index 0780d095..00520d52 100644 --- a/config.h.in +++ b/config.h.in @@ -1,6 +1,6 @@ /* config.h -- Configuration file for bash. */ -/* Copyright (C) 1987-2003 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -935,7 +935,7 @@ #undef HAVE_DCGETTEXT /* Define if your system has a working `malloc' function. */ -#define HAVE_MALLOC +#undef HAVE_MALLOC /* Define if you have the `mempcpy' function. */ #undef HAVE_MEMPCPY diff --git a/config.h.in~ b/config.h.in~ new file mode 100644 index 00000000..b23573ae --- /dev/null +++ b/config.h.in~ @@ -0,0 +1,974 @@ +/* config.h -- Configuration file for bash. */ + +/* Copyright (C) 1987-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +/* Configuration feature settings controllable by autoconf. */ + +/* Define JOB_CONTROL if your operating system supports + BSD-like job control. */ +#undef JOB_CONTROL + +/* Define ALIAS if you want the alias features. */ +#undef ALIAS + +/* Define PUSHD_AND_POPD if you want those commands to be compiled in. + (Also the `dirs' commands.) */ +#undef PUSHD_AND_POPD + +/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh: + foo{a,b} -> fooa foob. Even if this is compiled in (the default) you + can turn it off at shell startup with `-nobraceexpansion', or during + shell execution with `set +o braceexpand'. */ +#undef BRACE_EXPANSION + +/* Define READLINE to get the nifty/glitzy editing features. + This is on by default. You can turn it off interactively + with the -nolineediting flag. */ +#undef READLINE + +/* Define BANG_HISTORY if you want to have Csh style "!" history expansion. + This is unrelated to READLINE. */ +#undef BANG_HISTORY + +/* Define HISTORY if you want to have access to previously typed commands. + + If both HISTORY and READLINE are defined, you can get at the commands + with line editing commands, and you can directly manipulate the history + from the command line. + + If only HISTORY is defined, the `fc' and `history' builtins are + available. */ +#undef HISTORY + +/* Define this if you want completion that puts all alternatives into + a brace expansion shell expression. */ +#if defined (BRACE_EXPANSION) && defined (READLINE) +# define BRACE_COMPLETION +#endif /* BRACE_EXPANSION */ + +/* Define DEFAULT_ECHO_TO_XPG if you want the echo builtin to interpret + the backslash-escape characters by default, like the XPG Single Unix + Specification V2 for echo. + This requires that V9_ECHO be defined. */ +#undef DEFAULT_ECHO_TO_XPG + +/* Define HELP_BUILTIN if you want the `help' shell builtin and the long + documentation strings compiled into the shell. */ +#undef HELP_BUILTIN + +/* Define RESTRICTED_SHELL if you want the generated shell to have the + ability to be a restricted one. The shell thus generated can become + restricted by being run with the name "rbash", or by setting the -r + flag. */ +#undef RESTRICTED_SHELL + +/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the + shell builtin "foo", even if it has been disabled with "enable -n foo". */ +#undef DISABLED_BUILTINS + +/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process + substitution features "<(file)". */ +/* Right now, you cannot do this on machines without fully operational + FIFO support. This currently include NeXT and Alliant. */ +#undef PROCESS_SUBSTITUTION + +/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special + characters in PS1 and PS2 expanded. Variable expansion will still be + performed. */ +#undef PROMPT_STRING_DECODE + +/* Define SELECT_COMMAND if you want the Korn-shell style `select' command: + select word in word_list; do command_list; done */ +#undef SELECT_COMMAND + +/* Define COMMAND_TIMING of you want the ksh-style `time' reserved word and + the ability to time pipelines, functions, and builtins. */ +#undef COMMAND_TIMING + +/* Define ARRAY_VARS if you want ksh-style one-dimensional array variables. */ +#undef ARRAY_VARS + +/* Define DPAREN_ARITHMETIC if you want the ksh-style ((...)) arithmetic + evaluation command. */ +#undef DPAREN_ARITHMETIC + +/* Define EXTENDED_GLOB if you want the ksh-style [*+@?!](patlist) extended + pattern matching. */ +#undef EXTENDED_GLOB + +/* Define COND_COMMAND if you want the ksh-style [[...]] conditional + command. */ +#undef COND_COMMAND + +/* Define COND_REGEXP if you want extended regular expression matching and the + =~ binary operator in the [[...]] conditional command. */ +#define COND_REGEXP + +/* Define ARITH_FOR_COMMAND if you want the ksh93-style + for (( init; test; step )) do list; done + arithmetic for command. */ +#undef ARITH_FOR_COMMAND + +/* Define NETWORK_REDIRECTIONS if you want /dev/(tcp|udp)/host/port to open + socket connections when used in redirections */ +#undef NETWORK_REDIRECTIONS + +/* Define PROGRAMMABLE_COMPLETION for the programmable completion features + and the complete builtin. */ +#undef PROGRAMMABLE_COMPLETION + +/* Define NO_MULTIBYTE_SUPPORT to not compile in support for multibyte + characters, even if the OS supports them. */ +#undef NO_MULTIBYTE_SUPPORT + +/* Define DEBUGGER if you want to compile in some features used only by the + bash debugger. */ +#undef DEBUGGER + +/* Define MEMSCRAMBLE if you want the bash malloc and free to scramble + memory contents on malloc() and free(). */ +#undef MEMSCRAMBLE + +/* Define AFS if you are using Transarc's AFS. */ +#undef AFS + +#undef ENABLE_NLS + +/* End of configuration settings controllable by autoconf. */ +/* Other settable options appear in config-top.h. */ + +#include "config-top.h" + +/* Beginning of autoconf additions. */ + +/* Characteristics of the C compiler */ +#undef const + +#undef inline + +/* Define if cpp supports the ANSI-C stringizing `#' operator */ +#undef HAVE_STRINGIZE + +/* Define if the compiler supports `long double' variables. */ +#undef HAVE_LONG_DOUBLE + +#undef PROTOTYPES + +#undef __CHAR_UNSIGNED__ + +/* Define if the compiler supports `long long' variables. */ +#undef HAVE_LONG_LONG + +#undef HAVE_UNSIGNED_LONG_LONG + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a pointer to char. */ +#undef SIZEOF_CHAR_P + +/* The number of bytes in a double (hopefully 8). */ +#undef SIZEOF_DOUBLE + +/* The number of bytes in a `long long', if we have one. */ +#undef SIZEOF_LONG_LONG + +/* System paths */ + +#define DEFAULT_MAIL_DIRECTORY "/usr/spool/mail" + +/* Characteristics of the system's header files and libraries that affect + the compilation environment. */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to use GNU libc extensions */ +#undef _GNU_SOURCE + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Memory management functions. */ + +/* Define if using the bash version of malloc in lib/malloc/malloc.c */ +#undef USING_BASH_MALLOC + +#undef DISABLE_MALLOC_WRAPPERS + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + + +/* SYSTEM TYPES */ + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef off_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef mode_t + +/* Define to `int' if <signal.h> doesn't define. */ +#undef sigset_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef pid_t + +/* Define to `short' if <sys/types.h> doesn't define. */ +#undef bits16_t + +/* Define to `unsigned short' if <sys/types.h> doesn't define. */ +#undef u_bits16_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef bits32_t + +/* Define to `unsigned int' if <sys/types.h> doesn't define. */ +#undef u_bits32_t + +/* Define to `double' if <sys/types.h> doesn't define. */ +#undef bits64_t + +/* Define to `unsigned int' if <sys/types.h> doesn't define. */ +#undef u_int + +/* Define to `unsigned long' if <sys/types.h> doesn't define. */ +#undef u_long + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef ptrdiff_t + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef ssize_t + +/* Define to `long' if <stdint.h> doesn't define. */ +#undef intmax_t + +/* Define to `unsigned long' if <stdint.h> doesn't define. */ +#undef uintmax_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef clock_t + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef time_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define to `unsigned int' if <sys/socket.h> doesn't define. */ +#undef socklen_t + +/* Define if you have quad_t in <sys/types.h>. */ +#undef HAVE_QUAD_T + +#undef RLIMTYPE + +/* Define to the type of elements in the array set by `getgroups'. + Usually this is either `int' or `gid_t'. */ +#undef GETGROUPS_T + +/* Characteristics of the machine archictecture. */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if the machine architecture is big-endian. */ +#undef WORDS_BIGENDIAN + +/* Check for the presence of certain non-function symbols in the system + libraries. */ + +/* Define if `sys_siglist' is declared by <signal.h> or <unistd.h>. */ +#undef HAVE_DECL_SYS_SIGLIST +#undef SYS_SIGLIST_DECLARED + +/* Define if `_sys_siglist' is declared by <signal.h> or <unistd.h>. */ +#undef UNDER_SYS_SIGLIST_DECLARED + +#undef HAVE_SYS_SIGLIST + +#undef HAVE_UNDER_SYS_SIGLIST + +#undef HAVE_SYS_ERRLIST + +#undef HAVE_TZNAME + + +/* Characteristics of some of the system structures. */ + +#undef STRUCT_DIRENT_HAS_D_INO + +#undef STRUCT_DIRENT_HAS_D_FILENO + +#undef TIOCSTAT_IN_SYS_IOCTL + +#undef FIONREAD_IN_SYS_IOCTL + +#undef GWINSZ_IN_SYS_IOCTL + +#undef STRUCT_WINSIZE_IN_SYS_IOCTL + +#undef TM_IN_SYS_TIME + +#undef STRUCT_WINSIZE_IN_TERMIOS + +#undef SPEED_T_IN_SYS_TYPES + +#undef TERMIOS_LDISC + +#undef TERMIO_LDISC + +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +#undef HAVE_STRUCT_TM_TM_ZONE +#undef HAVE_TM_ZONE + +#undef HAVE_TIMEVAL + +#undef HAVE_STRUCT_TIMEZONE + +/* Characteristics of definitions in the system header files. */ + +#undef HAVE_GETPW_DECLS + +#undef HAVE_RESOURCE + +#undef HAVE_LIBC_FNM_EXTMATCH + + +#undef HAVE_DECL_CONFSTR + +#undef HAVE_DECL_PRINTF + +#undef HAVE_DECL_SBRK + +#undef HAVE_DECL_STRCPY + +#undef HAVE_DECL_STRSIGNAL + +#undef HAVE_DECL_STRTOLD + +#undef STRTOLD_BROKEN + +#undef HAVE_MBSTATE_T + +/* These are checked with BASH_CHECK_DECL */ + +#undef HAVE_DECL_STRTOIMAX +#undef HAVE_DECL_STRTOL +#undef HAVE_DECL_STRTOLL +#undef HAVE_DECL_STRTOUL +#undef HAVE_DECL_STRTOULL +#undef HAVE_DECL_STRTOUMAX + +/* Characteristics of system calls and C library functions. */ + +/* Define if the `getpgrp' function takes no argument. */ +#undef GETPGRP_VOID + +#undef NAMED_PIPES_MISSING + +#undef OPENDIR_NOT_ROBUST + +#undef PGRP_PIPE + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +#undef STAT_MACROS_BROKEN + +#undef ULIMIT_MAXFDS + +#undef CAN_REDEFINE_GETENV + +#undef HAVE_STD_PUTENV + +#undef HAVE_STD_UNSETENV + +#undef HAVE_PRINTF_A_FORMAT + +#undef CTYPE_NON_ASCII + +/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */ +#undef HAVE_LANGINFO_CODESET + +/* Characteristics of properties exported by the kernel. */ + +/* Define if the kernel can exec files beginning with #! */ +#undef HAVE_HASH_BANG_EXEC + +/* Define if you have the /dev/fd devices to map open files into the file system. */ +#undef HAVE_DEV_FD + +/* Defined to /dev/fd or /proc/self/fd (linux). */ +#undef DEV_FD_PREFIX + +/* Define if you have the /dev/stdin device. */ +#undef HAVE_DEV_STDIN + + +/* Type and behavior of signal handling functions. */ + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if return type of signal handlers is void */ +#undef VOID_SIGHANDLER + +#undef MUST_REINSTALL_SIGHANDLERS + +#undef HAVE_BSD_SIGNALS + +#undef HAVE_POSIX_SIGNALS + +#undef HAVE_USG_SIGHOLD + +#undef UNUSABLE_RT_SIGNALS + + +/* Presence of system and C library functions. */ + +/* Define if you have the asprintf function. */ +#undef HAVE_ASPRINTF + +/* Define if you have the bcopy function. */ +#undef HAVE_BCOPY + +/* Define if you have the bzero function. */ +#undef HAVE_BZERO + +/* Define if you have the confstr function. */ +#undef HAVE_CONFSTR + +/* Define if you have the dlclose function. */ +#undef HAVE_DLCLOSE + +/* Define if you have the dlopen function. */ +#undef HAVE_DLOPEN + +/* Define if you have the dlsym function. */ +#undef HAVE_DLSYM + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have the dup2 function. */ +#undef HAVE_DUP2 + +/* Define if you have the getaddrinfo function. */ +#undef HAVE_GETADDRINFO + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getdtablesize function. */ +#undef HAVE_GETDTABLESIZE + +/* Define if you have the getgroups function. */ +#undef HAVE_GETGROUPS + +/* Define if you have the gethostbyname function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the getpeername function. */ +#undef HAVE_GETPEERNAME + +/* Define if you have the getrlimit function. */ +#undef HAVE_GETRLIMIT + +/* Define if you have the getrusage function. */ +#undef HAVE_GETRUSAGE + +/* Define if you have the getservbyname function. */ +#undef HAVE_GETSERVBYNAME + +/* Define if you have the getservent function. */ +#undef HAVE_GETSERVENT + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the getwd function. */ +#undef HAVE_GETWD + +/* Define if you have the inet_aton function. */ +#undef HAVE_INET_ATON + +/* Define if you have the isascii function. */ +#undef HAVE_ISASCII + +/* Define if you have the isblank function. */ +#undef HAVE_ISBLANK + +/* Define if you have the isgraph function. */ +#undef HAVE_ISGRAPH + +/* Define if you have the isint function in libc */ +#undef HAVE_ISINF_IN_LIBC + +/* Define if you have the isprint function. */ +#undef HAVE_ISPRINT + +/* Define if you have the isspace function. */ +#undef HAVE_ISSPACE + +/* Define if you have the isxdigit function. */ +#undef HAVE_ISXDIGIT + +/* Define if you have the killpg function. */ +#undef HAVE_KILLPG + +/* Define if you have the lstat function. */ +#undef HAVE_LSTAT + +/* Define if you have the mbrlen function. */ +#undef HAVE_MBRLEN + +/* Define if you have the mbrtowc function. */ +#undef HAVE_MBRTOWC + +/* Define if you have the mbsrtowcs function. */ +#undef HAVE_MBSRTOWCS + +/* Define if you have the memmove function. */ +#undef HAVE_MEMMOVE + +/* Define if you have the memset function. */ +#undef HAVE_MEMSET + +/* Define if you have the mkfifo function. */ +#undef HAVE_MKFIFO + +/* Define if you have the pathconf function. */ +#undef HAVE_PATHCONF + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the readlink function. */ +#undef HAVE_READLINK + +/* Define if you have the regcomp function. */ +#undef HAVE_REGCOMP + +/* Define if you have the regexec function. */ +#undef HAVE_REGEXEC + +/* Define if you have the rename function. */ +#undef HAVE_RENAME + +/* Define if you have the sbrk function. */ +#undef HAVE_SBRK + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the setdtablesize function. */ +#undef HAVE_SETDTABLESIZE + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlinebuf function. */ +#undef HAVE_SETLINEBUF + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +/* Define if you have the setostype function. */ +#undef HAVE_SETOSTYPE + +/* Define if you have the setvbuf function. */ +#undef HAVE_SETVBUF + +/* Define if you have the siginterrupt function. */ +#undef HAVE_SIGINTERRUPT + +/* Define if you have the POSIX.1-style sigsetjmp function. */ +#undef HAVE_POSIX_SIGSETJMP + +/* Define if you have the snprintf function. */ +#undef HAVE_SNPRINTF + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strcoll function. */ +#undef HAVE_STRCOLL + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have the strpbrk function. */ +#undef HAVE_STRPBRK + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtod function. */ +#undef HAVE_STRTOD + +/* Define if you have the strtoimax function. */ +#undef HAVE_STRTOIMAX + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoll function. */ +#undef HAVE_STRTOLL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the strtoull function. */ +#undef HAVE_STRTOULL + +/* Define if you have the strtoumax function. */ +#undef HAVE_STRTOUMAX + +/* Define if you have the strsignal function or macro. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the sysconf function. */ +#undef HAVE_SYSCONF + +/* Define if you have the tcgetattr function. */ +#undef HAVE_TCGETATTR + +/* Define if you have the tcgetpgrp function. */ +#undef HAVE_TCGETPGRP + +/* Define if you have the times function. */ +#undef HAVE_TIMES + +/* Define if you have the ttyname function. */ +#undef HAVE_TTYNAME + +/* Define if you have the tzset function. */ +#undef HAVE_TZSET + +/* Define if you have the ulimit function. */ +#undef HAVE_ULIMIT + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the unsetenv function. */ +#undef HAVE_UNSETENV + +/* Define if you have the vasprintf function. */ +#undef HAVE_VASPRINTF + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + +/* Define if you have the waitpid function. */ +#undef HAVE_WAITPID + +/* Define if you have the wait3 function. */ +#undef HAVE_WAIT3 + +/* Define if you have the wcsdup function. */ +#undef HAVE_WCSDUP + +/* Define if you have the wctomb function. */ +#undef HAVE_WCTOMB + +/* Define if you have the wcwidth function. */ +#undef HAVE_WCWIDTH + +/* Presence of certain system include files. */ + +/* Define if you have the <arpa/inet.h> header file. */ +#undef HAVE_ARPA_INET_H + +/* Define if you have the <dirent.h> header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the <grp.h> header file. */ +#undef HAVE_GRP_H + +/* Define if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have the <langinfo.h> header file. */ +#undef HAVE_LANGINFO_H + +/* Define if you have the <libintl.h> header file. */ +#undef HAVE_LIBINTL_H + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <locale.h> header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the <ndir.h> header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the <netdh.h> header file. */ +#undef HAVE_NETDB_H + +/* Define if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the <regex.h> header file. */ +#undef HAVE_REGEX_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <stdarg.h> header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the <stddef.h> header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define if you have the <sys/dir.h> header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the <sys/ndir.h> header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the <sys/pte.h> header file. */ +#undef HAVE_SYS_PTE_H + +/* Define if you have the <sys/ptem.h> header file. */ +#undef HAVE_SYS_PTEM_H + +/* Define if you have the <sys/resource.h> header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the <sys/stream.h> header file. */ +#undef HAVE_SYS_STREAM_H + +/* Define if you have <sys/time.h> */ +#undef HAVE_SYS_TIME_H + +#undef TIME_WITH_SYS_TIME + +/* Define if you have <sys/times.h> */ +#undef HAVE_SYS_TIMES_H + +/* Define if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have the <termcap.h> header file. */ +#undef HAVE_TERMCAP_H + +/* Define if you have the <termio.h> header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the <termios.h> header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the <varargs.h> header file. */ +#undef HAVE_VARARGS_H + +/* Define if you have the <wchar.h> header file. */ +#undef HAVE_WCHAR_H + +/* Define if you have the <varargs.h> header file. */ +#undef HAVE_WCTYPE_H + +/* Presence of certain system libraries. */ + +#undef HAVE_LIBDL + +#undef HAVE_LIBSUN + +#undef HAVE_LIBSOCKET + + +/* Define if on MINIX. */ +#undef _MINIX + +/* Are we running SVR5 (UnixWare 7)? */ +#undef SVR5 + +/* Are we running SVR4.2? */ +#undef SVR4_2 + +/* Are we running some version of SVR4? */ +#undef SVR4 + +/* Define if job control is unusable or unsupported. */ +#undef JOB_CONTROL_MISSING + +/* Do we need to define _KERNEL to get the RLIMIT_* defines from + <sys/resource.h>? */ +#undef RLIMIT_NEEDS_KERNEL + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Do strcoll(3) and strcmp(3) give different results in the default locale? */ +#undef STRCOLL_BROKEN + +#undef DUP2_BROKEN + +#undef GETCWD_BROKEN + +/* Additional defines for configuring lib/intl, maintained by autoscan/autoheader */ + +/* Define if you have the <argz.h> header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the <errno.h> header file. */ +#undef HAVE_ERRNO_H + +/* Define if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the <stdio_ext.h> header file. */ +#undef HAVE_STDIO_EXT_H + +/* Define if you have the `dcgettext' function. */ +#undef HAVE_DCGETTEXT + +/* Define if your system has a working `malloc' function. */ +#undef HAVE_MALLOC + +/* Define if you have the `mempcpy' function. */ +#undef HAVE_MEMPCPY + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define if you have the `nl_langinfo' function. */ +#undef HAVE_NL_LANGINFO + +/* Define if you have the `stpcpy' function. */ +#undef HAVE_STPCPY + +/* Define if you have the `strcspn' function. */ +#undef HAVE_STRCSPN + +/* Define if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define if you have the `__argz_count' function. */ +#undef HAVE___ARGZ_COUNT + +/* Define if you have the `__argz_next' function. */ +#undef HAVE___ARGZ_NEXT + +/* Define if you have the `__argz_stringify' function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* End additions for lib/intl */ + +#include "config-bot.h" + +#endif /* _CONFIG_H_ */ @@ -808,6 +808,7 @@ exp0 () register intmax_t val = 0, v2; char *vincdec; int stok; + EXPR_CONTEXT ec; /* XXX - might need additional logic here to decide whether or not pre-increment or pre-decrement is legal at this point. */ @@ -853,17 +854,36 @@ exp0 () else if ((curtok == NUM) || (curtok == STR)) { val = tokval; - if (curtok == STR && (*tp == '+' || *tp == '-') && tp[1] == *tp && - (tp[2] == '\0' || (ISALNUM ((unsigned char)tp[2]) == 0))) + if (curtok == STR) { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + /* post-increment or post-decrement */ - v2 = val + ((*tp == '+') ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - expr_bind_variable (tokstr, vincdec); - free (vincdec); - tp += 2; - curtok = NUM; /* make sure x++=7 is flagged as an error */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + } readtok (); @@ -936,7 +956,7 @@ expr_streval (tok, e) static void readtok () { - register char *cp; + register char *cp, *xp; register unsigned char c, c1; register int e; @@ -995,6 +1015,7 @@ readtok () tokstr = (char *)NULL; /* keep it from being freed */ tp = savecp = cp; noeval = 1; + curtok = STR; readtok (); peektok = curtok; if (peektok == STR) /* free new tokstr before old one is restored */ @@ -1064,10 +1085,20 @@ readtok () c = LOR; else if ((c == '*') && (c1 == '*')) c = POWER; - else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) - c = PREDEC; - else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) - c = PREINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == STR) + c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c) + { + /* Quickly scan forward to see if this is followed by optional + whitespace and an identifier. */ + xp = cp; + while (xp && *xp && cr_whitespace (*xp)) + xp++; + if (legal_variable_starter ((unsigned char)*xp)) + c = (c == '-') ? PREDEC : PREINC; + else + cp--; /* not preinc or predec, so unget the character */ + } else if (c1 == EQ && member (c, "*/%+-&^|")) { assigntok = c; /* a OP= b */ diff --git a/expr.c.save1 b/expr.c.save1 new file mode 100644 index 00000000..147cf55f --- /dev/null +++ b/expr.c.save1 @@ -0,0 +1,1243 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* + All arithmetic is done as intmax_t integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "id++", "id--" [post-increment and post-decrement] + "++id", "--id" [pre-increment and pre-decrement] + "-", "+" [(unary operators)] + "!", "~" + "**" [(exponentiation)] + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "expr ? expr : expr" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] + + (Note that most of these operators have special meaning to bash, and an + entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@ins.CWRU.Edu +*/ + +#include "config.h" + +#include <stdio.h> +#include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "chartypes.h" +#include "bashintl.h" + +#include "shell.h" + +/* Because of the $((...)) construct, expressions may include newlines. + Here is a macro which accepts newlines, tabs and spaces as whitespace. */ +#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) + +/* Size be which the expression stack grows when neccessary. */ +#define EXPR_STACK_GROW_SIZE 10 + +/* Maximum amount of recursion allowed. This prevents a non-integer + variable such as "num=num+2" from infinitely adding to itself when + "let num=num+2" is given. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ +#define PREINC 14 /* ++var */ +#define PREDEC 15 /* --var */ +#define POSTINC 16 /* var++ */ +#define POSTDEC 17 /* var-- */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Bitwise OR. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' +#define COMMA ',' + +/* This should be the function corresponding to the operator with the + highest precedence. */ +#define EXP_HIGHEST expcomma + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static intmax_t tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +static void readtok __P((void)); /* lexical analyzer */ + +static intmax_t expr_streval __P((char *, int)); +static intmax_t strlong __P((char *)); +static void evalerror __P((char *)); + +static void pushexp __P((void)); +static void popexp __P((void)); +static void expr_unwind __P((void)); +static void expr_bind_variable __P((char *, char *)); + +static intmax_t subexpr __P((char *)); + +static intmax_t expcomma __P((void)); +static intmax_t expassign __P((void)); +static intmax_t expcond __P((void)); +static intmax_t explor __P((void)); +static intmax_t expland __P((void)); +static intmax_t expbor __P((void)); +static intmax_t expbxor __P((void)); +static intmax_t expband __P((void)); +static intmax_t exp5 __P((void)); +static intmax_t exp4 __P((void)); +static intmax_t expshift __P((void)); +static intmax_t exp3 __P((void)); +static intmax_t exp2 __P((void)); +static intmax_t exppower __P((void)); +static intmax_t exp1 __P((void)); +static intmax_t exp0 __P((void)); + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp, *lasttp; + intmax_t tokval; + char *tokstr; + int noeval; +} EXPR_CONTEXT; + +#ifdef INCLUDE_UNUSED +/* Not used yet. */ +typedef struct { + char *tokstr; + intmax_t tokval; +} LVALUE; +#endif + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +extern char *this_command_name; +extern int unbound_vars_is_error; + +#if defined (ARRAY_VARS) +extern char *bash_badsub_errmsg; +#endif + +#define SAVETOK(X) \ + do { \ + (X)->curtok = curtok; \ + (X)->lasttok = lasttok; \ + (X)->tp = tp; \ + (X)->lasttp = lasttp; \ + (X)->tokval = tokval; \ + (X)->tokstr = tokstr; \ + (X)->noeval = noeval; \ + } while (0) + +#define RESTORETOK(X) \ + do { \ + curtok = (X)->curtok; \ + lasttok = (X)->lasttok; \ + tp = (X)->tp; \ + lasttp = (X)->lasttp; \ + tokval = (X)->tokval; \ + tokstr = (X)->tokstr; \ + noeval = (X)->noeval; \ + } while (0) + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror (_("expression recursion level exceeded")); + + if (expr_depth >= expr_stack_size) + { + expr_stack_size += EXPR_STACK_GROW_SIZE; + expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); + } + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + context->expression = expression; + SAVETOK(context); + + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth == 0) + evalerror (_("recursion stack underflow")); + + context = expr_stack[--expr_depth]; + + expression = context->expression; + RESTORETOK (context); + + free (context); +} + +static void +expr_unwind () +{ + while (--expr_depth > 0) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + + free (expr_stack[expr_depth]); + } + free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ +} + +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + (void)bind_int_variable (lhs, rhs); + stupidly_hack_special_variables (lhs); +} + +/* Evaluate EXPR, and return the arithmetic result. If VALIDP is + non-null, a zero is stored into the location to which it points + if the expression is invalid, non-zero otherwise. If a non-zero + value is returned in *VALIDP, the return value of evalexp() may + be used. + + The `while' loop after the longjmp is caught relies on the above + implementation of pushexp and popexp leaving in expr_stack[0] the + values that the variables had when the program started. That is, + the first things saved are the initial values of the variables that + were assigned at program startup or by the compiler. Therefore, it is + safe to let the loop terminate when expr_depth == 0, without freeing up + any of the expr_depth[0] stuff. */ +intmax_t +evalexp (expr, validp) + char *expr; + int *validp; +{ + intmax_t val; + int c; + procenv_t oevalbuf; + + val = 0; + + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp (evalbuf); + + if (c) + { + FREE (tokstr); + FREE (expression); + tokstr = expression = (char *)NULL; + + expr_unwind (); + + if (validp) + *validp = 0; + return (0); + } + + val = subexpr (expr); + + if (validp) + *validp = 1; + + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + return (val); +} + +static intmax_t +subexpr (expr) + char *expr; +{ + intmax_t val; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + pushexp (); + curtok = lasttok = 0; + expression = savestring (expr); + tp = expression; + + tokstr = (char *)NULL; + tokval = 0; + + readtok (); + + val = EXP_HIGHEST (); + + if (curtok != 0) + evalerror (_("syntax error in expression")); + + FREE (tokstr); + FREE (expression); + + popexp (); + + return val; +} + +static intmax_t +expcomma () +{ + register intmax_t value; + + value = expassign (); + while (curtok == COMMA) + { + readtok (); + value = expassign (); + } + + return value; +} + +static intmax_t +expassign () +{ + register intmax_t value; + char *lhs, *rhs; + + value = expcond (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special, op; + intmax_t lvalue; + + special = curtok == OP_ASSIGN; + + if (lasttok != STR) + evalerror (_("attempted assignment to non-variable")); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + lhs = savestring (tokstr); + readtok (); + value = expassign (); + + if (special) + { + switch (op) + { + case MUL: + lvalue *= value; + break; + case DIV: + if (value == 0) + evalerror (_("division by 0")); + lvalue /= value; + break; + case MOD: + if (value == 0) + evalerror (_("division by 0")); + lvalue %= value; + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + case BXOR: + lvalue ^= value; + break; + default: + free (lhs); + evalerror (_("bug: bad expassign token")); + break; + } + value = lvalue; + } + + rhs = itos (value); + if (noeval == 0) + expr_bind_variable (lhs, rhs); + free (rhs); + free (lhs); + FREE (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + return (value); +} + +/* Conditional expression (expr?expr:expr) */ +static intmax_t +expcond () +{ + intmax_t cval, val1, val2, rval; + int set_noeval; + + set_noeval = 0; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + if (cval == 0) + { + set_noeval = 1; + noeval++; + } + + val1 = EXP_HIGHEST (); + + if (set_noeval) + noeval--; + if (curtok != COL) + evalerror (_("`:' expected for conditional expression")); + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); + set_noeval = 0; + if (cval) + { + set_noeval = 1; + noeval++; + } + val2 = explor (); + if (set_noeval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + +/* Logical OR. */ +static intmax_t +explor () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expland (); + + while (curtok == LOR) + { + set_noeval = 0; + if (val1 != 0) + { + noeval++; + set_noeval = 1; + } + readtok (); + val2 = expland (); + if (set_noeval) + noeval--; + val1 = val1 || val2; + lasttok = LOR; + } + + return (val1); +} + +/* Logical AND. */ +static intmax_t +expland () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expbor (); + + while (curtok == LAND) + { + set_noeval = 0; + if (val1 == 0) + { + set_noeval = 1; + noeval++; + } + readtok (); + val2 = expbor (); + if (set_noeval) + noeval--; + val1 = val1 && val2; + lasttok = LAND; + } + + return (val1); +} + +/* Bitwise OR. */ +static intmax_t +expbor () +{ + register intmax_t val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + } + + return (val1); +} + +/* Bitwise XOR. */ +static intmax_t +expbxor () +{ + register intmax_t val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + } + + return (val1); +} + +/* Bitwise AND. */ +static intmax_t +expband () +{ + register intmax_t val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + } + + return (val1); +} + +static intmax_t +exp5 () +{ + register intmax_t val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + } + return (val1); +} + +static intmax_t +exp4 () +{ + register intmax_t val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else /* (op == GT) */ + val1 = val1 > val2; + } + return (val1); +} + +/* Left and right shifts. */ +static intmax_t +expshift () +{ + register intmax_t val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + } + + return (val1); +} + +static intmax_t +exp3 () +{ + register intmax_t val1, val2; + + val1 = exp2 (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = exp2 (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + } + return (val1); +} + +static intmax_t +exp2 () +{ + register intmax_t val1, val2; + + val1 = exppower (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + + readtok (); + + val2 = exppower (); + + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + evalerror (_("division by 0")); + + if (op == MUL) + val1 *= val2; + else if (op == DIV) + val1 /= val2; + else if (op == MOD) + val1 %= val2; + } + return (val1); +} + +static intmax_t +exppower () +{ + register intmax_t val1, val2, c; + + val1 = exp1 (); + while (curtok == POWER) + { + readtok (); + val2 = exp1 (); + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + for (c = 1; val2--; c *= val1) + ; + val1 = c; + } + return (val1); +} + +static intmax_t +exp1 () +{ + register intmax_t val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + } + else + val = exp0 (); + + return (val); +} + +static intmax_t +exp0 () +{ + register intmax_t val = 0, v2; + char *vincdec; + int stok; + + /* XXX - might need additional logic here to decide whether or not + pre-increment or pre-decrement is legal at this point. */ + if (curtok == PREINC || curtok == PREDEC) + { + stok = lasttok = curtok; + readtok (); + if (curtok != STR) + /* readtok() catches this */ + evalerror (_("identifier expected after pre-increment or pre-decrement")); + + v2 = tokval + ((stok == PREINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + val = v2; + + curtok = NUM; /* make sure --x=7 is flagged as an error */ + readtok (); + } + else if (curtok == MINUS) + { + readtok (); + val = - exp0 (); + } + else if (curtok == PLUS) + { + readtok (); + val = exp0 (); + } + else if (curtok == LPAR) + { + readtok (); + val = EXP_HIGHEST (); + + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + if (curtok == STR && (*tp == '+' || *tp == '-') && tp[1] == *tp && + (tp[2] == '\0' || (ISALNUM ((unsigned char)tp[2]) == 0))) + { + /* post-increment or post-decrement */ + v2 = val + ((*tp == '+') ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + tp += 2; + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + + readtok (); + } + else + evalerror (_("syntax error: operand expected")); + + return (val); +} + +static intmax_t +expr_streval (tok, e) + char *tok; + int e; +{ + SHELL_VAR *v; + char *value; + intmax_t tval; + + /* [[[[[ */ +#if defined (ARRAY_VARS) + v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok); +#else + v = find_variable (tok); +#endif + + if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) + { +#if defined (ARRAY_VARS) + value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok; +#else + value = tok; +#endif + + err_unboundvar (value); + +#if defined (ARRAY_VARS) + if (e == ']') + FREE (value); /* array_variable_name returns new memory */ +#endif + + if (interactive_shell) + { + expr_unwind (); + jump_to_top_level (DISCARD); + } + else + jump_to_top_level (FORCE_EOF); + } + +#if defined (ARRAY_VARS) + /* Second argument of 0 to get_array_value means that we don't allow + references like array[@]. In this case, get_array_value is just + like get_variable_value in that it does not return newly-allocated + memory or quote the results. */ + value = (e == ']') ? get_array_value (tok, 0, (int *)NULL) : get_variable_value (v); +#else + value = get_variable_value (v); +#endif + + tval = (value && *value) ? subexpr (value) : 0; + + return (tval); +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp; + register unsigned char c, c1; + register int e; + + /* Skip leading whitespace. */ + cp = tp; + c = e = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + lasttp = tp = cp - 1; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + + if (legal_variable_starter (c)) + { + /* variable names not preceded with a dollar sign are shell variables. */ + char *savecp; + EXPR_CONTEXT ec; + int peektok; + + while (legal_variable_char (c)) + c = *cp++; + + c = *--cp; + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = skipsubscript (cp, 0); + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror (bash_badsub_errmsg); + } +#endif /* ARRAY_VARS */ + + *cp = '\0'; + FREE (tokstr); + tokstr = savestring (tp); + *cp = c; + + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + tp = savecp = cp; + noeval = 1; + readtok (); + peektok = curtok; + if (peektok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + cp = savecp; + + /* The tests for PREINC and PREDEC aren't strictly correct, but they + preserve old behavior if a construct like --x=9 is given. */ + if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) + tokval = expr_streval (tokstr, e); + else + tokval = 0; + + lasttok = curtok; + curtok = STR; + } + else if (DIGIT(c)) + { + while (ISALNUM (c) || c == '#' || c == '@' || c == '_') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; + else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) + c = PREDEC; + else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) + c = PREINC; + else if (c1 == EQ && member (c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else + cp--; /* `unget' the character */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + char *msg; +{ + char *name, *t; + + name = this_command_name; + for (t = expression; whitespace (*t); t++) + ; + internal_error ("%s%s%s: %s (error token is \"%s\")", + name ? name : "", name ? ": " : "", t, + msg, (lasttp && *lasttp) ? lasttp : ""); + longjmp (evalbuf, 1); +} + +/* Convert a string to an intmax_t integer, with an arbitrary base. + 0nnn -> base 8 + 0[Xx]nn -> base 16 + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 -- + you get the picture). */ + +static intmax_t +strlong (num) + char *num; +{ + register char *s; + register unsigned char c; + int base, foundbase; + intmax_t val; + + s = num; + + base = 10; + foundbase = 0; + if (*s == '0') + { + s++; + + if (*s == '\0') + return 0; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + foundbase++; + } + + val = 0; + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + if (foundbase) + evalerror (_("invalid number")); + + /* Illegal base specifications raise an evaluation error. */ + if (val < 2 || val > 64) + evalerror (_("invalid arithmetic base")); + + base = val; + val = 0; + foundbase++; + } + else if (ISALNUM(c) || (c == '_') || (c == '@')) + { + if (DIGIT(c)) + c = TODIGIT(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '@') + c = 62; + else if (c == '_') + c = 63; + + if (c >= base) + evalerror (_("value too great for base")); + + val = (val * base) + c; + } + else + break; + } + return (val); +} + +#if defined (EXPR_TEST) +void * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +void * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +procenv_t top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + intmax_t v; + int expok; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i], &expok); + if (expok == 0) + fprintf (stderr, "%s: expression error\n", argv[i]); + else + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + intmax_t n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ diff --git a/expr.c.save2 b/expr.c.save2 new file mode 100644 index 00000000..00896b71 --- /dev/null +++ b/expr.c.save2 @@ -0,0 +1,1268 @@ +/* expr.c -- arithmetic expression evaluation. */ + +/* Copyright (C) 1990-2003 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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* + All arithmetic is done as intmax_t integers with no checking for overflow + (though division by 0 is caught and flagged as an error). + + The following operators are handled, grouped into a set of levels in + order of decreasing precedence. + + "id++", "id--" [post-increment and post-decrement] + "++id", "--id" [pre-increment and pre-decrement] + "-", "+" [(unary operators)] + "!", "~" + "**" [(exponentiation)] + "*", "/", "%" + "+", "-" + "<<", ">>" + "<=", ">=", "<", ">" + "==", "!=" + "&" + "^" + "|" + "&&" + "||" + "expr ? expr : expr" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] + + (Note that most of these operators have special meaning to bash, and an + entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure + that it is passed intact to the evaluator when using `let'. When using + the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))' + is treated as if in double quotes.) + + Sub-expressions within parentheses have a precedence level greater than + all of the above levels and are evaluated first. Within a single prece- + dence group, evaluation is left-to-right, except for the arithmetic + assignment operator (`='), which is evaluated right-to-left (as in C). + + The expression evaluator returns the value of the expression (assignment + statements have as a value what is returned by the RHS). The `let' + builtin, on the other hand, returns 0 if the last expression evaluates to + a non-zero, and 1 otherwise. + + Implementation is a recursive-descent parser. + + Chet Ramey + chet@ins.CWRU.Edu +*/ + +#include "config.h" + +#include <stdio.h> +#include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "chartypes.h" +#include "bashintl.h" + +#include "shell.h" + +/* Because of the $((...)) construct, expressions may include newlines. + Here is a macro which accepts newlines, tabs and spaces as whitespace. */ +#define cr_whitespace(c) (whitespace(c) || ((c) == '\n')) + +/* Size be which the expression stack grows when neccessary. */ +#define EXPR_STACK_GROW_SIZE 10 + +/* Maximum amount of recursion allowed. This prevents a non-integer + variable such as "num=num+2" from infinitely adding to itself when + "let num=num+2" is given. */ +#define MAX_EXPR_RECURSION_LEVEL 1024 + +/* The Tokens. Singing "The Lion Sleeps Tonight". */ + +#define EQEQ 1 /* "==" */ +#define NEQ 2 /* "!=" */ +#define LEQ 3 /* "<=" */ +#define GEQ 4 /* ">=" */ +#define STR 5 /* string */ +#define NUM 6 /* number */ +#define LAND 7 /* "&&" Logical AND */ +#define LOR 8 /* "||" Logical OR */ +#define LSH 9 /* "<<" Left SHift */ +#define RSH 10 /* ">>" Right SHift */ +#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ +#define PREINC 14 /* ++var */ +#define PREDEC 15 /* --var */ +#define POSTINC 16 /* var++ */ +#define POSTDEC 17 /* var-- */ +#define EQ '=' +#define GT '>' +#define LT '<' +#define PLUS '+' +#define MINUS '-' +#define MUL '*' +#define DIV '/' +#define MOD '%' +#define NOT '!' +#define LPAR '(' +#define RPAR ')' +#define BAND '&' /* Bitwise AND */ +#define BOR '|' /* Bitwise OR. */ +#define BXOR '^' /* Bitwise eXclusive OR. */ +#define BNOT '~' /* Bitwise NOT; Two's complement. */ +#define QUES '?' +#define COL ':' +#define COMMA ',' + +/* This should be the function corresponding to the operator with the + highest precedence. */ +#define EXP_HIGHEST expcomma + +static char *expression; /* The current expression */ +static char *tp; /* token lexical position */ +static char *lasttp; /* pointer to last token position */ +static int curtok; /* the current token */ +static int lasttok; /* the previous token */ +static int assigntok; /* the OP in OP= */ +static char *tokstr; /* current token string */ +static intmax_t tokval; /* current token value */ +static int noeval; /* set to 1 if no assignment to be done */ +static procenv_t evalbuf; + +static void readtok __P((void)); /* lexical analyzer */ + +static intmax_t expr_streval __P((char *, int)); +static intmax_t strlong __P((char *)); +static void evalerror __P((char *)); + +static void pushexp __P((void)); +static void popexp __P((void)); +static void expr_unwind __P((void)); +static void expr_bind_variable __P((char *, char *)); + +static intmax_t subexpr __P((char *)); + +static intmax_t expcomma __P((void)); +static intmax_t expassign __P((void)); +static intmax_t expcond __P((void)); +static intmax_t explor __P((void)); +static intmax_t expland __P((void)); +static intmax_t expbor __P((void)); +static intmax_t expbxor __P((void)); +static intmax_t expband __P((void)); +static intmax_t exp5 __P((void)); +static intmax_t exp4 __P((void)); +static intmax_t expshift __P((void)); +static intmax_t exp3 __P((void)); +static intmax_t exp2 __P((void)); +static intmax_t exppower __P((void)); +static intmax_t exp1 __P((void)); +static intmax_t exp0 __P((void)); + +/* A structure defining a single expression context. */ +typedef struct { + int curtok, lasttok; + char *expression, *tp, *lasttp; + intmax_t tokval; + char *tokstr; + int noeval; +} EXPR_CONTEXT; + +#ifdef INCLUDE_UNUSED +/* Not used yet. */ +typedef struct { + char *tokstr; + intmax_t tokval; +} LVALUE; +#endif + +/* Global var which contains the stack of expression contexts. */ +static EXPR_CONTEXT **expr_stack; +static int expr_depth; /* Location in the stack. */ +static int expr_stack_size; /* Number of slots already allocated. */ + +extern char *this_command_name; +extern int unbound_vars_is_error; + +#if defined (ARRAY_VARS) +extern char *bash_badsub_errmsg; +#endif + +#define SAVETOK(X) \ + do { \ + (X)->curtok = curtok; \ + (X)->lasttok = lasttok; \ + (X)->tp = tp; \ + (X)->lasttp = lasttp; \ + (X)->tokval = tokval; \ + (X)->tokstr = tokstr; \ + (X)->noeval = noeval; \ + } while (0) + +#define RESTORETOK(X) \ + do { \ + curtok = (X)->curtok; \ + lasttok = (X)->lasttok; \ + tp = (X)->tp; \ + lasttp = (X)->lasttp; \ + tokval = (X)->tokval; \ + tokstr = (X)->tokstr; \ + noeval = (X)->noeval; \ + } while (0) + +/* Push and save away the contents of the globals describing the + current expression context. */ +static void +pushexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) + evalerror (_("expression recursion level exceeded")); + + if (expr_depth >= expr_stack_size) + { + expr_stack_size += EXPR_STACK_GROW_SIZE; + expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); + } + + context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); + + context->expression = expression; + SAVETOK(context); + + expr_stack[expr_depth++] = context; +} + +/* Pop the the contents of the expression context stack into the + globals describing the current expression context. */ +static void +popexp () +{ + EXPR_CONTEXT *context; + + if (expr_depth == 0) + evalerror (_("recursion stack underflow")); + + context = expr_stack[--expr_depth]; + + expression = context->expression; + RESTORETOK (context); + + free (context); +} + +static void +expr_unwind () +{ + while (--expr_depth > 0) + { + if (expr_stack[expr_depth]->tokstr) + free (expr_stack[expr_depth]->tokstr); + + if (expr_stack[expr_depth]->expression) + free (expr_stack[expr_depth]->expression); + + free (expr_stack[expr_depth]); + } + free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ +} + +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + (void)bind_int_variable (lhs, rhs); + stupidly_hack_special_variables (lhs); +} + +/* Evaluate EXPR, and return the arithmetic result. If VALIDP is + non-null, a zero is stored into the location to which it points + if the expression is invalid, non-zero otherwise. If a non-zero + value is returned in *VALIDP, the return value of evalexp() may + be used. + + The `while' loop after the longjmp is caught relies on the above + implementation of pushexp and popexp leaving in expr_stack[0] the + values that the variables had when the program started. That is, + the first things saved are the initial values of the variables that + were assigned at program startup or by the compiler. Therefore, it is + safe to let the loop terminate when expr_depth == 0, without freeing up + any of the expr_depth[0] stuff. */ +intmax_t +evalexp (expr, validp) + char *expr; + int *validp; +{ + intmax_t val; + int c; + procenv_t oevalbuf; + + val = 0; + + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp (evalbuf); + + if (c) + { + FREE (tokstr); + FREE (expression); + tokstr = expression = (char *)NULL; + + expr_unwind (); + + if (validp) + *validp = 0; + return (0); + } + + val = subexpr (expr); + + if (validp) + *validp = 1; + + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + + return (val); +} + +static intmax_t +subexpr (expr) + char *expr; +{ + intmax_t val; + char *p; + + for (p = expr; p && *p && cr_whitespace (*p); p++) + ; + + if (p == NULL || *p == '\0') + return (0); + + pushexp (); + curtok = lasttok = 0; + expression = savestring (expr); + tp = expression; + + tokstr = (char *)NULL; + tokval = 0; + + readtok (); + + val = EXP_HIGHEST (); + + if (curtok != 0) + evalerror (_("syntax error in expression")); + + FREE (tokstr); + FREE (expression); + + popexp (); + + return val; +} + +static intmax_t +expcomma () +{ + register intmax_t value; + + value = expassign (); + while (curtok == COMMA) + { + readtok (); + value = expassign (); + } + + return value; +} + +static intmax_t +expassign () +{ + register intmax_t value; + char *lhs, *rhs; + + value = expcond (); + if (curtok == EQ || curtok == OP_ASSIGN) + { + int special, op; + intmax_t lvalue; + + special = curtok == OP_ASSIGN; + + if (lasttok != STR) + evalerror (_("attempted assignment to non-variable")); + + if (special) + { + op = assigntok; /* a OP= b */ + lvalue = value; + } + + lhs = savestring (tokstr); + readtok (); + value = expassign (); + + if (special) + { + switch (op) + { + case MUL: + lvalue *= value; + break; + case DIV: + if (value == 0) + evalerror (_("division by 0")); + lvalue /= value; + break; + case MOD: + if (value == 0) + evalerror (_("division by 0")); + lvalue %= value; + break; + case PLUS: + lvalue += value; + break; + case MINUS: + lvalue -= value; + break; + case LSH: + lvalue <<= value; + break; + case RSH: + lvalue >>= value; + break; + case BAND: + lvalue &= value; + break; + case BOR: + lvalue |= value; + break; + case BXOR: + lvalue ^= value; + break; + default: + free (lhs); + evalerror (_("bug: bad expassign token")); + break; + } + value = lvalue; + } + + rhs = itos (value); + if (noeval == 0) + expr_bind_variable (lhs, rhs); + free (rhs); + free (lhs); + FREE (tokstr); + tokstr = (char *)NULL; /* For freeing on errors. */ + } + return (value); +} + +/* Conditional expression (expr?expr:expr) */ +static intmax_t +expcond () +{ + intmax_t cval, val1, val2, rval; + int set_noeval; + + set_noeval = 0; + rval = cval = explor (); + if (curtok == QUES) /* found conditional expr */ + { + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + if (cval == 0) + { + set_noeval = 1; + noeval++; + } + + val1 = EXP_HIGHEST (); + + if (set_noeval) + noeval--; + if (curtok != COL) + evalerror (_("`:' expected for conditional expression")); + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); + set_noeval = 0; + if (cval) + { + set_noeval = 1; + noeval++; + } + val2 = explor (); + if (set_noeval) + noeval--; + rval = cval ? val1 : val2; + lasttok = COND; + } + return rval; +} + +/* Logical OR. */ +static intmax_t +explor () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expland (); + + while (curtok == LOR) + { + set_noeval = 0; + if (val1 != 0) + { + noeval++; + set_noeval = 1; + } + readtok (); + val2 = expland (); + if (set_noeval) + noeval--; + val1 = val1 || val2; + lasttok = LOR; + } + + return (val1); +} + +/* Logical AND. */ +static intmax_t +expland () +{ + register intmax_t val1, val2; + int set_noeval; + + val1 = expbor (); + + while (curtok == LAND) + { + set_noeval = 0; + if (val1 == 0) + { + set_noeval = 1; + noeval++; + } + readtok (); + val2 = expbor (); + if (set_noeval) + noeval--; + val1 = val1 && val2; + lasttok = LAND; + } + + return (val1); +} + +/* Bitwise OR. */ +static intmax_t +expbor () +{ + register intmax_t val1, val2; + + val1 = expbxor (); + + while (curtok == BOR) + { + readtok (); + val2 = expbxor (); + val1 = val1 | val2; + } + + return (val1); +} + +/* Bitwise XOR. */ +static intmax_t +expbxor () +{ + register intmax_t val1, val2; + + val1 = expband (); + + while (curtok == BXOR) + { + readtok (); + val2 = expband (); + val1 = val1 ^ val2; + } + + return (val1); +} + +/* Bitwise AND. */ +static intmax_t +expband () +{ + register intmax_t val1, val2; + + val1 = exp5 (); + + while (curtok == BAND) + { + readtok (); + val2 = exp5 (); + val1 = val1 & val2; + } + + return (val1); +} + +static intmax_t +exp5 () +{ + register intmax_t val1, val2; + + val1 = exp4 (); + + while ((curtok == EQEQ) || (curtok == NEQ)) + { + int op = curtok; + + readtok (); + val2 = exp4 (); + if (op == EQEQ) + val1 = (val1 == val2); + else if (op == NEQ) + val1 = (val1 != val2); + } + return (val1); +} + +static intmax_t +exp4 () +{ + register intmax_t val1, val2; + + val1 = expshift (); + while ((curtok == LEQ) || + (curtok == GEQ) || + (curtok == LT) || + (curtok == GT)) + { + int op = curtok; + + readtok (); + val2 = expshift (); + + if (op == LEQ) + val1 = val1 <= val2; + else if (op == GEQ) + val1 = val1 >= val2; + else if (op == LT) + val1 = val1 < val2; + else /* (op == GT) */ + val1 = val1 > val2; + } + return (val1); +} + +/* Left and right shifts. */ +static intmax_t +expshift () +{ + register intmax_t val1, val2; + + val1 = exp3 (); + + while ((curtok == LSH) || (curtok == RSH)) + { + int op = curtok; + + readtok (); + val2 = exp3 (); + + if (op == LSH) + val1 = val1 << val2; + else + val1 = val1 >> val2; + } + + return (val1); +} + +static intmax_t +exp3 () +{ + register intmax_t val1, val2; + + val1 = exp2 (); + + while ((curtok == PLUS) || (curtok == MINUS)) + { + int op = curtok; + + readtok (); + val2 = exp2 (); + + if (op == PLUS) + val1 += val2; + else if (op == MINUS) + val1 -= val2; + } + return (val1); +} + +static intmax_t +exp2 () +{ + register intmax_t val1, val2; + + val1 = exppower (); + + while ((curtok == MUL) || + (curtok == DIV) || + (curtok == MOD)) + { + int op = curtok; + + readtok (); + + val2 = exppower (); + + if (((op == DIV) || (op == MOD)) && (val2 == 0)) + evalerror (_("division by 0")); + + if (op == MUL) + val1 *= val2; + else if (op == DIV) + val1 /= val2; + else if (op == MOD) + val1 %= val2; + } + return (val1); +} + +static intmax_t +exppower () +{ + register intmax_t val1, val2, c; + + val1 = exp1 (); + while (curtok == POWER) + { + readtok (); + val2 = exp1 (); + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + for (c = 1; val2--; c *= val1) + ; + val1 = c; + } + return (val1); +} + +static intmax_t +exp1 () +{ + register intmax_t val; + + if (curtok == NOT) + { + readtok (); + val = !exp1 (); + } + else if (curtok == BNOT) + { + readtok (); + val = ~exp1 (); + } + else + val = exp0 (); + + return (val); +} + +static intmax_t +exp0 () +{ + register intmax_t val = 0, v2; + char *vincdec; + int stok; + EXPR_CONTEXT ec; + + /* XXX - might need additional logic here to decide whether or not + pre-increment or pre-decrement is legal at this point. */ + if (curtok == PREINC || curtok == PREDEC) + { + stok = lasttok = curtok; + readtok (); + if (curtok != STR) + /* readtok() catches this */ + evalerror (_("identifier expected after pre-increment or pre-decrement")); + + v2 = tokval + ((stok == PREINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + val = v2; + + curtok = NUM; /* make sure --x=7 is flagged as an error */ + readtok (); + } + else if (curtok == MINUS) + { + readtok (); + val = - exp0 (); + } + else if (curtok == PLUS) + { + readtok (); + val = exp0 (); + } + else if (curtok == LPAR) + { + readtok (); + val = EXP_HIGHEST (); + + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); + + /* Skip over closing paren. */ + readtok (); + } + else if ((curtok == NUM) || (curtok == STR)) + { + val = tokval; + if (curtok == STR) + { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + + /* post-increment or post-decrement */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + + } + + readtok (); + } + else + evalerror (_("syntax error: operand expected")); + + return (val); +} + +static intmax_t +expr_streval (tok, e) + char *tok; + int e; +{ + SHELL_VAR *v; + char *value; + intmax_t tval; + + /* [[[[[ */ +#if defined (ARRAY_VARS) + v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok); +#else + v = find_variable (tok); +#endif + + if ((v == 0 || invisible_p (v)) && unbound_vars_is_error) + { +#if defined (ARRAY_VARS) + value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok; +#else + value = tok; +#endif + + err_unboundvar (value); + +#if defined (ARRAY_VARS) + if (e == ']') + FREE (value); /* array_variable_name returns new memory */ +#endif + + if (interactive_shell) + { + expr_unwind (); + jump_to_top_level (DISCARD); + } + else + jump_to_top_level (FORCE_EOF); + } + +#if defined (ARRAY_VARS) + /* Second argument of 0 to get_array_value means that we don't allow + references like array[@]. In this case, get_array_value is just + like get_variable_value in that it does not return newly-allocated + memory or quote the results. */ + value = (e == ']') ? get_array_value (tok, 0, (int *)NULL) : get_variable_value (v); +#else + value = get_variable_value (v); +#endif + + tval = (value && *value) ? subexpr (value) : 0; + + return (tval); +} + +/* Lexical analyzer/token reader for the expression evaluator. Reads the + next token and puts its value into curtok, while advancing past it. + Updates value of tp. May also set tokval (for number) or tokstr (for + string). */ +static void +readtok () +{ + register char *cp; + register unsigned char c, c1; + register int e; + + /* Skip leading whitespace. */ + cp = tp; + c = e = 0; + while (cp && (c = *cp) && (cr_whitespace (c))) + cp++; + + if (c) + cp++; + + lasttp = tp = cp - 1; + + if (c == '\0') + { + lasttok = curtok; + curtok = 0; + tp = cp; + return; + } + + if (legal_variable_starter (c)) + { + /* variable names not preceded with a dollar sign are shell variables. */ + char *savecp; + EXPR_CONTEXT ec; + int peektok; + + while (legal_variable_char (c)) + c = *cp++; + + c = *--cp; + +#if defined (ARRAY_VARS) + if (c == '[') + { + e = skipsubscript (cp, 0); + if (cp[e] == ']') + { + cp += e + 1; + c = *cp; + e = ']'; + } + else + evalerror (bash_badsub_errmsg); + } +#endif /* ARRAY_VARS */ + + *cp = '\0'; + FREE (tokstr); + tokstr = savestring (tp); + *cp = c; + + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + tp = savecp = cp; + noeval = 1; + curtok = STR; + readtok (); + peektok = curtok; + if (peektok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + cp = savecp; + + /* The tests for PREINC and PREDEC aren't strictly correct, but they + preserve old behavior if a construct like --x=9 is given. */ + if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ) + tokval = expr_streval (tokstr, e); + else + tokval = 0; + + lasttok = curtok; + curtok = STR; + } + else if (DIGIT(c)) + { + while (ISALNUM (c) || c == '#' || c == '@' || c == '_') + c = *cp++; + + c = *--cp; + *cp = '\0'; + + tokval = strlong (tp); + *cp = c; + lasttok = curtok; + curtok = NUM; + } + else + { + c1 = *cp++; + if ((c == EQ) && (c1 == EQ)) + c = EQEQ; + else if ((c == NOT) && (c1 == EQ)) + c = NEQ; + else if ((c == GT) && (c1 == EQ)) + c = GEQ; + else if ((c == LT) && (c1 == EQ)) + c = LEQ; + else if ((c == LT) && (c1 == LT)) + { + if (*cp == '=') /* a <<= b */ + { + assigntok = LSH; + c = OP_ASSIGN; + cp++; + } + else + c = LSH; + } + else if ((c == GT) && (c1 == GT)) + { + if (*cp == '=') + { + assigntok = RSH; /* a >>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = RSH; + } + else if ((c == BAND) && (c1 == BAND)) + c = LAND; + else if ((c == BOR) && (c1 == BOR)) + c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; + else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) + c = PREDEC; + else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) + c = PREINC; + else if ((c == '-') && (c1 == '-') && (curtok == STR)) + c = POSTDEC; + else if ((c == '+') && (c1 == '+') && (curtok == STR)) + c = POSTINC; + else if (c1 == EQ && member (c, "*/%+-&^|")) + { + assigntok = c; /* a OP= b */ + c = OP_ASSIGN; + } + else + cp--; /* `unget' the character */ + lasttok = curtok; + curtok = c; + } + tp = cp; +} + +static void +evalerror (msg) + char *msg; +{ + char *name, *t; + + name = this_command_name; + for (t = expression; whitespace (*t); t++) + ; + internal_error ("%s%s%s: %s (error token is \"%s\")", + name ? name : "", name ? ": " : "", t, + msg, (lasttp && *lasttp) ? lasttp : ""); + longjmp (evalbuf, 1); +} + +/* Convert a string to an intmax_t integer, with an arbitrary base. + 0nnn -> base 8 + 0[Xx]nn -> base 16 + Anything else: [base#]number (this is implemented to match ksh93) + + Base may be >=2 and <=64. If base is <= 36, the numbers are drawn + from [0-9][a-zA-Z], and lowercase and uppercase letters may be used + interchangably. If base is > 36 and <= 64, the numbers are drawn + from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 -- + you get the picture). */ + +static intmax_t +strlong (num) + char *num; +{ + register char *s; + register unsigned char c; + int base, foundbase; + intmax_t val; + + s = num; + + base = 10; + foundbase = 0; + if (*s == '0') + { + s++; + + if (*s == '\0') + return 0; + + /* Base 16? */ + if (*s == 'x' || *s == 'X') + { + base = 16; + s++; + } + else + base = 8; + foundbase++; + } + + val = 0; + for (c = *s++; c; c = *s++) + { + if (c == '#') + { + if (foundbase) + evalerror (_("invalid number")); + + /* Illegal base specifications raise an evaluation error. */ + if (val < 2 || val > 64) + evalerror (_("invalid arithmetic base")); + + base = val; + val = 0; + foundbase++; + } + else if (ISALNUM(c) || (c == '_') || (c == '@')) + { + if (DIGIT(c)) + c = TODIGIT(c); + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - ((base <= 36) ? 10 : 36); + else if (c == '@') + c = 62; + else if (c == '_') + c = 63; + + if (c >= base) + evalerror (_("value too great for base")); + + val = (val * base) + c; + } + else + break; + } + return (val); +} + +#if defined (EXPR_TEST) +void * +xmalloc (n) + int n; +{ + return (malloc (n)); +} + +void * +xrealloc (s, n) + char *s; + int n; +{ + return (realloc (s, n)); +} + +SHELL_VAR *find_variable () { return 0;} +SHELL_VAR *bind_variable () { return 0; } + +char *get_string_value () { return 0; } + +procenv_t top_level; + +main (argc, argv) + int argc; + char **argv; +{ + register int i; + intmax_t v; + int expok; + + if (setjmp (top_level)) + exit (0); + + for (i = 1; i < argc; i++) + { + v = evalexp (argv[i], &expok); + if (expok == 0) + fprintf (stderr, "%s: expression error\n", argv[i]); + else + printf ("'%s' -> %ld\n", argv[i], v); + } + exit (0); +} + +int +builtin_error (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "expr: "); + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); + return 0; +} + +char * +itos (n) + intmax_t n; +{ + return ("42"); +} + +#endif /* EXPR_TEST */ diff --git a/lib/readline/display.c b/lib/readline/display.c index ba8e3071..3eb417bf 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -506,7 +506,7 @@ rl_redisplay () } } - pmtlen = strlen (prompt_this_line); + prompt_physical_chars = pmtlen = strlen (prompt_this_line); temp = pmtlen + out + 2; if (temp >= line_size) { @@ -1841,6 +1841,7 @@ static char *saved_local_prefix; static int saved_last_invisible; static int saved_visible_length; static int saved_invis_chars_first_line; +static int saved_physical_chars; void rl_save_prompt () @@ -1850,10 +1851,11 @@ rl_save_prompt () saved_last_invisible = prompt_last_invisible; saved_visible_length = prompt_visible_length; saved_invis_chars_first_line = prompt_invis_chars_first_line; + saved_physical_chars = prompt_physical_chars; local_prompt = local_prompt_prefix = (char *)0; prompt_last_invisible = prompt_visible_length = 0; - prompt_invis_chars_first_line = 0; + prompt_invis_chars_first_line = prompt_physical_chars = 0; } void @@ -1867,6 +1869,7 @@ rl_restore_prompt () prompt_last_invisible = saved_last_invisible; prompt_visible_length = saved_visible_length; prompt_invis_chars_first_line = saved_invis_chars_first_line; + prompt_physical_chars = saved_physical_chars; } char * @@ -1899,6 +1902,7 @@ _rl_make_prompt_for_search (pchar) prompt_last_invisible = saved_last_invisible; prompt_visible_length = saved_visible_length + 1; } + return pmt; } diff --git a/lib/readline/display.c~ b/lib/readline/display.c~ new file mode 100644 index 00000000..ba8e3071 --- /dev/null +++ b/lib/readline/display.c~ @@ -0,0 +1,2274 @@ +/* display.c -- readline redisplay facility. */ + +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library 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. + + The GNU Readline Library 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. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include "posixstat.h" + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Termcap library stuff. */ +#include "tcap.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#if defined (HACK_TERMCAP_MOTION) +extern char *_rl_term_forward_char; +#endif + +static void update_line PARAMS((char *, char *, int, int, int, int)); +static void space_to_eol PARAMS((int)); +static void delete_chars PARAMS((int)); +static void insert_some_chars PARAMS((char *, int, int)); +static void cr PARAMS((void)); + +#if defined (HANDLE_MULTIBYTE) +static int _rl_col_width PARAMS((const char *, int, int)); +static int *_rl_wrapped_line; +#else +# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) +#endif + +static int *inv_lbreaks, *vis_lbreaks; +static int inv_lbsize, vis_lbsize; + +/* Heuristic used to decide whether it is faster to move from CUR to NEW + by backing up or outputting a carriage return and moving forward. */ +#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) + +/* **************************************************************** */ +/* */ +/* Display stuff */ +/* */ +/* **************************************************************** */ + +/* This is the stuff that is hard for me. I never seem to write good + display routines in C. Let's see how I do this time. */ + +/* (PWP) Well... Good for a simple line updater, but totally ignores + the problems of input lines longer than the screen width. + + update_line and the code that calls it makes a multiple line, + automatically wrapping line update. Careful attention needs + to be paid to the vertical position variables. */ + +/* Keep two buffers; one which reflects the current contents of the + screen, and the other to draw what we think the new contents should + be. Then compare the buffers, and make whatever changes to the + screen itself that we should. Finally, make the buffer that we + just drew into be the one which reflects the current contents of the + screen, and place the cursor where it belongs. + + Commands that want to can fix the display themselves, and then let + this function know that the display has been fixed by setting the + RL_DISPLAY_FIXED variable. This is good for efficiency. */ + +/* Application-specific redisplay function. */ +rl_voidfunc_t *rl_redisplay_function = rl_redisplay; + +/* Global variables declared here. */ +/* What YOU turn on when you have handled all redisplay yourself. */ +int rl_display_fixed = 0; + +int _rl_suppress_redisplay = 0; + +/* The stuff that gets printed out before the actual text of the line. + This is usually pointing to rl_prompt. */ +char *rl_display_prompt = (char *)NULL; + +/* Pseudo-global variables declared here. */ +/* The visible cursor position. If you print some text, adjust this. */ +int _rl_last_c_pos = 0; +int _rl_last_v_pos = 0; + +/* Number of lines currently on screen minus 1. */ +int _rl_vis_botlin = 0; + +/* Variables used only in this file. */ +/* The last left edge of text that was displayed. This is used when + doing horizontal scrolling. It shifts in thirds of a screenwidth. */ +static int last_lmargin; + +/* The line display buffers. One is the line currently displayed on + the screen. The other is the line about to be displayed. */ +static char *visible_line = (char *)NULL; +static char *invisible_line = (char *)NULL; + +/* A buffer for `modeline' messages. */ +static char msg_buf[128]; + +/* Non-zero forces the redisplay even if we thought it was unnecessary. */ +static int forced_display; + +/* Default and initial buffer size. Can grow. */ +static int line_size = 1024; + +/* Variables to keep track of the expanded prompt string, which may + include invisible characters. */ + +static char *local_prompt, *local_prompt_prefix; +static int prompt_visible_length, prompt_prefix_length; + +/* The number of invisible characters in the line currently being + displayed on the screen. */ +static int visible_wrap_offset; + +/* The number of invisible characters in the prompt string. Static so it + can be shared between rl_redisplay and update_line */ +static int wrap_offset; + +/* The index of the last invisible character in the prompt string. */ +static int prompt_last_invisible; + +/* The length (buffer offset) of the first line of the last (possibly + multi-line) buffer displayed on the screen. */ +static int visible_first_line_len; + +/* Number of invisible characters on the first physical line of the prompt. + Only valid when the number of physical characters in the prompt exceeds + (or is equal to) _rl_screenwidth. */ +static int prompt_invis_chars_first_line; + +static int prompt_last_screen_line; + +static int prompt_physical_chars; + +/* Expand the prompt string S and return the number of visible + characters in *LP, if LP is not null. This is currently more-or-less + a placeholder for expansion. LIP, if non-null is a place to store the + index of the last invisible character in the returned string. NIFLP, + if non-zero, is a place to store the number of invisible characters in + the first prompt line. The previous are used as byte counts -- indexes + into a character buffer. */ + +/* Current implementation: + \001 (^A) start non-visible characters + \002 (^B) end non-visible characters + all characters except \001 and \002 (following a \001) are copied to + the returned string; all characters except those between \001 and + \002 are assumed to be `visible'. */ + +static char * +expand_prompt (pmt, lp, lip, niflp, vlp) + char *pmt; + int *lp, *lip, *niflp, *vlp; +{ + char *r, *ret, *p; + int l, rl, last, ignoring, ninvis, invfl, ind, pind, physchars; + + /* Short-circuit if we can. */ + if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0) + { + r = savestring (pmt); + if (lp) + *lp = strlen (r); + if (lip) + *lip = 0; + if (niflp) + *niflp = 0; + if (vlp) + *vlp = lp ? *lp : strlen (r); + return r; + } + + l = strlen (pmt); + r = ret = (char *)xmalloc (l + 1); + + invfl = 0; /* invisible chars in first line of prompt */ + + for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++) + { + /* This code strips the invisible character string markers + RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ + if (*p == RL_PROMPT_START_IGNORE) + { + ignoring++; + continue; + } + else if (ignoring && *p == RL_PROMPT_END_IGNORE) + { + ignoring = 0; + last = r - ret - 1; + continue; + } + else + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + pind = p - pmt; + ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO); + l = ind - pind; + while (l--) + *r++ = *p++; + if (!ignoring) + rl += ind - pind; + else + ninvis += ind - pind; + p--; /* compensate for later increment */ + } + else +#endif + { + *r++ = *p; + if (!ignoring) + rl++; /* visible length byte counter */ + else + ninvis++; /* invisible chars byte counter */ + } + + if (rl >= _rl_screenwidth) + invfl = ninvis; + + if (ignoring == 0) + physchars++; + } + } + + if (rl < _rl_screenwidth) + invfl = ninvis; + + *r = '\0'; + if (lp) + *lp = rl; + if (lip) + *lip = last; + if (niflp) + *niflp = invfl; + if (vlp) + *vlp = physchars; + return ret; +} + +/* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from + PMT and return the rest of PMT. */ +char * +_rl_strip_prompt (pmt) + char *pmt; +{ + char *ret; + + ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL); + return ret; +} + +/* + * Expand the prompt string into the various display components, if + * necessary. + * + * local_prompt = expanded last line of string in rl_display_prompt + * (portion after the final newline) + * local_prompt_prefix = portion before last newline of rl_display_prompt, + * expanded via expand_prompt + * prompt_visible_length = number of visible characters in local_prompt + * prompt_prefix_length = number of visible characters in local_prompt_prefix + * + * This function is called once per call to readline(). It may also be + * called arbitrarily to expand the primary prompt. + * + * The return value is the number of visible characters on the last line + * of the (possibly multi-line) prompt. + */ +int +rl_expand_prompt (prompt) + char *prompt; +{ + char *p, *t; + int c; + + /* Clear out any saved values. */ + FREE (local_prompt); + FREE (local_prompt_prefix); + + local_prompt = local_prompt_prefix = (char *)0; + prompt_last_invisible = prompt_visible_length = 0; + + if (prompt == 0 || *prompt == 0) + return (0); + + p = strrchr (prompt, '\n'); + if (!p) + { + /* The prompt is only one logical line, though it might wrap. */ + local_prompt = expand_prompt (prompt, &prompt_visible_length, + &prompt_last_invisible, + &prompt_invis_chars_first_line, + &prompt_physical_chars); + local_prompt_prefix = (char *)0; + return (prompt_visible_length); + } + else + { + /* The prompt spans multiple lines. */ + t = ++p; + local_prompt = expand_prompt (p, &prompt_visible_length, + &prompt_last_invisible, + (int *)NULL, + (int *)NULL); + c = *t; *t = '\0'; + /* The portion of the prompt string up to and including the + final newline is now null-terminated. */ + local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length, + (int *)NULL, + &prompt_invis_chars_first_line, + &prompt_physical_chars); + *t = c; + return (prompt_prefix_length); + } +} + +/* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated + arrays of line break markers. MINSIZE is the minimum size of VISIBLE_LINE + and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is + increased. If the lines have already been allocated, this ensures that + they can hold at least MINSIZE characters. */ +static void +init_line_structures (minsize) + int minsize; +{ + register int n; + + if (invisible_line == 0) /* initialize it */ + { + if (line_size < minsize) + line_size = minsize; + visible_line = (char *)xmalloc (line_size); + invisible_line = (char *)xmalloc (line_size); + } + else if (line_size < minsize) /* ensure it can hold MINSIZE chars */ + { + line_size *= 2; + if (line_size < minsize) + line_size = minsize; + visible_line = (char *)xrealloc (visible_line, line_size); + invisible_line = (char *)xrealloc (invisible_line, line_size); + } + + for (n = minsize; n < line_size; n++) + { + visible_line[n] = 0; + invisible_line[n] = 1; + } + + if (vis_lbreaks == 0) + { + /* should be enough. */ + inv_lbsize = vis_lbsize = 256; + inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); + vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); +#if defined (HANDLE_MULTIBYTE) + _rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int)); +#endif + inv_lbreaks[0] = vis_lbreaks[0] = 0; + } +} + +/* Basic redisplay algorithm. */ +void +rl_redisplay () +{ + register int in, out, c, linenum, cursor_linenum; + register char *line; + int c_pos, inv_botlin, lb_botlin, lb_linenum; + int newlines, lpos, temp, modmark; + char *prompt_this_line; +#if defined (HANDLE_MULTIBYTE) + wchar_t wc; + size_t wc_bytes; + int wc_width; + mbstate_t ps; + int _rl_wrapped_multicolumn = 0; +#endif + + if (!readline_echoing_p) + return; + + if (!rl_display_prompt) + rl_display_prompt = ""; + + if (invisible_line == 0) + { + init_line_structures (0); + rl_on_new_line (); + } + + /* Draw the line into the buffer. */ + c_pos = -1; + + line = invisible_line; + out = inv_botlin = 0; + + /* Mark the line as modified or not. We only do this for history + lines. */ + modmark = 0; + if (_rl_mark_modified_lines && current_history () && rl_undo_list) + { + line[out++] = '*'; + line[out] = '\0'; + modmark = 1; + } + + /* If someone thought that the redisplay was handled, but the currently + visible line has a different modification state than the one about + to become visible, then correct the caller's misconception. */ + if (visible_line[0] != invisible_line[0]) + rl_display_fixed = 0; + + /* If the prompt to be displayed is the `primary' readline prompt (the + one passed to readline()), use the values we have already expanded. + If not, use what's already in rl_display_prompt. WRAP_OFFSET is the + number of non-visible characters in the prompt string. */ + if (rl_display_prompt == rl_prompt || local_prompt) + { + int local_len = local_prompt ? strlen (local_prompt) : 0; + if (local_prompt_prefix && forced_display) + _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); + + if (local_len > 0) + { + temp = local_len + out + 2; + if (temp >= line_size) + { + line_size = (temp + 1024) - (temp % 1024); + visible_line = (char *)xrealloc (visible_line, line_size); + line = invisible_line = (char *)xrealloc (invisible_line, line_size); + } + strncpy (line + out, local_prompt, local_len); + out += local_len; + } + line[out] = '\0'; + wrap_offset = local_len - prompt_visible_length; + } + else + { + int pmtlen; + prompt_this_line = strrchr (rl_display_prompt, '\n'); + if (!prompt_this_line) + prompt_this_line = rl_display_prompt; + else + { + prompt_this_line++; + pmtlen = prompt_this_line - rl_display_prompt; /* temp var */ + if (forced_display) + { + _rl_output_some_chars (rl_display_prompt, pmtlen); + /* Make sure we are at column zero even after a newline, + regardless of the state of terminal output processing. */ + if (pmtlen < 2 || prompt_this_line[-2] != '\r') + cr (); + } + } + + pmtlen = strlen (prompt_this_line); + temp = pmtlen + out + 2; + if (temp >= line_size) + { + line_size = (temp + 1024) - (temp % 1024); + visible_line = (char *)xrealloc (visible_line, line_size); + line = invisible_line = (char *)xrealloc (invisible_line, line_size); + } + strncpy (line + out, prompt_this_line, pmtlen); + out += pmtlen; + line[out] = '\0'; + wrap_offset = prompt_invis_chars_first_line = 0; + } + +#define CHECK_INV_LBREAKS() \ + do { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + } \ + } while (0) + +#if defined (HANDLE_MULTIBYTE) +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= _rl_screenwidth) \ + { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + _rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ + _rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \ + lpos = 0; \ + } \ + } while (0) +#else +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= _rl_screenwidth) \ + { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ + lpos = 0; \ + } \ + } while (0) +#endif + + /* inv_lbreaks[i] is where line i starts in the buffer. */ + inv_lbreaks[newlines = 0] = 0; +#if 0 + lpos = out - wrap_offset; +#else + lpos = prompt_physical_chars + modmark; +#endif + +#if defined (HANDLE_MULTIBYTE) + memset (_rl_wrapped_line, 0, vis_lbsize); +#endif + + /* prompt_invis_chars_first_line is the number of invisible characters in + the first physical line of the prompt. + wrap_offset - prompt_invis_chars_first_line is the number of invis + chars on the second line. */ + + /* what if lpos is already >= _rl_screenwidth before we start drawing the + contents of the command line? */ + while (lpos >= _rl_screenwidth) + { + /* fix from Darin Johnson <darin@acuson.com> for prompt string with + invisible characters that is longer than the screen width. The + prompt_invis_chars_first_line variable could be made into an array + saying how many invisible characters there are per line, but that's + probably too much work for the benefit gained. How many people have + prompts that exceed two physical lines? + Additional logic fix from Edward Catmur <ed@catmur.co.uk> */ + temp = ((newlines + 1) * _rl_screenwidth) + + ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line + : ((newlines == 1) ? wrap_offset : 0)) + : ((newlines == 0) ? wrap_offset :0)); + + inv_lbreaks[++newlines] = temp; + lpos -= _rl_screenwidth; + } + + prompt_last_screen_line = newlines; + + /* Draw the rest of the line (after the prompt) into invisible_line, keeping + track of where the cursor is (c_pos), the number of the line containing + the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin). + It maintains an array of line breaks for display (inv_lbreaks). + This handles expanding tabs for display and displaying meta characters. */ + lb_linenum = 0; +#if defined (HANDLE_MULTIBYTE) + in = 0; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps, 0, sizeof (mbstate_t)); + wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps); + } + else + wc_bytes = 1; + while (in < rl_end) +#else + for (in = 0; in < rl_end; in++) +#endif + { + c = (unsigned char)rl_line_buffer[in]; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + if (MB_INVALIDCH (wc_bytes)) + { + /* Byte sequence is invalid or shortened. Assume that the + first byte represents a character. */ + wc_bytes = 1; + /* Assume that a character occupies a single column. */ + wc_width = 1; + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (MB_NULLWCH (wc_bytes)) + break; /* Found '\0' */ + else + { + temp = wcwidth (wc); + wc_width = (temp >= 0) ? temp : 1; + } + } +#endif + + if (out + 8 >= line_size) /* XXX - 8 for \t */ + { + line_size *= 2; + visible_line = (char *)xrealloc (visible_line, line_size); + invisible_line = (char *)xrealloc (invisible_line, line_size); + line = invisible_line; + } + + if (in == rl_point) + { + c_pos = out; + lb_linenum = newlines; + } + +#if defined (HANDLE_MULTIBYTE) + if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */ +#else + if (META_CHAR (c)) +#endif + { + if (_rl_output_meta_chars == 0) + { + sprintf (line + out, "\\%o", c); + + if (lpos + 4 >= _rl_screenwidth) + { + temp = _rl_screenwidth - lpos; + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out + temp; + lpos = 4 - temp; + } + else + lpos += 4; + + out += 4; + } + else + { + line[out++] = c; + CHECK_LPOS(); + } + } +#if defined (DISPLAY_TABS) + else if (c == '\t') + { + register int newout; + +#if 0 + newout = (out | (int)7) + 1; +#else + newout = out + 8 - lpos % 8; +#endif + temp = newout - out; + if (lpos + temp >= _rl_screenwidth) + { + register int temp2; + temp2 = _rl_screenwidth - lpos; + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out + temp2; + lpos = temp - temp2; + while (out < newout) + line[out++] = ' '; + } + else + { + while (out < newout) + line[out++] = ' '; + lpos += temp; + } + } +#endif + else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up) + { + line[out++] = '\0'; /* XXX - sentinel */ + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out; + lpos = 0; + } + else if (CTRL_CHAR (c) || c == RUBOUT) + { + line[out++] = '^'; + CHECK_LPOS(); + line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + CHECK_LPOS(); + } + else + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + register int i; + + _rl_wrapped_multicolumn = 0; + + if (_rl_screenwidth < lpos + wc_width) + for (i = lpos; i < _rl_screenwidth; i++) + { + /* The space will be removed in update_line() */ + line[out++] = ' '; + _rl_wrapped_multicolumn++; + CHECK_LPOS(); + } + if (in == rl_point) + { + c_pos = out; + lb_linenum = newlines; + } + for (i = in; i < in+wc_bytes; i++) + line[out++] = rl_line_buffer[i]; + for (i = 0; i < wc_width; i++) + CHECK_LPOS(); + } + else + { + line[out++] = c; + CHECK_LPOS(); + } +#else + line[out++] = c; + CHECK_LPOS(); +#endif + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + in += wc_bytes; + wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps); + } + else + in++; +#endif + + } + line[out] = '\0'; + if (c_pos < 0) + { + c_pos = out; + lb_linenum = newlines; + } + + inv_botlin = lb_botlin = newlines; + CHECK_INV_LBREAKS (); + inv_lbreaks[newlines+1] = out; + cursor_linenum = lb_linenum; + + /* C_POS == position in buffer where cursor should be placed. + CURSOR_LINENUM == line number where the cursor should be placed. */ + + /* PWP: now is when things get a bit hairy. The visible and invisible + line buffers are really multiple lines, which would wrap every + (screenwidth - 1) characters. Go through each in turn, finding + the changed region and updating it. The line order is top to bottom. */ + + /* If we can move the cursor up and down, then use multiple lines, + otherwise, let long lines display in a single terminal line, and + horizontally scroll it. */ + + if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up) + { + int nleft, pos, changed_screen_line; + + if (!rl_display_fixed || forced_display) + { + forced_display = 0; + + /* If we have more than a screenful of material to display, then + only display a screenful. We should display the last screen, + not the first. */ + if (out >= _rl_screenchars) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY); + else + out = _rl_screenchars - 1; + } + + /* The first line is at character position 0 in the buffer. The + second and subsequent lines start at inv_lbreaks[N], offset by + OFFSET (which has already been calculated above). */ + +#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) +#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) +#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) +#define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) +#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) +#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) + + /* For each line in the buffer, do the updating display. */ + for (linenum = 0; linenum <= inv_botlin; linenum++) + { + update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, + VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); + + /* If this is the line with the prompt, we might need to + compensate for invisible characters in the new line. Do + this only if there is not more than one new line (which + implies that we completely overwrite the old visible line) + and the new line is shorter than the old. Make sure we are + at the end of the new line before clearing. */ + if (linenum == 0 && + inv_botlin == 0 && _rl_last_c_pos == out && + (wrap_offset > visible_wrap_offset) && + (_rl_last_c_pos < visible_first_line_len)) + { + nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; + if (nleft) + _rl_clear_to_eol (nleft); + } + + /* Since the new first line is now visible, save its length. */ + if (linenum == 0) + visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset; + } + + /* We may have deleted some lines. If so, clear the left over + blank ones at the bottom out. */ + if (_rl_vis_botlin > inv_botlin) + { + char *tt; + for (; linenum <= _rl_vis_botlin; linenum++) + { + tt = VIS_CHARS (linenum); + _rl_move_vert (linenum); + _rl_move_cursor_relative (0, tt); + _rl_clear_to_eol + ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth); + } + } + _rl_vis_botlin = inv_botlin; + + /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a + different screen line during this redisplay. */ + changed_screen_line = _rl_last_v_pos != cursor_linenum; + if (changed_screen_line) + { + _rl_move_vert (cursor_linenum); + /* If we moved up to the line with the prompt using _rl_term_up, + the physical cursor position on the screen stays the same, + but the buffer position needs to be adjusted to account + for invisible characters. */ + if (cursor_linenum == 0 && wrap_offset) + _rl_last_c_pos += wrap_offset; + } + + /* We have to reprint the prompt if it contains invisible + characters, since it's not generally OK to just reprint + the characters from the current cursor position. But we + only need to reprint it if the cursor is before the last + invisible character in the prompt string. */ + nleft = prompt_visible_length + wrap_offset; + if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && + _rl_last_c_pos <= prompt_last_invisible && local_prompt) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + if (_rl_term_cr) + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_output_some_chars (local_prompt, nleft); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft); + else + _rl_last_c_pos = nleft; + } + + /* Where on that line? And where does that line start + in the buffer? */ + pos = inv_lbreaks[cursor_linenum]; + /* nleft == number of characters in the line buffer between the + start of the line and the cursor position. */ + nleft = c_pos - pos; + + /* Since _rl_backspace() doesn't know about invisible characters in the + prompt, and there's no good way to tell it, we compensate for + those characters here and call _rl_backspace() directly. */ + if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) + { + _rl_backspace (_rl_last_c_pos - nleft); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (&visible_line[pos], 0, nleft); + else + _rl_last_c_pos = nleft; + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + else if (nleft != _rl_last_c_pos) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + } + } + else /* Do horizontal scrolling. */ + { +#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0) + int lmargin, ndisp, nleft, phys_c_pos, t; + + /* Always at top line. */ + _rl_last_v_pos = 0; + + /* Compute where in the buffer the displayed line should start. This + will be LMARGIN. */ + + /* The number of characters that will be displayed before the cursor. */ + ndisp = c_pos - wrap_offset; + nleft = prompt_visible_length + wrap_offset; + /* Where the new cursor position will be on the screen. This can be + longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ + phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); + t = _rl_screenwidth / 3; + + /* If the number of characters had already exceeded the screenwidth, + last_lmargin will be > 0. */ + + /* If the number of characters to be displayed is more than the screen + width, compute the starting offset so that the cursor is about + two-thirds of the way across the screen. */ + if (phys_c_pos > _rl_screenwidth - 2) + { + lmargin = c_pos - (2 * t); + if (lmargin < 0) + lmargin = 0; + /* If the left margin would be in the middle of a prompt with + invisible characters, don't display the prompt at all. */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else if (ndisp < _rl_screenwidth - 2) /* XXX - was -1 */ + lmargin = 0; + else if (phys_c_pos < 1) + { + /* If we are moving back towards the beginning of the line and + the last margin is no longer correct, compute a new one. */ + lmargin = ((c_pos - 1) / t) * t; /* XXX */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else + lmargin = last_lmargin; + + /* If the first character on the screen isn't the first character + in the display line, indicate this with a special character. */ + if (lmargin > 0) + line[lmargin] = '<'; + + /* If SCREENWIDTH characters starting at LMARGIN do not encompass + the whole line, indicate that with a special character at the + right edge of the screen. If LMARGIN is 0, we need to take the + wrap offset into account. */ + t = lmargin + M_OFFSET (lmargin, wrap_offset) + _rl_screenwidth; + if (t < out) + line[t - 1] = '>'; + + if (!rl_display_fixed || forced_display || lmargin != last_lmargin) + { + forced_display = 0; + update_line (&visible_line[last_lmargin], + &invisible_line[lmargin], + 0, + _rl_screenwidth + visible_wrap_offset, + _rl_screenwidth + (lmargin ? 0 : wrap_offset), + 0); + + /* If the visible new line is shorter than the old, but the number + of invisible characters is greater, and we are at the end of + the new line, we need to clear to eol. */ + t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset); + if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) && + (_rl_last_c_pos == out) && + t < visible_first_line_len) + { + nleft = _rl_screenwidth - t; + _rl_clear_to_eol (nleft); + } + visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); + if (visible_first_line_len > _rl_screenwidth) + visible_first_line_len = _rl_screenwidth; + + _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); + last_lmargin = lmargin; + } + } + fflush (rl_outstream); + + /* Swap visible and non-visible lines. */ + { + char *vtemp = visible_line; + int *itemp = vis_lbreaks, ntemp = vis_lbsize; + + visible_line = invisible_line; + invisible_line = vtemp; + + vis_lbreaks = inv_lbreaks; + inv_lbreaks = itemp; + + vis_lbsize = inv_lbsize; + inv_lbsize = ntemp; + + rl_display_fixed = 0; + /* If we are displaying on a single line, and last_lmargin is > 0, we + are not displaying any invisible characters, so set visible_wrap_offset + to 0. */ + if (_rl_horizontal_scroll_mode && last_lmargin) + visible_wrap_offset = 0; + else + visible_wrap_offset = wrap_offset; + } +} + +/* PWP: update_line() is based on finding the middle difference of each + line on the screen; vis: + + /old first difference + /beginning of line | /old last same /old EOL + v v v v +old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as +new: eddie> Oh, my little buggy says to me, as lurgid as + ^ ^ ^ ^ + \beginning of line | \new last same \new end of line + \new first difference + + All are character pointers for the sake of speed. Special cases for + no differences, as well as for end of line additions must be handled. + + Could be made even smarter, but this works well enough */ +static void +update_line (old, new, current_line, omax, nmax, inv_botlin) + register char *old, *new; + int current_line, omax, nmax, inv_botlin; +{ + register char *ofd, *ols, *oe, *nfd, *nls, *ne; + int temp, lendiff, wsatend, od, nd; + int current_invis_chars; + int col_lendiff, col_temp; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps_new, ps_old; + int new_offset, old_offset, tmp; +#endif + + /* If we're at the right edge of a terminal that supports xn, we're + ready to wrap around, so do so. This fixes problems with knowing + the exact cursor position and cut-and-paste with certain terminal + emulators. In this calculation, TEMP is the physical screen + position of the cursor. */ + temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); + if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode + && _rl_last_v_pos == current_line - 1) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + wchar_t wc; + mbstate_t ps; + int tempwidth, bytes; + size_t ret; + + /* This fixes only double-column characters, but if the wrapped + character comsumes more than three columns, spaces will be + inserted in the string buffer. */ + if (_rl_wrapped_line[current_line] > 0) + _rl_clear_to_eol (_rl_wrapped_line[current_line]); + + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); + if (MB_INVALIDCH (ret)) + { + tempwidth = 1; + ret = 1; + } + else if (MB_NULLWCH (ret)) + tempwidth = 0; + else + tempwidth = wcwidth (wc); + + if (tempwidth > 0) + { + int count; + bytes = ret; + for (count = 0; count < bytes; count++) + putc (new[count], rl_outstream); + _rl_last_c_pos = tempwidth; + _rl_last_v_pos++; + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps); + if (ret != 0 && bytes != 0) + { + if (MB_INVALIDCH (ret)) + memmove (old+bytes, old+1, strlen (old+1)); + else + memmove (old+bytes, old+ret, strlen (old+ret)); + memcpy (old, new, bytes); + } + } + else + { + putc (' ', rl_outstream); + _rl_last_c_pos = 1; + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + } + else +#endif + { + if (new[0]) + putc (new[0], rl_outstream); + else + putc (' ', rl_outstream); + _rl_last_c_pos = 1; /* XXX */ + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + } + + + /* Find first difference. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + /* See if the old line is a subset of the new line, so that the + only change is adding characters. */ + temp = (omax < nmax) ? omax : nmax; + if (memcmp (old, new, temp) == 0) + { + ofd = old + temp; + nfd = new + temp; + } + else + { + memset (&ps_new, 0, sizeof(mbstate_t)); + memset (&ps_old, 0, sizeof(mbstate_t)); + + if (omax == nmax && STREQN (new, old, omax)) + { + ofd = old + omax; + nfd = new + nmax; + } + else + { + new_offset = old_offset = 0; + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && + _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) + { + old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); + new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); + ofd = old + old_offset; + nfd = new + new_offset; + } + } + } + } + else +#endif + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && (*ofd == *nfd); + ofd++, nfd++) + ; + + /* Move to the end of the screen line. ND and OD are used to keep track + of the distance between ne and new and oe and old, respectively, to + move a subtraction out of each loop. */ + for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++); + for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++); + + /* If no difference, continue to next line. */ + if (ofd == oe && nfd == ne) + return; + + wsatend = 1; /* flag for trailing whitespace */ + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY); + while ((ols > ofd) && (nls > nfd)) + { + memset (&ps_old, 0, sizeof (mbstate_t)); + memset (&ps_new, 0, sizeof (mbstate_t)); + +#if 0 + /* On advice from jir@yamato.ibm.com */ + _rl_adjust_point (old, ols - old, &ps_old); + _rl_adjust_point (new, nls - new, &ps_new); +#endif + + if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0) + break; + + if (*ols == ' ') + wsatend = 0; + + ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY); + } + } + else + { +#endif /* HANDLE_MULTIBYTE */ + ols = oe - 1; /* find last same */ + nls = ne - 1; + while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) + { + if (*ols != ' ') + wsatend = 0; + ols--; + nls--; + } +#if defined (HANDLE_MULTIBYTE) + } +#endif + + if (wsatend) + { + ols = oe; + nls = ne; + } +#if defined (HANDLE_MULTIBYTE) + /* This may not work for stateful encoding, but who cares? To handle + stateful encoding properly, we have to scan each string from the + beginning and compare. */ + else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0) +#else + else if (*ols != *nls) +#endif + { + if (*ols) /* don't step past the NUL */ + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY); + else + ols++; + } + if (*nls) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY); + else + nls++; + } + } + + /* count of invisible characters in the current invisible line. */ + current_invis_chars = W_OFFSET (current_line, wrap_offset); + if (_rl_last_v_pos != current_line) + { + _rl_move_vert (current_line); + if (current_line == 0 && visible_wrap_offset) + _rl_last_c_pos += visible_wrap_offset; + } + + /* If this is the first line and there are invisible characters in the + prompt string, and the prompt string has not changed, and the current + cursor position is before the last invisible character in the prompt, + and the index of the character to move to is past the end of the prompt + string, then redraw the entire prompt string. We can only do this + reliably if the terminal supports a `cr' capability. + + This is not an efficiency hack -- there is a problem with redrawing + portions of the prompt string if they contain terminal escape + sequences (like drawing the `unbold' sequence without a corresponding + `bold') that manifests itself on certain terminals. */ + + lendiff = local_prompt ? strlen (local_prompt) : 0; + od = ofd - old; /* index of first difference in visible line */ + if (current_line == 0 && !_rl_horizontal_scroll_mode && + _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 && + od >= lendiff && _rl_last_c_pos <= prompt_last_invisible) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_output_some_chars (local_prompt, lendiff); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff); + else + _rl_last_c_pos = lendiff; + } + + _rl_move_cursor_relative (od, old); + + /* if (len (new) > len (old)) + lendiff == difference in buffer + col_lendiff == difference on screen + When not using multibyte characters, these are equal */ + lendiff = (nls - nfd) - (ols - ofd); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old); + else + col_lendiff = lendiff; + + /* If we are changing the number of invisible characters in a line, and + the spot of first difference is before the end of the invisible chars, + lendiff needs to be adjusted. */ + if (current_line == 0 && !_rl_horizontal_scroll_mode && + current_invis_chars != visible_wrap_offset) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff += visible_wrap_offset - current_invis_chars; + } + else + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff = lendiff; + } + } + + /* Insert (diff (len (old), len (new)) ch. */ + temp = ne - nfd; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_temp = _rl_col_width (new, nfd - new, ne - new); + else + col_temp = temp; + + if (col_lendiff > 0) /* XXX - was lendiff */ + { + /* Non-zero if we're increasing the number of lines. */ + int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; + /* Sometimes it is cheaper to print the characters rather than + use the terminal's capabilities. If we're growing the number + of lines, make sure we actually cause the new line to wrap + around on auto-wrapping terminals. */ + if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) + { + /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and + _rl_horizontal_scroll_mode == 1, inserting the characters with + _rl_term_IC or _rl_term_ic will screw up the screen because of the + invisible characters. We need to just draw them. */ + if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 || + lendiff <= prompt_visible_length || !current_invis_chars)) + { + insert_some_chars (nfd, lendiff, col_lendiff); + _rl_last_c_pos += col_lendiff; + } + else if (*ols == 0 && lendiff > 0) + { + /* At the end of a line the characters do not have to + be "inserted". They can just be placed on the screen. */ + /* However, this screws up the rest of this block, which + assumes you've done the insert because you can. */ + _rl_output_some_chars (nfd, lendiff); + _rl_last_c_pos += col_lendiff; + } + else + { + /* We have horizontal scrolling and we are not inserting at + the end. We have invisible characters in this line. This + is a dumb update. */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + return; + } + /* Copy (new) chars to screen from first diff to last match. */ + temp = nls - nfd; + if ((temp - lendiff) > 0) + { + _rl_output_some_chars (nfd + lendiff, temp - lendiff); +#if 1 + /* XXX -- this bears closer inspection. Fixes a redisplay bug + reported against bash-3.0-alpha by Andreas Schwab involving + multibyte characters and prompt strings with invisible + characters, but was previously disabled. */ + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); +#else + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff); +#endif + } + } + else + { + /* cannot insert chars, write to EOL */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + } + } + else /* Delete characters from line. */ + { + /* If possible and inexpensive to use terminal deletion, then do so. */ + if (_rl_term_dc && (2 * col_temp) >= -col_lendiff) + { + /* If all we're doing is erasing the invisible characters in the + prompt string, don't bother. It screws up the assumptions + about what's on the screen. */ + if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 && + -lendiff == visible_wrap_offset) + col_lendiff = 0; + + if (col_lendiff) + delete_chars (-col_lendiff); /* delete (diff) characters */ + + /* Copy (new) chars to screen from first diff to last match */ + temp = nls - nfd; + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += _rl_col_width (nfd, 0, temp);; + } + } + /* Otherwise, print over the existing material. */ + else + { + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + } + lendiff = (oe - old) - (ne - new); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new); + else + col_lendiff = lendiff; + + if (col_lendiff) + { + if (_rl_term_autowrap && current_line < inv_botlin) + space_to_eol (col_lendiff); + else + _rl_clear_to_eol (col_lendiff); + } + } + } +} + +/* Tell the update routines that we have moved onto a new (empty) line. */ +int +rl_on_new_line () +{ + if (visible_line) + visible_line[0] = '\0'; + + _rl_last_c_pos = _rl_last_v_pos = 0; + _rl_vis_botlin = last_lmargin = 0; + if (vis_lbreaks) + vis_lbreaks[0] = vis_lbreaks[1] = 0; + visible_wrap_offset = 0; + return 0; +} + +/* Tell the update routines that we have moved onto a new line with the + prompt already displayed. Code originally from the version of readline + distributed with CLISP. */ +int +rl_on_new_line_with_prompt () +{ + int prompt_size, i, l, real_screenwidth, newlines; + char *prompt_last_line; + + /* Initialize visible_line and invisible_line to ensure that they can hold + the already-displayed prompt. */ + prompt_size = strlen (rl_prompt) + 1; + init_line_structures (prompt_size); + + /* Make sure the line structures hold the already-displayed prompt for + redisplay. */ + strcpy (visible_line, rl_prompt); + strcpy (invisible_line, rl_prompt); + + /* If the prompt contains newlines, take the last tail. */ + prompt_last_line = strrchr (rl_prompt, '\n'); + if (!prompt_last_line) + prompt_last_line = rl_prompt; + + l = strlen (prompt_last_line); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l); + else + _rl_last_c_pos = l; + + /* Dissect prompt_last_line into screen lines. Note that here we have + to use the real screenwidth. Readline's notion of screenwidth might be + one less, see terminal.c. */ + real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1); + _rl_last_v_pos = l / real_screenwidth; + /* If the prompt length is a multiple of real_screenwidth, we don't know + whether the cursor is at the end of the last line, or already at the + beginning of the next line. Output a newline just to be safe. */ + if (l > 0 && (l % real_screenwidth) == 0) + _rl_output_some_chars ("\n", 1); + last_lmargin = 0; + + newlines = 0; i = 0; + while (i <= l) + { + _rl_vis_botlin = newlines; + vis_lbreaks[newlines++] = i; + i += real_screenwidth; + } + vis_lbreaks[newlines] = l; + visible_wrap_offset = 0; + + return 0; +} + +/* Actually update the display, period. */ +int +rl_forced_update_display () +{ + if (visible_line) + { + register char *temp = visible_line; + + while (*temp) + *temp++ = '\0'; + } + rl_on_new_line (); + forced_display++; + (*rl_redisplay_function) (); + return 0; +} + +/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices. + DATA is the contents of the screen line of interest; i.e., where + the movement is being done. */ +void +_rl_move_cursor_relative (new, data) + int new; + const char *data; +{ + register int i; + + /* If we don't have to do anything, then return. */ +#if defined (HANDLE_MULTIBYTE) + /* If we have multibyte characters, NEW is indexed by the buffer point in + a multibyte string, but _rl_last_c_pos is the display position. In + this case, NEW's display position is not obvious and must be + calculated. */ + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { + if (_rl_last_c_pos == new) + return; + } + else if (_rl_last_c_pos == _rl_col_width (data, 0, new)) + return; +#else + if (_rl_last_c_pos == new) return; +#endif + + /* It may be faster to output a CR, and then move forwards instead + of moving backwards. */ + /* i == current physical cursor position. */ + i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); + if (new == 0 || CR_FASTER (new, _rl_last_c_pos) || + (_rl_term_autowrap && i == _rl_screenwidth)) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif /* !__MSDOS__ */ + _rl_last_c_pos = 0; + } + + if (_rl_last_c_pos < new) + { + /* Move the cursor forward. We do it by printing the command + to move the cursor forward if there is one, else print that + portion of the output buffer again. Which is cheaper? */ + + /* The above comment is left here for posterity. It is faster + to print one character (non-control) than to print a control + sequence telling the terminal to move forward one character. + That kind of control is for people who don't know what the + data is underneath the cursor. */ +#if defined (HACK_TERMCAP_MOTION) + if (_rl_term_forward_char) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int width; + width = _rl_col_width (data, _rl_last_c_pos, new); + for (i = 0; i < width; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + else + { + for (i = _rl_last_c_pos; i < new; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + } + else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); + +#else /* !HACK_TERMCAP_MOTION */ + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); + +#endif /* !HACK_TERMCAP_MOTION */ + + } +#if defined (HANDLE_MULTIBYTE) + /* NEW points to the buffer point, but _rl_last_c_pos is the display point. + The byte length of the string is probably bigger than the column width + of the string, which means that if NEW == _rl_last_c_pos, then NEW's + display point is less than _rl_last_c_pos. */ + else if (_rl_last_c_pos >= new) +#else + else if (_rl_last_c_pos > new) +#endif + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_backspace (_rl_last_c_pos - _rl_col_width (data, 0, new)); + else + _rl_backspace (_rl_last_c_pos - new); + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (data, 0, new); + else + _rl_last_c_pos = new; +} + +/* PWP: move the cursor up or down. */ +void +_rl_move_vert (to) + int to; +{ + register int delta, i; + + if (_rl_last_v_pos == to || to > _rl_screenheight) + return; + + if ((delta = to - _rl_last_v_pos) > 0) + { + for (i = 0; i < delta; i++) + putc ('\n', rl_outstream); +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; + } + else + { /* delta < 0 */ + if (_rl_term_up && *_rl_term_up) + for (i = 0; i < -delta; i++) + tputs (_rl_term_up, 1, _rl_output_character_function); + } + + _rl_last_v_pos = to; /* Now TO is here */ +} + +/* Physically print C on rl_outstream. This is for functions which know + how to optimize the display. Return the number of characters output. */ +int +rl_show_char (c) + int c; +{ + int n = 1; + if (META_CHAR (c) && (_rl_output_meta_chars == 0)) + { + fprintf (rl_outstream, "M-"); + n += 2; + c = UNMETA (c); + } + +#if defined (DISPLAY_TABS) + if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT) +#else + if (CTRL_CHAR (c) || c == RUBOUT) +#endif /* !DISPLAY_TABS */ + { + fprintf (rl_outstream, "C-"); + n += 2; + c = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + } + + putc (c, rl_outstream); + fflush (rl_outstream); + return n; +} + +int +rl_character_len (c, pos) + register int c, pos; +{ + unsigned char uc; + + uc = (unsigned char)c; + + if (META_CHAR (uc)) + return ((_rl_output_meta_chars == 0) ? 4 : 1); + + if (uc == '\t') + { +#if defined (DISPLAY_TABS) + return (((pos | 7) + 1) - pos); +#else + return (2); +#endif /* !DISPLAY_TABS */ + } + + if (CTRL_CHAR (c) || c == RUBOUT) + return (2); + + return ((ISPRINT (uc)) ? 1 : 2); +} + +/* How to print things in the "echo-area". The prompt is treated as a + mini-modeline. */ + +#if defined (USE_VARARGS) +int +#if defined (PREFER_STDARG) +rl_message (const char *format, ...) +#else +rl_message (va_alist) + va_dcl +#endif +{ + va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); + format = va_arg (args, char *); +#endif + +#if defined (HAVE_VSNPRINTF) + vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args); +#else + vsprintf (msg_buf, format, args); + msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ +#endif + va_end (args); + + rl_display_prompt = msg_buf; + (*rl_redisplay_function) (); + return 0; +} +#else /* !USE_VARARGS */ +int +rl_message (format, arg1, arg2) + char *format; +{ + sprintf (msg_buf, format, arg1, arg2); + msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ + rl_display_prompt = msg_buf; + (*rl_redisplay_function) (); + return 0; +} +#endif /* !USE_VARARGS */ + +/* How to clear things from the "echo-area". */ +int +rl_clear_message () +{ + rl_display_prompt = rl_prompt; + (*rl_redisplay_function) (); + return 0; +} + +int +rl_reset_line_state () +{ + rl_on_new_line (); + + rl_display_prompt = rl_prompt ? rl_prompt : ""; + forced_display = 1; + return 0; +} + +/* These are getting numerous enough that it's time to create a struct. */ + +static char *saved_local_prompt; +static char *saved_local_prefix; +static int saved_last_invisible; +static int saved_visible_length; +static int saved_invis_chars_first_line; + +void +rl_save_prompt () +{ + saved_local_prompt = local_prompt; + saved_local_prefix = local_prompt_prefix; + saved_last_invisible = prompt_last_invisible; + saved_visible_length = prompt_visible_length; + saved_invis_chars_first_line = prompt_invis_chars_first_line; + + local_prompt = local_prompt_prefix = (char *)0; + prompt_last_invisible = prompt_visible_length = 0; + prompt_invis_chars_first_line = 0; +} + +void +rl_restore_prompt () +{ + FREE (local_prompt); + FREE (local_prompt_prefix); + + local_prompt = saved_local_prompt; + local_prompt_prefix = saved_local_prefix; + prompt_last_invisible = saved_last_invisible; + prompt_visible_length = saved_visible_length; + prompt_invis_chars_first_line = saved_invis_chars_first_line; +} + +char * +_rl_make_prompt_for_search (pchar) + int pchar; +{ + int len; + char *pmt; + + rl_save_prompt (); + + if (saved_local_prompt == 0) + { + len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; + pmt = (char *)xmalloc (len + 2); + if (len) + strcpy (pmt, rl_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + } + else + { + len = *saved_local_prompt ? strlen (saved_local_prompt) : 0; + pmt = (char *)xmalloc (len + 2); + if (len) + strcpy (pmt, saved_local_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + local_prompt = savestring (pmt); + prompt_last_invisible = saved_last_invisible; + prompt_visible_length = saved_visible_length + 1; + } + return pmt; +} + +/* Quick redisplay hack when erasing characters at the end of the line. */ +void +_rl_erase_at_end_of_line (l) + int l; +{ + register int i; + + _rl_backspace (l); + for (i = 0; i < l; i++) + putc (' ', rl_outstream); + _rl_backspace (l); + for (i = 0; i < l; i++) + visible_line[--_rl_last_c_pos] = '\0'; + rl_display_fixed++; +} + +/* Clear to the end of the line. COUNT is the minimum + number of character spaces to clear, */ +void +_rl_clear_to_eol (count) + int count; +{ + if (_rl_term_clreol) + tputs (_rl_term_clreol, 1, _rl_output_character_function); + else if (count) + space_to_eol (count); +} + +/* Clear to the end of the line using spaces. COUNT is the minimum + number of character spaces to clear, */ +static void +space_to_eol (count) + int count; +{ + register int i; + + for (i = 0; i < count; i++) + putc (' ', rl_outstream); + + _rl_last_c_pos += count; +} + +void +_rl_clear_screen () +{ + if (_rl_term_clrpag) + tputs (_rl_term_clrpag, 1, _rl_output_character_function); + else + rl_crlf (); +} + +/* Insert COUNT characters from STRING to the output stream at column COL. */ +static void +insert_some_chars (string, count, col) + char *string; + int count, col; +{ + /* DEBUGGING */ + if (MB_CUR_MAX == 1 || rl_byte_oriented) + if (count != col) + fprintf(stderr, "readline: debug: insert_some_chars: count (%d) != col (%d)\n", count, col); + + /* If IC is defined, then we do not have to "enter" insert mode. */ + if (_rl_term_IC) + { + char *buffer; + + buffer = tgoto (_rl_term_IC, 0, col); + tputs (buffer, 1, _rl_output_character_function); + _rl_output_some_chars (string, count); + } + else + { + register int i; + + /* If we have to turn on insert-mode, then do so. */ + if (_rl_term_im && *_rl_term_im) + tputs (_rl_term_im, 1, _rl_output_character_function); + + /* If there is a special command for inserting characters, then + use that first to open up the space. */ + if (_rl_term_ic && *_rl_term_ic) + { + for (i = col; i--; ) + tputs (_rl_term_ic, 1, _rl_output_character_function); + } + + /* Print the text. */ + _rl_output_some_chars (string, count); + + /* If there is a string to turn off insert mode, we had best use + it now. */ + if (_rl_term_ei && *_rl_term_ei) + tputs (_rl_term_ei, 1, _rl_output_character_function); + } +} + +/* Delete COUNT characters from the display line. */ +static void +delete_chars (count) + int count; +{ + if (count > _rl_screenwidth) /* XXX */ + return; + + if (_rl_term_DC && *_rl_term_DC) + { + char *buffer; + buffer = tgoto (_rl_term_DC, count, count); + tputs (buffer, count, _rl_output_character_function); + } + else + { + if (_rl_term_dc && *_rl_term_dc) + while (count--) + tputs (_rl_term_dc, 1, _rl_output_character_function); + } +} + +void +_rl_update_final () +{ + int full_lines; + + full_lines = 0; + /* If the cursor is the only thing on an otherwise-blank last line, + compensate so we don't print an extra CRLF. */ + if (_rl_vis_botlin && _rl_last_c_pos == 0 && + visible_line[vis_lbreaks[_rl_vis_botlin]] == 0) + { + _rl_vis_botlin--; + full_lines = 1; + } + _rl_move_vert (_rl_vis_botlin); + /* If we've wrapped lines, remove the final xterm line-wrap flag. */ + if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth)) + { + char *last_line; + + last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]]; + _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); + _rl_clear_to_eol (0); + putc (last_line[_rl_screenwidth - 1], rl_outstream); + } + _rl_vis_botlin = 0; + rl_crlf (); + fflush (rl_outstream); + rl_display_fixed++; +} + +/* Move to the start of the current line. */ +static void +cr () +{ + if (_rl_term_cr) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; + } +} + +/* Redraw the last line of a multi-line prompt that may possibly contain + terminal escape sequences. Called with the cursor at column 0 of the + line to draw the prompt on. */ +static void +redraw_prompt (t) + char *t; +{ + char *oldp, *oldl, *oldlprefix; + int oldlen, oldlast, oldplen, oldninvis, oldphyschars; + + /* Geez, I should make this a struct. */ + oldp = rl_display_prompt; + oldl = local_prompt; + oldlprefix = local_prompt_prefix; + oldlen = prompt_visible_length; + oldplen = prompt_prefix_length; + oldlast = prompt_last_invisible; + oldninvis = prompt_invis_chars_first_line; + oldphyschars = prompt_physical_chars; + + rl_display_prompt = t; + local_prompt = expand_prompt (t, &prompt_visible_length, + &prompt_last_invisible, + &prompt_invis_chars_first_line, + &prompt_physical_chars); + local_prompt_prefix = (char *)NULL; + rl_forced_update_display (); + + rl_display_prompt = oldp; + local_prompt = oldl; + local_prompt_prefix = oldlprefix; + prompt_visible_length = oldlen; + prompt_prefix_length = oldplen; + prompt_last_invisible = oldlast; + prompt_invis_chars_first_line = oldninvis; + prompt_physical_chars = oldphyschars; +} + +/* Redisplay the current line after a SIGWINCH is received. */ +void +_rl_redisplay_after_sigwinch () +{ + char *t; + + /* Clear the current line and put the cursor at column 0. Make sure + the right thing happens if we have wrapped to a new screen line. */ + if (_rl_term_cr) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; +#if defined (__MSDOS__) + space_to_eol (_rl_screenwidth); + putc ('\r', rl_outstream); +#else + if (_rl_term_clreol) + tputs (_rl_term_clreol, 1, _rl_output_character_function); + else + { + space_to_eol (_rl_screenwidth); + tputs (_rl_term_cr, 1, _rl_output_character_function); + } +#endif + if (_rl_last_v_pos > 0) + _rl_move_vert (0); + } + else + rl_crlf (); + + /* Redraw only the last line of a multi-line prompt. */ + t = strrchr (rl_display_prompt, '\n'); + if (t) + redraw_prompt (++t); + else + rl_forced_update_display (); +} + +void +_rl_clean_up_for_exit () +{ + if (readline_echoing_p) + { + _rl_move_vert (_rl_vis_botlin); + _rl_vis_botlin = 0; + fflush (rl_outstream); + rl_restart_output (1, 0); + } +} + +void +_rl_erase_entire_line () +{ + cr (); + _rl_clear_to_eol (0); + cr (); + fflush (rl_outstream); +} + +/* return the `current display line' of the cursor -- the number of lines to + move up to get to the first screen line of the current readline line. */ +int +_rl_current_display_line () +{ + int ret, nleft; + + /* Find out whether or not there might be invisible characters in the + editing buffer. */ + if (rl_display_prompt == rl_prompt) + nleft = _rl_last_c_pos - _rl_screenwidth - rl_visible_prompt_length; + else + nleft = _rl_last_c_pos - _rl_screenwidth; + + if (nleft > 0) + ret = 1 + nleft / _rl_screenwidth; + else + ret = 0; + + return ret; +} + +#if defined (HANDLE_MULTIBYTE) +/* Calculate the number of screen columns occupied by STR from START to END. + In the case of multibyte characters with stateful encoding, we have to + scan from the beginning of the string to take the state into account. */ +static int +_rl_col_width (str, start, end) + const char *str; + int start, end; +{ + wchar_t wc; + mbstate_t ps = {0}; + int tmp, point, width, max; + + if (end <= start) + return 0; + + point = 0; + max = end; + + while (point < start) + { + tmp = mbrlen (str + point, max, &ps); + if (MB_INVALIDCH ((size_t)tmp)) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (MB_NULLWCH (tmp)) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + } + } + + /* If START is not a byte that starts a character, then POINT will be + greater than START. In this case, assume that (POINT - START) gives + a byte count that is the number of columns of difference. */ + width = point - start; + + while (point < end) + { + tmp = mbrtowc (&wc, str + point, max, &ps); + if (MB_INVALIDCH ((size_t)tmp)) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* and assume that the byte occupies a single column. */ + width++; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (MB_NULLWCH (tmp)) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + tmp = wcwidth(wc); + width += (tmp >= 0) ? tmp : 1; + } + } + + width += point - end; + + return width; +} +#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c index a9cac9d0..2ab34cba 100644 --- a/lib/readline/histexpand.c +++ b/lib/readline/histexpand.c @@ -1,6 +1,6 @@ /* histexpand.c -- history expansion. */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1989-2004 Free Software Foundation, Inc. This file contains the GNU History Library (the Library), a set of routines for managing the text of previously typed lines. @@ -1220,7 +1220,9 @@ history_expand (hstring, output) if (only_printing) { +#if 0 add_history (result); +#endif return (2); } diff --git a/lib/readline/histexpand.c~ b/lib/readline/histexpand.c~ new file mode 100644 index 00000000..9ba35d65 --- /dev/null +++ b/lib/readline/histexpand.c~ @@ -0,0 +1,1591 @@ +/* histexpand.c -- history expansion. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library 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. + + The Library 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. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# ifndef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "rlmbutil.h" + +#include "history.h" +#include "histlib.h" + +#include "rlshell.h" +#include "xmalloc.h" + +#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" +#define HISTORY_QUOTE_CHARACTERS "\"'`" + +#define slashify_in_quotes "\\`\"$" + +typedef int _hist_search_func_t PARAMS((const char *, int)); + +extern int rl_byte_oriented; /* declared in mbutil.c */ + +static char error_pointer; + +static char *subst_lhs; +static char *subst_rhs; +static int subst_lhs_len; +static int subst_rhs_len; + +static char *get_history_word_specifier PARAMS((char *, char *, int *)); +static char *history_find_word PARAMS((char *, int)); +static int history_tokenize_word PARAMS((const char *, int)); +static char *history_substring PARAMS((const char *, int, int)); + +static char *quote_breaks PARAMS((char *)); + +/* Variables exported by this file. */ +/* The character that represents the start of a history expansion + request. This is usually `!'. */ +char history_expansion_char = '!'; + +/* The character that invokes word substitution if found at the start of + a line. This is usually `^'. */ +char history_subst_char = '^'; + +/* During tokenization, if this character is seen as the first character + of a word, then it, and all subsequent characters upto a newline are + ignored. For a Bourne shell, this should be '#'. Bash special cases + the interactive comment character to not be a comment delimiter. */ +char history_comment_char = '\0'; + +/* The list of characters which inhibit the expansion of text if found + immediately following history_expansion_char. */ +char *history_no_expand_chars = " \t\n\r="; + +/* If set to a non-zero value, single quotes inhibit history expansion. + The default is 0. */ +int history_quotes_inhibit_expansion = 0; + +/* Used to split words by history_tokenize_internal. */ +char *history_word_delimiters = HISTORY_WORD_DELIMITERS; + +/* If set, this points to a function that is called to verify that a + particular history expansion should be performed. */ +rl_linebuf_func_t *history_inhibit_expansion_function; + +/* **************************************************************** */ +/* */ +/* History Expansion */ +/* */ +/* **************************************************************** */ + +/* Hairy history expansion on text, not tokens. This is of general + use, and thus belongs in this library. */ + +/* The last string searched for by a !?string? search. */ +static char *search_string; + +/* The last string matched by a !?string? search. */ +static char *search_match; + +/* Return the event specified at TEXT + OFFSET modifying OFFSET to + point to after the event specifier. Just a pointer to the history + line is returned; NULL is returned in the event of a bad specifier. + You pass STRING with *INDEX equal to the history_expansion_char that + begins this specification. + DELIMITING_QUOTE is a character that is allowed to end the string + specification for what to search for in addition to the normal + characters `:', ` ', `\t', `\n', and sometimes `?'. + So you might call this function like: + line = get_history_event ("!echo:p", &index, 0); */ +char * +get_history_event (string, caller_index, delimiting_quote) + const char *string; + int *caller_index; + int delimiting_quote; +{ + register int i; + register char c; + HIST_ENTRY *entry; + int which, sign, local_index, substring_okay; + _hist_search_func_t *search_func; + char *temp; + + /* The event can be specified in a number of ways. + + !! the previous command + !n command line N + !-n current command-line minus N + !str the most recent command starting with STR + !?str[?] + the most recent command containing STR + + All values N are determined via HISTORY_BASE. */ + + i = *caller_index; + + if (string[i] != history_expansion_char) + return ((char *)NULL); + + /* Move on to the specification. */ + i++; + + sign = 1; + substring_okay = 0; + +#define RETURN_ENTRY(e, w) \ + return ((e = history_get (w)) ? e->line : (char *)NULL) + + /* Handle !! case. */ + if (string[i] == history_expansion_char) + { + i++; + which = history_base + (history_length - 1); + *caller_index = i; + RETURN_ENTRY (entry, which); + } + + /* Hack case of numeric line specification. */ + if (string[i] == '-') + { + sign = -1; + i++; + } + + if (_rl_digit_p (string[i])) + { + /* Get the extent of the digits and compute the value. */ + for (which = 0; _rl_digit_p (string[i]); i++) + which = (which * 10) + _rl_digit_value (string[i]); + + *caller_index = i; + + if (sign < 0) + which = (history_length + history_base) - which; + + RETURN_ENTRY (entry, which); + } + + /* This must be something to search for. If the spec begins with + a '?', then the string may be anywhere on the line. Otherwise, + the string must be found at the start of a line. */ + if (string[i] == '?') + { + substring_okay++; + i++; + } + + /* Only a closing `?' or a newline delimit a substring search string. */ + for (local_index = i; c = string[i]; i++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + /* These produce warnings because we're passing a const string to a + function that takes a non-const string. */ + _rl_adjust_point ((char *)string, i, &ps); + if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1) + { + i += v - 1; + continue; + } + } + else +#endif /* HANDLE_MULTIBYTE */ + if ((!substring_okay && (whitespace (c) || c == ':' || + (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || + string[i] == delimiting_quote)) || + string[i] == '\n' || + (substring_okay && string[i] == '?')) + break; + + which = i - local_index; + temp = (char *)xmalloc (1 + which); + if (which) + strncpy (temp, string + local_index, which); + temp[which] = '\0'; + + if (substring_okay && string[i] == '?') + i++; + + *caller_index = i; + +#define FAIL_SEARCH() \ + do { \ + history_offset = history_length; free (temp) ; return (char *)NULL; \ + } while (0) + + /* If there is no search string, try to use the previous search string, + if one exists. If not, fail immediately. */ + if (*temp == '\0' && substring_okay) + { + if (search_string) + { + free (temp); + temp = savestring (search_string); + } + else + FAIL_SEARCH (); + } + + search_func = substring_okay ? history_search : history_search_prefix; + while (1) + { + local_index = (*search_func) (temp, -1); + + if (local_index < 0) + FAIL_SEARCH (); + + if (local_index == 0 || substring_okay) + { + entry = current_history (); + history_offset = history_length; + + /* If this was a substring search, then remember the + string that we matched for word substitution. */ + if (substring_okay) + { + FREE (search_string); + search_string = temp; + + FREE (search_match); + search_match = history_find_word (entry->line, local_index); + } + else + free (temp); + + return (entry->line); + } + + if (history_offset) + history_offset--; + else + FAIL_SEARCH (); + } +#undef FAIL_SEARCH +#undef RETURN_ENTRY +} + +/* Function for extracting single-quoted strings. Used for inhibiting + history expansion within single quotes. */ + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing + to the closing single quote. */ +static void +hist_string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + + for (i = *sindex; string[i] && string[i] != '\''; i++) + ; + + *sindex = i; +} + +static char * +quote_breaks (s) + char *s; +{ + register char *p, *r; + char *ret; + int len = 3; + + for (p = s; p && *p; p++, len++) + { + if (*p == '\'') + len += 3; + else if (whitespace (*p) || *p == '\n') + len += 2; + } + + r = ret = (char *)xmalloc (len); + *r++ = '\''; + for (p = s; p && *p; ) + { + if (*p == '\'') + { + *r++ = '\''; + *r++ = '\\'; + *r++ = '\''; + *r++ = '\''; + p++; + } + else if (whitespace (*p) || *p == '\n') + { + *r++ = '\''; + *r++ = *p++; + *r++ = '\''; + } + else + *r++ = *p++; + } + *r++ = '\''; + *r = '\0'; + return ret; +} + +static char * +hist_error(s, start, current, errtype) + char *s; + int start, current, errtype; +{ + char *temp; + const char *emsg; + int ll, elen; + + ll = current - start; + + switch (errtype) + { + case EVENT_NOT_FOUND: + emsg = "event not found"; + elen = 15; + break; + case BAD_WORD_SPEC: + emsg = "bad word specifier"; + elen = 18; + break; + case SUBST_FAILED: + emsg = "substitution failed"; + elen = 19; + break; + case BAD_MODIFIER: + emsg = "unrecognized history modifier"; + elen = 29; + break; + case NO_PREV_SUBST: + emsg = "no previous substitution"; + elen = 24; + break; + default: + emsg = "unknown expansion error"; + elen = 23; + break; + } + + temp = (char *)xmalloc (ll + elen + 3); + strncpy (temp, s + start, ll); + temp[ll] = ':'; + temp[ll + 1] = ' '; + strcpy (temp + ll + 2, emsg); + return (temp); +} + +/* Get a history substitution string from STR starting at *IPTR + and return it. The length is returned in LENPTR. + + A backslash can quote the delimiter. If the string is the + empty string, the previous pattern is used. If there is + no previous pattern for the lhs, the last history search + string is used. + + If IS_RHS is 1, we ignore empty strings and set the pattern + to "" anyway. subst_lhs is not changed if the lhs is empty; + subst_rhs is allowed to be set to the empty string. */ + +static char * +get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) + char *str; + int *iptr, delimiter, is_rhs, *lenptr; +{ + register int si, i, j, k; + char *s; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; +#endif + + s = (char *)NULL; + i = *iptr; + +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); + _rl_adjust_point (str, i, &ps); +#endif + + for (si = i; str[si] && str[si] != delimiter; si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + if ((v = _rl_get_char_len (str + si, &ps)) > 1) + si += v - 1; + else if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + + if (si > i || is_rhs) + { + s = (char *)xmalloc (si - i + 1); + for (j = 0, k = i; k < si; j++, k++) + { + /* Remove a backslash quoting the search string delimiter. */ + if (str[k] == '\\' && str[k + 1] == delimiter) + k++; + s[j] = str[k]; + } + s[j] = '\0'; + if (lenptr) + *lenptr = j; + } + + i = si; + if (str[i]) + i++; + *iptr = i; + + return s; +} + +static void +postproc_subst_rhs () +{ + char *new; + int i, j, new_size; + + new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len); + for (i = j = 0; i < subst_rhs_len; i++) + { + if (subst_rhs[i] == '&') + { + if (j + subst_lhs_len >= new_size) + new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len)); + strcpy (new + j, subst_lhs); + j += subst_lhs_len; + } + else + { + /* a single backslash protects the `&' from lhs interpolation */ + if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&') + i++; + if (j >= new_size) + new = (char *)xrealloc (new, new_size *= 2); + new[j++] = subst_rhs[i]; + } + } + new[j] = '\0'; + free (subst_rhs); + subst_rhs = new; + subst_rhs_len = j; +} + +/* Expand the bulk of a history specifier starting at STRING[START]. + Returns 0 if everything is OK, -1 if an error occurred, and 1 + if the `p' modifier was supplied and the caller should just print + the returned string. Returns the new index into string in + *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */ +static int +history_expand_internal (string, start, end_index_ptr, ret_string, current_line) + char *string; + int start, *end_index_ptr; + char **ret_string; + char *current_line; /* for !# */ +{ + int i, n, starting_index; + int substitute_globally, subst_bywords, want_quotes, print_only; + char *event, *temp, *result, *tstr, *t, c, *word_spec; + int result_len; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + result = (char *)xmalloc (result_len = 128); + + i = start; + + /* If it is followed by something that starts a word specifier, + then !! is implied as the event specifier. */ + + if (member (string[i + 1], ":$*%^")) + { + char fake_s[3]; + int fake_i = 0; + i++; + fake_s[0] = fake_s[1] = history_expansion_char; + fake_s[2] = '\0'; + event = get_history_event (fake_s, &fake_i, 0); + } + else if (string[i + 1] == '#') + { + i += 2; + event = current_line; + } + else + { + int quoted_search_delimiter = 0; + + /* If the character before this `!' is a double or single + quote, then this expansion takes place inside of the + quoted string. If we have to search for some text ("!foo"), + allow the delimiter to end the search string. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int c, l; + l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY); + c = string[l]; + /* XXX - original patch had i - 1 ??? If i == 0 it would fail. */ + if (i && (c == '\'' || c == '"')) + quoted_search_delimiter = c; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) + quoted_search_delimiter = string[i - 1]; + + event = get_history_event (string, &i, quoted_search_delimiter); + } + + if (event == 0) + { + *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); + free (result); + return (-1); + } + + /* If a word specifier is found, then do what that requires. */ + starting_index = i; + word_spec = get_history_word_specifier (string, event, &i); + + /* There is no such thing as a `malformed word specifier'. However, + it is possible for a specifier that has no match. In that case, + we complain. */ + if (word_spec == (char *)&error_pointer) + { + *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); + free (result); + return (-1); + } + + /* If no word specifier, than the thing of interest was the event. */ + temp = word_spec ? savestring (word_spec) : savestring (event); + FREE (word_spec); + + /* Perhaps there are other modifiers involved. Do what they say. */ + want_quotes = substitute_globally = subst_bywords = print_only = 0; + starting_index = i; + + while (string[i] == ':') + { + c = string[i + 1]; + + if (c == 'g' || c == 'a') + { + substitute_globally = 1; + i++; + c = string[i + 1]; + } + else if (c == 'G') + { + subst_bywords = 1; + i++; + c = string[i + 1]; + } + + switch (c) + { + default: + *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); + free (result); + free (temp); + return -1; + + case 'q': + want_quotes = 'q'; + break; + + case 'x': + want_quotes = 'x'; + break; + + /* :p means make this the last executed line. So we + return an error state after adding this line to the + history. */ + case 'p': + print_only++; + break; + + /* :t discards all but the last part of the pathname. */ + case 't': + tstr = strrchr (temp, '/'); + if (tstr) + { + tstr++; + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :h discards the last part of a pathname. */ + case 'h': + tstr = strrchr (temp, '/'); + if (tstr) + *tstr = '\0'; + break; + + /* :r discards the suffix. */ + case 'r': + tstr = strrchr (temp, '.'); + if (tstr) + *tstr = '\0'; + break; + + /* :e discards everything but the suffix. */ + case 'e': + tstr = strrchr (temp, '.'); + if (tstr) + { + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :s/this/that substitutes `that' for the first + occurrence of `this'. :gs/this/that substitutes `that' + for each occurrence of `this'. :& repeats the last + substitution. :g& repeats the last substitution + globally. */ + + case '&': + case 's': + { + char *new_event; + int delimiter, failed, si, l_temp, ws, we; + + if (c == 's') + { + if (i + 2 < (int)strlen (string)) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + _rl_adjust_point (string, i + 2, &ps); + if (_rl_get_char_len (string + i + 2, &ps) > 1) + delimiter = 0; + else + delimiter = string[i + 2]; + } + else +#endif /* HANDLE_MULTIBYTE */ + delimiter = string[i + 2]; + } + else + break; /* no search delimiter */ + + i += 3; + + t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len); + /* An empty substitution lhs with no previous substitution + uses the last search string as the lhs. */ + if (t) + { + FREE (subst_lhs); + subst_lhs = t; + } + else if (!subst_lhs) + { + if (search_string && *search_string) + { + subst_lhs = savestring (search_string); + subst_lhs_len = strlen (subst_lhs); + } + else + { + subst_lhs = (char *) NULL; + subst_lhs_len = 0; + } + } + + FREE (subst_rhs); + subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len); + + /* If `&' appears in the rhs, it's supposed to be replaced + with the lhs. */ + if (member ('&', subst_rhs)) + postproc_subst_rhs (); + } + else + i += 2; + + /* If there is no lhs, the substitution can't succeed. */ + if (subst_lhs_len == 0) + { + *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST); + free (result); + free (temp); + return -1; + } + + l_temp = strlen (temp); + /* Ignore impossible cases. */ + if (subst_lhs_len > l_temp) + { + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + + /* Find the first occurrence of THIS in TEMP. */ + /* Substitute SUBST_RHS for SUBST_LHS in TEMP. There are three + cases to consider: + + 1. substitute_globally == subst_bywords == 0 + 2. substitute_globally == 1 && subst_bywords == 0 + 3. substitute_globally == 0 && subst_bywords == 1 + + In the first case, we substitute for the first occurrence only. + In the second case, we substitute for every occurrence. + In the third case, we tokenize into words and substitute the + first occurrence of each word. */ + + si = we = 0; + for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) + { + /* First skip whitespace and find word boundaries if + we're past the end of the word boundary we found + the last time. */ + if (subst_bywords && si > we) + { + for (; temp[si] && whitespace (temp[si]); si++) + ; + ws = si; + we = history_tokenize_word (temp, si); + } + + if (STREQN (temp+si, subst_lhs, subst_lhs_len)) + { + int len = subst_rhs_len - subst_lhs_len + l_temp; + new_event = (char *)xmalloc (1 + len); + strncpy (new_event, temp, si); + strncpy (new_event + si, subst_rhs, subst_rhs_len); + strncpy (new_event + si + subst_rhs_len, + temp + si + subst_lhs_len, + l_temp - (si + subst_lhs_len)); + new_event[len] = '\0'; + free (temp); + temp = new_event; + + failed = 0; + + if (substitute_globally) + { + /* Reported to fix a bug that causes it to skip every + other match when matching a single character. Was + si += subst_rhs_len previously. */ + si += subst_rhs_len - 1; + l_temp = strlen (temp); + substitute_globally++; + continue; + } + else if (subst_bywords) + { + si = we; + l_temp = strlen (temp); + continue; + } + else + break; + } + } + + if (substitute_globally > 1) + { + substitute_globally = 0; + continue; /* don't want to increment i */ + } + + if (failed == 0) + continue; /* don't want to increment i */ + + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + } + i += 2; + } + /* Done with modfiers. */ + /* Believe it or not, we have to back the pointer up by one. */ + --i; + + if (want_quotes) + { + char *x; + + if (want_quotes == 'q') + x = sh_single_quote (temp); + else if (want_quotes == 'x') + x = quote_breaks (temp); + else + x = savestring (temp); + + free (temp); + temp = x; + } + + n = strlen (temp); + if (n >= result_len) + result = (char *)xrealloc (result, n + 2); + strcpy (result, temp); + free (temp); + + *end_index_ptr = i; + *ret_string = result; + return (print_only); +} + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. Returns: + + -1) If there was an error in expansion. + 0) If no expansions took place (or, if the only change in + the text was the de-slashifying of the history expansion + character) + 1) If expansions did take place + 2) If the `p' modifier was given and the caller should print the result + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ + +#define ADD_STRING(s) \ + do \ + { \ + int sl = strlen (s); \ + j += sl; \ + if (j >= result_len) \ + { \ + while (j >= result_len) \ + result_len += 128; \ + result = (char *)xrealloc (result, result_len); \ + } \ + strcpy (result + j - sl, s); \ + } \ + while (0) + +#define ADD_CHAR(c) \ + do \ + { \ + if (j >= result_len - 1) \ + result = (char *)xrealloc (result, result_len += 64); \ + result[j++] = c; \ + result[j] = '\0'; \ + } \ + while (0) + +int +history_expand (hstring, output) + char *hstring; + char **output; +{ + register int j; + int i, r, l, passc, cc, modified, eindex, only_printing, dquote; + char *string; + + /* The output string, and its length. */ + int result_len; + char *result; + +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; + mbstate_t ps; +#endif + + /* Used when adding the string. */ + char *temp; + + if (output == 0) + return 0; + + /* Setting the history expansion character to 0 inhibits all + history expansion. */ + if (history_expansion_char == 0) + { + *output = savestring (hstring); + return (0); + } + + /* Prepare the buffer for printing error messages. */ + result = (char *)xmalloc (result_len = 256); + result[0] = '\0'; + + only_printing = modified = 0; + l = strlen (hstring); + + /* Grovel the string. Only backslash and single quotes can quote the + history escape character. We also handle arg specifiers. */ + + /* Before we grovel forever, see if the history_expansion_char appears + anywhere within the text. */ + + /* The quick substitution character is a history expansion all right. That + is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact, + that is the substitution that we do. */ + if (hstring[0] == history_subst_char) + { + string = (char *)xmalloc (l + 5); + + string[0] = string[1] = history_expansion_char; + string[2] = ':'; + string[3] = 's'; + strcpy (string + 4, hstring); + l += 4; + } + else + { +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + string = hstring; + /* If not quick substitution, still maybe have to do expansion. */ + + /* `!' followed by one of the characters in history_no_expand_chars + is NOT an expansion. */ + for (i = dquote = 0; string[i]; i++) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + v = _rl_get_char_len (string + i, &ps); + if (v > 1) + { + i += v - 1; + continue; + } + } +#endif /* HANDLE_MULTIBYTE */ + + cc = string[i + 1]; + /* The history_comment_char, if set, appearing at the beginning + of a word signifies that the rest of the line should not have + history expansion performed on it. + Skip the rest of the line and break out of the loop. */ + if (history_comment_char && string[i] == history_comment_char && + (i == 0 || member (string[i - 1], history_word_delimiters))) + { + while (string[i]) + i++; + break; + } + else if (string[i] == history_expansion_char) + { + if (!cc || member (cc, history_no_expand_chars)) + continue; + /* If the calling application has set + history_inhibit_expansion_function to a function that checks + for special cases that should not be history expanded, + call the function and skip the expansion if it returns a + non-zero value. */ + else if (history_inhibit_expansion_function && + (*history_inhibit_expansion_function) (string, i)) + continue; + else + break; + } + /* Shell-like quoting: allow backslashes to quote double quotes + inside a double-quoted string. */ + else if (dquote && string[i] == '\\' && cc == '"') + i++; + /* More shell-like quoting: if we're paying attention to single + quotes and letting them quote the history expansion character, + then we need to pay attention to double quotes, because single + quotes are not special inside double-quoted strings. */ + else if (history_quotes_inhibit_expansion && string[i] == '"') + { + dquote = 1 - dquote; + } + else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'') + { + /* If this is bash, single quotes inhibit history expansion. */ + i++; + hist_string_extract_single_quoted (string, &i); + } + else if (history_quotes_inhibit_expansion && string[i] == '\\') + { + /* If this is bash, allow backslashes to quote single + quotes and the history expansion character. */ + if (cc == '\'' || cc == history_expansion_char) + i++; + } + + } + + if (string[i] != history_expansion_char) + { + free (result); + *output = savestring (string); + return (0); + } + } + + /* Extract and perform the substitution. */ + for (passc = dquote = i = j = 0; i < l; i++) + { + int tchar = string[i]; + + if (passc) + { + passc = 0; + ADD_CHAR (tchar); + continue; + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int k, c; + + c = tchar; + memset (mb, 0, sizeof (mb)); + for (k = 0; k < MB_LEN_MAX; k++) + { + mb[k] = (char)c; + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_get_char_len (mb, &ps) == -2) + c = string[++i]; + else + break; + } + if (strlen (mb) > 1) + { + ADD_STRING (mb); + break; + } + } +#endif /* HANDLE_MULTIBYTE */ + + if (tchar == history_expansion_char) + tchar = -3; + else if (tchar == history_comment_char) + tchar = -2; + + switch (tchar) + { + default: + ADD_CHAR (string[i]); + break; + + case '\\': + passc++; + ADD_CHAR (tchar); + break; + + case '"': + dquote = 1 - dquote; + ADD_CHAR (tchar); + break; + + case '\'': + { + /* If history_quotes_inhibit_expansion is set, single quotes + inhibit history expansion. */ + if (dquote == 0 && history_quotes_inhibit_expansion) + { + int quote, slen; + + quote = i++; + hist_string_extract_single_quoted (string, &i); + + slen = i - quote + 2; + temp = (char *)xmalloc (slen); + strncpy (temp, string + quote, slen); + temp[slen - 1] = '\0'; + ADD_STRING (temp); + free (temp); + } + else + ADD_CHAR (string[i]); + break; + } + + case -2: /* history_comment_char */ + if (i == 0 || member (string[i - 1], history_word_delimiters)) + { + temp = (char *)xmalloc (l - i + 1); + strcpy (temp, string + i); + ADD_STRING (temp); + free (temp); + i = l; + } + else + ADD_CHAR (string[i]); + break; + + case -3: /* history_expansion_char */ + cc = string[i + 1]; + + /* If the history_expansion_char is followed by one of the + characters in history_no_expand_chars, then it is not a + candidate for expansion of any kind. */ + if (member (cc, history_no_expand_chars)) + { + ADD_CHAR (string[i]); + break; + } + +#if defined (NO_BANG_HASH_MODIFIERS) + /* There is something that is listed as a `word specifier' in csh + documentation which means `the expanded text to this point'. + That is not a word specifier, it is an event specifier. If we + don't want to allow modifiers with `!#', just stick the current + output line in again. */ + if (cc == '#') + { + if (result) + { + temp = (char *)xmalloc (1 + strlen (result)); + strcpy (temp, result); + ADD_STRING (temp); + free (temp); + } + i++; + break; + } +#endif + + r = history_expand_internal (string, i, &eindex, &temp, result); + if (r < 0) + { + *output = temp; + free (result); + if (string != hstring) + free (string); + return -1; + } + else + { + if (temp) + { + modified++; + if (*temp) + ADD_STRING (temp); + free (temp); + } + only_printing = r == 1; + i = eindex; + } + break; + } + } + + *output = result; + if (string != hstring) + free (string); + + if (only_printing) + { +#if 0 + add_history (result); +#endif + return (2); + } + + return (modified != 0); +} + +/* Return a consed string which is the word specified in SPEC, and found + in FROM. NULL is returned if there is no spec. The address of + ERROR_POINTER is returned if the word specified cannot be found. + CALLER_INDEX is the offset in SPEC to start looking; it is updated + to point to just after the last character parsed. */ +static char * +get_history_word_specifier (spec, from, caller_index) + char *spec, *from; + int *caller_index; +{ + register int i = *caller_index; + int first, last; + int expecting_word_spec = 0; + char *result; + + /* The range of words to return doesn't exist yet. */ + first = last = 0; + result = (char *)NULL; + + /* If we found a colon, then this *must* be a word specification. If + it isn't, then it is an error. */ + if (spec[i] == ':') + { + i++; + expecting_word_spec++; + } + + /* Handle special cases first. */ + + /* `%' is the word last searched for. */ + if (spec[i] == '%') + { + *caller_index = i + 1; + return (search_match ? savestring (search_match) : savestring ("")); + } + + /* `*' matches all of the arguments, but not the command. */ + if (spec[i] == '*') + { + *caller_index = i + 1; + result = history_arg_extract (1, '$', from); + return (result ? result : savestring ("")); + } + + /* `$' is last arg. */ + if (spec[i] == '$') + { + *caller_index = i + 1; + return (history_arg_extract ('$', '$', from)); + } + + /* Try to get FIRST and LAST figured out. */ + + if (spec[i] == '-') + first = 0; + else if (spec[i] == '^') + { + first = 1; + i++; + } + else if (_rl_digit_p (spec[i]) && expecting_word_spec) + { + for (first = 0; _rl_digit_p (spec[i]); i++) + first = (first * 10) + _rl_digit_value (spec[i]); + } + else + return ((char *)NULL); /* no valid `first' for word specifier */ + + if (spec[i] == '^' || spec[i] == '*') + { + last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ + i++; + } + else if (spec[i] != '-') + last = first; + else + { + i++; + + if (_rl_digit_p (spec[i])) + { + for (last = 0; _rl_digit_p (spec[i]); i++) + last = (last * 10) + _rl_digit_value (spec[i]); + } + else if (spec[i] == '$') + { + i++; + last = '$'; + } +#if 0 + else if (!spec[i] || spec[i] == ':') + /* check against `:' because there could be a modifier separator */ +#else + else + /* csh seems to allow anything to terminate the word spec here, + leaving it as an abbreviation. */ +#endif + last = -1; /* x- abbreviates x-$ omitting word `$' */ + } + + *caller_index = i; + + if (last >= first || last == '$' || last < 0) + result = history_arg_extract (first, last, from); + + return (result ? result : (char *)&error_pointer); +} + +/* Extract the args specified, starting at FIRST, and ending at LAST. + The args are taken from STRING. If either FIRST or LAST is < 0, + then make that arg count from the right (subtract from the number of + tokens, so that FIRST = -1 means the next to last token on the line). + If LAST is `$' the last arg from STRING is used. */ +char * +history_arg_extract (first, last, string) + int first, last; + const char *string; +{ + register int i, len; + char *result; + int size, offset; + char **list; + + /* XXX - think about making history_tokenize return a struct array, + each struct in array being a string and a length to avoid the + calls to strlen below. */ + if ((list = history_tokenize (string)) == NULL) + return ((char *)NULL); + + for (len = 0; list[len]; len++) + ; + + if (last < 0) + last = len + last - 1; + + if (first < 0) + first = len + first - 1; + + if (last == '$') + last = len - 1; + + if (first == '$') + first = len - 1; + + last++; + + if (first >= len || last > len || first < 0 || last < 0 || first > last) + result = ((char *)NULL); + else + { + for (size = 0, i = first; i < last; i++) + size += strlen (list[i]) + 1; + result = (char *)xmalloc (size + 1); + result[0] = '\0'; + + for (i = first, offset = 0; i < last; i++) + { + strcpy (result + offset, list[i]); + offset += strlen (list[i]); + if (i + 1 < last) + { + result[offset++] = ' '; + result[offset] = 0; + } + } + } + + for (i = 0; i < len; i++) + free (list[i]); + free (list); + + return (result); +} + +static int +history_tokenize_word (string, ind) + const char *string; + int ind; +{ + register int i; + int delimiter; + + i = ind; + delimiter = 0; + + if (member (string[i], "()\n")) + { + i++; + return i; + } + + if (member (string[i], "<>;&|$")) + { + int peek = string[i + 1]; + + if (peek == string[i] && peek != '$') + { + if (peek == '<' && string[i + 2] == '-') + i++; + i += 2; + return i; + } + else + { + if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || + (peek == '>' && string[i] == '&') || + (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */ + (peek == '(' && string[i] == '$')) /* ) */ + { + i += 2; + return i; + } + } + + if (string[i] != '$') + { + i++; + return i; + } + } + + /* Get word from string + i; */ + + if (member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i++]; + + for (; string[i]; i++) + { + if (string[i] == '\\' && string[i + 1] == '\n') + { + i++; + continue; + } + + if (string[i] == '\\' && delimiter != '\'' && + (delimiter != '"' || member (string[i], slashify_in_quotes))) + { + i++; + continue; + } + + if (delimiter && string[i] == delimiter) + { + delimiter = 0; + continue; + } + + if (!delimiter && (member (string[i], history_word_delimiters))) + break; + + if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i]; + } + + return i; +} + +static char * +history_substring (string, start, end) + const char *string; + int start, end; +{ + register int len; + register char *result; + + len = end - start; + result = (char *)xmalloc (len + 1); + strncpy (result, string + start, len); + result[len] = '\0'; + return result; +} + +/* Parse STRING into tokens and return an array of strings. If WIND is + not -1 and INDP is not null, we also want the word surrounding index + WIND. The position in the returned array of strings is returned in + *INDP. */ +static char ** +history_tokenize_internal (string, wind, indp) + const char *string; + int wind, *indp; +{ + char **result; + register int i, start, result_index, size; + + /* If we're searching for a string that's not part of a word (e.g., " "), + make sure we set *INDP to a reasonable value. */ + if (indp && wind != -1) + *indp = -1; + + /* Get a token, and stuff it into RESULT. The tokens are split + exactly where the shell would split them. */ + for (i = result_index = size = 0, result = (char **)NULL; string[i]; ) + { + /* Skip leading whitespace. */ + for (; string[i] && whitespace (string[i]); i++) + ; + if (string[i] == 0 || string[i] == history_comment_char) + return (result); + + start = i; + + i = history_tokenize_word (string, start); + + /* If we have a non-whitespace delimiter character (which would not be + skipped by the loop above), use it and any adjacent delimiters to + make a separate field. Any adjacent white space will be skipped the + next time through the loop. */ + if (i == start && history_word_delimiters) + { + i++; + while (string[i] && member (string[i], history_word_delimiters)) + i++; + } + + /* If we are looking for the word in which the character at a + particular index falls, remember it. */ + if (indp && wind != -1 && wind >= start && wind < i) + *indp = result_index; + + if (result_index + 2 >= size) + result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); + + result[result_index++] = history_substring (string, start, i); + result[result_index] = (char *)NULL; + } + + return (result); +} + +/* Return an array of tokens, much as the shell might. The tokens are + parsed out of STRING. */ +char ** +history_tokenize (string) + const char *string; +{ + return (history_tokenize_internal (string, -1, (int *)NULL)); +} + +/* Find and return the word which contains the character at index IND + in the history line LINE. Used to save the word matched by the + last history !?string? search. */ +static char * +history_find_word (line, ind) + char *line; + int ind; +{ + char **words, *s; + int i, wind; + + words = history_tokenize_internal (line, ind, &wind); + if (wind == -1 || words == 0) + return ((char *)NULL); + s = words[wind]; + for (i = 0; i < wind; i++) + free (words[i]); + for (i = wind + 1; words[i]; i++) + free (words[i]); + free (words); + return s; +} diff --git a/lib/readline/misc.c b/lib/readline/misc.c index 05c87090..f5541235 100644 --- a/lib/readline/misc.c +++ b/lib/readline/misc.c @@ -1,6 +1,6 @@ /* misc.c -- miscellaneous bindable readline functions. */ -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -253,7 +253,9 @@ rl_maybe_unsave_line () { if (_rl_saved_line_for_history) { - rl_replace_line (_rl_saved_line_for_history->line, 1); + /* Can't call with `1' because rl_undo_list might point to an undo + list from a history entry, as in rl_replace_from_history() below. */ + rl_replace_line (_rl_saved_line_for_history->line, 0); rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; _rl_free_history_entry (_rl_saved_line_for_history); _rl_saved_line_for_history = (HIST_ENTRY *)NULL; diff --git a/lib/readline/misc.c~ b/lib/readline/misc.c~ new file mode 100644 index 00000000..00e5a61a --- /dev/null +++ b/lib/readline/misc.c~ @@ -0,0 +1,500 @@ +/* misc.c -- miscellaneous bindable readline functions. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library 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. + + The GNU Readline Library 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. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +static int rl_digit_loop PARAMS((void)); +static void _rl_history_set_point PARAMS((void)); + +/* Forward declarations used in this file */ +void _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +/* If non-zero, rl_get_previous_history and rl_get_next_history attempt + to preserve the value of rl_point from line to line. */ +int _rl_history_preserve_point = 0; + +/* Saved target point for when _rl_history_preserve_point is set. Special + value of -1 means that point is at the end of the line. */ +int _rl_history_saved_point = -1; + +/* **************************************************************** */ +/* */ +/* Numeric Arguments */ +/* */ +/* **************************************************************** */ + +/* Handle C-u style numeric args, as well as M--, and M-digits. */ +static int +rl_digit_loop () +{ + int key, c, sawminus, sawdigits; + + rl_save_prompt (); + + RL_SETSTATE(RL_STATE_NUMERICARG); + sawminus = sawdigits = 0; + while (1) + { + if (rl_numeric_arg > 1000000) + { + sawdigits = rl_explicit_arg = rl_numeric_arg = 0; + rl_ding (); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return 1; + } + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); + RL_SETSTATE(RL_STATE_MOREINPUT); + key = c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c < 0) + { + _rl_abort_internal (); + return -1; + } + + /* If we see a key bound to `universal-argument' after seeing digits, + it ends the argument but is otherwise ignored. */ + if (_rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + if (sawdigits == 0) + { + rl_numeric_arg *= 4; + continue; + } + else + { + RL_SETSTATE(RL_STATE_MOREINPUT); + key = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + c = UNMETA (c); + + if (_rl_digit_p (c)) + { + rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; + sawdigits = rl_explicit_arg = 1; + } + else if (c == '-' && rl_explicit_arg == 0) + { + rl_numeric_arg = sawminus = 1; + rl_arg_sign = -1; + } + else + { + /* Make M-- command equivalent to M--1 command. */ + if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) + rl_explicit_arg = 1; + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + /*NOTREACHED*/ +} + +/* Add the current digit to the argument in progress. */ +int +rl_digit_argument (ignore, key) + int ignore, key; +{ + rl_execute_next (key); + return (rl_digit_loop ()); +} + +/* What to do when you abort reading an argument. */ +int +rl_discard_argument () +{ + rl_ding (); + rl_clear_message (); + _rl_init_argument (); + return 0; +} + +/* Create a default argument. */ +int +_rl_init_argument () +{ + rl_numeric_arg = rl_arg_sign = 1; + rl_explicit_arg = 0; + return 0; +} + +/* C-u, universal argument. Multiply the current argument by 4. + Read a key. If the key has nothing to do with arguments, then + dispatch on it. If the key is the abort character then abort. */ +int +rl_universal_argument (count, key) + int count, key; +{ + rl_numeric_arg *= 4; + return (rl_digit_loop ()); +} + +/* **************************************************************** */ +/* */ +/* History Utilities */ +/* */ +/* **************************************************************** */ + +/* We already have a history library, and that is what we use to control + the history features of readline. This is our local interface to + the history mechanism. */ + +/* While we are editing the history, this is the saved + version of the original line. */ +HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL; + +/* Set the history pointer back to the last entry in the history. */ +void +_rl_start_using_history () +{ + using_history (); + if (_rl_saved_line_for_history) + _rl_free_history_entry (_rl_saved_line_for_history); + + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; +} + +/* Free the contents (and containing structure) of a HIST_ENTRY. */ +void +_rl_free_history_entry (entry) + HIST_ENTRY *entry; +{ + if (entry == 0) + return; + if (entry->line) + free (entry->line); + free (entry); +} + +/* Perhaps put back the current line if it has changed. */ +int +rl_maybe_replace_line () +{ + HIST_ENTRY *temp; + + temp = current_history (); + /* If the current line has changed, save the changes. */ + if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) + { + temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list); + free (temp->line); + free (temp); + } + return 0; +} + +/* Restore the _rl_saved_line_for_history if there is one. */ +int +rl_maybe_unsave_line () +{ + if (_rl_saved_line_for_history) + { + /* Can't call with `1' because rl_undo_list might point to an undo + list from a history entry, as in rl_replace_from_history() below. */ + rl_replace_line (_rl_saved_line_for_history->line, 0); + rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + rl_point = rl_end; /* rl_replace_line sets rl_end */ + } + else + rl_ding (); + return 0; +} + +/* Save the current line in _rl_saved_line_for_history. */ +int +rl_maybe_save_line () +{ + if (_rl_saved_line_for_history == 0) + { + _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + _rl_saved_line_for_history->line = savestring (rl_line_buffer); + _rl_saved_line_for_history->data = (char *)rl_undo_list; + } + return 0; +} + +int +_rl_free_saved_history_line () +{ + if (_rl_saved_line_for_history) + { + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + } + return 0; +} + +static void +_rl_history_set_point () +{ + rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) + ? _rl_history_saved_point + : rl_end; + if (rl_point > rl_end) + rl_point = rl_end; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) + rl_point = 0; +#endif /* VI_MODE */ + + if (rl_editing_mode == emacs_mode) + rl_mark = (rl_point == rl_end ? 0 : rl_end); +} + +void +rl_replace_from_history (entry, flags) + HIST_ENTRY *entry; + int flags; /* currently unused */ +{ + /* Can't call with `1' because rl_undo_list might point to an undo list + from a history entry, just like we're setting up here. */ + rl_replace_line (entry->line, 0); + rl_undo_list = (UNDO_LIST *)entry->data; + rl_point = rl_end; + rl_mark = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + { + rl_point = 0; + rl_mark = rl_end; + } +#endif +} + +/* **************************************************************** */ +/* */ +/* History Commands */ +/* */ +/* **************************************************************** */ + +/* Meta-< goes to the start of the history. */ +int +rl_beginning_of_history (count, key) + int count, key; +{ + return (rl_get_previous_history (1 + where_history (), key)); +} + +/* Meta-> goes to the end of the history. (The current line). */ +int +rl_end_of_history (count, key) + int count, key; +{ + rl_maybe_replace_line (); + using_history (); + rl_maybe_unsave_line (); + return 0; +} + +/* Move down to the next history line. */ +int +rl_get_next_history (count, key) + int count, key; +{ + HIST_ENTRY *temp; + + if (count < 0) + return (rl_get_previous_history (-count, key)); + + if (count == 0) + return 0; + + rl_maybe_replace_line (); + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = next_history (); + if (!temp) + break; + --count; + } + + if (temp == 0) + rl_maybe_unsave_line (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* Get the previous item out of our interactive history, making it the current + line. If there is no previous history, just ding. */ +int +rl_get_previous_history (count, key) + int count, key; +{ + HIST_ENTRY *old_temp, *temp; + + if (count < 0) + return (rl_get_next_history (-count, key)); + + if (count == 0) + return 0; + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + /* If we don't have a line saved, then save this one. */ + rl_maybe_save_line (); + + /* If the current line has changed, save the changes. */ + rl_maybe_replace_line (); + + temp = old_temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = previous_history (); + if (temp == 0) + break; + + old_temp = temp; + --count; + } + + /* If there was a large argument, and we moved back to the start of the + history, that is not an error. So use the last value found. */ + if (!temp && old_temp) + temp = old_temp; + + if (temp == 0) + rl_ding (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* **************************************************************** */ +/* */ +/* Editing Modes */ +/* */ +/* **************************************************************** */ +/* How to toggle back and forth between editing modes. */ +int +rl_vi_editing_mode (count, key) + int count, key; +{ +#if defined (VI_MODE) + _rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */ + rl_editing_mode = vi_mode; + rl_vi_insertion_mode (1, key); +#endif /* VI_MODE */ + + return 0; +} + +int +rl_emacs_editing_mode (count, key) + int count, key; +{ + rl_editing_mode = emacs_mode; + _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */ + _rl_keymap = emacs_standard_keymap; + return 0; +} + +/* Function for the rest of the library to use to set insert/overwrite mode. */ +void +_rl_set_insert_mode (im, force) + int im, force; +{ +#ifdef CURSOR_MODE + _rl_set_cursor (im, force); +#endif + + rl_insert_mode = im; +} + +/* Toggle overwrite mode. A positive explicit argument selects overwrite + mode. A negative or zero explicit argument selects insert mode. */ +int +rl_overwrite_mode (count, key) + int count, key; +{ + if (rl_explicit_arg == 0) + _rl_set_insert_mode (rl_insert_mode ^ 1, 0); + else if (count > 0) + _rl_set_insert_mode (RL_IM_OVERWRITE, 0); + else + _rl_set_insert_mode (RL_IM_INSERT, 0); + + return 0; +} @@ -259,7 +259,7 @@ static intmax_t parameter_brace_expand_length __P((char *)); static char *skiparith __P((char *, int)); static int verify_substring_values __P((char *, char *, int, intmax_t *, intmax_t *)); -static int get_var_and_type __P((char *, char *, SHELL_VAR **, char **)); +static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **)); static char *mb_substring __P((char *, int, int)); static char *parameter_brace_substring __P((char *, char *, char *, int)); @@ -3530,7 +3530,7 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted) this_command_name = varname; - vtype = get_var_and_type (varname, value, &v, &val); + vtype = get_var_and_type (varname, value, quoted, &v, &val); if (vtype == -1) return ((char *)NULL); @@ -4446,7 +4446,12 @@ parameter_brace_expand_word (name, var_is_special, quoted) if (legal_number (name, &arg_index)) { tt = get_dollar_var_value (arg_index); - temp = tt ? quote_escapes (tt) : (char *)NULL; + if (tt) + temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (tt) + : quote_escapes (tt); + else + temp = (char *)NULL; FREE (tt); } else if (var_is_special) /* ${@} */ @@ -4465,7 +4470,9 @@ parameter_brace_expand_word (name, var_is_special, quoted) { temp = array_value (name, quoted, &atype); if (atype == 0 && temp) - temp = quote_escapes (temp); + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : quote_escapes (temp); } #endif else if (var = find_variable (name)) @@ -4479,7 +4486,9 @@ parameter_brace_expand_word (name, var_is_special, quoted) #endif if (temp) - temp = quote_escapes (temp); + temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) + ? quote_string (temp) + : quote_escapes (temp); } else temp = (char *)NULL; @@ -4501,6 +4510,15 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c char *temp, *t; t = parameter_brace_expand_word (name, var_is_special, quoted); + /* Have to dequote here if necessary */ + if (t) + { + temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + ? dequote_string (t) + : dequote_escapes (t); + free (t); + t = temp; + } chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); if (t == 0) return (t); @@ -4895,8 +4913,9 @@ verify_substring_values (value, substr, vtype, e1p, e2p) characters in the value are quoted with CTLESC and takes appropriate steps. For convenience, *VALP is set to the dequoted VALUE. */ static int -get_var_and_type (varname, value, varp, valp) +get_var_and_type (varname, value, quoted, varp, valp) char *varname, *value; + int quoted; SHELL_VAR **varp; char **valp; { @@ -4943,7 +4962,21 @@ get_var_and_type (varname, value, varp, valp) } else #endif +#if 1 + { + if (value && vtype == VT_VARIABLE) + { + if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) + *valp = dequote_string (value); + else + *valp = dequote_escapes (value); + } + else + *valp = value; + } +#else *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value; +#endif return vtype; } @@ -5002,7 +5035,7 @@ parameter_brace_substring (varname, value, substr, quoted) this_command_name = varname; - vtype = get_var_and_type (varname, value, &v, &val); + vtype = get_var_and_type (varname, value, quoted, &v, &val); if (vtype == -1) return ((char *)NULL); @@ -5201,7 +5234,7 @@ parameter_brace_patsub (varname, value, patsub, quoted) this_command_name = varname; - vtype = get_var_and_type (varname, value, &v, &val); + vtype = get_var_and_type (varname, value, quoted, &v, &val); if (vtype == -1) return ((char *)NULL); @@ -5738,7 +5771,7 @@ param_expand (string, sindex, quoted, expanded_something, } #if 1 if (temp1) - temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) ? quote_string (temp1) : quote_escapes (temp1); else @@ -5982,7 +6015,7 @@ comsub: { temp = array_reference (array_cell (var), 0); if (temp) - temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) ? quote_string (temp) : quote_escapes (temp); else if (unbound_vars_is_error) @@ -5990,10 +6023,14 @@ comsub: } else #endif + { + temp = value_cell (var); + + temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ? quote_string (temp) + : quote_escapes (temp); + } - temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (value_cell (var)) - : quote_escapes (value_cell (var)); free (temp1); goto return0; diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 3efcf32d..72ec06a2 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/arith.right b/tests/arith.right index 5e897b69..1365786f 100644 --- a/tests/arith.right +++ b/tests/arith.right @@ -140,14 +140,64 @@ ok -7 7 7 +./arith1.sub: line 2: 4-- : syntax error: operand expected (error token is " ") +./arith1.sub: line 3: 4++ : syntax error: operand expected (error token is " ") +./arith1.sub: line 4: 4 -- : syntax error: operand expected (error token is " ") +./arith1.sub: line 5: 4 ++ : syntax error: operand expected (error token is " ") +1 +2 +1 +2 +6 +3 +7 +4 +0 +3 +7 +2 +-2 +1 +./arith1.sub: line 35: ((: ++ : syntax error: operand expected (error token is " ") +7 +7 +./arith1.sub: line 38: ((: -- : syntax error: operand expected (error token is " ") +7 +7 +7 +7 +1 +2 +1 +2 +1 +0 +5 +1 +6 +2 +3 +1 +4 +0 +./arith2.sub: line 33: ((: -- : syntax error: operand expected (error token is " ") +-7 +-7 +./arith2.sub: line 37: ((: ++ : syntax error: operand expected (error token is " ") +7 +7 +-7 +-7 +7 +7 8 12 -./arith.tests: line 265: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ") -./arith.tests: line 269: a b: syntax error in expression (error token is "b") -./arith.tests: line 270: ((: a b: syntax error in expression (error token is "b") +./arith.tests: line 268: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ") +./arith.tests: line 272: a b: syntax error in expression (error token is "b") +./arith.tests: line 273: ((: a b: syntax error in expression (error token is "b") 42 42 42 42 42 42 -./arith.tests: line 281: b[c]d: syntax error in expression (error token is "d") +./arith.tests: line 284: b[c]d: syntax error in expression (error token is "d") diff --git a/tests/arith.tests b/tests/arith.tests index ce6a372a..33622e76 100644 --- a/tests/arith.tests +++ b/tests/arith.tests @@ -254,6 +254,9 @@ echo $(( -7 )) echo $(( ++7 )) echo $(( --7 )) +${THIS_SH} ./arith1.sub +${THIS_SH} ./arith2.sub + x=4 y=7 diff --git a/tests/arith.tests~ b/tests/arith.tests~ new file mode 100644 index 00000000..ce6a372a --- /dev/null +++ b/tests/arith.tests~ @@ -0,0 +1,281 @@ +set +o posix +declare -i iv jv + +iv=$(( 3 + 5 * 32 )) +echo $iv +iv=iv+3 +echo $iv +iv=2 +jv=iv + +let "jv *= 2" +echo $jv +jv=$(( $jv << 2 )) +echo $jv + +let jv="$jv / 2" +echo $jv +jv="jv >> 2" +echo $jv + +iv=$((iv+ $jv)) +echo $iv +echo $((iv -= jv)) +echo $iv +echo $(( iv == jv )) +echo $(( iv != $jv )) +echo $(( iv < jv )) +echo $(( $iv > $jv )) +echo $(( iv <= $jv )) +echo $(( $iv >= jv )) + +echo $jv +echo $(( ~$jv )) +echo $(( ~1 )) +echo $(( ! 0 )) + +echo $(( jv % 2 )) +echo $(( $iv % 4 )) + +echo $(( iv <<= 16 )) +echo $(( iv %= 33 )) + +echo $(( 33 & 55 )) +echo $(( 33 | 17 )) + +echo $(( iv && $jv )) +echo $(( $iv || jv )) + +echo $(( iv && 0 )) +echo $(( iv & 0 )) +echo $(( iv && 1 )) +echo $(( iv & 1 )) + +echo $(( $jv || 0 )) +echo $(( jv | 0 )) +echo $(( jv | 1 )) +echo $(( $jv || 1 )) + +let 'iv *= jv' +echo $iv +echo $jv +let "jv += $iv" +echo $jv + +echo $(( jv /= iv )) +echo $(( jv <<= 8 )) +echo $(( jv >>= 4 )) + +echo $(( iv |= 4 )) +echo $(( iv &= 4 )) + +echo $(( iv += (jv + 9))) +echo $(( (iv + 4) % 7 )) + +# unary plus, minus +echo $(( +4 - 8 )) +echo $(( -4 + 8 )) + +# conditional expressions +echo $(( 4<5 ? 1 : 32)) +echo $(( 4>5 ? 1 : 32)) +echo $(( 4>(2+3) ? 1 : 32)) +echo $(( 4<(2+3) ? 1 : 32)) +echo $(( (2+2)<(2+3) ? 1 : 32)) +echo $(( (2+2)>(2+3) ? 1 : 32)) + +# check that the unevaluated part of the ternary operator does not do +# evaluation or assignment +x=i+=2 +y=j+=2 +declare -i i=1 j=1 +echo $((1 ? 20 : (x+=2))) +echo $i,$x +echo $((0 ? (y+=2) : 30)) +echo $j,$y + +x=i+=2 +y=j+=2 +declare -i i=1 j=1 +echo $((1 ? 20 : (x+=2))) +echo $i,$x +echo $((0 ? (y+=2) : 30)) +echo $i,$y + +# check precedence of assignment vs. conditional operator +# should be an error +declare -i x=2 +y=$((1 ? 20 : x+=2)) + +# check precedence of assignment vs. conditional operator +declare -i x=2 +echo $((0 ? x+=2 : 20)) + +# associativity of assignment-operator operator +declare -i i=1 j=2 k=3 +echo $((i += j += k)) +echo $i,$j,$k + +# octal, hex +echo $(( 0x100 | 007 )) +echo $(( 0xff )) +echo $(( 16#ff )) +echo $(( 16#FF/2 )) +echo $(( 8#44 )) + +echo $(( 8 ^ 32 )) + +# other bases +echo $(( 16#a )) +echo $(( 32#a )) +echo $(( 56#a )) +echo $(( 64#a )) + +echo $(( 16#A )) +echo $(( 32#A )) +echo $(( 56#A )) +echo $(( 64#A )) + +echo $(( 64#@ )) +echo $(( 64#_ )) + +# weird bases +echo $(( 3425#56 )) + +# missing number after base +echo $(( 2# )) + +# these should generate errors +echo $(( 7 = 43 )) +echo $(( 2#44 )) +echo $(( 44 / 0 )) +let 'jv += $iv' +echo $(( jv += \$iv )) +let 'rv = 7 + (43 * 6' + +# more errors +declare -i i +i=0#4 +i=2#110#11 + +((echo abc; echo def;); echo ghi) + +if (((4+4) + (4 + 7))); then + echo ok +fi + +(()) # make sure the null expression works OK + +a=(0 2 4 6) +echo $(( a[1] + a[2] )) +echo $(( (a[1] + a[2]) == a[3] )) +(( (a[1] + a[2]) == a[3] )) ; echo $? + +# test pushing and popping the expression stack +unset A +A="4 + " +echo $(( ( 4 + A ) + 4 )) +A="3 + 5" +echo $(( ( 4 + A ) + 4 )) + +# badly-formed conditional expressions +echo $(( 4 ? : $A )) +echo $(( 1 ? 20 )) +echo $(( 4 ? 20 : )) + +# precedence and short-circuit evaluation +B=9 +echo $B + +echo $(( 0 && B=42 )) +echo $B + +echo $(( 1 || B=88 )) +echo $B + +echo $(( 0 && (B=42) )) +echo $B + +echo $(( (${$} - $$) && (B=42) )) +echo $B + +echo $(( 1 || (B=88) )) +echo $B + +# until command with (( )) command +x=7 + +echo $x +until (( x == 4 )) +do + echo $x + x=4 +done + +echo $x + +# exponentiation +echo $(( 2**15 - 1)) +echo $(( 2**(16-1))) +echo $(( 2**16*2 )) +echo $(( 2**31-1)) +echo $(( 2**0 )) + +# {pre,post}-{inc,dec}rement and associated errors + +x=4 + +echo $x +echo $(( x++ )) +echo $x +echo $(( x-- )) +echo $x + +echo $(( --x )) +echo $x + +echo $(( ++x )) +echo $x + +echo $(( ++7 )) +echo $(( 7-- )) + +echo $(( --x=7 )) +echo $(( ++x=7 )) + +echo $(( x++=7 )) +echo $(( x--=7 )) + +echo $x + +echo $(( +7 )) +echo $(( -7 )) + +echo $(( ++7 )) +echo $(( --7 )) + +x=4 +y=7 + +(( x=8 , y=12 )) + +echo $x $y + +# should be an error +(( x=9 y=41 )) + +# These are errors +unset b +echo $((a b)) +((a b)) + +n=42 +printf "%d\n" $n +printf "%i\n" $n +echo $(( 8#$(printf "%o\n" $n) )) +printf "%u\n" $n +echo $(( 16#$(printf "%x\n" $n) )) +echo $(( 16#$(printf "%X\n" $n) )) + +# causes longjmp botches through bash-2.05b +a[b[c]d]=e diff --git a/tests/arith1.sub b/tests/arith1.sub new file mode 100644 index 00000000..43cae806 --- /dev/null +++ b/tests/arith1.sub @@ -0,0 +1,38 @@ +# test of redone post-increment and post-decrement code +echo $(( 4-- )) +echo $(( 4++ )) +echo $(( 4 -- )) +echo $(( 4 ++ )) + +(( array[0]++ )) +echo ${array} + +(( array[0] ++ )) +echo ${array} + +(( a++ )) +echo $a +(( a ++ )) +echo $a + +echo $(( a ++ + 4 )) +echo $a + +echo $(( a+++4 )) +echo $a + +echo $(( a---4 )) +echo $a + +echo $(( a -- + 4 )) +echo $a + +echo $(( a -- - 4 )) +echo $a + +(( ++ + 7 )) + +(( ++ )) +echo $(( +++7 )) +echo $(( ++ + 7 )) +(( -- )) diff --git a/tests/arith2.sub b/tests/arith2.sub new file mode 100644 index 00000000..7eac9523 --- /dev/null +++ b/tests/arith2.sub @@ -0,0 +1,45 @@ +echo $(( --7 )) +echo $(( ++7 )) +echo $(( -- 7 )) +echo $(( ++ 7 )) + +((++array[0] )) +echo $array +(( ++ array[0] )) +echo $array + +(( ++a )) +echo $a +(( ++ a )) +echo $a + +(( --a )) +echo $a +(( -- a )) +echo $a + +echo $(( 4 + ++a )) +echo $a + +echo $(( 4+++a )) +echo $a + +echo $(( 4---a )) +echo $a + +echo $(( 4 - -- a )) +echo $a + +(( -- )) +echo $(( ---7 )) +echo $(( -- - 7 )) + +(( ++ )) +echo $(( ++7 )) +echo $(( ++ + 7 )) + +echo $(( ++-7 )) +echo $(( ++ - 7 )) + +echo $(( +--7 )) +echo $(( -- + 7 )) diff --git a/tests/dollar-at-star b/tests/dollar-at-star index 7b6d75ae..d8329b11 100755 --- a/tests/dollar-at-star +++ b/tests/dollar-at-star @@ -215,4 +215,8 @@ ${THIS_SH} ./dollar-star1.sub # though bash-2.05b ${THIS_SH} ./dollar-at1.sub +# tests for expansion of other variables in double-quoted strings containing +# $@. Bugs through bash-2.05b +${THIS_SH} ./dollar-at2.sub + exit 0 diff --git a/tests/dollar-at-star~ b/tests/dollar-at-star~ index ade9c1f9..7b6d75ae 100755 --- a/tests/dollar-at-star~ +++ b/tests/dollar-at-star~ @@ -211,4 +211,8 @@ esac # expansions -- bugs through bash-2.05b ${THIS_SH} ./dollar-star1.sub +# tests for expansion of "$@" on rhs of things like ${param:+word}. Bugs +# though bash-2.05b +${THIS_SH} ./dollar-at1.sub + exit 0 diff --git a/tests/dollar-at2.sub b/tests/dollar-at2.sub new file mode 100644 index 00000000..c079a295 --- /dev/null +++ b/tests/dollar-at2.sub @@ -0,0 +1,19 @@ +t1() +{ + xxx="echo $@" + + recho "$xxx ; echo $@" +} + +t2() +{ + xxx="echo $@" + + recho "${xxx} ; echo $@" +} + +t1 1 +t1 1 2 + +t2 1 +t2 1 2 diff --git a/tests/dollar.right b/tests/dollar.right index f836b831..7b0f511c 100644 --- a/tests/dollar.right +++ b/tests/dollar.right @@ -119,3 +119,9 @@ xa|xb|xc 3 3 3 +argv[1] = <echo 1 ; echo 1> +argv[1] = <echo 1 2 ; echo 1> +argv[2] = <2> +argv[1] = <echo 1 ; echo 1> +argv[1] = <echo 1 2 ; echo 1> +argv[2] = <2> diff --git a/tests/histexp.right b/tests/histexp.right index ff6453e5..193e9d4f 100644 --- a/tests/histexp.right +++ b/tests/histexp.right @@ -88,6 +88,7 @@ echo 'xwhix.h' xwhix.h echo 'xwhix.h' xwhix.h + 7 set -H 8 echo line 2 for history 9 echo a b c d e 10 echo line 2 for history @@ -117,9 +118,8 @@ xwhix.h 34 echo bar.c bar.o bar.html bar.h 35 echo xbar.c xbar.o xbar.html xbar.h 36 echo xwhix.c xwhix.o xwhix.html xwhix.h - 37 echo xwhix.c xwhix.o xwhix.html xwhix.h - 38 echo 'xwhix' - 39 echo 'xwhix.h' + 37 echo 'xwhix' + 38 echo 'xwhix.h' !! !! echo '!!' \!\! diff --git a/tests/histexp.right~ b/tests/histexp.right~ new file mode 100644 index 00000000..ff6453e5 --- /dev/null +++ b/tests/histexp.right~ @@ -0,0 +1,129 @@ +echo $BASH_VERSION +./histexp.tests: line 22: history: !!:z: history expansion failed + 1 for i in one two three; do echo $i; done + 2 /bin/sh -c 'echo this is $0' + 3 ls + 4 echo $BASH_VERSION + 1 for i in one two three; do echo $i; done + 2 /bin/sh -c 'echo this is $0' + 3 ls + 4 echo $BASH_VERSION + 5 HISTFILE=/tmp/newhistory + 6 echo line 2 for history +echo line 2 for history +echo line 2 for history +set -H +echo line 2 for history +line 2 for history + 1 for i in one two three; do echo $i; done + 2 /bin/sh -c 'echo this is $0' + 3 ls + 4 echo $BASH_VERSION + 5 HISTFILE=/tmp/newhistory + 6 echo line 2 for history + 7 set -H + 8 echo line 2 for history +a b c d e +echo a b c d e +a b c d e +echo line 2 for history +line 2 for history +echo line 8 for history +line 8 for history +/bin/sh -c 'echo this is $0' +this is /bin/sh +echo sh +sh +echo /bin +/bin +echo e +e +a b c d e +echo b c d e +b c d e +echo b c d +b c d +echo d e +d e +echo d e +d e +echo b c d +b c d +file.c +echo file +file +echo .c +.c +echo 'file' +file +bax.c +echo $file +bax +echo .c +.c +echo '$file' +$file +a b c d e +echo 'a' 'b' 'c' 'd' 'e' +a b c d e +echo 'a b c d e' +a b c d e +foo.c foo.o foo.html foo.h +echo bar.c foo.o foo.html foo.h +bar.c foo.o foo.html foo.h +echo bar.c bar.o bar.html bar.h +bar.c bar.o bar.html bar.h +echo xbar.c xbar.o xbar.html xbar.h +xbar.c xbar.o xbar.html xbar.h +echo xbar.c xbar.o xbar.html xbar.h +xbar.c xbar.o xbar.html xbar.h +echo xwhix.c xwhix.o xwhix.html xwhix.h +xwhix.c xwhix.o xwhix.html xwhix.h +echo xwhix.c xwhix.o xwhix.html xwhix.h +echo 'xwhix' +xwhix +echo 'xwhix.h' +xwhix.h +echo 'xwhix.h' +xwhix.h +echo 'xwhix.h' +xwhix.h + 8 echo line 2 for history + 9 echo a b c d e + 10 echo line 2 for history + 11 echo line 8 for history + 12 /bin/sh -c 'echo this is $0' + 13 echo sh + 14 echo /bin + 15 echo e + 16 echo a b c d e + 17 echo b c d e + 18 echo b c d + 19 echo d e + 20 echo b c d + 21 echo file.c + 22 echo file + 23 echo .c + 24 echo 'file' + 25 echo $file.c + 26 echo $file + 27 echo .c + 28 echo '$file' + 29 echo a b c d e + 30 echo 'a' 'b' 'c' 'd' 'e' + 31 echo 'a b c d e' + 32 echo foo.c foo.o foo.html foo.h + 33 echo bar.c foo.o foo.html foo.h + 34 echo bar.c bar.o bar.html bar.h + 35 echo xbar.c xbar.o xbar.html xbar.h + 36 echo xwhix.c xwhix.o xwhix.html xwhix.h + 37 echo xwhix.c xwhix.o xwhix.html xwhix.h + 38 echo 'xwhix' + 39 echo 'xwhix.h' +!! +!! +echo '!!' \!\! +!! !! +ok 1 +ok 2 +ok 3 diff --git a/tests/read.right b/tests/read.right index dcc869d9..c388294a 100644 --- a/tests/read.right +++ b/tests/read.right @@ -49,3 +49,15 @@ while read -u 3 var do echo "$var" done 3<$0 +argv[1] = <> +argv[1] = <> +argv[1] = <:> +argv[1] = <:> +FOO +argv[1] = <> +argv[1] = <3> +argv[1] = <> +argv[2] = <> +argv[3] = <> +FOO + 0 0 0 diff --git a/tests/read.tests b/tests/read.tests index e8b7e8f8..f9c78c5a 100644 --- a/tests/read.tests +++ b/tests/read.tests @@ -90,3 +90,6 @@ ${THIS_SH} ./read3.sub # test read -u fd behavior ${THIS_SH} ./read4.sub + +# test behavior when IFS is not the default -- bug through bash-2.05b +${THIS_SH} ./read5.sub diff --git a/tests/read.tests~ b/tests/read.tests~ new file mode 100644 index 00000000..e8b7e8f8 --- /dev/null +++ b/tests/read.tests~ @@ -0,0 +1,92 @@ +echo " a " | (read x; echo "$x.") + +echo " a b " | ( read x y ; echo -"$x"-"$y"- ) +echo " a b\ " | ( read x y ; echo -"$x"-"$y"- ) +echo " a b " | ( read x ; echo -"$x"- ) +echo " a b\ " | ( read x ; echo -"$x"- ) + +echo " a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo " a b\ " | ( read -r x ; echo -"$x"- ) + +echo "\ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo "\ a b\ " | ( read -r x ; echo -"$x"- ) +echo " \ a b\ " | ( read -r x y ; echo -"$x"-"$y"- ) +echo " \ a b\ " | ( read -r x ; echo -"$x"- ) + +# make sure that CTLESC and CTLNUL are passed through correctly +echo $'\001' | ( read var ; recho "$var" ) +echo $'\001' | ( read ; recho "$REPLY" ) + +echo $'\177' | ( read var ; recho "$var" ) +echo $'\177' | ( read ; recho "$REPLY" ) + +# make sure a backslash-quoted \\n still disappears from the input when +# we're not reading in `raw' mode, and no stray CTLESC chars are left in +# the input stream +echo $'ab\\\ncd' | ( read ; recho "$REPLY" ) + +echo "A B " > /tmp/IN +unset x y z +read x y z < /tmp/IN +echo 1: "x[$x] y[$y] z[$z]" +echo 1a: ${z-z not set} +read x < /tmp/IN +echo 2: "x[$x]" +rm /tmp/IN + +# this is where the bash `read' behavior with respect to $REPLY differs +# from ksh93 +echo "A B " > /tmp/IN + +read < /tmp/IN +echo "[$REPLY]" + +rm /tmp/IN + +echo " A B " > /tmp/IN + +read < /tmp/IN +echo "[$REPLY]" + +rm /tmp/IN + +# make sure that read with more variables than words sets the extra +# variables to the empty string + +bvar=bvar +cvar=cvar +echo aa > /tmp/IN +read avar bvar cvar < /tmp/IN +echo =="$avar"== +echo =="$bvar"== +echo =="$cvar"== + +rm /tmp/IN + +# test behavior of read with various settings of IFS + +echo " foo" | { IFS= read line; recho "$line"; } + +echo " foo" | { IFS= ; read line; recho "$line"; } + +echo " foo" | { unset IFS ; read line; recho "$line"; } + +echo " foo" | { IFS=$'\n' ; read line; recho "$line"; } + +echo " foo" | { IFS=$' \n' ; read line; recho "$line"; } + +echo " foo" | { IFS=$' \t\n' ; read line; recho "$line"; } + +echo " foo" | { IFS=$':' ; read line; recho "$line"; } + +# test read -d delim behavior +${THIS_SH} ./read1.sub + +# test read -t timeout behavior +${THIS_SH} ./read2.sub + +# test read -n nchars behavior +${THIS_SH} ./read3.sub + +# test read -u fd behavior +${THIS_SH} ./read4.sub diff --git a/tests/read5.sub b/tests/read5.sub new file mode 100644 index 00000000..58b992dc --- /dev/null +++ b/tests/read5.sub @@ -0,0 +1,36 @@ +IFS=: read x y z << EOF +::: +EOF +recho $x +recho "$x" +recho $y +recho "$y" +recho $z +recho "$z" + +if [ -z "$x" ]; then + echo FOO +else + echo BAR +fi + +IFS=: read -a A << EOF +::: +EOF + +recho ${A[0]} +recho "${A[0]}" + +recho ${#A[@]} + +recho "${A[@]}" + +if [ -z "${A[0]}" ]; then + echo FOO +else + echo BAR +fi + +echo -n ${A[0]} | cat -vet +echo -n ${A[0]} | wc + |