From d7d836dfc55b937f463f601ba5117d6442053089 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Tue, 20 Jun 2017 10:38:13 -0400 Subject: [PATCH] commit bash-snap-20170620 snapshot --- CWRU/CWRU.chlog | 67 +++++++++++++++++++++++++++++++++++ bashline.c | 7 ++-- builtins/bind.def | 42 +++++++++++++++++++--- builtins/read.def | 2 +- doc/bash.1 | 2 +- doc/bashref.texi | 2 +- examples/loadables/README | 14 ++++++-- examples/loadables/realpath.c | 5 ++- execute_cmd.c | 9 +++-- general.c | 14 ++++++++ general.h | 1 + lib/readline/display.c | 2 ++ lib/readline/input.c | 5 +-- lib/readline/mbutil.c | 8 +++-- lib/readline/vi_mode.c | 36 ++++++++++++------- parse.y | 13 ++++++- 16 files changed, 195 insertions(+), 34 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 31724be0..7dd09a3f 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -14102,3 +14102,70 @@ parse.y lib/readline/display.c - update_line: when wrapping multibyte characters, make sure we deal with WCWIDTH returning -1. Fixes a fuzzing bug + + 6/17 + ---- +execute_cmd.c + - execute_coproc: make sure `invert' is set before trying to use it + when returning failure on invalid coproc name. Report and fix from + Eduardo Bustamante + - execute_command_internal: make sure execute_coproc sets + last_command_exit_value if it returns failure, so an invalid name + can set $? = 1. Report and fix from Eduardo Bustamante + + +lib/readline/display.c + - update_line: make sure all references to `wrapped_line' are wrapped + with #ifdef HANDLE_MULTIBYTE. Report and fix from Eduardo Bustamante + + +lib/readline/vi_mode.c + - _rl_vi_change_char: don't use rl_point++ when you mean to move + forward a character; use _rl_vi_append_forward to account for + multibyte characters and take vi end of line handling into account + - _rl_vi_last_replacement: now an array of chars whether we are + using multibyte chars or not. If we're not, the character we read + to use as the replacement is saved as the first element of the array + - rl_vi_change_char,_rl_vi_callback_change_char: changes to deal with + _rl_vi_last_replacement being an array. Fixes bug reported by + Eduardo Bustamante + +lib/readline/mbutil.c + - _rl_get_char_len: look at at most MB_CUR_MAX characters, but maybe + fewer if the length of the string is less + +builtins/bind.def + - unbind_keyseq: new function for the -r option; checks whether the + key sequence is actually bound before trying to bind it to NULL. + Partial fix for https://savannah.gnu.org/support/?109329 + +parse.y + - augment `error yacc_EOF' production to call YYABORT in non-interactive + shells or calls to parse_and_execute (eval, command substitution, + etc.) Fixes bug reported by Martijn Dekker + + 6/19 + ---- +bashline.c + - edit_and_execute_command: don't add rl_line_buffer to the history + list if it's empty; consistent with how other code treats an empty + line + +execute_cmd.c + - execute_builtin: make sure to preserve the temporary env across the + execution of the `read' builtin or `fc' builtin if HISTORY is + defined, in case `read -e' calls edit-and-execute-command. Should + have no side effects. Reported by Eduardo Bustamante + + +general.c + - line_isblank: new function: returns true if passed string is composed + entirely of blanks + +general.h + - line_isblank: new extern declaration + +parse.y + - history_delimiting_chars: return "" for a blank line, since there's + nothing to delimit with `;' + diff --git a/bashline.c b/bashline.c index d107daed..be9c02d3 100644 --- a/bashline.c +++ b/bashline.c @@ -959,8 +959,11 @@ edit_and_execute_command (count, c, editing_mode, edit_command) /* This breaks down when using command-oriented history and are not finished with the command, so we should not ignore the last command */ using_history (); - current_command_line_count++; /* for rl_newline above */ - bash_add_history (rl_line_buffer); + if (rl_line_buffer[0]) + { + current_command_line_count++; /* for rl_newline above */ + bash_add_history (rl_line_buffer); + } current_command_line_count = 0; /* for dummy history entry */ bash_add_history (""); history_lines_this_session++; diff --git a/builtins/bind.def b/builtins/bind.def index f05cf918..5fc8d34f 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -88,6 +88,7 @@ extern int errno; static int query_bindings __P((char *)); static int unbind_command __P((char *)); +static int unbind_keyseq __P((char *)); #define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0) @@ -264,11 +265,8 @@ bind_builtin (list) if ((flags & RFLAG) && remove_seq) { - if (rl_bind_keyseq (remove_seq, (rl_command_func_t *)NULL) != 0) - { - builtin_error (_("`%s': cannot unbind"), remove_seq); - BIND_RETURN (EXECUTION_FAILURE); - } + opt = unbind_keyseq (remove_seq); + BIND_RETURN (opt); } if (flags & XFLAG) @@ -341,4 +339,38 @@ unbind_command (name) rl_unbind_function_in_map (function, rl_get_keymap ()); return EXECUTION_SUCCESS; } + +static int +unbind_keyseq (seq) + char *seq; +{ + char *kseq; + int kslen; + + kseq = (char *)xmalloc ((2 * strlen (seq)) + 1); + if (rl_translate_keyseq (seq, kseq, &kslen)) + { + free (kseq); + builtin_error (_("`%s': cannot unbind"), seq); + return EXECUTION_FAILURE; + } + if (rl_function_of_keyseq (kseq, (Keymap)0, (int *)0) == 0) + { + free (kseq); + return (EXECUTION_SUCCESS); + } + + /* I wish this didn't have to translate the key sequence again, but readline + doesn't have a binding function that takes a translated key sequence as + an argument. */ + if (rl_bind_keyseq (seq, (rl_command_func_t *)NULL) != 0) + { + free (kseq); + builtin_error (_("`%s': cannot unbind"), seq); + return (EXECUTION_FAILURE); + } + + free (kseq); + return (EXECUTION_SUCCESS); +} #endif /* READLINE */ diff --git a/builtins/read.def b/builtins/read.def index 520a2b34..7fa8f86a 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -39,7 +39,7 @@ Options: variable ARRAY, starting at zero -d delim continue until the first character of DELIM is read, rather than newline - -e use Readline to obtain the line in an interactive shell + -e use Readline to obtain the line -i text use TEXT as the initial text for Readline -n nchars return after reading NCHARS characters rather than waiting for a newline, but honor a delimiter if fewer than diff --git a/doc/bash.1 b/doc/bash.1 index 25c5ff42..d84f737f 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -9041,7 +9041,7 @@ is coming from a terminal, .B READLINE above) is used to obtain the line. Readline uses the current (or default, if line editing was not previously -active) editing settings. +active) editing settings, but uses Readline's default filename completion. .TP .B \-i \fItext\fP If diff --git a/doc/bashref.texi b/doc/bashref.texi index 9839801a..ceba551b 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -4493,7 +4493,7 @@ when it reads a NUL character. @item -e Readline (@pxref{Command Line Editing}) is used to obtain the line. Readline uses the current (or default, if line editing was not previously -active) editing settings. +active) editing settings, but uses Readline's default filename completion. @item -i @var{text} If Readline is being used to read the line, @var{text} is placed into diff --git a/examples/loadables/README b/examples/loadables/README index 318d0013..91febd48 100644 --- a/examples/loadables/README +++ b/examples/loadables/README @@ -32,29 +32,37 @@ the canonical example. There is no real `builtin writers' programming guide'. The file template.c provides a template to use for creating new loadable builtins. +The file "Makefile.inc" is created using the same values that configure +writes into Makefile.in, and is installed in the same directory as the +rest of the example builtins. It's intended to be a start at something +that can be modified or included to help you build your own loadables +without having to search for the right CFLAGS and LDFLAGS. + basename.c Return non-directory portion of pathname. cat.c cat(1) replacement with no options - the way cat was intended. dirname.c Return directory portion of pathname. +fdflags.c Change the flag associated with one of bash's open file desriptors. finfo.c Print file info. head.c Copy first part of files. hello.c Obligatory "Hello World" / sample loadable. id.c POSIX.2 user identity. ln.c Make links. -loadables.h Start at a file loadable builtins can include for shell definitions +loadables.h File loadable builtins can include for shell definitions. logname.c Print login name of current user. Makefile.in Simple makefile for the sample loadable builtins. mkdir.c Make directories. -mypid.c Add $MYPID variable, demonstrate use of unload hook function +mypid.c Add $MYPID variable, demonstrate use of unload hook functio.n necho.c echo without options or argument interpretation. pathchk.c Check pathnames for validity and portability. print.c Loadable ksh-93 style print builtin. printenv.c Minimal builtin clone of BSD printenv(1). push.c Anyone remember TOPS-20? -README README realpath.c Canonicalize pathnames, resolving symlinks. rm.c Remove files and directories. rmdir.c Remove directory. +setpgid.c Set a process's pgrp; example of how to wrap a system call. sleep.c sleep for fractions of a second. +stat.c populate an associative array with information about a file strftime.c Loadable builtin interface to strftime(3). sync.c Sync the disks by forcing pending filesystem writes to complete. tee.c Duplicate standard input. diff --git a/examples/loadables/realpath.c b/examples/loadables/realpath.c index b19b87fb..1d82dd61 100644 --- a/examples/loadables/realpath.c +++ b/examples/loadables/realpath.c @@ -88,13 +88,16 @@ WORD_LIST *list; break; default: builtin_usage(); + return (EX_USAGE); } } list = loptend; - if (list == 0) + if (list == 0) { builtin_usage(); + return (EX_USAGE); + } for (es = EXECUTION_SUCCESS; list; list = list->next) { p = list->word->word; diff --git a/execute_cmd.c b/execute_cmd.c index 0183a105..a006b3d3 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -598,7 +598,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, #if defined (COPROCESS_SUPPORT) if (command->type == cm_coproc) - return (execute_coproc (command, pipe_in, pipe_out, fds_to_close)); + return (last_command_exit_value = execute_coproc (command, pipe_in, pipe_out, fds_to_close)); #endif user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); @@ -2298,6 +2298,8 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close) coproc_init (&sh_coproc); #endif + invert = (command->flags & CMD_INVERT_RETURN) != 0; + /* XXX - expand coproc name without splitting -- bash-5.0 */ /* could make this dependent on a shopt option */ name = expand_string_unsplit_to_string (command->value.Coproc->name, 0); @@ -2313,7 +2315,6 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close) command->value.Coproc->name = name; } - invert = (command->flags & CMD_INVERT_RETURN) != 0; command_string_index = 0; tcmd = make_command_string (command); @@ -4554,6 +4555,10 @@ execute_builtin (builtin, words, flags, subshell) `mapfile' is a special case because it uses evalstring (same as eval or source) to run its callbacks. */ isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin || builtin == mapfile_builtin); +#if defined (HISTORY) && defined (READLINE) + if (builtin == fc_builtin || builtin == read_builtin) + isbltinenv = 1; +#endif if (isbltinenv) { diff --git a/general.c b/general.c index 584e7859..3c0885a9 100644 --- a/general.c +++ b/general.c @@ -402,6 +402,20 @@ assignment (string, flags) return (0); } +int +line_isblank (line) + const char *line; +{ + register int i; + + if (line == 0) + return 0; /* XXX */ + for (i = 0; line[i]; i++) + if (isblank ((unsigned char)line[i]) == 0) + break; + return (line[i] == '\0'); +} + /* **************************************************************** */ /* */ /* Functions to manage files and file descriptors */ diff --git a/general.h b/general.h index d55f26bf..73fc7761 100644 --- a/general.h +++ b/general.h @@ -292,6 +292,7 @@ extern int check_identifier __P((WORD_DESC *, int)); extern int valid_nameref_value __P((const char *, int)); extern int check_selfref __P((const char *, char *, int)); extern int legal_alias_name __P((const char *, int)); +extern int line_isblank __P((const char *)); extern int assignment __P((const char *, int)); extern int sh_unset_nodelay_mode __P((int)); diff --git a/lib/readline/display.c b/lib/readline/display.c index d5536211..b90437f1 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -2128,6 +2128,7 @@ dumb_update: } #if 1 +#ifdef HANDLE_MULTIBYTE /* If we write a non-space into the last screen column, remove the note that we added a space to compensate for a multibyte double-width character that didn't fit, since @@ -2137,6 +2138,7 @@ dumb_update: line_state_invisible->wrapped_line[current_line+1] && nfd[bytes_to_insert-1] != ' ') line_state_invisible->wrapped_line[current_line+1] = 0; +#endif #endif } else diff --git a/lib/readline/input.c b/lib/readline/input.c index b57bba61..00916456 100644 --- a/lib/readline/input.c +++ b/lib/readline/input.c @@ -655,7 +655,7 @@ _rl_read_mbchar (char *mbchar, int size) int _rl_read_mbstring (int first, char *mb, int mlen) { - int i, c; + int i, c, n; mbstate_t ps; c = first; @@ -664,7 +664,8 @@ _rl_read_mbstring (int first, char *mb, int mlen) { mb[i] = (char)c; memset (&ps, 0, sizeof (mbstate_t)); - if (_rl_get_char_len (mb, &ps) == -2) + n = _rl_get_char_len (mb, &ps); + if (n == -2) { /* Read more for multibyte character */ RL_SETSTATE (RL_STATE_MOREINPUT); diff --git a/lib/readline/mbutil.c b/lib/readline/mbutil.c index db39279c..65543416 100644 --- a/lib/readline/mbutil.c +++ b/lib/readline/mbutil.c @@ -223,9 +223,13 @@ _rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero) int _rl_get_char_len (char *src, mbstate_t *ps) { - size_t tmp; + size_t tmp, l; + int mb_cur_max; - tmp = mbrlen((const char *)src, MB_CUR_MAX, ps); + /* Look at no more than MB_CUR_MAX characters */ + l = (size_t)strlen (src); + mb_cur_max = MB_CUR_MAX; + tmp = mbrlen((const char *)src, (l < mb_cur_max) ? l : mb_cur_max, ps); if (tmp == (size_t)(-2)) { /* shorted to compose multibyte char */ diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index 3613d195..db1bd799 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -101,7 +101,7 @@ static int _rl_vi_last_search_mblen; #else static int _rl_vi_last_search_char; #endif -static int _rl_vi_last_replacement; +static char _rl_vi_last_replacement[MB_LEN_MAX+1]; /* reserve for trailing NULL */ static int _rl_vi_last_key_before_insert; @@ -646,11 +646,7 @@ _rl_vi_append_forward (int key) else { point = rl_point; -#if 0 - rl_forward_char (1, key); -#else rl_point = _rl_forward_char_internal (1); -#endif if (point == rl_point) rl_point = rl_end; } @@ -1889,7 +1885,7 @@ _rl_vi_change_char (int count, int c, char *mb) p = rl_point; rl_vi_delete (1, c); if (rl_point < p) /* Did we retreat at EOL? */ - rl_point++; + _rl_vi_append_forward (c); #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) rl_insert_text (mb); @@ -1931,9 +1927,15 @@ static int _rl_vi_callback_change_char (_rl_callback_generic_arg *data) { int c; - char mb[MB_LEN_MAX]; + char mb[MB_LEN_MAX+1]; - _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); + c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); +#if defined (HANDLE_MULTIBYTE) + strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX); +#else + _rl_vi_last_replacement[0] = c; +#endif + _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* XXX */ if (c < 0) return -1; @@ -1949,13 +1951,13 @@ int rl_vi_change_char (int count, int key) { int c; - char mb[MB_LEN_MAX]; + char mb[MB_LEN_MAX+1]; if (_rl_vi_redoing) { - c = _rl_vi_last_replacement; - mb[0] = c; - mb[1] = '\0'; + strncpy (mb, _rl_vi_last_replacement, MB_LEN_MAX); + c = (unsigned char)_rl_vi_last_replacement[0]; /* XXX */ + mb[MB_LEN_MAX] = '\0'; } #if defined (READLINE_CALLBACKS) else if (RL_ISSTATE (RL_STATE_CALLBACK)) @@ -1966,7 +1968,15 @@ rl_vi_change_char (int count, int key) } #endif else - _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); + { + c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); +#ifdef HANDLE_MULTIBYTE + strncpy (_rl_vi_last_replacement, mb, MB_LEN_MAX); +#else + _rl_vi_last_replacement[0] = c; +#endif + _rl_vi_last_replacement[MB_LEN_MAX] = '\0'; /* just in case */ + } if (c < 0) return -1; diff --git a/parse.y b/parse.y index d8d8e885..92da96b9 100644 --- a/parse.y +++ b/parse.y @@ -416,8 +416,16 @@ inputunit: simple_list simple_list_terminator /* EOF after an error. Do ignoreeof or not. Really only interesting in non-interactive shells */ global_command = (COMMAND *)NULL; + last_command_exit_value = 1; handle_eof_input_unit (); - YYACCEPT; + if (interactive && parse_and_execute_level == 0) + { + YYACCEPT; + } + else + { + YYABORT; + } } | yacc_EOF { @@ -5457,6 +5465,9 @@ history_delimiting_chars (line) return (" "); } + if (line_isblank (line)) + return (""); + return ("; "); } #endif /* HISTORY */