diff options
Diffstat (limited to 'lib/readline')
55 files changed, 5005 insertions, 1962 deletions
diff --git a/lib/readline/Makefile.in b/lib/readline/Makefile.in index 2f47e3a5..2caa69a3 100644 --- a/lib/readline/Makefile.in +++ b/lib/readline/Makefile.in @@ -73,20 +73,22 @@ CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \ $(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \ $(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \ $(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \ - $(srcdir)/compat.c + $(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \ + $(srcdir)/mbutil.c # The header files for this library. HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \ posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \ ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \ - rltypedefs.h + rltypedefs.h rlmbutil.h -HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o +HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \ + mbutil.o TILDEOBJ = tilde.o OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ rltty.o complete.o bind.o isearch.o display.o signals.o \ util.o kill.o undo.o macro.o input.o callback.o terminal.o \ - nls.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o + text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o # The texinfo files which document this library. DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo @@ -203,6 +205,11 @@ macro.o: ansi_stdlib.h macro.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h macro.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h macro.o: history.h rlstdc.h +mbutil.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h rlmbutil.h +mbutil.o: readline.h keymaps.h rltypedefs.h chardefs.h rlstdc.h +misc.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +misc.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +misc.o: history.h rlstdc.h ansi_stdlib.h nls.o: ansi_stdlib.h nls.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h nls.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h @@ -228,6 +235,10 @@ terminal.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h terminal.o: tcap.h terminal.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h terminal.o: history.h rlstdc.h +text.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h +text.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h +text.o: history.h rlstdc.h ansi_stdlib.h +rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h tilde.o: ansi_stdlib.h tilde.o: ${BUILD_DIR}/config.h tilde.o: tilde.h @@ -259,6 +270,8 @@ input.o: rlprivate.h isearch.o: rlprivate.h kill.o: rlprivate.h macro.o: rlprivate.h +mbutil.o: rlprivate.h +misc.o: rlprivate.h nls.o: rlprivate.h parens.o: rlprivate.h readline.o: rlprivate.h @@ -266,6 +279,7 @@ rltty.o: rlprivate.h search.o: rlprivate.h signals.o: rlprivate.h terminal.o: rlprivate.h +text.o: rlprivate.h undo.o: rlprivate.h util.o: rlprivate.h vi_mode.o: rlprivate.h @@ -282,14 +296,31 @@ isearch.o: xmalloc.h keymaps.o: xmalloc.h kill.o: xmalloc.h macro.o: xmalloc.h +mbutil.o: xmalloc.h +misc.o: xmalloc.h readline.o: xmalloc.h savestring.o: xmalloc.h search.o: xmalloc.h shell.o: xmalloc.h -tilde.o: xmalloc.h +terminal.o: xmalloc.h +text.o: xmalloc.h tilde.o: xmalloc.h +undo.o: xmalloc.h util.o: xmalloc.h vi_mode.o: xmalloc.h +xmalloc.o: xmalloc.h + +complete.o: rlmbutil.h +display.o: rlmbutil.h +histexpand.o: rlmbutil.h +input.o: rlmbutil.h +isearch.o: rlmbutil.h +mbutil.o: rlmbutil.h +misc.o: rlmbutil.h +readline.o: rlmbutil.h +search.o: rlmbutil.h +text.o: rlmbutil.h +vi_mode.o: rlmbutil.h # Rules for deficient makes, like SunOS and Solaris bind.o: bind.c @@ -298,15 +329,13 @@ compat.o: compat.c complete.o: complete.c display.o: display.c funmap.o: funmap.c -histexpand.o: histexpand.c -histfile.o: histfile.c -history.o: history.c -histsearch.o: histsearch.c input.o: input.c isearch.o: isearch.c keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c kill.o: kill.c macro.o: macro.c +mbutil.o: mbutil.c +misc.o: misc.c nls.o: nls.c parens.o: parens.c readline.o: readline.c @@ -316,8 +345,14 @@ search.o: search.c shell.o: shell.c signals.o: signals.c terminal.o: terminal.c +text.o: terminal.c tilde.o: tilde.c undo.o: undo.c util.o: util.c vi_mode.o: vi_mode.c xmalloc.o: xmalloc.c + +histexpand.o: histexpand.c +histfile.o: histfile.c +history.o: history.c +histsearch.o: histsearch.c diff --git a/lib/readline/bind.c b/lib/readline/bind.c index d429177d..65ef401e 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -68,6 +68,8 @@ extern char *strchr (), *strrchr (); /* Variables exported by this file. */ Keymap rl_binding_keymap; +static char *_rl_read_file PARAMS((char *, size_t *)); +static void _rl_init_file_error PARAMS((const char *)); static int _rl_read_init_file PARAMS((const char *, int)); static int glean_key_from_name PARAMS((char *)); static int substring_member_of_array PARAMS((char *, const char **)); @@ -246,6 +248,9 @@ rl_generic_bind (type, keyseq, data, map) char *keys; int keys_len; register int i; + KEYMAP_ENTRY k; + + k.function = 0; /* If no keys to bind to, exit right away. */ if (!keyseq || !*keyseq) @@ -269,7 +274,12 @@ rl_generic_bind (type, keyseq, data, map) /* Bind keys, making new keymaps as necessary. */ for (i = 0; i < keys_len; i++) { - unsigned char ic = keys[i]; + unsigned char uc = keys[i]; + int ic; + + ic = uc; + if (ic < 0 || ic >= KEYMAP_SIZE) + return -1; if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic)) { @@ -282,18 +292,40 @@ rl_generic_bind (type, keyseq, data, map) { if (map[ic].type != ISKMAP) { - if (map[ic].type == ISMACR) - free ((char *)map[ic].function); + /* We allow subsequences of keys. If a keymap is being + created that will `shadow' an existing function or macro + key binding, we save that keybinding into the ANYOTHERKEY + index in the new map. The dispatch code will look there + to find the function to execute if the subsequence is not + matched. ANYOTHERKEY was chosen to be greater than + UCHAR_MAX. */ + k = map[ic]; map[ic].type = ISKMAP; map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); } map = FUNCTION_TO_KEYMAP (map, ic); + /* The dispatch code will return this function if no matching + key sequence is found in the keymap. This (with a little + help from the dispatch code in readline.c) allows `a' to be + mapped to something, `abc' to be mapped to something else, + and the function bound to `a' to be executed when the user + types `abx', leaving `bx' in the input queue. */ + if (k.function /* && k.type == ISFUNC */) + { + map[ANYOTHERKEY] = k; + k.function = 0; + } } else { if (map[ic].type == ISMACR) free ((char *)map[ic].function); + else if (map[ic].type == ISKMAP) + { + map = FUNCTION_TO_KEYMAP (map, ic); + ic = ANYOTHERKEY; + } map[ic].function = KEYMAP_TO_FUNCTION (data); map[ic].type = type; @@ -331,7 +363,7 @@ rl_translate_keyseq (seq, array, len) /* Handle special case of backwards define. */ if (strncmp (&seq[i], "C-\\M-", 5) == 0) { - array[l++] = ESC; + array[l++] = ESC; /* ESC is meta-prefix */ i += 5; array[l++] = CTRL (_rl_to_upper (seq[i])); if (seq[i] == '\0') @@ -340,7 +372,7 @@ rl_translate_keyseq (seq, array, len) else if (c == 'M') { i++; - array[l++] = ESC; /* XXX */ + array[l++] = ESC; /* ESC is meta-prefix */ } else if (c == 'C') { @@ -632,25 +664,15 @@ _rl_read_file (filename, sizep) i = read (file, buffer, file_size); close (file); -#if 0 - if (i < file_size) -#else if (i < 0) -#endif { free (buffer); return ((char *)NULL); } -#if 0 - buffer[file_size] = '\0'; - if (sizep) - *sizep = file_size; -#else buffer[i] = '\0'; if (sizep) *sizep = i; -#endif return (buffer); } @@ -767,7 +789,7 @@ _rl_read_init_file (filename, include_level) static void _rl_init_file_error (msg) - char *msg; + const char *msg; { if (currently_reading_init_file) fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file, @@ -1075,7 +1097,7 @@ rl_parse_and_bind (string) /* Make VAR point to start of variable name. */ while (*var && whitespace (*var)) var++; - /* Make value point to start of value string. */ + /* Make VALUE point to start of value string. */ value = var; while (*value && !whitespace (*value)) value++; if (*value) @@ -1240,6 +1262,7 @@ static struct { int flags; } boolean_varlist [] = { { "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL }, + { "byte-oriented", &rl_byte_oriented, 0 }, { "completion-ignore-case", &_rl_completion_case_fold, 0 }, { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, { "disable-completion", &rl_inhibit_completion, 0 }, @@ -1250,9 +1273,11 @@ static struct { { "input-meta", &_rl_meta_flag, 0 }, { "mark-directories", &_rl_complete_mark_directories, 0 }, { "mark-modified-lines", &_rl_mark_modified_lines, 0 }, + { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 }, { "match-hidden-files", &_rl_match_hidden_files, 0 }, { "meta-flag", &_rl_meta_flag, 0 }, { "output-meta", &_rl_output_meta_chars, 0 }, + { "page-completions", &_rl_page_completions, 0 }, { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, @@ -1264,7 +1289,7 @@ static struct { static int find_boolean_var (name) - char *name; + const char *name; { register int i; @@ -1333,7 +1358,7 @@ static struct { static int find_string_var (name) - char *name; + const char *name; { register int i; @@ -1659,17 +1684,18 @@ _rl_get_keyname (key) pairs for possible inclusion in an inputrc file, we don't want to do any special meta processing on KEY. */ -#if 0 +#if 1 + /* XXX - Experimental */ /* We might want to do this, but the old version of the code did not. */ /* If this is an escape character, we don't want to do any more processing. Just add the special ESC key sequence and return. */ if (c == ESC) { - keyseq[0] = '\\'; - keyseq[1] = 'e'; - keyseq[2] = '\0'; - return keyseq; + keyname[0] = '\\'; + keyname[1] = 'e'; + keyname[2] = '\0'; + return keyname; } #endif @@ -1780,7 +1806,12 @@ rl_invoking_keyseqs_in_map (function, map) char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); if (key == ESC) +#if 0 sprintf (keyname, "\\e"); +#else + /* XXX - experimental */ + sprintf (keyname, "\\M-"); +#endif else if (CTRL_CHAR (key)) sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); else if (key == RUBOUT) @@ -1927,11 +1958,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix) { case ISMACR: keyname = _rl_get_keyname (key); -#if 0 - out = (char *)map[key].function; -#else out = _rl_untranslate_macro_value ((char *)map[key].function); -#endif + if (print_readably) fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", keyname, @@ -1941,9 +1969,7 @@ _rl_macro_dumper_internal (print_readably, map, prefix) keyname, out ? out : ""); free (keyname); -#if 1 free (out); -#endif break; case ISFUNC: break; @@ -2033,7 +2059,7 @@ rl_variable_dumper (print_readably) if (print_readably) fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); else - fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : ""); + fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); /* completion-query-items */ if (print_readably) @@ -2047,15 +2073,6 @@ rl_variable_dumper (print_readably) else fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); - /* keymap */ - kname = rl_get_keymap_name (_rl_keymap); - if (kname == 0) - kname = rl_get_keymap_name_from_edit_mode (); - if (print_readably) - fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none"); - else - fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none"); - /* isearch-terminators */ if (_rl_isearch_terminators) { @@ -2070,6 +2087,15 @@ rl_variable_dumper (print_readably) free (disp); } + + /* keymap */ + kname = rl_get_keymap_name (_rl_keymap); + if (kname == 0) + kname = rl_get_keymap_name_from_edit_mode (); + if (print_readably) + fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none"); + else + fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none"); } /* Print all of the current variables and their values to @@ -2086,7 +2112,9 @@ rl_dump_variables (count, key) return (0); } -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */ +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ void _rl_bind_if_unbound (keyseq, default_func) const char *keyseq; @@ -2097,7 +2125,11 @@ _rl_bind_if_unbound (keyseq, default_func) if (keyseq) { func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL); +#if defined (VI_MODE) + if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) +#else if (!func || func == rl_do_lowercase_version) +#endif rl_set_key (keyseq, default_func, _rl_keymap); } } diff --git a/lib/readline/chardefs.h b/lib/readline/chardefs.h index 33ee512f..a537be22 100644 --- a/lib/readline/chardefs.h +++ b/lib/readline/chardefs.h @@ -44,7 +44,10 @@ #endif #ifdef CTRL -#undef CTRL +# undef CTRL +#endif +#ifdef UNCTRL +# undef UNCTRL #endif /* Some character stuff. */ @@ -76,6 +79,9 @@ #define NON_NEGATIVE(c) ((unsigned char)(c) == (c)) +/* Some systems define these; we want our definitions. */ +#undef ISPRINT + #define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) #define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) #define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) diff --git a/lib/readline/complete.c b/lib/readline/complete.c index cbcee28f..21a9d708 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -55,6 +55,7 @@ extern int errno; /* System-specific feature definitions and include files. */ #include "rldefs.h" +#include "rlmbutil.h" /* Some standard library routines. */ #include "readline.h" @@ -100,10 +101,11 @@ static int stat_char PARAMS((char *)); static char *rl_quote_filename PARAMS((char *, int, char *)); -static int get_y_or_n PARAMS((void)); +static void set_completion_defaults PARAMS((int)); +static int get_y_or_n PARAMS((int)); +static int _rl_internal_pager PARAMS((int)); static char *printable_part PARAMS((char *)); static int print_filename PARAMS((char *, char *)); -static char find_completion_word PARAMS((int *, int *)); static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int)); @@ -116,7 +118,6 @@ static int compute_lcd_of_matches PARAMS((char **, int, const char *)); static int postprocess_matches PARAMS((char ***, int)); static char *make_quoted_replacement PARAMS((char *, int, char *)); -static void free_match_list PARAMS((char **)); /* **************************************************************** */ /* */ @@ -132,6 +133,12 @@ int _rl_complete_show_all = 0; /* If non-zero, completed directory names have a slash appended. */ int _rl_complete_mark_directories = 1; +/* If non-zero, the symlinked directory completion behavior introduced in + readline-4.2a is disabled, and symlinks that point to directories have + a slash appended (subject to the value of _rl_complete_mark_directories). + This is user-settable via the mark-symlinked-directories variable. */ +int _rl_complete_mark_symlink_dirs = 0; + /* If non-zero, completions are printed horizontally in alphabetical order, like `ls -x'. */ int _rl_print_completions_horizontally; @@ -194,10 +201,12 @@ int rl_completion_type = 0; she is sure she wants to see them all. */ int rl_completion_query_items = 100; +int _rl_page_completions = 1; + /* The basic list of characters that signal a break between words for the completer routine. The contents of this variable is what breaks words in the shell, i.e. " \t\n\"\\'`@$><=" */ -const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; +const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; /* }) */ /* List of basic quoting characters. */ const char *rl_basic_quote_characters = "\"'"; @@ -264,10 +273,26 @@ rl_dequote_func_t *rl_filename_dequoting_function = (rl_dequote_func_t *)NULL; completer. */ rl_linebuf_func_t *rl_char_is_quoted_p = (rl_linebuf_func_t *)NULL; +/* If non-zero, the completion functions don't append anything except a + possible closing quote. This is set to 0 by rl_complete_internal and + may be changed by an application-specific completion function. */ +int rl_completion_suppress_append = 0; + /* Character appended to completed words when at the end of the line. The default is a space. */ int rl_completion_append_character = ' '; +/* If non-zero, a slash will be appended to completed filenames that are + symbolic links to directory names, subject to the value of the + mark-directories variable (which is user-settable). This exists so + that application completion functions can override the user's preference + (set via the mark-symlinked-directories variable) if appropriate. + It's set to the value of _rl_complete_mark_symlink_dirs in + rl_complete_internal before any application-specific completion + function is called, so without that function doing anything, the user's + preferences are honored. */ +int rl_completion_mark_symlink_dirs; + /* If non-zero, inhibit completion (temporarily). */ int rl_inhibit_completion; @@ -290,7 +315,7 @@ rl_complete (ignore, invoking_key) int ignore, invoking_key; { if (rl_inhibit_completion) - return (rl_insert (ignore, invoking_key)); + return (_rl_insert_char (ignore, invoking_key)); else if (rl_last_func == rl_complete && !completion_changed_buffer) return (rl_complete_internal ('?')); else if (_rl_complete_show_all) @@ -314,15 +339,49 @@ rl_insert_completions (ignore, invoking_key) return (rl_complete_internal ('*')); } +/* Return the correct value to pass to rl_complete_internal performing + the same tests as rl_complete. This allows consecutive calls to an + application's completion function to list possible completions and for + an application-specific completion function to honor the + show-all-if-ambiguous readline variable. */ +int +rl_completion_mode (cfunc) + rl_command_func_t *cfunc; +{ + if (rl_last_func == cfunc && !completion_changed_buffer) + return '?'; + else if (_rl_complete_show_all) + return '!'; + else + return TAB; +} + /************************************/ /* */ /* Completion utility functions */ /* */ /************************************/ +/* Set default values for readline word completion. These are the variables + that application completion functions can change or inspect. */ +static void +set_completion_defaults (what_to_do) + int what_to_do; +{ + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + rl_completion_type = what_to_do; + rl_completion_suppress_append = 0; + + /* The completion entry function may optionally change this. */ + rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs; +} + /* The user must press "y" or "n". Non-zero return means "y" pressed. */ static int -get_y_or_n () +get_y_or_n (for_pager) + int for_pager; { int c; @@ -338,10 +397,32 @@ get_y_or_n () return (0); if (c == ABORT_CHAR) _rl_abort_internal (); + if (for_pager && (c == NEWLINE || c == RETURN)) + return (2); + if (for_pager && (c == 'q' || c == 'Q')) + return (0); rl_ding (); } } +static int +_rl_internal_pager (lines) + int lines; +{ + int i; + + fprintf (rl_outstream, "--More--"); + fflush (rl_outstream); + i = get_y_or_n (1); + _rl_erase_entire_line (); + if (i == 0) + return -1; + else if (i == 2) + return (lines - 1); + else + return 0; +} + #if defined (VISIBLE_STATS) /* Return the character which best describes FILENAME. `@' for symbolic links @@ -402,19 +483,41 @@ stat_char (filename) /* Return the portion of PATHNAME that should be output when listing possible completions. If we are hacking filename completion, we are only interested in the basename, the portion following the - final slash. Otherwise, we return what we were passed. */ + final slash. Otherwise, we return what we were passed. Since + printing empty strings is not very informative, if we're doing + filename completion, and the basename is the empty string, we look + for the previous slash and return the portion following that. If + there's no previous slash, we just return what we were passed. */ static char * printable_part (pathname) char *pathname; { - char *temp; + char *temp, *x; + + if (rl_filename_completion_desired == 0) /* don't need to do anything */ + return (pathname); - temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL; + temp = strrchr (pathname, '/'); #if defined (__MSDOS__) - if (rl_filename_completion_desired && temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':') + if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':') temp = pathname + 1; #endif - return (temp ? ++temp : pathname); + + if (temp == 0 || *temp == '\0') + return (pathname); + /* If the basename is NULL, we might have a pathname like '/usr/src/'. + Look for a previous slash and, if one is found, return the portion + following that slash. If there's no previous slash, just return the + pathname we were passed. */ + else if (temp[1] == '\0') + { + for (x = temp - 1; x > pathname; x--) + if (*x == '/') + break; + return ((*x == '/') ? x + 1 : pathname); + } + else + return ++temp; } /* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we @@ -543,8 +646,8 @@ rl_quote_filename (s, rtype, qcp) quote, or backslash) anywhere in the string. DP, if non-null, is set to the value of the delimiter character that caused a word break. */ -static char -find_completion_word (fp, dp) +char +_rl_find_completion_word (fp, dp) int *fp, *dp; { int scan, end, found_quote, delimiter, pass_next, isbrk; @@ -599,6 +702,8 @@ find_completion_word (fp, dp) found_quote |= RL_QF_SINGLE_QUOTE; else if (quote_char == '"') found_quote |= RL_QF_DOUBLE_QUOTE; + else + found_quote |= RL_QF_OTHER_QUOTE; } } } @@ -608,7 +713,11 @@ find_completion_word (fp, dp) /* We didn't find an unclosed quoted substring upon which to do completion, so use the word break characters to find the substring on which to complete. */ +#if defined (HANDLE_MULTIBYTE) + while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY)) +#else while (--rl_point) +#endif { scan = rl_line_buffer[rl_point]; @@ -780,6 +889,11 @@ compute_lcd_of_matches (match_list, matches, text) { register int i, c1, c2, si; int low; /* Count of max-matched characters. */ +#if defined (HANDLE_MULTIBYTE) + int v; + mbstate_t ps1, ps2; + wchar_t wc1, wc2; +#endif /* If only one match, just use that. Otherwise, compare each member of the list with the next, finding out where they @@ -793,12 +907,33 @@ compute_lcd_of_matches (match_list, matches, text) for (i = 1, low = 100000; i < matches; i++) { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps1, 0, sizeof (mbstate_t)); + memset (&ps2, 0, sizeof (mbstate_t)); + } +#endif if (_rl_completion_case_fold) { for (si = 0; (c1 = _rl_to_lower(match_list[i][si])) && (c2 = _rl_to_lower(match_list[i + 1][si])); si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); + mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); + wc1 = towlower (wc1); + wc2 = towlower (wc2); + if (wc1 != wc2) + break; + else if (v > 1) + si += v - 1; + } + else +#endif if (c1 != c2) break; } @@ -808,6 +943,17 @@ compute_lcd_of_matches (match_list, matches, text) (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + mbstate_t ps_back = ps1; + if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2)) + break; + else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1) + si += v - 1; + } + else +#endif if (c1 != c2) break; } @@ -828,6 +974,8 @@ compute_lcd_of_matches (match_list, matches, text) { match_list[0] = (char *)xmalloc (low + 1); + /* XXX - this might need changes in the presence of multibyte chars */ + /* If we are ignoring case, try to preserve the case of the string the user typed in the face of multiple matches differing in case. */ if (_rl_completion_case_fold) @@ -871,6 +1019,9 @@ postprocess_matches (matchesp, matching_filenames) matches = *matchesp; + if (matches == 0) + return 0; + /* It seems to me that in all the cases we handle we would like to ignore duplicate possiblilities. Scan for the text to insert being identical to the other completions. */ @@ -923,7 +1074,7 @@ rl_display_match_list (matches, len, max) char **matches; int len, max; { - int count, limit, printed_len; + int count, limit, printed_len, lines; int i, j, k, l; char *temp; @@ -951,6 +1102,7 @@ rl_display_match_list (matches, len, max) rl_crlf (); + lines = 0; if (_rl_print_completions_horizontally == 0) { /* Print the sorted items, up-and-down alphabetically, like ls. */ @@ -972,6 +1124,13 @@ rl_display_match_list (matches, len, max) l += count; } rl_crlf (); + lines++; + if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count) + { + lines = _rl_internal_pager (lines); + if (lines < 0) + return; + } } } else @@ -985,7 +1144,16 @@ rl_display_match_list (matches, len, max) if (matches[i+1]) { if (i && (limit > 1) && (i % limit) == 0) - rl_crlf (); + { + rl_crlf (); + lines++; + if (_rl_page_completions && lines >= _rl_screenheight - 1) + { + lines = _rl_internal_pager (lines); + if (lines < 0) + return; + } + } else for (k = 0; k < max - printed_len; k++) putc (' ', rl_outstream); @@ -1057,7 +1225,7 @@ display_matches (matches) rl_crlf (); fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); fflush (rl_outstream); - if (get_y_or_n () == 0) + if (get_y_or_n (0) == 0) { rl_crlf (); @@ -1155,7 +1323,11 @@ insert_match (match, start, mtype, qc) default trailing character is a space. Returns the number of characters appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS has them) and don't add a suffix for a symlink to a directory. A - nontrivial match is one that actually adds to the word being completed. */ + nontrivial match is one that actually adds to the word being completed. + The variable rl_completion_mark_symlink_dirs controls this behavior + (it's initially set to the what the user has chosen, indicated by the + value of _rl_complete_mark_symlink_dirs, but may be modified by an + application's completion function). */ static int append_to_match (text, delimiter, quote_char, nontrivial_match) char *text; @@ -1171,7 +1343,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) if (delimiter) temp_string[temp_string_index++] = delimiter; - else if (rl_completion_append_character) + else if (rl_completion_suppress_append == 0 && rl_completion_append_character) temp_string[temp_string_index++] = rl_completion_append_character; temp_string[temp_string_index++] = '\0'; @@ -1179,11 +1351,21 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) if (rl_filename_completion_desired) { filename = tilde_expand (text); - s = nontrivial_match ? LSTAT (filename, &finfo) : stat (filename, &finfo); + s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0) + ? LSTAT (filename, &finfo) + : stat (filename, &finfo); if (s == 0 && S_ISDIR (finfo.st_mode)) { - if (_rl_complete_mark_directories && rl_line_buffer[rl_point] != '/') - rl_insert_text ("/"); + if (_rl_complete_mark_directories) + { + /* This is clumsy. Avoid putting in a double slash if point + is at the end of the line and the previous character is a + slash. */ + if (rl_point && rl_line_buffer[rl_point] == '\0' && rl_line_buffer[rl_point - 1] == '/') + ; + else if (rl_line_buffer[rl_point] != '/') + rl_insert_text ("/"); + } } #ifdef S_ISLNK /* Don't add anything if the filename is a symlink and resolves to a @@ -1194,14 +1376,14 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) #endif else { - if (rl_point == rl_end) + if (rl_point == rl_end && temp_string_index) rl_insert_text (temp_string); } free (filename); } else { - if (rl_point == rl_end) + if (rl_point == rl_end && temp_string_index) rl_insert_text (temp_string); } @@ -1247,12 +1429,15 @@ insert_all_matches (matches, point, qc) rl_end_undo_group (); } -static void -free_match_list (matches) +void +_rl_free_match_list (matches) char **matches; { register int i; + if (matches == 0) + return; + for (i = 0; matches[i]; i++) free (matches[i]); free (matches); @@ -1276,10 +1461,8 @@ rl_complete_internal (what_to_do) char quote_char; RL_SETSTATE(RL_STATE_COMPLETING); - /* Only the completion entry function can change these. */ - rl_filename_completion_desired = 0; - rl_filename_quoting_desired = 1; - rl_completion_type = what_to_do; + + set_completion_defaults (what_to_do); saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; our_func = rl_completion_entry_function @@ -1294,7 +1477,7 @@ rl_complete_internal (what_to_do) if (rl_point) /* This (possibly) changes rl_point. If it returns a non-zero char, we know we have an open quote. */ - quote_char = find_completion_word (&found_quote, &delimiter); + quote_char = _rl_find_completion_word (&found_quote, &delimiter); start = rl_point; rl_point = end; @@ -1310,6 +1493,7 @@ rl_complete_internal (what_to_do) { rl_ding (); FREE (saved_line_buffer); + completion_changed_buffer = 0; RL_UNSETSTATE(RL_STATE_COMPLETING); return (0); } @@ -1375,7 +1559,7 @@ rl_complete_internal (what_to_do) return 1; } - free_match_list (matches); + _rl_free_match_list (matches); /* Check to see if the line has changed through all of this manipulation. */ if (saved_line_buffer) @@ -1735,15 +1919,13 @@ rl_menu_complete (count, ignore) /* Clean up from previous call, if any. */ FREE (orig_text); if (matches) - free_match_list (matches); + _rl_free_match_list (matches); match_list_index = match_list_size = 0; matches = (char **)NULL; /* Only the completion entry function can change these. */ - rl_filename_completion_desired = 0; - rl_filename_quoting_desired = 1; - rl_completion_type = '%'; + set_completion_defaults ('%'); our_func = rl_completion_entry_function ? rl_completion_entry_function @@ -1757,7 +1939,7 @@ rl_menu_complete (count, ignore) if (rl_point) /* This (possibly) changes rl_point. If it returns a non-zero char, we know we have an open quote. */ - quote_char = find_completion_word (&found_quote, &delimiter); + quote_char = _rl_find_completion_word (&found_quote, &delimiter); orig_start = rl_point; rl_point = orig_end; diff --git a/lib/readline/display.c b/lib/readline/display.c index 4ce7d6bf..5150ea6a 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -43,6 +43,7 @@ /* System-specific feature definitions and include files. */ #include "rldefs.h" +#include "rlmbutil.h" /* Termcap library stuff. */ #include "tcap.h" @@ -65,9 +66,16 @@ extern char *_rl_term_forward_char; static void update_line PARAMS((char *, char *, int, int, int, int)); static void space_to_eol PARAMS((int)); static void delete_chars PARAMS((int)); -static void insert_some_chars PARAMS((char *, int)); +static void insert_some_chars PARAMS((char *, int, int)); static void cr PARAMS((void)); +#if defined (HANDLE_MULTIBYTE) +static int _rl_col_width PARAMS((char *, int, int)); +static int *_rl_wrapped_line; +#else +# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) +#endif + static int *inv_lbreaks, *vis_lbreaks; static int inv_lbsize, vis_lbsize; @@ -359,6 +367,9 @@ init_line_structures (minsize) inv_lbsize = vis_lbsize = 256; inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); +#if defined (HANDLE_MULTIBYTE) + _rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int)); +#endif inv_lbreaks[0] = vis_lbreaks[0] = 0; } } @@ -372,6 +383,13 @@ rl_redisplay () int c_pos, inv_botlin, lb_botlin, lb_linenum; int newlines, lpos, temp; char *prompt_this_line; +#if defined (HANDLE_MULTIBYTE) + wchar_t wc; + size_t wc_bytes; + int wc_width; + mbstate_t ps; + int _rl_wrapped_multicolumn = 0; +#endif if (!readline_echoing_p) return; @@ -472,7 +490,8 @@ rl_redisplay () inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ } \ } while (0) - + +#if defined (HANDLE_MULTIBYTE) #define CHECK_LPOS() \ do { \ lpos++; \ @@ -482,15 +501,36 @@ rl_redisplay () { \ inv_lbsize *= 2; \ inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + _rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \ } \ inv_lbreaks[++newlines] = out; \ + _rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \ lpos = 0; \ } \ } while (0) +#else +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= _rl_screenwidth) \ + { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ + lpos = 0; \ + } \ + } while (0) +#endif /* inv_lbreaks[i] is where line i starts in the buffer. */ inv_lbreaks[newlines = 0] = 0; lpos = out - wrap_offset; +#if defined (HANDLE_MULTIBYTE) + memset (_rl_wrapped_line, 0, vis_lbsize); +#endif /* prompt_invis_chars_first_line is the number of invisible characters in the first physical line of the prompt. @@ -508,7 +548,11 @@ rl_redisplay () probably too much work for the benefit gained. How many people have prompts that exceed two physical lines? */ temp = ((newlines + 1) * _rl_screenwidth) + +#if 0 ((newlines == 0) ? prompt_invis_chars_first_line : 0) + +#else + ((newlines == 0 && local_prompt_prefix == 0) ? prompt_invis_chars_first_line : 0) + +#endif ((newlines == 1) ? wrap_offset : 0); inv_lbreaks[++newlines] = temp; @@ -523,10 +567,44 @@ rl_redisplay () It maintains an array of line breaks for display (inv_lbreaks). This handles expanding tabs for display and displaying meta characters. */ lb_linenum = 0; +#if defined (HANDLE_MULTIBYTE) + in = 0; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps, 0, sizeof (mbstate_t)); + wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps); + } + else + wc_bytes = 1; + while (in < rl_end) +#else for (in = 0; in < rl_end; in++) +#endif { c = (unsigned char)rl_line_buffer[in]; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + if (wc_bytes == (size_t)-1 || wc_bytes == (size_t)-2) + { + /* Byte sequence is invalid or shortened. Assume that the + first byte represents a character. */ + wc_bytes = 1; + /* Assume that a character occupies a single column. */ + wc_width = 1; + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (wc_bytes == (size_t)0) + break; /* Found '\0' */ + else + { + temp = wcwidth (wc); + wc_width = (temp < 0) ? 1 : temp; + } + } +#endif + if (out + 8 >= line_size) /* XXX - 8 for \t */ { line_size *= 2; @@ -541,7 +619,11 @@ rl_redisplay () lb_linenum = newlines; } +#if defined (HANDLE_MULTIBYTE) + if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */ +#else if (META_CHAR (c)) +#endif { if (_rl_output_meta_chars == 0) { @@ -610,9 +692,52 @@ rl_redisplay () } else { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + register int i; + + _rl_wrapped_multicolumn = 0; + + if (_rl_screenwidth < lpos + wc_width) + for (i = lpos; i < _rl_screenwidth; i++) + { + /* The space will be removed in update_line() */ + line[out++] = ' '; + _rl_wrapped_multicolumn++; + CHECK_LPOS(); + } + if (in == rl_point) + { + c_pos = out; + lb_linenum = newlines; + } + for (i = in; i < in+wc_bytes; i++) + line[out++] = rl_line_buffer[i]; + for (i = 0; i < wc_width; i++) + CHECK_LPOS(); + } + else + { + line[out++] = c; + CHECK_LPOS(); + } +#else line[out++] = c; CHECK_LPOS(); +#endif + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + in += wc_bytes; + wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps); } + else + in++; +#endif + } line[out] = '\0'; if (c_pos < 0) @@ -650,7 +775,12 @@ rl_redisplay () only display a screenful. We should display the last screen, not the first. */ if (out >= _rl_screenchars) - out = _rl_screenchars - 1; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY); + else + out = _rl_screenchars - 1; + } /* The first line is at character position 0 in the buffer. The second and subsequent lines start at inv_lbreaks[N], offset by @@ -736,7 +866,10 @@ rl_redisplay () tputs (_rl_term_cr, 1, _rl_output_character_function); #endif _rl_output_some_chars (local_prompt, nleft); - _rl_last_c_pos = nleft; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width(local_prompt, 0, nleft); + else + _rl_last_c_pos = nleft; } /* Where on that line? And where does that line start @@ -752,10 +885,15 @@ rl_redisplay () if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) { _rl_backspace (_rl_last_c_pos - nleft); - _rl_last_c_pos = nleft; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (&visible_line[pos], 0, nleft); + else + _rl_last_c_pos = nleft; } - if (nleft != _rl_last_c_pos) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + else if (nleft != _rl_last_c_pos) _rl_move_cursor_relative (nleft, &invisible_line[pos]); } } @@ -900,6 +1038,11 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) register char *ofd, *ols, *oe, *nfd, *nls, *ne; int temp, lendiff, wsatend, od, nd; int current_invis_chars; + int col_lendiff, col_temp; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps_new, ps_old; + int new_offset, old_offset, tmp; +#endif /* If we're at the right edge of a terminal that supports xn, we're ready to wrap around, so do so. This fixes problems with knowing @@ -908,19 +1051,97 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) position of the cursor. */ temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode - && _rl_last_v_pos == current_line - 1) + && _rl_last_v_pos == current_line - 1) { - if (new[0]) - putc (new[0], rl_outstream); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + wchar_t wc; + mbstate_t ps; + int tempwidth, bytes; + size_t ret; + + /* This fixes only double-column characters, but if the wrapped + character comsumes more than three columns, spaces will be + inserted in the string buffer. */ + if (_rl_wrapped_line[current_line] > 0) + _rl_clear_to_eol (_rl_wrapped_line[current_line]); + + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); + if (ret == (size_t)-1 || ret == (size_t)-2) + { + tempwidth = 1; + ret = 1; + } + else if (ret == 0) + tempwidth = 0; + else + tempwidth = wcwidth (wc); + + if (tempwidth > 0) + { + int count; + bytes = ret; + for (count = 0; count < bytes; count++) + putc (new[count], rl_outstream); + _rl_last_c_pos = tempwidth; + _rl_last_v_pos++; + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps); + if (ret != 0 && bytes != 0) + { + if (ret == (size_t)-1 || ret == (size_t)-2) + memmove (old+bytes, old+1, strlen (old+1)); + else + memmove (old+bytes, old+ret, strlen (old+ret)); + memcpy (old, new, bytes); + } + } + else + { + putc (' ', rl_outstream); + _rl_last_c_pos = 1; + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + } else - putc (' ', rl_outstream); - _rl_last_c_pos = 1; /* XXX */ - _rl_last_v_pos++; - if (old[0] && new[0]) - old[0] = new[0]; +#endif + { + if (new[0]) + putc (new[0], rl_outstream); + else + putc (' ', rl_outstream); + _rl_last_c_pos = 1; /* XXX */ + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } } + /* Find first difference. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps_new, 0, sizeof(mbstate_t)); + memset (&ps_old, 0, sizeof(mbstate_t)); + + new_offset = old_offset = 0; + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && + _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) + { + old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); + new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); + ofd = old + old_offset; + nfd = new + new_offset; + } + } + else +#endif for (ofd = old, nfd = new; (ofd - old < omax) && *ofd && (*ofd == *nfd); ofd++, nfd++) @@ -937,6 +1158,33 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) return; wsatend = 1; /* flag for trailing whitespace */ + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY); + while ((ols > ofd) && (nls > nfd)) + { + memset (&ps_old, 0, sizeof (mbstate_t)); + memset (&ps_new, 0, sizeof (mbstate_t)); + + _rl_adjust_point (old, ols - old, &ps_old); + _rl_adjust_point (new, nls - new, &ps_new); + + if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0) + break; + + if (*ols == ' ') + wsatend = 0; + + ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY); + } + } + else + { +#endif /* HANDLE_MULTIBYTE */ ols = oe - 1; /* find last same */ nls = ne - 1; while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) @@ -946,18 +1194,38 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) ols--; nls--; } +#if defined (HANDLE_MULTIBYTE) + } +#endif if (wsatend) { ols = oe; nls = ne; } +#if defined (HANDLE_MULTIBYTE) + /* This may not work for stateful encoding, but who cares? To handle + stateful encoding properly, we have to scan each string from the + beginning and compare. */ + else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0) +#else else if (*ols != *nls) +#endif { if (*ols) /* don't step past the NUL */ - ols++; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY); + else + ols++; + } if (*nls) - nls++; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY); + else + nls++; + } } /* count of invisible characters in the current invisible line. */ @@ -993,24 +1261,50 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) tputs (_rl_term_cr, 1, _rl_output_character_function); #endif _rl_output_some_chars (local_prompt, lendiff); - _rl_last_c_pos = lendiff; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff); + else + _rl_last_c_pos = lendiff; } _rl_move_cursor_relative (od, old); - /* if (len (new) > len (old)) */ + /* if (len (new) > len (old)) + lendiff == difference in buffer + col_lendiff == difference on screen + When not using multibyte characters, these are equal */ lendiff = (nls - nfd) - (ols - ofd); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old); + else + col_lendiff = lendiff; /* If we are changing the number of invisible characters in a line, and the spot of first difference is before the end of the invisible chars, lendiff needs to be adjusted. */ if (current_line == 0 && !_rl_horizontal_scroll_mode && current_invis_chars != visible_wrap_offset) - lendiff += visible_wrap_offset - current_invis_chars; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff += visible_wrap_offset - current_invis_chars; + } + else + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff = lendiff; + } + } /* Insert (diff (len (old), len (new)) ch. */ temp = ne - nfd; - if (lendiff > 0) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_temp = _rl_col_width (new, nfd - new, ne - new); + else + col_temp = temp; + + if (col_lendiff > 0) /* XXX - was lendiff */ { /* Non-zero if we're increasing the number of lines. */ int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; @@ -1018,7 +1312,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) use the terminal's capabilities. If we're growing the number of lines, make sure we actually cause the new line to wrap around on auto-wrapping terminals. */ - if (_rl_terminal_can_insert && ((2 * temp) >= lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) + if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) { /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and _rl_horizontal_scroll_mode == 1, inserting the characters with @@ -1027,8 +1321,8 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 || lendiff <= prompt_visible_length || !current_invis_chars)) { - insert_some_chars (nfd, lendiff); - _rl_last_c_pos += lendiff; + insert_some_chars (nfd, lendiff, col_lendiff); + _rl_last_c_pos += col_lendiff; } else if (*ols == 0) { @@ -1037,7 +1331,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) /* However, this screws up the rest of this block, which assumes you've done the insert because you can. */ _rl_output_some_chars (nfd, lendiff); - _rl_last_c_pos += lendiff; + _rl_last_c_pos += col_lendiff; } else { @@ -1045,7 +1339,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) the end. We have invisible characters in this line. This is a dumb update. */ _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += temp; + _rl_last_c_pos += col_temp; return; } /* Copy (new) chars to screen from first diff to last match. */ @@ -1053,37 +1347,41 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if ((temp - lendiff) > 0) { _rl_output_some_chars (nfd + lendiff, temp - lendiff); - _rl_last_c_pos += temp - lendiff; +#if 0 + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff) - col_lendiff; +#else + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); +#endif } } else { /* cannot insert chars, write to EOL */ _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += temp; + _rl_last_c_pos += col_temp; } } else /* Delete characters from line. */ { /* If possible and inexpensive to use terminal deletion, then do so. */ - if (_rl_term_dc && (2 * temp) >= -lendiff) + if (_rl_term_dc && (2 * col_temp) >= -col_lendiff) { /* If all we're doing is erasing the invisible characters in the prompt string, don't bother. It screws up the assumptions about what's on the screen. */ if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 && -lendiff == visible_wrap_offset) - lendiff = 0; + col_lendiff = 0; - if (lendiff) - delete_chars (-lendiff); /* delete (diff) characters */ + if (col_lendiff) + delete_chars (-col_lendiff); /* delete (diff) characters */ /* Copy (new) chars to screen from first diff to last match */ temp = nls - nfd; if (temp > 0) { _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += temp; + _rl_last_c_pos += _rl_col_width (nfd, 0, temp);; } } /* Otherwise, print over the existing material. */ @@ -1092,15 +1390,20 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if (temp > 0) { _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += temp; + _rl_last_c_pos += col_temp; } lendiff = (oe - old) - (ne - new); - if (lendiff) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new); + else + col_lendiff = lendiff; + + if (col_lendiff) { if (_rl_term_autowrap && current_line < inv_botlin) - space_to_eol (lendiff); + space_to_eol (col_lendiff); else - _rl_clear_to_eol (lendiff); + _rl_clear_to_eol (col_lendiff); } } } @@ -1146,7 +1449,10 @@ rl_on_new_line_with_prompt () prompt_last_line = rl_prompt; l = strlen (prompt_last_line); - _rl_last_c_pos = l; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l); + else + _rl_last_c_pos = l; /* Dissect prompt_last_line into screen lines. Note that here we have to use the real screenwidth. Readline's notion of screenwidth might be @@ -1201,7 +1507,14 @@ _rl_move_cursor_relative (new, data) register int i; /* If we don't have to do anything, then return. */ +#if defined (HANDLE_MULTIBYTE) + /* If we have multibyte characters, NEW is indexed by the buffer point in + a multibyte string, but _rl_last_c_pos is the display position. In + this case, NEW's display position is not obvious. */ + if ((MB_CUR_MAX == 1 || rl_byte_oriented ) && _rl_last_c_pos == new) return; +#else if (_rl_last_c_pos == new) return; +#endif /* It may be faster to output a CR, and then move forwards instead of moving backwards. */ @@ -1231,19 +1544,69 @@ _rl_move_cursor_relative (new, data) data is underneath the cursor. */ #if defined (HACK_TERMCAP_MOTION) if (_rl_term_forward_char) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int width; + width = _rl_col_width (data, _rl_last_c_pos, new); + for (i = 0; i < width; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + else + { + for (i = _rl_last_c_pos; i < new; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + } + else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else for (i = _rl_last_c_pos; i < new; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); + putc (data[i], rl_outstream); + +#else /* !HACK_TERMCAP_MOTION */ + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } else for (i = _rl_last_c_pos; i < new; i++) putc (data[i], rl_outstream); -#else - for (i = _rl_last_c_pos; i < new; i++) - putc (data[i], rl_outstream); -#endif /* HACK_TERMCAP_MOTION */ + +#endif /* !HACK_TERMCAP_MOTION */ + } +#if defined (HANDLE_MULTIBYTE) + /* NEW points to the buffer point, but _rl_last_c_pos is the display point. + The byte length of the string is probably bigger than the column width + of the string, which means that if NEW == _rl_last_c_pos, then NEW's + display point is less than _rl_last_c_pos. */ + else if (_rl_last_c_pos >= new) +#else else if (_rl_last_c_pos > new) - _rl_backspace (_rl_last_c_pos - new); - _rl_last_c_pos = new; +#endif + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + _rl_backspace (_rl_last_c_pos - new); + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (data, 0, new); + else + _rl_last_c_pos = new; } /* PWP: move the cursor up or down. */ @@ -1514,17 +1877,23 @@ _rl_clear_screen () rl_crlf (); } -/* Insert COUNT characters from STRING to the output stream. */ +/* Insert COUNT characters from STRING to the output stream at column COL. */ static void -insert_some_chars (string, count) +insert_some_chars (string, count, col) char *string; - int count; + int count, col; { + /* DEBUGGING */ + if (MB_CUR_MAX == 1 || rl_byte_oriented) + if (count != col) + fprintf(stderr, "readline: debug: insert_some_chars: count (%d) != col (%d)\n", count, col); + /* If IC is defined, then we do not have to "enter" insert mode. */ if (_rl_term_IC) { char *buffer; - buffer = tgoto (_rl_term_IC, 0, count); + + buffer = tgoto (_rl_term_IC, 0, col); tputs (buffer, 1, _rl_output_character_function); _rl_output_some_chars (string, count); } @@ -1540,7 +1909,7 @@ insert_some_chars (string, count) use that first to open up the space. */ if (_rl_term_ic && *_rl_term_ic) { - for (i = count; i--; ) + for (i = col; i--; ) tputs (_rl_term_ic, 1, _rl_output_character_function); } @@ -1595,11 +1964,8 @@ _rl_update_final () if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth)) { char *last_line; -#if 0 - last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]]; -#else + last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]]; -#endif _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); _rl_clear_to_eol (0); putc (last_line[_rl_screenwidth - 1], rl_outstream); @@ -1744,3 +2110,87 @@ _rl_current_display_line () return ret; } + +#if defined (HANDLE_MULTIBYTE) +/* Calculate the number of screen columns occupied by STR from START to END. + In the case of multibyte characters with stateful encoding, we have to + scan from the beginning of the string to take the state into account. */ +static int +_rl_col_width (str, start, end) + char *str; + int start, end; +{ + wchar_t wc; + mbstate_t ps = {0}; + int tmp, point, width, max; + + if (end <= start) + return 0; + + point = 0; + max = end; + + while (point < start) + { + tmp = mbrlen (str + point, max, &ps); + if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + } + } + + /* If START is not a byte that starts a character, then POINT will be + greater than START. In this case, assume that (POINT - START) gives + a byte count that is the number of columns of difference. */ + width = point - start; + + while (point < end) + { + tmp = mbrtowc (&wc, str + point, max, &ps); + if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* and assume that the byte occupies a single column. */ + width++; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + tmp = wcwidth(wc); + width += (tmp >= 0) ? tmp : 1; + } + } + + width += point - end; + + return width; +} +#endif /* HANDLE_MULTIBYTE */ + diff --git a/lib/readline/doc/Makefile b/lib/readline/doc/Makefile index 42b578e1..32f22280 100644 --- a/lib/readline/doc/Makefile +++ b/lib/readline/doc/Makefile @@ -1,6 +1,23 @@ # Derived by hand from the generated readline-src/doc/Makefile # This makefile for Readline library documentation is in -*- text -*- mode. # Emacs likes it that way. + +# Copyright (C) 1996-2002 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + topdir = . srcdir = . VPATH = . diff --git a/lib/readline/doc/hist.texinfo b/lib/readline/doc/hist.texinfo index 90ace3cc..63ceb16e 100644 --- a/lib/readline/doc/hist.texinfo +++ b/lib/readline/doc/hist.texinfo @@ -18,7 +18,7 @@ This document describes the GNU History library, a programming tool that provides a consistent user interface for recalling lines of previously typed input. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -73,7 +73,7 @@ except that this permission notice may be stated in a translation approved by the Free Software Foundation. @vskip 0pt plus 1filll -Copyright @copyright{} 1988-2001 Free Software Foundation, Inc. +Copyright @copyright{} 1988-2002 Free Software Foundation, Inc. @end titlepage @ifinfo diff --git a/lib/readline/doc/hstech.texinfo b/lib/readline/doc/hstech.texinfo index 003721a7..94944466 100644 --- a/lib/readline/doc/hstech.texinfo +++ b/lib/readline/doc/hstech.texinfo @@ -1,7 +1,7 @@ @ignore This file documents the user interface to the GNU History library. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. Permission is granted to make and distribute verbatim copies of this manual @@ -188,8 +188,9 @@ Stifle the history list, remembering only the last @var{max} entries. @end deftypefun @deftypefun int unstifle_history (void) -Stop stifling the history. This returns the previous amount the -history was stifled. The value is positive if the history was +Stop stifling the history. This returns the previously-set +maximum number of history entries (as set by @code{stifle_history()}). +The value is positive if the history was stifled, negative if it wasn't. @end deftypefun diff --git a/lib/readline/doc/hsuser.texinfo b/lib/readline/doc/hsuser.texinfo index 6926b26f..418bfa8e 100644 --- a/lib/readline/doc/hsuser.texinfo +++ b/lib/readline/doc/hsuser.texinfo @@ -1,7 +1,7 @@ @ignore This file documents the user interface to the GNU History library. -Copyright (C) 1988-1999 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. Permission is granted to make and distribute verbatim copies of this manual diff --git a/lib/readline/doc/manvers.texinfo b/lib/readline/doc/manvers.texinfo index 859afc1e..1206cf0f 100644 --- a/lib/readline/doc/manvers.texinfo +++ b/lib/readline/doc/manvers.texinfo @@ -1,6 +1,10 @@ -@set EDITION 4.2a -@set VERSION 4.2a -@set UPDATED 2001 October 9 -@set UPDATE-MONTH October 2001 +@ignore +Copyright (C) 1988-2002 Free Software Foundation, Inc. +@end ignore -@set LASTCHANGE Tue Oct 9 15:03:34 EDT 2001 +@set EDITION 4.3 +@set VERSION 4.3 +@set UPDATED 2002 March 4 +@set UPDATE-MONTH March 2002 + +@set LASTCHANGE Mon Mar 4 12:00:16 EST 2002 diff --git a/lib/readline/doc/rlman.texinfo b/lib/readline/doc/rlman.texinfo index 894c5163..1ffebad0 100644 --- a/lib/readline/doc/rlman.texinfo +++ b/lib/readline/doc/rlman.texinfo @@ -18,7 +18,7 @@ This document describes the GNU Readline Library, a utility which aids in the consistency of user interface across discrete programs that need to provide a command line interface. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -73,7 +73,7 @@ except that this permission notice may be stated in a translation approved by the Free Software Foundation. @vskip 0pt plus 1filll -Copyright @copyright{} 1988-2001 Free Software Foundation, Inc. +Copyright @copyright{} 1988-2002 Free Software Foundation, Inc. @end titlepage @ifinfo diff --git a/lib/readline/doc/rltech.texinfo b/lib/readline/doc/rltech.texinfo index be9f662f..037e824e 100644 --- a/lib/readline/doc/rltech.texinfo +++ b/lib/readline/doc/rltech.texinfo @@ -8,7 +8,7 @@ This document describes the GNU Readline Library, a utility for aiding in the consitency of user interface across discrete programs that need to provide a command line interface. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -111,12 +111,13 @@ function, and has the advantage of no static buffer to overflow: /* A static variable for holding the line. */ static char *line_read = (char *)NULL; -/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +/* Read a string, and return a pointer to it. + Returns NULL on EOF. */ char * rl_gets () @{ - /* If the buffer has already been allocated, return the memory - to the free pool. */ + /* If the buffer has already been allocated, + return the memory to the free pool. */ if (line_read) @{ free (line_read); @@ -126,7 +127,8 @@ rl_gets () /* Get a line from the user. */ line_read = readline (""); - /* If the line has any text in it, save it on the history. */ + /* If the line has any text in it, + save it on the history. */ if (line_read && *line_read) add_history (line_read); @@ -263,7 +265,7 @@ variables that describe the current state of the line read so far. The calling sequence for a command @code{foo} looks like @example -@code{foo (int count, int key)} +@code{int foo (int count, int key)} @end example @noindent @@ -280,6 +282,9 @@ to do something useful with both negative and positive arguments. At the very least, it should be aware that it can be passed a negative argument. +A command function should return 0 if its action completes successfully, +and a non-zero value if some error occurs. + @node Readline Variables @section Readline Variables @@ -385,10 +390,12 @@ The value allows conditional parsing of the inputrc file @deftypevar {FILE *} rl_instream The stdio stream from which Readline reads input. +If @code{NULL}, Readline defaults to @var{stdin}. @end deftypevar @deftypevar {FILE *} rl_outstream The stdio stream to which Readline performs output. +If @code{NULL}, Readline defaults to @var{stdout}. @end deftypevar @deftypevar {rl_command_func_t *} rl_last_func @@ -766,9 +773,9 @@ This is done with @code{rl_begin_undo_group()} and The types of events that can be undone are: -@example +@smallexample enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @}; -@end example +@end smallexample Notice that @code{UNDO_DELETE} means to insert some text, and @code{UNDO_INSERT} means to delete some text. That is, the undo code @@ -901,10 +908,12 @@ to the result. @deftypefun int rl_insert_text (const char *text) Insert @var{text} into the line at the current cursor position. +Returns the number of characters inserted. @end deftypefun @deftypefun int rl_delete_text (int start, int end) Delete the text between @var{start} and @var{end} in the current line. +Returns the number of characters deleted. @end deftypefun @deftypefun {char *} rl_copy_text (int start, int end) @@ -947,7 +956,9 @@ be the keyboard. @deftypefun int rl_stuff_char (int c) Insert @var{c} into the Readline input stream. It will be "read" before Readline attempts to read characters from the terminal with -@code{rl_read_key()}. +@code{rl_read_key()}. Up to 512 characters may be pushed back. +@code{rl_stuff_char} returns 1 if the character was successfully inserted; +0 otherwise. @end deftypefun @deftypefun int rl_execute_next (int c) @@ -1000,6 +1011,13 @@ environment variable is used. @node Utility Functions @subsection Utility Functions +@deftypefun void rl_replace_line (const char *text, int clear_undo) +Replace the contents of @code{rl_line_buffer} with @var{text}. +The point and mark are preserved, if possible. +If @var{clear_undo} is non-zero, the undo list associated with the +current line is cleared. +@end deftypefun + @deftypefun int rl_extend_line_buffer (int len) Ensure that @code{rl_line_buffer} has enough space to hold @var{len} characters, possibly reallocating it if necessary. @@ -1123,16 +1141,26 @@ The function takes the text of the line as an argument. @deftypefun void rl_callback_read_char (void) Whenever an application determines that keyboard input is available, it should call @code{rl_callback_read_char()}, which will read the next -character from the current input source. If that character completes the -line, @code{rl_callback_read_char} will invoke the @var{lhandler} -function saved by @code{rl_callback_handler_install} to process the -line. @code{EOF} is indicated by calling @var{lhandler} with a +character from the current input source. +If that character completes the line, @code{rl_callback_read_char} will +invoke the @var{lhandler} function saved by @code{rl_callback_handler_install} +to process the line. +Before calling the @var{lhandler} function, the terminal settings are +reset to the values they had before calling +@code{rl_callback_handler_install}. +If the @var{lhandler} function returns, +the terminal settings are modified for Readline's use again. +@code{EOF} is indicated by calling @var{lhandler} with a @code{NULL} line. @end deftypefun @deftypefun void rl_callback_handler_remove (void) Restore the terminal to its initial state and remove the line handler. This may be called from within a callback as well as independently. +If the @var{lhandler} installed by @code{rl_callback_handler_install} +does not exit the program, either this function or the function referred +to by the value of @code{rl_deprep_term_function} should be called before +the program exits to reset the terminal settings. @end deftypefun @node A Readline Example @@ -1185,8 +1213,8 @@ invert_case_line (count, key) end = temp; @} - /* Tell readline that we are modifying the line, so it will save - the undo information. */ + /* Tell readline that we are modifying the line, + so it will save the undo information. */ rl_modifying (start, end); for (i = start; i != end; i++) @@ -1442,6 +1470,14 @@ partially-completed word. See description of @code{rl_complete()}. This calls @code{rl_complete_internal()} with an argument of @samp{*}. @end deftypefun +@deftypefun int rl_completion_mode (rl_command_func_t *cfunc) +Returns the apppriate value to pass to @code{rl_complete_internal()} +depending on whether @var{cfunc} was called twice in succession and +the value of the @code{show-all-if-ambiguous} variable. +Application-specific completion functions may use this function to present +the same interface as @code{rl_complete()}. +@end deftypefun + @deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func) Returns an array of strings which is a list of completions for @var{text}. If there are no completions, returns @code{NULL}. @@ -1528,10 +1564,41 @@ character found in @code{rl_completer_word_break_characters} should be used to break words for the completer. @end deftypevar -@deftypevar int rl_completion_query_items -Up to this many items will be displayed in response to a -possible-completions call. After that, we ask the user if she is sure -she wants to see them all. The default value is 100. +@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function +This function, if defined, is called by the completer when real filename +completion is done, after all the matching names have been generated. +It is passed a @code{NULL} terminated array of matches. +The first element (@code{matches[0]}) is the +maximal substring common to all matches. This function can +re-arrange the list of matches as required, but each element deleted +from the array must be freed. +@end deftypevar + +@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook +This function, if defined, is allowed to modify the directory portion +of filenames Readline completes. It is called with the address of a +string (the current directory name) as an argument, and may modify that string. +If the string is replaced with a new string, the old value should be freed. +Any modified directory name should have a trailing slash. +The modified value will be displayed as part of the completion, replacing +the directory portion of the pathname the user typed. +It returns an integer that should be non-zero if the function modifies +its directory argument. +It could be used to expand symbolic links or shell variables in pathnames. +@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. +This function is called in lieu of Readline displaying the list. +It takes three arguments: +(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length}) +where @var{matches} is the array of matching strings, +@var{num_matches} is the number of strings in that array, and +@var{max_length} is the length of the longest string in that array. +Readline provides a convenience function, @code{rl_display_match_list}, +that takes care of doing the display to Readline's output stream. That +function may be called from this hook. @end deftypevar @deftypevar {const char *} rl_basic_word_break_characters @@ -1571,6 +1638,12 @@ For instance, Bash sets this variable to "$@@" so that it can complete shell variables and hostnames. @end deftypevar +@deftypevar int rl_completion_query_items +Up to this many items will be displayed in response to a +possible-completions call. After that, we ask the user if she is sure +she wants to see them all. The default value is 100. +@end deftypevar + @deftypevar {int} rl_completion_append_character When a single completion alternative matches at the end of the command line, this character is appended to the inserted completion text. The @@ -1581,6 +1654,24 @@ provide the ``most sensible word separator character'' according to an application-specific command line syntax specification. @end deftypevar +@deftypevar int rl_completion_suppress_append +If non-zero, @var{rl_completion_append_character} is not appended to +matches at the end of the command line, as described above. It is +set to 0 before any application-specific completion function is called. +@end deftypevar + +@deftypevar int rl_completion_mark_symlink_dirs +If non-zero, a slash will be appended to completed filenames that are +symbolic links to directory names, subject to the value of the +user-settable @var{mark-directories} variable. +This variable exists so that application completion functions can +override the user's global preference (set via the +@var{mark-symlinked-directories} Readline variable) if appropriate. +This variable is set to the user's preference before any +application completion function is called, so unless that function +modifies the value, the user's preferences are honored. +@end deftypevar + @deftypevar int rl_ignore_completion_duplicates If non-zero, then duplicates in the matches are removed. The default is 1. @@ -1625,43 +1716,6 @@ If this variable is non-zero, completion is inhibited. The completion character will be inserted as any other bound to @code{self-insert}. @end deftypevar -@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function -This function, if defined, is called by the completer when real filename -completion is done, after all the matching names have been generated. -It is passed a @code{NULL} terminated array of matches. -The first element (@code{matches[0]}) is the -maximal substring common to all matches. This function can -re-arrange the list of matches as required, but each element deleted -from the array must be freed. -@end deftypevar - -@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook -This function, if defined, is allowed to modify the directory portion -of filenames Readline completes. It is called with the address of a -string (the current directory name) as an argument, and may modify that string. -If the string is replaced with a new string, the old value should be freed. -Any modified directory name should have a trailing slash. -The modified value will be displayed as part of the completion, replacing -the directory portion of the pathname the user typed. -It returns an integer that should be non-zero if the function modifies -its directory argument. -It could be used to expand symbolic links or shell variables in pathnames. -@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. -This function is called in lieu of Readline displaying the list. -It takes three arguments: -(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length}) -where @var{matches} is the array of matching strings, -@var{num_matches} is the number of strings in that array, and -@var{max_length} is the length of the longest string in that array. -Readline provides a convenience function, @code{rl_display_match_list}, -that takes care of doing the display to Readline's output stream. That -function may be called from this hook. -@end deftypevar - @node A Short Completion Example @subsection A Short Completion Example @@ -2089,12 +2143,13 @@ too_dangerous (caller) char *caller; @{ fprintf (stderr, - "%s: Too dangerous for me to distribute. Write it yourself.\n", + "%s: Too dangerous for me to distribute.\n" caller); + fprintf (stderr, "Write it yourself.\n"); @} -/* Return non-zero if ARG is a valid argument for CALLER, else print - an error message and return zero. */ +/* Return non-zero if ARG is a valid argument for CALLER, + else print an error message and return zero. */ int valid_argument (caller, arg) char *caller, *arg; diff --git a/lib/readline/doc/rluser.texinfo b/lib/readline/doc/rluser.texinfo index e4e56ff1..94f851e6 100644 --- a/lib/readline/doc/rluser.texinfo +++ b/lib/readline/doc/rluser.texinfo @@ -10,7 +10,7 @@ use these features. There is a document entitled "readline.texinfo" which contains both end-user and programmer documentation for the GNU Readline Library. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Authored by Brian Fox and Chet Ramey. @@ -512,6 +512,13 @@ This variable, when set to @samp{on}, causes Readline to display an asterisk (@samp{*}) at the start of history lines which have been modified. This variable is @samp{off} by default. +@item mark-symlinked-directories +@vindex mark-symlinked-directories +If set to @samp{on}, completed names which are symbolic links +to directories have a slash appended (subject to the value of +@code{mark-directories}). +The default is @samp{off}. + @item match-hidden-files @vindex match-hidden-files This variable, when set to @samp{on}, causes Readline to match files whose @@ -526,6 +533,12 @@ If set to @samp{on}, Readline will display characters with the eighth bit set directly rather than as a meta-prefixed escape sequence. The default is @samp{off}. +@item page-completions +@vindex page-completions +If set to @samp{on}, Readline uses an internal @code{more}-like pager +to display a screenful of possible completions at a time. +This variable is @samp{on} by default. + @item print-completions-horizontally If set to @samp{on}, Readline will display completions with matches sorted horizontally in alphabetical order, rather than down the screen. @@ -757,14 +770,14 @@ binding, variable assignment, and conditional syntax. @example @page # This file controls the behaviour of line input editing for -# programs that use the Gnu Readline library. Existing programs -# include FTP, Bash, and Gdb. +# programs that use the GNU Readline library. Existing +# programs include FTP, Bash, and GDB. # # You can re-read the inputrc file with C-x C-r. # Lines beginning with '#' are comments. # -# First, include any systemwide bindings and variable assignments from -# /etc/Inputrc +# First, include any systemwide bindings and variable +# assignments from /etc/Inputrc $include /etc/Inputrc # @@ -816,10 +829,12 @@ TAB: complete $if Bash # edit the path "\C-xp": "PATH=$@{PATH@}\e\C-e\C-a\ef\C-f" -# prepare to type a quoted word -- insert open and close double quotes +# prepare to type a quoted word -- +# insert open and close double quotes # and move to just after the open quote "\C-x\"": "\"\"\C-b" -# insert a backslash (testing backslash escapes in sequences and macros) +# insert a backslash (testing backslash escapes +# in sequences and macros) "\C-x\\": "\\" # Quote the current or previous word "\C-xq": "\eb\"\ef\"" @@ -835,16 +850,16 @@ set bell-style visible # don't strip characters to 7 bits when reading set input-meta on -# allow iso-latin1 characters to be inserted rather than converted to -# prefix-meta sequences +# allow iso-latin1 characters to be inserted rather +# than converted to prefix-meta sequences set convert-meta off -# display characters with the eighth bit set directly rather than -# as meta-prefixed characters +# display characters with the eighth bit set directly +# rather than as meta-prefixed characters set output-meta on -# if there are more than 150 possible completions for a word, ask the -# user if he wants to see all of them +# if there are more than 150 possible completions for +# a word, ask the user if he wants to see all of them set completion-query-items 150 # For FTP @@ -1053,6 +1068,20 @@ lowercase the previous word, but do not move the cursor. Capitalize the current (or following) word. With a negative argument, capitalize the previous word, but do not move the cursor. +@item overwrite-mode () +Toggle overwrite mode. With an explicit positive numeric argument, +switches to overwrite mode. With an explicit non-positive numeric +argument, switches to insert mode. This command affects only +@code{emacs} mode; @code{vi} mode does overwrite differently. +Each call to @code{readline()} starts in insert mode. + +In overwrite mode, characters bound to @code{self-insert} replace +the text at point rather than pushing the text to the right. +Characters bound to @code{backward-delete-char} replace the character +before point with a space. + +By default, this command is unbound. + @end ftable @node Commands For Killing @@ -1312,12 +1341,19 @@ of that character. A negative count searches for subsequent occurrences. @item insert-comment (M-#) -The value of the @code{comment-begin} -variable is inserted at the beginning of the current line, -and the line is accepted as if a newline had been typed. +Without a numeric argument, the value of the @code{comment-begin} +variable is inserted at the beginning of the current line. +If a numeric argument is supplied, this command acts as a toggle: if +the characters at the beginning of the line do not match the value +of @code{comment-begin}, the value is inserted, otherwise +the characters in @code{comment-begin} are deleted from the beginning of +the line. +In either case, the line is accepted as if a newline had been typed. @ifset BashFeatures The default value of @code{comment-begin} causes this command to make the current line a shell comment. +If a numeric argument causes the comment character to be removed, the line +will be executed by the shell. @end ifset @item dump-functions () @@ -1339,13 +1375,22 @@ the output is formatted in such a way that it can be made part of an @var{inputrc} file. This command is unbound by default. @ifset BashFeatures +@item glob-complete-word (M-g) +The word before point is treated as a pattern for pathname expansion, +with an asterisk implicitly appended. This pattern is used to +generate a list of matching file names for possible completions. + @item glob-expand-word (C-x *) The word before point is treated as a pattern for pathname expansion, and the list of matching file names is inserted, replacing the word. +If a numeric argument is supplied, a @samp{*} is appended before +pathname expansion. @item glob-list-expansions (C-x g) The list of expansions that would have been generated by @code{glob-expand-word} is displayed, and the line is redrawn. +If a numeric argument is supplied, a @samp{*} is appended before +pathname expansion. @item display-shell-version (C-x C-v) Display version information about the current instance of Bash. @@ -1376,13 +1421,26 @@ Accept the current line for execution and fetch the next line relative to the current line from the history for editing. Any argument is ignored. -@item emacs-editing-mode (C-e) -When in @code{vi} editing mode, this causes a switch back to -@code{emacs} editing mode, as if the command @samp{set -o emacs} had -been executed. +@item edit-and-execute-command (C-xC-e) +Invoke an editor on the current command line, and execute the result as shell +commands. +Bash attempts to invoke +@code{$FCEDIT}, @code{$EDITOR}, and @code{emacs} +as the editor, in that order. @end ifset +@ifclear BashFeatures +@item emacs-editing-mode (C-e) +When in @code{vi} command mode, this causes a switch to @code{emacs} +editing mode. + +@item vi-editing-mode (M-C-j) +When in @code{emacs} editing mode, this causes a switch to @code{vi} +editing mode. + +@end ifclear + @end ftable @node Readline vi Mode @@ -1518,6 +1576,12 @@ If the @option{-o default} option was supplied to @code{complete} when the compspec was defined, Readline's default completion will be performed if the compspec generates no matches. +When a compspec indicates that directory name completion is desired, +the programmable completion functions force Readline to append a slash +to completed names which are symbolic links to directories, subject to +the value of the @var{mark-directories} Readline variable, regardless +of the setting of the @var{mark-symlinked-directories} Readline variable. + @node Programmable Completion Builtins @section Programmable Completion Builtins @cindex completion builtins @@ -1553,7 +1617,7 @@ matches were generated. @item complete @btindex complete @example -@code{complete [-abcdefgjkvu] [-o @var{comp-option}] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}] +@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}] [-P @var{prefix}] [-S @var{suffix}] [-X @var{filterpat}] [-F @var{function}] [-C @var{command}] @var{name} [@var{name} @dots{}]} @code{complete -pr [@var{name} @dots{}]} @@ -1586,7 +1650,8 @@ beyond the simple generation of completions. @table @code @item default -Use readline's default completion if the compspec generates no matches. +Use Readline's default filename completion if the compspec generates +no matches. @item dirnames Perform directory name completion if the compspec generates no matches. @@ -1596,6 +1661,10 @@ Tell Readline that the compspec generates filenames, so it can perform any filename\-specific processing (like adding a slash to directory names or suppressing trailing spaces). This option is intended to be used with shell functions specified with @option{-F}. + +@item nospace +Tell Readline not to append a space (the default) to words completed at +the end of the line. @end table @item -A @var{action} @@ -1655,6 +1724,9 @@ Shell reserved words. May also be specified as @option{-k}. @item running Names of running jobs, if job control is active. +@item service +Service names. May also be specified as @option{-s}. + @item setopt Valid arguments for the @option{-o} option to the @code{set} builtin (@pxref{The Set Builtin}). diff --git a/lib/readline/doc/rluserman.texinfo b/lib/readline/doc/rluserman.texinfo index db560b9c..89abe31a 100644 --- a/lib/readline/doc/rluserman.texinfo +++ b/lib/readline/doc/rluserman.texinfo @@ -17,7 +17,7 @@ This document describes the end user interface of the GNU Readline Library, a utility which aids in the consistency of user interface across discrete programs that need to provide a command line interface. -Copyright (C) 1988-2001 Free Software Foundation, Inc. +Copyright (C) 1988-2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -72,7 +72,7 @@ except that this permission notice may be stated in a translation approved by the Free Software Foundation. @vskip 0pt plus 1filll -Copyright @copyright{} 1988-2001 Free Software Foundation, Inc. +Copyright @copyright{} 1988-2002 Free Software Foundation, Inc. @end titlepage @ifinfo diff --git a/lib/readline/emacs_keymap.c b/lib/readline/emacs_keymap.c index e2f2b30f..ca9d1343 100644 --- a/lib/readline/emacs_keymap.c +++ b/lib/readline/emacs_keymap.c @@ -35,11 +35,11 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { /* Control keys. */ { ISFUNC, rl_set_mark }, /* Control-@ */ { ISFUNC, rl_beg_of_line }, /* Control-a */ - { ISFUNC, rl_backward }, /* Control-b */ + { ISFUNC, rl_backward_char }, /* Control-b */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ { ISFUNC, rl_delete }, /* Control-d */ { ISFUNC, rl_end_of_line }, /* Control-e */ - { ISFUNC, rl_forward }, /* Control-f */ + { ISFUNC, rl_forward_char }, /* Control-f */ { ISFUNC, rl_abort }, /* Control-g */ { ISFUNC, rl_rubout }, /* Control-h */ { ISFUNC, rl_complete }, /* Control-i */ diff --git a/lib/readline/examples/Inputrc b/lib/readline/examples/Inputrc index 5b71bd70..d7fdb42e 100644 --- a/lib/readline/examples/Inputrc +++ b/lib/readline/examples/Inputrc @@ -4,6 +4,22 @@ # on which program is running, or what terminal is active. # +# Copyright (C) 1989-2002 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + # In all programs, all terminals, make sure this is bound. "\C-x\C-r": re-read-init-file diff --git a/lib/readline/examples/Makefile b/lib/readline/examples/Makefile index d8df38c8..636a1dc3 100644 --- a/lib/readline/examples/Makefile +++ b/lib/readline/examples/Makefile @@ -35,6 +35,10 @@ fileman: fileman.o rltest: rltest.o $(CC) $(LDFLAGS) -o $@ rltest.o -lreadline -ltermcap +rlcat: rlcat.o + $(CC) $(LDFLAGS) -o $@ rlcat.o -lreadline -ltermcap + fileman.o: fileman.c rltest.o: rltest.c rl.o: rl.c +rlcat.o: rlcat.c diff --git a/lib/readline/examples/fileman.c b/lib/readline/examples/fileman.c index 578491a4..340eee73 100644 --- a/lib/readline/examples/fileman.c +++ b/lib/readline/examples/fileman.c @@ -1,3 +1,23 @@ +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + /* fileman.c -- A tiny application which demonstrates how to use the GNU Readline library. This application interactively allows users to manipulate files and their modes. */ diff --git a/lib/readline/examples/histexamp.c b/lib/readline/examples/histexamp.c index fa0de1be..45651dfb 100644 --- a/lib/readline/examples/histexamp.c +++ b/lib/readline/examples/histexamp.c @@ -1,3 +1,23 @@ +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + #include <stdio.h> #ifdef READLINE_LIBRARY diff --git a/lib/readline/examples/manexamp.c b/lib/readline/examples/manexamp.c index 132e2bfe..9c6cf2c7 100644 --- a/lib/readline/examples/manexamp.c +++ b/lib/readline/examples/manexamp.c @@ -1,5 +1,25 @@ /* manexamp.c -- The examples which appear in the documentation are here. */ +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + #include <stdio.h> #include <readline/readline.h> diff --git a/lib/readline/examples/rl.c b/lib/readline/examples/rl.c index 86361845..d2604895 100644 --- a/lib/readline/examples/rl.c +++ b/lib/readline/examples/rl.c @@ -5,6 +5,26 @@ * usage: rl [-p prompt] [-u unit] [-d default] [-n nchars] */ +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + #if defined (HAVE_CONFIG_H) # include <config.h> #endif diff --git a/lib/readline/examples/rlcat.c b/lib/readline/examples/rlcat.c new file mode 100644 index 00000000..176b9f44 --- /dev/null +++ b/lib/readline/examples/rlcat.c @@ -0,0 +1,174 @@ +/* + * rlcat - cat(1) using readline + * + * usage: rlcat + */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <sys/types.h> +#include "posixstat.h" + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> + +#ifndef errno +extern int errno; +#endif + +#if defined (READLINE_LIBRARY) +# include "readline.h" +# include "history.h" +#else +# include <readline/readline.h> +# include <readline/history.h> +#endif + +extern int optind; +extern char *optarg; + +static int stdcat(); + +static char *progname; +static int vflag; + +static void +usage() +{ + fprintf (stderr, "%s: usage: %s [-vEVN] [filename]\n", progname, progname); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + char *temp; + int opt, Vflag, Nflag; + + progname = strrchr(argv[0], '/'); + if (progname == 0) + progname = argv[0]; + else + progname++; + + vflag = Vflag = Nflag = 0; + while ((opt = getopt(argc, argv, "vEVN")) != EOF) + { + switch (opt) + { + case 'v': + vflag = 1; + break; + case 'V': + Vflag = 1; + break; + case 'E': + Vflag = 0; + break; + case 'N': + Nflag = 1; + break; + default: + usage (); + exit (2); + } + } + + argc -= optind; + argv += optind; + + if (isatty(0) == 0 || argc || Nflag) + return stdcat(argc, argv); + + rl_variable_bind ("editing-mode", Vflag ? "vi" : "emacs"); + while (temp = readline ("")) + { + if (*temp) + add_history (temp); + printf ("%s\n", temp); + } + + return (ferror (stdout)); +} + +static int +fcopy(fp) + FILE *fp; +{ + int c; + char *x; + + while ((c = getc(fp)) != EOF) + { + if (vflag && isascii ((unsigned char)c) && isprint((unsigned char)c) == 0) + { + x = rl_untranslate_keyseq (c); + if (fputs (x, stdout) != 0) + return 1; + } + else if (putchar (c) == EOF) + return 1; + } + return (ferror (stdout)); +} + +int +stdcat (argc, argv) + int argc; + char **argv; +{ + int i, fd, r; + char *s; + FILE *fp; + + if (argc == 0) + return (fcopy(stdin)); + + for (i = 0, r = 1; i < argc; i++) + { + if (*argv[i] == '-' && argv[i][1] == 0) + fp = stdin; + else + { + fp = fopen (argv[i], "r"); + if (fp == 0) + { + fprintf (stderr, "%s: %s: cannot open: %s\n", progname, argv[i], strerror(errno)); + continue; + } + } + r = fcopy (fp); + if (fp != stdin) + fclose(fp); + } + return r; +} diff --git a/lib/readline/examples/rltest.c b/lib/readline/examples/rltest.c index 6250f900..99f083b2 100644 --- a/lib/readline/examples/rltest.c +++ b/lib/readline/examples/rltest.c @@ -4,6 +4,26 @@ /* */ /* **************************************************************** */ +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + #if defined (HAVE_CONFIG_H) #include <config.h> #endif diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c index e4f28012..fe9a1da4 100644 --- a/lib/readline/funmap.c +++ b/lib/readline/funmap.c @@ -60,7 +60,8 @@ static FUNMAP default_funmap[] = { { "abort", rl_abort }, { "accept-line", rl_newline }, { "arrow-key-prefix", rl_arrow_keys }, - { "backward-char", rl_backward }, + { "backward-byte", rl_backward_byte }, + { "backward-char", rl_backward_char }, { "backward-delete-char", rl_rubout }, { "backward-kill-line", rl_backward_kill_line }, { "backward-kill-word", rl_backward_kill_word }, @@ -91,7 +92,8 @@ static FUNMAP default_funmap[] = { { "end-of-line", rl_end_of_line }, { "exchange-point-and-mark", rl_exchange_point_and_mark }, { "forward-backward-delete-char", rl_rubout_or_delete }, - { "forward-char", rl_forward }, + { "forward-byte", rl_forward_byte }, + { "forward-char", rl_forward_char }, { "forward-search-history", rl_forward_search_history }, { "forward-word", rl_forward_word }, { "history-search-backward", rl_history_search_backward }, @@ -108,6 +110,7 @@ static FUNMAP default_funmap[] = { { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again }, { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again }, + { "overwrite-mode", rl_overwrite_mode }, #ifdef __CYGWIN__ { "paste-from-clipboard", rl_paste_from_clipboard }, #endif diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c index 04f6478e..6c811961 100644 --- a/lib/readline/histexpand.c +++ b/lib/readline/histexpand.c @@ -41,11 +41,7 @@ # include <unistd.h> #endif -#if defined (HAVE_STRING_H) -# include <string.h> -#else -# include <strings.h> -#endif /* !HAVE_STRING_H */ +#include "rlmbutil.h" #include "history.h" #include "histlib.h" @@ -58,6 +54,8 @@ typedef int _hist_search_func_t PARAMS((const char *, int)); +extern int rl_byte_oriented; /* declared in mbutil.c */ + static char error_pointer; static char *subst_lhs; @@ -204,12 +202,30 @@ get_history_event (string, caller_index, delimiting_quote) /* Only a closing `?' or a newline delimit a substring search string. */ for (local_index = i; c = string[i]; i++) - if ((!substring_okay && (whitespace (c) || c == ':' || - (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || - string[i] == delimiting_quote)) || - string[i] == '\n' || - (substring_okay && string[i] == '?')) - break; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + /* These produce warnings because we're passing a const string to a + function that takes a non-const string. */ + _rl_adjust_point (string, i, &ps); + if ((v = _rl_get_char_len (string + i, &ps)) > 1) + { + i += v - 1; + continue; + } + } + else +#endif /* HANDLE_MULTIBYTE */ + if ((!substring_okay && (whitespace (c) || c == ':' || + (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || + string[i] == delimiting_quote)) || + string[i] == '\n' || + (substring_okay && string[i] == '?')) + break; which = i - local_index; temp = (char *)xmalloc (1 + which); @@ -405,13 +421,33 @@ get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) int *iptr, delimiter, is_rhs, *lenptr; { register int si, i, j, k; - char *s = (char *) NULL; + char *s; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; +#endif + s = (char *)NULL; i = *iptr; +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); + _rl_adjust_point (str, i, &ps); +#endif + for (si = i; str[si] && str[si] != delimiter; si++) - if (str[si] == '\\' && str[si + 1] == delimiter) - si++; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + if ((v = _rl_get_char_len (str + si, &ps)) > 1) + si += v - 1; + else if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (str[si] == '\\' && str[si + 1] == delimiter) + si++; if (si > i || is_rhs) { @@ -484,6 +520,11 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) int substitute_globally, want_quotes, print_only; char *event, *temp, *result, *tstr, *t, c, *word_spec; int result_len; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif result = (char *)xmalloc (result_len = 128); @@ -514,8 +555,21 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) quote, then this expansion takes place inside of the quoted string. If we have to search for some text ("!foo"), allow the delimiter to end the search string. */ - if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) - quoted_search_delimiter = string[i - 1]; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int c, l; + l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY); + c = string[l]; + /* XXX - original patch had i - 1 ??? If i == 0 it would fail. */ + if (i && (c == '\'' || c == '"')) + quoted_search_delimiter = c; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) + quoted_search_delimiter = string[i - 1]; + event = get_history_event (string, &i, quoted_search_delimiter); } @@ -634,7 +688,20 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) if (c == 's') { if (i + 2 < (int)strlen (string)) - delimiter = string[i + 2]; + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + _rl_adjust_point (string, i + 2, &ps); + if (_rl_get_char_len (string + i + 2, &ps) > 1) + delimiter = 0; + else + delimiter = string[i + 2]; + } + else +#endif /* HANDLE_MULTIBYTE */ + delimiter = string[i + 2]; + } else break; /* no search delimiter */ @@ -819,6 +886,11 @@ history_expand (hstring, output) int result_len; char *result; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; + mbstate_t ps; +#endif + /* Used when adding the string. */ char *temp; @@ -861,6 +933,10 @@ history_expand (hstring, output) } else { +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); +#endif + string = hstring; /* If not quick substitution, still maybe have to do expansion. */ @@ -868,8 +944,21 @@ history_expand (hstring, output) is NOT an expansion. */ for (i = 0; string[i]; i++) { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + v = _rl_get_char_len (string + i, &ps); + if (v > 1) + { + i += v - 1; + continue; + } + } +#endif /* HANDLE_MULTIBYTE */ + cc = string[i + 1]; - /* The history_comment_char, if set, appearing that the beginning + /* The history_comment_char, if set, appearing at the beginning of a word signifies that the rest of the line should not have history expansion performed on it. Skip the rest of the line and break out of the loop. */ @@ -932,6 +1021,30 @@ history_expand (hstring, output) continue; } +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int k, c; + + c = tchar; + memset (mb, 0, sizeof (mb)); + for (k = 0; k < MB_LEN_MAX; k++) + { + mb[k] = (char)c; + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_get_char_len (mb, &ps) == -2) + c = string[++i]; + else + break; + } + if (strlen (mb) > 1) + { + ADD_STRING (mb); + break; + } + } +#endif /* HANDLE_MULTIBYTE */ + if (tchar == history_expansion_char) tchar = -3; else if (tchar == history_comment_char) diff --git a/lib/readline/histfile.c b/lib/readline/histfile.c index ab3c6c1d..60a91251 100644 --- a/lib/readline/histfile.c +++ b/lib/readline/histfile.c @@ -48,12 +48,26 @@ # include <unistd.h> #endif -#if defined (HAVE_STRING_H) -# include <string.h> -#else -# include <strings.h> -#endif /* !HAVE_STRING_H */ +#if defined (__EMX__) || defined (__CYGWIN__) +# undef HAVE_MMAP +#endif +#ifdef HAVE_MMAP +# include <sys/mman.h> + +# ifdef MAP_FILE +# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) +# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) +# else +# define MAP_RFLAGS MAP_PRIVATE +# define MAP_WFLAGS MAP_SHARED +# endif + +# ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +# endif + +#endif /* HAVE_MMAP */ /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment on win 95/98/nt), we want to open files with O_BINARY mode so that there @@ -137,8 +151,8 @@ read_history_range (filename, from, to) const char *filename; int from, to; { - register int line_start, line_end; - char *input, *buffer; + register char *line_start, *line_end; + char *input, *buffer, *bufend; int file, current_line, chars_read; struct stat finfo; size_t file_size; @@ -157,23 +171,39 @@ read_history_range (filename, from, to) { #if defined (EFBIG) errno = EFBIG; +#elif defined (EOVERFLOW) + errno = EOVERFLOW; #endif goto error_and_exit; } - buffer = (char *)xmalloc (file_size + 1); +#ifdef HAVE_MMAP + /* We map read/write and private so we can change newlines to NULs without + affecting the underlying object. */ + buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); + if ((void *)buffer == MAP_FAILED) + goto error_and_exit; + chars_read = file_size; +#else + buffer = (char *)malloc (file_size + 1); + if (buffer == 0) + goto error_and_exit; chars_read = read (file, buffer, file_size); +#endif if (chars_read < 0) { error_and_exit: + chars_read = errno; if (file >= 0) close (file); FREE (input); +#ifndef HAVE_MMAP FREE (buffer); +#endif - return (errno); + return (chars_read); } close (file); @@ -183,29 +213,25 @@ read_history_range (filename, from, to) to = chars_read; /* Start at beginning of file, work to end. */ - line_start = line_end = current_line = 0; + bufend = buffer + chars_read; + current_line = 0; /* Skip lines until we are at FROM. */ - while (line_start < chars_read && current_line < from) - { - for (line_end = line_start; line_end < chars_read; line_end++) - if (buffer[line_end] == '\n') - { - current_line++; - line_start = line_end + 1; - if (current_line == from) - break; - } - } + for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) + if (*line_end == '\n') + { + current_line++; + line_start = line_end + 1; + } /* If there are lines left to gobble, then gobble them now. */ - for (line_end = line_start; line_end < chars_read; line_end++) - if (buffer[line_end] == '\n') + for (line_end = line_start; line_end < bufend; line_end++) + if (*line_end == '\n') { - buffer[line_end] = '\0'; + *line_end = '\0'; - if (buffer[line_start]) - add_history (buffer + line_start); + if (*line_start) + add_history (line_start); current_line++; @@ -216,7 +242,11 @@ read_history_range (filename, from, to) } FREE (input); +#ifndef HAVE_MMAP FREE (buffer); +#else + munmap (buffer, file_size); +#endif return (0); } @@ -229,9 +259,8 @@ history_truncate_file (fname, lines) const char *fname; int lines; { - register int i; + char *buffer, *filename, *bp; int file, chars_read, rv; - char *buffer, *filename; struct stat finfo; size_t file_size; @@ -276,7 +305,13 @@ history_truncate_file (fname, lines) goto truncate_exit; } - buffer = (char *)xmalloc (file_size + 1); + buffer = (char *)malloc (file_size + 1); + if (buffer == 0) + { + close (file); + goto truncate_exit; + } + chars_read = read (file, buffer, file_size); close (file); @@ -288,9 +323,9 @@ history_truncate_file (fname, lines) /* Count backwards from the end of buffer until we have passed LINES lines. */ - for (i = chars_read - 1; lines && i; i--) + for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) { - if (buffer[i] == '\n') + if (*bp == '\n') lines--; } @@ -299,22 +334,22 @@ history_truncate_file (fname, lines) anything. It's the first line if we don't find a newline between the current value of i and 0. Otherwise, write from the start of this line until the end of the buffer. */ - for ( ; i; i--) - if (buffer[i] == '\n') + for ( ; bp > buffer; bp--) + if (*bp == '\n') { - i++; + bp++; break; } /* Write only if there are more lines in the file than we want to truncate to. */ - if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) + if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) { - write (file, buffer + i, chars_read - i); + write (file, bp, chars_read - (bp - buffer)); #if defined (__BEOS__) /* BeOS ignores O_TRUNC. */ - ftruncate (file, chars_read - i); + ftruncate (file, chars_read - (bp - buffer)); #endif close (file); @@ -339,8 +374,13 @@ history_do_write (filename, nelements, overwrite) register int i; char *output; int file, mode, rv; + size_t cursize; +#ifdef HAVE_MMAP + mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; +#else mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; +#endif output = history_filename (filename); rv = 0; @@ -350,6 +390,10 @@ history_do_write (filename, nelements, overwrite) return (errno); } +#ifdef HAVE_MMAP + cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); +#endif + if (nelements > history_length) nelements = history_length; @@ -367,7 +411,28 @@ history_do_write (filename, nelements, overwrite) buffer_size += 1 + strlen (the_history[i]->line); /* Allocate the buffer, and fill it. */ - buffer = (char *)xmalloc (buffer_size); +#ifdef HAVE_MMAP + if (ftruncate (file, buffer_size+cursize) == -1) + goto mmap_error; + buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); + if ((void *)buffer == MAP_FAILED) + { +mmap_error: + rv = errno; + FREE (output); + close (file); + return rv; + } +#else + buffer = (char *)malloc (buffer_size); + if (buffer == 0) + { + rv = errno; + FREE (output); + close (file); + return rv; + } +#endif for (j = 0, i = history_length - nelements; i < history_length; i++) { @@ -376,9 +441,14 @@ history_do_write (filename, nelements, overwrite) buffer[j++] = '\n'; } +#ifdef HAVE_MMAP + if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) + rv = errno; +#else if (write (file, buffer, buffer_size) < 0) rv = errno; free (buffer); +#endif } close (file); diff --git a/lib/readline/histlib.h b/lib/readline/histlib.h index bc948b08..c39af718 100644 --- a/lib/readline/histlib.h +++ b/lib/readline/histlib.h @@ -22,6 +22,12 @@ #if !defined (_HISTLIB_H_) #define _HISTLIB_H_ +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + #if !defined (STREQ) #define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) #define STREQN(a, b, n) (((n) == 0) ? (1) \ @@ -29,9 +35,6 @@ #endif #ifndef savestring -# ifndef strcpy -extern char *strcpy (); -# endif #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) #endif diff --git a/lib/readline/history.c b/lib/readline/history.c index e2d65ea5..4242f33e 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -44,12 +44,6 @@ # include <unistd.h> #endif -#if defined (HAVE_STRING_H) -# include <string.h> -#else -# include <strings.h> -#endif /* !HAVE_STRING_H */ - #include "history.h" #include "histlib.h" @@ -349,19 +343,19 @@ stifle_history (max) max_input_history = history_max_entries = max; } -/* Stop stifling the history. This returns the previous amount the - history was stifled by. The value is positive if the history was - stifled, negative if it wasn't. */ +/* Stop stifling the history. This returns the previous maximum + number of history entries. The value is positive if the history + was stifled, negative if it wasn't. */ int unstifle_history () { if (history_stifled) { history_stifled = 0; - return (-history_max_entries); + return (history_max_entries); } - - return (history_max_entries); + else + return (-history_max_entries); } int diff --git a/lib/readline/histsearch.c b/lib/readline/histsearch.c index 76303f4c..d94fd6cd 100644 --- a/lib/readline/histsearch.c +++ b/lib/readline/histsearch.c @@ -32,17 +32,13 @@ #else # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ + #if defined (HAVE_UNISTD_H) # ifdef _MINIX # include <sys/types.h> # endif # include <unistd.h> #endif -#if defined (HAVE_STRING_H) -# include <string.h> -#else -# include <strings.h> -#endif /* !HAVE_STRING_H */ #include "history.h" #include "histlib.h" diff --git a/lib/readline/input.c b/lib/readline/input.c index e34558bf..841f05d1 100644 --- a/lib/readline/input.c +++ b/lib/readline/input.c @@ -63,6 +63,7 @@ extern int errno; /* System-specific feature definitions and include files. */ #include "rldefs.h" +#include "rlmbutil.h" /* Some standard library routines. */ #include "readline.h" @@ -86,8 +87,7 @@ static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */ static int ibuffer_space PARAMS((void)); static int rl_get_char PARAMS((int *)); -static int rl_unget_char PARAMS((int)); -static void rl_gather_tyi PARAMS((void)); +static int rl_gather_tyi PARAMS((void)); /* **************************************************************** */ /* */ @@ -139,8 +139,8 @@ rl_get_char (key) /* Stuff KEY into the *front* of the input buffer. Returns non-zero if successful, zero if there is no space left in the buffer. */ -static int -rl_unget_char (key) +int +_rl_unget_char (key) int key; { if (ibuffer_space ()) @@ -154,9 +154,10 @@ rl_unget_char (key) return (0); } -/* If a character is available to be read, then read it - and stuff it into IBUFFER. Otherwise, just return. */ -static void +/* If a character is available to be read, then read it and stuff it into + IBUFFER. Otherwise, just return. Returns number of characters read + (0 if none available) and -1 on error (EIO). */ +static int rl_gather_tyi () { int tty; @@ -177,13 +178,17 @@ rl_gather_tyi () FD_SET (tty, &exceptfds); timeout.tv_sec = 0; timeout.tv_usec = _keyboard_input_timeout; - if (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) <= 0) - return; /* Nothing to read. */ + result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout); + if (result <= 0) + return 0; /* Nothing to read. */ #endif result = -1; #if defined (FIONREAD) + errno = 0; result = ioctl (tty, FIONREAD, &chars_avail); + if (result == -1 && errno == EIO) + return -1; #endif #if defined (O_NDELAY) @@ -196,14 +201,14 @@ rl_gather_tyi () fcntl (tty, F_SETFL, tem); if (chars_avail == -1 && errno == EAGAIN) - return; + return 0; } #endif /* O_NDELAY */ /* If there's nothing available, don't waste time trying to read something. */ if (chars_avail <= 0) - return; + return 0; tem = ibuffer_space (); @@ -227,6 +232,8 @@ rl_gather_tyi () if (chars_avail) rl_stuff_char (input); } + + return 1; } int @@ -242,7 +249,11 @@ rl_set_keyboard_input_timeout (u) } /* Is there input available to be read on the readline input file - descriptor? Only works if the system has select(2) or FIONREAD. */ + descriptor? Only works if the system has select(2) or FIONREAD. + Uses the value of _keyboard_input_timeout as the timeout; if another + readline function wants to specify a timeout and not leave it up to + the user, it should use _rl_input_queued(timeout_value_in_microseconds) + instead. */ int _rl_input_available () { @@ -277,6 +288,18 @@ _rl_input_available () return 0; } +int +_rl_input_queued (t) + int t; +{ + int old_timeout, r; + + old_timeout = rl_set_keyboard_input_timeout (t); + r = _rl_input_available (); + rl_set_keyboard_input_timeout (old_timeout); + return r; +} + void _rl_insert_typein (c) int c; @@ -294,7 +317,7 @@ _rl_insert_typein (c) string[i++] = key; if (t) - rl_unget_char (key); + _rl_unget_char (key); string[i] = '\0'; rl_insert_text (string); @@ -375,7 +398,11 @@ rl_read_key () (*rl_event_hook) (); if (rl_done) /* XXX - experimental */ return ('\n'); - rl_gather_tyi (); + if (rl_gather_tyi () < 0) /* XXX - EIO */ + { + rl_done = 1; + return ('\n'); + } } } else @@ -441,3 +468,73 @@ rl_getc (stream) return (EOF); } } + +#if defined (HANDLE_MULTIBYTE) +/* read multibyte char */ +int +_rl_read_mbchar (mbchar, size) + char *mbchar; + int size; +{ + int mb_len = 0; + size_t mbchar_bytes_length; + wchar_t wc; + mbstate_t ps, ps_back; + + memset(&ps, 0, sizeof (mbstate_t)); + memset(&ps_back, 0, sizeof (mbstate_t)); + + while (mb_len < size) + { + RL_SETSTATE(RL_STATE_MOREINPUT); + mbchar[mb_len++] = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps); + if (mbchar_bytes_length == (size_t)(-1)) + break; /* invalid byte sequence for the current locale */ + else if (mbchar_bytes_length == (size_t)(-2)) + { + /* shorted bytes */ + ps = ps_back; + continue; + } + else if (mbchar_bytes_length > (size_t)(0)) + break; + } + + return mb_len; +} + +/* Read a multibyte-character string whose first character is FIRST into + the buffer MB of length MBLEN. Returns the last character read, which + may be FIRST. Used by the search functions, among others. Very similar + to _rl_read_mbchar. */ +int +_rl_read_mbstring (first, mb, mblen) + int first; + char *mb; + int mblen; +{ + int i, c; + mbstate_t ps; + + c = first; + memset (mb, 0, mblen); + for (i = 0; i < mblen; i++) + { + mb[i] = (char)c; + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_get_char_len (mb, &ps) == -2) + { + /* Read more for multibyte character */ + RL_SETSTATE (RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE (RL_STATE_MOREINPUT); + } + else + break; + } + return c; +} +#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/readline/isearch.c b/lib/readline/isearch.c index 2e3e16b8..c1ea5b30 100644 --- a/lib/readline/isearch.c +++ b/lib/readline/isearch.c @@ -4,7 +4,7 @@ /* */ /* **************************************************************** */ -/* Copyright (C) 1987,1989 Free Software Foundation, Inc. +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. This file contains the Readline Library (the Library), a set of routines for providing Emacs style line input to programs that ask @@ -45,6 +45,8 @@ #endif #include "rldefs.h" +#include "rlmbutil.h" + #include "readline.h" #include "history.h" @@ -165,8 +167,12 @@ rl_search_history (direction, invoking_key) HIST_ENTRY **hlist; register int i; - int orig_point, orig_line, last_found_line; + int orig_point, orig_mark, orig_line, last_found_line; int c, found, failed, sline_len; + int n, wstart, wlen; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; +#endif /* The line currently being searched. */ char *sline; @@ -184,6 +190,7 @@ rl_search_history (direction, invoking_key) RL_SETSTATE(RL_STATE_ISEARCH); orig_point = rl_point; + orig_mark = rl_mark; last_found_line = orig_line = where_history (); reverse = direction < 0; hlist = history_list (); @@ -246,6 +253,12 @@ rl_search_history (direction, invoking_key) c = rl_read_key (); RL_UNSETSTATE(RL_STATE_MOREINPUT); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, MB_LEN_MAX); +#endif + + /* Translate the keys we do something with to opcodes. */ if (c >= 0 && _rl_keymap[c].type == ISFUNC) { f = _rl_keymap[c].function; @@ -254,33 +267,53 @@ rl_search_history (direction, invoking_key) c = reverse ? -1 : -2; else if (f == rl_forward_search_history) c = !reverse ? -1 : -2; + else if (f == rl_rubout) + c = -3; + else if (c == CTRL ('G')) + c = -4; + else if (c == CTRL ('W')) /* XXX */ + c = -5; + else if (c == CTRL ('Y')) /* XXX */ + c = -6; } -#if 0 - /* Let NEWLINE (^J) terminate the search for people who don't like - using ESC. ^M can still be used to terminate the search and - immediately execute the command. */ - if (c == ESC || c == NEWLINE) -#else /* The characters in isearch_terminators (set from the user-settable variable isearch-terminators) are used to terminate the search but not subsequently execute the character as a command. The default value is "\033\012" (ESC and C-J). */ if (strchr (isearch_terminators, c)) -#endif { /* ESC still terminates the search, but if there is pending input or if input arrives within 0.1 seconds (on systems with select(2)) it is used as a prefix character with rl_execute_next. WATCH OUT FOR THIS! This is intended to allow the arrow keys to be used like ^F and ^B are used - to terminate the search and execute the movement command. */ - if (c == ESC && _rl_input_available ()) /* XXX */ + to terminate the search and execute the movement command. + XXX - since _rl_input_available depends on the application- + settable keyboard timeout value, this could alternatively + use _rl_input_queued(100000) */ + if (c == ESC && _rl_input_available ()) rl_execute_next (ESC); break; } - if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G')) +#define ENDSRCH_CHAR(c) \ + ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c)) + { + /* This sets rl_pending_input to c; it will be picked up the next + time rl_read_key is called. */ + rl_execute_next (c); + break; + } + } + else +#endif + if (c >= 0 && ENDSRCH_CHAR (c)) { /* This sets rl_pending_input to c; it will be picked up the next time rl_read_key is called. */ @@ -318,10 +351,23 @@ rl_search_history (direction, invoking_key) reverse = direction < 0; break; - case CTRL ('G'): - strcpy (rl_line_buffer, lines[orig_line]); + /* delete character from search string. */ + case -3: /* C-H, DEL */ + /* This is tricky. To do this right, we need to keep a + stack of search positions for the current search, with + sentinels marking the beginning and end. But this will + do until we have a real isearch-undo. */ + if (search_string_index == 0) + rl_ding (); + else + search_string[--search_string_index] = '\0'; + + break; + + case -4: /* C-G */ + rl_replace_line (lines[orig_line], 0); rl_point = orig_point; - rl_end = strlen (rl_line_buffer); + rl_mark = orig_mark; rl_restore_prompt(); rl_clear_message (); if (allocated_line) @@ -330,20 +376,53 @@ rl_search_history (direction, invoking_key) RL_UNSETSTATE(RL_STATE_ISEARCH); return 0; -#if 0 - /* delete character from search string. */ - case -3: - if (search_string_index == 0) - rl_ding (); - else + case -5: /* C-W */ + /* skip over portion of line we already matched */ + wstart = rl_point + search_string_index; + if (wstart >= rl_end) + { + rl_ding (); + break; + } + + /* if not in a word, move to one. */ + if (rl_alphabetic(rl_line_buffer[wstart]) == 0) { - search_string[--search_string_index] = '\0'; - /* This is tricky. To do this right, we need to keep a - stack of search positions for the current search, with - sentinels marking the beginning and end. */ + rl_ding (); + break; } + n = wstart; + while (n < rl_end && rl_alphabetic(rl_line_buffer[n])) + n++; + wlen = n - wstart + 1; + if (search_string_index + wlen + 1 >= search_string_size) + { + search_string_size += wlen + 1; + search_string = (char *)xrealloc (search_string, search_string_size); + } + for (; wstart < n; wstart++) + search_string[search_string_index++] = rl_line_buffer[wstart]; + search_string[search_string_index] = '\0'; + break; + + case -6: /* C-Y */ + /* skip over portion of line we already matched */ + wstart = rl_point + search_string_index; + if (wstart >= rl_end) + { + rl_ding (); + break; + } + n = rl_end - wstart + 1; + if (search_string_index + n + 1 >= search_string_size) + { + search_string_size += n + 1; + search_string = (char *)xrealloc (search_string, search_string_size); + } + for (n = wstart; n < rl_end; n++) + search_string[search_string_index++] = rl_line_buffer[n]; + search_string[search_string_index] = '\0'; break; -#endif default: /* Add character to search string and continue search. */ @@ -352,7 +431,16 @@ rl_search_history (direction, invoking_key) search_string_size += 128; search_string = (char *)xrealloc (search_string, search_string_size); } - search_string[search_string_index++] = c; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int j, l; + for (j = 0, l = strlen (mb); j < l; ) + search_string[search_string_index++] = mb[j++]; + } + else +#endif + search_string[search_string_index++] = c; search_string[search_string_index] = '\0'; break; } @@ -417,17 +505,9 @@ rl_search_history (direction, invoking_key) the location. */ if (found) { - int line_len; - prev_line_found = lines[i]; - line_len = strlen (lines[i]); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (rl_line_buffer, lines[i]); + rl_replace_line (lines[i], 0); rl_point = line_index; - rl_end = line_len; last_found_line = i; rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); } @@ -443,25 +523,32 @@ rl_search_history (direction, invoking_key) rl_restore_prompt (); -#if 1 /* Save the search string for possible later use. */ FREE (last_isearch_string); last_isearch_string = search_string; last_isearch_string_len = search_string_index; -#else - /* Free the search string. */ - free (search_string); -#endif if (last_found_line < orig_line) rl_get_previous_history (orig_line - last_found_line, 0); else rl_get_next_history (last_found_line - orig_line, 0); - /* If the string was not found, put point at the end of the line. */ + /* If the string was not found, put point at the end of the last matching + line. If last_found_line == orig_line, we didn't find any matching + history lines at all, so put point back in its original position. */ if (line_index < 0) - line_index = strlen (rl_line_buffer); + { + if (last_found_line == orig_line) + line_index = orig_point; + else + line_index = strlen (rl_line_buffer); + rl_mark = orig_mark; + } + rl_point = line_index; + /* Don't worry about where to put the mark here; rl_get_previous_history + and rl_get_next_history take care of it. */ + rl_clear_message (); FREE (allocated_line); diff --git a/lib/readline/keymaps.h b/lib/readline/keymaps.h index 93cc8208..66fa2a5e 100644 --- a/lib/readline/keymaps.h +++ b/lib/readline/keymaps.h @@ -49,8 +49,9 @@ typedef struct _keymap_entry { /* This must be large enough to hold bindings for all of the characters in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x, - and so on). */ -#define KEYMAP_SIZE 256 + and so on) plus one for subsequence matching. */ +#define KEYMAP_SIZE 257 +#define ANYOTHERKEY KEYMAP_SIZE-1 /* I wanted to make the above structure contain a union of: union { rl_command_func_t *function; struct _keymap_entry *keymap; } value; diff --git a/lib/readline/kill.c b/lib/readline/kill.c index 90ce6e45..a616b920 100644 --- a/lib/readline/kill.c +++ b/lib/readline/kill.c @@ -201,18 +201,21 @@ int rl_kill_word (count, key) int count, key; { - int orig_point = rl_point; + int orig_point; if (count < 0) return (rl_backward_kill_word (-count, key)); else { + orig_point = rl_point; rl_forward_word (count, key); if (rl_point != orig_point) rl_kill_text (orig_point, rl_point); rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } return 0; } @@ -222,16 +225,20 @@ int rl_backward_kill_word (count, ignore) int count, ignore; { - int orig_point = rl_point; + int orig_point; if (count < 0) return (rl_kill_word (-count, ignore)); else { + orig_point = rl_point; rl_backward_word (count, ignore); if (rl_point != orig_point) rl_kill_text (orig_point, rl_point); + + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } return 0; } @@ -242,16 +249,19 @@ int rl_kill_line (direction, ignore) int direction, ignore; { - int orig_point = rl_point; + int orig_point; if (direction < 0) return (rl_backward_kill_line (1, ignore)); else { + orig_point = rl_point; rl_end_of_line (1, ignore); if (orig_point != rl_point) rl_kill_text (orig_point, rl_point); rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } return 0; } @@ -262,7 +272,7 @@ int rl_backward_kill_line (direction, ignore) int direction, ignore; { - int orig_point = rl_point; + int orig_point; if (direction < 0) return (rl_kill_line (1, ignore)); @@ -272,8 +282,12 @@ rl_backward_kill_line (direction, ignore) rl_ding (); else { + orig_point = rl_point; rl_beg_of_line (1, ignore); - rl_kill_text (orig_point, rl_point); + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } } return 0; @@ -287,6 +301,7 @@ rl_kill_full_line (count, ignore) rl_begin_undo_group (); rl_point = 0; rl_kill_text (rl_point, rl_end); + rl_mark = 0; rl_end_undo_group (); return 0; } @@ -321,6 +336,8 @@ rl_unix_word_rubout (count, key) } rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } return 0; } @@ -341,6 +358,8 @@ rl_unix_line_discard (count, key) { rl_kill_text (rl_point, 0); rl_point = 0; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; } return 0; } @@ -353,17 +372,14 @@ region_kill_internal (delete) { char *text; - if (rl_mark == rl_point) + if (rl_mark != rl_point) { - _rl_last_command_was_kill++; - return 0; + text = rl_copy_text (rl_point, rl_mark); + if (delete) + rl_delete_text (rl_point, rl_mark); + _rl_copy_to_kill_ring (text, rl_point < rl_mark); } - text = rl_copy_text (rl_point, rl_mark); - if (delete) - rl_delete_text (rl_point, rl_mark); - _rl_copy_to_kill_ring (text, rl_point < rl_mark); - _rl_last_command_was_kill++; return 0; } @@ -530,6 +546,8 @@ rl_yank_nth_arg_internal (count, ignore, history_skip) rl_begin_undo_group (); + _rl_set_mark_at_pos (rl_point); + #if defined (VI_MODE) /* Vi mode always inserts a space before yanking the argument, and it inserts it right *after* rl_point. */ @@ -623,6 +641,7 @@ rl_paste_from_clipboard (count, key) } else ptr = data; + _rl_set_mark_at_pos (rl_point); rl_insert_text (ptr); if (ptr != data) free (ptr); diff --git a/lib/readline/macro.c b/lib/readline/macro.c index 347f89bf..b73c3af9 100644 --- a/lib/readline/macro.c +++ b/lib/readline/macro.c @@ -49,8 +49,6 @@ #include "rlprivate.h" #include "xmalloc.h" -#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) - /* **************************************************************** */ /* */ /* Hacking Keyboard Macros */ @@ -61,9 +59,6 @@ then it is a malloc ()'ed string where input is coming from. */ char *rl_executing_macro = (char *)NULL; -/* Non-zero means to save keys that we dispatch on in a kbd macro. */ -int _rl_defining_kbd_macro = 0; - /* The offset in the above string to the next character to be read. */ static int executing_macro_index; @@ -186,7 +181,6 @@ _rl_kill_kbd_macro () rl_executing_macro = (char *) NULL; executing_macro_index = 0; - _rl_defining_kbd_macro = 0; RL_UNSETSTATE(RL_STATE_MACRODEF); } @@ -200,7 +194,7 @@ int rl_start_kbd_macro (ignore1, ignore2) int ignore1, ignore2; { - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) { _rl_abort_internal (); return -1; @@ -214,7 +208,6 @@ rl_start_kbd_macro (ignore1, ignore2) else current_macro_index = 0; - _rl_defining_kbd_macro = 1; RL_SETSTATE(RL_STATE_MACRODEF); return 0; } @@ -226,7 +219,7 @@ int rl_end_kbd_macro (count, ignore) int count, ignore; { - if (_rl_defining_kbd_macro == 0) + if (RL_ISSTATE (RL_STATE_MACRODEF) == 0) { _rl_abort_internal (); return -1; @@ -235,7 +228,6 @@ rl_end_kbd_macro (count, ignore) current_macro_index -= rl_key_sequence_length - 1; current_macro[current_macro_index] = '\0'; - _rl_defining_kbd_macro = 0; RL_UNSETSTATE(RL_STATE_MACRODEF); return (rl_call_last_kbd_macro (--count, 0)); @@ -250,7 +242,7 @@ rl_call_last_kbd_macro (count, ignore) if (current_macro == 0) _rl_abort_internal (); - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) { rl_ding (); /* no recursive macros */ current_macro[--current_macro_index] = '\0'; /* erase this char */ diff --git a/lib/readline/mbutil.c b/lib/readline/mbutil.c new file mode 100644 index 00000000..50302f01 --- /dev/null +++ b/lib/readline/mbutil.c @@ -0,0 +1,337 @@ +/* mbutil.c -- readline multibyte character utility functions */ + +/* Copyright (C) 2001 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include "posixjmp.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> +#include <ctype.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (TIOCSTAT_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* TIOCSTAT_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* Declared here so it can be shared between the readline and history + libraries. */ +#if defined (HANDLE_MULTIBYTE) +int rl_byte_oriented = 0; +#else +int rl_byte_oriented = 1; +#endif + +/* **************************************************************** */ +/* */ +/* Multibyte Character Utility Functions */ +/* */ +/* **************************************************************** */ + +#if defined(HANDLE_MULTIBYTE) + +static int +_rl_find_next_mbchar_internal (string, seed, count, find_non_zero) + char *string; + int seed, count, find_non_zero; +{ + size_t tmp = 0; + mbstate_t ps; + int point = 0; + wchar_t wc; + + memset(&ps, 0, sizeof (mbstate_t)); + if (seed < 0) + seed = 0; + if (count <= 0) + return seed; + + point = seed + _rl_adjust_point(string, seed, &ps); + /* if this is true, means that seed was not pointed character + started byte. So correct the point and consume count */ + if (seed < point) + count --; + + while (count > 0) + { + tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps); + if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* invalid bytes. asume a byte represents a character */ + point++; + count--; + /* reset states. */ + memset(&ps, 0, sizeof(mbstate_t)); + } + else if (tmp == (size_t)0) + /* found '\0' char */ + break; + else + { + /* valid bytes */ + point += tmp; + if (find_non_zero) + { + if (wcwidth (wc) == 0) + continue; + else + count--; + } + else + count--; + } + } + + if (find_non_zero) + { + tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); + while (wcwidth (wc) == 0) + { + point += tmp; + tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); + if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2)) + break; + } + } + return point; +} + +static int +_rl_find_prev_mbchar_internal (string, seed, find_non_zero) + char *string; + int seed, find_non_zero; +{ + mbstate_t ps; + int prev, non_zero_prev, point, length; + size_t tmp; + wchar_t wc; + + memset(&ps, 0, sizeof(mbstate_t)); + length = strlen(string); + + if (seed < 0) + return 0; + else if (length < seed) + return length; + + prev = non_zero_prev = point = 0; + while (point < seed) + { + tmp = mbrtowc (&wc, string + point, length - point, &ps); + if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* in this case, bytes are invalid or shorted to compose + multibyte char, so assume that the first byte represents + a single character anyway. */ + tmp = 1; + /* clear the state of the byte sequence, because + in this case effect of mbstate is undefined */ + memset(&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' char. Can this happen? */ + else + { + if (find_non_zero) + { + if (wcwidth (wc) != 0) + prev = point; + } + else + prev = point; + } + + point += tmp; + } + + return prev; +} + +/* return the number of bytes parsed from the multibyte sequence starting + at src, if a non-L'\0' wide character was recognized. It returns 0, + if a L'\0' wide character was recognized. It returns (size_t)(-1), + if an invalid multibyte sequence was encountered. It returns (size_t)(-2) + if it couldn't parse a complete multibyte character. */ +int +_rl_get_char_len (src, ps) + char *src; + mbstate_t *ps; +{ + size_t tmp; + + tmp = mbrlen((const char *)src, (size_t)strlen (src), ps); + if (tmp == (size_t)(-2)) + { + /* shorted to compose multibyte char */ + memset (ps, 0, sizeof(mbstate_t)); + return -2; + } + else if (tmp == (size_t)(-1)) + { + /* invalid to compose multibyte char */ + /* initialize the conversion state */ + memset (ps, 0, sizeof(mbstate_t)); + return -1; + } + else if (tmp == (size_t)0) + return 0; + else + return (int)tmp; +} + +/* compare the specified two characters. If the characters matched, + return 1. Otherwise return 0. */ +int +_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) + char *buf1, *buf2; + mbstate_t *ps1, *ps2; + int pos1, pos2; +{ + int i, w1, w2; + + if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 || + (w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 || + (w1 != w2) || + (buf1[pos1] != buf2[pos2])) + return 0; + + for (i = 1; i < w1; i++) + if (buf1[pos1+i] != buf2[pos2+i]) + return 0; + + return 1; +} + +/* adjust pointed byte and find mbstate of the point of string. + adjusted point will be point <= adjusted_point, and returns + differences of the byte(adjusted_point - point). + if point is invalied (point < 0 || more than string length), + it returns -1 */ +int +_rl_adjust_point(string, point, ps) + char *string; + int point; + mbstate_t *ps; +{ + size_t tmp = 0; + int length; + int pos = 0; + + length = strlen(string); + if (point < 0) + return -1; + if (length < point) + return -1; + + while (pos < point) + { + tmp = mbrlen (string + pos, length - pos, ps); + if((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* in this case, bytes are invalid or shorted to compose + multibyte char, so assume that the first byte represents + a single character anyway. */ + pos++; + /* clear the state of the byte sequence, because + in this case effect of mbstate is undefined */ + memset (ps, 0, sizeof (mbstate_t)); + } + else + pos += tmp; + } + + return (pos - point); +} + +int +_rl_is_mbchar_matched (string, seed, end, mbchar, length) + char *string; + int seed, end; + char *mbchar; + int length; +{ + int i; + + if ((end - seed) < length) + return 0; + + for (i = 0; i < length; i++) + if (string[seed + i] != mbchar[i]) + return 0; + return 1; +} +#endif /* HANDLE_MULTIBYTE */ + +/* Find next `count' characters started byte point of the specified seed. + If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte + characters. */ +#undef _rl_find_next_mbchar +int +_rl_find_next_mbchar (string, seed, count, flags) + char *string; + int seed, count, flags; +{ +#if defined (HANDLE_MULTIBYTE) + return _rl_find_next_mbchar_internal (string, seed, count, flags); +#else + return (seed + count); +#endif +} + +/* Find previous character started byte point of the specified seed. + Returned point will be point <= seed. If flags is MB_FIND_NONZERO, + we look for non-zero-width multibyte characters. */ +#undef _rl_find_prev_mbchar +int +_rl_find_prev_mbchar (string, seed, flags) + char *string; + int seed, flags; +{ +#if defined (HANDLE_MULTIBYTE) + return _rl_find_prev_mbchar_internal (string, seed, flags); +#else + return ((seed == 0) ? seed : seed - 1); +#endif +} diff --git a/lib/readline/misc.c b/lib/readline/misc.c new file mode 100644 index 00000000..f3775d30 --- /dev/null +++ b/lib/readline/misc.c @@ -0,0 +1,496 @@ +/* misc.c -- miscellaneous bindable readline functions. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +static int rl_digit_loop PARAMS((void)); +static void _rl_history_set_point PARAMS((void)); + +/* Forward declarations used in this file */ +void _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +/* If non-zero, rl_get_previous_history and rl_get_next_history attempt + to preserve the value of rl_point from line to line. */ +int _rl_history_preserve_point = 0; + +/* Saved target point for when _rl_history_preserve_point is set. Special + value of -1 means that point is at the end of the line. */ +int _rl_history_saved_point = -1; + +/* **************************************************************** */ +/* */ +/* Numeric Arguments */ +/* */ +/* **************************************************************** */ + +/* Handle C-u style numeric args, as well as M--, and M-digits. */ +static int +rl_digit_loop () +{ + int key, c, sawminus, sawdigits; + + rl_save_prompt (); + + RL_SETSTATE(RL_STATE_NUMERICARG); + sawminus = sawdigits = 0; + while (1) + { + if (rl_numeric_arg > 1000000) + { + sawdigits = rl_explicit_arg = rl_numeric_arg = 0; + rl_ding (); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return 1; + } + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); + RL_SETSTATE(RL_STATE_MOREINPUT); + key = c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c < 0) + { + _rl_abort_internal (); + return -1; + } + + /* If we see a key bound to `universal-argument' after seeing digits, + it ends the argument but is otherwise ignored. */ + if (_rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + if (sawdigits == 0) + { + rl_numeric_arg *= 4; + continue; + } + else + { + RL_SETSTATE(RL_STATE_MOREINPUT); + key = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + c = UNMETA (c); + + if (_rl_digit_p (c)) + { + rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; + sawdigits = rl_explicit_arg = 1; + } + else if (c == '-' && rl_explicit_arg == 0) + { + rl_numeric_arg = sawminus = 1; + rl_arg_sign = -1; + } + else + { + /* Make M-- command equivalent to M--1 command. */ + if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) + rl_explicit_arg = 1; + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + /*NOTREACHED*/ +} + +/* Add the current digit to the argument in progress. */ +int +rl_digit_argument (ignore, key) + int ignore, key; +{ + rl_execute_next (key); + return (rl_digit_loop ()); +} + +/* What to do when you abort reading an argument. */ +int +rl_discard_argument () +{ + rl_ding (); + rl_clear_message (); + _rl_init_argument (); + return 0; +} + +/* Create a default argument. */ +int +_rl_init_argument () +{ + rl_numeric_arg = rl_arg_sign = 1; + rl_explicit_arg = 0; + return 0; +} + +/* C-u, universal argument. Multiply the current argument by 4. + Read a key. If the key has nothing to do with arguments, then + dispatch on it. If the key is the abort character then abort. */ +int +rl_universal_argument (count, key) + int count, key; +{ + rl_numeric_arg *= 4; + return (rl_digit_loop ()); +} + +/* **************************************************************** */ +/* */ +/* History Utilities */ +/* */ +/* **************************************************************** */ + +/* We already have a history library, and that is what we use to control + the history features of readline. This is our local interface to + the history mechanism. */ + +/* While we are editing the history, this is the saved + version of the original line. */ +HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL; + +/* Set the history pointer back to the last entry in the history. */ +void +_rl_start_using_history () +{ + using_history (); + if (_rl_saved_line_for_history) + _rl_free_history_entry (_rl_saved_line_for_history); + + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; +} + +/* Free the contents (and containing structure) of a HIST_ENTRY. */ +void +_rl_free_history_entry (entry) + HIST_ENTRY *entry; +{ + if (entry == 0) + return; + if (entry->line) + free (entry->line); + free (entry); +} + +/* Perhaps put back the current line if it has changed. */ +int +rl_maybe_replace_line () +{ + HIST_ENTRY *temp; + + temp = current_history (); + /* If the current line has changed, save the changes. */ + if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) + { + temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list); + free (temp->line); + free (temp); + } + return 0; +} + +/* Restore the _rl_saved_line_for_history if there is one. */ +int +rl_maybe_unsave_line () +{ + if (_rl_saved_line_for_history) + { + rl_replace_line (_rl_saved_line_for_history->line, 0); + rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + rl_point = rl_end; /* rl_replace_line sets rl_end */ + } + else + rl_ding (); + return 0; +} + +/* Save the current line in _rl_saved_line_for_history. */ +int +rl_maybe_save_line () +{ + if (_rl_saved_line_for_history == 0) + { + _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + _rl_saved_line_for_history->line = savestring (rl_line_buffer); + _rl_saved_line_for_history->data = (char *)rl_undo_list; + } + return 0; +} + +int +_rl_free_saved_history_line () +{ + if (_rl_saved_line_for_history) + { + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + } + return 0; +} + +static void +_rl_history_set_point () +{ + rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) + ? _rl_history_saved_point + : rl_end; + if (rl_point > rl_end) + rl_point = rl_end; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_point = 0; +#endif /* VI_MODE */ + + if (rl_editing_mode == emacs_mode) + rl_mark = (rl_point == rl_end ? 0 : rl_end); +} + +void +rl_replace_from_history (entry, flags) + HIST_ENTRY *entry; + int flags; /* currently unused */ +{ + rl_replace_line (entry->line, 0); + rl_undo_list = (UNDO_LIST *)entry->data; + rl_point = rl_end; + rl_mark = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + { + rl_point = 0; + rl_mark = rl_end; + } +#endif +} + +/* **************************************************************** */ +/* */ +/* History Commands */ +/* */ +/* **************************************************************** */ + +/* Meta-< goes to the start of the history. */ +int +rl_beginning_of_history (count, key) + int count, key; +{ + return (rl_get_previous_history (1 + where_history (), key)); +} + +/* Meta-> goes to the end of the history. (The current line). */ +int +rl_end_of_history (count, key) + int count, key; +{ + rl_maybe_replace_line (); + using_history (); + rl_maybe_unsave_line (); + return 0; +} + +/* Move down to the next history line. */ +int +rl_get_next_history (count, key) + int count, key; +{ + HIST_ENTRY *temp; + + if (count < 0) + return (rl_get_previous_history (-count, key)); + + if (count == 0) + return 0; + + rl_maybe_replace_line (); + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = next_history (); + if (!temp) + break; + --count; + } + + if (temp == 0) + rl_maybe_unsave_line (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* Get the previous item out of our interactive history, making it the current + line. If there is no previous history, just ding. */ +int +rl_get_previous_history (count, key) + int count, key; +{ + HIST_ENTRY *old_temp, *temp; + + if (count < 0) + return (rl_get_next_history (-count, key)); + + if (count == 0) + return 0; + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + /* If we don't have a line saved, then save this one. */ + rl_maybe_save_line (); + + /* If the current line has changed, save the changes. */ + rl_maybe_replace_line (); + + temp = old_temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = previous_history (); + if (temp == 0) + break; + + old_temp = temp; + --count; + } + + /* If there was a large argument, and we moved back to the start of the + history, that is not an error. So use the last value found. */ + if (!temp && old_temp) + temp = old_temp; + + if (temp == 0) + rl_ding (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* **************************************************************** */ +/* */ +/* Editing Modes */ +/* */ +/* **************************************************************** */ +/* How to toggle back and forth between editing modes. */ +int +rl_vi_editing_mode (count, key) + int count, key; +{ +#if defined (VI_MODE) + _rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */ + rl_editing_mode = vi_mode; + rl_vi_insertion_mode (1, key); +#endif /* VI_MODE */ + + return 0; +} + +int +rl_emacs_editing_mode (count, key) + int count, key; +{ + rl_editing_mode = emacs_mode; + _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */ + _rl_keymap = emacs_standard_keymap; + return 0; +} + +/* Function for the rest of the library to use to set insert/overwrite mode. */ +void +_rl_set_insert_mode (im, force) + int im, force; +{ +#ifdef CURSOR_MODE + _rl_set_cursor (im, force); +#endif + + rl_insert_mode = im; +} + +/* Toggle overwrite mode. A positive explicit argument selects overwrite + mode. A negative or zero explicit argument selects insert mode. */ +int +rl_overwrite_mode (count, key) + int count, key; +{ + if (rl_explicit_arg == 0) + _rl_set_insert_mode (rl_insert_mode ^ 1, 0); + else if (count > 0) + _rl_set_insert_mode (RL_IM_OVERWRITE, 0); + else + _rl_set_insert_mode (RL_IM_INSERT, 0); + + return 0; +} diff --git a/lib/readline/parens.c b/lib/readline/parens.c index ca6c3688..54ef1f36 100644 --- a/lib/readline/parens.c +++ b/lib/readline/parens.c @@ -30,6 +30,10 @@ #include <stdio.h> #include <sys/types.h> +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + #if defined (FD_SET) && !defined (HAVE_SELECT) # define HAVE_SELECT #endif @@ -103,7 +107,7 @@ rl_insert_close (count, invoking_key) int count, invoking_key; { if (rl_explicit_arg || !rl_blink_matching_paren) - rl_insert (count, invoking_key); + _rl_insert_char (count, invoking_key); else { #if defined (HAVE_SELECT) @@ -111,7 +115,7 @@ rl_insert_close (count, invoking_key) struct timeval timer; fd_set readfds; - rl_insert (1, invoking_key); + _rl_insert_char (1, invoking_key); (*rl_redisplay_function) (); match_point = find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); @@ -131,7 +135,7 @@ rl_insert_close (count, invoking_key) ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); rl_point = orig_point; #else /* !HAVE_SELECT */ - rl_insert (count, invoking_key); + _rl_insert_char (count, invoking_key); #endif /* !HAVE_SELECT */ } return 0; diff --git a/lib/readline/posixdir.h b/lib/readline/posixdir.h index 98ced75b..505e2795 100644 --- a/lib/readline/posixdir.h +++ b/lib/readline/posixdir.h @@ -46,4 +46,12 @@ # define d_fileno d_ino #endif +#if defined (_POSIX_SOURCE) && (!defined (STRUCT_DIRENT_HAS_D_INO) || defined (BROKEN_DIRENT_D_INO)) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* _POSIX_SOURCE */ + #endif /* !_POSIXDIR_H_ */ diff --git a/lib/readline/readline.c b/lib/readline/readline.c index 3efd8102..28801f19 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -1,7 +1,7 @@ /* readline.c -- a general facility for reading lines of input with emacs style editing and completion. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -52,6 +52,7 @@ /* System-specific feature definitions and include files. */ #include "rldefs.h" +#include "rlmbutil.h" #if defined (__EMX__) # define INCL_DOSPROCESS @@ -67,24 +68,21 @@ #include "xmalloc.h" #ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "4.2a" +# define RL_LIBRARY_VERSION "4.3" #endif #ifndef RL_READLINE_VERSION -# define RL_READLINE_VERSION 0x0402 +# define RL_READLINE_VERSION 0x0403 #endif -/* Evaluates its arguments multiple times. */ -#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); /* Forward declarations used in this file. */ -void _rl_free_history_entry PARAMS((HIST_ENTRY *)); - static char *readline_internal PARAMS((void)); static void readline_initialize_everything PARAMS((void)); -static void start_using_history PARAMS((void)); + +static void bind_arrow_keys_internal PARAMS((Keymap)); static void bind_arrow_keys PARAMS((void)); -static int rl_change_case PARAMS((int, int)); static void readline_default_bindings PARAMS((void)); @@ -108,6 +106,9 @@ Keymap _rl_keymap = emacs_standard_keymap; /* The current style of editing. */ int rl_editing_mode = emacs_mode; +/* The current insert mode: input (the default) or overwrite */ +int rl_insert_mode = RL_IM_DEFAULT; + /* Non-zero if we called this function from _rl_dispatch(). It's present so functions can find out whether they were called from a key binding or directly from an application. */ @@ -249,14 +250,6 @@ int _rl_convert_meta_chars_to_ascii = 1; rather than as a meta-prefixed escape sequence. */ int _rl_output_meta_chars = 0; -/* If non-zero, rl_get_previous_history and rl_get_next_history attempt - to preserve the value of rl_point from line to line. */ -int _rl_history_preserve_point = 0; - -/* Saved target point for when _rl_history_preserve_point is set. Special - value of -1 means that point is at the end of the line. */ -static int _rl_history_saved_point = -1; - /* **************************************************************** */ /* */ /* Top Level Functions */ @@ -330,7 +323,10 @@ readline_internal_setup () if (rl_startup_hook) (*rl_startup_hook) (); - if (readline_echoing_p == 0) + /* If we're not echoing, we still want to at least print a prompt, because + rl_redisplay will not do it for us. If the calling application has a + custom redisplay function, though, let that function handle it. */ + if (readline_echoing_p == 0 && rl_redisplay_function == rl_redisplay) { if (rl_prompt && rl_already_prompted == 0) { @@ -347,11 +343,12 @@ readline_internal_setup () else rl_on_new_line (); (*rl_redisplay_function) (); + } + #if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (1, 0); + if (rl_editing_mode == vi_mode) + rl_vi_insertion_mode (1, 0); #endif /* VI_MODE */ - } if (rl_pre_input_hook) (*rl_pre_input_hook) (); @@ -384,6 +381,9 @@ readline_internal_teardown (eof) if (rl_undo_list) rl_free_undo_list (); + /* Restore normal cursor, if available. */ + _rl_set_insert_mode (RL_IM_INSERT, 0); + return (eof ? (char *)NULL : savestring (the_line)); } @@ -507,7 +507,7 @@ readline_internal () void _rl_init_line_state () { - rl_point = rl_end = 0; + rl_point = rl_end = rl_mark = 0; the_line = rl_line_buffer; the_line[0] = 0; } @@ -526,6 +526,15 @@ _rl_dispatch (key, map) register int key; Keymap map; { + return _rl_dispatch_subseq (key, map, 0); +} + +int +_rl_dispatch_subseq (key, map, got_subseq) + register int key; + Keymap map; + int got_subseq; +{ int r, newkey; char *macro; rl_command_func_t *func; @@ -534,7 +543,7 @@ _rl_dispatch (key, map) { if (map[ESC].type == ISKMAP) { - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) _rl_add_macro_char (ESC); map = FUNCTION_TO_KEYMAP (map, ESC); key = UNMETA (key); @@ -546,7 +555,7 @@ _rl_dispatch (key, map) return 0; } - if (_rl_defining_kbd_macro) + if (RL_ISSTATE (RL_STATE_MACRODEF)) _rl_add_macro_char (key); r = 0; @@ -578,6 +587,23 @@ _rl_dispatch (key, map) if (rl_pending_input == 0 && map[key].function != rl_digit_argument) rl_last_func = map[key].function; } + else if (map[ANYOTHERKEY].function) + { + /* OK, there's no function bound in this map, but there is a + shadow function that was overridden when the current keymap + was created. Return -2 to note that. */ + _rl_unget_char (key); + return -2; + } + else if (got_subseq) + { + /* Return -1 to note that we're in a subsequence, but we don't + have a matching key, nor was one overridden. This means + we need to back up the recursion chain and find the last + subsequence that is bound to a function. */ + _rl_unget_char (key); + return -1; + } else { _rl_abort_internal (); @@ -588,6 +614,18 @@ _rl_dispatch (key, map) case ISKMAP: if (map[key].function != 0) { +#if defined (VI_MODE) + /* The only way this test will be true is if a subsequence has been + bound starting with ESC, generally the arrow keys. What we do is + check whether there's input in the queue, which there generally + will be if an arrow key has been pressed, and, if there's not, + just dispatch to (what we assume is) rl_vi_movement_mode right + away. This is essentially an input test with a zero timeout. */ + if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap + && _rl_input_queued (0) == 0) + return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); +#endif + rl_key_sequence_length++; if (key == ESC) @@ -604,7 +642,29 @@ _rl_dispatch (key, map) return -1; } - r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key)); + r = _rl_dispatch_subseq (newkey, FUNCTION_TO_KEYMAP (map, key), got_subseq || map[ANYOTHERKEY].function); + + if (r == -2) + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ + r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); + else if (r && map[ANYOTHERKEY].function) + { + /* We didn't match (r is probably -1), so return something to + tell the caller that it should try ANYOTHERKEY for an + overridden function. */ + _rl_unget_char (key); + return -2; + } + else if (r && got_subseq) + { + /* OK, back up the chain. */ + _rl_unget_char (key); + return -1; + } } else { @@ -659,7 +719,7 @@ rl_initialize () RL_UNSETSTATE(RL_STATE_DONE); /* Tell the history routines what is going on. */ - start_using_history (); + _rl_start_using_history (); /* Make the display buffer match the state of the line. */ rl_reset_line_state (); @@ -675,6 +735,9 @@ rl_initialize () _rl_vi_initialize_line (); #endif + /* Each line starts in insert mode (the default). */ + _rl_set_insert_mode (RL_IM_DEFAULT, 1); + return 0; } @@ -787,1426 +850,124 @@ readline_default_bindings () rl_tty_set_default_bindings (_rl_keymap); } +/* Bind some common arrow key sequences in MAP. */ static void -bind_arrow_keys_internal () -{ - rl_command_func_t *f; - -#if defined (__MSDOS__) - f = rl_function_of_keyseq ("\033[0A", _rl_keymap, (int *)NULL); - if (!f || f == rl_do_lowercase_version) - { - _rl_bind_if_unbound ("\033[0A", rl_get_previous_history); - _rl_bind_if_unbound ("\033[0B", rl_backward); - _rl_bind_if_unbound ("\033[0C", rl_forward); - _rl_bind_if_unbound ("\033[0D", rl_get_next_history); - } -#endif - - f = rl_function_of_keyseq ("\033[A", _rl_keymap, (int *)NULL); - if (!f || f == rl_do_lowercase_version) - { - _rl_bind_if_unbound ("\033[A", rl_get_previous_history); - _rl_bind_if_unbound ("\033[B", rl_get_next_history); - _rl_bind_if_unbound ("\033[C", rl_forward); - _rl_bind_if_unbound ("\033[D", rl_backward); - } - - f = rl_function_of_keyseq ("\033OA", _rl_keymap, (int *)NULL); - if (!f || f == rl_do_lowercase_version) - { - _rl_bind_if_unbound ("\033OA", rl_get_previous_history); - _rl_bind_if_unbound ("\033OB", rl_get_next_history); - _rl_bind_if_unbound ("\033OC", rl_forward); - _rl_bind_if_unbound ("\033OD", rl_backward); - } -} - -/* Try and bind the common arrow key prefix after giving termcap and - the inputrc file a chance to bind them and create `real' keymaps - for the arrow key prefix. */ -static void -bind_arrow_keys () +bind_arrow_keys_internal (map) + Keymap map; { Keymap xkeymap; xkeymap = _rl_keymap; + _rl_keymap = map; - _rl_keymap = emacs_standard_keymap; - bind_arrow_keys_internal (); - -#if defined (VI_MODE) - _rl_keymap = vi_movement_keymap; - bind_arrow_keys_internal (); -#endif - - _rl_keymap = xkeymap; -} - - -/* **************************************************************** */ -/* */ -/* Numeric Arguments */ -/* */ -/* **************************************************************** */ - -/* Handle C-u style numeric args, as well as M--, and M-digits. */ -static int -rl_digit_loop () -{ - int key, c, sawminus, sawdigits; - - rl_save_prompt (); - - RL_SETSTATE(RL_STATE_NUMERICARG); - sawminus = sawdigits = 0; - while (1) - { - if (rl_numeric_arg > 1000000) - { - sawdigits = rl_explicit_arg = rl_numeric_arg = 0; - rl_ding (); - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return 1; - } - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - RL_SETSTATE(RL_STATE_MOREINPUT); - key = c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - { - _rl_abort_internal (); - return -1; - } - - /* If we see a key bound to `universal-argument' after seeing digits, - it ends the argument but is otherwise ignored. */ - if (_rl_keymap[c].type == ISFUNC && - _rl_keymap[c].function == rl_universal_argument) - { - if (sawdigits == 0) - { - rl_numeric_arg *= 4; - continue; - } - else - { - RL_SETSTATE(RL_STATE_MOREINPUT); - key = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (_rl_dispatch (key, _rl_keymap)); - } - } - - c = UNMETA (c); - - if (_rl_digit_p (c)) - { - rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; - sawdigits = rl_explicit_arg = 1; - } - else if (c == '-' && rl_explicit_arg == 0) - { - rl_numeric_arg = sawminus = 1; - rl_arg_sign = -1; - } - else - { - /* Make M-- command equivalent to M--1 command. */ - if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) - rl_explicit_arg = 1; - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (_rl_dispatch (key, _rl_keymap)); - } - } - - /*NOTREACHED*/ -} - -/* Add the current digit to the argument in progress. */ -int -rl_digit_argument (ignore, key) - int ignore, key; -{ - rl_execute_next (key); - return (rl_digit_loop ()); -} - -/* What to do when you abort reading an argument. */ -int -rl_discard_argument () -{ - rl_ding (); - rl_clear_message (); - _rl_init_argument (); - return 0; -} - -/* Create a default argument. */ -int -_rl_init_argument () -{ - rl_numeric_arg = rl_arg_sign = 1; - rl_explicit_arg = 0; - return 0; -} - -/* C-u, universal argument. Multiply the current argument by 4. - Read a key. If the key has nothing to do with arguments, then - dispatch on it. If the key is the abort character then abort. */ -int -rl_universal_argument (count, key) - int count, key; -{ - rl_numeric_arg *= 4; - return (rl_digit_loop ()); -} - -/* **************************************************************** */ -/* */ -/* Insert and Delete */ -/* */ -/* **************************************************************** */ - -/* Insert a string of text into the line at point. This is the only - way that you should do insertion. rl_insert () calls this - function. */ -int -rl_insert_text (string) - const char *string; -{ - register int i, l = strlen (string); - - if (rl_end + l >= rl_line_buffer_len) - rl_extend_line_buffer (rl_end + l); - - for (i = rl_end; i >= rl_point; i--) - the_line[i + l] = the_line[i]; - strncpy (the_line + rl_point, string, l); - - /* Remember how to undo this if we aren't undoing something. */ - if (!_rl_doing_an_undo) - { - /* If possible and desirable, concatenate the undos. */ - if ((l == 1) && - rl_undo_list && - (rl_undo_list->what == UNDO_INSERT) && - (rl_undo_list->end == rl_point) && - (rl_undo_list->end - rl_undo_list->start < 20)) - rl_undo_list->end++; - else - rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); - } - rl_point += l; - rl_end += l; - the_line[rl_end] = '\0'; - return l; -} - -/* Delete the string between FROM and TO. FROM is - inclusive, TO is not. */ -int -rl_delete_text (from, to) - int from, to; -{ - register char *text; - register int diff, i; - - /* Fix it if the caller is confused. */ - if (from > to) - SWAP (from, to); - - /* fix boundaries */ - if (to > rl_end) - { - to = rl_end; - if (from > to) - from = to; - } - - text = rl_copy_text (from, to); - - /* Some versions of strncpy() can't handle overlapping arguments. */ - diff = to - from; - for (i = from; i < rl_end - diff; i++) - the_line[i] = the_line[i + diff]; - - /* Remember how to undo this delete. */ - if (_rl_doing_an_undo == 0) - rl_add_undo (UNDO_DELETE, from, to, text); - else - free (text); - - rl_end -= diff; - the_line[rl_end] = '\0'; - return (diff); -} - -/* Fix up point so that it is within the line boundaries after killing - text. If FIX_MARK_TOO is non-zero, the mark is forced within line - boundaries also. */ - -#define _RL_FIX_POINT(x) \ - do { \ - if (x > rl_end) \ - x = rl_end; \ - else if (x < 0) \ - x = 0; \ - } while (0) - -void -_rl_fix_point (fix_mark_too) - int fix_mark_too; -{ - _RL_FIX_POINT (rl_point); - if (fix_mark_too) - _RL_FIX_POINT (rl_mark); -} -#undef _RL_FIX_POINT - -void -_rl_replace_text (text, start, end) - const char *text; - int start, end; -{ - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - rl_insert_text (text); - rl_end_undo_group (); -} - -/* **************************************************************** */ -/* */ -/* Readline character functions */ -/* */ -/* **************************************************************** */ - -/* This is not a gap editor, just a stupid line input routine. No hair - is involved in writing any of the functions, and none should be. */ - -/* Note that: - - rl_end is the place in the string that we would place '\0'; - i.e., it is always safe to place '\0' there. - - rl_point is the place in the string where the cursor is. Sometimes - this is the same as rl_end. - - Any command that is called interactively receives two arguments. - The first is a count: the numeric arg pased to this command. - The second is the key which invoked this command. -*/ - -/* **************************************************************** */ -/* */ -/* Movement Commands */ -/* */ -/* **************************************************************** */ - -/* Note that if you `optimize' the display for these functions, you cannot - use said functions in other functions which do not do optimizing display. - I.e., you will have to update the data base for rl_redisplay, and you - might as well let rl_redisplay do that job. */ - -/* Move forward COUNT characters. */ -int -rl_forward (count, key) - int count, key; -{ - if (count < 0) - rl_backward (-count, key); - else if (count > 0) - { - int end = rl_point + count; -#if defined (VI_MODE) - int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end; -#else - int lend = rl_end; -#endif - - if (end > lend) - { - rl_point = lend; - rl_ding (); - } - else - rl_point = end; - } - - if (rl_end < 0) - rl_end = 0; - - return 0; -} - -/* Move backward COUNT characters. */ -int -rl_backward (count, key) - int count, key; -{ - if (count < 0) - rl_forward (-count, key); - else if (count > 0) - { - if (rl_point < count) - { - rl_point = 0; - rl_ding (); - } - else - rl_point -= count; - } - - if (rl_point < 0) - rl_point = 0; - - return 0; -} - -/* Move to the beginning of the line. */ -int -rl_beg_of_line (count, key) - int count, key; -{ - rl_point = 0; - return 0; -} - -/* Move to the end of the line. */ -int -rl_end_of_line (count, key) - int count, key; -{ - rl_point = rl_end; - return 0; -} - -/* Move forward a word. We do what Emacs does. */ -int -rl_forward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - { - rl_backward_word (-count, key); - return 0; - } - - while (count) - { - if (rl_point == rl_end) - return 0; - - /* If we are not in a word, move forward until we are in one. - Then, move forward until we hit a non-alphabetic character. */ - c = the_line[rl_point]; - if (rl_alphabetic (c) == 0) - { - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (rl_alphabetic (c)) - break; - } - } - if (rl_point == rl_end) - return 0; - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (rl_alphabetic (c) == 0) - break; - } - --count; - } - return 0; -} - -/* Move backward a word. We do what Emacs does. */ -int -rl_backward_word (count, key) - int count, key; -{ - int c; - - if (count < 0) - { - rl_forward_word (-count, key); - return 0; - } - - while (count) - { - if (!rl_point) - return 0; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - c = the_line[rl_point - 1]; - if (rl_alphabetic (c) == 0) - { - while (--rl_point) - { - c = the_line[rl_point - 1]; - if (rl_alphabetic (c)) - break; - } - } - - while (rl_point) - { - c = the_line[rl_point - 1]; - if (rl_alphabetic (c) == 0) - break; - else - --rl_point; - } - --count; - } - return 0; -} - -/* Clear the current line. Numeric argument to C-l does this. */ -int -rl_refresh_line (ignore1, ignore2) - int ignore1, ignore2; -{ - int curr_line; - - curr_line = _rl_current_display_line (); - - _rl_move_vert (curr_line); - _rl_move_cursor_relative (0, the_line); /* XXX is this right */ - - _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ - - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -/* C-l typed to a line without quoting clears the screen, and then reprints - the prompt and the current input line. Given a numeric arg, redraw only - the current line. */ -int -rl_clear_screen (count, key) - int count, key; -{ - if (rl_explicit_arg) - { - rl_refresh_line (count, key); - return 0; - } - - _rl_clear_screen (); /* calls termcap function to clear screen */ - rl_forced_update_display (); - rl_display_fixed = 1; - - return 0; -} - -int -rl_arrow_keys (count, c) - int count, c; -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - switch (_rl_to_upper (ch)) - { - case 'A': - rl_get_previous_history (count, ch); - break; - - case 'B': - rl_get_next_history (count, ch); - break; - - case 'C': - rl_forward (count, ch); - break; - - case 'D': - rl_backward (count, ch); - break; - - default: - rl_ding (); - } - return 0; -} - - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -/* Insert the character C at the current location, moving point forward. */ -int -rl_insert (count, c) - int count, c; -{ - register int i; - char *string; - - if (count <= 0) - return 0; - - /* If we can optimize, then do it. But don't let people crash - readline because of extra large arguments. */ - if (count > 1 && count <= 1024) - { - string = (char *)xmalloc (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; - - string[i] = '\0'; - rl_insert_text (string); - free (string); - - return 0; - } - - if (count > 1024) - { - int decreaser; - char str[1024+1]; - - for (i = 0; i < 1024; i++) - str[i] = c; - - while (count) - { - decreaser = (count > 1024 ? 1024 : count); - str[decreaser] = '\0'; - rl_insert_text (str); - count -= decreaser; - } - - return 0; - } - - /* We are inserting a single character. - If there is pending input, then make a string of all of the - pending characters that are bound to rl_insert, and insert - them all. */ - if (_rl_any_typein ()) - _rl_insert_typein (c); - else - { - /* Inserting a single character. */ - char str[2]; - - str[1] = '\0'; - str[0] = c; - rl_insert_text (str); - } - return 0; -} - -/* Insert the next typed character verbatim. */ -int -rl_quoted_insert (count, key) - int count, key; -{ - int c; - -#if defined (HANDLE_SIGNALS) - _rl_disable_tty_signals (); +#if defined (__MSDOS__) + _rl_bind_if_unbound ("\033[0A", rl_get_previous_history); + _rl_bind_if_unbound ("\033[0B", rl_backward_char); + _rl_bind_if_unbound ("\033[0C", rl_forward_char); + _rl_bind_if_unbound ("\033[0D", rl_get_next_history); #endif - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); + _rl_bind_if_unbound ("\033[A", rl_get_previous_history); + _rl_bind_if_unbound ("\033[B", rl_get_next_history); + _rl_bind_if_unbound ("\033[C", rl_forward_char); + _rl_bind_if_unbound ("\033[D", rl_backward_char); + _rl_bind_if_unbound ("\033[H", rl_beg_of_line); + _rl_bind_if_unbound ("\033[F", rl_end_of_line); -#if defined (HANDLE_SIGNALS) - _rl_restore_tty_signals (); -#endif + _rl_bind_if_unbound ("\033OA", rl_get_previous_history); + _rl_bind_if_unbound ("\033OB", rl_get_next_history); + _rl_bind_if_unbound ("\033OC", rl_forward_char); + _rl_bind_if_unbound ("\033OD", rl_backward_char); + _rl_bind_if_unbound ("\033OH", rl_beg_of_line); + _rl_bind_if_unbound ("\033OF", rl_end_of_line); - return (rl_insert (count, c)); -} - -/* Insert a tab character. */ -int -rl_tab_insert (count, key) - int count, key; -{ - return (rl_insert (count, '\t')); + _rl_keymap = xkeymap; } -/* What to do when a NEWLINE is pressed. We accept the whole line. - KEY is the key that invoked this command. I guess it could have - meaning in the future. */ -int -rl_newline (count, key) - int count, key; +/* Try and bind the common arrow key prefixes after giving termcap and + the inputrc file a chance to bind them and create `real' keymaps + for the arrow key prefix. */ +static void +bind_arrow_keys () { - rl_done = 1; - - if (_rl_history_preserve_point) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - RL_SETSTATE(RL_STATE_DONE); + bind_arrow_keys_internal (emacs_standard_keymap); #if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - { - _rl_vi_done_inserting (); - _rl_vi_reset_last (); - } -#endif /* VI_MODE */ - - /* If we've been asked to erase empty lines, suppress the final update, - since _rl_update_final calls rl_crlf(). */ - if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) - return 0; - - if (readline_echoing_p) - _rl_update_final (); - return 0; -} - -/* What to do for some uppercase characters, like meta characters, - and some characters appearing in emacs_ctlx_keymap. This function - is just a stub, you bind keys to it and the code in _rl_dispatch () - is special cased. */ -int -rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; -{ - return 0; -} - -/* Rubout the character behind point. */ -int -rl_rubout (count, key) - int count, key; -{ - if (count < 0) - { - rl_delete (-count, key); - return 0; - } - - if (!rl_point) - { - rl_ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - int orig_point = rl_point; - rl_backward (count, key); - rl_kill_text (orig_point, rl_point); - } - else - { - unsigned char c = the_line[--rl_point]; - rl_delete_text (rl_point, rl_point + 1); - - if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos) - { - int l; - l = rl_character_len (c, rl_point); - _rl_erase_at_end_of_line (l); - } - } - return 0; -} - -/* Delete the character under the cursor. Given a numeric argument, - kill that many characters instead. */ -int -rl_delete (count, key) - int count, key; -{ - if (count < 0) - return (rl_rubout (-count, key)); - - if (rl_point == rl_end) - { - rl_ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - int orig_point = rl_point; - rl_forward (count, key); - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - return 0; - } - else - return (rl_delete_text (rl_point, rl_point + 1)); -} - -/* Delete the character under the cursor, unless the insertion - point is at the end of the line, in which case the character - behind the cursor is deleted. COUNT is obeyed and may be used - to delete forward or backward that many characters. */ -int -rl_rubout_or_delete (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_rubout (count, key)); - else - return (rl_delete (count, key)); -} - -/* Delete all spaces and tabs around point. */ -int -rl_delete_horizontal_space (count, ignore) - int count, ignore; -{ - int start = rl_point; - - while (rl_point && whitespace (the_line[rl_point - 1])) - rl_point--; - - start = rl_point; - - while (rl_point < rl_end && whitespace (the_line[rl_point])) - rl_point++; - - if (start != rl_point) - { - rl_delete_text (start, rl_point); - rl_point = start; - } - return 0; -} - -/* Like the tcsh editing function delete-char-or-list. The eof character - is caught before this is invoked, so this really does the same thing as - delete-char-or-list-or-eof, as long as it's bound to the eof character. */ -int -rl_delete_or_show_completions (count, key) - int count, key; -{ - if (rl_end != 0 && rl_point == rl_end) - return (rl_possible_completions (count, key)); - else - return (rl_delete (count, key)); -} - -#ifndef RL_COMMENT_BEGIN_DEFAULT -#define RL_COMMENT_BEGIN_DEFAULT "#" + bind_arrow_keys_internal (vi_movement_keymap); + bind_arrow_keys_internal (vi_insertion_keymap); #endif - -/* Turn the current line into a comment in shell history. - A K*rn shell style function. */ -int -rl_insert_comment (count, key) - int count, key; -{ - rl_beg_of_line (1, key); - rl_insert_text (_rl_comment_begin ? _rl_comment_begin - : RL_COMMENT_BEGIN_DEFAULT); - (*rl_redisplay_function) (); - rl_newline (1, '\n'); - return (0); } /* **************************************************************** */ /* */ -/* Changing Case */ -/* */ -/* **************************************************************** */ - -/* The three kinds of things that we know how to do. */ -#define UpCase 1 -#define DownCase 2 -#define CapCase 3 - -/* Uppercase the word at point. */ -int -rl_upcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, UpCase)); -} - -/* Lowercase the word at point. */ -int -rl_downcase_word (count, key) - int count, key; -{ - return (rl_change_case (count, DownCase)); -} - -/* Upcase the first letter, downcase the rest. */ -int -rl_capitalize_word (count, key) - int count, key; -{ - return (rl_change_case (count, CapCase)); -} - -/* The meaty function. - Change the case of COUNT words, performing OP on them. - OP is one of UpCase, DownCase, or CapCase. - If a negative argument is given, leave point where it started, - otherwise, leave it where it moves to. */ -static int -rl_change_case (count, op) - int count, op; -{ - register int start, end; - int inword, c; - - start = rl_point; - rl_forward_word (count, 0); - end = rl_point; - - if (count < 0) - SWAP (start, end); - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - for (inword = 0; start < end; start++) - { - c = the_line[start]; - switch (op) - { - case UpCase: - the_line[start] = _rl_to_upper (c); - break; - - case DownCase: - the_line[start] = _rl_to_lower (c); - break; - - case CapCase: - the_line[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c); - inword = rl_alphabetic (the_line[start]); - break; - - default: - rl_ding (); - return -1; - } - } - rl_point = end; - return 0; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. If point is at the end of the line, - transpose the two words before point. */ -int -rl_transpose_words (count, key) - int count, key; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) - return 0; - - /* Find the two words. */ - rl_forward_word (count, key); - w2_end = rl_point; - rl_backward_word (1, key); - w2_beg = rl_point; - rl_backward_word (count, key); - w1_beg = rl_point; - rl_forward_word (1, key); - w1_end = rl_point; - - /* Do some check to make sure that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - rl_ding (); - rl_point = orig_point; - return -1; - } - - /* Get the text of the words. */ - word1 = rl_copy_text (w1_beg, w1_end); - word2 = rl_copy_text (w2_beg, w2_end); - - /* We are about to do many insertions and deletions. Remember them - as one operation. */ - rl_begin_undo_group (); - - /* Do the stuff at word2 first, so that we don't have to worry - about word1 moving. */ - rl_point = w2_beg; - rl_delete_text (w2_beg, w2_end); - rl_insert_text (word1); - - rl_point = w1_beg; - rl_delete_text (w1_beg, w1_end); - rl_insert_text (word2); - - /* This is exactly correct since the text before this point has not - changed in length. */ - rl_point = w2_end; - - /* I think that does it. */ - rl_end_undo_group (); - free (word1); - free (word2); - - return 0; -} - -/* Transpose the characters at point. If point is at the end of the line, - then transpose the characters before point. */ -int -rl_transpose_chars (count, key) - int count, key; -{ - char dummy[2]; - - if (!count) - return 0; - - if (!rl_point || rl_end < 2) - { - rl_ding (); - return -1; - } - - rl_begin_undo_group (); - - if (rl_point == rl_end) - { - --rl_point; - count = 1; - } - rl_point--; - - dummy[0] = the_line[rl_point]; - dummy[1] = '\0'; - - rl_delete_text (rl_point, rl_point + 1); - - rl_point += count; - _rl_fix_point (0); - rl_insert_text (dummy); - - rl_end_undo_group (); - return 0; -} - -/* **************************************************************** */ -/* */ -/* Character Searching */ +/* Saving and Restoring Readline's state */ /* */ /* **************************************************************** */ int -_rl_char_search_internal (count, dir, schar) - int count, dir, schar; +rl_save_state (sp) + struct readline_state *sp; { - int pos, inc; + if (sp == 0) + return -1; - pos = rl_point; - inc = (dir < 0) ? -1 : 1; - while (count) - { - if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) - { - rl_ding (); - return -1; - } + sp->point = rl_point; + sp->end = rl_end; + sp->mark = rl_mark; + sp->buffer = rl_line_buffer; + sp->buflen = rl_line_buffer_len; + sp->ul = rl_undo_list; + sp->prompt = rl_prompt; + + sp->rlstate = rl_readline_state; + sp->done = rl_done; + sp->kmap = _rl_keymap; + + sp->lastfunc = rl_last_func; + sp->insmode = rl_insert_mode; + sp->edmode = rl_editing_mode; + sp->kseqlen = rl_key_sequence_length; + sp->inf = rl_instream; + sp->outf = rl_outstream; + sp->pendingin = rl_pending_input; + sp->macro = rl_executing_macro; + + sp->catchsigs = rl_catch_signals; + sp->catchsigwinch = rl_catch_sigwinch; - pos += inc; - do - { - if (rl_line_buffer[pos] == schar) - { - count--; - if (dir < 0) - rl_point = (dir == BTO) ? pos + 1 : pos; - else - rl_point = (dir == FTO) ? pos - 1 : pos; - break; - } - } - while ((dir < 0) ? pos-- : ++pos < rl_end); - } return (0); } -/* Search COUNT times for a character read from the current input stream. - FDIR is the direction to search if COUNT is non-negative; otherwise - the search goes in BDIR. */ -static int -_rl_char_search (count, fdir, bdir) - int count, fdir, bdir; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, c)); - else - return (_rl_char_search_internal (count, fdir, c)); -} - -int -rl_char_search (count, key) - int count, key; -{ - return (_rl_char_search (count, FFIND, BFIND)); -} - int -rl_backward_char_search (count, key) - int count, key; +rl_restore_state (sp) + struct readline_state *sp; { - return (_rl_char_search (count, BFIND, FFIND)); -} - -/* **************************************************************** */ -/* */ -/* History Utilities */ -/* */ -/* **************************************************************** */ - -/* We already have a history library, and that is what we use to control - the history features of readline. This is our local interface to - the history mechanism. */ - -/* While we are editing the history, this is the saved - version of the original line. */ -HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL; - -/* Set the history pointer back to the last entry in the history. */ -static void -start_using_history () -{ - using_history (); - if (_rl_saved_line_for_history) - _rl_free_history_entry (_rl_saved_line_for_history); - - _rl_saved_line_for_history = (HIST_ENTRY *)NULL; -} - -/* Free the contents (and containing structure) of a HIST_ENTRY. */ -void -_rl_free_history_entry (entry) - HIST_ENTRY *entry; -{ - if (entry == 0) - return; - if (entry->line) - free (entry->line); - free (entry); -} - -/* Perhaps put back the current line if it has changed. */ -int -rl_maybe_replace_line () -{ - HIST_ENTRY *temp; - - temp = current_history (); - /* If the current line has changed, save the changes. */ - if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) - { - temp = replace_history_entry (where_history (), the_line, (histdata_t)rl_undo_list); - free (temp->line); - free (temp); - } - return 0; -} - -/* Restore the _rl_saved_line_for_history if there is one. */ -int -rl_maybe_unsave_line () -{ - int line_len; - - if (_rl_saved_line_for_history) - { - line_len = strlen (_rl_saved_line_for_history->line); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (the_line, _rl_saved_line_for_history->line); - rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; - _rl_free_history_entry (_rl_saved_line_for_history); - _rl_saved_line_for_history = (HIST_ENTRY *)NULL; - rl_end = rl_point = strlen (the_line); - } - else - rl_ding (); - return 0; -} - -/* Save the current line in _rl_saved_line_for_history. */ -int -rl_maybe_save_line () -{ - if (_rl_saved_line_for_history == 0) - { - _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - _rl_saved_line_for_history->line = savestring (the_line); - _rl_saved_line_for_history->data = (char *)rl_undo_list; - } - return 0; -} - -int -_rl_free_saved_history_line () -{ - if (_rl_saved_line_for_history) - { - _rl_free_history_entry (_rl_saved_line_for_history); - _rl_saved_line_for_history = (HIST_ENTRY *)NULL; - } - return 0; -} - -/* **************************************************************** */ -/* */ -/* History Commands */ -/* */ -/* **************************************************************** */ - -/* Meta-< goes to the start of the history. */ -int -rl_beginning_of_history (count, key) - int count, key; -{ - return (rl_get_previous_history (1 + where_history (), key)); -} - -/* Meta-> goes to the end of the history. (The current line). */ -int -rl_end_of_history (count, key) - int count, key; -{ - rl_maybe_replace_line (); - using_history (); - rl_maybe_unsave_line (); - return 0; -} - -/* Move down to the next history line. */ -int -rl_get_next_history (count, key) - int count, key; -{ - HIST_ENTRY *temp; - int line_len; - - if (count < 0) - return (rl_get_previous_history (-count, key)); - - if (count == 0) - return 0; - - rl_maybe_replace_line (); - - /* either not saved by rl_newline or at end of line, so set appropriately. */ - if (_rl_history_saved_point == -1 && (rl_point || rl_end)) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - temp = (HIST_ENTRY *)NULL; - while (count) - { - temp = next_history (); - if (!temp) - break; - --count; - } - - if (temp == 0) - rl_maybe_unsave_line (); - else - { - line_len = strlen (temp->line); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = strlen (the_line); - rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) - ? _rl_history_saved_point - : rl_end; - if (rl_point > rl_end) - rl_point = rl_end; -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_point = 0; -#endif /* VI_MODE */ - } - return 0; -} - -/* Get the previous item out of our interactive history, making it the current - line. If there is no previous history, just ding. */ -int -rl_get_previous_history (count, key) - int count, key; -{ - HIST_ENTRY *old_temp, *temp; - int line_len; - - if (count < 0) - return (rl_get_next_history (-count, key)); - - if (count == 0) - return 0; - - /* either not saved by rl_newline or at end of line, so set appropriately. */ - if (_rl_history_saved_point == -1 && (rl_point || rl_end)) - _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; - - /* If we don't have a line saved, then save this one. */ - rl_maybe_save_line (); - - /* If the current line has changed, save the changes. */ - rl_maybe_replace_line (); - - temp = old_temp = (HIST_ENTRY *)NULL; - while (count) - { - temp = previous_history (); - if (temp == 0) - break; - - old_temp = temp; - --count; - } - - /* If there was a large argument, and we moved back to the start of the - history, that is not an error. So use the last value found. */ - if (!temp && old_temp) - temp = old_temp; - - if (temp == 0) - rl_ding (); - else - { - line_len = strlen (temp->line); - - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = line_len; - rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) - ? _rl_history_saved_point - : rl_end; - if (rl_point > rl_end) - rl_point = rl_end; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_point = 0; -#endif /* VI_MODE */ - } - return 0; -} - -/* **************************************************************** */ -/* */ -/* The Mark and the Region. */ -/* */ -/* **************************************************************** */ - -/* Set the mark at POSITION. */ -int -_rl_set_mark_at_pos (position) - int position; -{ - if (position > rl_end) + if (sp == 0) return -1; - rl_mark = position; - return 0; -} - -/* A bindable command to set the mark. */ -int -rl_set_mark (count, key) - int count, key; -{ - return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); -} - -/* Exchange the position of mark and point. */ -int -rl_exchange_point_and_mark (count, key) - int count, key; -{ - if (rl_mark > rl_end) - rl_mark = -1; - - if (rl_mark == -1) - { - rl_ding (); - return -1; - } - else - SWAP (rl_point, rl_mark); - - return 0; -} - -/* **************************************************************** */ -/* */ -/* Editing Modes */ -/* */ -/* **************************************************************** */ -/* How to toggle back and forth between editing modes. */ -int -rl_vi_editing_mode (count, key) - int count, key; -{ -#if defined (VI_MODE) - rl_editing_mode = vi_mode; - rl_vi_insertion_mode (1, key); -#endif /* VI_MODE */ - return 0; -} + rl_point = sp->point; + rl_end = sp->end; + rl_mark = sp->mark; + the_line = rl_line_buffer = sp->buffer; + rl_line_buffer_len = sp->buflen; + rl_undo_list = sp->ul; + rl_prompt = sp->prompt; + + rl_readline_state = sp->rlstate; + rl_done = sp->done; + _rl_keymap = sp->kmap; + + rl_last_func = sp->lastfunc; + rl_insert_mode = sp->insmode; + rl_editing_mode = sp->edmode; + rl_key_sequence_length = sp->kseqlen; + rl_instream = sp->inf; + rl_outstream = sp->outf; + rl_pending_input = sp->pendingin; + rl_executing_macro = sp->macro; + + rl_catch_signals = sp->catchsigs; + rl_catch_sigwinch = sp->catchsigwinch; -int -rl_emacs_editing_mode (count, key) - int count, key; -{ - rl_editing_mode = emacs_mode; - _rl_keymap = emacs_standard_keymap; - return 0; + return (0); } diff --git a/lib/readline/readline.h b/lib/readline/readline.h index d608c7ab..f11b3d03 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -29,18 +29,20 @@ extern "C" { #if defined (READLINE_LIBRARY) # include "rlstdc.h" +# include "rltypedefs.h" # include "keymaps.h" # include "tilde.h" #else # include <readline/rlstdc.h> +# include <readline/rltypedefs.h> # include <readline/keymaps.h> # include <readline/tilde.h> #endif /* Hex-encoded Readline version number. */ -#define RL_READLINE_VERSION 0x0402 /* Readline 4.2 */ +#define RL_READLINE_VERSION 0x0403 /* Readline 4.3 */ #define RL_VERSION_MAJOR 4 -#define RL_VERSION_MINOR 2 +#define RL_VERSION_MINOR 3 /* Readline data structures. */ @@ -82,7 +84,11 @@ extern int rl_digit_argument PARAMS((int, int)); extern int rl_universal_argument PARAMS((int, int)); /* Bindable commands for moving the cursor. */ +extern int rl_forward_byte PARAMS((int, int)); +extern int rl_forward_char PARAMS((int, int)); extern int rl_forward PARAMS((int, int)); +extern int rl_backward_byte PARAMS((int, int)); +extern int rl_backward_char PARAMS((int, int)); extern int rl_backward PARAMS((int, int)); extern int rl_beg_of_line PARAMS((int, int)); extern int rl_end_of_line PARAMS((int, int)); @@ -132,6 +138,9 @@ extern int rl_exchange_point_and_mark PARAMS((int, int)); extern int rl_vi_editing_mode PARAMS((int, int)); extern int rl_emacs_editing_mode PARAMS((int, int)); +/* Bindable commands to change the insert mode (insert or overwrite) */ +extern int rl_overwrite_mode PARAMS((int, int)); + /* Bindable commands for managing key bindings. */ extern int rl_re_read_init_file PARAMS((int, int)); extern int rl_dump_functions PARAMS((int, int)); @@ -365,6 +374,7 @@ extern void rl_save_prompt PARAMS((void)); extern void rl_restore_prompt PARAMS((void)); /* Modifying text. */ +extern void rl_replace_line PARAMS((const char *, int)); extern int rl_insert_text PARAMS((const char *)); extern int rl_delete_text PARAMS((int, int)); extern int rl_kill_text PARAMS((int, int)); @@ -417,6 +427,8 @@ extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *) extern char *rl_username_completion_function PARAMS((const char *, int)); extern char *rl_filename_completion_function PARAMS((const char *, int)); +extern int rl_completion_mode PARAMS((rl_command_func_t *)); + #if 0 /* Backwards compatibility (compat.c). These will go away sometime. */ extern void free_undo_list PARAMS((void)); @@ -453,6 +465,10 @@ extern int rl_readline_state; 0 means vi mode. */ extern int rl_editing_mode; +/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means + overwrite mode. Reset to insert mode on each input line. */ +extern int rl_insert_mode; + /* The name of the calling program. You should initialize this to whatever was in argv[0]. It is used when parsing conditionals. */ extern const char *rl_readline_name; @@ -675,18 +691,33 @@ extern int rl_completion_type; default is a space. Nothing is added if this is '\0'. */ extern int rl_completion_append_character; +/* If set to non-zero by an application completion function, + rl_completion_append_character will not be appended. */ +extern int rl_completion_suppress_append; + /* Up to this many items will be displayed in response to a possible-completions call. After that, we ask the user if she is sure she wants to see them all. The default value is 100. */ extern int rl_completion_query_items; +/* If non-zero, a slash will be appended to completed filenames that are + symbolic links to directory names, subject to the value of the + mark-directories variable (which is user-settable). This exists so + that application completion functions can override the user's preference + (set via the mark-symlinked-directories variable) if appropriate. + It's set to the value of _rl_complete_mark_symlink_dirs in + rl_complete_internal before any application-specific completion + function is called, so without that function doing anything, the user's + preferences are honored. */ +extern int rl_completion_mark_symlink_dirs; + /* If non-zero, then disallow duplicates in the matches. */ extern int rl_ignore_completion_duplicates; /* If this is non-zero, completion is (temporarily) inhibited, and the completion character will be inserted as any other. */ extern int rl_inhibit_completion; - + /* Definitions available for use by readline clients. */ #define RL_PROMPT_START_IGNORE '\001' #define RL_PROMPT_END_IGNORE '\002' @@ -725,6 +756,42 @@ extern int rl_inhibit_completion; #define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) #define RL_ISSTATE(x) (rl_readline_state & (x)) +struct readline_state { + /* line state */ + int point; + int end; + int mark; + char *buffer; + int buflen; + UNDO_LIST *ul; + char *prompt; + + /* global state */ + int rlstate; + int done; + Keymap kmap; + + /* input state */ + rl_command_func_t *lastfunc; + int insmode; + int edmode; + int kseqlen; + FILE *inf; + FILE *outf; + int pendingin; + char *macro; + + /* signal state */ + int catchsigs; + int catchsigwinch; + + /* reserved for future expansion, so the struct size doesn't change */ + char reserved[64]; +}; + +extern int rl_save_state PARAMS((struct readline_state *)); +extern int rl_restore_state PARAMS((struct readline_state *)); + #ifdef __cplusplus } #endif diff --git a/lib/readline/rlconf.h b/lib/readline/rlconf.h index d2ab7040..c651fd8b 100644 --- a/lib/readline/rlconf.h +++ b/lib/readline/rlconf.h @@ -54,4 +54,7 @@ X `callback' style. */ #define READLINE_CALLBACKS +/* Define this if you want the cursor to indicate insert or overwrite mode. */ +/* #define CURSOR_MODE */ + #endif /* _RLCONF_H_ */ diff --git a/lib/readline/rldefs.h b/lib/readline/rldefs.h index bd055e3b..4a28bd1e 100644 --- a/lib/readline/rldefs.h +++ b/lib/readline/rldefs.h @@ -74,7 +74,7 @@ extern char *strchr (), *strrchr (); #define _rl_strnicmp strncasecmp #else extern int _rl_stricmp PARAMS((char *, char *)); -extern int _rl_strnicmp PARAMS((char *, char *)); +extern int _rl_strnicmp PARAMS((char *, char *, int)); #endif #if defined (HAVE_STRPBRK) @@ -89,6 +89,13 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *)); # define emacs_mode 1 #endif +#if !defined (RL_IM_INSERT) +# define RL_IM_INSERT 1 +# define RL_IM_OVERWRITE 0 +# +# define RL_IM_DEFAULT RL_IM_INSERT +#endif + /* If you cast map[key].function to type (Keymap) on a Cray, the compiler takes the value of map[key].function and divides it by 4 to convert between pointer types (pointers @@ -121,9 +128,10 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *)); /* Possible values for the found_quote flags word used by the completion functions. It says what kind of (shell-like) quoting we found anywhere in the line. */ -#define RL_QF_SINGLE_QUOTE 0x1 -#define RL_QF_DOUBLE_QUOTE 0x2 -#define RL_QF_BACKSLASH 0x4 +#define RL_QF_SINGLE_QUOTE 0x01 +#define RL_QF_DOUBLE_QUOTE 0x02 +#define RL_QF_BACKSLASH 0x04 +#define RL_QF_OTHER_QUOTE 0x08 /* Default readline line buffer length. */ #define DEFAULT_BUFFER_SIZE 256 @@ -138,6 +146,10 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *)); # define FREE(x) if (x) free (x) #endif +#if !defined (SWAP) +# define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) +#endif + /* CONFIGURATION SECTION */ #include "rlconf.h" diff --git a/lib/readline/rlmbutil.h b/lib/readline/rlmbutil.h new file mode 100644 index 00000000..27ca32bf --- /dev/null +++ b/lib/readline/rlmbutil.h @@ -0,0 +1,108 @@ +/* rlmbutil.h -- utility functions for multibyte characters. */ + +/* Copyright (C) 2001 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_MBUTIL_H_) +#define _RL_MBUTIL_H_ + +#include "rlstdc.h" + +/************************************************/ +/* check multibyte capability for I18N code */ +/************************************************/ + +/* For platforms which support the ISO C amendement 1 functionality we + support user defined character classes. */ + /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ +#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) +# include <wchar.h> +# include <wctype.h> +# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */ +# define HANDLE_MULTIBYTE 1 +# endif +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) +# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) +# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) +# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) +# define mbstate_t int +#endif + +/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to + handle multibyte chars (some systems define MB_LEN_MAX as 1) */ +#ifdef HANDLE_MULTIBYTE +# include <limits.h> +# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) +# undef MB_LEN_MAX +# endif +# if !defined (MB_LEN_MAX) +# define MB_LEN_MAX 16 +# endif +#endif + +/************************************************/ +/* end of multibyte capability checks for I18N */ +/************************************************/ + +/* + * Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar: + * + * MB_FIND_ANY find any multibyte character + * MB_FIND_NONZERO find a non-zero-width multibyte character + */ + +#define MB_FIND_ANY 0x00 +#define MB_FIND_NONZERO 0x01 + +extern int _rl_find_prev_mbchar PARAMS((char *, int, int)); +extern int _rl_find_next_mbchar PARAMS((char *, int, int, int)); + +#ifdef HANDLE_MULTIBYTE + +extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *)); +extern int _rl_get_char_len PARAMS((char *, mbstate_t *)); +extern int _rl_adjust_point PARAMS((char *, int, mbstate_t *)); + +extern int _rl_read_mbchar PARAMS((char *, int)); +extern int _rl_read_mbstring PARAMS((int, char *, int)); + +extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int)); + +#else /* !HANDLE_MULTIBYTE */ + +#undef MB_LEN_MAX +#undef MB_CUR_MAX + +#define MB_LEN_MAX 1 +#define MB_CUR_MAX 1 + +#define _rl_find_prev_mbchar(b, i, f) (((i) == 0) ? (i) : ((i) - 1)) +#define _rl_find_next_mbchar(b, i1, i2, f) ((i1) + (i2)) + +#endif /* !HANDLE_MULTIBYTE */ + +extern int rl_byte_oriented; + +#endif /* _RL_MBUTIL_H_ */ diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 9347b361..ccb91446 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -52,6 +52,7 @@ extern int rl_arg_sign; extern int rl_visible_prompt_length; extern int readline_echoing_p; extern int rl_key_sequence_length; +extern int rl_byte_oriented; /* display.c */ extern int rl_display_fixed; @@ -65,18 +66,9 @@ extern int rl_blink_matching_paren; * * *************************************************************************/ -/* bind.c */ -extern char *rl_untranslate_keyseq PARAMS((int)); - /* kill.c */ extern int rl_set_retained_kills PARAMS((int)); -/* readline.c */ -extern int rl_discard_argument PARAMS((void)); - -/* rltty.c */ -extern int rl_stop_output PARAMS((int, int)); - /* terminal.c */ extern void _rl_set_screen_size PARAMS((int, int)); @@ -113,6 +105,10 @@ extern int readline_internal_char PARAMS((void)); /* bind.c */ extern void _rl_bind_if_unbound PARAMS((const char *, rl_command_func_t *)); +/* complete.c */ +extern char _rl_find_completion_word PARAMS((int *, int *)); +extern void _rl_free_match_list PARAMS((char **)); + /* display.c */ extern char *_rl_strip_prompt PARAMS((char *)); extern void _rl_move_cursor_relative PARAMS((int, const char *)); @@ -132,7 +128,9 @@ extern int _rl_current_display_line PARAMS((void)); /* input.c */ extern int _rl_any_typein PARAMS((void)); extern int _rl_input_available PARAMS((void)); +extern int _rl_input_queued PARAMS((int)); extern void _rl_insert_typein PARAMS((int)); +extern int _rl_unget_char PARAMS((int)); /* macro.c */ extern void _rl_with_macro_input PARAMS((char *)); @@ -142,6 +140,12 @@ extern void _rl_pop_executing_macro PARAMS((void)); extern void _rl_add_macro_char PARAMS((int)); extern void _rl_kill_kbd_macro PARAMS((void)); +/* misc.c */ +extern int _rl_init_argument PARAMS((void)); +extern void _rl_start_using_history PARAMS((void)); +extern int _rl_free_saved_history_line PARAMS((void)); +extern void _rl_set_insert_mode PARAMS((int, int)); + /* nls.c */ extern int _rl_init_eightbit PARAMS((void)); @@ -152,12 +156,7 @@ extern void _rl_enable_paren_matching PARAMS((int)); extern void _rl_init_line_state PARAMS((void)); extern void _rl_set_the_line PARAMS((void)); extern int _rl_dispatch PARAMS((int, Keymap)); -extern int _rl_init_argument PARAMS((void)); -extern void _rl_fix_point PARAMS((int)); -extern void _rl_replace_text PARAMS((const char *, int, int)); -extern int _rl_char_search_internal PARAMS((int, int, int)); -extern int _rl_set_mark_at_pos PARAMS((int)); -extern int _rl_free_saved_history_line PARAMS((void)); +extern int _rl_dispatch_subseq PARAMS((int, Keymap, int)); /* rltty.c */ extern int _rl_disable_tty_signals PARAMS((void)); @@ -175,9 +174,23 @@ extern void _rl_output_some_chars PARAMS((const char *, int)); extern int _rl_backspace PARAMS((int)); extern void _rl_enable_meta_key PARAMS((void)); extern void _rl_control_keypad PARAMS((int)); +extern void _rl_set_cursor PARAMS((int, int)); + +/* text.c */ +extern void _rl_fix_point PARAMS((int)); +extern int _rl_replace_text PARAMS((const char *, int, int)); +extern int _rl_insert_char PARAMS((int, int)); +extern int _rl_overwrite_char PARAMS((int, int)); +extern int _rl_overwrite_rubout PARAMS((int, int)); +extern int _rl_rubout_char PARAMS((int, int)); +#if defined (HANDLE_MULTIBYTE) +extern int _rl_char_search_internal PARAMS((int, int, char *, int)); +#else +extern int _rl_char_search_internal PARAMS((int, int, int)); +#endif +extern int _rl_set_mark_at_pos PARAMS((int)); /* util.c */ -extern int rl_alphabetic PARAMS((int)); extern int _rl_abort_internal PARAMS((void)); extern char *_rl_strindex PARAMS((const char *, const char *)); extern int _rl_qsort_string_compare PARAMS((char **, char **)); @@ -207,9 +220,11 @@ extern const char *_rl_possible_meta_prefixes[]; /* complete.c */ extern int _rl_complete_show_all; extern int _rl_complete_mark_directories; +extern int _rl_complete_mark_symlink_dirs; extern int _rl_print_completions_horizontally; extern int _rl_completion_case_fold; extern int _rl_match_hidden_files; +extern int _rl_page_completions; /* display.c */ extern int _rl_vis_botlin; @@ -221,9 +236,12 @@ extern char *rl_display_prompt; extern char *_rl_isearch_terminators; /* macro.c */ -extern int _rl_defining_kbd_macro; extern char *_rl_executing_macro; +/* misc.c */ +extern int _rl_history_preserve_point; +extern int _rl_history_saved_point; + /* readline.c */ extern int _rl_horizontal_scroll_mode; extern int _rl_mark_modified_lines; @@ -231,7 +249,6 @@ extern int _rl_bell_preference; extern int _rl_meta_flag; extern int _rl_convert_meta_chars_to_ascii; extern int _rl_output_meta_chars; -extern int _rl_history_preserve_point; extern char *_rl_comment_begin; extern unsigned char _rl_parsing_conditionalized_out; extern Keymap _rl_keymap; diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c index cc0dc030..755efeba 100644 --- a/lib/readline/rltty.c +++ b/lib/readline/rltty.c @@ -647,7 +647,6 @@ rl_prep_terminal (meta_flag) if (get_tty_settings (tty, &tio) < 0) { release_sigint (); -fprintf(stderr, "readline: warning: rl_prep_terminal: cannot get terminal settings"); return; } diff --git a/lib/readline/search.c b/lib/readline/search.c index 9c2feb17..7e0d60b5 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -40,6 +40,8 @@ #endif #include "rldefs.h" +#include "rlmbutil.h" + #include "readline.h" #include "history.h" @@ -80,15 +82,8 @@ static void make_history_line_current (entry) HIST_ENTRY *entry; { - int line_len; - - line_len = strlen (entry->line); - if (line_len >= rl_line_buffer_len) - rl_extend_line_buffer (line_len); - strcpy (rl_line_buffer, entry->line); - + rl_replace_line (entry->line, 0); rl_undo_list = (UNDO_LIST *)entry->data; - rl_end = line_len; if (_rl_saved_line_for_history) _rl_free_history_entry (_rl_saved_line_for_history); @@ -169,6 +164,8 @@ noninc_dosearch (string, dir) make_history_line_current (entry); rl_point = 0; + rl_mark = rl_end; + rl_clear_message (); } @@ -182,11 +179,15 @@ noninc_search (dir, pchar) int dir; int pchar; { - int saved_point, c; + int saved_point, saved_mark, c; char *p; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; +#endif rl_maybe_save_line (); saved_point = rl_point; + saved_mark = rl_mark; /* Use the line buffer to read the search string. */ rl_line_buffer[0] = 0; @@ -206,6 +207,11 @@ noninc_search (dir, pchar) c = rl_read_key (); RL_UNSETSTATE(RL_STATE_MOREINPUT); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, MB_LEN_MAX); +#endif + if (c == 0) break; @@ -218,9 +224,10 @@ noninc_search (dir, pchar) rl_maybe_unsave_line (); rl_clear_message (); rl_point = saved_point; + rl_mark = saved_mark; SEARCH_RETURN; } - rl_rubout (1, c); + _rl_rubout_char (1, c); break; case CTRL('W'): @@ -242,17 +249,25 @@ noninc_search (dir, pchar) rl_maybe_unsave_line (); rl_clear_message (); rl_point = saved_point; + rl_mark = saved_mark; rl_ding (); SEARCH_RETURN; default: - rl_insert (1, c); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mb); + else +#endif + _rl_insert_char (1, c); break; } (*rl_redisplay_function) (); } dosearch: + rl_mark = saved_mark; + /* If rl_point == 0, we want to re-use the previous search string and start from the saved history position. If there's no previous search string, punt. */ @@ -373,9 +388,11 @@ rl_history_search_internal (count, dir) { rl_point = rl_end = rl_history_search_len; rl_line_buffer[rl_end] = '\0'; + rl_mark = 0; } #else rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ + rl_mark = rl_end; #endif return 1; } @@ -384,6 +401,8 @@ rl_history_search_internal (count, dir) make_history_line_current (temp); rl_point = rl_history_search_len; + rl_mark = rl_end; + return 0; } diff --git a/lib/readline/signals.c b/lib/readline/signals.c index a1912691..0a1468b6 100644 --- a/lib/readline/signals.c +++ b/lib/readline/signals.c @@ -74,6 +74,7 @@ typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt #endif /* !HAVE_POSIX_SIGNALS */ static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); +static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); /* Exported variables for use by applications. */ @@ -232,7 +233,7 @@ rl_set_sighandler (sig, handler, ohandler) struct sigaction act; act.sa_handler = handler; - act.sa_flags = 0; + act.sa_flags = 0; /* XXX - should we set SA_RESTART for SIGWINCH? */ sigemptyset (&act.sa_mask); sigemptyset (&ohandler->sa_mask); sigaction (sig, &act, &old_handler); diff --git a/lib/readline/terminal.c b/lib/readline/terminal.c index 4d2268c0..f3f5b6c4 100644 --- a/lib/readline/terminal.c +++ b/lib/readline/terminal.c @@ -66,6 +66,9 @@ #include "rlshell.h" #include "xmalloc.h" +#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) +#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) + /* **************************************************************** */ /* */ /* Terminal and Termcap */ @@ -140,6 +143,16 @@ static char *_rl_term_ke; /* The key sequences sent by the Home and End keys, if any. */ static char *_rl_term_kh; static char *_rl_term_kH; +static char *_rl_term_at7; /* @7 */ + +/* Insert key */ +static char *_rl_term_kI; + +/* Cursor control */ +static char *_rl_term_vs; /* very visible */ +static char *_rl_term_ve; /* normal */ + +static void bind_termcap_arrow_keys PARAMS((Keymap)); /* Variables that hold the screen dimensions, used by the display code. */ int _rl_screenwidth, _rl_screenheight, _rl_screenchars; @@ -274,7 +287,10 @@ rl_resize_terminal () if (readline_echoing_p) { _rl_get_screen_size (fileno (rl_instream), 1); - _rl_redisplay_after_sigwinch (); + if (CUSTOM_REDISPLAY_FUNC ()) + rl_forced_update_display (); + else + _rl_redisplay_after_sigwinch (); } } @@ -287,6 +303,7 @@ struct _tc_string { search algorithm to something smarter. */ static struct _tc_string tc_strings[] = { + { "@7", &_rl_term_at7 }, { "DC", &_rl_term_DC }, { "IC", &_rl_term_IC }, { "ce", &_rl_term_clreol }, @@ -296,14 +313,15 @@ static struct _tc_string tc_strings[] = { "ei", &_rl_term_ei }, { "ic", &_rl_term_ic }, { "im", &_rl_term_im }, + { "kH", &_rl_term_kH }, /* home down ?? */ + { "kI", &_rl_term_kI }, /* insert */ { "kd", &_rl_term_kd }, + { "ke", &_rl_term_ke }, /* end keypad mode */ { "kh", &_rl_term_kh }, /* home */ - { "kH", &_rl_term_kH }, /* end */ { "kl", &_rl_term_kl }, { "kr", &_rl_term_kr }, + { "ks", &_rl_term_ks }, /* start keypad mode */ { "ku", &_rl_term_ku }, - { "ks", &_rl_term_ks }, - { "ke", &_rl_term_ke }, { "le", &_rl_term_backspace }, { "mm", &_rl_term_mm }, { "mo", &_rl_term_mo }, @@ -313,6 +331,8 @@ static struct _tc_string tc_strings[] = { "pc", &_rl_term_pc }, { "up", &_rl_term_up }, { "vb", &_rl_visible_bell }, + { "vs", &_rl_term_vs }, + { "ve", &_rl_term_ve }, }; #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) @@ -336,9 +356,6 @@ get_term_capabilities (bp) tcap_initialized = 1; } -#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) -#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) - int _rl_init_terminal_io (terminal_name) const char *terminal_name; @@ -346,7 +363,6 @@ _rl_init_terminal_io (terminal_name) const char *term; char *buffer; int tty, tgetent_ret; - Keymap xkeymap; term = terminal_name ? terminal_name : sh_get_env_value ("TERM"); _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL; @@ -404,7 +420,10 @@ _rl_init_terminal_io (terminal_name) _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL; _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL; _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL; + _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL; + _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL; _rl_term_mm = _rl_term_mo = (char *)NULL; + _rl_term_ve = _rl_term_vs = (char *)NULL; #if defined (HACK_TERMCAP_MOTION) term_forward_char = (char *)NULL; #endif @@ -449,31 +468,36 @@ _rl_init_terminal_io (terminal_name) /* Attempt to find and bind the arrow keys. Do not override already bound keys in an overzealous attempt, however. */ - xkeymap = _rl_keymap; - _rl_keymap = emacs_standard_keymap; - _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history); - _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history); - _rl_bind_if_unbound (_rl_term_kr, rl_forward); - _rl_bind_if_unbound (_rl_term_kl, rl_backward); - - _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ - _rl_bind_if_unbound (_rl_term_kH, rl_end_of_line); /* End */ + bind_termcap_arrow_keys (emacs_standard_keymap); #if defined (VI_MODE) - _rl_keymap = vi_movement_keymap; + bind_termcap_arrow_keys (vi_movement_keymap); + bind_termcap_arrow_keys (vi_insertion_keymap); +#endif /* VI_MODE */ + + return 0; +} + +/* Bind the arrow key sequences from the termcap description in MAP. */ +static void +bind_termcap_arrow_keys (map) + Keymap map; +{ + Keymap xkeymap; + + xkeymap = _rl_keymap; + _rl_keymap = map; + _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history); _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history); _rl_bind_if_unbound (_rl_term_kr, rl_forward); _rl_bind_if_unbound (_rl_term_kl, rl_backward); _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ - _rl_bind_if_unbound (_rl_term_kH, rl_end_of_line); /* End */ -#endif /* VI_MODE */ + _rl_bind_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ _rl_keymap = xkeymap; - - return 0; } char * @@ -610,3 +634,29 @@ _rl_control_keypad (on) tputs (_rl_term_ke, 1, _rl_output_character_function); #endif } + +/* **************************************************************** */ +/* */ +/* Controlling the Cursor */ +/* */ +/* **************************************************************** */ + +/* Set the cursor appropriately depending on IM, which is one of the + insert modes (insert or overwrite). Insert mode gets the normal + cursor. Overwrite mode gets a very visible cursor. Only does + anything if we have both capabilities. */ +void +_rl_set_cursor (im, force) + int im, force; +{ + if (_rl_term_ve && _rl_term_vs) + { + if (force || im != rl_insert_mode) + { + if (im == RL_IM_OVERWRITE) + tputs (_rl_term_vs, 1, _rl_output_character_function); + else + tputs (_rl_term_ve, 1, _rl_output_character_function); + } + } +} diff --git a/lib/readline/text.c b/lib/readline/text.c new file mode 100644 index 00000000..2a7b724f --- /dev/null +++ b/lib/readline/text.c @@ -0,0 +1,1540 @@ +/* text.c -- text handling commands for readline. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (__EMX__) +# define INCL_DOSPROCESS +# include <os2.h> +#endif /* __EMX__ */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +/* Forward declarations. */ +static int rl_change_case PARAMS((int, int)); +static int _rl_char_search PARAMS((int, int, int)); + +/* **************************************************************** */ +/* */ +/* Insert and Delete */ +/* */ +/* **************************************************************** */ + +/* Insert a string of text into the line at point. This is the only + way that you should do insertion. _rl_insert_char () calls this + function. Returns the number of characters inserted. */ +int +rl_insert_text (string) + const char *string; +{ + register int i, l; + + l = (string && *string) ? strlen (string) : 0; + if (l == 0) + return 0; + + if (rl_end + l >= rl_line_buffer_len) + rl_extend_line_buffer (rl_end + l); + + for (i = rl_end; i >= rl_point; i--) + rl_line_buffer[i + l] = rl_line_buffer[i]; + strncpy (rl_line_buffer + rl_point, string, l); + + /* Remember how to undo this if we aren't undoing something. */ + if (_rl_doing_an_undo == 0) + { + /* If possible and desirable, concatenate the undos. */ + if ((l == 1) && + rl_undo_list && + (rl_undo_list->what == UNDO_INSERT) && + (rl_undo_list->end == rl_point) && + (rl_undo_list->end - rl_undo_list->start < 20)) + rl_undo_list->end++; + else + rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); + } + rl_point += l; + rl_end += l; + rl_line_buffer[rl_end] = '\0'; + return l; +} + +/* Delete the string between FROM and TO. FROM is inclusive, TO is not. + Returns the number of characters deleted. */ +int +rl_delete_text (from, to) + int from, to; +{ + register char *text; + register int diff, i; + + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + /* fix boundaries */ + if (to > rl_end) + { + to = rl_end; + if (from > to) + from = to; + } + if (from < 0) + from = 0; + + text = rl_copy_text (from, to); + + /* Some versions of strncpy() can't handle overlapping arguments. */ + diff = to - from; + for (i = from; i < rl_end - diff; i++) + rl_line_buffer[i] = rl_line_buffer[i + diff]; + + /* Remember how to undo this delete. */ + if (_rl_doing_an_undo == 0) + rl_add_undo (UNDO_DELETE, from, to, text); + else + free (text); + + rl_end -= diff; + rl_line_buffer[rl_end] = '\0'; + return (diff); +} + +/* Fix up point so that it is within the line boundaries after killing + text. If FIX_MARK_TOO is non-zero, the mark is forced within line + boundaries also. */ + +#define _RL_FIX_POINT(x) \ + do { \ + if (x > rl_end) \ + x = rl_end; \ + else if (x < 0) \ + x = 0; \ + } while (0) + +void +_rl_fix_point (fix_mark_too) + int fix_mark_too; +{ + _RL_FIX_POINT (rl_point); + if (fix_mark_too) + _RL_FIX_POINT (rl_mark); +} +#undef _RL_FIX_POINT + +int +_rl_replace_text (text, start, end) + const char *text; + int start, end; +{ + int n; + + rl_begin_undo_group (); + rl_delete_text (start, end + 1); + rl_point = start; + n = rl_insert_text (text); + rl_end_undo_group (); + + return n; +} + +/* Replace the current line buffer contents with TEXT. If CLEAR_UNDO is + non-zero, we free the current undo list. */ +void +rl_replace_line (text, clear_undo) + const char *text; + int clear_undo; +{ + int len; + + len = strlen (text); + if (len >= rl_line_buffer_len) + rl_extend_line_buffer (len); + strcpy (rl_line_buffer, text); + rl_end = len; + + if (clear_undo) + rl_free_undo_list (); + + _rl_fix_point (1); +} + +/* **************************************************************** */ +/* */ +/* Readline character functions */ +/* */ +/* **************************************************************** */ + +/* This is not a gap editor, just a stupid line input routine. No hair + is involved in writing any of the functions, and none should be. */ + +/* Note that: + + rl_end is the place in the string that we would place '\0'; + i.e., it is always safe to place '\0' there. + + rl_point is the place in the string where the cursor is. Sometimes + this is the same as rl_end. + + Any command that is called interactively receives two arguments. + The first is a count: the numeric arg pased to this command. + The second is the key which invoked this command. +*/ + +/* **************************************************************** */ +/* */ +/* Movement Commands */ +/* */ +/* **************************************************************** */ + +/* Note that if you `optimize' the display for these functions, you cannot + use said functions in other functions which do not do optimizing display. + I.e., you will have to update the data base for rl_redisplay, and you + might as well let rl_redisplay do that job. */ + +/* Move forward COUNT bytes. */ +int +rl_forward_byte (count, key) + int count, key; +{ + if (count < 0) + return (rl_backward_byte (-count, key)); + + if (count > 0) + { + int end = rl_point + count; +#if defined (VI_MODE) + int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end; +#else + int lend = rl_end; +#endif + + if (end > lend) + { + rl_point = lend; + rl_ding (); + } + else + rl_point = end; + } + + if (rl_end < 0) + rl_end = 0; + + return 0; +} + +#if defined (HANDLE_MULTIBYTE) +/* Move forward COUNT characters. */ +int +rl_forward_char (count, key) + int count, key; +{ + int point; + + if (MB_CUR_MAX == 1 || rl_byte_oriented) + return (rl_forward_byte (count, key)); + + if (count < 0) + return (rl_backward_char (-count, key)); + + if (count > 0) + { + point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + +#if defined (VI_MODE) + if (rl_end <= point && rl_editing_mode == vi_mode) + point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO); +#endif + + if (rl_point == point) + rl_ding (); + + rl_point = point; + + if (rl_end < 0) + rl_end = 0; + } + + return 0; +} +#else /* !HANDLE_MULTIBYTE */ +int +rl_forward_char (count, key) + int count, key; +{ + return (rl_forward_byte (count, key)); +} +#endif /* !HANDLE_MULTIBYTE */ + +/* Backwards compatibility. */ +int +rl_forward (count, key) + int count, key; +{ + return (rl_forward_char (count, key)); +} + +/* Move backward COUNT bytes. */ +int +rl_backward_byte (count, key) + int count, key; +{ + if (count < 0) + return (rl_forward_byte (-count, key)); + + if (count > 0) + { + if (rl_point < count) + { + rl_point = 0; + rl_ding (); + } + else + rl_point -= count; + } + + if (rl_point < 0) + rl_point = 0; + + return 0; +} + +#if defined (HANDLE_MULTIBYTE) +/* Move backward COUNT characters. */ +int +rl_backward_char (count, key) + int count, key; +{ + int point; + + if (MB_CUR_MAX == 1 || rl_byte_oriented) + return (rl_backward_byte (count, key)); + + if (count < 0) + return (rl_forward_char (-count, key)); + + if (count > 0) + { + point = rl_point; + + while (count > 0 && point > 0) + { + point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO); + count--; + } + if (count > 0) + { + rl_point = 0; + rl_ding (); + } + else + rl_point = point; + } + + return 0; +} +#else +int +rl_backward_char (count, key) + int count, key; +{ + return (rl_backward_byte (count, key)); +} +#endif + +/* Backwards compatibility. */ +int +rl_backward (count, key) + int count, key; +{ + return (rl_backward_char (count, key)); +} + +/* Move to the beginning of the line. */ +int +rl_beg_of_line (count, key) + int count, key; +{ + rl_point = 0; + return 0; +} + +/* Move to the end of the line. */ +int +rl_end_of_line (count, key) + int count, key; +{ + rl_point = rl_end; + return 0; +} + +/* XXX - these might need changes for multibyte characters */ +/* Move forward a word. We do what Emacs does. */ +int +rl_forward_word (count, key) + int count, key; +{ + int c; + + if (count < 0) + return (rl_backward_word (-count, key)); + + while (count) + { + if (rl_point == rl_end) + return 0; + + /* If we are not in a word, move forward until we are in one. + Then, move forward until we hit a non-alphabetic character. */ + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c) == 0) + { + while (++rl_point < rl_end) + { + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c)) + break; + } + } + + if (rl_point == rl_end) + return 0; + + while (++rl_point < rl_end) + { + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c) == 0) + break; + } + --count; + } + + return 0; +} + +/* Move backward a word. We do what Emacs does. */ +int +rl_backward_word (count, key) + int count, key; +{ + int c; + + if (count < 0) + return (rl_forward_word (-count, key)); + + while (count) + { + if (!rl_point) + return 0; + + /* Like rl_forward_word (), except that we look at the characters + just before point. */ + + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c) == 0) + { + while (--rl_point) + { + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c)) + break; + } + } + + while (rl_point) + { + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c) == 0) + break; + else + --rl_point; + } + + --count; + } + + return 0; +} + +/* Clear the current line. Numeric argument to C-l does this. */ +int +rl_refresh_line (ignore1, ignore2) + int ignore1, ignore2; +{ + int curr_line; + + curr_line = _rl_current_display_line (); + + _rl_move_vert (curr_line); + _rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */ + + _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ + + rl_forced_update_display (); + rl_display_fixed = 1; + + return 0; +} + +/* C-l typed to a line without quoting clears the screen, and then reprints + the prompt and the current input line. Given a numeric arg, redraw only + the current line. */ +int +rl_clear_screen (count, key) + int count, key; +{ + if (rl_explicit_arg) + { + rl_refresh_line (count, key); + return 0; + } + + _rl_clear_screen (); /* calls termcap function to clear screen */ + rl_forced_update_display (); + rl_display_fixed = 1; + + return 0; +} + +int +rl_arrow_keys (count, c) + int count, c; +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + switch (_rl_to_upper (ch)) + { + case 'A': + rl_get_previous_history (count, ch); + break; + + case 'B': + rl_get_next_history (count, ch); + break; + + case 'C': + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_forward_char (count, ch); + else + rl_forward_byte (count, ch); + break; + + case 'D': + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, ch); + else + rl_backward_byte (count, ch); + break; + + default: + rl_ding (); + } + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Text commands */ +/* */ +/* **************************************************************** */ + +#ifdef HANDLE_MULTIBYTE +static char pending_bytes[MB_LEN_MAX]; +static int pending_bytes_length = 0; +static mbstate_t ps = {0}; +#endif + +/* Insert the character C at the current location, moving point forward. + If C introduces a multibyte sequence, we read the whole sequence and + then insert the multibyte char into the line buffer. */ +int +_rl_insert_char (count, c) + int count, c; +{ + register int i; + char *string; +#ifdef HANDLE_MULTIBYTE + int string_size; + char incoming[MB_LEN_MAX + 1]; + int incoming_length = 0; + mbstate_t ps_back; + static int stored_count = 0; +#endif + + if (count <= 0) + return 0; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { + incoming[0] = c; + incoming[1] = '\0'; + incoming_length = 1; + } + else + { + wchar_t wc; + size_t ret; + + if (stored_count <= 0) + stored_count = count; + else + count = stored_count; + + ps_back = ps; + pending_bytes[pending_bytes_length++] = c; + ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps); + + if (ret == (size_t)-2) + { + /* Bytes too short to compose character, try to wait for next byte. + Restore the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + ps = ps_back; + return 1; + } + else if (ret == (size_t)-1) + { + /* Invalid byte sequence for the current locale. Treat first byte + as a single character. */ + incoming[0] = pending_bytes[0]; + incoming[1] = '\0'; + incoming_length = 1; + pending_bytes_length--; + memmove (pending_bytes, pending_bytes + 1, pending_bytes_length); + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (ret == (size_t)0) + { + incoming[0] = '\0'; + incoming_length = 0; + pending_bytes_length--; + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else + { + /* We successfully read a single multibyte character. */ + memcpy (incoming, pending_bytes, pending_bytes_length); + incoming[pending_bytes_length] = '\0'; + incoming_length = pending_bytes_length; + pending_bytes_length = 0; + } + } +#endif /* HANDLE_MULTIBYTE */ + + /* If we can optimize, then do it. But don't let people crash + readline because of extra large arguments. */ + if (count > 1 && count <= 1024) + { +#if defined (HANDLE_MULTIBYTE) + string_size = count * incoming_length; + string = (char *)xmalloc (1 + string_size); + + i = 0; + while (i < string_size) + { + strncpy (string + i, incoming, incoming_length); + i += incoming_length; + } + incoming_length = 0; + stored_count = 0; +#else /* !HANDLE_MULTIBYTE */ + string = (char *)xmalloc (1 + count); + + for (i = 0; i < count; i++) + string[i] = c; +#endif /* !HANDLE_MULTIBYTE */ + + string[i] = '\0'; + rl_insert_text (string); + free (string); + + return 0; + } + + if (count > 1024) + { + int decreaser; +#if defined (HANDLE_MULTIBYTE) + string_size = incoming_length * 1024; + string = (char *)xmalloc (1 + string_size); + + i = 0; + while (i < string_size) + { + strncpy (string + i, incoming, incoming_length); + i += incoming_length; + } + + while (count) + { + decreaser = (count > 1024) ? 1024 : count; + string[decreaser*incoming_length] = '\0'; + rl_insert_text (string); + count -= decreaser; + } + + free (string); + incoming_length = 0; + stored_count = 0; +#else /* !HANDLE_MULTIBYTE */ + char str[1024+1]; + + for (i = 0; i < 1024; i++) + str[i] = c; + + while (count) + { + decreaser = (count > 1024 ? 1024 : count); + str[decreaser] = '\0'; + rl_insert_text (str); + count -= decreaser; + } +#endif /* !HANDLE_MULTIBYTE */ + + return 0; + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { +#endif + /* We are inserting a single character. + If there is pending input, then make a string of all of the + pending characters that are bound to rl_insert, and insert + them all. */ + if (_rl_any_typein ()) + _rl_insert_typein (c); + else + { + /* Inserting a single character. */ + char str[2]; + + str[1] = '\0'; + str[0] = c; + rl_insert_text (str); + } +#if defined (HANDLE_MULTIBYTE) + } + else + { + rl_insert_text (incoming); + stored_count = 0; + } +#endif + + return 0; +} + +/* Overwrite the character at point (or next COUNT characters) with C. + If C introduces a multibyte character sequence, read the entire sequence + before starting the overwrite loop. */ +int +_rl_overwrite_char (count, c) + int count, c; +{ + int i; +#if defined (HANDLE_MULTIBYTE) + char mbkey[MB_LEN_MAX]; + int k; + + /* Read an entire multibyte character sequence to insert COUNT times. */ + if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) + k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX); +#endif + + for (i = 0; i < count; i++) + { + rl_begin_undo_group (); + + if (rl_point < rl_end) + rl_delete (1, c); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mbkey); + else +#endif + _rl_insert_char (1, c); + + rl_end_undo_group (); + } + + return 0; +} + +int +rl_insert (count, c) + int count, c; +{ + return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c) + : _rl_overwrite_char (count, c)); +} + +/* Insert the next typed character verbatim. */ +int +rl_quoted_insert (count, key) + int count, key; +{ + int c; + +#if defined (HANDLE_SIGNALS) + _rl_disable_tty_signals (); +#endif + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + +#if defined (HANDLE_SIGNALS) + _rl_restore_tty_signals (); +#endif + + return (_rl_insert_char (count, c)); +} + +/* Insert a tab character. */ +int +rl_tab_insert (count, key) + int count, key; +{ + return (_rl_insert_char (count, '\t')); +} + +/* What to do when a NEWLINE is pressed. We accept the whole line. + KEY is the key that invoked this command. I guess it could have + meaning in the future. */ +int +rl_newline (count, key) + int count, key; +{ + rl_done = 1; + + if (_rl_history_preserve_point) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + RL_SETSTATE(RL_STATE_DONE); + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + { + _rl_vi_done_inserting (); + _rl_vi_reset_last (); + } +#endif /* VI_MODE */ + + /* If we've been asked to erase empty lines, suppress the final update, + since _rl_update_final calls rl_crlf(). */ + if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) + return 0; + + if (readline_echoing_p) + _rl_update_final (); + return 0; +} + +/* What to do for some uppercase characters, like meta characters, + and some characters appearing in emacs_ctlx_keymap. This function + is just a stub, you bind keys to it and the code in _rl_dispatch () + is special cased. */ +int +rl_do_lowercase_version (ignore1, ignore2) + int ignore1, ignore2; +{ + return 0; +} + +/* This is different from what vi does, so the code's not shared. Emacs + rubout in overwrite mode has one oddity: it replaces a control + character that's displayed as two characters (^X) with two spaces. */ +int +_rl_overwrite_rubout (count, key) + int count, key; +{ + int opoint; + int i, l; + + if (rl_point == 0) + { + rl_ding (); + return 1; + } + + opoint = rl_point; + + /* L == number of spaces to insert */ + for (i = l = 0; i < count; i++) + { + rl_backward_char (1, key); + l += rl_character_len (rl_line_buffer[rl_point], rl_point); /* not exactly right */ + } + + rl_begin_undo_group (); + + if (count > 1 || rl_explicit_arg) + rl_kill_text (opoint, rl_point); + else + rl_delete_text (opoint, rl_point); + + /* Emacs puts point at the beginning of the sequence of spaces. */ + opoint = rl_point; + _rl_insert_char (l, ' '); + rl_point = opoint; + + rl_end_undo_group (); + + return 0; +} + +/* Rubout the character behind point. */ +int +rl_rubout (count, key) + int count, key; +{ + if (count < 0) + return (rl_delete (-count, key)); + + if (!rl_point) + { + rl_ding (); + return -1; + } + + if (rl_insert_mode == RL_IM_OVERWRITE) + return (_rl_overwrite_rubout (count, key)); + + return (_rl_rubout_char (count, key)); +} + +int +_rl_rubout_char (count, key) + int count, key; +{ + int orig_point; + unsigned char c; + + /* Duplicated code because this is called from other parts of the library. */ + if (count < 0) + return (rl_delete (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return -1; + } + + if (count > 1 || rl_explicit_arg) + { + orig_point = rl_point; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, key); + else +#endif + rl_backward_byte (count, key); + rl_kill_text (orig_point, rl_point); + } + else + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { +#endif + c = rl_line_buffer[--rl_point]; + rl_delete_text (rl_point, rl_point + 1); +#if defined (HANDLE_MULTIBYTE) + } + else + { + int orig_point; + + orig_point = rl_point; + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + c = rl_line_buffer[rl_point]; + rl_delete_text (rl_point, orig_point); + } +#endif /* HANDLE_MULTIBYTE */ + + /* I don't think that the hack for end of line is needed for + multibyte chars. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) +#endif + if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos) + { + int l; + l = rl_character_len (c, rl_point); + _rl_erase_at_end_of_line (l); + } + } + + return 0; +} + +/* Delete the character under the cursor. Given a numeric argument, + kill that many characters instead. */ +int +rl_delete (count, key) + int count, key; +{ + int r; + + if (count < 0) + return (_rl_rubout_char (-count, key)); + + if (rl_point == rl_end) + { + rl_ding (); + return -1; + } + + if (count > 1 || rl_explicit_arg) + { + int orig_point = rl_point; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_forward_char (count, key); + else +#endif + rl_forward_byte (count, key); + + r = rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + return r; + } + else + { + int new_point; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); + else + new_point = rl_point + 1; + + return (rl_delete_text (rl_point, new_point)); + } +} + +/* Delete the character under the cursor, unless the insertion + point is at the end of the line, in which case the character + behind the cursor is deleted. COUNT is obeyed and may be used + to delete forward or backward that many characters. */ +int +rl_rubout_or_delete (count, key) + int count, key; +{ + if (rl_end != 0 && rl_point == rl_end) + return (_rl_rubout_char (count, key)); + else + return (rl_delete (count, key)); +} + +/* Delete all spaces and tabs around point. */ +int +rl_delete_horizontal_space (count, ignore) + int count, ignore; +{ + int start = rl_point; + + while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + start = rl_point; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (start != rl_point) + { + rl_delete_text (start, rl_point); + rl_point = start; + } + return 0; +} + +/* Like the tcsh editing function delete-char-or-list. The eof character + is caught before this is invoked, so this really does the same thing as + delete-char-or-list-or-eof, as long as it's bound to the eof character. */ +int +rl_delete_or_show_completions (count, key) + int count, key; +{ + if (rl_end != 0 && rl_point == rl_end) + return (rl_possible_completions (count, key)); + else + return (rl_delete (count, key)); +} + +#ifndef RL_COMMENT_BEGIN_DEFAULT +#define RL_COMMENT_BEGIN_DEFAULT "#" +#endif + +/* Turn the current line into a comment in shell history. + A K*rn shell style function. */ +int +rl_insert_comment (count, key) + int count, key; +{ + char *rl_comment_text; + int rl_comment_len; + + rl_beg_of_line (1, key); + rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT; + + if (rl_explicit_arg == 0) + rl_insert_text (rl_comment_text); + else + { + rl_comment_len = strlen (rl_comment_text); + if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len)) + rl_delete_text (rl_point, rl_point + rl_comment_len); + else + rl_insert_text (rl_comment_text); + } + + (*rl_redisplay_function) (); + rl_newline (1, '\n'); + + return (0); +} + +/* **************************************************************** */ +/* */ +/* Changing Case */ +/* */ +/* **************************************************************** */ + +/* The three kinds of things that we know how to do. */ +#define UpCase 1 +#define DownCase 2 +#define CapCase 3 + +/* Uppercase the word at point. */ +int +rl_upcase_word (count, key) + int count, key; +{ + return (rl_change_case (count, UpCase)); +} + +/* Lowercase the word at point. */ +int +rl_downcase_word (count, key) + int count, key; +{ + return (rl_change_case (count, DownCase)); +} + +/* Upcase the first letter, downcase the rest. */ +int +rl_capitalize_word (count, key) + int count, key; +{ + return (rl_change_case (count, CapCase)); +} + +/* The meaty function. + Change the case of COUNT words, performing OP on them. + OP is one of UpCase, DownCase, or CapCase. + If a negative argument is given, leave point where it started, + otherwise, leave it where it moves to. */ +static int +rl_change_case (count, op) + int count, op; +{ + register int start, end; + int inword, c; + + start = rl_point; + rl_forward_word (count, 0); + end = rl_point; + + if (count < 0) + SWAP (start, end); + + /* We are going to modify some text, so let's prepare to undo it. */ + rl_modifying (start, end); + + for (inword = 0; start < end; start++) + { + c = rl_line_buffer[start]; + switch (op) + { + case UpCase: + rl_line_buffer[start] = _rl_to_upper (c); + break; + + case DownCase: + rl_line_buffer[start] = _rl_to_lower (c); + break; + + case CapCase: + rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c); + inword = rl_alphabetic (rl_line_buffer[start]); + break; + + default: + rl_ding (); + return -1; + } + } + rl_point = end; + return 0; +} + +/* **************************************************************** */ +/* */ +/* Transposition */ +/* */ +/* **************************************************************** */ + +/* Transpose the words at point. If point is at the end of the line, + transpose the two words before point. */ +int +rl_transpose_words (count, key) + int count, key; +{ + char *word1, *word2; + int w1_beg, w1_end, w2_beg, w2_end; + int orig_point = rl_point; + + if (!count) + return 0; + + /* Find the two words. */ + rl_forward_word (count, key); + w2_end = rl_point; + rl_backward_word (1, key); + w2_beg = rl_point; + rl_backward_word (count, key); + w1_beg = rl_point; + rl_forward_word (1, key); + w1_end = rl_point; + + /* Do some check to make sure that there really are two words. */ + if ((w1_beg == w2_beg) || (w2_beg < w1_end)) + { + rl_ding (); + rl_point = orig_point; + return -1; + } + + /* Get the text of the words. */ + word1 = rl_copy_text (w1_beg, w1_end); + word2 = rl_copy_text (w2_beg, w2_end); + + /* We are about to do many insertions and deletions. Remember them + as one operation. */ + rl_begin_undo_group (); + + /* Do the stuff at word2 first, so that we don't have to worry + about word1 moving. */ + rl_point = w2_beg; + rl_delete_text (w2_beg, w2_end); + rl_insert_text (word1); + + rl_point = w1_beg; + rl_delete_text (w1_beg, w1_end); + rl_insert_text (word2); + + /* This is exactly correct since the text before this point has not + changed in length. */ + rl_point = w2_end; + + /* I think that does it. */ + rl_end_undo_group (); + free (word1); + free (word2); + + return 0; +} + +/* Transpose the characters at point. If point is at the end of the line, + then transpose the characters before point. */ +int +rl_transpose_chars (count, key) + int count, key; +{ +#if defined (HANDLE_MULTIBYTE) + char *dummy; + int i, prev_point; +#else + char dummy[2]; +#endif + int char_length; + + if (count == 0) + return 0; + + if (!rl_point || rl_end < 2) + { + rl_ding (); + return -1; + } + + rl_begin_undo_group (); + + if (rl_point == rl_end) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + --rl_point; + count = 1; + } + +#if defined (HANDLE_MULTIBYTE) + prev_point = rl_point; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else +#endif + rl_point--; + +#if defined (HANDLE_MULTIBYTE) + char_length = prev_point - rl_point; + dummy = (char *)xmalloc (char_length + 1); + for (i = 0; i < char_length; i++) + dummy[i] = rl_line_buffer[rl_point + i]; + dummy[i] = '\0'; +#else + dummy[0] = rl_line_buffer[rl_point]; + dummy[char_length = 1] = '\0'; +#endif + + rl_delete_text (rl_point, rl_point + char_length); + + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + + _rl_fix_point (0); + rl_insert_text (dummy); + rl_end_undo_group (); + +#if defined (HANDLE_MULTIBYTE) + free (dummy); +#endif + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Character Searching */ +/* */ +/* **************************************************************** */ + +int +#if defined (HANDLE_MULTIBYTE) +_rl_char_search_internal (count, dir, smbchar, len) + int count, dir; + char *smbchar; + int len; +#else +_rl_char_search_internal (count, dir, schar) + int count, dir, schar; +#endif +{ + int pos, inc; +#if defined (HANDLE_MULTIBYTE) + int prepos; +#endif + + pos = rl_point; + inc = (dir < 0) ? -1 : 1; + while (count) + { + if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) + { + rl_ding (); + return -1; + } + +#if defined (HANDLE_MULTIBYTE) + pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) + : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); +#else + pos += inc; +#endif + do + { +#if defined (HANDLE_MULTIBYTE) + if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len)) +#else + if (rl_line_buffer[pos] == schar) +#endif + { + count--; + if (dir < 0) + rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) + : pos; + else + rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY) + : pos; + break; + } +#if defined (HANDLE_MULTIBYTE) + prepos = pos; +#endif + } +#if defined (HANDLE_MULTIBYTE) + while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos + : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos); +#else + while ((dir < 0) ? pos-- : ++pos < rl_end); +#endif + } + return (0); +} + +/* Search COUNT times for a character read from the current input stream. + FDIR is the direction to search if COUNT is non-negative; otherwise + the search goes in BDIR. So much is dependent on HANDLE_MULTIBYTE + that there are two separate versions of this function. */ +#if defined (HANDLE_MULTIBYTE) +static int +_rl_char_search (count, fdir, bdir) + int count, fdir, bdir; +{ + char mbchar[MB_LEN_MAX]; + int mb_len; + + mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX); + + if (count < 0) + return (_rl_char_search_internal (-count, bdir, mbchar, mb_len)); + else + return (_rl_char_search_internal (count, fdir, mbchar, mb_len)); +} +#else /* !HANDLE_MULTIBYTE */ +static int +_rl_char_search (count, fdir, bdir) + int count, fdir, bdir; +{ + int c; + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (count < 0) + return (_rl_char_search_internal (-count, bdir, c)); + else + return (_rl_char_search_internal (count, fdir, c)); +} +#endif /* !HANDLE_MULTIBYTE */ + +int +rl_char_search (count, key) + int count, key; +{ + return (_rl_char_search (count, FFIND, BFIND)); +} + +int +rl_backward_char_search (count, key) + int count, key; +{ + return (_rl_char_search (count, BFIND, FFIND)); +} + +/* **************************************************************** */ +/* */ +/* The Mark and the Region. */ +/* */ +/* **************************************************************** */ + +/* Set the mark at POSITION. */ +int +_rl_set_mark_at_pos (position) + int position; +{ + if (position > rl_end) + return -1; + + rl_mark = position; + return 0; +} + +/* A bindable command to set the mark. */ +int +rl_set_mark (count, key) + int count, key; +{ + return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); +} + +/* Exchange the position of mark and point. */ +int +rl_exchange_point_and_mark (count, key) + int count, key; +{ + if (rl_mark > rl_end) + rl_mark = -1; + + if (rl_mark == -1) + { + rl_ding (); + return -1; + } + else + SWAP (rl_point, rl_mark); + + return 0; +} diff --git a/lib/readline/tilde.c b/lib/readline/tilde.c index 6e4f116f..154f7f81 100644 --- a/lib/readline/tilde.c +++ b/lib/readline/tilde.c @@ -59,9 +59,6 @@ extern struct passwd *getpwnam PARAMS((const char *)); #endif /* !HAVE_GETPW_DECLS */ #if !defined (savestring) -# ifndef strcpy -extern char *strcpy (); -# endif #define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x)) #endif /* !savestring */ diff --git a/lib/readline/tilde.h b/lib/readline/tilde.h index 0df608b3..f8182c99 100644 --- a/lib/readline/tilde.h +++ b/lib/readline/tilde.h @@ -24,10 +24,6 @@ #if !defined (_TILDE_H_) # define _TILDE_H_ -#if defined (HAVE_CONFIG_H) -# include <config.h> -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/lib/readline/undo.c b/lib/readline/undo.c index 9be231de..25c287b5 100644 --- a/lib/readline/undo.c +++ b/lib/readline/undo.c @@ -50,8 +50,6 @@ #include "rlprivate.h" #include "xmalloc.h" -#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) - /* Non-zero tells rl_delete_text and rl_insert_text to not add to the undo list. */ int _rl_doing_an_undo = 0; diff --git a/lib/readline/util.c b/lib/readline/util.c index bd08b38a..c7bd360e 100644 --- a/lib/readline/util.c +++ b/lib/readline/util.c @@ -55,8 +55,6 @@ #include "rlprivate.h" #include "xmalloc.h" -#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) - /* **************************************************************** */ /* */ /* Utility Functions */ @@ -89,7 +87,7 @@ _rl_abort_internal () _rl_init_argument (); rl_clear_pending_input (); - _rl_defining_kbd_macro = 0; + RL_UNSETSTATE (RL_STATE_MACRODEF); while (rl_executing_macro) _rl_pop_executing_macro (); @@ -233,6 +231,12 @@ _rl_strpbrk (string1, string2) const char *string1, *string2; { register const char *scan; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + register int i, v; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif for (; *string1; string1++) { @@ -241,6 +245,14 @@ _rl_strpbrk (string1, string2) if (*string1 == *scan) return ((char *)string1); } +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + v = _rl_get_char_len (string1, &ps); + if (v > 1) + string += v - 1; /* -1 to account for auto-increment in loop */ + } +#endif } return ((char *)NULL); } diff --git a/lib/readline/vi_keymap.c b/lib/readline/vi_keymap.c index cb84c06d..53a67c67 100644 --- a/lib/readline/vi_keymap.c +++ b/lib/readline/vi_keymap.c @@ -41,7 +41,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, rl_backward_char }, /* Control-h */ { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-i */ { ISFUNC, rl_newline }, /* Control-j */ { ISFUNC, rl_kill_line }, /* Control-k */ @@ -68,7 +68,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_vi_undo }, /* Control-_ */ /* The start of printing characters. */ - { ISFUNC, rl_forward }, /* SPACE */ + { ISFUNC, rl_forward_char }, /* SPACE */ { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ { ISFUNC, rl_insert_comment }, /* # */ @@ -150,11 +150,11 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = { { ISFUNC, rl_vi_end_word }, /* e */ { ISFUNC, rl_vi_char_search }, /* f */ { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ - { ISFUNC, rl_backward }, /* h */ + { ISFUNC, rl_backward_char }, /* h */ { ISFUNC, rl_vi_insertion_mode }, /* i */ { ISFUNC, rl_get_next_history }, /* j */ { ISFUNC, rl_get_previous_history }, /* k */ - { ISFUNC, rl_forward }, /* l */ + { ISFUNC, rl_forward_char }, /* l */ { ISFUNC, rl_vi_set_mark }, /* m */ { ISFUNC, rl_vi_search_again }, /* n */ { ISFUNC, (rl_command_func_t *)0x0 }, /* o */ diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index 09ccecf6..5d146b3f 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -51,6 +51,8 @@ /* Some standard library routines. */ #include "rldefs.h" +#include "rlmbutil.h" + #include "readline.h" #include "history.h" @@ -61,10 +63,6 @@ #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) #endif -#ifndef exchange -#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0) -#endif - /* Non-zero means enter insertion mode. */ static int _rl_vi_doing_insert; @@ -89,7 +87,11 @@ static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ static int _rl_vi_last_repeat = 1; static int _rl_vi_last_arg_sign = 1; static int _rl_vi_last_motion; +#if defined (HANDLE_MULTIBYTE) +static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; +#else static int _rl_vi_last_search_char; +#endif static int _rl_vi_last_replacement; static int _rl_vi_last_key_before_insert; @@ -158,12 +160,15 @@ int rl_vi_redo (count, c) int count, c; { + int r; + if (!rl_explicit_arg) { rl_numeric_arg = _rl_vi_last_repeat; rl_arg_sign = _rl_vi_last_arg_sign; } + r = 0; vi_redoing = 1; /* If we're redoing an insert with `i', stuff in the inserted text and do not go into insertion mode. */ @@ -175,10 +180,10 @@ rl_vi_redo (count, c) rl_point--; } else - _rl_dispatch (_rl_vi_last_command, _rl_keymap); + r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); vi_redoing = 0; - return (0); + return (r); } /* A placeholder for further expansion. */ @@ -547,7 +552,17 @@ rl_vi_append_mode (count, key) int count, key; { if (rl_point < rl_end) - rl_point++; + { + if (MB_CUR_MAX == 1 || rl_byte_oriented) + rl_point++; + else + { + int point = rl_point; + rl_forward_char (1, key); + if (point == rl_point) + rl_point = rl_end; + } + } rl_vi_insertion_mode (1, key); return (0); } @@ -612,6 +627,7 @@ _rl_vi_done_inserting () { if (_rl_vi_doing_insert) { + /* The `C', `s', and `S' commands set this. */ rl_end_undo_group (); /* Now, the text between rl_undo_list->next->start and rl_undo_list->next->end is what was inserted while in insert @@ -640,7 +656,7 @@ rl_vi_movement_mode (count, key) int count, key; { if (rl_point > 0) - rl_backward (1, key); + rl_backward_char (1, key); _rl_keymap = vi_movement_keymap; _rl_vi_done_inserting (); @@ -657,6 +673,51 @@ rl_vi_arg_digit (count, c) return (rl_digit_argument (count, c)); } +/* Change the case of the next COUNT characters. */ +#if defined (HANDLE_MULTIBYTE) +static int +_rl_vi_change_mbchar_case (count) + int count; +{ + wchar_t wc; + char mb[MB_LEN_MAX]; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) + count--; + while (count-- && rl_point < rl_end) + { + mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); + if (iswupper (wc)) + wc = towlower (wc); + else if (iswlower (wc)) + wc = towupper (wc); + else + { + /* Just skip over chars neither upper nor lower case */ + rl_forward_char (1, 0); + continue; + } + + /* Vi is kind of strange here. */ + if (wc) + { + wctomb (mb, wc); + rl_begin_undo_group (); + rl_delete (1, 0); + rl_insert_text (mb); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward_char (1, 0); + } + + return 0; +} +#endif + int rl_vi_change_case (count, ignore) int count, ignore; @@ -667,6 +728,11 @@ rl_vi_change_case (count, ignore) if (rl_point >= rl_end) return (0); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + return (_rl_vi_change_mbchar_case (count)); +#endif + while (count-- && rl_point < rl_end) { if (_rl_uppercase_p (rl_line_buffer[rl_point])) @@ -676,7 +742,7 @@ rl_vi_change_case (count, ignore) else { /* Just skip over characters neither upper nor lower case. */ - rl_forward (1, c); + rl_forward_char (1, c); continue; } @@ -685,12 +751,12 @@ rl_vi_change_case (count, ignore) { rl_begin_undo_group (); rl_delete (1, c); - rl_insert (1, c); + _rl_insert_char (1, c); rl_end_undo_group (); rl_vi_check (); } else - rl_forward (1, c); + rl_forward_char (1, c); } return (0); } @@ -700,10 +766,10 @@ rl_vi_put (count, key) int count, key; { if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) - rl_point++; + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); rl_yank (1, key); - rl_backward (1, key); + rl_backward_char (1, key); return (0); } @@ -711,7 +777,12 @@ int rl_vi_check () { if (rl_point && rl_point == rl_end) - rl_point--; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; + } return (0); } @@ -813,7 +884,7 @@ rl_vi_domove (key, nextkey) } if (rl_mark < rl_point) - exchange (rl_point, rl_mark); + SWAP (rl_point, rl_mark); return (0); } @@ -991,7 +1062,10 @@ rl_vi_delete (count, key) return -1; } - end = rl_point + count; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + else + end = rl_point + count; if (end >= rl_end) end = rl_end; @@ -999,7 +1073,7 @@ rl_vi_delete (count, key) rl_kill_text (rl_point, end); if (rl_point > 0 && rl_point == rl_end) - rl_backward (1, key); + rl_backward_char (1, key); return (0); } @@ -1024,7 +1098,12 @@ int rl_vi_char_search (count, key) int count, key; { +#if defined (HANDLE_MULTIBYTE) + static char *target; + static int mb_len; +#else static char target; +#endif static int orig_dir, dir; if (key == ';' || key == ',') @@ -1032,12 +1111,21 @@ rl_vi_char_search (count, key) else { if (vi_redoing) +#if defined (HANDLE_MULTIBYTE) + target = _rl_vi_last_search_mbchar; +#else target = _rl_vi_last_search_char; +#endif else { +#if defined (HANDLE_MULTIBYTE) + mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); + target = _rl_vi_last_search_mbchar; +#else RL_SETSTATE(RL_STATE_MOREINPUT); _rl_vi_last_search_char = target = rl_read_key (); RL_UNSETSTATE(RL_STATE_MOREINPUT); +#endif } switch (key) @@ -1060,7 +1148,11 @@ rl_vi_char_search (count, key) } } +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (count, dir, target, mb_len)); +#else return (_rl_char_search_internal (count, dir, target)); +#endif } /* Match brackets */ @@ -1068,14 +1160,25 @@ int rl_vi_match (ignore, key) int ignore, key; { - int count = 1, brack, pos; + int count = 1, brack, pos, tmp, pre; pos = rl_point; if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) { - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && - rl_point < rl_end - 1) - rl_forward (1, key); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + pre = rl_point; + rl_forward_char (1, key); + if (pre == rl_point) + break; + } + } + else + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && + rl_point < rl_end - 1) + rl_forward_char (1, key); if (brack <= 0) { @@ -1091,7 +1194,16 @@ rl_vi_match (ignore, key) { while (count) { - if (--pos >= 0) + tmp = pos; + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos--; + else + { + pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); + if (tmp == pos) + pos--; + } + if (pos >= 0) { int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) @@ -1110,7 +1222,12 @@ rl_vi_match (ignore, key) { /* brack > 0 */ while (count) { - if (++pos < rl_end) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos++; + else + pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); + + if (pos < rl_end) { int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) @@ -1145,6 +1262,11 @@ rl_vi_bracktype (c) } } +/* XXX - think about reading an entire mbchar with _rl_read_mbchar and + inserting it in one bunch instead of the loop below (like in + rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] + for test against 033 or ^C. Make sure that _rl_read_mbchar does + this right. */ int rl_vi_change_char (count, key) int count, key; @@ -1168,9 +1290,19 @@ rl_vi_change_char (count, key) rl_begin_undo_group (); rl_delete (1, c); - rl_insert (1, c); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + while (_rl_insert_char (1, c)) + { + RL_SETSTATE (RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE (RL_STATE_MOREINPUT); + } + else +#endif + _rl_insert_char (1, c); if (count == 0) - rl_backward (1, c); + rl_backward_char (1, c); rl_end_undo_group (); } @@ -1181,66 +1313,29 @@ int rl_vi_subst (count, key) int count, key; { - rl_begin_undo_group (); - - if (_rl_uppercase_p (key)) - { - rl_beg_of_line (1, key); - rl_kill_line (1, key); - } - else - rl_delete_text (rl_point, rl_point+count); - - rl_end_undo_group (); - - _rl_vi_set_last (key, count, rl_arg_sign); + /* If we are redoing, rl_vi_change_to will stuff the last motion char */ + if (vi_redoing == 0) + rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ - if (vi_redoing) - { - int o = _rl_doing_an_undo; - - _rl_doing_an_undo = 1; - if (vi_insert_buffer && *vi_insert_buffer) - rl_insert_text (vi_insert_buffer); - _rl_doing_an_undo = o; - } - else - { - rl_begin_undo_group (); - _rl_vi_doing_insert = 1; - rl_vi_insertion_mode (1, key); - } - - return (0); + return (rl_vi_change_to (count, 'c')); } int rl_vi_overstrike (count, key) int count, key; { - int i; - if (_rl_vi_doing_insert == 0) { _rl_vi_doing_insert = 1; rl_begin_undo_group (); } - for (i = 0; i < count; i++) + if (count > 0) { - vi_replace_count++; - rl_begin_undo_group (); - - if (rl_point < rl_end) - { - rl_delete (1, key); - rl_insert (1, key); - } - else - rl_insert (1, key); - - rl_end_undo_group (); + _rl_overwrite_char (count, key); + vi_replace_count += count; } + return (0); } @@ -1263,7 +1358,7 @@ rl_vi_overstrike_delete (count, key) vi_replace_count--; if (rl_point == s) - rl_backward (1, key); + rl_backward_char (1, key); } if (vi_replace_count == 0 && _rl_vi_doing_insert) |