From ec1101c37ea25a61db37c268f736089061c9afaa Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Sat, 5 Nov 2016 13:28:27 -0400 Subject: [PATCH] commit bash-20161104 snapshot --- CWRU/CWRU.chlog | 61 ++++++++++++++++++++++++++++++++++- bashline.c | 11 +++++++ examples/loadables/rm.c | 4 ++- execute_cmd.c | 25 ++++++++++++++- jobs.c | 3 ++ lib/glob/sm_loop.c | 3 ++ lib/malloc/malloc.c | 6 +++- lib/readline/macro.c | 19 ++++++++++- lib/readline/readline.c | 9 ++++++ lib/readline/readline.h | 1 + lib/readline/rlprivate.h | 1 + shell.h | 1 + subst.c | 69 ++++++++++++++++++++++++++++++++++++---- 13 files changed, 201 insertions(+), 12 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 59daed23..289c8e5c 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -12105,7 +12105,7 @@ examples/loadables/rm.c , heavily rewritten for inclusion as loadable examples/loadables/Makefile.in - - rm: add rules to build rm as one of the standard targets + - rm: add rules to build rm as one of the `other' targets examples/loadables/stat.c - stat: new loadable builtin that takes a filename and loads the info @@ -12140,3 +12140,62 @@ subst.c - process_substitute: call discard_last_procsub_child instead of calling discard_pipeline directly. Fixes bug reported by Christian Weisgerber + + 11/3 + ---- +shell.h + - EX_DISKFALLBACK: new special return status available to builtins; + means to attempt to execute a disk command with the same name as + the builtin + +examples/loadables/rm.c + - if we see the -i option, return EX_DISKFALLBACK + +execute_cmd.c + - execute_simple_command: if executing a builtin returns EX_DISKFALLBACK, + try running execute_disk_command instead + +bashline.c + - shell_expand_line: use expand_word to expand the readline line + buffer, which allows us to pass flags with the word. If a numeric + argument is supplied, do not perform quote removal (pass + Q_HERE_DOCUMENT since here-doc quoting does the right thing) and + do not perform command or process subsitution. From a suggestion + by Dabrien 'Dabe' Murphy based on an old bug-bash + discussion + +subst.c + - expand_word_internal: note that we have added a quoted IFS char to + istring by setting sentinel has_quoted_ifs. Usually we only add + one if we are not going to be performing word splitting, but we + will not perform word splitting if there's no expansion, so we need + to take care of that case + - expand_word_internal: when performing final word split, if there are + no expansions but has_quoted_ifs is non-zero, call remove_quoted_ifs() + to remove any quoted ifs characters we added while processing + - remove_quoted_ifs: new function, removes CTLESC chars preceding + (single-byte) chars in IFS. Used when we are not performing word + splitting. Fixes bug reported by Martijn Dekker + + 11/4 + ---- +lib/readline/macro.c + - _rl_peek_macro_key: return the next character from the current + keyboard macro; the next character from the `next' keyboard macro, + if there is one, if at the end of the current macro; or 0 to + indicate that we are at the end of a keyboard macro sequence + +lib/readline/rlprivate.h + - _rl_peek_macro_key: extern declaration + +lib/readline/readline.c + - _rl_dispatch_subseq: add test for ESC at the end of a keyboard macro, + which should cause the keyboard timeout for ESC to kick in. The + previous test didn't run the timeout code if executing from a macro, + even if we had read the last character of the macro. Fixes bug + reported by Clark Wang + +lib/glob/sm_loop.c + - GMATCH: allow trailing backslash in pattern to explicitly match a + backslash that is the last character in the string. Bug report from + Stephane Chazelas diff --git a/bashline.c b/bashline.c index b9a2a918..735e23b9 100644 --- a/bashline.c +++ b/bashline.c @@ -2704,6 +2704,7 @@ shell_expand_line (count, ignore) { char *new_line; WORD_LIST *expanded_string; + WORD_DESC *w; new_line = 0; #if defined (BANG_HISTORY) @@ -2733,9 +2734,19 @@ shell_expand_line (count, ignore) /* If there is variable expansion to perform, do that as a separate operation to be undone. */ + +#if 1 + w = alloc_word_desc (); + w->word = savestring (rl_line_buffer); + w->flags = rl_explicit_arg ? (W_NOPROCSUB|W_NOCOMSUB) : 0; + expanded_string = expand_word (w, rl_explicit_arg ? Q_HERE_DOCUMENT : 0); + dispose_word (w); +#else new_line = savestring (rl_line_buffer); expanded_string = expand_string (new_line, 0); FREE (new_line); +#endif + if (expanded_string == 0) { new_line = (char *)xmalloc (1); diff --git a/examples/loadables/rm.c b/examples/loadables/rm.c index 6940befa..adfbffdc 100644 --- a/examples/loadables/rm.c +++ b/examples/loadables/rm.c @@ -122,7 +122,7 @@ rm_builtin (list) rval = EXECUTION_SUCCESS; reset_internal_getopt (); - while ((opt = internal_getopt (list, "Rrf")) != -1) + while ((opt = internal_getopt (list, "Rrfi")) != -1) { switch (opt) { @@ -133,6 +133,8 @@ rm_builtin (list) case 'f': force = 1; break; + case 'i': + return (EX_DISKFALLBACK); CASE_HELPOPT; default: builtin_usage (); diff --git a/execute_cmd.c b/execute_cmd.c index ced48fc7..b2f0dbc3 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -4096,13 +4096,15 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (dofork) { + char *p; + /* Do this now, because execute_disk_command will do it anyway in the vast majority of cases. */ maybe_make_export_env (); /* Don't let a DEBUG trap overwrite the command string to be saved with the process/job associated with this child. */ - if (make_child (savestring (the_printed_command_except_trap), async) == 0) + if (make_child (p = savestring (the_printed_command_except_trap), async) == 0) { already_forked = 1; simple_command->flags |= CMD_NO_FORK; @@ -4135,6 +4137,8 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (async) subshell_level++; /* not for pipes yet */ + +FREE (p); } else { @@ -4356,6 +4360,15 @@ run_builtin: last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level (ERREXIT); } + break; + case EX_DISKFALLBACK: + /* XXX - experimental */ +itrace("execute_simple_command: fallback to file system"); + executing_builtin = old_builtin; + executing_command_builtin = old_command_builtin; + builtin = 0; + /* XXX - redirections will have to be performed again */ + goto execute_from_filesystem; } result = builtin_status (result); if (builtin_is_special) @@ -4390,6 +4403,7 @@ run_builtin: goto run_builtin; } +execute_from_filesystem: if (command_line == 0) command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); @@ -4958,6 +4972,15 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, fflush (stdout); if (r == EX_USAGE) r = EX_BADUSAGE; + /* XXX - experimental */ + else if (r == EX_DISKFALLBACK) + { + char *command_line; +itrace("execute_subshell_builtin_or_function: fall back to disk command"); + command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : ""); + r = execute_disk_command (words, (REDIRECT *)0, command_line, + -1, -1, async, (struct fd_bitmap *)0, flags|CMD_NO_FORK); + } sh_exit (r); } } diff --git a/jobs.c b/jobs.c index cd863e29..7fb5372a 100644 --- a/jobs.c +++ b/jobs.c @@ -1961,6 +1961,9 @@ make_child (command, async_p) signals to the default state for a new process. */ pid_t mypid; + /* If this ends up being changed to modify or use `command' in the + child process, go back and change callers who free `command' in + the child process when this returns. */ mypid = getpid (); #if defined (BUFFERED_INPUT) /* Close default_buffered_input if it's > 0. We don't close it if it's diff --git a/lib/glob/sm_loop.c b/lib/glob/sm_loop.c index 65179e24..aadb1190 100644 --- a/lib/glob/sm_loop.c +++ b/lib/glob/sm_loop.c @@ -103,6 +103,9 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe); break; case L('\\'): /* backslash escape removes special meaning */ + if (p == pe && sc == '\\' && (n+1 == se)) + break; + if (p == pe) return FNM_NOMATCH; diff --git a/lib/malloc/malloc.c b/lib/malloc/malloc.c index 2cff99dd..7df92075 100644 --- a/lib/malloc/malloc.c +++ b/lib/malloc/malloc.c @@ -81,7 +81,7 @@ #else # include #endif - +#include #include /* Define getpagesize () if the system does not. */ @@ -246,6 +246,10 @@ static const unsigned long binsizes[NBUCKETS] = { /* binsizes[x] == (1 << ((x) + 3)) */ #define binsize(x) binsizes[(x)] +#if !defined (errno) +extern int errno; +#endif + /* Declarations for internal functions */ static PTR_T internal_malloc __P((size_t, const char *, int, int)); static PTR_T internal_realloc __P((PTR_T, size_t, const char *, int, int)); diff --git a/lib/readline/macro.c b/lib/readline/macro.c index 8884e44e..47525c79 100644 --- a/lib/readline/macro.c +++ b/lib/readline/macro.c @@ -100,7 +100,10 @@ _rl_with_macro_input (string) return; } - _rl_push_executing_macro (); +#if 0 + if (rl_executing_macro) /* XXX - later */ +#endif + _rl_push_executing_macro (); rl_executing_macro = string; executing_macro_index = 0; RL_SETSTATE(RL_STATE_MACROINPUT); @@ -128,10 +131,24 @@ _rl_next_macro_key () _rl_pop_executing_macro (); return c; #else + /* XXX - consider doing the same as the callback code, just not testing + whether we're running in callback mode */ return (rl_executing_macro[executing_macro_index++]); #endif } +int +_rl_peek_macro_key () +{ + if (rl_executing_macro == 0) + return (0); + if (rl_executing_macro[executing_macro_index] == 0 && (macro_list == 0 || macro_list->string == 0)) + return (0); + if (rl_executing_macro[executing_macro_index] == 0 && macro_list && macro_list->string) + return (macro_list->string[0]); + return (rl_executing_macro[executing_macro_index]); +} + int _rl_prev_macro_key () { diff --git a/lib/readline/readline.c b/lib/readline/readline.c index e51df4f0..4e88dc76 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -920,6 +920,15 @@ _rl_dispatch_subseq (key, map, got_subseq) _rl_pushed_input_available () == 0 && _rl_input_queued ((_rl_keyseq_timeout > 0) ? _rl_keyseq_timeout*1000 : 0) == 0) return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); + /* This is a very specific test. It can possibly be generalized in + the future, but for now it handles a specific case of ESC being + the last character in a keyboard macro. */ + if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap && + (RL_ISSTATE (RL_STATE_INPUTPENDING) == 0) && + (RL_ISSTATE (RL_STATE_MACROINPUT) && _rl_peek_macro_key () == 0) && + _rl_pushed_input_available () == 0 && + _rl_input_queued ((_rl_keyseq_timeout > 0) ? _rl_keyseq_timeout*1000 : 0) == 0) + return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); #endif RESIZE_KEYSEQ_BUFFER (); diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 924bbfb0..bc1e5b52 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -413,6 +413,7 @@ extern void rl_deprep_terminal PARAMS((void)); extern void rl_tty_set_default_bindings PARAMS((Keymap)); extern void rl_tty_unset_default_bindings PARAMS((Keymap)); +extern int rl_tty_set_echoing PARAMS((int)); extern int rl_reset_terminal PARAMS((const char *)); extern void rl_resize_terminal PARAMS((void)); extern void rl_set_screen_size PARAMS((int, int)); diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index fc3856a1..f2d66163 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -309,6 +309,7 @@ extern int _rl_search_getchar PARAMS((_rl_search_cxt *)); /* macro.c */ extern void _rl_with_macro_input PARAMS((char *)); +extern int _rl_peek_macro_key PARAMS((void)); extern int _rl_next_macro_key PARAMS((void)); extern int _rl_prev_macro_key PARAMS((void)); extern void _rl_push_executing_macro PARAMS((void)); diff --git a/shell.h b/shell.h index ce088791..6a6bdcdb 100644 --- a/shell.h +++ b/shell.h @@ -72,6 +72,7 @@ extern int EOF_Reached; #define EX_REDIRFAIL 259 /* redirection failed */ #define EX_BADASSIGN 260 /* variable assignment error */ #define EX_EXPFAIL 261 /* word expansion failed */ +#define EX_DISKFALLBACK 262 /* fall back to disk command from builtin */ /* Flag values that control parameter pattern substitution. */ #define MATCH_ANY 0x000 diff --git a/subst.c b/subst.c index d9d7966c..0cee56f0 100644 --- a/subst.c +++ b/subst.c @@ -4149,11 +4149,43 @@ remove_quoted_escapes (string) return (string); } -/* Perform quoted null character removal on STRING. We don't allow any - quoted null characters in the middle or at the ends of strings because - of how expand_word_internal works. remove_quoted_nulls () turns - STRING into an empty string iff it only consists of a quoted null, - and removes all unquoted CTLNUL characters. */ +/* Remove quoted $IFS characters from STRING. Quoted IFS characters are + added to protect them from word splitting, but we need to remove them + if no word splitting takes place. This returns newly-allocated memory, + so callers can use it to replace savestring(). */ +char * +remove_quoted_ifs (string) + char *string; +{ + register size_t slen; + register int i, j, prev_i; + char *ret, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + + i = j = 0; + ret = (char *)xmalloc (slen + 1); + + while (i < slen) + { + if (string[i] == CTLESC) + { + i++; + if (string[i] == 0 || isifs (string[i]) == 0) + ret[j++] = CTLESC; + if (i == slen) + break; + } + + COPY_CHAR_I (ret, j, string, send, i); + } + ret[j] = '\0'; + + return (ret); +} + char * remove_quoted_nulls (string) char *string; @@ -9084,8 +9116,10 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin /* State flags */ int had_quoted_null; + int has_quoted_ifs; /* did we add a quoted $IFS character here? */ int has_dollar_at, temp_has_dollar_at; int split_on_spaces; + int local_expanded; int tflag; int pflags; /* flags passed to param_expand */ int mb_cur_max; @@ -9119,6 +9153,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); istring[istring_index = 0] = '\0'; quoted_dollar_at = had_quoted_null = has_dollar_at = 0; + has_quoted_ifs = 0; split_on_spaces = 0; quoted_state = UNQUOTED; @@ -9247,7 +9282,10 @@ add_string: word->flags |= W_ASSIGNRHS; /* affects $@ */ if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c)) - goto add_ifs_character; + { + has_quoted_ifs++; + goto add_ifs_character; + } else goto add_character; @@ -9320,6 +9358,7 @@ add_string: case '$': if (expanded_something) *expanded_something = 1; + local_expanded = 1; temp_has_dollar_at = 0; pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0; @@ -9386,6 +9425,7 @@ add_string: if (expanded_something) *expanded_something = 1; + local_expanded = 1; if (word->flags & W_NOCOMSUB) /* sindex + 1 because string[sindex] == '`' */ @@ -9536,6 +9576,7 @@ add_twochars: *contains_dollar_at = 1; if (expanded_something) *expanded_something = 1; + local_expanded = 1; } } else @@ -9663,6 +9704,8 @@ add_twochars: add_ifs_character: if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0)) { + if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0) + has_quoted_ifs++; if (string[sindex]) /* from old goto dollar_add_string */ sindex++; if (c == 0) @@ -9840,7 +9883,19 @@ finished_with_string: list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1); else { - tword = make_bare_word (istring); +#if 0 + /* XXX might want to use *expanded_something == 0 instead of + local_expanded here */ + if (local_expanded == 0 && has_quoted_ifs) +#else + if (expanded_something && *expanded_something == 0 && has_quoted_ifs) +#endif + { + tword = alloc_word_desc (); + tword->word = remove_quoted_ifs (istring); + } + else + tword = make_bare_word (istring); set_word_flags: if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED)) tword->flags |= W_QUOTED;