From: Chet Ramey Date: Mon, 6 Nov 2023 14:49:49 +0000 (-0500) Subject: fix bug with custom completion suffix; split filename completion rewrite hooks into... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5e50a6456d0a8e744f55010491a6fbe1a2add6d;p=thirdparty%2Freadline.git fix bug with custom completion suffix; split filename completion rewrite hooks into two functions; new `execute-named-command' bindable function --- diff --git a/MANIFEST b/MANIFEST index 24da6e8..6db30fd 100644 --- a/MANIFEST +++ b/MANIFEST @@ -90,14 +90,14 @@ histsearch.c f patchlevel f shlib/Makefile.in f support/config.guess f -support/config.rpath f +support/config.rpath f 755 support/config.sub f -support/install.sh f -support/mkdirs f +support/install.sh f 755 +support/mkdirs f 755 support/mkdist f -support/mkinstalldirs f +support/mkinstalldirs f 755 support/shobj-conf f -support/shlib-install f +support/shlib-install f 755 support/wcwidth.c f doc/Makefile.in f doc/texinfo.tex f diff --git a/aclocal.m4 b/aclocal.m4 index 96d6383..26af88a 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -955,6 +955,9 @@ TERMCAP_DEP= elif test $bash_cv_termcap_lib = libncurses; then TERMCAP_LIB=-lncurses TERMCAP_DEP= +elif test $bash_cv_termcap_lib = libcurses; then +TERMCAP_LIB=-lcurses +TERMCAP_DEP= elif test $bash_cv_termcap_lib = libc; then TERMCAP_LIB= TERMCAP_DEP= diff --git a/colors.c b/colors.c index dba81a2..28ed7bc 100644 --- a/colors.c +++ b/colors.c @@ -2,7 +2,7 @@ Modified by Chet Ramey for Readline. - Copyright (C) 1985, 1988, 1990-1991, 1995-2021 + Copyright (C) 1985, 1988, 1990-1991, 1995-2021, 2023 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -73,7 +73,7 @@ static bool is_colored (enum indicator_no type); static void restore_default_color (void); -#define RL_COLOR_PREFIX_EXTENSION "readline-colored-completion-prefix" +#define RL_COLOR_PREFIX_EXTENSION ".readline-colored-completion-prefix" COLOR_EXT_TYPE *_rl_color_ext_list = 0; diff --git a/complete.c b/complete.c index 9f17033..d202e08 100644 --- a/complete.c +++ b/complete.c @@ -246,11 +246,24 @@ rl_icppfunc_t *rl_filename_stat_hook = (rl_icppfunc_t *)NULL; either return its first argument (if no conversion takes place) or newly-allocated memory. This can, for instance, convert filenames between character sets for comparison against what's typed at the - keyboard. The returned value is what is added to the list of - matches. The second argument is the length of the filename to be - converted. */ + keyboard (after its potential modification by rl_completion_rewrite_hook). + The returned value is what is added to the list of matches. + The second argument is the length of the filename to be converted. */ rl_dequote_func_t *rl_filename_rewrite_hook = (rl_dequote_func_t *)NULL; +/* If non-zero, this is the address of a function to call before + comparing the filename portion of a word to be completed with directory + entries from the filesystem. This takes the address of the partial word + to be completed, after any rl_filename_dequoting_function has been applied. + The function should either return its first argument (if no conversion + takes place) or newly-allocated memory. This can, for instance, convert + the filename portion of the completion word to a character set suitable + for comparison against directory entries read from the filesystem (after + their potential modification by rl_filename_rewrite_hook). + The returned value is what is added to the list of matches. + The second argument is the length of the filename to be converted. */ +rl_dequote_func_t *rl_completion_rewrite_hook = (rl_dequote_func_t *)NULL; + /* Non-zero means readline completion functions perform tilde expansion. */ int rl_complete_with_tilde_expansion = 0; @@ -460,6 +473,7 @@ rl_complete (int ignore, int invoking_key) int rl_possible_completions (int ignore, int invoking_key) { + last_completion_failed = 0; rl_completion_invoking_key = invoking_key; return (rl_complete_internal ('?')); } @@ -2174,7 +2188,9 @@ rl_complete_internal (int what_to_do) append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); break; } - + /*FALLTHROUGH*/ + + case '%': do_display = 1; break; @@ -2537,9 +2553,9 @@ rl_filename_completion_function (const char *text, int state) filename_len = strlen (filename); /* Normalize the filename if the application has set a rewrite hook. */ - if (*filename && rl_filename_rewrite_hook) + if (*filename && rl_completion_rewrite_hook) { - temp = (*rl_filename_rewrite_hook) (filename, filename_len); + temp = (*rl_completion_rewrite_hook) (filename, filename_len); if (temp != filename) { xfree (filename); diff --git a/doc/hsuser.texi b/doc/hsuser.texi index 1771140..386d6c5 100644 --- a/doc/hsuser.texi +++ b/doc/hsuser.texi @@ -288,14 +288,14 @@ current one. The line selected from the history is called the @dfn{event}, and the portions of that line that are acted upon are called @dfn{words}. -The dfn{event designator} selects the event, the optional +The line is broken into words in the same fashion +that Bash does, so that several words +surrounded by quotes are considered one word. +The @dfn{event designator} selects the event, the optional @dfn{word designator} selects words from the event, and various optional @dfn{modifiers} are available to manipulate the selected words. -The line is broken into words in the same fashion -that Bash does, so that several words -surrounded by quotes are considered one word. History expansions are introduced by the appearance of the history expansion character, which is @samp{!} by default. History expansions may appear anywhere in the input, but do not nest. diff --git a/doc/rltech.texi b/doc/rltech.texi index c83d99d..8b9bd8c 100644 --- a/doc/rltech.texi +++ b/doc/rltech.texi @@ -1377,7 +1377,6 @@ If the application has assigned a value to @code{rl_macro_display_hook}, @code{rl_macro_dumper} calls it instead of printing anything. If @var{readable} is greater than zero, the list is formatted in such a way that it can be made part of an @code{inputrc} file and re-read. - @end deftypefun @deftypefun int rl_variable_bind (const char *variable, const char *value) @@ -1413,6 +1412,10 @@ use all of a terminal's capabilities, and this function will return values for only those capabilities Readline uses. @end deftypefun +@deftypefun {void} rl_reparse_colors (void) +Read or re-read color definitions from @env{LS_COLORS}. +@end deftypefun + @deftypefun {void} rl_clear_history (void) Clear the history list by deleting all of the entries, in the same manner as the History library's @code{clear_history()} function. @@ -2162,7 +2165,9 @@ The function should not modify the directory argument if it returns 0. @deftypevar {rl_dequote_func_t *} rl_filename_rewrite_hook If non-zero, this is the address of a function called when reading directory entries from the filesystem for completion and comparing -them to the partial word to be completed. The function should +them to the filename portion of the partial word to be completed +(after its potential modification by @code{rl_completion_rewrite_hook}). +The function should perform any necessary application or system-specific conversion on the filename, such as converting between character sets or converting from a filesystem format to a character input format. @@ -2175,6 +2180,24 @@ matches, is added to the list of matches. Readline will free the allocated string. @end deftypevar +@deftypevar {rl_dequote_func_t *} rl_completion_rewrite_hook +If non-zero, this is the address of a function to call before +comparing the filename portion of a word to be completed with directory +entries from the filesystem. +The function takes two arguments: @var{fname}, the filename to be converted, +after any @code{rl_filename_dequoting_function} has been applied, +and @var{fnlen}, its length in bytes. +It must either return its first argument (if no conversion takes place) +or the converted filename in newly-allocated memory. +The function should perform any necessary application or system-specific +conversion on the filename, such as converting between character sets or +converting from a character input format to some other format. +Readline compares the converted form against directory entries, after +their potential modification by @code{rl_filename_rewrite_hook}, and adds +any matches to the list of matches. +Readline will free the allocated string. +@end deftypevar + @deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook If non-zero, then this is the address of a function to call when completing a word would normally display the list of possible matches. diff --git a/doc/rluser.texi b/doc/rluser.texi index a0cf21c..72d951a 100644 --- a/doc/rluser.texi +++ b/doc/rluser.texi @@ -1912,6 +1912,13 @@ editing mode. @end ifclear +@item execute-named-command (M-x) +Read a bindable readline command name from the input and execute the +function to which it's bound, as if the key sequence to which it was +bound appeared in the input. +If this function is supplied with a numeric argument, it passes that +argument to the function it executes. + @end ftable @node Readline vi Mode diff --git a/doc/version.texi b/doc/version.texi index 19dfe9a..aa585cd 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -5,7 +5,7 @@ Copyright (C) 1988-2023 Free Software Foundation, Inc. @set EDITION 8.3 @set VERSION 8.3 -@set UPDATED 31 July 2023 -@set UPDATED-MONTH July 2023 +@set UPDATED 3 November 2023 +@set UPDATED-MONTH November 2023 -@set LASTCHANGE Mon Jul 31 10:09:09 EDT 2023 +@set LASTCHANGE Fri Nov 3 12:04:26 EDT 2023 diff --git a/emacs_keymap.c b/emacs_keymap.c index 02597da..cf2adcc 100644 --- a/emacs_keymap.c +++ b/emacs_keymap.c @@ -448,7 +448,7 @@ KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { { ISFUNC, rl_upcase_word }, /* Meta-u */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-v */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-w */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-x */ + { ISFUNC, rl_execute_named_command }, /* Meta-x */ { ISFUNC, rl_yank_pop }, /* Meta-y */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-z */ diff --git a/examples/Makefile.in b/examples/Makefile.in index dc1aba3..f3dd266 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -71,7 +71,7 @@ TERMCAP_LIB = @TERMCAP_LIB@ SOURCES = excallback.c fileman.c histexamp.c manexamp.c rl-fgets.c rl.c \ rlbasic.c rlcat.c rlevent.c rlptytest.c rltest.c rlversion.c \ - rltest2.c rl-callbacktest.c hist_erasedups.c hist_purgecmd.c \ + rl-callbacktest.c hist_erasedups.c hist_purgecmd.c \ rlkeymaps.c rl-timeout.c EXECUTABLES = fileman$(EXEEXT) rltest$(EXEEXT) rl$(EXEEXT) rlcat$(EXEEXT) \ @@ -81,7 +81,7 @@ EXECUTABLES = fileman$(EXEEXT) rltest$(EXEEXT) rl$(EXEEXT) rlcat$(EXEEXT) \ rlkeymaps$(EXEEXT) rl-timeout$(EXEEXT) OBJECTS = fileman.o rltest.o rl.o rlevent.o rlcat.o rlversion.o histexamp.o \ - rltest2.o rl-callbacktest.o rlbasic.o hist_erasedups.o hist_purgecmd.o \ + rl-callbacktest.o rlbasic.o hist_erasedups.o hist_purgecmd.o \ rlkeymaps.o rl-timeout.o OTHEREXE = rlptytest$(EXEEXT) diff --git a/examples/autoconf/BASH_CHECK_LIB_TERMCAP b/examples/autoconf/BASH_CHECK_LIB_TERMCAP index 0a09883..7047d72 100644 --- a/examples/autoconf/BASH_CHECK_LIB_TERMCAP +++ b/examples/autoconf/BASH_CHECK_LIB_TERMCAP @@ -31,11 +31,14 @@ TERMCAP_DEP= elif test $bash_cv_termcap_lib = libncurses; then TERMCAP_LIB=-lncurses TERMCAP_DEP= +elif test $bash_cv_termcap_lib = libcurses; then +TERMCAP_LIB=-lcurses +TERMCAP_DEP= elif test $bash_cv_termcap_lib = libc; then TERMCAP_LIB= TERMCAP_DEP= else -TERMCAP_LIB=-lcurses +TERMCAP_LIB=-lncurses TERMCAP_DEP= fi ]) diff --git a/funmap.c b/funmap.c index affa0fd..548cfb5 100644 --- a/funmap.c +++ b/funmap.c @@ -89,6 +89,7 @@ static const FUNMAP default_funmap[] = { { "end-of-history", rl_end_of_history }, { "end-of-line", rl_end_of_line }, { "exchange-point-and-mark", rl_exchange_point_and_mark }, + { "execute-named-command", rl_execute_named_command }, { "fetch-history", rl_fetch_history }, { "forward-backward-delete-char", rl_rubout_or_delete }, { "forward-byte", rl_forward_byte }, diff --git a/misc.c b/misc.c index 7e3efca..bbb0332 100644 --- a/misc.c +++ b/misc.c @@ -150,6 +150,7 @@ _rl_arg_dispatch (_rl_arg_cxt cxt, int c) if (_rl_digit_p (c)) { + _rl_add_executing_keyseq (key); r = _rl_digit_value (c); rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + r : r; rl_explicit_arg = 1; @@ -157,6 +158,7 @@ _rl_arg_dispatch (_rl_arg_cxt cxt, int c) } else if (c == '-' && rl_explicit_arg == 0) { + _rl_add_executing_keyseq (key); rl_numeric_arg = 1; _rl_argcxt |= NUM_SAWMINUS; rl_arg_sign = -1; @@ -808,7 +810,10 @@ _rl_set_insert_mode (int im, int force) _rl_set_cursor (im, force); #endif + RL_UNSETSTATE (RL_STATE_OVERWRITE); rl_insert_mode = im; + if (rl_insert_mode == RL_IM_OVERWRITE) + RL_SETSTATE (RL_STATE_OVERWRITE); } /* Toggle overwrite mode. A positive explicit argument selects overwrite diff --git a/parse-colors.c b/parse-colors.c index 05ec9bc..2b58eb9 100644 --- a/parse-colors.c +++ b/parse-colors.c @@ -297,6 +297,22 @@ get_funky_string (char **dest, const char **src, bool equals_end, size_t *output } #endif /* COLOR_SUPPORT */ +static void +free_color_ext_list (void) +{ + COLOR_EXT_TYPE *e; + COLOR_EXT_TYPE *e2; + + for (e = _rl_color_ext_list; e != NULL; /* empty */) + { + e2 = e; + e = e->next; + free (e2); + } + + _rl_color_ext_list = 0; +} + void _rl_parse_colors(void) { #if defined (COLOR_SUPPORT) @@ -420,21 +436,32 @@ void _rl_parse_colors(void) if (state < 0) { - COLOR_EXT_TYPE *e; - COLOR_EXT_TYPE *e2; _rl_errmsg ("unparsable value for LS_COLORS environment variable"); free (color_buf); - for (e = _rl_color_ext_list; e != NULL; /* empty */) - { - e2 = e; - e = e->next; - free (e2); - } - _rl_color_ext_list = NULL; + free_color_ext_list (); + _rl_colored_stats = 0; /* can't have colored stats without colors */ + _rl_colored_completion_prefix = 0; /* or colored prefixes */ } #else /* !COLOR_SUPPORT */ ; #endif /* !COLOR_SUPPORT */ } + +void +rl_reparse_colors (void) +{ + char *v; + + v = sh_get_env_value ("LS_COLORS"); + if (v == 0 && color_buf == 0) + return; /* no change */ + if (v && color_buf && STREQ (v, color_buf)) + return; /* no change */ + + free (color_buf); + free_color_ext_list (); + + _rl_parse_colors (); +} diff --git a/readline.c b/readline.c index cf70a01..608c65e 100644 --- a/readline.c +++ b/readline.c @@ -1576,7 +1576,7 @@ void _rl_add_executing_keyseq (int key) { RESIZE_KEYSEQ_BUFFER (); - rl_executing_keyseq[rl_key_sequence_length++] = key; + rl_executing_keyseq[rl_key_sequence_length++] = key; } /* `delete' the last character added to the executing key sequence. Use this diff --git a/readline.h b/readline.h index 828a42a..d300e6a 100644 --- a/readline.h +++ b/readline.h @@ -209,6 +209,8 @@ extern int rl_stop_output (int, int); extern int rl_abort (int, int); extern int rl_tty_status (int, int); +extern int rl_execute_named_command (int, int); + /* Bindable commands for incremental and non-incremental history searching. */ extern int rl_history_search_forward (int, int); extern int rl_history_search_backward (int, int); @@ -439,6 +441,7 @@ extern void rl_get_screen_size (int *, int *); extern void rl_reset_screen_size (void); extern char *rl_get_termcap (const char *); +extern void rl_reparse_colors (void); /* Functions for character input. */ extern int rl_stuff_char (int); @@ -770,6 +773,19 @@ extern rl_icppfunc_t *rl_filename_stat_hook; converted. */ extern rl_dequote_func_t *rl_filename_rewrite_hook; +/* If non-zero, this is the address of a function to call before + comparing the filename portion of a word to be completed with directory + entries from the filesystem. This takes the address of the partial word + to be completed, after any rl_filename_dequoting_function has been applied. + The function should either return its first argument (if no conversion + takes place) or newly-allocated memory. This can, for instance, convert + the filename portion of the completion word to a character set suitable + for comparison against directory entries read from the filesystem (after + their potential modification by rl_filename_rewrite_hook). + The returned value is what is added to the list of matches. + The second argument is the length of the filename to be converted. */ +extern rl_dequote_func_t *rl_completion_rewrite_hook; + /* Backwards compatibility with previous versions of readline. */ #define rl_symbolic_link_hook rl_directory_completion_hook diff --git a/rlprivate.h b/rlprivate.h index c3e43e3..461617c 100644 --- a/rlprivate.h +++ b/rlprivate.h @@ -110,6 +110,27 @@ typedef struct __rl_search_context char *search_terminators; } _rl_search_cxt; +/* readstr flags */ +#define RL_READSTR_NOSPACE 0x01 /* don't insert space, use for completion */ + +typedef struct __rl_readstr_context +{ + int flags; + + int prevc; + int lastc; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; + char pmb[MB_LEN_MAX]; +#endif + + int save_point; + int save_mark; + int save_line; + + int (*compfunc) (struct __rl_readstr_context *, int); +} _rl_readstr_cxt; + struct _rl_cmd { Keymap map; int count; @@ -461,6 +482,16 @@ extern int _rl_char_search_internal (int, int, int); #endif extern int _rl_set_mark_at_pos (int); +extern _rl_readstr_cxt *_rl_rscxt_alloc (int); +extern void _rl_rscxt_dispose (_rl_readstr_cxt *, int); +extern void _rl_free_saved_readstr_line (void); +extern void _rl_unsave_saved_readstr_line (void); +extern _rl_readstr_cxt *_rl_readstr_init (int, int); +extern int _rl_readstr_cleanup (_rl_readstr_cxt *, int); +extern void _rl_readstr_restore (_rl_readstr_cxt *); +extern int _rl_readstr_getchar (_rl_readstr_cxt *); +extern int _rl_readstr_dispatch (_rl_readstr_cxt *, int); + /* undo.c */ extern UNDO_LIST *_rl_copy_undo_entry (UNDO_LIST *); extern UNDO_LIST *_rl_copy_undo_list (UNDO_LIST *); @@ -635,6 +666,8 @@ extern int _rl_term_autowrap; extern int _rl_optimize_typeahead; extern int _rl_keep_mark_active; +extern _rl_readstr_cxt *_rl_rscxt; + /* undo.c */ extern int _rl_doing_an_undo; extern int _rl_undo_group_level; diff --git a/rltty.c b/rltty.c index 337f0af..a4ad94c 100644 --- a/rltty.c +++ b/rltty.c @@ -49,6 +49,8 @@ extern int errno; #endif /* !errno */ +int _rl_use_tty_xon_xoff = 1; + rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; @@ -275,15 +277,16 @@ prepare_terminal_settings (int meta_flag, TIOTYPE oldtio, TIOTYPE *tiop) } #if defined (TIOCGETC) -# if defined (USE_XON_XOFF) - /* Get rid of terminal output start and stop characters. */ - tiop->tchars.t_stopc = -1; /* C-s */ - tiop->tchars.t_startc = -1; /* C-q */ + if (_rl_use_tty_xon_xoff == 0) + { + /* Get rid of terminal output start and stop characters. */ + tiop->tchars.t_stopc = -1; /* C-s */ + tiop->tchars.t_startc = -1; /* C-q */ - /* If there is an XON character, bind it to restart the output. */ - if (oldtio.tchars.t_startc != -1) - rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); -# endif /* USE_XON_XOFF */ + /* If there is an XON character, bind it to restart the output. */ + if (oldtio.tchars.t_startc != -1) + rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); + } /* If there is an EOF char, bind _rl_eof_char to it. */ if (oldtio.tchars.t_eofc != -1) @@ -514,14 +517,13 @@ prepare_terminal_settings (int meta_flag, TIOTYPE oldtio, TIOTYPE *tiop) if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) _rl_eof_char = oldtio.c_cc[VEOF]; -#if defined (USE_XON_XOFF) + if (_rl_use_tty_xon_xoff == 0) #if defined (IXANY) - tiop->c_iflag &= ~(IXON | IXANY); + tiop->c_iflag &= ~(IXON | IXANY); #else - /* `strict' Posix systems do not define IXANY. */ - tiop->c_iflag &= ~IXON; + /* `strict' Posix systems do not define IXANY. */ + tiop->c_iflag &= ~IXON; #endif /* IXANY */ -#endif /* USE_XON_XOFF */ /* Only turn this off if we are using all 8 bits. */ if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) diff --git a/support/config.rpath b/support/config.rpath old mode 100644 new mode 100755 diff --git a/support/install.sh b/support/install.sh old mode 100644 new mode 100755 diff --git a/support/mkdirs b/support/mkdirs old mode 100644 new mode 100755 diff --git a/support/mkinstalldirs b/support/mkinstalldirs old mode 100644 new mode 100755 diff --git a/support/shlib-install b/support/shlib-install old mode 100644 new mode 100755 diff --git a/text.c b/text.c index e3e5bb9..933536a 100644 --- a/text.c +++ b/text.c @@ -1928,3 +1928,421 @@ rl_mark_active_p (void) { return (mark_active); } + +/* **************************************************************** */ +/* */ +/* Reading a string entered from the keyboard */ +/* */ +/* **************************************************************** */ + +/* A very simple set of functions to read a string from the keyboard using + the line buffer as temporary storage. The caller can set a completion + function to perform completion on TAB and SPACE. */ + +/* XXX - this is all very similar to the search stuff but with a different + CXT. */ + +static HIST_ENTRY *_rl_saved_line_for_readstr; +_rl_readstr_cxt *_rl_rscxt; + +_rl_readstr_cxt * +_rl_rscxt_alloc (int flags) +{ + _rl_readstr_cxt *cxt; + + cxt = (_rl_readstr_cxt *)xmalloc (sizeof (_rl_readstr_cxt)); + + cxt->flags = flags; + + cxt->save_point = rl_point; + cxt->save_mark = rl_mark; + cxt->save_line = where_history (); + + cxt->prevc = cxt->lastc = 0; + + cxt->compfunc = NULL; + + return cxt; +} + +void +_rl_rscxt_dispose (_rl_readstr_cxt *cxt, int flags) +{ + xfree (cxt); +} + +void +_rl_free_saved_readstr_line () +{ + if (_rl_saved_line_for_readstr) + _rl_free_saved_line (_rl_saved_line_for_readstr); + _rl_saved_line_for_readstr = (HIST_ENTRY *)NULL; +} + +void +_rl_unsave_saved_readstr_line () +{ + if (_rl_saved_line_for_readstr) + _rl_unsave_line (_rl_saved_line_for_readstr); + _rl_saved_line_for_readstr = (HIST_ENTRY *)NULL; +} + +_rl_readstr_cxt * +_rl_readstr_init (int pchar, int flags) +{ + _rl_readstr_cxt *cxt; + char *p; + + cxt = _rl_rscxt_alloc (flags); + + rl_maybe_replace_line (); + _rl_saved_line_for_readstr = _rl_alloc_saved_line (); + + rl_undo_list = 0; + + rl_line_buffer[0] = 0; + rl_end = rl_point = 0; + + p = _rl_make_prompt_for_search (pchar ? pchar : '@'); + rl_message ("%s", p); + xfree (p); + + _rl_rscxt = cxt; + + return cxt; +} + +int +_rl_readstr_cleanup (_rl_readstr_cxt *cxt, int r) +{ + _rl_rscxt_dispose (cxt, 0); + _rl_rscxt = 0; + + return (r != 1); +} + +void +_rl_readstr_restore (_rl_readstr_cxt *cxt) +{ + _rl_unsave_saved_readstr_line (); /* restores rl_undo_list */ + rl_point = cxt->save_point; + rl_mark = cxt->save_mark; + rl_restore_prompt (); /* _rl_make_prompt_for_search saved it */ + rl_clear_message (); + _rl_fix_point (1); +} + +int +_rl_readstr_getchar (_rl_readstr_cxt *cxt) +{ + int c; + + cxt->prevc = cxt->lastc; + + /* Read a key and decide how to proceed. */ + RL_SETSTATE(RL_STATE_MOREINPUT); + c = cxt->lastc = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + +#if defined (HANDLE_MULTIBYTE) + /* This ends up with C (and LASTC) being set to the last byte of the + multibyte character. In most cases c == lastc == mb[0] */ + if (c >= 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX); +#endif + + RL_CHECK_SIGNALS (); + return c; +} + +/* Process just-read character C according to readstr context CXT. Return -1 + if the caller should abort the read, 0 if we should break out of the + loop, and 1 if we should continue to read characters. This can perform + completion on the string read so far (stored in rl_line_buffer) if the + caller has set up a completion function. The completion function can + return -1 to indicate that we should abort the read. If we return -1 + we will call _rl_readstr_restore to clean up the state, leaving the caller + to free the context. */ +int +_rl_readstr_dispatch (_rl_readstr_cxt *cxt, int c) +{ + int n; + + if (c < 0) + c = CTRL ('C'); + + switch (c) + { + case CTRL('W'): + rl_unix_word_rubout (1, c); + break; + + case CTRL('U'): + rl_unix_line_discard (1, c); + break; + + case CTRL('Q'): + case CTRL('V'): + n = rl_quoted_insert (1, c); + if (n < 0) + { + _rl_readstr_restore (cxt); + return -1; + } + cxt->lastc = rl_line_buffer[rl_point - 1]; /* preserve prevc */ + break; + + case RETURN: + case NEWLINE: + return 0; + + case CTRL('H'): + case RUBOUT: + if (rl_point == 0) + { + _rl_readstr_restore (cxt); + return -1; + } + _rl_rubout_char (1, c); + break; + + case CTRL('C'): + case CTRL('G'): + rl_ding (); + _rl_readstr_restore (cxt); + return -1; + + case ESC: + /* Allow users to bracketed-paste text into the string. + Similar code is in search.c:_rl_nsearch_dispatch(). */ + if (_rl_enable_bracketed_paste && ((n = _rl_nchars_available ()) >= (BRACK_PASTE_SLEN-1))) + { + if (_rl_read_bracketed_paste_prefix (c) == 1) + rl_bracketed_paste_begin (1, c); + else + { + c = rl_read_key (); /* get the ESC that got pushed back */ + _rl_insert_char (1, c); + } + } + else + _rl_insert_char (1, c); + break; + + case ' ': + if ((cxt->flags & RL_READSTR_NOSPACE) == 0) + { + _rl_insert_char (1, c); + break; + } + /* FALLTHROUGH */ + case TAB: + /* Perform completion if the caller has set a completion function. */ + n = (cxt->compfunc) ? (*cxt->compfunc) (cxt, c) : _rl_insert_char (1, c); + if (n < 0) + { + _rl_readstr_restore (cxt); + return -1; + } + break; + + default: +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (cxt->mb); + else +#endif + _rl_insert_char (1, c); + break; + } + + (*rl_redisplay_function) (); + rl_deactivate_mark (); + return 1; +} + +/* **************************************************************** */ +/* */ +/* Reading and Executing named commands */ +/* */ +/* **************************************************************** */ + +/* A completion generator for bindable readline command names. */ +static char * +readcmd_completion_function (const char *text, int state) +{ + static const char **cmdlist = NULL; + static size_t lind, nlen; + const char *cmdname; + + if (state == 0) + { + if (cmdlist) + free (cmdlist); + + cmdlist = rl_funmap_names (); + lind = 0; + nlen = RL_STRLEN (text); + } + if (cmdlist == 0 || cmdlist[lind] == 0) + return (char *)NULL; + + while (cmdlist[lind]) + { + cmdname = cmdlist[lind++]; + if (STREQN (text, cmdname, nlen)) + return (savestring (cmdname)); + } + return ((char *)NULL); +} + +static void +_rl_display_cmdname_matches (char **matches) +{ + size_t len, max, i; + int old; + + old = rl_filename_completion_desired; + rl_filename_completion_desired = 0; + + /* There is more than one match. Find out how many there are, + and find the maximum printed length of a single entry. */ + for (max = 0, i = 1; matches[i]; i++) + { + len = strlen (matches[i]); + + if (len > max) + max = len; + } + len = i - 1; + + rl_display_match_list (matches, len, max); + rl_filename_completion_desired = old; + + rl_forced_update_display (); + rl_display_fixed = 1; +} + +static int +_rl_readcmd_complete (_rl_readstr_cxt *cxt, int c) +{ + char **matches; + char *prefix; + size_t plen; + + matches = rl_completion_matches (rl_line_buffer, readcmd_completion_function); + + if (RL_SIG_RECEIVED()) + { + _rl_free_match_list (matches); + matches = 0; + RL_CHECK_SIGNALS (); + return -1; + } + else if (matches == 0) + rl_ding (); + + /* Whether or not there are multiple matches, we just want to append the + new characters in matches[0]. We display possible matches if we didn't + append anything. */ + if (matches) + { + prefix = matches[0]; + plen = strlen (prefix); + + if (plen > rl_end) + { + size_t n; + for (n = rl_end; n < plen && prefix[n]; n++) + _rl_insert_char (1, prefix[n]); + } + else if (matches[1]) + _rl_display_cmdname_matches (matches); + _rl_free_match_list (matches); + } + + return 0; +} + +/* Use the readstr functions to read a bindable command name using the + line buffer, with completion. */ +static char * +_rl_read_command_name () +{ + _rl_readstr_cxt *cxt; + char *ret; + int c, r; + + cxt = _rl_readstr_init ('!', RL_READSTR_NOSPACE); + cxt->compfunc = _rl_readcmd_complete; + + /* skip callback stuff for now */ + r = 0; + while (1) + { + c = _rl_readstr_getchar (cxt); + + if (c < 0) + { + _rl_readstr_restore (cxt); + _rl_readstr_cleanup (cxt, r); + return NULL; + } + + if (c == 0) + break; + + r = _rl_readstr_dispatch (cxt, c); + if (r < 0) + { + _rl_readstr_cleanup (cxt, r); + return NULL; /* dispatch function cleans up */ + } + else if (r == 0) + break; + } + + ret = savestring (rl_line_buffer); + + /* Now restore the original line and perform one final redisplay. */ + _rl_readstr_restore (cxt); + (*rl_redisplay_function) (); + + /* And free up the context. */ + _rl_readstr_cleanup (cxt, r); + return ret; +} + +/* Read a command name from the keyboard and execute it as if the bound key + sequence had been entered. */ +int +rl_execute_named_command (int count, int key) +{ + char *command; + rl_command_func_t *func; + int r; + + command = _rl_read_command_name (); + if (command == 0 || *command == '\0') + return 1; + if (func = rl_named_function (command)) + { + int prev, ostate; + + prev = rl_dispatching; + ostate = RL_ISSTATE (RL_STATE_DISPATCHING); + rl_dispatching = 1; + RL_SETSTATE (RL_STATE_DISPATCHING); /* make sure it's set */ + r = (*func) (count, key); + if (ostate == 0) + RL_UNSETSTATE (RL_STATE_DISPATCHING); /* unset it if it wasn't set */ + rl_dispatching = prev; + } + else + { + rl_ding (); + r = 1; + } + + return r; +}