diff --git a/COMPAT b/COMPAT index 07ac5177..a5128c79 100644 --- a/COMPAT +++ b/COMPAT @@ -425,6 +425,8 @@ compat43 set - the shell does not print a warning message if an attempt is made to use a quoted compound assignment as an argument to declare (declare -a foo='(1 2)') + - word expansion errors are considered non-fatal errors that cause the + current command to fail, even in Posix mode ------------------------------------------------------------------------------- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 31de3b17..c6baf1fa 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -9212,3 +9212,106 @@ builtins/exec.def doc/{bash.1,bashref.texi} - clarify definition of metacharacter to explicitly include newline; prompted by report from George Gallo + + 8/3 + --- +lib/readline/search.c + - _rl_free_history_entry: should be void, not int. Report from + Dilyan Palauzov + +general.h + - sh_load_func_t, sh_unload_func_t: new function pointer types, used by + enable for load and unload hook functions + +builtins/enable.def + - dyn_load_builtin: attempt to execute a function named BUILTIN_builtin_load, + where BUILTIN is the name of the command being loaded. If that function + returns 0, the load fails + - dyn_unload_builtin: attempt to execute a function named BUILTIN_builtin_unload, + where BUILTIN is the name of the command being unloaded. It offers a + dynamic builtin a way to clean up after itself. Inspired by suggestion + from Piotr Grzybowski in response to a bug report + from isabella parakiss + + 8/6 + --- +lib/readline/colors.[ch] + - _rl_print_color_indicator: now takes `const char *' argument + +lib/readline/complete.c + - colored_stat_start: now takes `const char *' argument + +lib/malloc/table.h + - ma_table_t: `file' member is now `const char *' + +lib/malloc/table.c + - mlocation_register_alloc: make sure variable assigned to `file' in + ma_table_t is of type `const char *'. Fixes from Dilyan Palauzov + + +lib/termcap/termcap.[ch] + - tputs: should return int instead of void + +lib/readline/readline.h + - RL_STATE_DONE: correct value, avoid collision + +lib/readline/vi_mode.c + - _rl_vi_redoing: now global, added _rl_ prefix to `vi_redoing' + +lib/readline/readline.c + - _rl_subseq_result: call _rl_dispatch_subseq instead of rl_dispatch to + avoid changing _rl_dispatching_keymap + - _rl_subseq_result: in the -2 case, set _rl_dispatching_keymap to the + map passed as an argument. Without this, vi mode doesn't call + rl_vi_set_last when it should + - _rl_dispatch_subseq: if redoing a vi mode command with `.' + (_rl_vi_redoing != 0) in callback mode and we're indirecting into another + keymap that has shadowed the key corresponding to the command we are + redoing, just call _rl_subseq_result immediately: vi redo doesn't need + to read any additional input, and rl_vi_redo assumes that a single call + to rl_dispatch is sufficient. Fixes bug reported by Carlos Pita + + + 8/7 + --- +subst.c + - parameter_brace_expand: if a substitution (parameter expansion) error + occurs, and shell_compatibility_level is <= 43, return expansion error + as in all previous versions. If shell_compatibility_level is > 43, + a posix-mode non-interactive shell will consider this a fatal error. + Problem reported by Christian Neukirchen + +doc/bashref.texi + - documented that word expansion errors cause fatal errors in posix mode + non-interactive shells + + 8/8 + --- +subst.h + - SD_COMPLETE: skip_to_delim being called as part of word completion + - SX_COMPLETE: one of the string_extract functions being called as + part of word completion + +bashline.c + - find_cmd_start,find_cmd_end,find_cmd_name: call skip_to_delim with + SD_COMPLETE flag + +subst.c + - skip_double_quoted: takes new flags argument; changed callers + - skip_double_quoted: if flags argument includes SX_COMPLETE, pass it + to extract_command_subst + - extract_command_subst: if flags&SX_COMPLETE, call + extract_delimited_string instead of xparse_dolparen, since completion + may call this for unterminated command substitutions. Fixes + (imperfectly) bug reported by Ingo Ruhnke + - skip_to_delim: if passed the SD_COMPLETE flag, pass the SX_COMPLETE + flag to skip_double_quoted + - char_is_quoted: pass SX_COMPLETE flag to skip_double_quoted + - unclosed_pair: pass SX_COMPLETE flag to skip_double_quoted + + 8/9 + --- +execute_cmd.c + - time_command: catch longjmps to top_level and print command timing + statistics even after a jump to top_level. Fixes issue reported by + Sam Watkins diff --git a/bashhist.c b/bashhist.c index 9c0df004..fbb20ea2 100644 --- a/bashhist.c +++ b/bashhist.c @@ -316,6 +316,7 @@ bash_clear_history () { clear_history (); history_lines_this_session = 0; + /* XXX - reset history_lines_read_from_file? */ } /* Delete and free the history list entry at offset I. */ diff --git a/bashline.c b/bashline.c index 9d4f0a0c..2ecd2f28 100644 --- a/bashline.c +++ b/bashline.c @@ -1319,13 +1319,13 @@ find_cmd_start (start) /* Flags == SD_NOJMP only because we want to skip over command substitutions in assignment statements. Have to test whether this affects `standalone' command substitutions as individual words. */ - while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/)) <= start) && + while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/)) <= start) && rl_line_buffer[s]) { /* Handle >| token crudely; treat as > not | */ if (rl_line_buffer[s] == '|' && rl_line_buffer[s-1] == '>') { - ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/); + ns = skip_to_delim (rl_line_buffer, s+1, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE/*|SD_NOSKIPCMD*/); if (ns > start || rl_line_buffer[ns] == 0) return os; os = ns+1; @@ -1342,7 +1342,7 @@ find_cmd_end (end) { register int e; - e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP); + e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP|SD_COMPLETE); return e; } @@ -1358,7 +1358,7 @@ find_cmd_name (start, sp, ep) ; /* skip until a shell break character */ - e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP); + e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); name = substring (rl_line_buffer, s, e); diff --git a/builtins/enable.def b/builtins/enable.def index f3ab99b0..6e8e959b 100644 --- a/builtins/enable.def +++ b/builtins/enable.def @@ -92,6 +92,11 @@ static void delete_builtin __P((struct builtin *)); static int local_dlclose __P((void *)); #endif +#define STRUCT_SUFFIX "_struct" +/* for now */ +#define LOAD_SUFFIX "_builtin_load" +#define UNLOAD_SUFFIX "_builtin_unload" + static void list_some_builtins __P((int)); static int enable_shell_command __P((char *, int)); @@ -290,8 +295,9 @@ dyn_load_builtin (list, flags, filename) WORD_LIST *l; void *handle; - int total, size, new, replaced; - char *struct_name, *name; + int total, size, new, replaced, r; + char *struct_name, *name, *funcname; + sh_load_func_t *loadfunc; struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin; if (list == 0) @@ -330,7 +336,7 @@ dyn_load_builtin (list, flags, filename) size = strlen (name); struct_name = (char *)xmalloc (size + 8); strcpy (struct_name, name); - strcpy (struct_name + size, "_struct"); + strcpy (struct_name + size, STRUCT_SUFFIX); b = (struct builtin *)dlsym (handle, struct_name); if (b == 0) @@ -344,7 +350,22 @@ dyn_load_builtin (list, flags, filename) continue; } - free (struct_name); + funcname = xrealloc (struct_name, size + sizeof (LOAD_SUFFIX) + 1); + strcpy (funcname, name); + strcpy (funcname + size, LOAD_SUFFIX); + + loadfunc = (sh_load_func_t *)dlsym (handle, funcname); + if (loadfunc) + { + r = (*loadfunc) (name); + if (r == 0) + { + builtin_error (_("load function for %s returns failure (%d): not loaded"), r); + free (funcname); + continue; + } + } + free (funcname); b->flags &= ~STATIC_BUILTIN; if (flags & SPECIAL) @@ -452,7 +473,9 @@ dyn_unload_builtin (name) { struct builtin *b; void *handle; - int ref, i; + char *funcname; + sh_unload_func_t *unloadfunc; + int ref, i, size; b = builtin_address_internal (name, 1); if (b == 0) @@ -473,6 +496,17 @@ dyn_unload_builtin (name) ref++; } + /* Call any unload function */ + size = strlen (name); + funcname = xmalloc (size + sizeof (UNLOAD_SUFFIX) + 1); + strcpy (funcname, name); + strcpy (funcname + size, UNLOAD_SUFFIX); + + unloadfunc = (sh_unload_func_t *)dlsym (handle, funcname); + if (unloadfunc) + (*unloadfunc) (name); /* void function */ + free (funcname); + /* Don't remove the shared object unless the reference count of builtins using it drops to zero. */ if (ref == 1 && local_dlclose (handle) != 0) diff --git a/doc/bashref.texi b/doc/bashref.texi index a3240879..7b75f3fa 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -7307,6 +7307,9 @@ is not found. Non-interactive shells exit if a syntax error in an arithmetic expansion results in an invalid expression. +@item +Non-interactive shells exit on word expansion errors. + @item Non-interactive shells exit if there is a syntax error in a script read with the @code{.} or @code{source} builtins, or in a string processed by diff --git a/examples/loadables/README b/examples/loadables/README index d29b43a1..2eae9cc6 100644 --- a/examples/loadables/README +++ b/examples/loadables/README @@ -34,18 +34,17 @@ new loadable builtins. basename.c Return non-directory portion of pathname. cat.c cat(1) replacement with no options - the way cat was intended. -cut.c cut(1) replacement. dirname.c Return directory portion of pathname. finfo.c Print file info. -getconf.c POSIX.2 getconf utility. -getconf.h Replacement definitions for ones the system doesn't provide. 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 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 necho.c echo without options or argument interpretation. pathchk.c Check pathnames for validity and portability. print.c Loadable ksh-93 style print builtin. diff --git a/examples/loadables/hello.c b/examples/loadables/hello.c index 9a23b5bb..fc11204b 100644 --- a/examples/loadables/hello.c +++ b/examples/loadables/hello.c @@ -56,6 +56,23 @@ hello_builtin (list) return (EXECUTION_SUCCESS); } +int +hello_builtin_load (s) + char *s; +{ + printf ("hello builtin loaded\n"); + fflush (stdout); + return (1); +} + +void +hello_builtin_unload (s) + char *s; +{ + printf ("hello builtin unloaded\n"); + fflush (stdout); +} + /* An array of strings forming the `long' documentation for a builtin xxx, which is printed by `help xxx'. It must end with a NULL. By convention, the first line is a short description. */ diff --git a/examples/loadables/mypid.c b/examples/loadables/mypid.c index 135cdb30..1f185486 100644 --- a/examples/loadables/mypid.c +++ b/examples/loadables/mypid.c @@ -5,6 +5,11 @@ * Then, from within bash, enable -f ./mypid enable_mypid, where ./mypid * is the binary obtained from running make. Hereafter, `${MYPID}' * is a shell builtin variable. + * + * This defines an unload hook function that is called when the builtin is + * deleted with enable -d that will unbind the MYPID variable so future + * references to it do not attempt to access memory that is no longer part + * of this process's address space. */ #include @@ -56,6 +61,12 @@ enable_mypid_builtin(WORD_LIST *list) return 0; } +void +enable_mypid_builtin_unload (char *s) +{ + unbind_variable ("MYPID"); +} + char const *enable_mypid_doc[] = { "Enable $MYPID.", "", diff --git a/examples/loadables/template.c b/examples/loadables/template.c index 64dd79ad..8cfd571d 100644 --- a/examples/loadables/template.c +++ b/examples/loadables/template.c @@ -41,6 +41,22 @@ template_builtin (list) return (rval); } +/* Called when `template' is enabled and loaded from the shared object. If this + function returns 0, the load fails. */ +int +template_builtin_load (name) + char *name; +{ + return (1); +} + +/* Called when `template' is disabled. */ +void +template_builtin_unload (name) + char *name; +{ +} + char *template_doc[] = { "Short description.", "" diff --git a/execute_cmd.c b/execute_cmd.c index 6c58b2c2..eaeea675 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -1304,11 +1304,12 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) int asynchronous, pipe_in, pipe_out; struct fd_bitmap *fds_to_close; { - int rv, posix_time, old_flags, nullcmd; + int rv, posix_time, old_flags, nullcmd, code; time_t rs, us, ss; int rsf, usf, ssf; int cpu; char *time_format; + volatile procenv_t save_top_level; #if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) struct timeval real, user, sys; @@ -1355,9 +1356,13 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) } old_flags = command->flags; + COPY_PROCENV (top_level, save_top_level); command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); - rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); + code = setjmp_nosigs (top_level); + if (code == NOT_JUMPED) + rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); command->flags = old_flags; + COPY_PROCENV (save_top_level, top_level); rs = us = ss = 0; rsf = usf = ssf = cpu = 0; @@ -1416,6 +1421,9 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) if (time_format && *time_format) print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); + if (code) + sh_longjmp (top_level, code); + return rv; } #endif /* COMMAND_TIMING */ diff --git a/general.h b/general.h index a4e322d9..430aeceb 100644 --- a/general.h +++ b/general.h @@ -219,6 +219,9 @@ typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */ typedef int sh_assign_func_t __P((const char *)); typedef int sh_wassign_func_t __P((WORD_DESC *, int)); +typedef int sh_load_func_t __P((char *)); +typedef void sh_unload_func_t __P((char *)); + typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */ #endif /* SH_FUNCTION_TYPEDEF */ diff --git a/lib/malloc/table.c b/lib/malloc/table.c index 1e642d33..49b6a55f 100644 --- a/lib/malloc/table.c +++ b/lib/malloc/table.c @@ -340,7 +340,7 @@ mlocation_register_alloc (file, line) int line; { ma_table_t *lentry; - char *nfile; + const char *nfile; if (file == 0) { diff --git a/lib/malloc/table.h b/lib/malloc/table.h index f9c5f1c4..7494f0a5 100644 --- a/lib/malloc/table.h +++ b/lib/malloc/table.h @@ -65,7 +65,7 @@ extern void mregister_dump_table __P((void)); extern void mregister_table_init __P((void)); typedef struct ma_table { - char *file; + const char *file; int line; int nalloc; } ma_table_t; diff --git a/lib/readline/colors.c b/lib/readline/colors.c index 963dc12e..d4bcb32e 100644 --- a/lib/readline/colors.c +++ b/lib/readline/colors.c @@ -120,7 +120,7 @@ _rl_print_prefix_color (void) /* Returns whether any color sequence was printed. */ bool -_rl_print_color_indicator (char *f) +_rl_print_color_indicator (const char *f) { enum indicator_no colored_filetype; COLOR_EXT_TYPE *ext; /* Color extension */ diff --git a/lib/readline/colors.h b/lib/readline/colors.h index 5c77af9d..ec627747 100644 --- a/lib/readline/colors.h +++ b/lib/readline/colors.h @@ -120,7 +120,7 @@ enum filetype extern void _rl_put_indicator (const struct bin_str *ind); extern void _rl_set_normal_color (void); extern bool _rl_print_prefix_color (void); -extern bool _rl_print_color_indicator (char *f); +extern bool _rl_print_color_indicator (const char *f); extern void _rl_prep_non_filename_text (void); #endif /* !_COLORS_H_ */ diff --git a/lib/readline/complete.c b/lib/readline/complete.c index f905c09f..d0bbe7df 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -111,7 +111,7 @@ static int stat_char PARAMS((char *)); #endif #if defined (COLOR_SUPPORT) -static int colored_stat_start PARAMS((char *)); +static int colored_stat_start PARAMS((const char *)); static void colored_stat_end PARAMS((void)); static int colored_prefix_start PARAMS((void)); static void colored_prefix_end PARAMS((void)); @@ -676,7 +676,7 @@ stat_char (filename) #if defined (COLOR_SUPPORT) static int colored_stat_start (filename) - char *filename; + const char *filename; { _rl_set_normal_color (); return (_rl_print_color_indicator (filename)); diff --git a/lib/readline/examples/fileman.c b/lib/readline/examples/fileman.c index f7eed8a9..c821df03 100644 --- a/lib/readline/examples/fileman.c +++ b/lib/readline/examples/fileman.c @@ -63,6 +63,12 @@ extern char *xmalloc PARAMS((size_t)); +void initialize_readline PARAMS((void)); +void too_dangerous PARAMS((char *)); + +int execute_line PARAMS((char *)); +int valid_argument PARAMS((char *, char *)); + /* The names of functions that actually do the manipulation. */ int com_list PARAMS((char *)); int com_view PARAMS((char *)); @@ -119,6 +125,7 @@ dupstr (s) return (r); } +int main (argc, argv) int argc; char **argv; @@ -241,6 +248,7 @@ char **fileman_completion PARAMS((const char *, int, int)); /* Tell the GNU Readline library how to complete. We want to try to complete on command names if this is the first word in the line, or on filenames if not. */ +void initialize_readline () { /* Allow conditional parsing of the ~/.inputrc file. */ @@ -317,6 +325,7 @@ command_generator (text, state) static char syscom[1024]; /* List the file(s) named in arg. */ +int com_list (arg) char *arg; { @@ -327,6 +336,7 @@ com_list (arg) return (system (syscom)); } +int com_view (arg) char *arg; { @@ -342,6 +352,7 @@ com_view (arg) return (system (syscom)); } +int com_rename (arg) char *arg; { @@ -349,6 +360,7 @@ com_rename (arg) return (1); } +int com_stat (arg) char *arg; { @@ -377,6 +389,7 @@ com_stat (arg) return (0); } +int com_delete (arg) char *arg; { @@ -386,6 +399,7 @@ com_delete (arg) /* Print out help for ARG, or for all of the commands if ARG is not present. */ +int com_help (arg) char *arg; { @@ -425,6 +439,7 @@ com_help (arg) } /* Change to the directory ARG. */ +int com_cd (arg) char *arg; { @@ -439,6 +454,7 @@ com_cd (arg) } /* Print out the current working directory. */ +int com_pwd (ignore) char *ignore; { @@ -456,6 +472,7 @@ com_pwd (ignore) } /* The user wishes to quit using this program. Just set DONE non-zero. */ +int com_quit (arg) char *arg; { @@ -464,6 +481,7 @@ com_quit (arg) } /* Function which tells you that you can't do this. */ +void too_dangerous (caller) char *caller; { diff --git a/lib/readline/examples/rl.c b/lib/readline/examples/rl.c index 845a4b17..a5cf276c 100644 --- a/lib/readline/examples/rl.c +++ b/lib/readline/examples/rl.c @@ -28,6 +28,7 @@ # include #endif +#include #include #include diff --git a/lib/readline/readline.c b/lib/readline/readline.c index ce72501d..71f666ce 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -930,6 +930,16 @@ _rl_dispatch_subseq (key, map, got_subseq) /* Allocate new context here. Use linked contexts (linked through cxt->ocxt) to simulate recursion */ #if defined (READLINE_CALLBACKS) +# if defined (VI_MODE) + /* If we're redoing a vi mode command and we know there is a shadowed + function corresponding to this key, just call it -- all the redoable + vi mode commands already have all the input they need, and rl_vi_redo + assumes that one call to rl_dispatch is sufficient to complete the + command. */ + if (_rl_vi_redoing && RL_ISSTATE (RL_STATE_CALLBACK) && + map[ANYOTHERKEY].function != 0) + return (_rl_subseq_result (-2, map, key, got_subseq)); +# endif if (RL_ISSTATE (RL_STATE_CALLBACK)) { /* Return 0 only the first time, to indicate success to @@ -992,6 +1002,7 @@ _rl_dispatch_subseq (key, map, got_subseq) } break; } + #if defined (VI_MODE) if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && key != ANYOTHERKEY && @@ -1037,7 +1048,9 @@ _rl_subseq_result (r, map, key, got_subseq) m[key].type = type; m[key].function = func; - r = _rl_dispatch (key, m); + /* Don't change _rl_dispatching_keymap, set it here */ + _rl_dispatching_keymap = map; /* previous map */ + r = _rl_dispatch_subseq (key, m, 0); m[key].type = nt; m[key].function = nf; } diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 8d71f9a7..6b63ae4b 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -873,7 +873,7 @@ extern int rl_inhibit_completion; #define RL_STATE_CHARSEARCH 0x0800000 /* vi mode char search */ #define RL_STATE_REDISPLAYING 0x1000000 /* updating terminal display */ -#define RL_STATE_DONE 0x1000000 /* done; accepted line */ +#define RL_STATE_DONE 0x2000000 /* done; accepted line */ #define RL_SETSTATE(x) (rl_readline_state |= (x)) #define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 8064f9ff..fb3644ea 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -558,6 +558,7 @@ extern int _rl_undo_group_level; /* vi_mode.c */ extern int _rl_vi_last_command; +extern int _rl_vi_redoing; extern _rl_vimotion_cxt *_rl_vimvcxt; #endif /* _RL_PRIVATE_H_ */ diff --git a/lib/readline/search.c b/lib/readline/search.c index c9bc6b1c..cf2ae8f7 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -58,7 +58,7 @@ _rl_search_cxt *_rl_nscxt = 0; extern HIST_ENTRY *_rl_saved_line_for_history; /* Functions imported from the rest of the library. */ -extern int _rl_free_history_entry PARAMS((HIST_ENTRY *)); +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); static char *noninc_search_string = (char *) NULL; static int noninc_history_pos; diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index dcde2fbd..f4cce5db 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -67,6 +67,9 @@ int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ _rl_vimotion_cxt *_rl_vimvcxt = 0; +/* Non-zero indicates we are redoing a vi-mode command with `.' */ +int _rl_vi_redoing; + /* Non-zero means enter insertion mode. */ static int _rl_vi_doing_insert; @@ -100,8 +103,6 @@ static int _rl_vi_last_replacement; static int _rl_vi_last_key_before_insert; -static int vi_redoing; - /* Text modification commands. These are the `redoable' commands. */ static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; @@ -241,7 +242,7 @@ rl_vi_redo (count, c) } r = 0; - vi_redoing = 1; + _rl_vi_redoing = 1; /* If we're redoing an insert with `i', stuff in the inserted text and do not go into insertion mode. */ if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) @@ -287,7 +288,8 @@ rl_vi_redo (count, c) } else r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); - vi_redoing = 0; + + _rl_vi_redoing = 0; return (r); } @@ -1335,12 +1337,12 @@ rl_vi_delete_to (count, key) _rl_vimvcxt->motion = '$'; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */ + else if (_rl_vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */ { _rl_vimvcxt->motion = _rl_vi_last_motion; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing) /* handle redoing `dd' here */ + else if (_rl_vi_redoing) /* handle redoing `dd' here */ { _rl_vimvcxt->motion = _rl_vi_last_motion; rl_mark = rl_end; @@ -1385,7 +1387,7 @@ vi_change_dispatch (m) if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start) rl_point = m->start; - if (vi_redoing) + if (_rl_vi_redoing) { if (vi_insert_buffer && *vi_insert_buffer) rl_begin_undo_group (); @@ -1425,12 +1427,12 @@ rl_vi_change_to (count, key) _rl_vimvcxt->motion = '$'; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */ + else if (_rl_vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */ { _rl_vimvcxt->motion = _rl_vi_last_motion; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing) /* handle redoing `cc' here */ + else if (_rl_vi_redoing) /* handle redoing `cc' here */ { _rl_vimvcxt->motion = _rl_vi_last_motion; rl_mark = rl_end; @@ -1494,12 +1496,12 @@ rl_vi_yank_to (count, key) _rl_vimvcxt->motion = '$'; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */ + else if (_rl_vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */ { _rl_vimvcxt->motion = _rl_vi_last_motion; r = rl_domove_motion_callback (_rl_vimvcxt); } - else if (vi_redoing) /* handle redoing `yy' here */ + else if (_rl_vi_redoing) /* handle redoing `yy' here */ { _rl_vimvcxt->motion = _rl_vi_last_motion; rl_mark = rl_end; @@ -1719,7 +1721,7 @@ rl_vi_char_search (count, key) break; } - if (vi_redoing) + if (_rl_vi_redoing) { /* set target and tlen below */ } @@ -1955,7 +1957,7 @@ rl_vi_change_char (count, key) int c; char mb[MB_LEN_MAX]; - if (vi_redoing) + if (_rl_vi_redoing) { c = _rl_vi_last_replacement; mb[0] = c; @@ -1983,7 +1985,7 @@ rl_vi_subst (count, key) int count, key; { /* If we are redoing, rl_vi_change_to will stuff the last motion char */ - if (vi_redoing == 0) + if (_rl_vi_redoing == 0) rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ return (rl_vi_change_to (count, 'c')); diff --git a/lib/termcap/termcap.c b/lib/termcap/termcap.c index 7311349b..ba3dab2c 100644 --- a/lib/termcap/termcap.c +++ b/lib/termcap/termcap.c @@ -309,7 +309,7 @@ static int speeds[] = }; __private_extern__ -void +int tputs (str, nlines, outfun) register char *str; int nlines; @@ -335,7 +335,7 @@ tputs (str, nlines, outfun) #endif if (!str) - return; + return -1; while (*str >= '0' && *str <= '9') { @@ -372,6 +372,8 @@ tputs (str, nlines, outfun) while (padcount-- > 0) (*outfun) (PC); + + return 0; } /* Finding the termcap entry in the termcap data base. */ diff --git a/lib/termcap/termcap.h b/lib/termcap/termcap.h index 5d715956..b0e3061f 100644 --- a/lib/termcap/termcap.h +++ b/lib/termcap/termcap.h @@ -29,7 +29,7 @@ extern char *tgetstr (const char *name, char **area); extern char PC; extern short ospeed; -extern void tputs (const char *string, int nlines, int (*outfun) (int)); +extern int tputs (const char *string, int nlines, int (*outfun) (int)); extern char *tparam (const char *ctlstring, char *buffer, int size, ...); diff --git a/subst.c b/subst.c index d445c2c1..383c9392 100644 --- a/subst.c +++ b/subst.c @@ -247,7 +247,7 @@ static char *string_extract __P((char *, int *, char *, int)); static char *string_extract_double_quoted __P((char *, int *, int)); static inline char *string_extract_single_quoted __P((char *, int *)); static inline int skip_single_quoted __P((const char *, size_t, int)); -static int skip_double_quoted __P((char *, size_t, int)); +static int skip_double_quoted __P((char *, size_t, int, int)); static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); static char *extract_dollar_brace_string __P((char *, int *, int, int)); static int skip_matched_pair __P((const char *, int, int, int, int)); @@ -631,7 +631,7 @@ unquoted_member (character, string) break; case '"': - sindex = skip_double_quoted (string, slen, ++sindex); + sindex = skip_double_quoted (string, slen, ++sindex, 0); break; } } @@ -670,7 +670,7 @@ unquoted_substring (substr, string) break; case '"': - sindex = skip_double_quoted (string, slen, ++sindex); + sindex = skip_double_quoted (string, slen, ++sindex, 0); break; default: @@ -969,7 +969,7 @@ add_one_character: /* This should really be another option to string_extract_double_quoted. */ static int -skip_double_quoted (string, slen, sind) +skip_double_quoted (string, slen, sind, flags) char *string; size_t slen; int sind; @@ -1012,7 +1012,7 @@ skip_double_quoted (string, slen, sind) { si = i + 2; if (string[i + 1] == LPAREN) - ret = extract_command_subst (string, &si, SX_NOALLOC); + ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE)); else ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC); @@ -1191,7 +1191,7 @@ extract_command_subst (string, sindex, xflags) int *sindex; int xflags; { - if (string[*sindex] == LPAREN) + if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE)) return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ else { @@ -1376,7 +1376,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) { si = i + 1; i = (c == '\'') ? skip_single_quoted (string, slen, si) - : skip_double_quoted (string, slen, si); + : skip_double_quoted (string, slen, si, 0); continue; } @@ -1502,7 +1502,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags) if (c == '"') { si = i + 1; - i = skip_double_quoted (string, slen, si); + i = skip_double_quoted (string, slen, si, 0); /* skip_XXX_quoted leaves index one past close quote */ continue; } @@ -1689,7 +1689,7 @@ skip_matched_pair (string, start, open, close, flags) else if ((flags & 1) == 0 && (c == '\'' || c == '"')) { i = (c == '\'') ? skip_single_quoted (ss, slen, ++i) - : skip_double_quoted (ss, slen, ++i); + : skip_double_quoted (ss, slen, ++i, 0); /* no increment, the skip functions increment past the closing quote. */ } else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE)) @@ -1738,7 +1738,8 @@ skip_to_delim (string, start, delims, flags) char *delims; int flags; { - int i, pass_next, backq, si, c, invert, skipquote, skipcmd, noprocsub; + int i, pass_next, backq, si, c; + int invert, skipquote, skipcmd, noprocsub, completeflag; size_t slen; char *temp, open[3]; DECLARE_MBSTATE; @@ -1749,6 +1750,7 @@ skip_to_delim (string, start, delims, flags) invert = (flags & SD_INVERT); skipcmd = (flags & SD_NOSKIPCMD) == 0; noprocsub = (flags & SD_NOPROCSUB); + completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0; i = start; pass_next = backq = 0; @@ -1791,7 +1793,7 @@ skip_to_delim (string, start, delims, flags) else if (c == '\'' || c == '"') { i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); + : skip_double_quoted (string, slen, ++i, completeflag); /* no increment, the skip functions increment past the closing quote. */ } else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE)) @@ -1913,7 +1915,7 @@ char_is_quoted (string, eindex) else if (c == '\'' || c == '"') { i = (c == '\'') ? skip_single_quoted (string, slen, ++i) - : skip_double_quoted (string, slen, ++i); + : skip_double_quoted (string, slen, ++i, SX_COMPLETE); if (i > eindex) CQ_RETURN(1); /* no increment, the skip_xxx functions go one past end */ @@ -1962,7 +1964,7 @@ unclosed_pair (string, eindex, openstr) else if (string[i] == '\'' || string[i] == '"') { i = (string[i] == '\'') ? skip_single_quoted (string, slen, i) - : skip_double_quoted (string, slen, i); + : skip_double_quoted (string, slen, i, SX_COMPLETE); if (i > eindex) return 0; } @@ -2725,7 +2727,7 @@ list_string_with_quotes (string) else if (c == '\'') i = skip_single_quoted (s, s_len, ++i); else if (c == '"') - i = skip_double_quoted (s, s_len, ++i); + i = skip_double_quoted (s, s_len, ++i, 0); else if (c == 0 || spctabnl (c)) { /* We have found the end of a token. Make a word out of it and @@ -7535,7 +7537,7 @@ chk_arithsub (s, len) break; case '"': - i = skip_double_quoted ((char *)s, len, ++i); + i = skip_double_quoted ((char *)s, len, ++i, 0); break; } } @@ -7677,7 +7679,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta member (c, "%:=+/") && string[sindex] == RBRACE) { temp = (char *)NULL; - goto bad_substitution; + goto bad_substitution; /* XXX - substitution error */ } /* Indirect expansion begins with a `!'. A valid indirect expansion is @@ -7704,7 +7706,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0)) { temp = (char *)NULL; - goto bad_substitution; + goto bad_substitution; /* substitution error */ } number = parameter_brace_expand_length (name); @@ -7819,7 +7821,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta var_is_special) == 0) { temp = (char *)NULL; - goto bad_substitution; + goto bad_substitution; /* substitution error */ } if (want_indir) @@ -7878,7 +7880,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta if (string[sindex] == RBRACE) sindex++; else - goto bad_substitution; + goto bad_substitution; /* substitution error */ } else value = (char *)NULL; @@ -7973,25 +7975,31 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta { default: case '\0': - bad_substitution: +bad_substitution: last_command_exit_value = EXECUTION_FAILURE; report_error (_("%s: bad substitution"), string ? string : "??"); FREE (value); FREE (temp); free (name); - return &expand_wdesc_error; + if (shell_compatibility_level <= 43) + return &expand_wdesc_error; + else + return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error); case RBRACE: break; case '@': temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); - if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) - goto bad_substitution; - free (temp); free (value); free (name); + if (temp1 == &expand_param_error || temp1 == &expand_param_fatal) + { + last_command_exit_value = EXECUTION_FAILURE; + report_error (_("%s: bad substitution"), string ? string : "??"); + return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal); + } ret = alloc_word_desc (); ret->word = temp1; diff --git a/subst.h b/subst.h index 71f572c3..28cde9b9 100644 --- a/subst.h +++ b/subst.h @@ -62,6 +62,7 @@ #define SX_ARITHSUB 0x0080 /* extracting $(( ... )) (currently unused) */ #define SX_POSIXEXP 0x0100 /* extracting new Posix pattern removal expansions in extract_dollar_brace_string */ #define SX_WORD 0x0200 /* extracting word in ${param op word} */ +#define SX_COMPLETE 0x0400 /* extracting word for completion */ /* Remove backslashes which are quoting backquotes from STRING. Modifies STRING, and returns a pointer to it. */ @@ -282,14 +283,15 @@ extern char *cond_expand_word __P((WORD_DESC *, int)); #endif /* Flags for skip_to_delim */ -#define SD_NOJMP 0x01 /* don't longjmp on fatal error. */ -#define SD_INVERT 0x02 /* look for chars NOT in passed set */ -#define SD_NOQUOTEDELIM 0x04 /* don't let single or double quotes act as delimiters */ -#define SD_NOSKIPCMD 0x08 /* don't skip over $(, <(, or >( command/process substitution; parse them as commands */ -#define SD_EXTGLOB 0x10 /* skip over extended globbing patterns if appropriate */ -#define SD_IGNOREQUOTE 0x20 /* single and double quotes are not special */ -#define SD_GLOB 0x40 /* skip over glob patterns like bracket expressions */ -#define SD_NOPROCSUB 0x80 /* don't parse process substitutions as commands */ +#define SD_NOJMP 0x001 /* don't longjmp on fatal error. */ +#define SD_INVERT 0x002 /* look for chars NOT in passed set */ +#define SD_NOQUOTEDELIM 0x004 /* don't let single or double quotes act as delimiters */ +#define SD_NOSKIPCMD 0x008 /* don't skip over $(, <(, or >( command/process substitution; parse them as commands */ +#define SD_EXTGLOB 0x010 /* skip over extended globbing patterns if appropriate */ +#define SD_IGNOREQUOTE 0x020 /* single and double quotes are not special */ +#define SD_GLOB 0x040 /* skip over glob patterns like bracket expressions */ +#define SD_NOPROCSUB 0x080 /* don't parse process substitutions as commands */ +#define SD_COMPLETE 0x100 /* skip_to_delim during completion */ extern int skip_to_delim __P((char *, int, char *, int)); diff --git a/trap.c b/trap.c index 8162bbfe..bf3cfbc6 100644 --- a/trap.c +++ b/trap.c @@ -931,7 +931,7 @@ _run_trap_internal (sig, tag) int trap_exit_value, *token_state; volatile int save_return_catch_flag, function_code, top_level_code, old_int; int flags; - procenv_t save_return_catch, save_top_level; + procenv_t save_return_catch; WORD_LIST *save_subst_varlist; sh_parser_state_t pstate; #if defined (ARRAY_VARS)