Merge in changes from bash-1.13. The most obvious one is
authorPer Bothner <per@bothner.com>
Sun, 16 Jan 1994 03:39:57 +0000 (03:39 +0000)
committerPer Bothner <per@bothner.com>
Sun, 16 Jan 1994 03:39:57 +0000 (03:39 +0000)
that the file readline.c has been split into multiple files.
* bind.c, complete.c, dispay.c, isearch.c, parens.c, rldefs.h,
rltty.c, search.c signals.c, tilde.c, tilde.h, xmalloc.c:  New files.

16 files changed:
readline/.Sanitize
readline/ChangeLog
readline/Makefile.in
readline/bind.c [new file with mode: 0644]
readline/chardefs.h
readline/complete.c [new file with mode: 0644]
readline/display.c [new file with mode: 0644]
readline/isearch.c [new file with mode: 0644]
readline/keymaps.h
readline/parens.c [new file with mode: 0644]
readline/readline.c
readline/rldefs.h [new file with mode: 0644]
readline/search.c [new file with mode: 0644]
readline/tilde.c [new file with mode: 0644]
readline/tilde.h [new file with mode: 0644]
readline/xmalloc.c [new file with mode: 0644]

index 82bc37a4819e42fc773706d8862d60a86b16e6b5..69bf4744b029cb1d49196552374611655f251850 100644 (file)
@@ -28,28 +28,40 @@ Things-to-keep:
 COPYING
 ChangeLog
 Makefile.in
-configure.bat
+bind.c
 chardefs.h
+complete.c
 config
+configure.bat
 configure.in
+display.c
 doc
 emacs_keymap.c
 examples
 funmap.c
 history.c
 history.h
+isearch.c
 keymaps.c
 keymaps.h
+parens.c
 readline.c
 readline.h
+rldefs.h
+rltty.c
+search.c
+signals.c
 sysdep-aix.h
 sysdep-irix.h
 sysdep-norm.h
 sysdep-obsd.h
 sysdep-sco.h
 sysdep-sysv4.h
+tilde.c
+tilde.h
 vi_keymap.c
 vi_mode.c
+xmalloc.c
 
 Things-to-lose:
 
index ccdb5abb9054be10205d9a1ff5a30bf777786f8f..1aa1e98b9465ce00f182e64f71dc0fcb2258fff0 100644 (file)
@@ -1,3 +1,10 @@
+Sat Jan 15 19:36:12 1994  Per Bothner  (bothner@kalessin.cygnus.com)
+
+       Merge in changes from bash-1.13.  The most obvious one is
+       that the file readline.c has been split into multiple files.
+       * bind.c, complete.c, dispay.c, isearch.c, parens.c, rldefs.h,
+       rltty.c, search.c signals.c, tilde.c, tilde.h, xmalloc.c:  New files.
+
 Sat Dec 11 16:29:17 1993  Steve Chamberlain  (sac@thepub.cygnus.com)
 
        * readline.c (rl_getc): If GO32, trim high bit from getkey,
index 635763e5952709c3696b42e9af7784ae8810a43b..05762db46ca6348ef78231bdfd371a598faa4629 100644 (file)
@@ -81,10 +81,22 @@ CP = cp
 
 LOCAL_INCLUDES = -I$(srcdir)/../
 
-CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \
-          emacs_keymap.c vi_keymap.c
+# The name of the main library target.
+LIBRARY_NAME = libreadline.a
+
+# The C code source files for this library.
+CSOURCES = readline.c funmap.c keymaps.c vi_mode.c parens.c \
+          rltty.c complete.c bind.c isearch.c display.c signals.c \
+          emacs_keymap.c vi_keymap.c history.c tilde.c xmalloc.c
+
+# The header files for this library.
+HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h \
+          posixstat.h tilde.h
+
+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 \
+         history.o tilde.o xmalloc.o
 
-HSOURCES = readline.h chardefs.h history.h keymaps.h
 SOURCES  = $(CSOURCES) $(HSOURCES)
 
 DOCUMENTATION = readline.texi inc-read.texi \
@@ -94,6 +106,17 @@ SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog
 
 THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
 
+FLAGS_TO_PASS = \
+       "prefix=$(prefix)" \
+       "exec_prefix=$(exec_prefix)" \
+       "against=$(against)" \
+       "MAKEINFO=$(MAKEINFO)" \
+       "INSTALL=$(INSTALL)" \
+       "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+       "INSTALL_DATA=$(INSTALL_DATA)"
+
+SUBDIRS = doc
+
 #### Host, target, and site specific Makefile fragments come in here.
 ###
 
@@ -106,11 +129,18 @@ all: libreadline.a
 
 check:
 installcheck:
-info:
-dvi:
 
-clean-info: force
-       -rm -f *.info*
+info dvi install-info clean-info: force
+       @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do
+
+subdir_do: force
+       @for i in $(DODIRS); do \
+               if [ -f ./$$i/Makefile ] ; then \
+                       if (cd ./$$i; \
+                               $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \
+                       else exit 1 ; fi ; \
+               else true ; fi ; \
+       done
 
 history.info: $(srcdir)/history.texi
        $(MAKEINFO) -o history.info $(srcdir)/history.texi
@@ -118,9 +148,9 @@ history.info: $(srcdir)/history.texi
 readline.info: $(srcdir)/readline.texi $(srcdir)/inc-read.texi
        $(MAKEINFO) -o readline.info $(srcdir)/readline.texi
 
-libreadline.a: readline.o history.o funmap.o keymaps.o tilde.o vi_mode.o
+libreadline.a: $(OBJECTS)
        $(RM) -f libreadline.a
-       $(AR) $(AR_FLAGS) libreadline.a readline.o history.o funmap.o keymaps.o tilde.o vi_mode.o
+       $(AR) $(AR_FLAGS) libreadline.a $(OBJECTS)
        $(RANLIB) libreadline.a
 
 readline.o:    readline.h chardefs.h  keymaps.h history.h readline.c vi_mode.c
@@ -146,35 +176,13 @@ readline.tar.Z:   readline.tar
                compress -f readline.tar
 
 install:
-               -parent=`echo $(libdir)|sed -e 's@/[^/]*$$@@'`; \
-               if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi
-               -if [ -d $(libdir) ] ; then true ; else mkdir $(libdir) ; fi
                $(INSTALL_DATA) libreadline.a $(libdir)/libreadline.a
                $(RANLIB) $(libdir)/libreadline.a
-               -parent=`echo $(includedir)|sed -e 's@/[^/]*$$@@'`; \
-               if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi
-               -if [ -d $(includedir) ] ; then true ; else mkdir $(includedir) ; fi
-               -if [ -d $(includedir)/readline ] ; then true ; else mkdir $(includedir)/readline ; fi
                $(INSTALL_DATA) $(srcdir)/readline.h $(includedir)/readline/readline.h
                $(INSTALL_DATA) $(srcdir)/keymaps.h $(includedir)/readline/keymaps.h
                $(INSTALL_DATA) $(srcdir)/chardefs.h $(includedir)/readline/chardefs.h
 
-install-info: info
-#              -parent=`echo $(infodir)|sed -e 's@/[^/]*$$@@'`; \
-#              if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi
-#              -if [ -d $(infodir) ] ; then true ; else mkdir $(infodir) ; fi
-#              for i in *.info* ; do \
-#                      $(INSTALL_DATA) $$i $(infodir)/$$i ; \
-#              done
-
 includes:
-               -parent=`echo $(includedir)|sed -e 's@/[^/]*$$@@'`; \
-               if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi
-               -if [ -d $(includedir) ] ; then true ; else mkdir $(includedir) ; fi
-               -if [ ! -r $(includedir)/readline ]; then\
-                mkdir $(includedir)/readline;\
-                chmod a+r $(includedir)/readline;\
-               fi
                $(INSTALL_FILE) $(srcdir)/readline.h $(includedir)/readline/readline.h
                $(INSTALL_FILE) $(srcdir)/keymaps.h $(includedir)/readline/keymaps.h
                $(INSTALL_FILE) $(srcdir)/chardefs.h $(includedir)/readline/chardefs.h
diff --git a/readline/bind.c b/readline/bind.c
new file mode 100644 (file)
index 0000000..a7ffe25
--- /dev/null
@@ -0,0 +1,1396 @@
+/* bind.c -- key binding and startup file support for the readline library. */
+
+/* Copyright (C) 1987, 1989, 1992 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 1, 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "sysdep.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef        NO_SYS_FILE
+#include <sys/file.h>
+#endif
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+extern char *tilde_expand ();
+
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_prefer_visible_bell;
+extern int _rl_meta_flag;
+extern int rl_blink_matching_paren;
+extern int _rl_convert_meta_chars_to_ascii;
+#if defined (VISIBLE_STATS)
+extern int rl_visible_stats;
+#endif /* VISIBLE_STATS */
+extern int rl_complete_with_tilde_expansion;
+extern int rl_completion_query_items;
+
+extern int rl_explicit_arg;
+extern int rl_editing_mode;
+extern unsigned short _rl_parsing_conditionalized_out;
+extern Keymap _rl_keymap;
+
+extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+
+extern char **rl_funmap_names ();
+
+static void rl_generic_bind ();
+static int glean_key_from_name ();
+static int stricmp (), strnicmp ();
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Binding keys                                */
+/*                                                                 */
+/* **************************************************************** */
+
+/* rl_add_defun (char *name, Function *function, int key)
+   Add NAME to the list of named functions.  Make FUNCTION be the function
+   that gets called.  If KEY is not -1, then bind it. */
+rl_add_defun (name, function, key)
+     char *name;
+     Function *function;
+     int key;
+{
+  if (key != -1)
+    rl_bind_key (key, function);
+  rl_add_funmap_entry (name, function);
+}
+
+/* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
+int
+rl_bind_key (key, function)
+     int key;
+     Function *function;
+{
+  if (key < 0)
+    return (key);
+
+  if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+    {
+      if (_rl_keymap[ESC].type == ISKMAP)
+       {
+         Keymap escmap = (Keymap)_rl_keymap[ESC].function;
+
+         key = UNMETA (key);
+         escmap[key].type = ISFUNC;
+         escmap[key].function = function;
+         return (0);
+       }
+      return (key);
+    }
+
+  _rl_keymap[key].type = ISFUNC;
+  _rl_keymap[key].function = function;
+  return (0);
+}
+
+/* Bind KEY to FUNCTION in MAP.  Returns non-zero in case of invalid
+   KEY. */
+int
+rl_bind_key_in_map (key, function, map)
+     int key;
+     Function *function;
+     Keymap map;
+{
+  int result;
+  Keymap oldmap = _rl_keymap;
+
+  _rl_keymap = map;
+  result = rl_bind_key (key, function);
+  _rl_keymap = oldmap;
+  return (result);
+}
+
+/* Make KEY do nothing in the currently selected keymap.
+   Returns non-zero in case of error. */
+int
+rl_unbind_key (key)
+     int key;
+{
+  return (rl_bind_key (key, (Function *)NULL));
+}
+
+/* Make KEY do nothing in MAP.
+   Returns non-zero in case of error. */
+int
+rl_unbind_key_in_map (key, map)
+     int key;
+     Keymap map;
+{
+  return (rl_bind_key_in_map (key, (Function *)NULL, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   FUNCTION.  This makes new keymaps as necessary.  The initial
+   place to do bindings is in MAP. */
+rl_set_key (keyseq, function, map)
+     char *keyseq;
+     Function *function;
+     Keymap map;
+{
+  rl_generic_bind (ISFUNC, keyseq, function, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   the string of characters MACRO.  This makes new keymaps as
+   necessary.  The initial place to do bindings is in MAP. */
+rl_macro_bind (keyseq, macro, map)
+     char *keyseq, *macro;
+     Keymap map;
+{
+  char *macro_keys;
+  int macro_keys_len;
+
+  macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1);
+
+  if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
+    {
+      free (macro_keys);
+      return;
+    }
+  rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   the arbitrary pointer DATA.  TYPE says what kind of data is
+   pointed to by DATA, right now this can be a function (ISFUNC),
+   a macro (ISMACR), or a keymap (ISKMAP).  This makes new keymaps
+   as necessary.  The initial place to do bindings is in MAP. */
+
+static void
+rl_generic_bind (type, keyseq, data, map)
+     int type;
+     char *keyseq, *data;
+     Keymap map;
+{
+  char *keys;
+  int keys_len;
+  register int i;
+
+  /* If no keys to bind to, exit right away. */
+  if (!keyseq || !*keyseq)
+    {
+      if (type == ISMACR)
+       free (data);
+      return;
+    }
+
+  keys = (char *)alloca (1 + (2 * strlen (keyseq)));
+
+  /* Translate the ASCII representation of KEYSEQ into an array of
+     characters.  Stuff the characters into KEYS, and the length of
+     KEYS into KEYS_LEN. */
+  if (rl_translate_keyseq (keyseq, keys, &keys_len))
+    return;
+
+  /* Bind keys, making new keymaps as necessary. */
+  for (i = 0; i < keys_len; i++)
+    {
+      int ic = (int) ((unsigned char)keys[i]);
+
+      if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic))
+       {
+         ic = UNMETA (ic);
+         if (map[ESC].type == ISKMAP)
+           map = (Keymap) map[ESC].function;
+       }
+
+      if ((i + 1) < keys_len)
+       {
+         if (map[ic].type != ISKMAP)
+           {
+             if (map[ic].type == ISMACR)
+               free ((char *)map[ic].function);
+
+             map[ic].type = ISKMAP;
+             map[ic].function = (Function *)rl_make_bare_keymap ();
+           }
+         map = (Keymap)map[ic].function;
+       }
+      else
+       {
+         if (map[ic].type == ISMACR)
+           free ((char *)map[ic].function);
+
+         map[ic].function = (Function *)data;
+         map[ic].type = type;
+       }
+    }
+}
+
+/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY,
+   an array of characters.  LEN gets the final length of ARRAY.  Return
+   non-zero if there was an error parsing SEQ. */
+rl_translate_keyseq (seq, array, len)
+     char *seq, *array;
+     int *len;
+{
+  register int i, c, l = 0;
+
+  for (i = 0; c = seq[i]; i++)
+    {
+      if (c == '\\')
+       {
+         c = seq[++i];
+
+         if (!c)
+           break;
+
+         if (((c == 'C' || c == 'M') &&  seq[i + 1] == '-') ||
+             (c == 'e'))
+           {
+             /* Handle special case of backwards define. */
+             if (strncmp (&seq[i], "C-\\M-", 5) == 0)
+               {
+                 array[l++] = ESC;
+                 i += 5;
+                 array[l++] = CTRL (to_upper (seq[i]));
+                 if (!seq[i])
+                   i--;
+                 continue;
+               }
+
+             switch (c)
+               {
+               case 'M':
+                 i++;
+                 array[l++] = ESC;
+                 break;
+
+               case 'C':
+                 i += 2;
+                 /* Special hack for C-?... */
+                 if (seq[i] == '?')
+                   array[l++] = RUBOUT;
+                 else
+                   array[l++] = CTRL (to_upper (seq[i]));
+                 break;
+
+               case 'e':
+                 array[l++] = ESC;
+               }
+
+             continue;
+           }
+       }
+      array[l++] = c;
+    }
+
+  *len = l;
+  array[l] = '\0';
+  return (0);
+}
+
+/* Return a pointer to the function that STRING represents.
+   If STRING doesn't have a matching function, then a NULL pointer
+   is returned. */
+Function *
+rl_named_function (string)
+     char *string;
+{
+  register int i;
+
+  rl_initialize_funmap ();
+
+  for (i = 0; funmap[i]; i++)
+    if (stricmp (funmap[i]->name, string) == 0)
+      return (funmap[i]->function);
+  return ((Function *)NULL);
+}
+
+/* Return the function (or macro) definition which would be invoked via
+   KEYSEQ if executed in MAP.  If MAP is NULL, then the current keymap is
+   used.  TYPE, if non-NULL, is a pointer to an int which will receive the
+   type of the object pointed to.  One of ISFUNC (function), ISKMAP (keymap),
+   or ISMACR (macro). */
+Function *
+rl_function_of_keyseq (keyseq, map, type)
+     char *keyseq;
+     Keymap map;
+     int *type;
+{
+  register int i;
+
+  if (!map)
+    map = _rl_keymap;
+
+  for (i = 0; keyseq && keyseq[i]; i++)
+    {
+      int ic = keyseq[i];
+
+      if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
+       {
+         if (map[ESC].type != ISKMAP)
+           {
+             if (type)
+               *type = map[ESC].type;
+
+             return (map[ESC].function);
+           }
+         else
+           {
+             map = (Keymap)map[ESC].function;
+             ic = UNMETA (ic);
+           }
+       }
+
+      if (map[ic].type == ISKMAP)
+       {
+         /* If this is the last key in the key sequence, return the
+            map. */
+         if (!keyseq[i + 1])
+           {
+             if (type)
+               *type = ISKMAP;
+
+             return (map[ic].function);
+           }
+         else
+           map = (Keymap)map[ic].function;
+       }
+      else
+       {
+         if (type)
+           *type = map[ic].type;
+
+         return (map[ic].function);
+       }
+    }
+}
+
+/* The last key bindings file read. */
+static char *last_readline_init_file = (char *)NULL;
+
+/* Re-read the current keybindings file. */
+rl_re_read_init_file (count, ignore)
+     int count, ignore;
+{
+  rl_read_init_file ((char *)NULL);
+}
+
+/* The final, last-ditch effort file name for an init file. */
+#ifdef __MSDOS__
+/* Don't know what to do, but this is a guess */
+#define DEFAULT_INPUTRC "/INPUTRC";
+#else
+#define DEFAULT_INPUTRC "~/.inputrc"
+#endif
+
+/* Do key bindings from a file.  If FILENAME is NULL it defaults
+   to `~/.inputrc'.  If the file existed and could be opened and
+   read, 0 is returned, otherwise errno is returned. */
+int
+rl_read_init_file (filename)
+     char *filename;
+{
+  register int i;
+  char *buffer, *openname, *line, *end;
+  struct stat finfo;
+  int file;
+
+  /* Default the filename. */
+  if (!filename)
+    {
+      if (last_readline_init_file)
+       filename = last_readline_init_file;
+      else
+       filename = DEFAULT_INPUTRC;
+    }
+
+  openname = tilde_expand (filename);
+
+  if (!openname || *openname == '\000')
+    return ENOENT;
+
+  if ((stat (openname, &finfo) < 0) ||
+      (file = open (openname, O_RDONLY, 0666)) < 0)
+    {
+      free (openname);
+      return (errno);
+    }
+  else
+    free (openname);
+
+  if (last_readline_init_file)
+    free (last_readline_init_file);
+
+  last_readline_init_file = savestring (filename);
+
+  /* Read the file into BUFFER. */
+  buffer = (char *)xmalloc ((int)finfo.st_size + 1);
+  i = read (file, buffer, finfo.st_size);
+  close (file);
+
+  if (i != finfo.st_size)
+    return (errno);
+
+  /* Loop over the lines in the file.  Lines that start with `#' are
+     comments; all other lines are commands for readline initialization. */
+  line = buffer;
+  end = buffer + finfo.st_size;
+  while (line < end)
+    {
+      /* Find the end of this line. */
+      for (i = 0; line + i != end && line[i] != '\n'; i++);
+
+      /* Mark end of line. */
+      line[i] = '\0';
+
+      /* If the line is not a comment, then parse it. */
+      if (*line && *line != '#')
+       rl_parse_and_bind (line);
+
+      /* Move to the next line. */
+      line += i + 1;
+    }
+  free (buffer);
+  return (0);
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Parser Directives                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Conditionals. */
+
+/* Calling programs set this to have their argv[0]. */
+char *rl_readline_name = "other";
+
+/* Stack of previous values of parsing_conditionalized_out. */
+static unsigned char *if_stack = (unsigned char *)NULL;
+static int if_stack_depth = 0;
+static int if_stack_size = 0;
+
+/* Push _rl_parsing_conditionalized_out, and set parser state based
+   on ARGS. */
+static int
+parser_if (args)
+     char *args;
+{
+  register int i;
+
+  /* Push parser state. */
+  if (if_stack_depth + 1 >= if_stack_size)
+    {
+      if (!if_stack)
+       if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
+      else
+       if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
+    }
+  if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out;
+
+  /* If parsing is turned off, then nothing can turn it back on except
+     for finding the matching endif.  In that case, return right now. */
+  if (_rl_parsing_conditionalized_out)
+    return 0;
+
+  /* Isolate first argument. */
+  for (i = 0; args[i] && !whitespace (args[i]); i++);
+
+  if (args[i])
+    args[i++] = '\0';
+
+  /* Handle "if term=foo" and "if mode=emacs" constructs.  If this
+     isn't term=foo, or mode=emacs, then check to see if the first
+     word in ARGS is the same as the value stored in rl_readline_name. */
+  if (rl_terminal_name && strnicmp (args, "term=", 5) == 0)
+    {
+      char *tem, *tname;
+
+      /* Terminals like "aaa-60" are equivalent to "aaa". */
+      tname = savestring (rl_terminal_name);
+      tem = (char*) strrchr (tname, '-');
+      if (tem)
+       *tem = '\0';
+
+      /* Test the `long' and `short' forms of the terminal name so that
+        if someone has a `sun-cmd' and does not want to have bindings
+        that will be executed if the terminal is a `sun', they can put
+        `$if term=sun-cmd' into their .inputrc. */
+      if ((stricmp (args + 5, tname) == 0) ||
+         (stricmp (args + 5, rl_terminal_name) == 0))
+       _rl_parsing_conditionalized_out = 0;
+      else
+       _rl_parsing_conditionalized_out = 1;
+
+      free (tname);
+    }
+#if defined (VI_MODE)
+  else if (strnicmp (args, "mode=", 5) == 0)
+    {
+      int mode;
+
+      if (stricmp (args + 5, "emacs") == 0)
+       mode = emacs_mode;
+      else if (stricmp (args + 5, "vi") == 0)
+       mode = vi_mode;
+      else
+       mode = no_mode;
+
+      if (mode == rl_editing_mode)
+       _rl_parsing_conditionalized_out = 0;
+      else
+       _rl_parsing_conditionalized_out = 1;
+    }
+#endif /* VI_MODE */
+  /* Check to see if the first word in ARGS is the same as the
+     value stored in rl_readline_name. */
+  else if (stricmp (args, rl_readline_name) == 0)
+    _rl_parsing_conditionalized_out = 0;
+  else
+    _rl_parsing_conditionalized_out = 1;
+  return 0;
+}
+
+/* Invert the current parser state if there is anything on the stack. */
+static int
+parser_else (args)
+     char *args;
+{
+  register int i;
+
+  if (!if_stack_depth)
+    {
+      /* Error message? */
+      return 0;
+    }
+
+  /* Check the previous (n - 1) levels of the stack to make sure that
+     we haven't previously turned off parsing. */
+  for (i = 0; i < if_stack_depth - 1; i++)
+    if (if_stack[i] == 1)
+      return 0;
+
+  /* Invert the state of parsing if at top level. */
+  _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out;
+  return 0;
+}
+
+/* Terminate a conditional, popping the value of
+   _rl_parsing_conditionalized_out from the stack. */
+static int
+parser_endif (args)
+     char *args;
+{
+  if (if_stack_depth)
+    _rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
+  else
+    {
+      /* *** What, no error message? *** */
+    }
+  return 0;
+}
+
+/* Associate textual names with actual functions. */
+static struct {
+  char *name;
+  Function *function;
+} parser_directives [] = {
+  { "if", parser_if },
+  { "endif", parser_endif },
+  { "else", parser_else },
+  { (char *)0x0, (Function *)0x0 }
+};
+
+/* Handle a parser directive.  STATEMENT is the line of the directive
+   without any leading `$'. */
+static int
+handle_parser_directive (statement)
+     char *statement;
+{
+  register int i;
+  char *directive, *args;
+
+  /* Isolate the actual directive. */
+
+  /* Skip whitespace. */
+  for (i = 0; whitespace (statement[i]); i++);
+
+  directive = &statement[i];
+
+  for (; statement[i] && !whitespace (statement[i]); i++);
+
+  if (statement[i])
+    statement[i++] = '\0';
+
+  for (; statement[i] && whitespace (statement[i]); i++);
+
+  args = &statement[i];
+
+  /* Lookup the command, and act on it. */
+  for (i = 0; parser_directives[i].name; i++)
+    if (stricmp (directive, parser_directives[i].name) == 0)
+      {
+       (*parser_directives[i].function) (args);
+       return (0);
+      }
+
+  /* *** Should an error message be output? */
+  return (1);
+}
+
+/* Ugly but working hack for binding prefix meta. */
+#define PREFIX_META_HACK
+
+static int substring_member_of_array ();
+
+/* Read the binding command from STRING and perform it.
+   A key binding command looks like: Keyname: function-name\0,
+   a variable binding command looks like: set variable value.
+   A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
+rl_parse_and_bind (string)
+     char *string;
+{
+  char *funname, *kname;
+  register int c, i;
+  int key, equivalency;
+
+  while (string && whitespace (*string))
+    string++;
+
+  if (!string || !*string || *string == '#')
+    return;
+
+  /* If this is a parser directive, act on it. */
+  if (*string == '$')
+    {
+      handle_parser_directive (&string[1]);
+      return;
+    }
+
+  /* If we aren't supposed to be parsing right now, then we're done. */
+  if (_rl_parsing_conditionalized_out)
+    return;
+
+  i = 0;
+  /* If this keyname is a complex key expression surrounded by quotes,
+     advance to after the matching close quote.  This code allows the
+     backslash to quote characters in the key expression. */
+  if (*string == '"')
+    {
+      int passc = 0;
+
+      for (i = 1; c = string[i]; i++)
+       {
+         if (passc)
+           {
+             passc = 0;
+             continue;
+           }
+
+         if (c == '\\')
+           {
+             passc++;
+             continue;
+           }
+
+         if (c == '"')
+           break;
+       }
+    }
+
+  /* Advance to the colon (:) or whitespace which separates the two objects. */
+  for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
+
+  equivalency = (c == ':' && string[i + 1] == '=');
+
+  /* Mark the end of the command (or keyname). */
+  if (string[i])
+    string[i++] = '\0';
+
+  /* If doing assignment, skip the '=' sign as well. */
+  if (equivalency)
+    string[i++] = '\0';
+
+  /* If this is a command to set a variable, then do that. */
+  if (stricmp (string, "set") == 0)
+    {
+      char *var = string + i;
+      char *value;
+
+      /* Make VAR point to start of variable name. */
+      while (*var && whitespace (*var)) var++;
+
+      /* Make value point to start of value string. */
+      value = var;
+      while (*value && !whitespace (*value)) value++;
+      if (*value)
+       *value++ = '\0';
+      while (*value && whitespace (*value)) value++;
+
+      rl_variable_bind (var, value);
+      return;
+    }
+
+  /* Skip any whitespace between keyname and funname. */
+  for (; string[i] && whitespace (string[i]); i++);
+  funname = &string[i];
+
+  /* Now isolate funname.
+     For straight function names just look for whitespace, since
+     that will signify the end of the string.  But this could be a
+     macro definition.  In that case, the string is quoted, so skip
+     to the matching delimiter.  We allow the backslash to quote the
+     delimiter characters in the macro body. */
+  /* This code exists to allow whitespace in macro expansions, which
+     would otherwise be gobbled up by the next `for' loop.*/
+  /* XXX - it may be desirable to allow backslash quoting only if " is
+     the quoted string delimiter, like the shell. */
+  if (*funname == '\'' || *funname == '"')
+    {
+      int delimiter = string[i++];
+      int passc = 0;
+
+      for (; c = string[i]; i++)
+       {
+         if (passc)
+           {
+             passc = 0;
+             continue;
+           }
+
+         if (c == '\\')
+           {
+             passc = 1;
+             continue;
+           }
+
+         if (c == delimiter)
+           break;
+       }
+      if (c)
+       i++;
+    }
+
+  /* Advance to the end of the string.  */
+  for (; string[i] && !whitespace (string[i]); i++);
+
+  /* No extra whitespace at the end of the string. */
+  string[i] = '\0';
+
+  /* Handle equivalency bindings here.  Make the left-hand side be exactly
+     whatever the right-hand evaluates to, including keymaps. */
+  if (equivalency)
+    {
+      return;
+    }
+
+  /* If this is a new-style key-binding, then do the binding with
+     rl_set_key ().  Otherwise, let the older code deal with it. */
+  if (*string == '"')
+    {
+      char *seq = (char *)alloca (1 + strlen (string));
+      register int j, k = 0;
+      int passc = 0;
+
+      for (j = 1; string[j]; j++)
+       {
+         /* Allow backslash to quote characters, but leave them in place.
+            This allows a string to end with a backslash quoting another
+            backslash, or with a backslash quoting a double quote.  The
+            backslashes are left in place for rl_translate_keyseq (). */
+         if (passc || (string[j] == '\\'))
+           {
+             seq[k++] = string[j];
+             passc = !passc;
+             continue;
+           }
+
+         if (string[j] == '"')
+           break;
+
+         seq[k++] = string[j];
+       }
+      seq[k] = '\0';
+
+      /* Binding macro? */
+      if (*funname == '\'' || *funname == '"')
+       {
+         j = strlen (funname);
+
+         /* Remove the delimiting quotes from each end of FUNNAME. */
+         if (j && funname[j - 1] == *funname)
+           funname[j - 1] = '\0';
+
+         rl_macro_bind (seq, &funname[1], _rl_keymap);
+       }
+      else
+       rl_set_key (seq, rl_named_function (funname), _rl_keymap);
+
+      return;
+    }
+
+  /* Get the actual character we want to deal with. */
+  kname = (char*) strrchr (string, '-');
+  if (!kname)
+    kname = string;
+  else
+    kname++;
+
+  key = glean_key_from_name (kname);
+
+  /* Add in control and meta bits. */
+  if (substring_member_of_array (string, possible_control_prefixes))
+    key = CTRL (to_upper (key));
+
+  if (substring_member_of_array (string, possible_meta_prefixes))
+    key = META (key);
+
+  /* Temporary.  Handle old-style keyname with macro-binding. */
+  if (*funname == '\'' || *funname == '"')
+    {
+      char seq[2];
+      int fl = strlen (funname);
+
+      seq[0] = key; seq[1] = '\0';
+      if (fl && funname[fl - 1] == *funname)
+       funname[fl - 1] = '\0';
+
+      rl_macro_bind (seq, &funname[1], _rl_keymap);
+    }
+#if defined (PREFIX_META_HACK)
+  /* Ugly, but working hack to keep prefix-meta around. */
+  else if (stricmp (funname, "prefix-meta") == 0)
+    {
+      char seq[2];
+
+      seq[0] = key;
+      seq[1] = '\0';
+      rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap);
+    }
+#endif /* PREFIX_META_HACK */
+  else
+    rl_bind_key (key, rl_named_function (funname));
+}
+
+/* Simple structure for boolean readline variables (i.e., those that can
+   have one of two values; either "On" or 1 for truth, or "Off" or 0 for
+   false. */
+
+static struct {
+  char *name;
+  int *value;
+} boolean_varlist [] = {
+  { "horizontal-scroll-mode",  &_rl_horizontal_scroll_mode },
+  { "mark-modified-lines",     &_rl_mark_modified_lines },
+  { "prefer-visible-bell",     &_rl_prefer_visible_bell },
+  { "meta-flag",               &_rl_meta_flag },
+  { "blink-matching-paren",    &rl_blink_matching_paren },
+  { "convert-meta",            &_rl_convert_meta_chars_to_ascii },
+#if defined (VISIBLE_STATS)
+  { "visible-stats",           &rl_visible_stats },
+#endif /* VISIBLE_STATS */
+  { "expand-tilde",            &rl_complete_with_tilde_expansion },
+  { (char *)NULL, (int *)NULL }
+};
+
+rl_variable_bind (name, value)
+     char *name, *value;
+{
+  register int i;
+
+  /* Check for simple variables first. */
+  for (i = 0; boolean_varlist[i].name; i++)
+    {
+      if (stricmp (name, boolean_varlist[i].name) == 0)
+       {
+         /* A variable is TRUE if the "value" is "on", "1" or "". */
+         if ((!*value) ||
+             (stricmp (value, "On") == 0) ||
+             (value[0] == '1' && value[1] == '\0'))
+           *boolean_varlist[i].value = 1;
+         else
+           *boolean_varlist[i].value = 0;
+         return;
+       }
+    }
+
+  /* Not a boolean variable, so check for specials. */
+
+  /* Editing mode change? */
+  if (stricmp (name, "editing-mode") == 0)
+    {
+      if (strnicmp (value, "vi", 2) == 0)
+       {
+#if defined (VI_MODE)
+         _rl_keymap = vi_insertion_keymap;
+         rl_editing_mode = vi_mode;
+#else
+#if defined (NOTDEF)
+         /* What state is the terminal in?  I'll tell you:
+            non-determinate!  That means we cannot do any output. */
+         ding ();
+#endif /* NOTDEF */
+#endif /* VI_MODE */
+       }
+      else if (strnicmp (value, "emacs", 5) == 0)
+       {
+         _rl_keymap = emacs_standard_keymap;
+         rl_editing_mode = emacs_mode;
+       }
+    }
+
+  /* Comment string change? */
+  else if (stricmp (name, "comment-begin") == 0)
+    {
+#if defined (VI_MODE)
+      extern char *rl_vi_comment_begin;
+
+      if (*value)
+       {
+         if (rl_vi_comment_begin)
+           free (rl_vi_comment_begin);
+
+         rl_vi_comment_begin = savestring (value);
+       }
+#endif /* VI_MODE */
+    }
+  else if (stricmp (name, "completion-query-items") == 0)
+    {
+      int nval = 100;
+      if (*value)
+       {
+         nval = atoi (value);
+         if (nval < 0)
+           nval = 0;
+       }
+      rl_completion_query_items = nval;
+    }
+}
+
+/* Return the character which matches NAME.
+   For example, `Space' returns ' '. */
+
+typedef struct {
+  char *name;
+  int value;
+} assoc_list;
+
+static assoc_list name_key_alist[] = {
+  { "DEL", 0x7f },
+  { "ESC", '\033' },
+  { "Escape", '\033' },
+  { "LFD", '\n' },
+  { "Newline", '\n' },
+  { "RET", '\r' },
+  { "Return", '\r' },
+  { "Rubout", 0x7f },
+  { "SPC", ' ' },
+  { "Space", ' ' },
+  { "Tab", 0x09 },
+  { (char *)0x0, 0 }
+};
+
+static int
+glean_key_from_name (name)
+     char *name;
+{
+  register int i;
+
+  for (i = 0; name_key_alist[i].name; i++)
+    if (stricmp (name, name_key_alist[i].name) == 0)
+      return (name_key_alist[i].value);
+
+  return (*(unsigned char *)name);     /* XXX was return (*name) */
+}
+
+/* Auxiliary functions to manage keymaps. */
+static struct {
+  char *name;
+  Keymap map;
+} keymap_names[] = {
+  { "emacs", emacs_standard_keymap },
+  { "emacs-standard", emacs_standard_keymap },
+  { "emacs-meta", emacs_meta_keymap },
+  { "emacs-ctlx", emacs_ctlx_keymap },
+#if defined (VI_MODE)
+  { "vi", vi_movement_keymap },
+  { "vi-move", vi_movement_keymap },
+  { "vi-command", vi_movement_keymap },
+  { "vi-insert", vi_insertion_keymap },
+#endif /* VI_MODE */
+  { (char *)0x0, (Keymap)0x0 }
+};
+
+Keymap
+rl_get_keymap_by_name (name)
+     char *name;
+{
+  register int i;
+
+  for (i = 0; keymap_names[i].name; i++)
+    if (strcmp (name, keymap_names[i].name) == 0)
+      return (keymap_names[i].map);
+  return ((Keymap) NULL);
+}
+
+void
+rl_set_keymap (map)
+     Keymap map;
+{
+  if (map)
+    _rl_keymap = map;
+}
+
+Keymap
+rl_get_keymap ()
+{
+  return (_rl_keymap);
+}
+
+void
+rl_set_keymap_from_edit_mode ()
+{
+  if (rl_editing_mode == emacs_mode)
+    _rl_keymap = emacs_standard_keymap;
+  else if (rl_editing_mode == vi_mode)
+    _rl_keymap = vi_insertion_keymap;
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*               Key Binding and Function Information              */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Each of the following functions produces information about the
+   state of keybindings and functions known to Readline.  The info
+   is always printed to rl_outstream, and in such a way that it can
+   be read back in (i.e., passed to rl_parse_and_bind (). */
+
+/* Print the names of functions known to Readline. */
+void
+rl_list_funmap_names (ignore)
+     int ignore;
+{
+  register int i;
+  char **funmap_names;
+
+  funmap_names = rl_funmap_names ();
+
+  if (!funmap_names)
+    return;
+
+  for (i = 0; funmap_names[i]; i++)
+    fprintf (rl_outstream, "%s\n", funmap_names[i]);
+
+  free (funmap_names);
+}
+
+/* Return a NULL terminated array of strings which represent the key
+   sequences that are used to invoke FUNCTION in MAP. */
+static char **
+invoking_keyseqs_in_map (function, map)
+     Function *function;
+     Keymap map;
+{
+  register int key;
+  char **result;
+  int result_index, result_size;
+
+  result = (char **)NULL;
+  result_index = result_size = 0;
+
+  for (key = 0; key < 128; key++)
+    {
+      switch (map[key].type)
+       {
+       case ISMACR:
+         /* Macros match, if, and only if, the pointers are identical.
+            Thus, they are treated exactly like functions in here. */
+       case ISFUNC:
+         /* If the function in the keymap is the one we are looking for,
+            then add the current KEY to the list of invoking keys. */
+         if (map[key].function == function)
+           {
+             char *keyname = (char *)xmalloc (5);
+
+             if (CTRL_P (key))
+               sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
+             else if (key == RUBOUT)
+               sprintf (keyname, "\\C-?");
+             else if (key == '\\' || key == '"')
+               {
+                 keyname[0] = '\\';
+                 keyname[1] = (char) key;
+                 keyname[2] = '\0';
+               }
+             else
+               {
+                 keyname[0] = (char) key;
+                 keyname[1] = '\0';
+               }
+
+             if (result_index + 2 > result_size)
+               result = (char **) xrealloc
+                 (result, (result_size += 10) * sizeof (char *));
+
+             result[result_index++] = keyname;
+             result[result_index] = (char *)NULL;
+           }
+         break;
+
+       case ISKMAP:
+         {
+           char **seqs = (char **)NULL;
+
+           /* Find the list of keyseqs in this map which have FUNCTION as
+              their target.  Add the key sequences found to RESULT. */
+           if (map[key].function)
+             seqs =
+               invoking_keyseqs_in_map (function, (Keymap)map[key].function);
+
+           if (seqs)
+             {
+               register int i;
+
+               for (i = 0; seqs[i]; i++)
+                 {
+                   char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
+
+                   if (key == ESC)
+                     sprintf (keyname, "\\e");
+                   else if (CTRL_P (key))
+                     sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
+                   else if (key == RUBOUT)
+                     sprintf (keyname, "\\C-?");
+                   else if (key == '\\' || key == '"')
+                     {
+                       keyname[0] = '\\';
+                       keyname[1] = (char) key;
+                       keyname[2] = '\0';
+                     }
+                   else
+                     {
+                       keyname[0] = (char) key;
+                       keyname[1] = '\0';
+                     }
+
+                   strcat (keyname, seqs[i]);
+
+                   if (result_index + 2 > result_size)
+                     result = (char **) xrealloc
+                       (result, (result_size += 10) * sizeof (char *));
+
+                   result[result_index++] = keyname;
+                   result[result_index] = (char *)NULL;
+                 }
+             }
+         }
+         break;
+       }
+    }
+  return (result);
+}
+
+/* Return a NULL terminated array of strings which represent the key
+   sequences that can be used to invoke FUNCTION using the current keymap. */
+char **
+rl_invoking_keyseqs (function)
+     Function *function;
+{
+  return (invoking_keyseqs_in_map (function, _rl_keymap));
+}
+
+/* Print all of the current functions and their bindings to
+   rl_outstream.  If an explicit argument is given, then print
+   the output in such a way that it can be read back in. */
+int
+rl_dump_functions (count)
+     int count;
+{
+  void rl_function_dumper ();
+
+  rl_function_dumper (rl_explicit_arg);
+  rl_on_new_line ();
+  return (0);
+}
+
+/* Print all of the functions and their bindings to rl_outstream.  If
+   PRINT_READABLY is non-zero, then print the output in such a way
+   that it can be read back in. */
+void
+rl_function_dumper (print_readably)
+     int print_readably;
+{
+  register int i;
+  char **names;
+  char *name;
+
+  names = rl_funmap_names ();
+
+  fprintf (rl_outstream, "\n");
+
+  for (i = 0; name = names[i]; i++)
+    {
+      Function *function;
+      char **invokers;
+
+      function = rl_named_function (name);
+      invokers = invoking_keyseqs_in_map (function, _rl_keymap);
+
+      if (print_readably)
+       {
+         if (!invokers)
+           fprintf (rl_outstream, "# %s (not bound)\n", name);
+         else
+           {
+             register int j;
+
+             for (j = 0; invokers[j]; j++)
+               {
+                 fprintf (rl_outstream, "\"%s\": %s\n",
+                          invokers[j], name);
+                 free (invokers[j]);
+               }
+
+             free (invokers);
+           }
+       }
+      else
+       {
+         if (!invokers)
+           fprintf (rl_outstream, "%s is not bound to any keys\n",
+                    name);
+         else
+           {
+             register int j;
+
+             fprintf (rl_outstream, "%s can be found on ", name);
+
+             for (j = 0; invokers[j] && j < 5; j++)
+               {
+                 fprintf (rl_outstream, "\"%s\"%s", invokers[j],
+                          invokers[j + 1] ? ", " : ".\n");
+               }
+
+             if (j == 5 && invokers[j])
+               fprintf (rl_outstream, "...\n");
+
+             for (j = 0; invokers[j]; j++)
+               free (invokers[j]);
+
+             free (invokers);
+           }
+       }
+    }
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     String Utility Functions                    */
+/*                                                                 */
+/* **************************************************************** */
+
+static char *strindex ();
+
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+     char *string, **array;
+{
+  while (*array)
+    {
+      if (strindex (string, *array))
+       return (1);
+      array++;
+    }
+  return (0);
+}
+
+/* Whoops, Unix doesn't have strnicmp. */
+
+/* Compare at most COUNT characters from string1 to string2.  Case
+   doesn't matter. */
+static int
+strnicmp (string1, string2, count)
+     char *string1, *string2;
+{
+  register char ch1, ch2;
+
+  while (count)
+    {
+      ch1 = *string1++;
+      ch2 = *string2++;
+      if (to_upper(ch1) == to_upper(ch2))
+       count--;
+      else break;
+    }
+  return (count);
+}
+
+/* strcmp (), but caseless. */
+static int
+stricmp (string1, string2)
+     char *string1, *string2;
+{
+  register char ch1, ch2;
+
+  while (*string1 && *string2)
+    {
+      ch1 = *string1++;
+      ch2 = *string2++;
+      if (to_upper(ch1) != to_upper(ch2))
+       return (1);
+    }
+  return (*string1 | *string2);
+}
+
+/* Determine if s2 occurs in s1.  If so, return a pointer to the
+   match in s1.  The compare is case insensitive. */
+static char *
+strindex (s1, s2)
+     register char *s1, *s2;
+{
+  register int i, l = strlen (s2);
+  register int len = strlen (s1);
+
+  for (i = 0; (len - i) >= l; i++)
+    if (strnicmp (&s1[i], s2, l) == 0)
+      return (s1 + i);
+  return ((char *)NULL);
+}
index 9749ae489f468175f2bb9c51906db85a0e1d6da7..43d8539c79c4ce9b0ee516b1b91c79aa10c44410 100644 (file)
@@ -1,8 +1,21 @@
 /* chardefs.h -- Character definitions for readline. */
 #ifndef _CHARDEFS_
+#define _CHARDEFS_
+
+#include <ctype.h>
+
+#if defined (HAVE_STRING_H)
+#  include <string.h>
+#else
+#  include <strings.h>
+#endif /* HAVE_STRING_H */
 
 #ifndef savestring
-#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+extern char *xmalloc ();
+#  ifndef strcpy
+extern char *strcpy ();
+#  endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
 #endif
 
 #ifndef whitespace
 #endif
 
 /* Some character stuff. */
-#define control_character_threshold 0x020   /* smaller than this is control */
-#define meta_character_threshold 0x07f     /* larger than this is Meta. */
+#define control_character_threshold 0x020   /* Smaller than this is control. */
+#define meta_character_threshold 0x07f     /* Larger than this is Meta. */
 #define control_character_bit 0x40         /* 0x000000, must be off. */
 #define meta_character_bit 0x080           /* x0000000, must be on. */
+#define largest_char 255                   /* Largest character value. */
 
+#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
 #define CTRL(c) ((c) & (~control_character_bit))
 #define META(c) ((c) | meta_character_bit)
 
 #define CTRL_P(c) ((c) < control_character_threshold)
 #define META_P(c) ((c) > meta_character_threshold)
 
+#ifndef NEWLINE
 #define NEWLINE '\n'
+#endif
+
+#ifndef RETURN
 #define RETURN CTRL('M')
+#endif
+
+#ifndef RUBOUT
 #define RUBOUT 0x07f
+#endif
+
+#ifndef TAB
 #define TAB '\t'
+#endif
+
+#ifdef ABORT_CHAR
+#undef ABORT_CHAR
+#endif
 #define ABORT_CHAR CTRL('G')
+
+#ifdef PAGE
+#undef PAGE
+#endif
 #define PAGE CTRL('L')
+
+#ifdef SPACE
+#undef SPACE
+#endif
 #define SPACE 0x020
+
+#ifdef ESC
+#undef ESC
+#endif
+
 #define ESC CTRL('[')
 
 #endif  /* _CHARDEFS_ */
diff --git a/readline/complete.c b/readline/complete.c
new file mode 100644 (file)
index 0000000..7b733a3
--- /dev/null
@@ -0,0 +1,1205 @@
+/* complete.c -- filename completion for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 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 1, 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "sysdep.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if !defined (NO_SYS_FILE)
+#  include <sys/file.h>
+#endif /* !NO_SYS_FILE */
+
+#include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* These next are for filename completion.  Perhaps this belongs
+   in a different place. */
+#ifndef __MSDOS__
+#include <pwd.h>
+#endif /* __MSDOS__ */
+#if defined (USG) && !defined (isc386) && !defined (sgi)
+extern struct passwd *getpwuid (), *getpwent ();
+#endif
+#if defined (isc386) && !defined (__STDC__) && defined (_POSIX_SOURCE)
+extern struct passwd *getpwent ();
+#endif
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+
+#if !defined (strchr)
+extern char *strchr ();
+#endif /* !strchr */
+#if !defined (strrchr)
+extern char *strrchr ();
+#endif /* !strrchr*/
+
+extern char *tilde_expand ();
+extern char *rl_copy_text ();
+
+extern Function *rl_last_func;
+extern int rl_editing_mode;
+extern int screenwidth;
+
+static int compare_strings ();
+static char *rl_strpbrk ();
+
+#if defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
+\f
+/* If non-zero, then this is the address of a function to call when
+   completing on a directory name.  The function is called with
+   the address of a string (the current directory name) as an arg. */
+Function *rl_symbolic_link_hook = (Function *)NULL;
+
+/* Non-zero means readline completion functions perform tilde expansion. */
+int rl_complete_with_tilde_expansion = 0;
+
+#define VISIBLE_STATS
+
+#if defined (VISIBLE_STATS)
+static int stat_char ();
+
+/* Non-zero means add an additional character to each filename displayed
+   during listing completion iff rl_filename_completion_desired which helps
+   to indicate the type of file being listed. */
+int rl_visible_stats = 0;
+#endif /* VISIBLE_STATS */
+
+/* **************************************************************** */
+/*                                                                 */
+/*     Completion matching, from readline's point of view.         */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Pointer to the generator function for completion_matches ().
+   NULL means to use filename_entry_function (), the default filename
+   completer. */
+Function *rl_completion_entry_function = (Function *)NULL;
+
+/* Pointer to alternative function to create matches.
+   Function is called with TEXT, START, and END.
+   START and END are indices in RL_LINE_BUFFER saying what the boundaries
+   of TEXT are.
+   If this function exists and returns NULL then call the value of
+   rl_completion_entry_function to try to match, otherwise use the
+   array of strings returned. */
+Function *rl_attempted_completion_function = (Function *)NULL;
+
+/* Local variable states what happened during the last completion attempt. */
+static int completion_changed_buffer = 0;
+
+/* Complete the word at or before point.  You have supplied the function
+   that does the initial simple matching selection algorithm (see
+   completion_matches ()).  The default is to do filename completion. */
+
+rl_complete (ignore, invoking_key)
+     int ignore, invoking_key;
+{
+  if (rl_last_func == rl_complete && !completion_changed_buffer)
+    rl_complete_internal ('?');
+  else
+    rl_complete_internal (TAB);
+}
+
+/* List the possible completions.  See description of rl_complete (). */
+rl_possible_completions (ignore, invoking_key)
+{
+  rl_complete_internal ('?');
+}
+
+rl_insert_completions (ignore, invoking_key)
+     int ignore, invoking_key;
+{
+  rl_complete_internal ('*');
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed. */
+get_y_or_n ()
+{
+  int c;
+
+  for (;;)
+    {
+      c = rl_read_key ();
+      if (c == 'y' || c == 'Y')
+       return (1);
+      if (c == 'n' || c == 'N')
+       return (0);
+      if (c == ABORT_CHAR)
+       rl_abort ();
+      ding ();
+    }
+}
+
+/* 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. */
+int rl_completion_query_items = 100;
+
+/* 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\"\\'`@$><=" */
+char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
+
+/* The list of characters that signal a break between words for
+   rl_complete_internal.  The default list is the contents of
+   rl_basic_word_break_characters.  */
+char *rl_completer_word_break_characters = (char *)NULL;
+
+/* List of characters which can be used to quote a substring of the line.
+   Completion occurs on the entire substring, and within the substring
+   rl_completer_word_break_characters are treated as any other character,
+   unless they also appear within this list. */
+char *rl_completer_quote_characters = (char *)NULL;
+
+/* List of characters that are word break characters, but should be left
+   in TEXT when it is passed to the completion function.  The shell uses
+   this to help determine what kind of completing to do. */
+char *rl_special_prefixes = (char *)NULL;
+
+/* If non-zero, then disallow duplicates in the matches. */
+int rl_ignore_completion_duplicates = 1;
+
+/* Non-zero means that the results of the matches are to be treated
+   as filenames.  This is ALWAYS zero on entry, and can only be changed
+   within a completion entry finder function. */
+int rl_filename_completion_desired = 0;
+
+/* 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 (char**) known as matches in the code below.
+   It consists of a NULL-terminated array of pointers to potential
+   matching strings.  The 1st element (matches[0]) is the maximal
+   substring that is common to all matches. This function can re-arrange
+   the list of matches as required, but all elements of the array must be
+   free()'d if they are deleted. The main intent of this function is
+   to implement FIGNORE a la SunOS csh. */
+Function *rl_ignore_some_completions_function = (Function *)NULL;
+
+/* Complete the word at or before point.
+   WHAT_TO_DO says what to do with the completion.
+   `?' means list the possible completions.
+   TAB means do standard completion.
+   `*' means insert all of the possible completions. */
+rl_complete_internal (what_to_do)
+     int what_to_do;
+{
+  char *filename_completion_function ();
+  char **completion_matches (), **matches;
+  Function *our_func;
+  int start, scan, end, delimiter = 0;
+  char *text, *saved_line_buffer;
+  char quote_char = '\0';
+  char *replacement;
+
+  if (rl_line_buffer)
+    saved_line_buffer = savestring (rl_line_buffer);
+  else
+    saved_line_buffer = (char *)NULL;
+
+  if (rl_completion_entry_function)
+    our_func = rl_completion_entry_function;
+  else
+    our_func = (int (*)())filename_completion_function;
+
+  /* Only the completion entry function can change this. */
+  rl_filename_completion_desired = 0;
+
+  /* We now look backwards for the start of a filename/variable word. */
+  end = rl_point;
+
+  if (rl_point)
+    {
+      if (rl_completer_quote_characters)
+       {
+         /* We have a list of characters which can be used in pairs to
+            quote substrings for the completer.  Try to find the start
+            of an unclosed quoted substring.
+            [FIXME: Doesn't yet handle '\' escapes to quote quotes. */
+         for (scan = 0; scan < end; scan++)
+           {
+             if (quote_char != '\0')
+               {
+                 /* Ignore everything until the matching close quote char. */
+                 if (rl_line_buffer[scan] == quote_char)
+                   {
+                     /* Found matching close quote. Abandon this substring. */
+                     quote_char = '\0';
+                     rl_point = end;
+                   }
+               }
+             else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan]))
+               {
+                 /* Found start of a quoted substring. */
+                 quote_char = rl_line_buffer[scan];
+                 rl_point = scan + 1;
+               }
+           }
+       }
+      if (rl_point == end)
+       {
+         /* 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 do completion. */
+         while (--rl_point &&
+                !strchr (rl_completer_word_break_characters,
+                         rl_line_buffer[rl_point])) {;}
+       }
+
+      /* If we are at a word break, then advance past it. */
+      if (strchr (rl_completer_word_break_characters, rl_line_buffer[rl_point]))
+       {
+         /* If the character that caused the word break was a quoting
+            character, then remember it as the delimiter. */
+         if (strchr ("\"'", rl_line_buffer[rl_point]) && (end - rl_point) > 1)
+           delimiter = rl_line_buffer[rl_point];
+
+         /* If the character isn't needed to determine something special
+            about what kind of completion to perform, then advance past it. */
+
+         if (!rl_special_prefixes ||
+             !strchr (rl_special_prefixes, rl_line_buffer[rl_point]))
+           rl_point++;
+       }
+    }
+
+  start = rl_point;
+  rl_point = end;
+  text = rl_copy_text (start, end);
+
+  /* If the user wants to TRY to complete, but then wants to give
+     up and use the default completion function, they set the
+     variable rl_attempted_completion_function. */
+  if (rl_attempted_completion_function)
+    {
+      matches =
+       (char **)(*rl_attempted_completion_function) (text, start, end);
+
+      if (matches)
+       {
+         if (matches == (char **)-1)
+           matches = (char **)NULL;
+         our_func = (Function *)NULL;
+         goto after_usual_completion;
+       }
+    }
+
+  matches = completion_matches (text, our_func);
+
+ after_usual_completion:
+  free (text);
+
+  if (!matches)
+    ding ();
+  else
+    {
+      register int i;
+
+    some_matches:
+
+      /* It seems to me that in all the cases we handle we would like
+        to ignore duplicate possibilities.   Scan for the text to
+        insert being identical to the other completions. */
+      if (rl_ignore_completion_duplicates)
+       {
+         char *lowest_common;
+         int j, newlen = 0;
+
+         /* Sort the items. */
+         /* It is safe to sort this array, because the lowest common
+            denominator found in matches[0] will remain in place. */
+         for (i = 0; matches[i]; i++);
+         qsort (matches, i, sizeof (char *), compare_strings);
+
+         /* Remember the lowest common denominator for it may be unique. */
+         lowest_common = savestring (matches[0]);
+
+         for (i = 0; matches[i + 1]; i++)
+           {
+             if (strcmp (matches[i], matches[i + 1]) == 0)
+               {
+                 free (matches[i]);
+                 matches[i] = (char *)-1;
+               }
+             else
+               newlen++;
+           }
+
+         /* We have marked all the dead slots with (char *)-1.
+            Copy all the non-dead entries into a new array. */
+         {
+           char **temp_array =
+             (char **)xmalloc ((3 + newlen) * sizeof (char *));
+
+           for (i = 1, j = 1; matches[i]; i++)
+             {
+               if (matches[i] != (char *)-1)
+                 temp_array[j++] = matches[i];
+             }
+
+           temp_array[j] = (char *)NULL;
+
+           if (matches[0] != (char *)-1)
+             free (matches[0]);
+
+           free (matches);
+
+           matches = temp_array;
+         }
+
+         /* Place the lowest common denominator back in [0]. */
+         matches[0] = lowest_common;
+
+         /* If there is one string left, and it is identical to the
+            lowest common denominator, then the LCD is the string to
+            insert. */
+         if (j == 2 && strcmp (matches[0], matches[1]) == 0)
+           {
+             free (matches[1]);
+             matches[1] = (char *)NULL;
+           }
+       }
+
+      switch (what_to_do)
+       {
+       case TAB:
+         /* If we are matching filenames, then here is our chance to
+            do clever processing by re-examining the list.  Call the
+            ignore function with the array as a parameter.  It can
+            munge the array, deleting matches as it desires. */
+         if (rl_ignore_some_completions_function &&
+             our_func == (int (*)())filename_completion_function)
+           (void)(*rl_ignore_some_completions_function)(matches);
+
+         /* If we are doing completion on quoted substrings, and any matches
+            contain any of the completer_word_break_characters, then auto-
+            matically prepend the substring with a quote character (just pick
+            the first one from the list of such) if it does not already begin
+            with a quote string.  FIXME: Need to remove any such automatically
+            inserted quote character when it no longer is necessary, such as
+            if we change the string we are completing on and the new set of
+            matches don't require a quoted substring. */
+         replacement = matches[0];
+
+         if (matches[0] && rl_completer_quote_characters && !quote_char &&
+             rl_filename_completion_desired)
+           {
+             int do_replace;
+
+             do_replace = 0;
+
+             /* If there is only a single match, see if we need to
+                quote it. */
+             if (!matches[1] &&
+                 rl_strpbrk (matches[0], rl_completer_word_break_characters))
+               do_replace = 1;
+
+             /* If there are multiple matches, check to see if any of them
+                require that the substring be quoted. */
+             for (i = 1; matches[i] != NULL; i++)
+               if (rl_strpbrk (matches[i], rl_completer_word_break_characters))
+                 {
+                   do_replace = 1;
+                   break;
+                 }
+             if (do_replace)
+               {
+#if defined (SHELL)
+                 /* XXX - experimental */
+                 /* Single-quote the replacement, since we found an
+                    embedded word break character in a potential match. */
+                 char *rtext;
+                 extern char *single_quote (); /* in builtins/common.c */
+
+                 rtext = single_quote (matches[0]);
+                 replacement = (char *)alloca (strlen (rtext) + 1);
+                 strcpy (replacement, rtext);
+                 free (rtext);
+#else /* !SHELL */
+                 /* Found an embedded word break character in a potential
+                    match, so we need to prepend a quote character if we
+                    are replacing the completion string. */
+                 replacement = (char *)alloca (strlen (matches[0]) + 2);
+                 quote_char = *rl_completer_quote_characters;
+                 *replacement = quote_char;
+                 strcpy (replacement + 1, matches[0]);
+#endif /* SHELL */
+               }
+           }
+         if (replacement)
+           {
+             rl_delete_text (start, rl_point);
+             rl_point = start;
+             rl_insert_text (replacement);
+           }
+
+         /* If there are more matches, ring the bell to indicate.
+            If this was the only match, and we are hacking files,
+            check the file to see if it was a directory.  If so,
+            add a '/' to the name.  If not, and we are at the end
+            of the line, then add a space. */
+         if (matches[1])
+           {
+             if (rl_editing_mode != vi_mode)
+               ding ();        /* There are other matches remaining. */
+           }
+         else
+           {
+             char temp_string[4];
+             int temp_string_index = 0;
+
+             if (quote_char)
+               temp_string[temp_string_index++] = quote_char;
+
+             temp_string[temp_string_index++] = delimiter ? delimiter : ' ';
+             temp_string[temp_string_index++] = '\0';
+
+             if (rl_filename_completion_desired)
+               {
+                 struct stat finfo;
+                 char *filename = tilde_expand (matches[0]);
+
+                 if ((stat (filename, &finfo) == 0) &&
+                     S_ISDIR (finfo.st_mode))
+                   {
+                     if (rl_line_buffer[rl_point] != '/')
+                       rl_insert_text ("/");
+                   }
+                 else
+                   {
+                     if (rl_point == rl_end)
+                       rl_insert_text (temp_string);
+                   }
+                 free (filename);
+               }
+             else
+               {
+                 if (rl_point == rl_end)
+                   rl_insert_text (temp_string);
+               }
+           }
+         break;
+
+       case '*':
+         {
+           int i = 1;
+
+           rl_delete_text (start, rl_point);
+           rl_point = start;
+           rl_begin_undo_group ();
+           if (matches[1])
+             {
+               while (matches[i])
+                 {
+                   rl_insert_text (matches[i++]);
+                   rl_insert_text (" ");
+                 }
+             }
+           else
+             {
+               rl_insert_text (matches[0]);
+               rl_insert_text (" ");
+             }
+           rl_end_undo_group ();
+         }
+         break;
+
+       case '?':
+         {
+           int len, count, limit, max = 0;
+           int j, k, l;
+
+           /* Handle simple case first.  What if there is only one answer? */
+           if (!matches[1])
+             {
+               char *temp;
+
+               if (rl_filename_completion_desired)
+                 temp = strrchr (matches[0], '/');
+               else
+                 temp = (char *)NULL;
+
+               if (!temp)
+                 temp = matches[0];
+               else
+                 temp++;
+
+               crlf ();
+               fprintf (rl_outstream, "%s", temp);
+#if defined (VISIBLE_STATS)
+               if (rl_filename_completion_desired && rl_visible_stats)
+                 {
+                   int extension_char;
+
+                   extension_char = stat_char (matches[0]);
+                   if (extension_char)
+                     putc (extension_char, rl_outstream);
+                 }
+#endif /* VISIBLE_STATS */
+               crlf ();
+               goto restart;
+             }
+
+           /* There is more than one answer.  Find out how many there are,
+              and find out what the maximum printed length of a single entry
+              is. */
+           for (i = 1; matches[i]; i++)
+             {
+               char *temp;
+               int name_length;
+
+               /* If we are hacking filenames, then only count the characters
+                  after the last slash in the pathname. */
+               if (rl_filename_completion_desired)
+                 temp = strrchr (matches[i], '/');
+               else
+                 temp = (char *)NULL;
+
+               if (!temp)
+                 temp = matches[i];
+               else
+                 temp++;
+
+               name_length = strlen (temp);
+
+               if (name_length > max)
+                 max = name_length;
+             }
+
+           len = i - 1;
+
+           /* If there are many items, then ask the user if she
+              really wants to see them all. */
+           if (len >= rl_completion_query_items)
+             {
+               crlf ();
+               fprintf (rl_outstream,
+                        "There are %d possibilities.  Do you really", len);
+               crlf ();
+               fprintf (rl_outstream, "wish to see them all? (y or n)");
+               fflush (rl_outstream);
+               if (!get_y_or_n ())
+                 {
+                   crlf ();
+                   goto restart;
+                 }
+             }
+           /* How many items of MAX length can we fit in the screen window? */
+           max += 2;
+           limit = screenwidth / max;
+           if (limit != 1 && (limit * max == screenwidth))
+             limit--;
+
+           /* Avoid a possible floating exception.  If max > screenwidth,
+              limit will be 0 and a divide-by-zero fault will result. */
+           if (limit == 0)
+             limit = 1;
+
+           /* How many iterations of the printing loop? */
+           count = (len + (limit - 1)) / limit;
+
+           /* Watch out for special case.  If LEN is less than LIMIT, then
+              just do the inner printing loop. */
+           if (len < limit)
+             count = 1;
+
+           /* Sort the items if they are not already sorted. */
+           if (!rl_ignore_completion_duplicates)
+             qsort (matches, len, sizeof (char *), compare_strings);
+
+           /* Print the sorted items, up-and-down alphabetically, like
+              ls might. */
+           crlf ();
+
+           for (i = 1; i < count + 1; i++)
+             {
+               for (j = 0, l = i; j < limit; j++)
+                 {
+                   if (l > len || !matches[l])
+                     {
+                       break;
+                     }
+                   else
+                     {
+                       char *temp = (char *)NULL;
+                       int printed_length;
+
+                       if (rl_filename_completion_desired)
+                         temp = strrchr (matches[l], '/');
+
+                       if (!temp)
+                         temp = matches[l];
+                       else
+                         temp++;
+
+                       printed_length = strlen (temp);
+                       fprintf (rl_outstream, "%s", temp);
+
+#if defined (VISIBLE_STATS)
+                       if (rl_filename_completion_desired &&
+                           rl_visible_stats)
+                         {
+                           int extension_char;
+
+                           extension_char = stat_char (matches[l]);
+
+                           if (extension_char)
+                             {
+                               putc (extension_char, rl_outstream);
+                               printed_length++;
+                             }
+                         }
+#endif /* VISIBLE_STATS */
+
+                       if (j + 1 < limit)
+                         {
+                           for (k = 0; k < max - printed_length; k++)
+                             putc (' ', rl_outstream);
+                         }
+                     }
+                   l += count;
+                 }
+               crlf ();
+             }
+         restart:
+
+           rl_on_new_line ();
+         }
+         break;
+
+       default:
+         abort ();
+       }
+
+      for (i = 0; matches[i]; i++)
+       free (matches[i]);
+      free (matches);
+    }
+
+  /* Check to see if the line has changed through all of this manipulation. */
+  if (saved_line_buffer)
+    {
+      if (strcmp (rl_line_buffer, saved_line_buffer) != 0)
+       completion_changed_buffer = 1;
+      else
+       completion_changed_buffer = 0;
+
+      free (saved_line_buffer);
+    }
+}
+
+#if defined (VISIBLE_STATS)
+/* Return the character which best describes FILENAME.
+     `@' for symbolic links
+     `/' for directories
+     `*' for executables
+     `=' for sockets */
+static int
+stat_char (filename)
+     char *filename;
+{
+  struct stat finfo;
+  int character = 0;
+
+  if (stat (filename, &finfo) == -1)
+    return (character);
+
+  if (S_ISDIR (finfo.st_mode))
+    character = '/';
+#if defined (S_ISLNK)
+  else if (S_ISLNK (finfo.st_mode))
+    character = '@';
+#endif /* S_ISLNK */
+#if defined (S_ISSOCK)
+  else if (S_ISSOCK (finfo.st_mode))
+    character = '=';
+#endif /* S_ISSOCK */
+  else if (S_ISREG (finfo.st_mode))
+    {
+      if (access (filename, X_OK) == 0)
+       character = '*';
+    }
+  return (character);
+}
+#endif /* VISIBLE_STATS */
+
+/* Stupid comparison routine for qsort () ing strings. */
+static int
+compare_strings (s1, s2)
+  char **s1, **s2;
+{
+  return (strcmp (*s1, *s2));
+}
+
+/* A completion function for usernames.
+   TEXT contains a partial username preceded by a random
+   character (usually `~').  */
+char *
+username_completion_function (text, state)
+     int state;
+     char *text;
+{
+#ifdef __GO32__
+  return (char *)NULL;
+#else /* !__GO32__ */
+  static char *username = (char *)NULL;
+  static struct passwd *entry;
+  static int namelen, first_char, first_char_loc;
+
+  if (!state)
+    {
+      if (username)
+       free (username);
+
+      first_char = *text;
+
+      if (first_char == '~')
+       first_char_loc = 1;
+      else
+       first_char_loc = 0;
+
+      username = savestring (&text[first_char_loc]);
+      namelen = strlen (username);
+      setpwent ();
+    }
+
+  while (entry = getpwent ())
+    {
+      if (strncmp (username, entry->pw_name, namelen) == 0)
+       break;
+    }
+
+  if (!entry)
+    {
+      endpwent ();
+      return ((char *)NULL);
+    }
+  else
+    {
+      char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
+
+      *value = *text;
+
+      strcpy (value + first_char_loc, entry->pw_name);
+
+      if (first_char == '~')
+       rl_filename_completion_desired = 1;
+
+      return (value);
+    }
+#endif /* !__GO32__ */
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                          Completion                             */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means that case is not significant in completion. */
+int completion_case_fold = 0;
+
+/* Return an array of (char *) which is a list of completions for TEXT.
+   If there are no completions, return a NULL pointer.
+   The first entry in the returned array is the substitution for TEXT.
+   The remaining entries are the possible completions.
+   The array is terminated with a NULL pointer.
+
+   ENTRY_FUNCTION is a function of two args, and returns a (char *).
+     The first argument is TEXT.
+     The second is a state argument; it should be zero on the first call, and
+     non-zero on subsequent calls.  It returns a NULL pointer to the caller
+     when there are no more matches.
+ */
+char **
+completion_matches (text, entry_function)
+     char *text;
+     char *(*entry_function) ();
+{
+  /* Number of slots in match_list. */
+  int match_list_size;
+
+  /* The list of matches. */
+  char **match_list =
+    (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
+
+  /* Number of matches actually found. */
+  int matches = 0;
+
+  /* Temporary string binder. */
+  char *string;
+
+  match_list[1] = (char *)NULL;
+
+  while (string = (*entry_function) (text, matches))
+    {
+      if (matches + 1 == match_list_size)
+       match_list = (char **)xrealloc
+         (match_list, ((match_list_size += 10) + 1) * sizeof (char *));
+
+      match_list[++matches] = string;
+      match_list[matches + 1] = (char *)NULL;
+    }
+
+  /* If there were any matches, then look through them finding out the
+     lowest common denominator.  That then becomes match_list[0]. */
+  if (matches)
+    {
+      register int i = 1;
+      int low = 100000;                /* Count of max-matched characters. */
+
+      /* If only one match, just use that. */
+      if (matches == 1)
+       {
+         match_list[0] = match_list[1];
+         match_list[1] = (char *)NULL;
+       }
+      else
+       {
+         /* Otherwise, compare each member of the list with
+            the next, finding out where they stop matching. */
+
+         while (i < matches)
+           {
+             register int c1, c2, si;
+
+             if (completion_case_fold)
+               {
+                 for (si = 0;
+                      (c1 = to_lower(match_list[i][si])) &&
+                      (c2 = to_lower(match_list[i + 1][si]));
+                      si++)
+                   if (c1 != c2) break;
+               }
+             else
+               {
+                 for (si = 0;
+                      (c1 = match_list[i][si]) &&
+                      (c2 = match_list[i + 1][si]);
+                      si++)
+                   if (c1 != c2) break;
+               }
+
+             if (low > si) low = si;
+             i++;
+           }
+         match_list[0] = (char *)xmalloc (low + 1);
+         strncpy (match_list[0], match_list[1], low);
+         match_list[0][low] = '\0';
+       }
+    }
+  else                         /* There were no matches. */
+    {
+      free (match_list);
+      match_list = (char **)NULL;
+    }
+  return (match_list);
+}
+
+/* Okay, now we write the entry_function for filename completion.  In the
+   general case.  Note that completion in the shell is a little different
+   because of all the pathnames that must be followed when looking up the
+   completion for a command. */
+char *
+filename_completion_function (text, state)
+     int state;
+     char *text;
+{
+  static DIR *directory;
+  static char *filename = (char *)NULL;
+  static char *dirname = (char *)NULL;
+  static char *users_dirname = (char *)NULL;
+  static int filename_len;
+
+  dirent *entry = (dirent *)NULL;
+
+  /* If we don't have any state, then do some initialization. */
+  if (!state)
+    {
+      char *temp;
+
+      if (dirname) free (dirname);
+      if (filename) free (filename);
+      if (users_dirname) free (users_dirname);
+
+      filename = savestring (text);
+      if (!*text) text = ".";
+      dirname = savestring (text);
+
+      temp = strrchr (dirname, '/');
+
+      if (temp)
+       {
+         strcpy (filename, ++temp);
+         *temp = '\0';
+       }
+      else
+       strcpy (dirname, ".");
+
+      /* We aren't done yet.  We also support the "~user" syntax. */
+
+      /* Save the version of the directory that the user typed. */
+      users_dirname = savestring (dirname);
+      {
+       char *temp_dirname;
+
+       temp_dirname = tilde_expand (dirname);
+       free (dirname);
+       dirname = temp_dirname;
+
+       if (rl_symbolic_link_hook)
+         (*rl_symbolic_link_hook) (&dirname);
+      }
+      directory = opendir (dirname);
+      filename_len = strlen (filename);
+
+      rl_filename_completion_desired = 1;
+    }
+
+  /* At this point we should entertain the possibility of hacking wildcarded
+     filenames, like /usr/man/man<WILD>/te<TAB>.  If the directory name
+     contains globbing characters, then build an array of directories, and
+     then map over that list while completing. */
+  /* *** UNIMPLEMENTED *** */
+
+  /* Now that we have some state, we can read the directory. */
+
+  while (directory && (entry = readdir (directory)))
+    {
+      /* Special case for no filename.
+        All entries except "." and ".." match. */
+      if (!filename_len)
+       {
+         if ((strcmp (entry->d_name, ".") != 0) &&
+             (strcmp (entry->d_name, "..") != 0))
+           break;
+       }
+      else
+       {
+         /* Otherwise, if these match upto the length of filename, then
+            it is a match. */
+           if (((int)D_NAMLEN (entry)) >= filename_len &&
+               (entry->d_name[0] == filename[0]) &&
+               (strncmp (filename, entry->d_name, filename_len) == 0))
+             {
+               break;
+             }
+       }
+    }
+
+  if (!entry)
+    {
+      if (directory)
+       {
+         closedir (directory);
+         directory = (DIR *)NULL;
+       }
+
+      if (dirname)
+       {
+         free (dirname);
+         dirname = (char *)NULL;
+       }
+      if (filename)
+       {
+         free (filename);
+         filename = (char *)NULL;
+       }
+      if (users_dirname)
+       {
+         free (users_dirname);
+         users_dirname = (char *)NULL;
+       }
+
+      return (char *)NULL;
+    }
+  else
+    {
+      char *temp;
+
+      if (dirname && (strcmp (dirname, ".") != 0))
+       {
+         if (rl_complete_with_tilde_expansion && *users_dirname == '~')
+           {
+             int dirlen = strlen (dirname);
+             temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry));
+             strcpy (temp, dirname);
+             /* Canonicalization cuts off any final slash present.  We need
+                to add it back. */
+             if (dirname[dirlen - 1] != '/')
+               {
+                 temp[dirlen] = '/';
+                 temp[dirlen + 1] = '\0';
+               }
+           }
+         else
+           {
+             temp = (char *)
+               xmalloc (1 + strlen (users_dirname) + D_NAMLEN (entry));
+             strcpy (temp, users_dirname);
+           }
+
+         strcat (temp, entry->d_name);
+       }
+      else
+       {
+         temp = (savestring (entry->d_name));
+       }
+      return (temp);
+    }
+}
+
+/* A function for simple tilde expansion. */
+int
+rl_tilde_expand (ignore, key)
+     int ignore, key;
+{
+  register int start, end;
+  char *homedir;
+
+  end = rl_point;
+  start = end - 1;
+
+  if (rl_point == rl_end && rl_line_buffer[rl_point] == '~')
+    {
+      homedir = tilde_expand ("~");
+      goto insert;
+    }
+  else if (rl_line_buffer[start] != '~')
+    {
+      for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--);
+      start++;
+    }
+
+  end = start;
+  do
+    {
+      end++;
+    }
+  while (!whitespace (rl_line_buffer[end]) && end < rl_end);
+
+  if (whitespace (rl_line_buffer[end]) || end >= rl_end)
+    end--;
+
+  /* If the first character of the current word is a tilde, perform
+     tilde expansion and insert the result.  If not a tilde, do
+     nothing. */
+  if (rl_line_buffer[start] == '~')
+    {
+      char *temp;
+      int len;
+
+      len = end - start + 1;
+      temp = (char *)alloca (len + 1);
+      strncpy (temp, rl_line_buffer + start, len);
+      temp[len] = '\0';
+      homedir = tilde_expand (temp);
+
+    insert:
+      rl_begin_undo_group ();
+      rl_delete_text (start, end + 1);
+      rl_point = start;
+      rl_insert_text (homedir);
+      rl_end_undo_group ();
+    }
+
+  return (0);
+}
+
+/* Find the first occurrence in STRING1 of any character from STRING2.
+   Return a pointer to the character in STRING1. */
+static char *
+rl_strpbrk (string1, string2)
+     char *string1, *string2;
+{
+  register char *scan;
+
+  for (; *string1; string1++)
+    {
+      for (scan = string2; *scan; scan++)
+       {
+         if (*string1 == *scan)
+           {
+             return (string1);
+           }
+       }
+    }
+  return ((char *)NULL);
+}
+
+#if defined (STATIC_MALLOC)
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     xmalloc and xrealloc ()                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp;
+
+  if (!pointer)
+    temp = (char *)malloc (bytes);
+  else
+    temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "readline: Out of virtual memory!\n");
+  abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/readline/display.c b/readline/display.c
new file mode 100644 (file)
index 0000000..c889318
--- /dev/null
@@ -0,0 +1,801 @@
+/* display.c -- readline redisplay facility. */
+
+/* Copyright (C) 1987, 1989, 1992 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 1, 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#if !defined (strrchr)
+extern char *strrchr ();
+#endif /* !strchr */
+
+/* Global and pseudo-global variables and functions
+   imported from readline.c. */
+extern char *rl_prompt;
+extern int readline_echoing_p;
+extern char *term_clreol, *term_im, *term_ic,  *term_ei, *term_DC;
+/* Termcap variables. */
+extern char *term_up, *term_dc, *term_cr, *term_IC;
+extern int screenheight, screenwidth, terminal_can_insert;
+
+extern void _rl_output_some_chars ();
+extern void _rl_output_character_function ();
+
+extern int _rl_convert_meta_chars_to_ascii;
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_prefer_visible_bell;
+
+/* Pseudo-global functions (local to the readline library) exported
+   by this file. */
+void _rl_move_cursor_relative (), _rl_output_some_chars ();
+void _rl_move_vert ();
+
+static void update_line (), clear_to_eol ();
+static void delete_chars (), insert_some_chars ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Display stuff                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me.  I never seem to write good
+   display routines in C.  Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+   the problems of input lines longer than the screen width.
+
+   update_line and the code that calls it makes a multiple line,
+   automatically wrapping line update.  Carefull attention needs
+   to be paid to the vertical position variables.
+
+   handling of terminals with autowrap on (incl. DEC braindamage)
+   could be improved a bit.  Right now I just cheat and decrement
+   screenwidth by one. */
+
+/* Keep two buffers; one which reflects the current contents of the
+   screen, and the other to draw what we think the new contents should
+   be.  Then compare the buffers, and make whatever changes to the
+   screen itself that we should.  Finally, make the buffer that we
+   just drew into be the one which reflects the current contents of the
+   screen, and place the cursor where it belongs.
+
+   Commands that want to can fix the display themselves, and then let
+   this function know that the display has been fixed by setting the
+   RL_DISPLAY_FIXED variable.  This is good for efficiency. */
+
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+/* The stuff that gets printed out before the actual text of the line.
+   This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *)NULL;
+
+/* Pseudo-global variables declared here. */
+/* The visible cursor position.  If you print some text, adjust this. */
+int _rl_last_c_pos = 0;
+int _rl_last_v_pos = 0;
+
+/* Number of lines currently on screen minus 1. */
+int _rl_vis_botlin = 0;
+
+/* Variables used only in this file. */
+/* The last left edge of text that was displayed.  This is used when
+   doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
+static int last_lmargin = 0;
+
+/* The line display buffers.  One is the line currently displayed on
+   the screen.  The other is the line about to be displayed. */
+static char *visible_line = (char *)NULL;
+static char *invisible_line = (char *)NULL;
+
+/* A buffer for `modeline' messages. */
+static char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+static int forced_display = 0;
+
+/* Default and initial buffer size.  Can grow. */
+static int line_size = 1024;
+
+/* Basic redisplay algorithm. */
+rl_redisplay ()
+{
+  register int in, out, c, linenum;
+  register char *line = invisible_line;
+  char *prompt_this_line;
+  int c_pos = 0;
+  int inv_botlin = 0;          /* Number of lines in newly drawn buffer. */
+
+  if (!readline_echoing_p)
+    return;
+
+  if (!rl_display_prompt)
+    rl_display_prompt = "";
+
+  if (!invisible_line)
+    {
+      visible_line = (char *)xmalloc (line_size);
+      invisible_line = (char *)xmalloc (line_size);
+      line = invisible_line;
+      for (in = 0; in < line_size; in++)
+       {
+         visible_line[in] = 0;
+         invisible_line[in] = 1;
+       }
+      rl_on_new_line ();
+    }
+
+  /* Draw the line into the buffer. */
+  c_pos = -1;
+
+  /* Mark the line as modified or not.  We only do this for history
+     lines. */
+  out = 0;
+  if (_rl_mark_modified_lines && current_history () && rl_undo_list)
+    {
+      line[out++] = '*';
+      line[out] = '\0';
+    }
+
+  /* If someone thought that the redisplay was handled, but the currently
+     visible line has a different modification state than the one about
+     to become visible, then correct the caller's misconception. */
+  if (visible_line[0] != invisible_line[0])
+    rl_display_fixed = 0;
+
+  prompt_this_line = strrchr (rl_display_prompt, '\n');
+  if (!prompt_this_line)
+    prompt_this_line = rl_display_prompt;
+  else
+    {
+      prompt_this_line++;
+      if (forced_display)
+       _rl_output_some_chars
+         (rl_display_prompt, prompt_this_line - rl_display_prompt);
+    }
+
+  strncpy (line + out,  prompt_this_line, strlen (prompt_this_line));
+  out += strlen (prompt_this_line);
+  line[out] = '\0';
+
+  for (in = 0; in < rl_end; in++)
+    {
+      c = (unsigned char)rl_line_buffer[in];
+
+      if (out + 8 >= line_size)                /* XXX - 8 for \t */
+       {
+         line_size *= 2;
+         visible_line = (char *)xrealloc (visible_line, line_size);
+         invisible_line = (char *)xrealloc (invisible_line, line_size);
+         line = invisible_line;
+       }
+
+      if (in == rl_point)
+       c_pos = out;
+
+      if (META_CHAR (c))
+       {
+         if (_rl_convert_meta_chars_to_ascii)
+           {
+             sprintf (line + out, "\\%o", c);
+             out += 4;
+           }
+         else
+           line[out++] = c;      
+       }
+#define DISPLAY_TABS
+#if defined (DISPLAY_TABS)
+      else if (c == '\t')
+       {
+         register int newout = (out | (int)7) + 1;
+         while (out < newout)
+           line[out++] = ' ';
+       }
+#endif
+      else if (c < ' ')
+       {
+         line[out++] = '^';
+         line[out++] = UNCTRL (c);     /* XXX was c ^ 0x40 */
+       }
+      else if (c == 127)
+       {
+         line[out++] = '^';
+         line[out++] = '?';
+       }
+      else
+       line[out++] = c;
+    }
+  line[out] = '\0';
+  if (c_pos < 0)
+    c_pos = out;
+
+  /* PWP: now is when things get a bit hairy.  The visible and invisible
+     line buffers are really multiple lines, which would wrap every
+     (screenwidth - 1) characters.  Go through each in turn, finding
+     the changed region and updating it.  The line order is top to bottom. */
+
+  /* If we can move the cursor up and down, then use multiple lines,
+     otherwise, let long lines display in a single terminal line, and
+     horizontally scroll it. */
+
+  if (!_rl_horizontal_scroll_mode && term_up && *term_up)
+    {
+      int total_screen_chars = (screenwidth * screenheight);
+
+      if (!rl_display_fixed || forced_display)
+       {
+         forced_display = 0;
+
+         /* If we have more than a screenful of material to display, then
+            only display a screenful.  We should display the last screen,
+            not the first.  I'll fix this in a minute. */
+         if (out >= total_screen_chars)
+           out = total_screen_chars - 1;
+
+         /* Number of screen lines to display. */
+         inv_botlin = out / screenwidth;
+
+         /* For each line in the buffer, do the updating display. */
+         for (linenum = 0; linenum <= inv_botlin; linenum++)
+           update_line (linenum > _rl_vis_botlin ? ""
+                        : &visible_line[linenum * screenwidth],
+                        &invisible_line[linenum * screenwidth],
+                        linenum);
+
+         /* We may have deleted some lines.  If so, clear the left over
+            blank ones at the bottom out. */
+         if (_rl_vis_botlin > inv_botlin)
+           {
+             char *tt;
+             for (; linenum <= _rl_vis_botlin; linenum++)
+               {
+                 tt = &visible_line[linenum * screenwidth];
+                 _rl_move_vert (linenum);
+                 _rl_move_cursor_relative (0, tt);
+                 clear_to_eol
+                   ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth);
+               }
+           }
+         _rl_vis_botlin = inv_botlin;
+
+         /* Move the cursor where it should be. */
+         _rl_move_vert (c_pos / screenwidth);
+         _rl_move_cursor_relative (c_pos % screenwidth,
+                               &invisible_line[(c_pos / screenwidth) * screenwidth]);
+       }
+    }
+  else                         /* Do horizontal scrolling. */
+    {
+      int lmargin;
+
+      /* Always at top line. */
+      _rl_last_v_pos = 0;
+
+      /* If the display position of the cursor would be off the edge
+        of the screen, start the display of this line at an offset that
+        leaves the cursor on the screen. */
+      if (c_pos - last_lmargin > screenwidth - 2)
+       lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
+      else if (c_pos - last_lmargin < 1)
+       lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
+      else
+       lmargin = last_lmargin;
+
+      /* If the first character on the screen isn't the first character
+        in the display line, indicate this with a special character. */
+      if (lmargin > 0)
+       line[lmargin] = '<';
+
+      if (lmargin + screenwidth < out)
+       line[lmargin + screenwidth - 1] = '>';
+
+      if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+       {
+         forced_display = 0;
+         update_line (&visible_line[last_lmargin],
+                      &invisible_line[lmargin], 0);
+
+         _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+         last_lmargin = lmargin;
+       }
+    }
+  fflush (rl_outstream);
+
+  /* Swap visible and non-visible lines. */
+  {
+    char *temp = visible_line;
+    visible_line = invisible_line;
+    invisible_line = temp;
+    rl_display_fixed = 0;
+  }
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+   line on the screen; vis:
+
+                            /old first difference
+       /beginning of line   |              /old last same       /old EOL
+       v                    v              v                    v
+old:   eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new:   eddie> Oh, my little buggy says to me, as lurgid as
+       ^                    ^        ^                    ^
+       \beginning of line   |        \new last same       \new end of line
+                            \new first difference
+
+   All are character pointers for the sake of speed.  Special cases for
+   no differences, as well as for end of line additions must be handeled.
+
+   Could be made even smarter, but this works well enough */
+static void
+update_line (old, new, current_line)
+     register char *old, *new;
+     int current_line;
+{
+  register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+  int lendiff, wsatend;
+
+  /* Find first difference. */
+  for (ofd = old, nfd = new;
+       (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
+       ofd++, nfd++)
+    ;
+
+  /* Move to the end of the screen line. */
+  for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
+  for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
+
+  /* If no difference, continue to next line. */
+  if (ofd == oe && nfd == ne)
+    return;
+
+  wsatend = 1;                 /* flag for trailing whitespace */
+  ols = oe - 1;                        /* find last same */
+  nls = ne - 1;
+  while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
+    {
+      if (*ols != ' ')
+       wsatend = 0;
+      ols--;
+      nls--;
+    }
+
+  if (wsatend)
+    {
+      ols = oe;
+      nls = ne;
+    }
+  else if (*ols != *nls)
+    {
+      if (*ols)                        /* don't step past the NUL */
+       ols++;
+      if (*nls)
+       nls++;
+    }
+
+  _rl_move_vert (current_line);
+  _rl_move_cursor_relative (ofd - old, old);
+
+  /* if (len (new) > len (old)) */
+  lendiff = (nls - nfd) - (ols - ofd);
+
+  /* Insert (diff (len (old), len (new)) ch. */
+  if (lendiff > 0)
+    {
+      if (terminal_can_insert)
+       {
+         /* Sometimes it is cheaper to print the characters rather than
+            use the terminal's capabilities. */
+         if ((2 * (ne - nfd)) < lendiff && !term_IC)
+           {
+             _rl_output_some_chars (nfd, (ne - nfd));
+             _rl_last_c_pos += (ne - nfd);
+           }
+         else
+           {
+             if (*ols)
+               {
+                 insert_some_chars (nfd, lendiff);
+                 _rl_last_c_pos += lendiff;
+               }
+             else
+               {
+                 /* At the end of a line the characters do not have to
+                    be "inserted".  They can just be placed on the screen. */
+                 _rl_output_some_chars (nfd, lendiff);
+                 _rl_last_c_pos += lendiff;
+               }
+             /* Copy (new) chars to screen from first diff to last match. */
+             if (((nls - nfd) - lendiff) > 0)
+               {
+                 _rl_output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
+                 _rl_last_c_pos += ((nls - nfd) - lendiff);
+               }
+           }
+       }
+      else
+       {               /* cannot insert chars, write to EOL */
+         _rl_output_some_chars (nfd, (ne - nfd));
+         _rl_last_c_pos += (ne - nfd);
+       }
+    }
+  else                         /* Delete characters from line. */
+    {
+      /* If possible and inexpensive to use terminal deletion, then do so. */
+      if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
+       {
+         if (lendiff)
+           delete_chars (-lendiff); /* delete (diff) characters */
+
+         /* Copy (new) chars to screen from first diff to last match */
+         if ((nls - nfd) > 0)
+           {
+             _rl_output_some_chars (nfd, (nls - nfd));
+             _rl_last_c_pos += (nls - nfd);
+           }
+       }
+      /* Otherwise, print over the existing material. */
+      else
+       {
+         _rl_output_some_chars (nfd, (ne - nfd));
+         _rl_last_c_pos += (ne - nfd);
+         clear_to_eol ((oe - old) - (ne - new));
+       }
+    }
+}
+
+/* Tell the update routines that we have moved onto a new (empty) line. */
+rl_on_new_line ()
+{
+  if (visible_line)
+    visible_line[0] = '\0';
+
+  _rl_last_c_pos = _rl_last_v_pos = 0;
+  _rl_vis_botlin = last_lmargin = 0;
+}
+
+/* Actually update the display, period. */
+rl_forced_update_display ()
+{
+  if (visible_line)
+    {
+      register char *temp = visible_line;
+
+      while (*temp) *temp++ = '\0';
+    }
+  rl_on_new_line ();
+  forced_display++;
+  rl_redisplay ();
+}
+
+/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
+   DATA is the contents of the screen line of interest; i.e., where
+   the movement is being done. */
+void
+_rl_move_cursor_relative (new, data)
+     int new;
+     char *data;
+{
+  register int i;
+
+  /* It may be faster to output a CR, and then move forwards instead
+     of moving backwards. */
+  if (new + 1 < _rl_last_c_pos - new)
+    {
+#ifdef __MSDOS__
+      putc('\r', rl_outstream);
+#else
+      tputs (term_cr, 1, _rl_output_character_function);
+#endif
+      _rl_last_c_pos = 0;
+    }
+
+  if (_rl_last_c_pos == new) return;
+
+  if (_rl_last_c_pos < new)
+    {
+      /* Move the cursor forward.  We do it by printing the command
+        to move the cursor forward if there is one, else print that
+        portion of the output buffer again.  Which is cheaper? */
+
+      /* The above comment is left here for posterity.  It is faster
+        to print one character (non-control) than to print a control
+        sequence telling the terminal to move forward one character.
+        That kind of control is for people who don't know what the
+        data is underneath the cursor. */
+#if defined (HACK_TERMCAP_MOTION)
+      extern char *term_forward_char;
+
+      if (term_forward_char)
+       for (i = _rl_last_c_pos; i < new; i++)
+         tputs (term_forward_char, 1, _rl_output_character_function);
+      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 */
+    }
+  else
+    backspace (_rl_last_c_pos - new);
+  _rl_last_c_pos = new;
+}
+
+/* PWP: move the cursor up or down. */
+void
+_rl_move_vert (to)
+     int to;
+{
+  register int delta, i;
+
+  if (_rl_last_v_pos == to || to > screenheight)
+    return;
+
+#ifdef __GO32__
+  {
+    int row, col;
+    ScreenGetCursor (&row, &col);
+    ScreenSetCursor ((row + to - _rl_last_v_pos), col);
+  }
+#else /* __GO32__ */
+  if ((delta = to - _rl_last_v_pos) > 0)
+    {
+      for (i = 0; i < delta; i++)
+       putc ('\n', rl_outstream);
+      tputs (term_cr, 1, _rl_output_character_function);
+      _rl_last_c_pos = 0;
+    }
+  else
+    {                  /* delta < 0 */
+      if (term_up && *term_up)
+       for (i = 0; i < -delta; i++)
+         tputs (term_up, 1, _rl_output_character_function);
+    }
+#endif /* !__GO32__ */
+  _rl_last_v_pos = to;         /* Now TO is here */
+}
+
+/* Physically print C on rl_outstream.  This is for functions which know
+   how to optimize the display. */
+rl_show_char (c)
+     int c;
+{
+  if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii)
+    {
+      fprintf (rl_outstream, "M-");
+      c = UNMETA (c);
+    }
+
+#if defined (DISPLAY_TABS)
+  if (c < 32 && c != '\t')
+#else
+  if (c < 32)
+#endif /* !DISPLAY_TABS */
+    {
+
+      c += 64;
+    }
+
+  putc (c, rl_outstream);
+  fflush (rl_outstream);
+}
+
+int
+rl_character_len (c, pos)
+     register int c, pos;
+{
+  if (META_CHAR (c))
+    return (_rl_convert_meta_chars_to_ascii ? 4 : 1);
+
+  if (c == '\t')
+    {
+#if defined (DISPLAY_TABS)
+      return (((pos | (int)7) + 1) - pos);
+#else
+      return (2);
+#endif /* !DISPLAY_TABS */
+    }
+
+  if (isprint (c))
+    return (1);
+  else
+    return (2);
+}
+
+/* How to print things in the "echo-area".  The prompt is treated as a
+   mini-modeline. */
+
+#if defined (HAVE_VARARGS_H)
+rl_message (va_alist)
+     va_dcl
+{
+  char *format;
+  va_list args;
+
+  va_start (args);
+  format = va_arg (args, char *);
+  vsprintf (msg_buf, format, args);
+  va_end (args);
+
+  rl_display_prompt = msg_buf;
+  rl_redisplay ();
+}
+#else /* !HAVE_VARARGS_H */
+rl_message (format, arg1, arg2)
+     char *format;
+{
+  sprintf (msg_buf, format, arg1, arg2);
+  rl_display_prompt = msg_buf;
+  rl_redisplay ();
+}
+#endif /* !HAVE_VARARGS_H */
+
+/* How to clear things from the "echo-area". */
+rl_clear_message ()
+{
+  rl_display_prompt = rl_prompt;
+  rl_redisplay ();
+}
+
+rl_reset_line_state ()
+{
+  rl_on_new_line ();
+
+  rl_display_prompt = rl_prompt ? rl_prompt : "";
+  forced_display = 1;
+}
+
+/* Quick redisplay hack when erasing characters at the end of the line. */
+void
+_rl_erase_at_end_of_line (l)
+     int l;
+{
+  register int i;
+
+  backspace (l);
+  for (i = 0; i < l; i++)
+    putc (' ', rl_outstream);
+  backspace (l);
+  for (i = 0; i < l; i++)
+    visible_line[--_rl_last_c_pos] = '\0';
+  rl_display_fixed++;
+}
+
+/* Clear to the end of the line.  COUNT is the minimum
+   number of character spaces to clear, */
+static void
+clear_to_eol (count)
+     int count;
+{
+#ifndef __GO32__
+  if (term_clreol)
+    {
+      tputs (term_clreol, 1, _rl_output_character_function);
+    }
+  else
+#endif /* !__GO32__ */
+    {
+      register int i;
+
+      /* Do one more character space. */
+      count++;
+
+      for (i = 0; i < count; i++)
+       putc (' ', rl_outstream);
+
+      backspace (count);
+    }
+}
+/* Insert COUNT characters from STRING to the output stream. */
+static void
+insert_some_chars (string, count)
+     char *string;
+     int count;
+{
+#ifdef __GO32__
+  int row, col, width;
+  char *row_start;
+
+  ScreenGetCursor (&row, &col);
+  width = ScreenCols ();
+  row_start = ScreenPrimary + (row * width);
+  memcpy (row_start + col + count, row_start + col, width - col - count);
+  /* Place the text on the screen. */
+  _rl_output_some_chars (string, count);
+#else /* __GO32__ */
+  /* If IC is defined, then we do not have to "enter" insert mode. */
+  if (term_IC)
+    {
+      char *tgoto (), *buffer;
+      buffer = tgoto (term_IC, 0, count);
+      tputs (buffer, 1, _rl_output_character_function);
+      _rl_output_some_chars (string, count);
+    }
+  else
+    {
+      register int i;
+
+      /* If we have to turn on insert-mode, then do so. */
+      if (term_im && *term_im)
+       tputs (term_im, 1, _rl_output_character_function);
+
+      /* If there is a special command for inserting characters, then
+        use that first to open up the space. */
+      if (term_ic && *term_ic)
+       {
+         for (i = count; i--; )
+           tputs (term_ic, 1, _rl_output_character_function);
+       }
+
+      /* Print the text. */
+      _rl_output_some_chars (string, count);
+
+      /* If there is a string to turn off insert mode, we had best use
+        it now. */
+      if (term_ei && *term_ei)
+       tputs (term_ei, 1, _rl_output_character_function);
+    }
+#endif /* __GO32__ */
+}
+
+/* Delete COUNT characters from the display line. */
+static void
+delete_chars (count)
+     int count;
+{
+#if defined (__GO32__)
+  int row, col, width;
+  char *row_start;
+
+  ScreenGetCursor (&row, &col);
+  width = ScreenCols ();
+  row_start = ScreenPrimary + (row * width);
+  memcpy (row_start + col, row_start + col + count, width - col - count);
+  memset (row_start + width - count, 0, count * 2);
+#else /* !__GO32__ */
+  if (count > screenwidth)
+    return;
+
+  if (term_DC && *term_DC)
+    {
+      char *tgoto (), *buffer;
+      buffer = tgoto (term_DC, 0, count);
+      tputs (buffer, 1, _rl_output_character_function);
+    }
+  else
+    {
+      if (term_dc && *term_dc)
+       while (count--)
+         tputs (term_dc, 1, _rl_output_character_function);
+    }
+#endif /* !__GO32__ */
+}
diff --git a/readline/isearch.c b/readline/isearch.c
new file mode 100644 (file)
index 0000000..9b44c93
--- /dev/null
@@ -0,0 +1,378 @@
+/* **************************************************************** */
+/*                                                                 */
+/*                     I-Search and Searching                      */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Copyright (C) 1987,1989 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
+   for it.
+
+   The 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 1, or (at your option)
+   any later version.
+
+   The 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#if defined (__GNUC__)
+#  define alloca __builtin_alloca
+#else
+#  if defined (sparc) || defined (HAVE_ALLOCA_H)
+#    include <alloca.h>
+#  endif
+#endif
+
+#include "readline.h"
+#include "history.h"
+
+extern Keymap _rl_keymap;
+extern HIST_ENTRY *saved_line_for_history;
+extern int rl_line_buffer_len;
+extern int rl_point, rl_end;
+extern char *rl_prompt, *rl_line_buffer;
+
+/* Remove these declarations when we have a complete libgnu.a. */
+extern char *xmalloc (), *xrealloc ();
+
+static void rl_search_history ();
+
+/* Search backwards through the history looking for a string which is typed
+   interactively.  Start with the current line. */
+rl_reverse_search_history (sign, key)
+     int sign;
+     int key;
+{
+  rl_search_history (-sign, key);
+}
+
+/* Search forwards through the history looking for a string which is typed
+   interactively.  Start with the current line. */
+rl_forward_search_history (sign, key)
+     int sign;
+     int key;
+{
+  rl_search_history (sign, key);
+}
+
+/* Display the current state of the search in the echo-area.
+   SEARCH_STRING contains the string that is being searched for,
+   DIRECTION is zero for forward, or 1 for reverse,
+   WHERE is the history list number of the current line.  If it is
+   -1, then this line is the starting one. */
+static void
+rl_display_search (search_string, reverse_p, where)
+     char *search_string;
+     int reverse_p, where;
+{
+  char *message = (char *)NULL;
+
+  message =
+    (char *)xmalloc (1 + (search_string ? strlen (search_string) : 0) + 30);
+
+  *message = '\0';
+
+#if defined (NOTDEF)
+  if (where != -1)
+    sprintf (message, "[%d]", where + history_base);
+#endif /* NOTDEF */
+
+  strcat (message, "(");
+
+  if (reverse_p)
+    strcat (message, "reverse-");
+
+  strcat (message, "i-search)`");
+
+  if (search_string)
+    strcat (message, search_string);
+
+  strcat (message, "': ");
+  rl_message ("%s", message, 0);
+  free (message);
+  rl_redisplay ();
+}
+
+/* Search through the history looking for an interactively typed string.
+   This is analogous to i-search.  We start the search in the current line.
+   DIRECTION is which direction to search; >= 0 means forward, < 0 means
+   backwards. */
+static void
+rl_search_history (direction, invoking_key)
+     int direction;
+     int invoking_key;
+{
+  /* The string that the user types in to search for. */
+  char *search_string;
+
+  /* The current length of SEARCH_STRING. */
+  int search_string_index;
+
+  /* The amount of space that SEARCH_STRING has allocated to it. */
+  int search_string_size;
+
+  /* The list of lines to search through. */
+  char **lines;
+
+  /* The length of LINES. */
+  int hlen;
+
+  /* Where we get LINES from. */
+  HIST_ENTRY **hlist = history_list ();
+
+  register int i = 0;
+  int orig_point = rl_point;
+  int orig_line = where_history ();
+  int last_found_line = orig_line;
+  int c, done = 0;
+
+  /* The line currently being searched. */
+  char *sline;
+
+  /* Offset in that line. */
+  int index;
+
+  /* Non-zero if we are doing a reverse search. */
+  int reverse = (direction < 0);
+
+  /* Create an arrary of pointers to the lines that we want to search. */
+  maybe_replace_line ();
+  if (hlist)
+    for (i = 0; hlist[i]; i++);
+
+  /* Allocate space for this many lines, +1 for the current input line,
+     and remember those lines. */
+  lines = (char **)alloca ((1 + (hlen = i)) * sizeof (char *));
+  for (i = 0; i < hlen; i++)
+    lines[i] = hlist[i]->line;
+
+  if (saved_line_for_history)
+    lines[i] = saved_line_for_history->line;
+  else
+    /* So I have to type it in this way instead. */
+    {
+      char *alloced_line;
+
+      /* Keep that MIPS alloca () happy. */
+      alloced_line = (char *)alloca (1 + strlen (rl_line_buffer));
+      lines[i] = alloced_line;
+      strcpy (lines[i], &rl_line_buffer[0]);
+    }
+
+  hlen++;
+
+  /* The line where we start the search. */
+  i = orig_line;
+
+  /* Initialize search parameters. */
+  search_string = (char *)xmalloc (search_string_size = 128);
+  *search_string = '\0';
+  search_string_index = 0;
+
+  /* Normalize DIRECTION into 1 or -1. */
+  if (direction >= 0)
+    direction = 1;
+  else
+    direction = -1;
+
+  rl_display_search (search_string, reverse, -1);
+
+  sline = rl_line_buffer;
+  index = rl_point;
+
+  while (!done)
+    {
+      c = rl_read_key ();
+
+      /* Hack C to Do What I Mean. */
+      {
+       Function *f = (Function *)NULL;
+
+       if (_rl_keymap[c].type == ISFUNC)
+         {
+           f = _rl_keymap[c].function;
+
+           if (f == rl_reverse_search_history)
+             c = reverse ? -1 : -2;
+           else if (f == rl_forward_search_history)
+             c =  !reverse ? -1 : -2;
+         }
+      }
+
+      switch (c)
+       {
+       case ESC:
+         done = 1;
+         continue;
+
+         /* case invoking_key: */
+       case -1:
+         goto search_again;
+
+         /* switch directions */
+       case -2:
+         direction = -direction;
+         reverse = (direction < 0);
+
+         goto do_search;
+
+       case CTRL ('G'):
+         strcpy (rl_line_buffer, lines[orig_line]);
+         rl_point = orig_point;
+         rl_end = strlen (rl_line_buffer);
+         rl_clear_message ();
+         return;
+
+       default:
+         if (c < 32 || c > 126)
+           {
+             rl_execute_next (c);
+             done = 1;
+             continue;
+           }
+         else
+           {
+             if (search_string_index + 2 >= search_string_size)
+               search_string = (char *)xrealloc
+                 (search_string, (search_string_size += 128));
+             search_string[search_string_index++] = c;
+             search_string[search_string_index] = '\0';
+             goto do_search;
+
+           search_again:
+
+             if (!search_string_index)
+               continue;
+             else
+               {
+                 if (reverse)
+                   --index;
+                 else
+                   if (index != strlen (sline))
+                     ++index;
+                   else
+                     ding ();
+               }
+           do_search:
+
+             while (1)
+               {
+                 if (reverse)
+                   {
+                     while (index >= 0)
+                       if (strncmp
+                           (search_string, sline + index, search_string_index)
+                           == 0)
+                         goto string_found;
+                       else
+                         index--;
+                   }
+                 else
+                   {
+                     register int limit =
+                       (strlen (sline) - search_string_index) + 1;
+
+                     while (index < limit)
+                       {
+                         if (strncmp (search_string,
+                                      sline + index,
+                                      search_string_index) == 0)
+                           goto string_found;
+                         index++;
+                       }
+                   }
+
+               next_line:
+                 i += direction;
+
+                 /* At limit for direction? */
+                 if ((reverse && i < 0) ||
+                     (!reverse && i == hlen))
+                   goto search_failed;
+
+                 sline = lines[i];
+                 if (reverse)
+                   index = strlen (sline);
+                 else
+                   index = 0;
+
+                 /* If the search string is longer than the current
+                    line, no match. */
+                 if (search_string_index > (int)strlen (sline))
+                   goto next_line;
+
+                 /* Start actually searching. */
+                 if (reverse)
+                   index -= search_string_index;
+               }
+
+           search_failed:
+             /* We cannot find the search string.  Ding the bell. */
+             ding ();
+             i = last_found_line;
+             break;
+
+           string_found:
+             /* We have found the search string.  Just display it.  But don't
+                actually move there in the history list until the user accepts
+                the location. */
+             {
+               int line_len;
+
+               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_point = index;
+               rl_end = line_len;
+               last_found_line = i;
+               rl_display_search
+                 (search_string, reverse, (i == orig_line) ? -1 : i);
+             }
+           }
+       }
+      continue;
+    }
+
+  /* The searching is over.  The user may have found the string that she
+     was looking for, or else she may have exited a failing search.  If
+     INDEX is -1, then that shows that the string searched for was not
+     found.  We use this to determine where to place rl_point. */
+  {
+    int now = last_found_line;
+
+    /* First put back the original state. */
+    strcpy (rl_line_buffer, lines[orig_line]);
+
+    /* Free the search string. */
+    free (search_string);
+
+    if (now < orig_line)
+      rl_get_previous_history (orig_line - now);
+    else
+      rl_get_next_history (now - orig_line);
+
+    /* If the index of the "matched" string is less than zero, then the
+       final search string was never matched, so put point somewhere
+       reasonable. */
+    if (index < 0)
+      index = strlen (rl_line_buffer);
+
+    rl_point = index;
+    rl_clear_message ();
+  }
+}
index 3c577b398f59c09ee0dfad8ed77536fabfef7a70..5fd0cba150a660d14e35351042e8f60880e054b1 100644 (file)
@@ -1,5 +1,25 @@
 /* keymaps.h -- Manipulation of readline keymaps. */
 
+/* Copyright (C) 1987, 1989, 1992 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 1, 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
 #ifndef _KEYMAPS_H_
 #define _KEYMAPS_H_
 
@@ -20,12 +40,17 @@ typedef struct _keymap_entry {
   Function *function;
 } 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
+
 /* I wanted to make the above structure contain a union of:
    union { Function *function; struct _keymap_entry *keymap; } value;
    but this made it impossible for me to create a static array.
    Maybe I need C lessons. */
 
-typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128];
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
 typedef KEYMAP_ENTRY *Keymap;
 
 /* The values that TYPE can have in a keymap entry. */
@@ -48,6 +73,14 @@ Keymap rl_copy_keymap ();
    the Meta digits bound to produce numeric arguments. */
 Keymap rl_make_keymap ();
 
-#endif /* _KEYMAPS_H_ */
+/* Return the keymap corresponding to a given name.  Names look like
+   `emacs' or `emacs-meta' or `vi-insert'. */
+Keymap rl_get_keymap_by_name ();
 
+/* Return the current keymap. */
+Keymap rl_get_keymap ();
 
+/* Set the current keymap to MAP. */
+void rl_set_keymap ();
+
+#endif /* _KEYMAPS_H_ */
diff --git a/readline/parens.c b/readline/parens.c
new file mode 100644 (file)
index 0000000..2c96012
--- /dev/null
@@ -0,0 +1,115 @@
+/* parens.c -- Implemenation of matching parenthesis feature. */
+
+/* Copyright (C) 1987, 1989, 1992 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 1, 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "readline.h"
+
+/* Non-zero means try to blink the matching open parenthesis when the
+   close parenthesis is inserted. */
+#if defined (FD_SET)
+int rl_blink_matching_paren = 1;
+#else /* !FD_SET */
+int rl_blink_matching_paren = 0;
+#endif /* !FD_SET */
+
+static int find_matching_open ();
+
+rl_insert_close (count, invoking_key)
+     int count, invoking_key;
+{
+  extern int rl_explicit_arg;
+
+  if (rl_explicit_arg || !rl_blink_matching_paren)
+    rl_insert (count, invoking_key);
+  else
+    {
+#if defined (FD_SET)
+      int orig_point, match_point, ready;
+      struct timeval timer;
+      fd_set readfds;
+
+      rl_insert (1, invoking_key);
+      rl_redisplay ();
+      match_point =
+       find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
+
+      /* Emacs might message or ring the bell here, but I don't. */
+      if (match_point < 0)
+       return;
+
+      FD_ZERO (&readfds);
+      FD_SET (fileno (rl_instream), &readfds);
+      timer.tv_sec = 1;
+      timer.tv_usec = 500;
+
+      orig_point = rl_point;
+      rl_point = match_point;
+      rl_redisplay ();
+      ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
+      rl_point = orig_point;
+#else /* !FD_SET */
+      rl_insert (count, invoking_key);
+#endif /* !FD_SET */
+    }
+}
+
+static int
+find_matching_open (string, from, closer)
+     char *string;
+     int from, closer;
+{
+  register int i;
+  int opener, level, delimiter;
+
+  switch (closer)
+    {
+    case ']': opener = '['; break;
+    case '}': opener = '{'; break;
+    case ')': opener = '('; break;
+    default:
+      return (-1);
+    }
+
+  level = 1;                   /* The closer passed in counts as 1. */
+  delimiter = 0;               /* Delimited state unknown. */
+
+  for (i = from; i > -1; i--)
+    {
+      if (delimiter && (string[i] == delimiter))
+       delimiter = 0;
+      else if ((string[i] == '\'') || (string[i] == '"'))
+       delimiter = rl_line_buffer[i];
+      else if (!delimiter && (string[i] == closer))
+       level++;
+      else if (!delimiter && (string[i] == opener))
+       level--;
+
+      if (!level)
+       break;
+    }
+  return (i);
+}
+
+
+      
index 32ca4b7c575ec42c94ea6e5f503854daea27f1ea..7e5a820bcd7809b732a2c507094b6f5fc9f4cc6e 100644 (file)
@@ -1,36 +1,27 @@
 /* readline.c -- a general facility for reading lines of input
-   with emacs style editing and completion.  */
+   with emacs style editing and completion. */
 
 /* Copyright 1987, 1989, 1991, 1992 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
-   for it.
+   This file is part of the GNU Readline Library, a library for
+   reading lines of text with interactive input and history editing.
 
-   The 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 of the License, or
+   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 1, or
    (at your option) any later version.
 
-   The 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
+   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.
 
-   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* Remove these declarations when we have a complete libgnu.a. */
-/* #define STATIC_MALLOC */
-#if !defined (STATIC_MALLOC)
-extern char *xmalloc (), *xrealloc ();
-#else
-static char *xmalloc (), *xrealloc ();
-#endif /* STATIC_MALLOC */
+   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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "sysdep.h"
-#include <sys/types.h>
 #include <stdio.h>
 #include <fcntl.h>
 #ifndef        NO_SYS_FILE
@@ -38,216 +29,76 @@ static char *xmalloc (), *xrealloc ();
 #endif
 #include <signal.h>
 
+/* This is needed to include support for TIOCGWINSZ and window resizing. */
+#if defined (OSF1) || defined (BSD386) || defined (_386BSD) || defined (AIX)
+#  include <sys/ioctl.h>
+#endif /* OSF1 */
+
 #if defined (HAVE_UNISTD_H)
 #  include <unistd.h>
 #endif
-
-#define NEW_TTY_DRIVER
-#define HAVE_BSD_SIGNALS
-/* #define USE_XON_XOFF */
-
-#ifdef __MSDOS__
-#undef NEW_TTY_DRIVER
-#undef HAVE_BSD_SIGNALS
-#endif
-
-/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
-#if defined (USG) && !defined (hpux)
-#undef HAVE_BSD_SIGNALS
-#endif
-
-/* System V machines use termio. */
-#if !defined (_POSIX_VERSION)
-#  if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX)
-#    undef NEW_TTY_DRIVER
-#    define TERMIO_TTY_DRIVER
-#    include <termio.h>
-#    if !defined (TCOON)
-#      define TCOON 1
-#    endif
-#  endif /* USG || hpux || Xenix || sgi || DUGX */
-#endif /* !_POSIX_VERSION */
-
-/* Posix systems use termios and the Posix signal functions. */
-#if defined (_POSIX_VERSION)
-#  if !defined (TERMIOS_MISSING)
-#    undef NEW_TTY_DRIVER
-#    define TERMIOS_TTY_DRIVER
-#    include <termios.h>
-#  endif /* !TERMIOS_MISSING */
-#  define HAVE_POSIX_SIGNALS
-#  if !defined (O_NDELAY)
-#    define O_NDELAY O_NONBLOCK        /* Posix-style non-blocking i/o */
-#  endif /* O_NDELAY */
-#endif /* _POSIX_VERSION */
-
-/* Other (BSD) machines use sgtty. */
-#if defined (NEW_TTY_DRIVER)
-#include <sgtty.h>
-#endif
-
-/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
-   it is not already defined.  It is used both to determine if a
-   special character is disabled and to disable certain special
-   characters.  Posix systems should set to 0, USG systems to -1. */
-#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
-#  if defined (_POSIX_VERSION)
-#    define _POSIX_VDISABLE 0
-#  else /* !_POSIX_VERSION */
-#    define _POSIX_VDISABLE -1
-#  endif /* !_POSIX_VERSION */
-#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
 \f
-/* Define some macros for dealing with assorted signalling disciplines.
-
-   These macros provide a way to use signal blocking and disabling
-   without smothering your code in a pile of #ifdef's.
-
-   SIGNALS_UNBLOCK;                    Stop blocking all signals.
-
-   {
-     SIGNALS_DECLARE_SAVED (name);     Declare a variable to save the 
-                                       signal blocking state.
-       ...
-     SIGNALS_BLOCK (SIGSTOP, name);    Block a signal, and save the previous
-                                       state for restoration later.
-       ...
-     SIGNALS_RESTORE (name);           Restore previous signals.
-   }
-
-*/
-
-#ifdef HAVE_POSIX_SIGNALS
-                                                       /* POSIX signals */
-
-#define        SIGNALS_UNBLOCK \
-      do { sigset_t set;       \
-       sigemptyset (&set);     \
-       sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);      \
-      } while (0)
-
-#define        SIGNALS_DECLARE_SAVED(name)     sigset_t name
-
-#define        SIGNALS_BLOCK(SIG, saved)       \
-       do { sigset_t set;              \
-         sigemptyset (&set);           \
-         sigaddset (&set, SIG);        \
-         sigprocmask (SIG_BLOCK, &set, &saved);        \
-       } while (0)
-
-#define        SIGNALS_RESTORE(saved)          \
-  sigprocmask (SIG_SETMASK, &saved, (sigset_t *)NULL)
-
-
-#else  /* HAVE_POSIX_SIGNALS */
-#ifdef HAVE_BSD_SIGNALS
-                                                       /* BSD signals */
-
-#define        SIGNALS_UNBLOCK                 sigsetmask (0)
-#define        SIGNALS_DECLARE_SAVED(name)     int name
-#define        SIGNALS_BLOCK(SIG, saved)       saved = sigblock (sigmask (SIG))
-#define        SIGNALS_RESTORE(saved)          sigsetmask (saved)
-
-
-#else  /* HAVE_BSD_SIGNALS */
-                                                       /* None of the Above */
-
-#define        SIGNALS_UNBLOCK                 /* nothing */
-#define        SIGNALS_DECLARE_SAVED(name)     /* nothing */
-#define        SIGNALS_BLOCK(SIG, saved)       /* nothing */
-#define        SIGNALS_RESTORE(saved)          /* nothing */
-
-
-#endif /* HAVE_BSD_SIGNALS */
-#endif /* HAVE_POSIX_SIGNALS */
-
-/*  End of signal handling definitions.  */
-
-
 #include <errno.h>
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
 extern int errno;
+#endif /* !errno */
+
+extern char * getenv ();
 
 #include <setjmp.h>
 #include <sys/stat.h>
 
-/* Posix macro to check file in statbuf for directory-ness. */
-#if defined (S_IFDIR) && !defined (S_ISDIR)
-#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
-#endif
-
-#ifndef __MSDOS__
-/* These next are for filename completion.  Perhaps this belongs
-   in a different place. */
-#include <pwd.h>
-#endif /* __MSDOS__ */
-
-#if defined (USG) && !defined (isc386) && !defined (sgi)
-struct passwd *getpwuid (), *getpwent ();
-#endif
-
-/* #define HACK_TERMCAP_MOTION */
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
 
 /* Some standard library routines. */
 #include "readline.h"
 #include "history.h"
 
-#ifndef digit
-#define digit(c)  ((c) >= '0' && (c) <= '9')
-#endif
-
-#ifndef isletter
-#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
-#endif
-
-#ifndef digit_value
-#define digit_value(c) ((c) - '0')
-#endif
-
-#ifndef member
-#define member(c, s) ((c) ? index ((s), (c)) : 0)
-#endif
-
-#ifndef isident
-#define isident(c) ((isletter(c) || digit(c) || c == '_'))
-#endif
-
-#ifndef exchange
-#define exchange(x, y) {int temp = x; x = y; y = temp;}
-#endif
+/* NOTE: Functions and variables prefixed with `_rl_' are
+   pseudo-global: they are global so they can be shared
+   between files in the readline library, but are not intended
+   to be visible to readline callers. */
 
-#if !defined (rindex)
-extern char *rindex ();
-#endif /* rindex */
+/* Functions imported from other files in the library. */
+extern char *tgetstr ();
+extern void rl_prep_terminal (), rl_deprep_terminal ();
+extern Function *rl_function_of_keyseq ();
+extern char *tilde_expand ();
 
-#if !defined (index)
-extern char *index ();
-#endif /* index */
+/* External redisplay functions and variables from display.c */
+extern void rl_redisplay ();
+extern void _rl_move_vert ();
 
-extern char *getenv ();
-extern char *tilde_expand ();
+extern void _rl_erase_at_end_of_line ();
+extern void _rl_move_cursor_relative ();
 
-static update_line ();
-static void output_character_function ();
-static delete_chars ();
-static void insert_some_chars ();
+extern int _rl_vis_botlin;
+extern int _rl_last_c_pos;
+extern int rl_display_fixed;
 
-#if defined (VOID_SIGHANDLER)
-#  define sighandler void
-#else
-#  define sighandler int
-#endif /* VOID_SIGHANDLER */
+/* Variables imported from complete.c. */
+extern char *rl_completer_word_break_characters;
+extern char *rl_basic_word_break_characters;
+extern Function *rl_symbolic_link_hook;
+extern int rl_completion_query_items;
+extern int rl_complete_with_tilde_expansion;
 
-/* This typedef is equivalant to the one for Function; it allows us
-   to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
-typedef sighandler SigHandler ();
+/* Forward declarations used in this file. */
+void rl_dispatch ();
+void free_history_entry ();
+void _rl_output_character_function ();
+void _rl_set_screen_size ();
 
-/* If on, then readline handles signals in a way that doesn't screw. */
-#define HANDLE_SIGNALS
+#if !defined (_GO32_)
+static void readline_default_bindings ();
+#endif /* !_GO32_ */
 
-#ifdef __GO32__
-#include <sys/pc.h>
-#undef HANDLE_SIGNALS
-#endif
+#if defined (_GO32_)
+#  include <sys/pc.h>
+#  undef HANDLE_SIGNALS
+#endif /* _GO32_ */
 
 \f
 /* **************************************************************** */
@@ -256,13 +107,11 @@ typedef sighandler SigHandler ();
 /*                                                                 */
 /* **************************************************************** */
 
+static char *LibraryVersion = "2.0 (Cygnus)";
+
 /* A pointer to the keymap that is currently in use.
    By default, it is the standard emacs keymap. */
-Keymap keymap = emacs_standard_keymap;
-
-#define no_mode -1
-#define vi_mode 0
-#define emacs_mode 1
+Keymap _rl_keymap = emacs_standard_keymap;
 
 /* The current style of editing. */
 int rl_editing_mode = emacs_mode;
@@ -307,7 +156,8 @@ static jmp_buf readline_top_level;
 static FILE *in_stream, *out_stream;
 
 /* The names of the streams that we do input and output to. */
-FILE *rl_instream, *rl_outstream;
+FILE *rl_instream = (FILE *)NULL;
+FILE *rl_outstream = (FILE *)NULL;
 
 /* Non-zero means echo characters as they are read. */
 int readline_echoing_p = 1;
@@ -322,17 +172,12 @@ int rl_key_sequence_length = 0;
    before readline_internal () prints the first prompt. */
 Function *rl_startup_hook = (Function *)NULL;
 
-/* If non-zero, then this is the address of a function to call when
-   completing on a directory name.  The function is called with
-   the address of a string (the current directory name) as an arg. */
-Function *rl_symbolic_link_hook = (Function *)NULL;
-
 /* What we use internally.  You should always refer to RL_LINE_BUFFER. */
 static char *the_line;
 
 /* The character that can generate an EOF.  Really read from
    the terminal driver... just defaulted here. */
-static int eof_char = CTRL ('D');
+int _rl_eof_char = CTRL ('D');
 
 /* Non-zero makes this the next keystroke to read. */
 int rl_pending_input = 0;
@@ -340,11 +185,26 @@ int rl_pending_input = 0;
 /* Pointer to a useful terminal name. */
 char *rl_terminal_name = (char *)NULL;
 
+/* Non-zero means to always use horizontal scrolling in line display. */
+int _rl_horizontal_scroll_mode = 0;
+
+/* Non-zero means to display an asterisk at the starts of history lines
+   which have been modified. */
+int _rl_mark_modified_lines = 0;  
+   
+/* Non-zero means to use a visible bell if one is available rather than
+   simply ringing the terminal bell. */
+int _rl_prefer_visible_bell = 0;
+     
 /* Line buffer and maintenence. */
 char *rl_line_buffer = (char *)NULL;
 int rl_line_buffer_len = 0;
 #define DEFAULT_BUFFER_SIZE 256
 
+#if defined (VISIBLE_STATS)
+int rl_visible_stats = 0;
+#endif /* VISIBLE_STATS */
+
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -354,15 +214,17 @@ int rl_line_buffer_len = 0;
 
 /* Non-zero means do not parse any lines other than comments and
    parser directives. */
-static unsigned char parsing_conditionalized_out = 0;
-
-/* Caseless strcmp (). */
-static int stricmp (), strnicmp ();
-static char *strpbrk ();
+unsigned char _rl_parsing_conditionalized_out = 0;
 
 /* Non-zero means to save keys that we dispatch on in a kbd macro. */
 static int defining_kbd_macro = 0;
 
+/* Non-zero means to convert characters with the meta bit set to
+   escape-prefixed characters so we can indirect through
+   emacs_meta_keymap or vi_escape_keymap. */
+int _rl_convert_meta_chars_to_ascii = 1;
+
+static int doing_an_undo;
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -370,8 +232,8 @@ static int defining_kbd_macro = 0;
 /*                                                                 */
 /* **************************************************************** */
 
-static void rl_prep_terminal (), rl_deprep_terminal ();
-static void clear_to_eol (), rl_generic_bind ();
+/* Non-zero means treat 0200 bit in terminal input as Meta bit. */
+int _rl_meta_flag = 0; /* Forward declaration */
 
 /* Read a line of input.  Prompt with PROMPT.  A NULL PROMPT means
    none.  A return value of NULL means that EOF was encountered. */
@@ -392,7 +254,7 @@ readline (prompt)
     }
 
   rl_initialize ();
-  rl_prep_terminal ();
+  rl_prep_terminal (_rl_meta_flag);
 
 #if defined (HANDLE_SIGNALS)
   rl_set_signals ();
@@ -446,7 +308,9 @@ readline_internal ()
   while (!rl_done)
     {
       int lk = last_command_was_kill;
-      int code = setjmp (readline_top_level);
+      int code;
+
+      code = setjmp (readline_top_level);
 
       if (code)
        rl_redisplay ();
@@ -464,16 +328,16 @@ readline_internal ()
       if (c == EOF && rl_end)
        c = NEWLINE;
 
-      /* The character eof_char typed to blank line, and not as the
+      /* The character _rl_eof_char typed to blank line, and not as the
         previous character is interpreted as EOF. */
-      if (((c == eof_char && lastc != c) || c == EOF) && !rl_end)
+      if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
        {
          eof_found = 1;
          break;
        }
 
       lastc = c;
-      rl_dispatch (c, keymap);
+      rl_dispatch (c, _rl_keymap);
 
       /* If there was no change in last_command_was_kill, then no kill
         has taken place.  Note that if input is pending we are reading
@@ -487,7 +351,7 @@ readline_internal ()
 #if defined (VI_MODE)
       /* In vi mode, when you exit insert mode, the cursor moves back
         over the previous character.  We explicitly check for that here. */
-      if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap)
+      if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
        rl_vi_check ();
 #endif /* VI_MODE */
 
@@ -524,151 +388,6 @@ readline_internal ()
     return (savestring (the_line));
 }
 
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                        Signal Handling                          */
-/*                                                                 */
-/* **************************************************************** */
-
-#if defined (SIGWINCH)
-static SigHandler *old_sigwinch = (SigHandler *)NULL;
-
-static sighandler
-rl_handle_sigwinch (sig)
-     int sig;
-{
-  char *term;
-
-  term = rl_terminal_name;
-
-  if (readline_echoing_p)
-    {
-      if (!term)
-       term = getenv ("TERM");
-      if (!term)
-       term = "dumb";
-      rl_reset_terminal (term);
-#if defined (NOTDEF)
-      crlf ();
-      rl_forced_update_display ();
-#endif /* NOTDEF */
-    }
-
-  if (old_sigwinch &&
-      old_sigwinch != (SigHandler *)SIG_IGN &&
-      old_sigwinch != (SigHandler *)SIG_DFL)
-    (*old_sigwinch) (sig);
-#if !defined (VOID_SIGHANDLER)
-  return (0);
-#endif /* VOID_SIGHANDLER */
-}
-#endif  /* SIGWINCH */
-
-#if defined (HANDLE_SIGNALS)
-/* Interrupt handling. */
-static SigHandler
-  *old_int  = (SigHandler *)NULL,
-  *old_tstp = (SigHandler *)NULL,
-  *old_ttou = (SigHandler *)NULL,
-  *old_ttin = (SigHandler *)NULL,
-  *old_cont = (SigHandler *)NULL,
-  *old_alrm = (SigHandler *)NULL;
-
-/* Handle an interrupt character. */
-static sighandler
-rl_signal_handler (sig)
-     int sig;
-{
-#if !defined (HAVE_BSD_SIGNALS)
-  /* Since the signal will not be blocked while we are in the signal
-     handler, ignore it until rl_clear_signals resets the catcher. */
-  if (sig == SIGINT)
-    signal (sig, SIG_IGN);
-#endif /* !HAVE_BSD_SIGNALS */
-
-  switch (sig)
-    {
-    case SIGINT:
-      free_undo_list ();
-      rl_clear_message ();
-      rl_init_argument ();
-
-#if defined (SIGTSTP)
-    case SIGTSTP:
-    case SIGTTOU:
-    case SIGTTIN:
-#endif /* SIGTSTP */
-    case SIGALRM:
-      rl_clean_up_for_exit ();
-      rl_deprep_terminal ();
-      rl_clear_signals ();
-      rl_pending_input = 0;
-
-      kill (getpid (), sig);
-
-      SIGNALS_UNBLOCK;
-
-      rl_prep_terminal ();
-      rl_set_signals ();
-    }
-
-#if !defined (VOID_SIGHANDLER)
-  return (0);
-#endif /* !VOID_SIGHANDLER */
-}
-
-rl_set_signals ()
-{
-  old_int = (SigHandler *)signal (SIGINT, rl_signal_handler);
-  if (old_int == (SigHandler *)SIG_IGN)
-    signal (SIGINT, SIG_IGN);
-
-  old_alrm = (SigHandler *)signal (SIGALRM, rl_signal_handler);
-  if (old_alrm == (SigHandler *)SIG_IGN)
-    signal (SIGALRM, SIG_IGN);
-
-#if defined (SIGTSTP)
-  old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler);
-  if (old_tstp == (SigHandler *)SIG_IGN)
-    signal (SIGTSTP, SIG_IGN);
-#endif
-#if defined (SIGTTOU)
-  old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler);
-  old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler);
-
-  if (old_tstp == (SigHandler *)SIG_IGN)
-    {
-      signal (SIGTTOU, SIG_IGN);
-      signal (SIGTTIN, SIG_IGN);
-    }
-#endif
-
-#if defined (SIGWINCH)
-  old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch);
-#endif
-}
-
-rl_clear_signals ()
-{
-  signal (SIGINT, old_int);
-  signal (SIGALRM, old_alrm);
-
-#if defined (SIGTSTP)
-  signal (SIGTSTP, old_tstp);
-#endif
-
-#if defined (SIGTTOU)
-  signal (SIGTTOU, old_ttou);
-  signal (SIGTTIN, old_ttin);
-#endif
-
-#if defined (SIGWINCH)
-      signal (SIGWINCH, old_sigwinch);
-#endif
-}
-#endif  /* HANDLE_SIGNALS */
-
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -676,12 +395,6 @@ rl_clear_signals ()
 /*                                                                 */
 /* **************************************************************** */
 
-#if defined (USE_XON_XOFF)
-/* If the terminal was in xoff state when we got to it, then xon_char
-   contains the character that is supposed to start it again. */
-static int xon_char, xoff_state;
-#endif /* USE_XON_XOFF */
-
 static int pop_index = 0, push_index = 0, ibuffer_len = 511;
 static unsigned char ibuffer[512];
 
@@ -754,29 +467,31 @@ rl_unget_char (key)
 
 /* If a character is available to be read, then read it
    and stuff it into IBUFFER.  Otherwise, just return. */
+void
 rl_gather_tyi ()
 {
 #ifdef __GO32__
   char input;
-  if (isatty(0))
-  {
-    int i = rl_getc();
-    if (i != EOF)
-      rl_stuff_char(i);
-  }
-  else
-    if (kbhit() && ibuffer_space())
-      rl_stuff_char(getkey());
+  if (isatty (0))
+    {
+      int i = rl_getc ();
+      if (i != EOF)
+       rl_stuff_char (i);
+    }
+  else if (kbhit () && ibuffer_space ())
+    rl_stuff_char (getkey ());
 #else
+
   int tty = fileno (in_stream);
   register int tem, result = -1;
-  long chars_avail;
+  int chars_avail;
   char input;
 
 #if defined (FIONREAD)
   result = ioctl (tty, FIONREAD, &chars_avail);
 #endif
 
+#if defined (O_NDELAY)
   if (result == -1)
     {
       int flags;
@@ -790,6 +505,7 @@ rl_gather_tyi ()
       if (chars_avail == -1 && errno == EAGAIN)
        return;
     }
+#endif /* O_NDELAY */
 
   /* If there's nothing available, don't waste time trying to read
      something. */
@@ -860,26 +576,31 @@ rl_read_key ()
   return (c);
 }
 
-/* I'm beginning to hate the declaration rules for various compilers. */
+/* Found later in this file. */
 static void add_macro_char (), with_macro_input ();
 
 /* Do the command associated with KEY in MAP.
    If the associated command is really a keymap, then read
    another key, and dispatch into that map. */
+void
 rl_dispatch (key, map)
      register int key;
      Keymap map;
 {
+#if defined (VI_MODE)
+  extern int _rl_vi_last_command, _rl_vi_last_repeat, _rl_vi_last_arg_sign;
+#endif
 
   if (defining_kbd_macro)
     add_macro_char (key);
 
-  if (key > 127 && key < 256)
+  if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
     {
       if (map[ESC].type == ISKMAP)
        {
          map = (Keymap)map[ESC].function;
-         key -= 128;
+         key = UNMETA (key);
+         rl_key_sequence_length += 2;
          rl_dispatch (key, map);
        }
       else
@@ -945,6 +666,15 @@ rl_dispatch (key, map)
        }
       break;
     }
+#if defined (VI_MODE)
+  if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
+      rl_vi_textmod_command (key))
+    {
+      _rl_vi_last_command = key;
+      _rl_vi_last_repeat = rl_numeric_arg;
+      _rl_vi_last_arg_sign = rl_arg_sign;
+    }
+#endif
 }
 
 \f
@@ -1131,8 +861,6 @@ rl_call_last_kbd_macro (count, ignore)
 /* Initliaze readline (and terminal if not already). */
 rl_initialize ()
 {
-  extern char *rl_display_prompt;
-
   /* If we have never been called before, initialize the
      terminal and data structures. */
   if (!rl_initialized)
@@ -1153,21 +881,13 @@ rl_initialize ()
   start_using_history ();
 
   /* Make the display buffer match the state of the line. */
-  {
-    extern char *rl_display_prompt;
-    extern int forced_display;
-
-    rl_on_new_line ();
-
-    rl_display_prompt = rl_prompt ? rl_prompt : "";
-    forced_display = 1;
-  }
+  rl_reset_line_state ();
 
   /* No such function typed yet. */
   rl_last_func = (Function *)NULL;
 
   /* Parsing of key-bindings begins in an enabled state. */
-  parsing_conditionalized_out = 0;
+  _rl_parsing_conditionalized_out = 0;
 }
 
 /* Initialize the entire state of the world. */
@@ -1176,12 +896,18 @@ readline_initialize_everything ()
   /* Find out if we are running in Emacs. */
   running_in_emacs = getenv ("EMACS");
 
-  /* Set up input and output if they aren't already.  */
+  /* Set up input and output if they are not already set up. */
   if (!rl_instream)
     rl_instream = stdin;
+
   if (!rl_outstream)
     rl_outstream = stdout;
 
+  /* Bind in_stream and out_stream immediately.  These values may change,
+     but they may also be used before readline_internal () is called. */
+  in_stream = rl_instream;
+  out_stream = rl_outstream;
+
   /* Allocate data structures. */
   if (!rl_line_buffer)
     rl_line_buffer =
@@ -1202,9 +928,6 @@ readline_initialize_everything ()
   /* If the completion parser's default word break characters haven't
      been set yet, then do so now. */
   {
-    extern char *rl_completer_word_break_characters;
-    extern char *rl_basic_word_break_characters;
-
     if (rl_completer_word_break_characters == (char *)NULL)
       rl_completer_word_break_characters = rl_basic_word_break_characters;
   }
@@ -1213,101 +936,10 @@ readline_initialize_everything ()
 /* If this system allows us to look at the values of the regular
    input editing characters, then bind them to their readline
    equivalents, iff the characters are not bound to keymaps. */
+static void
 readline_default_bindings ()
 {
-#ifndef __GO32__
-
-#if defined (NEW_TTY_DRIVER)
-  struct sgttyb ttybuff;
-  int tty = fileno (rl_instream);
-
-  if (ioctl (tty, TIOCGETP, &ttybuff) != -1)
-    {
-      int erase, kill;
-
-      erase = ttybuff.sg_erase;
-      kill  = ttybuff.sg_kill;
-
-      if (erase != -1 && keymap[erase].type == ISFUNC)
-       keymap[erase].function = rl_rubout;
-
-      if (kill != -1 && keymap[kill].type == ISFUNC)
-       keymap[kill].function = rl_unix_line_discard;
-    }
-
-#if defined (TIOCGLTC)
-  {
-    struct ltchars lt;
-
-    if (ioctl (tty, TIOCGLTC, &lt) != -1)
-      {
-       int erase, nextc;
-
-       erase = lt.t_werasc;
-       nextc = lt.t_lnextc;
-
-       if (erase != -1 && keymap[erase].type == ISFUNC)
-         keymap[erase].function = rl_unix_word_rubout;
-
-       if (nextc != -1 && keymap[nextc].type == ISFUNC)
-         keymap[nextc].function = rl_quoted_insert;
-      }
-  }
-#endif /* TIOCGLTC */
-#else /* not NEW_TTY_DRIVER */
-
-#if defined (TERMIOS_TTY_DRIVER)
-  struct termios ttybuff;
-#else
-  struct termio ttybuff;
-#endif /* TERMIOS_TTY_DRIVER */
-  int tty = fileno (rl_instream);
-
-#if defined (TERMIOS_TTY_DRIVER)
-  if (tcgetattr (tty, &ttybuff) != -1)
-#else
-  if (ioctl (tty, TCGETA, &ttybuff) != -1)
-#endif /* !TERMIOS_TTY_DRIVER */
-    {
-      int erase, kill;
-
-      erase = ttybuff.c_cc[VERASE];
-      kill = ttybuff.c_cc[VKILL];
-
-      if (erase != _POSIX_VDISABLE &&
-         keymap[(unsigned char)erase].type == ISFUNC)
-       keymap[(unsigned char)erase].function = rl_rubout;
-
-      if (kill != _POSIX_VDISABLE &&
-         keymap[(unsigned char)kill].type == ISFUNC)
-       keymap[(unsigned char)kill].function = rl_unix_line_discard;
-
-#if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
-      {
-       int nextc;
-
-       nextc = ttybuff.c_cc[VLNEXT];
-
-       if (nextc != _POSIX_VDISABLE &&
-           keymap[(unsigned char)nextc].type == ISFUNC)
-         keymap[(unsigned char)nextc].function = rl_quoted_insert;
-      }
-#endif /* VLNEXT && TERMIOS_TTY_DRIVER */
-
-#if defined (VWERASE)
-      {
-       int werase;
-
-       werase = ttybuff.c_cc[VWERASE];
-
-       if (werase != _POSIX_VDISABLE &&
-           keymap[(unsigned char)werase].type == ISFUNC)
-         keymap[(unsigned char)werase].function = rl_unix_word_rubout;
-      }
-#endif /* VWERASE */
-    }
-#endif /* !NEW_TTY_DRIVER */
-#endif /* def __GO32__ */
+  rltty_set_default_bindings (_rl_keymap);
 }
 
 \f
@@ -1356,11 +988,11 @@ rl_digit_loop ()
   int key, c;
   while (1)
     {
-      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
+      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
       key = c = rl_read_key ();
 
-      if (keymap[c].type == ISFUNC &&
-         keymap[c].function == rl_universal_argument)
+      if (_rl_keymap[c].type == ISFUNC &&
+         _rl_keymap[c].function == rl_universal_argument)
        {
          rl_numeric_arg *= 4;
          continue;
@@ -1384,706 +1016,163 @@ rl_digit_loop ()
          else
            {
              rl_clear_message ();
-             rl_dispatch (key, keymap);
+             rl_dispatch (key, _rl_keymap);
              return;
            }
        }
     }
 }
-
 \f
 /* **************************************************************** */
 /*                                                                 */
-/*                     Display stuff                               */
+/*                     Terminal and Termcap                        */
 /*                                                                 */
 /* **************************************************************** */
 
-/* This is the stuff that is hard for me.  I never seem to write good
-   display routines in C.  Let's see how I do this time. */
-
-/* (PWP) Well... Good for a simple line updater, but totally ignores
-   the problems of input lines longer than the screen width.
-
-   update_line and the code that calls it makes a multiple line,
-   automatically wrapping line update.  Carefull attention needs
-   to be paid to the vertical position variables.
-
-   handling of terminals with autowrap on (incl. DEC braindamage)
-   could be improved a bit.  Right now I just cheat and decrement
-   screenwidth by one. */
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
 
-/* Keep two buffers; one which reflects the current contents of the
-   screen, and the other to draw what we think the new contents should
-   be.  Then compare the buffers, and make whatever changes to the
-   screen itself that we should.  Finally, make the buffer that we
-   just drew into be the one which reflects the current contents of the
-   screen, and place the cursor where it belongs.
+/* Non-zero means this terminal can't really do anything. */
+int dumb_term = 0;
+/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
+   Unfortunately, PC is a global variable used by the termcap library. */
+#undef PC      
 
-   Commands that want to can fix the display themselves, and then let
-   this function know that the display has been fixed by setting the
-   RL_DISPLAY_FIXED variable.  This is good for efficiency. */
+#if !defined (__linux__)
+char PC;
+char *BC, *UP;
+#endif /* __linux__ */
 
-/* Termcap variables: */
-extern char *term_up, *term_dc, *term_cr;
-extern int screenheight, screenwidth, terminal_can_insert;
+/* Some strings to control terminal actions.  These are output by tputs (). */
+char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
 
-/* What YOU turn on when you have handled all redisplay yourself. */
-int rl_display_fixed = 0;
+int screenwidth, screenheight;
 
-/* The visible cursor position.  If you print some text, adjust this. */
-int last_c_pos = 0;
-int last_v_pos = 0;
+/* Non-zero if we determine that the terminal can do character insertion. */
+int terminal_can_insert = 0;
 
-/* The last left edge of text that was displayed.  This is used when
-   doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
-static int last_lmargin = 0;
+/* How to insert characters. */
+char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
 
-/* The line display buffers.  One is the line currently displayed on
-   the screen.  The other is the line about to be displayed. */
-static char *visible_line = (char *)NULL;
-static char *invisible_line = (char *)NULL;
+/* How to delete characters. */
+char *term_dc, *term_DC;
 
-/* Number of lines currently on screen minus 1. */
-int vis_botlin = 0;
+#if defined (HACK_TERMCAP_MOTION)
+char *term_forward_char;
+#endif  /* HACK_TERMCAP_MOTION */
 
-/* A buffer for `modeline' messages. */
-char msg_buf[128];
+/* How to go up a line. */
+char *term_up;
 
-/* Non-zero forces the redisplay even if we thought it was unnecessary. */
-int forced_display = 0;
+/* A visible bell, if the terminal can be made to flash the screen. */
+char *visible_bell;
 
-/* The stuff that gets printed out before the actual text of the line.
-   This is usually pointing to rl_prompt. */
-char *rl_display_prompt = (char *)NULL;
+/* Non-zero means that this terminal has a meta key. */
+int term_has_meta;
 
-/* Default and initial buffer size.  Can grow. */
-static int line_size = 1024;
+/* The string to write to turn on the meta key, if this term has one. */
+char *term_mm;
 
-/* Non-zero means to always use horizontal scrolling in line display. */
-static int horizontal_scroll_mode = 0;
+/* The string to write to turn off the meta key, if this term has one. */
+char *term_mo;
 
-/* Non-zero means to display an asterisk at the starts of history lines
-   which have been modified. */
-static int mark_modified_lines = 0;
+/* The key sequences output by the arrow keys, if this terminal has any. */
+char *term_ku, *term_kd, *term_kr, *term_kl;
 
-/* Non-zero means to use a visible bell if one is available rather than
-   simply ringing the terminal bell. */
-static int prefer_visible_bell = 0;
-
-/* I really disagree with this, but my boss (among others) insists that we
-   support compilers that don't work.  I don't think we are gaining by doing
-   so; what is the advantage in producing better code if we can't use it? */
-/* The following two declarations belong inside the
-   function block, not here. */
-static void move_cursor_relative ();
-static void output_some_chars ();
-static void output_character_function ();
-static int compare_strings ();
-
-/* Basic redisplay algorithm. */
-rl_redisplay ()
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+   has changed. */
+rl_reset_terminal (terminal_name)
+     char *terminal_name;
 {
-  register int in, out, c, linenum;
-  register char *line = invisible_line;
-  char *prompt_this_line;
-  int c_pos = 0;
-  int inv_botlin = 0;          /* Number of lines in newly drawn buffer. */
-
-  extern int readline_echoing_p;
-
-  if (!readline_echoing_p)
-    return;
+  init_terminal_io (terminal_name);
+}
 
-  if (!rl_display_prompt)
-    rl_display_prompt = "";
+/* Set readline's idea of the screen size.  TTY is a file descriptor open
+   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
+   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
+   non-null serve to check whether or not we have initialized termcap. */
+void
+_rl_set_screen_size (tty, ignore_env)
+     int tty, ignore_env;
+{
+#if defined (TIOCGWINSZ)
+  struct winsize window_size;
+#endif /* TIOCGWINSZ */
 
-  if (!invisible_line)
+#if defined (TIOCGWINSZ)
+  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
     {
-      visible_line = (char *)xmalloc (line_size);
-      invisible_line = (char *)xmalloc (line_size);
-      line = invisible_line;
-      for (in = 0; in < line_size; in++)
-       {
-         visible_line[in] = 0;
-         invisible_line[in] = 1;
-       }
-      rl_on_new_line ();
+      screenwidth = (int) window_size.ws_col;
+      screenheight = (int) window_size.ws_row;
     }
+#endif /* TIOCGWINSZ */
 
-  /* Draw the line into the buffer. */
-  c_pos = -1;
-
-  /* Mark the line as modified or not.  We only do this for history
-     lines. */
-  out = 0;
-  if (mark_modified_lines && current_history () && rl_undo_list)
+  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
+     is unset. */
+  if (screenwidth <= 0)
     {
-      line[out++] = '*';
-      line[out] = '\0';
-    }
+      char *sw;
 
-  /* If someone thought that the redisplay was handled, but the currently
-     visible line has a different modification state than the one about
-     to become visible, then correct the callers misconception. */
-  if (visible_line[0] != invisible_line[0])
-    rl_display_fixed = 0;
+      if (!ignore_env && (sw = getenv ("COLUMNS")))
+       screenwidth = atoi (sw);
 
-  prompt_this_line = rindex (rl_display_prompt, '\n');
-  if (!prompt_this_line)
-    prompt_this_line = rl_display_prompt;
-  else
-    {
-      prompt_this_line++;
-      if (forced_display)
-       output_some_chars (rl_display_prompt,
-                          prompt_this_line - rl_display_prompt);
+      if (screenwidth <= 0 && term_string_buffer)
+       screenwidth = tgetnum ("co");
     }
 
-  strncpy (line + out,  prompt_this_line, strlen (prompt_this_line));
-  out += strlen (prompt_this_line);
-  line[out] = '\0';
-
-  for (in = 0; in < rl_end; in++)
+  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
+     is unset. */
+  if (screenheight <= 0)
     {
-      c = (unsigned char)the_line[in];
+      char *sh;
 
-      if (out + 1 >= line_size)
-       {
-         line_size *= 2;
-         visible_line = (char *)xrealloc (visible_line, line_size);
-         invisible_line = (char *)xrealloc (invisible_line, line_size);
-         line = invisible_line;
-       }
+      if (!ignore_env && (sh = getenv ("LINES")))
+       screenheight = atoi (sh);
 
-      if (in == rl_point)
-       c_pos = out;
-
-      if (c > 127)
-       {
-         line[out++] = 'M';
-         line[out++] = '-';
-         line[out++] = c - 128;
-       }
-#define DISPLAY_TABS
-#if defined (DISPLAY_TABS)
-      else if (c == '\t')
-       {
-         register int newout = (out | (int)7) + 1;
-         while (out < newout)
-           line[out++] = ' ';
-       }
-#endif
-      else if (c < 32)
-       {
-         line[out++] = 'C';
-         line[out++] = '-';
-         line[out++] = c + 64;
-       }
-      else if (c == 127)
-       {
-         line[out++] = 'C';
-         line[out++] = '-';
-         line[out++] = '?';
-       }
-      else
-       line[out++] = c;
+      if (screenheight <= 0 && term_string_buffer)
+       screenheight = tgetnum ("li");
     }
-  line[out] = '\0';
-  if (c_pos < 0)
-    c_pos = out;
 
-  /* PWP: now is when things get a bit hairy.  The visible and invisible
-     line buffers are really multiple lines, which would wrap every
-     (screenwidth - 1) characters.  Go through each in turn, finding
-     the changed region and updating it.  The line order is top to bottom. */
+  /* If all else fails, default to 80x24 terminal. */
+  if (screenwidth <= 0)
+    screenwidth = 80;
 
-  /* If we can move the cursor up and down, then use multiple lines,
-     otherwise, let long lines display in a single terminal line, and
-     horizontally scroll it. */
+  if (screenheight <= 0)
+    screenheight = 24;
 
-  if (!horizontal_scroll_mode && term_up && *term_up)
-    {
-      int total_screen_chars = (screenwidth * screenheight);
-
-      if (!rl_display_fixed || forced_display)
-       {
-         forced_display = 0;
-
-         /* If we have more than a screenful of material to display, then
-            only display a screenful.  We should display the last screen,
-            not the first.  I'll fix this in a minute. */
-         if (out >= total_screen_chars)
-           out = total_screen_chars - 1;
-
-         /* Number of screen lines to display. */
-         inv_botlin = out / screenwidth;
-
-         /* For each line in the buffer, do the updating display. */
-         for (linenum = 0; linenum <= inv_botlin; linenum++)
-           update_line (linenum > vis_botlin ? ""
-                        : &visible_line[linenum * screenwidth],
-                        &invisible_line[linenum * screenwidth],
-                        linenum);
-
-         /* We may have deleted some lines.  If so, clear the left over
-            blank ones at the bottom out. */
-         if (vis_botlin > inv_botlin)
-           {
-             char *tt;
-             for (; linenum <= vis_botlin; linenum++)
-               {
-                 tt = &visible_line[linenum * screenwidth];
-                 move_vert (linenum);
-                 move_cursor_relative (0, tt);
-                 clear_to_eol ((linenum == vis_botlin)?
-                               strlen (tt) : screenwidth);
-               }
-           }
-         vis_botlin = inv_botlin;
-
-         /* Move the cursor where it should be. */
-         move_vert (c_pos / screenwidth);
-         move_cursor_relative (c_pos % screenwidth,
-                               &invisible_line[(c_pos / screenwidth) * screenwidth]);
-       }
-    }
-  else                         /* Do horizontal scrolling. */
-    {
-      int lmargin;
-
-      /* Always at top line. */
-      last_v_pos = 0;
-
-      /* If the display position of the cursor would be off the edge
-        of the screen, start the display of this line at an offset that
-        leaves the cursor on the screen. */
-      if (c_pos - last_lmargin > screenwidth - 2)
-       lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
-      else if (c_pos - last_lmargin < 1)
-       lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
-      else
-       lmargin = last_lmargin;
-
-      /* If the first character on the screen isn't the first character
-        in the display line, indicate this with a special character. */
-      if (lmargin > 0)
-       line[lmargin] = '<';
-
-      if (lmargin + screenwidth < out)
-       line[lmargin + screenwidth - 1] = '>';
-
-      if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
-       {
-         forced_display = 0;
-         update_line (&visible_line[last_lmargin],
-                      &invisible_line[lmargin], 0);
-
-         move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
-         last_lmargin = lmargin;
-       }
-    }
-  fflush (out_stream);
-
-  /* Swap visible and non-visible lines. */
-  {
-    char *temp = visible_line;
-    visible_line = invisible_line;
-    invisible_line = temp;
-    rl_display_fixed = 0;
-  }
-}
-
-/* PWP: update_line() is based on finding the middle difference of each
-   line on the screen; vis:
-
-                            /old first difference
-       /beginning of line   |              /old last same       /old EOL
-       v                    v              v                    v
-old:   eddie> Oh, my little gruntle-buggy is to me, as lurgid as
-new:   eddie> Oh, my little buggy says to me, as lurgid as
-       ^                    ^        ^                    ^
-       \beginning of line   |        \new last same       \new end of line
-                            \new first difference
-
-   All are character pointers for the sake of speed.  Special cases for
-   no differences, as well as for end of line additions must be handeled.
-
-   Could be made even smarter, but this works well enough */
-static
-update_line (old, new, current_line)
-     register char *old, *new;
-     int current_line;
-{
-  register char *ofd, *ols, *oe, *nfd, *nls, *ne;
-  int lendiff, wsatend;
-
-  /* Find first difference. */
-  for (ofd = old, nfd = new;
-       (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
-       ofd++, nfd++)
-    ;
-
-  /* Move to the end of the screen line. */
-  for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
-  for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
-
-  /* If no difference, continue to next line. */
-  if (ofd == oe && nfd == ne)
-    return;
-
-  wsatend = 1;                 /* flag for trailing whitespace */
-  ols = oe - 1;                        /* find last same */
-  nls = ne - 1;
-  while ((*ols == *nls) && (ols > ofd) && (nls > nfd))
-    {
-      if (*ols != ' ')
-       wsatend = 0;
-      ols--;
-      nls--;
-    }
-
-  if (wsatend)
-    {
-      ols = oe;
-      nls = ne;
-    }
-  else if (*ols != *nls)
-    {
-      if (*ols)                        /* don't step past the NUL */
-       ols++;
-      if (*nls)
-       nls++;
-    }
-
-  move_vert (current_line);
-  move_cursor_relative (ofd - old, old);
-
-  /* if (len (new) > len (old)) */
-  lendiff = (nls - nfd) - (ols - ofd);
-
-  /* Insert (diff(len(old),len(new)) ch */
-  if (lendiff > 0)
-    {
-      if (terminal_can_insert)
-       {
-         extern char *term_IC;
-
-         /* Sometimes it is cheaper to print the characters rather than
-            use the terminal's capabilities. */
-         if ((2 * (ne - nfd)) < lendiff && !term_IC)
-           {
-             output_some_chars (nfd, (ne - nfd));
-             last_c_pos += (ne - nfd);
-           }
-         else
-           {
-             if (*ols)
-               {
-                 insert_some_chars (nfd, lendiff);
-                 last_c_pos += lendiff;
-               }
-             else
-               {
-                 /* At the end of a line the characters do not have to
-                    be "inserted".  They can just be placed on the screen. */
-                 output_some_chars (nfd, lendiff);
-                 last_c_pos += lendiff;
-               }
-             /* Copy (new) chars to screen from first diff to last match. */
-             if (((nls - nfd) - lendiff) > 0)
-               {
-                 output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
-                 last_c_pos += ((nls - nfd) - lendiff);
-               }
-           }
-       }
-      else
-       {               /* cannot insert chars, write to EOL */
-         output_some_chars (nfd, (ne - nfd));
-         last_c_pos += (ne - nfd);
-       }
-    }
-  else                         /* Delete characters from line. */
-    {
-      /* If possible and inexpensive to use terminal deletion, then do so. */
-      if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
-       {
-         if (lendiff)
-           delete_chars (-lendiff); /* delete (diff) characters */
-
-         /* Copy (new) chars to screen from first diff to last match */
-         if ((nls - nfd) > 0)
-           {
-             output_some_chars (nfd, (nls - nfd));
-             last_c_pos += (nls - nfd);
-           }
-       }
-      /* Otherwise, print over the existing material. */
-      else
-       {
-         output_some_chars (nfd, (ne - nfd));
-         last_c_pos += (ne - nfd);
-         clear_to_eol ((oe - old) - (ne - new));
-       }
-    }
-}
-
-/* (PWP) tell the update routines that we have moved onto a
-   new (empty) line. */
-rl_on_new_line ()
-{
-  if (visible_line)
-    visible_line[0] = '\0';
-
-  last_c_pos = last_v_pos = 0;
-  vis_botlin = last_lmargin = 0;
-}
-
-/* Actually update the display, period. */
-rl_forced_update_display ()
-{
-  if (visible_line)
-    {
-      register char *temp = visible_line;
-
-      while (*temp) *temp++ = '\0';
-    }
-  rl_on_new_line ();
-  forced_display++;
-  rl_redisplay ();
-}
-
-/* Move the cursor from last_c_pos to NEW, which are buffer indices.
-   DATA is the contents of the screen line of interest; i.e., where
-   the movement is being done. */
-static void
-move_cursor_relative (new, data)
-     int new;
-     char *data;
-{
-  register int i;
-
-  /* It may be faster to output a CR, and then move forwards instead
-     of moving backwards. */
-  if (new + 1 < last_c_pos - new)
-    {
-#ifdef __MSDOS__
-      putc('\r', out_stream);
-#else
-      tputs (term_cr, 1, output_character_function);
-#endif
-      last_c_pos = 0;
-    }
-
-  if (last_c_pos == new) return;
-
-  if (last_c_pos < new)
-    {
-      /* Move the cursor forward.  We do it by printing the command
-        to move the cursor forward if there is one, else print that
-        portion of the output buffer again.  Which is cheaper? */
-
-      /* The above comment is left here for posterity.  It is faster
-        to print one character (non-control) than to print a control
-        sequence telling the terminal to move forward one character.
-        That kind of control is for people who don't know what the
-        data is underneath the cursor. */
-#if defined (HACK_TERMCAP_MOTION)
-      extern char *term_forward_char;
-
-      if (term_forward_char)
-       for (i = last_c_pos; i < new; i++)
-         tputs (term_forward_char, 1, output_character_function);
-      else
-       for (i = last_c_pos; i < new; i++)
-         putc (data[i], out_stream);
-#else
-      for (i = last_c_pos; i < new; i++)
-       putc (data[i], out_stream);
-#endif                         /* HACK_TERMCAP_MOTION */
-    }
-  else
-    backspace (last_c_pos - new);
-  last_c_pos = new;
-}
-
-/* PWP: move the cursor up or down. */
-move_vert (to)
-     int to;
-{
-  void output_character_function ();
-  register int delta, i;
-
-  if (last_v_pos == to) return;
-
-  if (to > screenheight)
-    return;
-
-#ifdef __GO32__
-  {
-    int cur_r, cur_c;
-    ScreenGetCursor(&cur_r, &cur_c);
-    ScreenSetCursor(cur_r+to-last_v_pos, cur_c);
-  }
-#else /* __GO32__ */
-  if ((delta = to - last_v_pos) > 0)
-    {
-      for (i = 0; i < delta; i++)
-       putc ('\n', out_stream);
-      tputs (term_cr, 1, output_character_function);
-      last_c_pos = 0;
-    }
-  else
-    {                  /* delta < 0 */
-      if (term_up && *term_up)
-       for (i = 0; i < -delta; i++)
-         tputs (term_up, 1, output_character_function);
-    }
-#endif /* __GO32__ */
-  last_v_pos = to;             /* now to is here */
-}
-
-/* Physically print C on out_stream.  This is for functions which know
-   how to optimize the display. */
-rl_show_char (c)
-     int c;
-{
-  if (c > 127)
-    {
-      fprintf (out_stream, "M-");
-      c -= 128;
-    }
-
-#if defined (DISPLAY_TABS)
-  if (c < 32 && c != '\t')
-#else
-  if (c < 32)
+#if defined (SHELL)
+  /* If we're being compiled as part of bash, set the environment
+     variables $LINES and $COLUMNS to new values. */
+  set_lines_and_columns (screenheight, screenwidth);
 #endif
-    {
-
-      c += 64;
-    }
-
-  putc (c, out_stream);
-  fflush (out_stream);
-}
-
-#if defined (DISPLAY_TABS)
-int
-rl_character_len (c, pos)
-     register int c, pos;
-{
-  if (c < ' ' || c > 126)
-    {
-      if (c == '\t')
-       return (((pos | (int)7) + 1) - pos);
-      else
-       return (3);
-    }
-  else
-    return (1);
-}
-#else
-int
-rl_character_len (c)
-     int c;
-{
-  if (c < ' ' || c > 126)
-    return (3);
-  else
-    return (1);
-}
-#endif  /* DISPLAY_TAB */
-
-/* How to print things in the "echo-area".  The prompt is treated as a
-   mini-modeline. */
-rl_message (string, arg1, arg2)
-     char *string;
-{
-  sprintf (msg_buf, string, arg1, arg2);
-  rl_display_prompt = msg_buf;
-  rl_redisplay ();
-}
-
-/* How to clear things from the "echo-area". */
-rl_clear_message ()
-{
-  rl_display_prompt = rl_prompt;
-  rl_redisplay ();
-}
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     Terminal and Termcap                        */
-/*                                                                 */
-/* **************************************************************** */
-
-static char *term_buffer = (char *)NULL;
-static char *term_string_buffer = (char *)NULL;
-
-/* Non-zero means this terminal can't really do anything. */
-int dumb_term = 0;
-
-/* On Solaris2, sys/types.h brings in sys/reg.h,
-   which screws up the Termcap variable PC, used below.  */
-
-#undef PC      
-
-char PC;
-char *BC, *UP;
-
-/* Some strings to control terminal actions.  These are output by tputs (). */
-char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
-
-int screenwidth, screenheight;
-
-/* Non-zero if we determine that the terminal can do character insertion. */
-int terminal_can_insert = 0;
-
-/* How to insert characters. */
-char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
-
-/* How to delete characters. */
-char *term_dc, *term_DC;
-
-#if defined (HACK_TERMCAP_MOTION)
-char *term_forward_char;
-#endif  /* HACK_TERMCAP_MOTION */
-
-/* How to go up a line. */
-char *term_up;
-
-/* A visible bell, if the terminal can be made to flash the screen. */
-char *visible_bell;
 
-/* Re-initialize the terminal considering that the TERM/TERMCAP variable
-   has changed. */
-rl_reset_terminal (terminal_name)
-     char *terminal_name;
-{
-  init_terminal_io (terminal_name);
+  screenwidth--;
 }
 
 init_terminal_io (terminal_name)
      char *terminal_name;
 {
 #ifdef __GO32__
-  screenwidth = ScreenCols();
-  screenheight = ScreenRows();
+  screenwidth = ScreenCols ();
+  screenheight = ScreenRows ();
   term_cr = "\r";
   term_im = term_ei = term_ic = term_IC = (char *)NULL;
   term_up = term_dc = term_DC = visible_bell = (char *)NULL;
+
+  /* Does the _GO32_ have a meta key?  I don't know. */
+  term_has_meta = 0;
+  term_mm = term_mo = (char *)NULL;
+
+  /* It probably has arrow keys, but I don't know what they are. */
+  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
+
 #if defined (HACK_TERMCAP_MOTION)
-      term_forward_char = (char *)NULL;
+  term_forward_char = (char *)NULL;
 #endif
   terminal_can_insert = 0;
   return;
-#else
-  extern char *tgetstr ();
+#else /* !__GO32__ */
   char *term, *buffer;
-#if defined (TIOCGWINSZ)
-  struct winsize window_size;
-#endif
   int tty;
 
   term = terminal_name ? terminal_name : getenv ("TERM");
@@ -2109,6 +1198,7 @@ init_terminal_io (terminal_name)
       term_cr = "\r";
       term_im = term_ei = term_ic = term_IC = (char *)NULL;
       term_up = term_dc = term_DC = visible_bell = (char *)NULL;
+      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
 #if defined (HACK_TERMCAP_MOTION)
       term_forward_char = (char *)NULL;
 #endif
@@ -2138,27 +1228,8 @@ init_terminal_io (terminal_name)
     tty = 0;
 
   screenwidth = screenheight = 0;
-#if defined (TIOCGWINSZ)
-  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
-    {
-      screenwidth = (int) window_size.ws_col;
-      screenheight = (int) window_size.ws_row;
-    }
-#endif
-
-  if (screenwidth <= 0 || screenheight <= 0)
-    {
-      screenwidth = tgetnum ("co");
-      screenheight = tgetnum ("li");
-    }
-
-  screenwidth--;
 
-  if (screenwidth <= 0)
-    screenwidth = 79;
-
-  if (screenheight <= 0)
-    screenheight = 24;
+  _rl_set_screen_size (tty, 0);
 
   term_im = tgetstr ("im", &buffer);
   term_ei = tgetstr ("ei", &buffer);
@@ -2176,104 +1247,87 @@ init_terminal_io (terminal_name)
   term_DC = tgetstr ("DC", &buffer);
 
   visible_bell = tgetstr ("vb", &buffer);
+
+  /* Check to see if this terminal has a meta key. */
+  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
+  if (term_has_meta)
+    {
+      term_mm = tgetstr ("mm", &buffer);
+      term_mo = tgetstr ("mo", &buffer);
+    }
+  else
+    {
+      term_mm = (char *)NULL;
+      term_mo = (char *)NULL;
+    }
+
+  /* Attempt to find and bind the arrow keys.  Do not override already
+     bound keys in an overzealous attempt, however. */
+  term_ku = tgetstr ("ku", &buffer);
+  term_kd = tgetstr ("kd", &buffer);
+  term_kr = tgetstr ("kr", &buffer);
+  term_kl = tgetstr ("kl", &buffer);
+
+  if (term_ku)
+    {
+      Function *func;
+
+      func = rl_function_of_keyseq (term_ku, _rl_keymap, (int *)NULL);
+
+      if (!func || func == rl_do_lowercase_version)
+       rl_set_key (term_ku, rl_get_previous_history, _rl_keymap);
+    }
+
+  if (term_kd)
+    {
+      Function *func;
+
+      func = rl_function_of_keyseq (term_kd, _rl_keymap, (int *)NULL);
+
+      if (!func || func == rl_do_lowercase_version)
+       rl_set_key (term_kd, rl_get_next_history, _rl_keymap);
+    }
+
+  if (term_kr)
+    {
+      Function *func;
+
+      func = rl_function_of_keyseq (term_kr, _rl_keymap, (int *)NULL);
+
+      if (!func || func == rl_do_lowercase_version)
+       rl_set_key (term_kr, rl_forward, _rl_keymap);
+    }
+
+  if (term_kl)
+    {
+      Function *func;
+
+      func = rl_function_of_keyseq (term_kl, _rl_keymap, (int *)NULL);
+
+      if (!func || func == rl_do_lowercase_version)
+       rl_set_key (term_kl, rl_backward, _rl_keymap);
+    }
 #endif /* !__GO32__ */
 }
 
 /* A function for the use of tputs () */
-static void
-output_character_function (c)
+void
+_rl_output_character_function (c)
      int c;
 {
   putc (c, out_stream);
 }
 
 /* Write COUNT characters from STRING to the output stream. */
-static void
-output_some_chars (string, count)
+void
+_rl_output_some_chars (string, count)
      char *string;
      int count;
 {
   fwrite (string, 1, count, out_stream);
 }
 
-/* Delete COUNT characters from the display line. */
-static
-delete_chars (count)
-     int count;
-{
-#ifdef __GO32__
-  int r, c, w;
-  ScreenGetCursor(&r, &c);
-  w = ScreenCols();
-  memcpy(ScreenPrimary+r*w+c, ScreenPrimary+r*w+c+count, w-c-count);
-  memset(ScreenPrimary+r*w+w-count, 0, count*2);
-#else /* __GO32__ */
-  if (count > screenwidth)
-    return;
-
-  if (term_DC && *term_DC)
-    {
-      char *tgoto (), *buffer;
-      buffer = tgoto (term_DC, 0, count);
-      tputs (buffer, 1, output_character_function);
-    }
-  else
-    {
-      if (term_dc && *term_dc)
-       while (count--)
-         tputs (term_dc, 1, output_character_function);
-    }
-#endif /* __GO32__ */
-}
-
-/* Insert COUNT characters from STRING to the output stream. */
-static void
-insert_some_chars (string, count)
-     char *string;
-     int count;
-{
-#ifdef __GO32__
-  int r, c, w;
-  ScreenGetCursor(&r, &c);
-  w = ScreenCols();
-  memcpy(ScreenPrimary+r*w+c+count, ScreenPrimary+r*w+c, w-c-count);
-  /* Print the text. */
-  output_some_chars (string, count);
-#else /* __GO32__ */
-  /* If IC is defined, then we do not have to "enter" insert mode. */
-  if (term_IC)
-    {
-      char *tgoto (), *buffer;
-      buffer = tgoto (term_IC, 0, count);
-      tputs (buffer, 1, output_character_function);
-      output_some_chars (string, count);
-    }
-  else
-    {
-      register int i;
-
-      /* If we have to turn on insert-mode, then do so. */
-      if (term_im && *term_im)
-       tputs (term_im, 1, output_character_function);
 
-      /* If there is a special command for inserting characters, then
-        use that first to open up the space. */
-      if (term_ic && *term_ic)
-       {
-         for (i = count; i--; )
-           tputs (term_ic, 1, output_character_function);
-       }
-
-      /* Print the text. */
-      output_some_chars (string, count);
-
-      /* If there is a string to turn off insert mode, we had best use
-        it now. */
-      if (term_ei && *term_ei)
-       tputs (term_ei, 1, output_character_function);
-    }
-#endif /* __GO32__ */
-}
 
 /* Move the cursor back. */
 backspace (count)
@@ -2284,7 +1338,7 @@ backspace (count)
 #ifndef __GO32__
   if (term_backspace)
     for (i = 0; i < count; i++)
-      tputs (term_backspace, 1, output_character_function);
+      tputs (term_backspace, 1, _rl_output_character_function);
   else
 #endif /* !__GO32__ */
     for (i = 0; i < count; i++)
@@ -2295,342 +1349,11 @@ backspace (count)
 crlf ()
 {
 #if defined (NEW_TTY_DRIVER)
-  tputs (term_cr, 1, output_character_function);
+  tputs (term_cr, 1, _rl_output_character_function);
 #endif /* NEW_TTY_DRIVER */
   putc ('\n', out_stream);
 }
 
-/* Clear to the end of the line.  COUNT is the minimum
-   number of character spaces to clear, */
-static void
-clear_to_eol (count)
-     int count;
-{
-#ifndef __GO32__
-  if (term_clreol)
-    {
-      tputs (term_clreol, 1, output_character_function);
-    }
-  else
-#endif /* !__GO32__ */
-    {
-      register int i;
-
-      /* Do one more character space. */
-      count++;
-
-      for (i = 0; i < count; i++)
-       putc (' ', out_stream);
-
-      backspace (count);
-    }
-}
-
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                   Saving and Restoring the TTY                  */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Non-zero means that the terminal is in a prepped state. */
-static int terminal_prepped = 0;
-
-#if defined (NEW_TTY_DRIVER)
-
-/* Standard flags, including ECHO. */
-static int original_tty_flags = 0;
-
-/* Local mode flags, like LPASS8. */
-static int local_mode_flags = 0;
-
-/* Terminal characters.  This has C-s and C-q in it. */
-static struct tchars original_tchars;
-
-/* Local special characters.  This has the interrupt characters in it. */
-#if defined (TIOCGLTC)
-static struct ltchars original_ltchars;
-#endif
-
-/* We use this to get and set the tty_flags. */
-static struct sgttyb the_ttybuff;
-
-/* Put the terminal in CBREAK mode so that we can detect key presses. */
-static void
-rl_prep_terminal ()
-{
-#ifndef __GO32__
-  int tty = fileno (rl_instream);
-  SIGNALS_DECLARE_SAVED (saved_signals);
-
-  if (terminal_prepped)
-    return;
-
-  SIGNALS_BLOCK (SIGINT, saved_signals);
-
-  /* We always get the latest tty values.  Maybe stty changed them. */
-  ioctl (tty, TIOCGETP, &the_ttybuff);
-  original_tty_flags = the_ttybuff.sg_flags;
-
-  readline_echoing_p = (original_tty_flags & ECHO);
-
-#if defined (TIOCLGET)
-  ioctl (tty, TIOCLGET, &local_mode_flags);
-#endif
-
-#if !defined (ANYP)
-#  define ANYP (EVENP | ODDP)
-#endif
-
-  /* If this terminal doesn't care how the 8th bit is used,
-     then we can use it for the meta-key.  We check by seeing
-     if BOTH odd and even parity are allowed. */
-  if (the_ttybuff.sg_flags & ANYP)
-    {
-#if defined (PASS8)
-      the_ttybuff.sg_flags |= PASS8;
-#endif
-
-      /* Hack on local mode flags if we can. */
-#if defined (TIOCLGET) && defined (LPASS8)
-      {
-       int flags;
-       flags = local_mode_flags | LPASS8;
-       ioctl (tty, TIOCLSET, &flags);
-      }
-#endif /* TIOCLGET && LPASS8 */
-    }
-
-#if defined (TIOCGETC)
-  {
-    struct tchars temp;
-
-    ioctl (tty, TIOCGETC, &original_tchars);
-    temp = original_tchars;
-
-#if defined (USE_XON_XOFF)
-    /* Get rid of C-s and C-q.
-       We remember the value of startc (C-q) so that if the terminal is in
-       xoff state, the user can xon it by pressing that character. */
-    xon_char = temp.t_startc;
-    temp.t_stopc = -1;
-    temp.t_startc = -1;
-
-    /* If there is an XON character, bind it to restart the output. */
-    if (xon_char != -1)
-      rl_bind_key (xon_char, rl_restart_output);
-#endif /* USE_XON_XOFF */
-
-    /* If there is an EOF char, bind eof_char to it. */
-    if (temp.t_eofc != -1)
-      eof_char = temp.t_eofc;
-
-#if defined (NO_KILL_INTR)
-    /* Get rid of C-\ and C-c. */
-    temp.t_intrc = temp.t_quitc = -1;
-#endif /* NO_KILL_INTR */
-
-    ioctl (tty, TIOCSETC, &temp);
-  }
-#endif /* TIOCGETC */
-
-#if defined (TIOCGLTC)
-  {
-    struct ltchars temp;
-
-    ioctl (tty, TIOCGLTC, &original_ltchars);
-    temp = original_ltchars;
-
-    /* Make the interrupt keys go away.  Just enough to make people
-       happy. */
-    temp.t_dsuspc = -1;        /* C-y */
-    temp.t_lnextc = -1;        /* C-v */
-
-    ioctl (tty, TIOCSLTC, &temp);
-  }
-#endif /* TIOCGLTC */
-
-  the_ttybuff.sg_flags &= ~(ECHO | CRMOD);
-  the_ttybuff.sg_flags |= CBREAK;
-  ioctl (tty, TIOCSETN, &the_ttybuff);
-
-  terminal_prepped = 1;
-
-  SIGNALS_RESTORE (saved_signals);
-#endif /* !__GO32__ */
-}
-
-/* Restore the terminal to its original state. */
-static void
-rl_deprep_terminal ()
-{
-#ifndef __GO32__
-  int tty = fileno (rl_instream);
-  SIGNALS_DECLARE_SAVED (saved_signals);
-
-  if (!terminal_prepped)
-    return;
-
-  SIGNALS_BLOCK (SIGINT, saved_signals);
-
-  the_ttybuff.sg_flags = original_tty_flags;
-  ioctl (tty, TIOCSETN, &the_ttybuff);
-  readline_echoing_p = 1;
-
-#if defined (TIOCLGET)
-  ioctl (tty, TIOCLSET, &local_mode_flags);
-#endif
-
-#if defined (TIOCSLTC)
-  ioctl (tty, TIOCSLTC, &original_ltchars);
-#endif
-
-#if defined (TIOCSETC)
-  ioctl (tty, TIOCSETC, &original_tchars);
-#endif
-  terminal_prepped = 0;
-
-  SIGNALS_RESTORE (saved_signals);
-#endif /* !__GO32 */
-}
-
-#else  /* !defined (NEW_TTY_DRIVER) */
-
-#if !defined (VMIN)
-#define VMIN VEOF
-#endif
-
-#if !defined (VTIME)
-#define VTIME VEOL
-#endif
-
-#ifndef __GO32__
-#if defined (TERMIOS_TTY_DRIVER)
-static struct termios otio;
-#else
-static struct termio otio;
-#endif /* !TERMIOS_TTY_DRIVER */
-#endif /* __GO32__ */
-
-static void
-rl_prep_terminal ()
-{
-#ifndef __GO32__
-  int tty = fileno (rl_instream);
-#if defined (TERMIOS_TTY_DRIVER)
-  struct termios tio;
-#else
-  struct termio tio;
-#endif /* !TERMIOS_TTY_DRIVER */
-
-  SIGNALS_DECLARE_SAVED (saved_signals);
-
-  if (terminal_prepped)
-    return;
-
-  /* Try to keep this function from being INTerrupted.  We can do it
-     on POSIX and systems with BSD-like signal handling. */
-  SIGNALS_BLOCK (SIGINT, saved_signals);
-
-#if defined (TERMIOS_TTY_DRIVER)
-  tcgetattr (tty, &tio);
-#else
-  ioctl (tty, TCGETA, &tio);
-#endif /* !TERMIOS_TTY_DRIVER */
-
-  otio = tio;
-
-  readline_echoing_p = (tio.c_lflag & ECHO);
-
-  tio.c_lflag &= ~(ICANON|ECHO);
-
-  if (otio.c_cc[VEOF] != _POSIX_VDISABLE)
-    eof_char = otio.c_cc[VEOF];
-
-#if defined (USE_XON_XOFF)
-#if defined (IXANY)
-  tio.c_iflag &= ~(IXON|IXOFF|IXANY);
-#else
-  /* `strict' Posix systems do not define IXANY. */
-  tio.c_iflag &= ~(IXON|IXOFF);
-#endif /* IXANY */
-#endif /* USE_XON_XOFF */
-
-  /* Only turn this off if we are using all 8 bits. */
-  /* |ISTRIP|INPCK */
-  tio.c_iflag &= ~(ISTRIP | INPCK);
-
-  /* Make sure we differentiate between CR and NL on input. */
-  tio.c_iflag &= ~(ICRNL | INLCR);
-
-#if !defined (HANDLE_SIGNALS)
-  tio.c_lflag &= ~ISIG;
-#else
-  tio.c_lflag |= ISIG;
-#endif
-
-  tio.c_cc[VMIN] = 1;
-  tio.c_cc[VTIME] = 0;
-
-  /* Turn off characters that we need on Posix systems with job control,
-     just to be sure.  This includes ^Y and ^V.  This should not really
-     be necessary.  */
-#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL)
-
-#if defined (VLNEXT)
-  tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
-#endif
-
-#if defined (VDSUSP)
-  tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
-#endif
-
-#endif /* POSIX && JOB_CONTROL */
-
-#if defined (TERMIOS_TTY_DRIVER)
-  tcsetattr (tty, TCSADRAIN, &tio);
-  tcflow (tty, TCOON);         /* Simulate a ^Q. */
-#else
-  ioctl (tty, TCSETAW, &tio);
-  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
-#endif /* !TERMIOS_TTY_DRIVER */
-
-  terminal_prepped = 1;
-
-  SIGNALS_RESTORE (saved_signals);
-#endif /* !__GO32__ */
-}
-
-static void
-rl_deprep_terminal ()
-{
-#ifndef __GO32__ 
-  int tty = fileno (rl_instream);
-
-  /* Try to keep this function from being INTerrupted.  We can do it
-     on POSIX and systems with BSD-like signal handling. */
-  SIGNALS_DECLARE_SAVED (saved_signals);
-
-  if (!terminal_prepped)
-    return;
-
-  SIGNALS_BLOCK (SIGINT, saved_signals);
-
-#if defined (TERMIOS_TTY_DRIVER)
-  tcsetattr (tty, TCSADRAIN, &otio);
-  tcflow (tty, TCOON);         /* Simulate a ^Q. */
-#else /* TERMIOS_TTY_DRIVER */
-  ioctl (tty, TCSETAW, &otio);
-  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
-#endif /* !TERMIOS_TTY_DRIVER */
-
-  terminal_prepped = 0;
-
-  SIGNALS_RESTORE (saved_signals);
-#endif /* !__GO32__ */
-}
-#endif  /* NEW_TTY_DRIVER */
-
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -2652,7 +1375,7 @@ alphabetic (c)
     return (1);
 
   if (allow_pathname_alphabetic_chars)
-    return ((int)rindex (pathname_alphabetic_chars, c));
+    return ((int) strchr (pathname_alphabetic_chars, c));
   else
     return (0);
 }
@@ -2672,8 +1395,8 @@ ding ()
   if (readline_echoing_p)
     {
 #ifndef __GO32__
-      if (prefer_visible_bell && visible_bell)
-       tputs (visible_bell, 1, output_character_function);
+      if (_rl_prefer_visible_bell && visible_bell)
+       tputs (visible_bell, 1, _rl_output_character_function);
       else
 #endif /* !__GO32__ */
        {
@@ -2702,12 +1425,8 @@ rl_abort ()
 
 /* Return a copy of the string between FROM and TO.
    FROM is inclusive, TO is not. */
-#if defined (sun) /* Yes, that's right, some crufty function in sunview is
-                    called rl_copy (). */
-static
-#endif
 char *
-rl_copy (from, to)
+rl_copy_text (from, to)
      int from, to;
 {
   register int length;
@@ -2755,7 +1474,6 @@ rl_extend_line_buffer (len)
 rl_insert_text (string)
      char *string;
 {
-  extern int doing_an_undo;
   register int i, l = strlen (string);
 
   if (rl_end + l >= rl_line_buffer_len)
@@ -2788,7 +1506,6 @@ rl_insert_text (string)
 rl_delete_text (from, to)
      int from, to;
 {
-  extern int doing_an_undo;
   register char *text;
 
   /* Fix it if the caller is confused. */
@@ -2798,7 +1515,7 @@ rl_delete_text (from, to)
       from = to;
       to = t;
     }
-  text = rl_copy (from, to);
+  text = rl_copy_text (from, to);
   strncpy (the_line + from, the_line + to, rl_end - to);
 
   /* Remember how to undo this delete. */
@@ -2856,7 +1573,7 @@ rl_forward (count)
     while (count)
       {
 #if defined (VI_MODE)
-       if (rl_point == (rl_end - (rl_editing_mode == vi_mode)))
+       if (rl_point >= (rl_end - (rl_editing_mode == vi_mode)))
 #else
        if (rl_point == rl_end)
 #endif /* VI_MODE */
@@ -2984,22 +1701,23 @@ rl_backward_word (count)
 /* Clear the current line.  Numeric argument to C-l does this. */
 rl_refresh_line ()
 {
-  int curr_line = last_c_pos / screenwidth;
-  extern char *term_clreol;
+  int curr_line = _rl_last_c_pos / screenwidth;
 
-  move_vert(curr_line);
-  move_cursor_relative (0, the_line);   /* XXX is this right */
+  _rl_move_vert (curr_line);
+  _rl_move_cursor_relative (0, the_line);   /* XXX is this right */
 
 #ifdef __GO32__
   {
-  int r, c, w;
-  ScreenGetCursor(&r, &c);
-  w = ScreenCols();
-  memset(ScreenPrimary+r*w+c, 0, (w-c)*2);
+    int row, col, width, row_start;
+
+    ScreenGetCursor (&row, &col);
+    width = ScreenCols ();
+    row_start = ScreenPrimary + (row * width);
+    memset (row_start + col, 0, (width - col) * 2);
   }
 #else /* __GO32__ */
   if (term_clreol)
-    tputs (term_clreol, 1, output_character_function);
+    tputs (term_clreol, 1, _rl_output_character_function);
 #endif /* __GO32__/else */
 
   rl_forced_update_display ();
@@ -3011,8 +1729,6 @@ rl_refresh_line ()
    the current line. */
 rl_clear_screen ()
 {
-  extern char *term_clrpag;
-
   if (rl_explicit_arg)
     {
       rl_refresh_line ();
@@ -3021,7 +1737,7 @@ rl_clear_screen ()
 
 #ifndef __GO32__
   if (term_clrpag)
-    tputs (term_clrpag, 1, output_character_function);
+    tputs (term_clrpag, 1, _rl_output_character_function);
   else
 #endif /* !__GO32__ */
     crlf ();
@@ -3081,7 +1797,7 @@ rl_insert (count, c)
      readline because of extra large arguments. */
   if (count > 1 && count < 1024)
     {
-      string = alloca (1 + count);
+      string = (char *)alloca (1 + count);
 
       for (i = 0; i < count; i++)
        string[i] = c;
@@ -3095,7 +1811,7 @@ rl_insert (count, c)
     {
       int decreaser;
 
-      string = alloca (1024 + 1);
+      string = (char *)alloca (1024 + 1);
 
       for (i = 0; i < 1024; i++)
        string[i] = c;
@@ -3119,12 +1835,12 @@ rl_insert (count, c)
       int key = 0, t;
 
       i = 0;
-      string = alloca (ibuffer_len + 1);
+      string = (char *)alloca (ibuffer_len + 1);
       string[i++] = c;
 
       while ((t = rl_get_char (&key)) &&
-            (keymap[key].type == ISFUNC &&
-             keymap[key].function == rl_insert))
+            (_rl_keymap[key].type == ISFUNC &&
+             _rl_keymap[key].function == rl_insert))
        string[i++] = key;
 
       if (t)
@@ -3137,7 +1853,7 @@ rl_insert (count, c)
   else
     {
       /* Inserting a single character. */
-      string = alloca (2);
+      string = (char *)alloca (2);
 
       string[1] = '\0';
       string[0] = c;
@@ -3149,7 +1865,9 @@ rl_insert (count, c)
 rl_quoted_insert (count)
      int count;
 {
-  int c = rl_read_key ();
+  int c;
+
+  c = rl_read_key ();
   rl_insert (count, c);
 }
 
@@ -3171,19 +1889,21 @@ rl_newline (count, key)
 
 #if defined (VI_MODE)
   {
-    extern int vi_doing_insert;
-    if (vi_doing_insert)
+    extern int _rl_vi_doing_insert;
+    if (_rl_vi_doing_insert)
       {
        rl_end_undo_group ();
-       vi_doing_insert = 0;
+       _rl_vi_doing_insert = 0;
       }
   }
+  rl_vi_set_last ();
+
 #endif /* VI_MODE */
 
   if (readline_echoing_p)
     {
-      move_vert (vis_botlin);
-      vis_botlin = 0;
+      _rl_move_vert (_rl_vis_botlin);
+      _rl_vis_botlin = 0;
       crlf ();
       fflush (out_stream);
       rl_display_fixed++;
@@ -3194,8 +1914,8 @@ rl_clean_up_for_exit ()
 {
   if (readline_echoing_p)
     {
-      move_vert (vis_botlin);
-      vis_botlin = 0;
+      _rl_move_vert (_rl_vis_botlin);
+      _rl_vis_botlin = 0;
       fflush (out_stream);
       rl_restart_output ();
     }
@@ -3226,7 +1946,7 @@ rl_rubout (count)
       return;
     }
 
-  if (count > 1)
+  if (count > 1 || rl_explicit_arg)
     {
       int orig_point = rl_point;
       rl_backward (count);
@@ -3237,14 +1957,11 @@ rl_rubout (count)
       int c = the_line[--rl_point];
       rl_delete_text (rl_point, rl_point + 1);
 
-      if (rl_point == rl_end && alphabetic (c) && last_c_pos)
+      if (rl_point == rl_end && isprint (c) && _rl_last_c_pos)
        {
-         backspace (1);
-         putc (' ', out_stream);
-         backspace (1);
-         last_c_pos--;
-         visible_line[last_c_pos] = '\0';
-         rl_display_fixed++;
+         int l;
+         l = rl_character_len (c, rl_point);
+         _rl_erase_at_end_of_line (l);
        }
     }
 }
@@ -3266,7 +1983,7 @@ rl_delete (count, invoking_key)
       return;
     }
 
-  if (count > 1)
+  if (count > 1 || rl_explicit_arg)
     {
       int orig_point = rl_point;
       rl_forward (count);
@@ -3277,6 +1994,28 @@ rl_delete (count, invoking_key)
     rl_delete_text (rl_point, rl_point + 1);
 }
 
+/* Delete all spaces and tabs around point. */
+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)
+    return;
+  else
+    {
+      rl_delete_text (start, rl_point);
+      rl_point = start;
+    }
+}
 \f
 /* **************************************************************** */
 /*                                                                 */
@@ -3292,15 +2031,20 @@ rl_delete (count, invoking_key)
    using behaviour that they expect. */
 rl_unix_word_rubout ()
 {
-  if (!rl_point) ding ();
-  else {
-    int orig_point = rl_point;
-    while (rl_point && whitespace (the_line[rl_point - 1]))
-      rl_point--;
-    while (rl_point && !whitespace (the_line[rl_point - 1]))
-      rl_point--;
-    rl_kill_text (rl_point, orig_point);
-  }
+  if (!rl_point)
+    ding ();
+  else
+    {
+      int orig_point = rl_point;
+
+      while (rl_point && whitespace (the_line[rl_point - 1]))
+       rl_point--;
+
+      while (rl_point && !whitespace (the_line[rl_point - 1]))
+       rl_point--;
+
+      rl_kill_text (rl_point, orig_point);
+    }
 }
 
 /* Here is C-u doing what Unix does.  You don't *have* to use these
@@ -3311,15 +2055,16 @@ rl_unix_word_rubout ()
    doing. */
 rl_unix_line_discard ()
 {
-  if (!rl_point) ding ();
-  else {
-    rl_kill_text (rl_point, 0);
-    rl_point = 0;
-  }
+  if (!rl_point)
+    ding ();
+  else
+    {
+      rl_kill_text (rl_point, 0);
+      rl_point = 0;
+    }
 }
 
 \f
-
 /* **************************************************************** */
 /*                                                                 */
 /*                     Commands For Typos                          */
@@ -3452,8 +2197,8 @@ rl_transpose_words (count)
     }
 
   /* Get the text of the words. */
-  word1 = rl_copy (w1_beg, w1_end);
-  word2 = rl_copy (w2_beg, w2_end);
+  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. */
@@ -3483,729 +2228,60 @@ rl_transpose_words (count)
 rl_transpose_chars (count)
      int count;
 {
+  char dummy[2];
+
   if (!count)
     return;
 
-  if (!rl_point || rl_end < 2) {
-    ding ();
-    return;
-  }
+  if (!rl_point || rl_end < 2)
+    {
+      ding ();
+      return;
+    }
 
-  while (count)
+  rl_begin_undo_group ();
+
+  if (rl_point == rl_end)
     {
-      if (rl_point == rl_end)
-       {
-         int t = the_line[rl_point - 1];
+      --rl_point;
+      count = 1;
+    }
+  rl_point--;
 
-         the_line[rl_point - 1] = the_line[rl_point - 2];
-         the_line[rl_point - 2] = t;
-       }
-      else
-       {
-         int t = the_line[rl_point];
+  dummy[0] = the_line[rl_point];
+  dummy[1] = '\0';
 
-         the_line[rl_point] = the_line[rl_point - 1];
-         the_line[rl_point - 1] = t;
+  rl_delete_text (rl_point, rl_point + 1);
 
-         if (count < 0 && rl_point)
-           rl_point--;
-         else
-           rl_point++;
-       }
+  rl_point += count;
+  if (rl_point > rl_end)
+    rl_point = rl_end;
+  else if (rl_point < 0)
+    rl_point = 0;
+  rl_insert_text (dummy);
 
-      if (count < 0)
-       count++;
-      else
-       count--;
-    }
+  rl_end_undo_group ();
 }
-
 \f
 /* **************************************************************** */
 /*                                                                 */
-/*                     Bogus Flow Control                          */
+/*                     Undo, and Undoing                           */
 /*                                                                 */
 /* **************************************************************** */
 
-rl_restart_output (count, key)
-     int count, key;
-{
-  int fildes = fileno (rl_outstream);
-#if defined (TIOCSTART)
-#if defined (apollo)
-  ioctl (&fildes, TIOCSTART, 0);
-#else
-  ioctl (fildes, TIOCSTART, 0);
-#endif /* apollo */
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+   the undo list. */
+static int doing_an_undo = 0;
 
-#else
-#  if defined (TERMIOS_TTY_DRIVER)
-        tcflow (fildes, TCOON);
-#  else
-#    if defined (TCXONC)
-        ioctl (fildes, TCXONC, TCOON);
-#    endif /* TCXONC */
-#  endif /* !TERMIOS_TTY_DRIVER */
-#endif /* TIOCSTART */
-}
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
 
-rl_stop_output (count, key)
-     int count, key;
-{
-  int fildes = fileno (rl_instream);
-
-#if defined (TIOCSTOP)
-# if defined (apollo)
-  ioctl (&fildes, TIOCSTOP, 0);
-# else
-  ioctl (fildes, TIOCSTOP, 0);
-# endif /* apollo */
-#else
-# if defined (TERMIOS_TTY_DRIVER)
-  tcflow (fildes, TCOOFF);
-# else
-#   if defined (TCXONC)
-  ioctl (fildes, TCXONC, TCOON);
-#   endif /* TCXONC */
-# endif /* !TERMIOS_TTY_DRIVER */
-#endif /* TIOCSTOP */
-}
-
-/* **************************************************************** */
-/*                                                                 */
-/*     Completion matching, from readline's point of view.         */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Pointer to the generator function for completion_matches ().
-   NULL means to use filename_entry_function (), the default filename
-   completer. */
-Function *rl_completion_entry_function = (Function *)NULL;
-
-/* Pointer to alternative function to create matches.
-   Function is called with TEXT, START, and END.
-   START and END are indices in RL_LINE_BUFFER saying what the boundaries
-   of TEXT are.
-   If this function exists and returns NULL then call the value of
-   rl_completion_entry_function to try to match, otherwise use the
-   array of strings returned. */
-Function *rl_attempted_completion_function = (Function *)NULL;
-
-/* Local variable states what happened during the last completion attempt. */
-static int completion_changed_buffer = 0;
-
-/* Complete the word at or before point.  You have supplied the function
-   that does the initial simple matching selection algorithm (see
-   completion_matches ()).  The default is to do filename completion. */
-
-rl_complete (ignore, invoking_key)
-     int ignore, invoking_key;
-{
-  if (rl_last_func == rl_complete && !completion_changed_buffer)
-    rl_complete_internal ('?');
-  else
-    rl_complete_internal (TAB);
-}
-
-/* List the possible completions.  See description of rl_complete (). */
-rl_possible_completions ()
-{
-  rl_complete_internal ('?');
-}
-
-/* The user must press "y" or "n". Non-zero return means "y" pressed. */
-get_y_or_n ()
-{
-  int c;
- loop:
-  c = rl_read_key ();
-  if (c == 'y' || c == 'Y') return (1);
-  if (c == 'n' || c == 'N') return (0);
-  if (c == ABORT_CHAR) rl_abort ();
-  ding (); goto loop;
-}
-
-/* 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. */
-int rl_completion_query_items = 100;
-
-/* 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\"\\'`@$><=" */
-char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
-
-/* The list of characters that signal a break between words for
-   rl_complete_internal.  The default list is the contents of
-   rl_basic_word_break_characters.  */
-char *rl_completer_word_break_characters = (char *)NULL;
-
-/* The list of characters which are used to quote a substring of the command
-   line.  Command completion occurs on the entire substring, and within the
-   substring rl_completer_word_break_characters are treated as any other
-   character, unless they also appear within this list. */
-char *rl_completer_quote_characters = (char *)NULL;
-
-/* List of characters that are word break characters, but should be left
-   in TEXT when it is passed to the completion function.  The shell uses
-   this to help determine what kind of completing to do. */
-char *rl_special_prefixes = (char *)NULL;
-
-/* If non-zero, then disallow duplicates in the matches. */
-int rl_ignore_completion_duplicates = 1;
-
-/* Non-zero means that the results of the matches are to be treated
-   as filenames.  This is ALWAYS zero on entry, and can only be changed
-   within a completion entry finder function. */
-int rl_filename_completion_desired = 0;
-
-/* 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 (char**) known as matches in the code below.
-   It consists of a NULL-terminated array of pointers to potential
-   matching strings.  The 1st element (matches[0]) is the maximal
-   substring that is common to all matches. This function can re-arrange
-   the list of matches as required, but all elements of the array must be
-   free()'d if they are deleted. The main intent of this function is
-   to implement FIGNORE a la SunOS csh. */
-Function *rl_ignore_some_completions_function = (Function *)NULL;
-
-/* Complete the word at or before point.
-   WHAT_TO_DO says what to do with the completion.
-   `?' means list the possible completions.
-   TAB means do standard completion.
-   `*' means insert all of the possible completions. */
-rl_complete_internal (what_to_do)
-     int what_to_do;
-{
-  char *filename_completion_function ();
-  char **completion_matches (), **matches;
-  Function *our_func;
-  int start, scan, end, delimiter = 0;
-  char *text, *saved_line_buffer;
-  char quote_char = '\0';
-  char *replacement;
-
-  if (the_line)
-    saved_line_buffer = savestring (the_line);
-  else
-    saved_line_buffer = (char *)NULL;
-
-  if (rl_completion_entry_function)
-    our_func = rl_completion_entry_function;
-  else
-    our_func = (int (*)())filename_completion_function;
-
-  /* Only the completion entry function can change this. */
-  rl_filename_completion_desired = 0;
-
-  /* We now look backwards for the start of a filename/variable word. */
-  end = rl_point;
-
-  if (rl_point)
-    {
-      if (rl_completer_quote_characters)
-       {
-         /* We have a list of characters which can be used in pairs to quote
-            substrings for completion.  Try to find the start of an unclosed
-            quoted substring.
-            FIXME:  Doesn't yet handle '\' escapes to hid embedded quotes */
-         for (scan = 0; scan < end; scan++)
-           {
-             if (quote_char != '\0')
-               {
-                 /* Ignore everything until the matching close quote char */
-                 if (the_line[scan] == quote_char)
-                   {
-                     /* Found matching close quote. Abandon this substring. */
-                     quote_char = '\0';
-                     rl_point = end;
-                   }
-               }
-             else if (rindex (rl_completer_quote_characters, the_line[scan]))
-               {
-                 /* Found start of a quoted substring. */
-                 quote_char = the_line[scan];
-                 rl_point = scan + 1;
-               }
-           }
-       }
-      if (rl_point == end)
-       {
-         /* 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 do completion. */
-         while (--rl_point &&
-                !rindex (rl_completer_word_break_characters,
-                         the_line[rl_point])) {;}
-       }
-
-      /* If we are at a word break, then advance past it. */
-      if (rindex (rl_completer_word_break_characters, the_line[rl_point]))
-       {
-         /* If the character that caused the word break was a quoting
-            character, then remember it as the delimiter. */
-         if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1)
-           delimiter = the_line[rl_point];
-
-         /* If the character isn't needed to determine something special
-            about what kind of completion to perform, then advance past it. */
-
-         if (!rl_special_prefixes ||
-             !rindex (rl_special_prefixes, the_line[rl_point]))
-           rl_point++;
-       }
-    }
-
-  start = rl_point;
-  rl_point = end;
-  text = rl_copy (start, end);
-
-  /* If the user wants to TRY to complete, but then wants to give
-     up and use the default completion function, they set the
-     variable rl_attempted_completion_function. */
-  if (rl_attempted_completion_function)
-    {
-      matches =
-       (char **)(*rl_attempted_completion_function) (text, start, end);
-
-      if (matches)
-       {
-         our_func = (Function *)NULL;
-         goto after_usual_completion;
-       }
-    }
-
-  matches = completion_matches (text, our_func);
-
- after_usual_completion:
-  free (text);
-
-  if (!matches)
-    ding ();
-  else
-    {
-      register int i;
-
-    some_matches:
-
-      /* It seems to me that in all the cases we handle we would like
-        to ignore duplicate possibilities.  Scan for the text to
-        insert being identical to the other completions. */
-      if (rl_ignore_completion_duplicates)
-       {
-         char *lowest_common;
-         int j, newlen = 0;
-
-         /* Sort the items. */
-         /* It is safe to sort this array, because the lowest common
-            denominator found in matches[0] will remain in place. */
-         for (i = 0; matches[i]; i++);
-         qsort (matches, i, sizeof (char *), compare_strings);
-
-         /* Remember the lowest common denominator for it may be unique. */
-         lowest_common = savestring (matches[0]);
-
-         for (i = 0; matches[i + 1]; i++)
-           {
-             if (strcmp (matches[i], matches[i + 1]) == 0)
-               {
-                 free (matches[i]);
-                 matches[i] = (char *)-1;
-               }
-             else
-               newlen++;
-           }
-
-         /* We have marked all the dead slots with (char *)-1.
-            Copy all the non-dead entries into a new array. */
-         {
-           char **temp_array =
-             (char **)malloc ((3 + newlen) * sizeof (char *));
-
-           for (i = 1, j = 1; matches[i]; i++)
-             {
-               if (matches[i] != (char *)-1)
-                 temp_array[j++] = matches[i];
-             }
-
-           temp_array[j] = (char *)NULL;
-
-           if (matches[0] != (char *)-1)
-             free (matches[0]);
-
-           free (matches);
-
-           matches = temp_array;
-         }
-
-         /* Place the lowest common denominator back in [0]. */
-         matches[0] = lowest_common;
-
-         /* If there is one string left, and it is identical to the
-            lowest common denominator, then the LCD is the string to
-            insert. */
-         if (j == 2 && strcmp (matches[0], matches[1]) == 0)
-           {
-             free (matches[1]);
-             matches[1] = (char *)NULL;
-           }
-       }
-
-      switch (what_to_do)
-       {
-       case TAB:
-         /* If we are matching filenames, then here is our chance to
-            do clever processing by re-examining the list.  Call the
-            ignore function with the array as a parameter.  It can
-            munge the array, deleting matches as it desires. */
-         if (rl_ignore_some_completions_function &&
-             our_func == (int (*)())filename_completion_function)
-           (void)(*rl_ignore_some_completions_function)(matches);
-
-         /* If we are doing completions on quoted substrings, and any matches
-            contain any of the completer word break characters, then auto-
-            matically prepend the substring with a quote character (just
-            pick the first one from the list of such) if it does not already
-            begin with a quote string.  FIXME:  Need to remove any such
-            automatically inserted quote character when it no longer is
-            necessary, such as if we change the string we are completing on
-            and the new set of matches don't require a quoted substring? */
-
-         replacement = matches[0];
-         if (matches[0] != NULL
-             && rl_completer_quote_characters != NULL
-             && (quote_char == '\0'))
-           {
-             for (i = 1; matches[i] != NULL; i++)
-               {
-                 if (strpbrk (matches[i], rl_completer_word_break_characters))
-                   {
-                     /* Found an embedded word break character in a potential
-                        match, so need to prepend a quote character if we are
-                        replacing the completion string. */
-                     replacement = (char *)alloca (strlen (matches[0]) + 2);
-                     quote_char = *rl_completer_quote_characters;
-                     *replacement = quote_char;
-                     strcpy (replacement + 1, matches[0]);
-                     break;
-                   }
-               }
-           }
-         if (replacement)
-           {
-             rl_delete_text (start, rl_point);
-             rl_point = start;
-             rl_insert_text (replacement);
-           }
-
-         /* If there are more matches, ring the bell to indicate.
-            If this was the only match, and we are hacking files,
-            check the file to see if it was a directory.  If so,
-            add a '/' to the name.  If not, and we are at the end
-            of the line, then add a space. */
-         if (matches[1])
-           {
-             ding ();          /* There are other matches remaining. */
-           }
-         else
-           {
-             char temp_string[16];
-             int temp_index = 0;
-
-             if (quote_char)
-               {
-                 temp_string[temp_index++] = quote_char;
-               }
-             temp_string[temp_index++] = delimiter ? delimiter : ' ';
-             temp_string[temp_index++] = '\0';
-
-             if (rl_filename_completion_desired)
-               {
-                 struct stat finfo;
-                 char *filename = tilde_expand (matches[0]);
-
-                 if ((stat (filename, &finfo) == 0) &&
-                     S_ISDIR (finfo.st_mode))
-                   {
-                     if (the_line[rl_point] != '/')
-                       rl_insert_text ("/");
-                   }
-                 else
-                   {
-                     if (rl_point == rl_end)
-                       rl_insert_text (temp_string);
-                   }
-                 free (filename);
-               }
-             else
-               {
-                 if (rl_point == rl_end)
-                   rl_insert_text (temp_string);
-               }
-           }
-         break;
-
-       case '*':
-         {
-           int i = 1;
-
-           rl_delete_text (start, rl_point);
-           rl_point = start;
-           rl_begin_undo_group ();
-           if (matches[1])
-             {
-               while (matches[i])
-                 {
-                   rl_insert_text (matches[i++]);
-                   rl_insert_text (" ");
-                 }
-             }
-           else
-             {
-               rl_insert_text (matches[0]);
-               rl_insert_text (" ");
-             }
-           rl_end_undo_group ();
-         }
-         break;
-
-       case '?':
-         {
-           int len, count, limit, max = 0;
-           int j, k, l;
-
-           /* Handle simple case first.  What if there is only one answer? */
-           if (!matches[1])
-             {
-               char *temp;
-
-               if (rl_filename_completion_desired)
-                 temp = rindex (matches[0], '/');
-               else
-                 temp = (char *)NULL;
-
-               if (!temp)
-                 temp = matches[0];
-               else
-                 temp++;
-
-               crlf ();
-               fprintf (out_stream, "%s", temp);
-               crlf ();
-               goto restart;
-             }
-
-           /* There is more than one answer.  Find out how many there are,
-              and find out what the maximum printed length of a single entry
-              is. */
-           for (i = 1; matches[i]; i++)
-             {
-               char *temp = (char *)NULL;
-
-               /* If we are hacking filenames, then only count the characters
-                  after the last slash in the pathname. */
-               if (rl_filename_completion_desired)
-                 temp = rindex (matches[i], '/');
-               else
-                 temp = (char *)NULL;
-
-               if (!temp)
-                 temp = matches[i];
-               else
-                 temp++;
-
-               if (strlen (temp) > max)
-                 max = strlen (temp);
-             }
-
-           len = i;
-
-           /* If there are many items, then ask the user if she
-              really wants to see them all. */
-           if (len >= rl_completion_query_items)
-             {
-               crlf ();
-               fprintf (out_stream,
-                        "There are %d possibilities.  Do you really", len);
-               crlf ();
-               fprintf (out_stream, "wish to see them all? (y or n)");
-               fflush (out_stream);
-               if (!get_y_or_n ())
-                 {
-                   crlf ();
-                   goto restart;
-                 }
-             }
-           /* How many items of MAX length can we fit in the screen window? */
-           max += 2;
-           limit = screenwidth / max;
-           if (limit != 1 && (limit * max == screenwidth))
-             limit--;
-
-           /* Avoid a possible floating exception.  If max > screenwidth,
-              limit will be 0 and a divide-by-zero fault will result. */
-           if (limit == 0)
-             limit = 1;
-
-           /* How many iterations of the printing loop? */
-           count = (len + (limit - 1)) / limit;
-
-           /* Watch out for special case.  If LEN is less than LIMIT, then
-              just do the inner printing loop. */
-           if (len < limit) count = 1;
-
-           /* Sort the items if they are not already sorted. */
-           if (!rl_ignore_completion_duplicates)
-             qsort (matches, len, sizeof (char *), compare_strings);
-
-           /* Print the sorted items, up-and-down alphabetically, like
-              ls might. */
-           crlf ();
-
-           for (i = 1; i < count + 1; i++)
-             {
-               for (j = 0, l = i; j < limit; j++)
-                 {
-                   if (l > len || !matches[l])
-                     {
-                       break;
-                     }
-                   else
-                     {
-                       char *temp = (char *)NULL;
-
-                       if (rl_filename_completion_desired)
-                         temp = rindex (matches[l], '/');
-                       else
-                         temp = (char *)NULL;
-
-                       if (!temp)
-                         temp = matches[l];
-                       else
-                         temp++;
-
-                       fprintf (out_stream, "%s", temp);
-                       for (k = 0; k < max - strlen (temp); k++)
-                         putc (' ', out_stream);
-                     }
-                   l += count;
-                 }
-               crlf ();
-             }
-         restart:
-
-           rl_on_new_line ();
-         }
-         break;
-
-       default:
-         abort ();
-       }
-
-      for (i = 0; matches[i]; i++)
-       free (matches[i]);
-      free (matches);
-    }
-
-  /* Check to see if the line has changed through all of this manipulation. */
-  if (saved_line_buffer)
-    {
-      if (strcmp (the_line, saved_line_buffer) != 0)
-       completion_changed_buffer = 1;
-      else
-       completion_changed_buffer = 0;
-
-      free (saved_line_buffer);
-    }
-}
-
-/* Stupid comparison routine for qsort () ing strings. */
-static int
-compare_strings (s1, s2)
-  char **s1, **s2;
-{
-  return (strcmp (*s1, *s2));
-}
-
-/* A completion function for usernames.
-   TEXT contains a partial username preceded by a random
-   character (usually `~').  */
-char *
-username_completion_function (text, state)
-     int state;
-     char *text;
-{
-#ifdef __GO32__
-  return (char *)NULL;
-#else /* !__GO32__ */
-  static char *username = (char *)NULL;
-  static struct passwd *entry;
-  static int namelen, first_char, first_char_loc;
-
-  if (!state)
-    {
-      if (username)
-       free (username);
-
-      first_char = *text;
-
-      if (first_char == '~')
-       first_char_loc = 1;
-      else
-       first_char_loc = 0;
-
-      username = savestring (&text[first_char_loc]);
-      namelen = strlen (username);
-      setpwent ();
-    }
-
-  while (entry = getpwent ())
-    {
-      if (strncmp (username, entry->pw_name, namelen) == 0)
-       break;
-    }
-
-  if (!entry)
-    {
-      endpwent ();
-      return ((char *)NULL);
-    }
-  else
-    {
-      char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
-
-      *value = *text;
-
-      strcpy (value + first_char_loc, entry->pw_name);
-
-      if (first_char == '~')
-       rl_filename_completion_desired = 1;
-
-      return (value);
-    }
-#endif /* !__GO32__ */
-}
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     Undo, and Undoing                           */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Non-zero tells rl_delete_text and rl_insert_text to not add to
-   the undo list. */
-int doing_an_undo = 0;
-
-/* The current undo list for THE_LINE. */
-UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
-
-/* Remember how to undo something.  Concatenate some undos if that
-   seems right. */
-rl_add_undo (what, start, end, text)
-     enum undo_code what;
-     int start, end;
-     char *text;
+/* Remember how to undo something.  Concatenate some undos if that
+   seems right. */
+rl_add_undo (what, start, end, text)
+     enum undo_code what;
+     int start, end;
+     char *text;
 {
   UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
   temp->what = what;
@@ -4219,15 +2295,17 @@ rl_add_undo (what, start, end, text)
 /* Free the existing undo list. */
 free_undo_list ()
 {
-  while (rl_undo_list) {
-    UNDO_LIST *release = rl_undo_list;
-    rl_undo_list = rl_undo_list->next;
+  while (rl_undo_list)
+    {
+      UNDO_LIST *release = rl_undo_list;
+      rl_undo_list = rl_undo_list->next;
 
-    if (release->what == UNDO_DELETE)
-      free (release->text);
+      if (release->what == UNDO_DELETE)
+       free (release->text);
 
-    free (release);
-  }
+      free (release);
+    }
+  rl_undo_list = (UNDO_LIST *)NULL;
 }
 
 /* Undo the next thing in the list.  Return 0 if there
@@ -4270,7 +2348,11 @@ undo_thing:
     if (waiting_for_begin)
       waiting_for_begin--;
     else
+#if 0
       abort ();
+#else
+      ding ();
+#endif
     break;
   }
 
@@ -4311,7 +2393,7 @@ rl_modifying (start, end)
 
   if (start != end)
     {
-      char *temp = rl_copy (start, end);
+      char *temp = rl_copy_text (start, end);
       rl_begin_undo_group ();
       rl_add_undo (UNDO_DELETE, start, end, temp);
       rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
@@ -4322,11 +2404,13 @@ rl_modifying (start, end)
 /* Revert the current line to its previous state. */
 rl_revert_line ()
 {
-  if (!rl_undo_list) ding ();
-  else {
-    while (rl_undo_list)
-      rl_do_undo ();
-  }
+  if (!rl_undo_list)
+    ding ();
+  else
+    {
+      while (rl_undo_list)
+       rl_do_undo ();
+    }
 }
 
 /* Do some undoing of things that were done. */
@@ -4373,6 +2457,7 @@ start_using_history ()
 }
 
 /* Free the contents (and containing structure) of a HIST_ENTRY. */
+void
 free_history_entry (entry)
      HIST_ENTRY *entry;
 {
@@ -4555,351 +2640,67 @@ rl_get_previous_history (count)
     }
 }
 
-\f
+/* Make C be the next command to be executed. */
+rl_execute_next (c)
+     int c;
+{
+  rl_pending_input = c;
+}
+
 /* **************************************************************** */
 /*                                                                 */
-/*                     I-Search and Searching                      */
+/*                The Mark and the Region.                         */
 /*                                                                 */
 /* **************************************************************** */
 
-/* Search backwards through the history looking for a string which is typed
-   interactively.  Start with the current line. */
-rl_reverse_search_history (sign, key)
-     int sign;
-     int key;
+/* Set the mark at POSITION. */
+rl_set_mark (position)
+     int position;
 {
-  rl_search_history (-sign, key);
-}
+  if (position > rl_end)
+    return;
 
-/* Search forwards through the history looking for a string which is typed
-   interactively.  Start with the current line. */
-rl_forward_search_history (sign, key)
-     int sign;
-     int key;
-{
-  rl_search_history (sign, key);
+  rl_mark = position;
 }
 
-/* Display the current state of the search in the echo-area.
-   SEARCH_STRING contains the string that is being searched for,
-   DIRECTION is zero for forward, or 1 for reverse,
-   WHERE is the history list number of the current line.  If it is
-   -1, then this line is the starting one. */
-rl_display_search (search_string, reverse_p, where)
-     char *search_string;
-     int reverse_p, where;
+/* Exchange the position of mark and point. */
+rl_exchange_mark_and_point ()
 {
-  char *message = (char *)NULL;
-
-  message = alloca (1 + (search_string ? strlen (search_string) : 0) + 30);
-
-  *message = '\0';
-
-#if defined (NOTDEF)
-  if (where != -1)
-    sprintf (message, "[%d]", where + history_base);
-#endif /* NOTDEF */
+  if (rl_mark > rl_end)
+    rl_mark = -1;
 
-  strcat (message, "(");
-
-  if (reverse_p)
-    strcat (message, "reverse-");
-
-  strcat (message, "i-search)`");
-
-  if (search_string)
-    strcat (message, search_string);
+  if (rl_mark == -1)
+    {
+      ding ();
+      return;
+    }
+  else
+    {
+      int temp = rl_point;
 
-  strcat (message, "': ");
-  rl_message (message, 0, 0);
-  rl_redisplay ();
+      rl_point = rl_mark;
+      rl_mark = temp;
+    }
 }
 
-/* Search through the history looking for an interactively typed string.
-   This is analogous to i-search.  We start the search in the current line.
-   DIRECTION is which direction to search; >= 0 means forward, < 0 means
-   backwards. */
-rl_search_history (direction, invoking_key)
-     int direction;
-     int invoking_key;
-{
-  /* The string that the user types in to search for. */
-  char *search_string = alloca (128);
-
-  /* The current length of SEARCH_STRING. */
-  int search_string_index;
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Killing Mechanism                           */
+/*                                                                 */
+/* **************************************************************** */
 
-  /* The list of lines to search through. */
-  char **lines;
+/* What we assume for a max number of kills. */
+#define DEFAULT_MAX_KILLS 10
 
-  /* The length of LINES. */
-  int hlen;
+/* The real variable to look at to find out when to flush kills. */
+int rl_max_kills = DEFAULT_MAX_KILLS;
 
-  /* Where we get LINES from. */
-  HIST_ENTRY **hlist = history_list ();
+/* Where to store killed text. */
+char **rl_kill_ring = (char **)NULL;
 
-  register int i = 0;
-  int orig_point = rl_point;
-  int orig_line = where_history ();
-  int last_found_line = orig_line;
-  int c, done = 0;
-
-  /* The line currently being searched. */
-  char *sline;
-
-  /* Offset in that line. */
-  int index;
-
-  /* Non-zero if we are doing a reverse search. */
-  int reverse = (direction < 0);
-
-  /* Create an arrary of pointers to the lines that we want to search. */
-  maybe_replace_line ();
-  if (hlist)
-    for (i = 0; hlist[i]; i++);
-
-  /* Allocate space for this many lines, +1 for the current input line,
-     and remember those lines. */
-  lines = alloca ((1 + (hlen = i)) * sizeof (char *));
-  for (i = 0; i < hlen; i++)
-    lines[i] = hlist[i]->line;
-
-  if (saved_line_for_history)
-    lines[i] = saved_line_for_history->line;
-  else
-    /* So I have to type it in this way instead. */
-    {
-      char *alloced_line;
-
-      /* Keep that mips alloca happy. */
-      alloced_line = alloca (1 + strlen (the_line));
-      lines[i] = alloced_line;
-      strcpy (lines[i], &the_line[0]);
-    }
-
-  hlen++;
-
-  /* The line where we start the search. */
-  i = orig_line;
-
-  /* Initialize search parameters. */
-  *search_string = '\0';
-  search_string_index = 0;
-
-  /* Normalize DIRECTION into 1 or -1. */
-  if (direction >= 0)
-    direction = 1;
-  else
-    direction = -1;
-
-  rl_display_search (search_string, reverse, -1);
-
-  sline = the_line;
-  index = rl_point;
-
-  while (!done)
-    {
-      c = rl_read_key ();
-
-      /* Hack C to Do What I Mean. */
-      {
-       Function *f = (Function *)NULL;
-
-       if (keymap[c].type == ISFUNC)
-         {
-           f = keymap[c].function;
-
-           if (f == rl_reverse_search_history)
-             c = reverse ? -1 : -2;
-           else if (f == rl_forward_search_history)
-             c =  !reverse ? -1 : -2;
-         }
-      }
-
-      switch (c)
-       {
-       case ESC:
-         done = 1;
-         continue;
-
-         /* case invoking_key: */
-       case -1:
-         goto search_again;
-
-         /* switch directions */
-       case -2:
-         direction = -direction;
-         reverse = (direction < 0);
-
-         goto do_search;
-
-       case CTRL ('G'):
-         strcpy (the_line, lines[orig_line]);
-         rl_point = orig_point;
-         rl_end = strlen (the_line);
-         rl_clear_message ();
-         return;
-
-       default:
-         if (c < 32 || c > 126)
-           {
-             rl_execute_next (c);
-             done = 1;
-             continue;
-           }
-         else
-           {
-             search_string[search_string_index++] = c;
-             search_string[search_string_index] = '\0';
-             goto do_search;
-
-           search_again:
-
-             if (!search_string_index)
-               continue;
-             else
-               {
-                 if (reverse)
-                   --index;
-                 else
-                   if (index != strlen (sline))
-                     ++index;
-                   else
-                     ding ();
-               }
-           do_search:
-
-             while (1)
-               {
-                 if (reverse)
-                   {
-                     while (index >= 0)
-                       if (strncmp
-                           (search_string, sline + index, search_string_index)
-                           == 0)
-                         goto string_found;
-                       else
-                         index--;
-                   }
-                 else
-                   {
-                     register int limit =
-                       (strlen (sline) - search_string_index) + 1;
-
-                     while (index < limit)
-                       {
-                         if (strncmp (search_string,
-                                      sline + index,
-                                      search_string_index) == 0)
-                           goto string_found;
-                         index++;
-                       }
-                   }
-
-               next_line:
-                 i += direction;
-
-                 /* At limit for direction? */
-                 if ((reverse && i < 0) ||
-                     (!reverse && i == hlen))
-                   goto search_failed;
-
-                 sline = lines[i];
-                 if (reverse)
-                   index = strlen (sline);
-                 else
-                   index = 0;
-
-                 /* If the search string is longer than the current
-                    line, no match. */
-                 if (search_string_index > strlen (sline))
-                   goto next_line;
-
-                 /* Start actually searching. */
-                 if (reverse)
-                   index -= search_string_index;
-               }
-
-           search_failed:
-             /* We cannot find the search string.  Ding the bell. */
-             ding ();
-             i = last_found_line;
-             break;
-
-           string_found:
-             /* We have found the search string.  Just display it.  But don't
-                actually move there in the history list until the user accepts
-                the location. */
-             {
-               int line_len;
-
-               line_len = strlen (lines[i]);
-
-               if (line_len >= rl_line_buffer_len)
-                 rl_extend_line_buffer (line_len);
-
-               strcpy (the_line, lines[i]);
-               rl_point = index;
-               rl_end = line_len;
-               last_found_line = i;
-               rl_display_search
-                 (search_string, reverse, (i == orig_line) ? -1 : i);
-             }
-           }
-       }
-      continue;
-    }
-
-  /* The searching is over.  The user may have found the string that she
-     was looking for, or else she may have exited a failing search.  If
-     INDEX is -1, then that shows that the string searched for was not
-     found.  We use this to determine where to place rl_point. */
-  {
-    int now = last_found_line;
-
-    /* First put back the original state. */
-    strcpy (the_line, lines[orig_line]);
-
-    if (now < orig_line)
-      rl_get_previous_history (orig_line - now);
-    else
-      rl_get_next_history (now - orig_line);
-
-    /* If the index of the "matched" string is less than zero, then the
-       final search string was never matched, so put point somewhere
-       reasonable. */
-    if (index < 0)
-      index = strlen (the_line);
-
-    rl_point = index;
-    rl_clear_message ();
-  }
-}
-
-/* Make C be the next command to be executed. */
-rl_execute_next (c)
-     int c;
-{
-  rl_pending_input = c;
-}
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     Killing Mechanism                           */
-/*                                                                 */
-/* **************************************************************** */
-
-/* What we assume for a max number of kills. */
-#define DEFAULT_MAX_KILLS 10
-
-/* The real variable to look at to find out when to flush kills. */
-int rl_max_kills = DEFAULT_MAX_KILLS;
-
-/* Where to store killed text. */
-char **rl_kill_ring = (char **)NULL;
-
-/* Where we are in the kill ring. */
-int rl_kill_index = 0;
+/* Where we are in the kill ring. */
+int rl_kill_index = 0;
 
 /* How many slots we have in the kill ring. */
 int rl_kill_ring_length = 0;
@@ -4919,7 +2720,7 @@ rl_kill_text (from, to)
      int from, to;
 {
   int slot;
-  char *text = rl_copy (from, to);
+  char *text = rl_copy_text (from, to);
 
   /* Is there anything to kill? */
   if (from == to)
@@ -5087,7 +2888,10 @@ rl_backward_kill_line (direction)
 /* Yank back the last killed text.  This ignores arguments. */
 rl_yank ()
 {
-  if (!rl_kill_ring) rl_abort ();
+  if (!rl_kill_ring)
+    rl_abort ();
+
+  rl_set_mark (rl_point);
   rl_insert_text (rl_kill_ring[rl_kill_index]);
 }
 
@@ -5147,7 +2951,7 @@ rl_yank_nth_arg (count, ignore)
   rl_begin_undo_group ();
 
 #if defined (VI_MODE)
-  /* Vi mode always inserts a space befoe yanking the argument, and it
+  /* Vi mode always inserts a space before yanking the argument, and it
      inserts it right *after* rl_point. */
   if (rl_editing_mode == vi_mode)
     rl_point++;
@@ -5174,1361 +2978,72 @@ rl_vi_editing_mode ()
 rl_emacs_editing_mode ()
 {
   rl_editing_mode = emacs_mode;
-  keymap = emacs_standard_keymap;
+  _rl_keymap = emacs_standard_keymap;
 }
 
 \f
 /* **************************************************************** */
 /*                                                                 */
-/*                          Completion                             */
+/*                     USG (System V) Support                      */
 /*                                                                 */
 /* **************************************************************** */
 
-/* Non-zero means that case is not significant in completion. */
-int completion_case_fold = 0;
-
-/* Return an array of (char *) which is a list of completions for TEXT.
-   If there are no completions, return a NULL pointer.
-   The first entry in the returned array is the substitution for TEXT.
-   The remaining entries are the possible completions.
-   The array is terminated with a NULL pointer.
-
-   ENTRY_FUNCTION is a function of two args, and returns a (char *).
-     The first argument is TEXT.
-     The second is a state argument; it should be zero on the first call, and
-     non-zero on subsequent calls.  It returns a NULL pointer to the caller
-     when there are no more matches.
- */
-char **
-completion_matches (text, entry_function)
-     char *text;
-     char *(*entry_function) ();
+int
+rl_getc (stream)
+     FILE *stream;
 {
-  /* Number of slots in match_list. */
-  int match_list_size;
-
-  /* The list of matches. */
-  char **match_list =
-    (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
-
-  /* Number of matches actually found. */
-  int matches = 0;
-
-  /* Temporary string binder. */
-  char *string;
+  int result;
+  unsigned char c;
 
-  match_list[1] = (char *)NULL;
+#ifdef __GO32__
+  if (isatty (0))
+    return (getkey () & 0x7f);
+#endif /* __GO32__ */
 
-  while (string = (*entry_function) (text, matches))
+  while (1)
     {
-      if (matches + 1 == match_list_size)
-       match_list = (char **)xrealloc
-         (match_list, ((match_list_size += 10) + 1) * sizeof (char *));
+      result = read (fileno (stream), &c, sizeof (unsigned char));
 
-      match_list[++matches] = string;
-      match_list[matches + 1] = (char *)NULL;
-    }
+      if (result == sizeof (unsigned char))
+       return (c);
 
-  /* If there were any matches, then look through them finding out the
-     lowest common denominator.  That then becomes match_list[0]. */
-  if (matches)
-    {
-      register int i = 1;
-      int low = 100000;                /* Count of max-matched characters. */
+      /* If zero characters are returned, then the file that we are
+        reading from is empty!  Return EOF in that case. */
+      if (result == 0)
+       return (EOF);
 
-      /* If only one match, just use that. */
-      if (matches == 1)
-       {
-         match_list[0] = match_list[1];
-         match_list[1] = (char *)NULL;
-       }
-      else
+#if defined (EWOULDBLOCK)
+      if (errno == EWOULDBLOCK)
        {
-         /* Otherwise, compare each member of the list with
-            the next, finding out where they stop matching. */
+         int flags;
 
-         while (i < matches)
+         if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+           return (EOF);
+         if (flags & O_NDELAY)
            {
-             register int c1, c2, si;
-
-             if (completion_case_fold)
-               {
-                 for (si = 0;
-                      (c1 = to_lower(match_list[i][si])) &&
-                      (c2 = to_lower(match_list[i + 1][si]));
-                      si++)
-                   if (c1 != c2) break;
-               }
-             else
-               {
-                 for (si = 0;
-                      (c1 = match_list[i][si]) &&
-                      (c2 = match_list[i + 1][si]);
-                      si++)
-                   if (c1 != c2) break;
-               }
-
-             if (low > si) low = si;
-             i++;
+             flags &= ~O_NDELAY;
+             fcntl (fileno (stream), F_SETFL, flags);
+             continue;
            }
-         match_list[0] = (char *)xmalloc (low + 1);
-         strncpy (match_list[0], match_list[1], low);
-         match_list[0][low] = '\0';
-       }
-    }
-  else                         /* There were no matches. */
-    {
-      free (match_list);
-      match_list = (char **)NULL;
-    }
-  return (match_list);
-}
-
-/* Okay, now we write the entry_function for filename completion.  In the
-   general case.  Note that completion in the shell is a little different
-   because of all the pathnames that must be followed when looking up the
-   completion for a command. */
-char *
-filename_completion_function (text, state)
-     int state;
-     char *text;
-{
-  static DIR *directory;
-  static char *filename = (char *)NULL;
-  static char *dirname = (char *)NULL;
-  static char *users_dirname = (char *)NULL;
-  static int filename_len;
-
-  dirent *entry = (dirent *)NULL;
-
-  /* If we don't have any state, then do some initialization. */
-  if (!state)
-    {
-      char *temp;
-
-      if (dirname) free (dirname);
-      if (filename) free (filename);
-      if (users_dirname) free (users_dirname);
-
-      filename = savestring (text);
-      if (!*text) text = ".";
-      dirname = savestring (text);
-
-      temp = rindex (dirname, '/');
-
-      if (temp)
-       {
-         strcpy (filename, ++temp);
-         *temp = '\0';
-       }
-      else
-       strcpy (dirname, ".");
-
-      /* We aren't done yet.  We also support the "~user" syntax. */
-
-      /* Save the version of the directory that the user typed. */
-      users_dirname = savestring (dirname);
-      {
-       char *temp_dirname;
-
-       temp_dirname = tilde_expand (dirname);
-       free (dirname);
-       dirname = temp_dirname;
-
-       if (rl_symbolic_link_hook)
-         (*rl_symbolic_link_hook) (&dirname);
-      }
-      directory = opendir (dirname);
-      filename_len = strlen (filename);
-
-      rl_filename_completion_desired = 1;
-    }
-
-  /* At this point we should entertain the possibility of hacking wildcarded
-     filenames, like /usr/man/man<WILD>/te<TAB>.  If the directory name
-     contains globbing characters, then build an array of directories to
-     glob on, and glob on the first one. */
-
-  /* Now that we have some state, we can read the directory. */
-
-  while (directory && (entry = readdir (directory)))
-    {
-      /* Special case for no filename.
-        All entries except "." and ".." match. */
-      if (!filename_len)
-       {
-         if ((strcmp (entry->d_name, ".") != 0) &&
-             (strcmp (entry->d_name, "..") != 0))
-           break;
-       }
-      else
-       {
-         /* Otherwise, if these match upto the length of filename, then
-            it is a match. */
-           if (entry->d_name[0] == filename[0] && /* Quick test */
-               (strncmp (filename, entry->d_name, filename_len) == 0))
-             {
-               break;
-             }
-       }
-    }
-
-  if (!entry)
-    {
-      if (directory)
-       {
-         closedir (directory);
-         directory = (DIR *)NULL;
-       }
-      return (char *)NULL;
-    }
-  else
-    {
-      char *temp;
-
-      if (dirname && (strcmp (dirname, ".") != 0))
-       {
-         temp = (char *)
-           xmalloc (1 + strlen (users_dirname) + strlen (entry->d_name));
-         strcpy (temp, users_dirname);
-         strcat (temp, entry->d_name);
-       }
-      else
-       {
-         temp = (savestring (entry->d_name));
+         continue;
        }
-      return (temp);
-    }
-}
-
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     Binding keys                                */
-/*                                                                 */
-/* **************************************************************** */
-
-/* rl_add_defun (char *name, Function *function, int key)
-   Add NAME to the list of named functions.  Make FUNCTION
-   be the function that gets called.
-   If KEY is not -1, then bind it. */
-rl_add_defun (name, function, key)
-     char *name;
-     Function *function;
-     int key;
-{
-  if (key != -1)
-    rl_bind_key (key, function);
-  rl_add_funmap_entry (name, function);
-}
-
-/* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
-int
-rl_bind_key (key, function)
-     int key;
-     Function *function;
-{
-  if (key < 0)
-    return (key);
+#endif /* EWOULDBLOCK */
 
-  if (key > 127 && key < 256)
-    {
-      if (keymap[ESC].type == ISKMAP)
+#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK)
+      if (errno == EAGAIN)
        {
-         Keymap escmap = (Keymap)keymap[ESC].function;
-
-         key -= 128;
-         escmap[key].type = ISFUNC;
-         escmap[key].function = function;
-         return (0);
-       }
-      return (key);
-    }
-
-  keymap[key].type = ISFUNC;
-  keymap[key].function = function;
- return (0);
-}
-
-/* Bind KEY to FUNCTION in MAP.  Returns non-zero in case of invalid
-   KEY. */
-int
-rl_bind_key_in_map (key, function, map)
-     int key;
-     Function *function;
-     Keymap map;
-{
-  int result;
-  Keymap oldmap = keymap;
-
-  keymap = map;
-  result = rl_bind_key (key, function);
-  keymap = oldmap;
-  return (result);
-}
-
-/* Make KEY do nothing in the currently selected keymap.
-   Returns non-zero in case of error. */
-int
-rl_unbind_key (key)
-     int key;
-{
-  return (rl_bind_key (key, (Function *)NULL));
-}
-
-/* Make KEY do nothing in MAP.
-   Returns non-zero in case of error. */
-int
-rl_unbind_key_in_map (key, map)
-     int key;
-     Keymap map;
-{
-  return (rl_bind_key_in_map (key, (Function *)NULL, map));
-}
-
-/* Bind the key sequence represented by the string KEYSEQ to
-   FUNCTION.  This makes new keymaps as necessary.  The initial
-   place to do bindings is in MAP. */
-rl_set_key (keyseq, function, map)
-     char *keyseq;
-     Function *function;
-     Keymap map;
-{
-  rl_generic_bind (ISFUNC, keyseq, function, map);
-}
-
-/* Bind the key sequence represented by the string KEYSEQ to
-   the string of characters MACRO.  This makes new keymaps as
-   necessary.  The initial place to do bindings is in MAP. */
-rl_macro_bind (keyseq, macro, map)
-     char *keyseq, *macro;
-     Keymap map;
-{
-  char *macro_keys;
-  int macro_keys_len;
-
-  macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1);
-
-  if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
-    {
-      free (macro_keys);
-      return;
-    }
-  rl_generic_bind (ISMACR, keyseq, macro_keys, map);
-}
+         int flags;
 
-/* Bind the key sequence represented by the string KEYSEQ to
-   the arbitrary pointer DATA.  TYPE says what kind of data is
-   pointed to by DATA, right now this can be a function (ISFUNC),
-   a macro (ISMACR), or a keymap (ISKMAP).  This makes new keymaps
-   as necessary.  The initial place to do bindings is in MAP. */
-
-static void
-rl_generic_bind (type, keyseq, data, map)
-     int type;
-     char *keyseq, *data;
-     Keymap map;
-{
-  char *keys;
-  int keys_len;
-  register int i;
-
-  /* If no keys to bind to, exit right away. */
-  if (!keyseq || !*keyseq)
-    {
-      if (type == ISMACR)
-       free (data);
-      return;
-    }
-
-  keys = alloca (1 + (2 * strlen (keyseq)));
-
-  /* Translate the ASCII representation of KEYSEQ into an array
-     of characters.  Stuff the characters into ARRAY, and the
-     length of ARRAY into LENGTH. */
-  if (rl_translate_keyseq (keyseq, keys, &keys_len))
-    return;
-
-  /* Bind keys, making new keymaps as necessary. */
-  for (i = 0; i < keys_len; i++)
-    {
-      if (i + 1 < keys_len)
-       {
-         if (map[keys[i]].type != ISKMAP)
+         if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+           return (EOF);
+         if (flags & O_NONBLOCK)
            {
-             if (map[i].type == ISMACR)
-               free ((char *)map[i].function);
-
-             map[keys[i]].type = ISKMAP;
-             map[keys[i]].function = (Function *)rl_make_bare_keymap ();
-           }
-         map = (Keymap)map[keys[i]].function;
-       }
-      else
-       {
-         if (map[keys[i]].type == ISMACR)
-           free ((char *)map[keys[i]].function);
-
-         map[keys[i]].function = (Function *)data;
-         map[keys[i]].type = type;
-       }
-    }
-}
-
-/* Translate the ASCII representation of SEQ, stuffing the
-   values into ARRAY, an array of characters.  LEN gets the
-   final length of ARRAY.  Return non-zero if there was an
-   error parsing SEQ. */
-rl_translate_keyseq (seq, array, len)
-     char *seq, *array;
-     int *len;
-{
-  register int i, c, l = 0;
-
-  for (i = 0; c = seq[i]; i++)
-    {
-      if (c == '\\')
-       {
-         c = seq[++i];
-
-         if (!c)
-           break;
-
-         if (((c == 'C' || c == 'M') &&  seq[i + 1] == '-') ||
-             (c == 'e'))
-           {
-             /* Handle special case of backwards define. */
-             if (strncmp (&seq[i], "C-\\M-", 5) == 0)
-               {
-                 array[l++] = ESC;
-                 i += 5;
-                 array[l++] = CTRL (to_upper (seq[i]));
-                 if (!seq[i])
-                   i--;
-                 continue;
-               }
-
-             switch (c)
-               {
-               case 'M':
-                 i++;
-                 array[l++] = ESC;
-                 break;
-
-               case 'C':
-                 i += 2;
-                 /* Special hack for C-?... */
-                 if (seq[i] == '?')
-                   array[l++] = RUBOUT;
-                 else
-                   array[l++] = CTRL (to_upper (seq[i]));
-                 break;
-
-               case 'e':
-                 array[l++] = ESC;
-               }
-
+             flags &= ~O_NONBLOCK;
+             fcntl (fileno (stream), F_SETFL, flags);
              continue;
            }
        }
-      array[l++] = c;
-    }
-
-  *len = l;
-  array[l] = '\0';
-  return (0);
-}
-
-/* Return a pointer to the function that STRING represents.
-   If STRING doesn't have a matching function, then a NULL pointer
-   is returned. */
-Function *
-rl_named_function (string)
-     char *string;
-{
-  register int i;
-
-  for (i = 0; funmap[i]; i++)
-    if (stricmp (funmap[i]->name, string) == 0)
-      return (funmap[i]->function);
-  return ((Function *)NULL);
-}
-
-/* The last key bindings file read. */
-#ifdef __MSDOS__
-/* Don't know what to do, but this is a guess */
-static char *last_readline_init_file = "/INPUTRC";
-#else
-static char *last_readline_init_file = "~/.inputrc";
-#endif
-
-/* Re-read the current keybindings file. */
-rl_re_read_init_file (count, ignore)
-     int count, ignore;
-{
-  rl_read_init_file ((char *)NULL);
-}
-
-/* Do key bindings from a file.  If FILENAME is NULL it defaults
-   to `~/.inputrc'.  If the file existed and could be opened and
-   read, 0 is returned, otherwise errno is returned. */
-int
-rl_read_init_file (filename)
-     char *filename;
-{
-  register int i;
-  char *buffer, *openname, *line, *end;
-  struct stat finfo;
-  int file;
-
-  /* Default the filename. */
-  if (!filename)
-    filename = last_readline_init_file;
-
-  openname = tilde_expand (filename);
-
-  if (!openname || *openname == '\000')
-    return ENOENT;
-
-  if ((stat (openname, &finfo) < 0) ||
-      (file = open (openname, O_RDONLY, 0666)) < 0)
-    {
-      free (openname);
-      return (errno);
-    }
-  else
-    free (openname);
-
-  last_readline_init_file = filename;
-
-  /* Read the file into BUFFER. */
-  buffer = (char *)xmalloc (finfo.st_size + 1);
-  i = read (file, buffer, finfo.st_size);
-  close (file);
-
-  if (i != finfo.st_size)
-    return (errno);
-
-  /* Loop over the lines in the file.  Lines that start with `#' are
-     comments; all other lines are commands for readline initialization. */
-  line = buffer;
-  end = buffer + finfo.st_size;
-  while (line < end)
-    {
-      /* Find the end of this line. */
-      for (i = 0; line + i != end && line[i] != '\n'; i++);
-
-      /* Mark end of line. */
-      line[i] = '\0';
-
-      /* If the line is not a comment, then parse it. */
-      if (*line != '#')
-       rl_parse_and_bind (line);
-
-      /* Move to the next line. */
-      line += i + 1;
-    }
-  return (0);
-}
-
-/* **************************************************************** */
-/*                                                                 */
-/*                     Parser Directives                           */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Conditionals. */
-
-/* Calling programs set this to have their argv[0]. */
-char *rl_readline_name = "other";
-
-/* Stack of previous values of parsing_conditionalized_out. */
-static unsigned char *if_stack = (unsigned char *)NULL;
-static int if_stack_depth = 0;
-static int if_stack_size = 0;
-
-/* Push parsing_conditionalized_out, and set parser state based on ARGS. */
-parser_if (args)
-     char *args;
-{
-  register int i;
-
-  /* Push parser state. */
-  if (if_stack_depth + 1 >= if_stack_size)
-    {
-      if (!if_stack)
-       if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
-      else
-       if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
-    }
-  if_stack[if_stack_depth++] = parsing_conditionalized_out;
-
-  /* If parsing is turned off, then nothing can turn it back on except
-     for finding the matching endif.  In that case, return right now. */
-  if (parsing_conditionalized_out)
-    return;
-
-  /* Isolate first argument. */
-  for (i = 0; args[i] && !whitespace (args[i]); i++);
-
-  if (args[i])
-    args[i++] = '\0';
-
-  /* Handle "if term=foo" and "if mode=emacs" constructs.  If this
-     isn't term=foo, or mode=emacs, then check to see if the first
-     word in ARGS is the same as the value stored in rl_readline_name. */
-  if (rl_terminal_name && strnicmp (args, "term=", 5) == 0)
-    {
-      char *tem, *tname;
-
-      /* Terminals like "aaa-60" are equivalent to "aaa". */
-      tname = savestring (rl_terminal_name);
-      tem = rindex (tname, '-');
-      if (tem)
-       *tem = '\0';
-
-      if (stricmp (args + 5, tname) == 0)
-       parsing_conditionalized_out = 0;
-      else
-       parsing_conditionalized_out = 1;
-    }
-#if defined (VI_MODE)
-  else if (strnicmp (args, "mode=", 5) == 0)
-    {
-      int mode;
-
-      if (stricmp (args + 5, "emacs") == 0)
-       mode = emacs_mode;
-      else if (stricmp (args + 5, "vi") == 0)
-       mode = vi_mode;
-      else
-       mode = no_mode;
-
-      if (mode == rl_editing_mode)
-       parsing_conditionalized_out = 0;
-      else
-       parsing_conditionalized_out = 1;
-    }
-#endif /* VI_MODE */
-  /* Check to see if the first word in ARGS is the same as the
-     value stored in rl_readline_name. */
-  else if (stricmp (args, rl_readline_name) == 0)
-    parsing_conditionalized_out = 0;
-  else
-    parsing_conditionalized_out = 1;
-}
-
-/* Invert the current parser state if there is anything on the stack. */
-parser_else (args)
-     char *args;
-{
-  register int i;
-
-  if (!if_stack_depth)
-    {
-      /* Error message? */
-      return;
-    }
-
-  /* Check the previous (n - 1) levels of the stack to make sure that
-     we haven't previously turned off parsing. */
-  for (i = 0; i < if_stack_depth - 1; i++)
-    if (if_stack[i] == 1)
-      return;
-
-  /* Invert the state of parsing if at top level. */
-  parsing_conditionalized_out = !parsing_conditionalized_out;
-}
-
-/* Terminate a conditional, popping the value of
-   parsing_conditionalized_out from the stack. */
-parser_endif (args)
-     char *args;
-{
-  if (if_stack_depth)
-    parsing_conditionalized_out = if_stack[--if_stack_depth];
-  else
-    {
-      /* *** What, no error message? *** */
-    }
-}
-
-/* Associate textual names with actual functions. */
-static struct {
-  char *name;
-  Function *function;
-} parser_directives [] = {
-  { "if", parser_if },
-  { "endif", parser_endif },
-  { "else", parser_else },
-  { (char *)0x0, (Function *)0x0 }
-};
-
-/* Handle a parser directive.  STATEMENT is the line of the directive
-   without any leading `$'. */
-static int
-handle_parser_directive (statement)
-     char *statement;
-{
-  register int i;
-  char *directive, *args;
-
-  /* Isolate the actual directive. */
-
-  /* Skip whitespace. */
-  for (i = 0; whitespace (statement[i]); i++);
-
-  directive = &statement[i];
-
-  for (; statement[i] && !whitespace (statement[i]); i++);
-
-  if (statement[i])
-    statement[i++] = '\0';
-
-  for (; statement[i] && whitespace (statement[i]); i++);
-
-  args = &statement[i];
-
-  /* Lookup the command, and act on it. */
-  for (i = 0; parser_directives[i].name; i++)
-    if (stricmp (directive, parser_directives[i].name) == 0)
-      {
-       (*parser_directives[i].function) (args);
-       return (0);
-      }
-
-  /* *** Should an error message be output? */
-  return (1);
-}
-
-/* Ugly but working hack for binding prefix meta. */
-#define PREFIX_META_HACK
-
-static int substring_member_of_array ();
-
-/* Read the binding command from STRING and perform it.
-   A key binding command looks like: Keyname: function-name\0,
-   a variable binding command looks like: set variable value.
-   A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
-rl_parse_and_bind (string)
-     char *string;
-{
-  extern char *possible_control_prefixes[], *possible_meta_prefixes[];
-  char *funname, *kname;
-  register int c;
-  int key, i;
-
-  while (string && whitespace (*string))
-    string++;
-
-  if (!string || !*string || *string == '#')
-    return;
-
-  /* If this is a parser directive, act on it. */
-  if (*string == '$')
-    {
-      handle_parser_directive (&string[1]);
-      return;
-    }
-
-  /* If we are supposed to be skipping parsing right now, then do it. */
-  if (parsing_conditionalized_out)
-    return;
-
-  i = 0;
-  /* If this keyname is a complex key expression surrounded by quotes,
-     advance to after the matching close quote. */
-  if (*string == '"')
-    {
-      for (i = 1; c = string[i]; i++)
-       {
-         if (c == '"' && string[i - 1] != '\\')
-           break;
-       }
-    }
-
-  /* Advance to the colon (:) or whitespace which separates the two objects. */
-  for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
-
-  /* Mark the end of the command (or keyname). */
-  if (string[i])
-    string[i++] = '\0';
-
-  /* If this is a command to set a variable, then do that. */
-  if (stricmp (string, "set") == 0)
-    {
-      char *var = string + i;
-      char *value;
-
-      /* Make VAR point to start of variable name. */
-      while (*var && whitespace (*var)) var++;
-
-      /* Make value point to start of value string. */
-      value = var;
-      while (*value && !whitespace (*value)) value++;
-      if (*value)
-       *value++ = '\0';
-      while (*value && whitespace (*value)) value++;
-
-      rl_variable_bind (var, value);
-      return;
-    }
-
-  /* Skip any whitespace between keyname and funname. */
-  for (; string[i] && whitespace (string[i]); i++);
-  funname = &string[i];
-
-  /* Now isolate funname.
-     For straight function names just look for whitespace, since
-     that will signify the end of the string.  But this could be a
-     macro definition.  In that case, the string is quoted, so skip
-     to the matching delimiter. */
-  if (*funname == '\'' || *funname == '"')
-    {
-      int delimiter = string[i++];
-
-      for (; c = string[i]; i++)
-       {
-         if (c == delimiter && string[i - 1] != '\\')
-           break;
-       }
-      if (c)
-       i++;
-    }
-
-  /* Advance to the end of the string.  */
-  for (; string[i] && !whitespace (string[i]); i++);
-
-  /* No extra whitespace at the end of the string. */
-  string[i] = '\0';
-
-  /* If this is a new-style key-binding, then do the binding with
-     rl_set_key ().  Otherwise, let the older code deal with it. */
-  if (*string == '"')
-    {
-      char *seq = alloca (1 + strlen (string));
-      register int j, k = 0;
-
-      for (j = 1; string[j]; j++)
-       {
-         if (string[j] == '"' && string[j - 1] != '\\')
-           break;
-
-         seq[k++] = string[j];
-       }
-      seq[k] = '\0';
-
-      /* Binding macro? */
-      if (*funname == '\'' || *funname == '"')
-       {
-         j = strlen (funname);
-
-         if (j && funname[j - 1] == *funname)
-           funname[j - 1] = '\0';
-
-         rl_macro_bind (seq, &funname[1], keymap);
-       }
-      else
-       rl_set_key (seq, rl_named_function (funname), keymap);
-
-      return;
-    }
-
-  /* Get the actual character we want to deal with. */
-  kname = rindex (string, '-');
-  if (!kname)
-    kname = string;
-  else
-    kname++;
-
-  key = glean_key_from_name (kname);
-
-  /* Add in control and meta bits. */
-  if (substring_member_of_array (string, possible_control_prefixes))
-    key = CTRL (to_upper (key));
-
-  if (substring_member_of_array (string, possible_meta_prefixes))
-    key = META (key);
-
-  /* Temporary.  Handle old-style keyname with macro-binding. */
-  if (*funname == '\'' || *funname == '"')
-    {
-      char seq[2];
-      int fl = strlen (funname);
-
-      seq[0] = key; seq[1] = '\0';
-      if (fl && funname[fl - 1] == *funname)
-       funname[fl - 1] = '\0';
-
-      rl_macro_bind (seq, &funname[1], keymap);
-    }
-#if defined (PREFIX_META_HACK)
-  /* Ugly, but working hack to keep prefix-meta around. */
-  else if (stricmp (funname, "prefix-meta") == 0)
-    {
-      char seq[2];
-
-      seq[0] = key;
-      seq[1] = '\0';
-      rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, keymap);
-    }
-#endif /* PREFIX_META_HACK */
-  else
-    rl_bind_key (key, rl_named_function (funname));
-}
-
-rl_variable_bind (name, value)
-     char *name, *value;
-{
-  if (stricmp (name, "editing-mode") == 0)
-    {
-      if (strnicmp (value, "vi", 2) == 0)
-       {
-#if defined (VI_MODE)
-         keymap = vi_insertion_keymap;
-         rl_editing_mode = vi_mode;
-#else
-#if defined (NOTDEF)
-         /* What state is the terminal in?  I'll tell you:
-            non-determinate!  That means we cannot do any output. */
-         ding ();
-#endif /* NOTDEF */
-#endif /* VI_MODE */
-       }
-      else if (strnicmp (value, "emacs", 5) == 0)
-       {
-         keymap = emacs_standard_keymap;
-         rl_editing_mode = emacs_mode;
-       }
-    }
-  else if (stricmp (name, "horizontal-scroll-mode") == 0)
-    {
-      if (!*value || stricmp (value, "On") == 0)
-       horizontal_scroll_mode = 1;
-      else
-       horizontal_scroll_mode = 0;
-    }
-  else if (stricmp (name, "mark-modified-lines") == 0)
-    {
-      if (!*value || stricmp (value, "On") == 0)
-       mark_modified_lines = 1;
-      else
-       mark_modified_lines = 0;
-    }
-  else if (stricmp (name, "prefer-visible-bell") == 0)
-    {
-      if (!*value || stricmp (value, "On") == 0)
-        prefer_visible_bell = 1;
-      else
-        prefer_visible_bell = 0;
-    }
-  else if (stricmp (name, "comment-begin") == 0)
-    {
-#if defined (VI_MODE)
-      extern char *rl_vi_comment_begin;
-
-      if (*value)
-       {
-         if (rl_vi_comment_begin)
-           free (rl_vi_comment_begin);
-
-         rl_vi_comment_begin = savestring (value);
-       }
-#endif /* VI_MODE */
-    }
-}
-
-/* Return the character which matches NAME.
-   For example, `Space' returns ' '. */
-
-typedef struct {
-  char *name;
-  int value;
-} assoc_list;
-
-assoc_list name_key_alist[] = {
-  { "DEL", 0x7f },
-  { "ESC", '\033' },
-  { "Escape", '\033' },
-  { "LFD", '\n' },
-  { "Newline", '\n' },
-  { "RET", '\r' },
-  { "Return", '\r' },
-  { "Rubout", 0x7f },
-  { "SPC", ' ' },
-  { "Space", ' ' },
-  { "Tab", 0x09 },
-  { (char *)0x0, 0 }
-};
-
-int
-glean_key_from_name (name)
-     char *name;
-{
-  register int i;
-
-  for (i = 0; name_key_alist[i].name; i++)
-    if (stricmp (name, name_key_alist[i].name) == 0)
-      return (name_key_alist[i].value);
-
-  return (*name);
-}
-
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*               Key Binding and Function Information              */
-/*                                                                 */
-/* **************************************************************** */
-
-/* Each of the following functions produces information about the
-   state of keybindings and functions known to Readline.  The info
-   is always printed to rl_outstream, and in such a way that it can
-   be read back in (i.e., passed to rl_parse_and_bind (). */
-
-/* Print the names of functions known to Readline. */
-void
-rl_list_funmap_names (ignore)
-     int ignore;
-{
-  register int i;
-  char **funmap_names;
-  extern char **rl_funmap_names ();
-
-  funmap_names = rl_funmap_names ();
-
-  if (!funmap_names)
-    return;
-
-  for (i = 0; funmap_names[i]; i++)
-    fprintf (rl_outstream, "%s\n", funmap_names[i]);
-
-  free (funmap_names);
-}
-
-/* Return a NULL terminated array of strings which represent the key
-   sequences that are used to invoke FUNCTION in MAP. */
-static char **
-invoking_keyseqs_in_map (function, map)
-     Function *function;
-     Keymap map;
-{
-  register int key;
-  char **result;
-  int result_index, result_size;
-
-  result = (char **)NULL;
-  result_index = result_size = 0;
-
-  for (key = 0; key < 128; key++)
-    {
-      switch (map[key].type)
-       {
-       case ISMACR:
-         /* Macros match, if, and only if, the pointers are identical.
-            Thus, they are treated exactly like functions in here. */
-       case ISFUNC:
-         /* If the function in the keymap is the one we are looking for,
-            then add the current KEY to the list of invoking keys. */
-         if (map[key].function == function)
-           {
-             char *keyname = (char *)xmalloc (5);
-
-             if (CTRL_P (key))
-               sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
-             else if (key == RUBOUT)
-               sprintf (keyname, "\\C-?");
-             else
-               sprintf (keyname, "%c", key);
-             
-             if (result_index + 2 > result_size)
-               {
-                 if (!result)
-                   result = (char **) xmalloc
-                     ((result_size = 10) * sizeof (char *));
-                 else
-                   result = (char **) xrealloc
-                     (result, (result_size += 10) * sizeof (char *));
-               }
-
-             result[result_index++] = keyname;
-             result[result_index] = (char *)NULL;
-           }
-         break;
-
-       case ISKMAP:
-         {
-           char **seqs = (char **)NULL;
-
-           /* Find the list of keyseqs in this map which have FUNCTION as
-              their target.  Add the key sequences found to RESULT. */
-           if (map[key].function)
-             seqs =
-               invoking_keyseqs_in_map (function, (Keymap)map[key].function);
-
-           if (seqs)
-             {
-               register int i;
-
-               for (i = 0; seqs[i]; i++)
-                 {
-                   char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
-
-                   if (key == ESC)
-                     sprintf (keyname, "\\e");
-                   else if (CTRL_P (key))
-                     sprintf (keyname, "\\C-%c", to_lower (UNCTRL (key)));
-                   else if (key == RUBOUT)
-                     sprintf (keyname, "\\C-?");
-                   else
-                     sprintf (keyname, "%c", key);
-
-                   strcat (keyname, seqs[i]);
-
-                   if (result_index + 2 > result_size)
-                     {
-                       if (!result)
-                         result = (char **)
-                           xmalloc ((result_size = 10) * sizeof (char *));
-                       else
-                         result = (char **)
-                           xrealloc (result,
-                                     (result_size += 10) * sizeof (char *));
-                     }
-
-                   result[result_index++] = keyname;
-                   result[result_index] = (char *)NULL;
-                 }
-             }
-         }
-         break;
-       }
-    }
-  return (result);
-}
-
-/* Return a NULL terminated array of strings which represent the key
-   sequences that can be used to invoke FUNCTION using the current keymap. */
-char **
-rl_invoking_keyseqs (function)
-     Function *function;
-{
-  return (invoking_keyseqs_in_map (function, keymap));
-}
-
-/* Print all of the current functions and their bindings to
-   rl_outstream.  If an explicit argument is given, then print
-   the output in such a way that it can be read back in. */
-int
-rl_dump_functions (count)
-     int count;
-{
-  void rl_function_dumper ();
-
-  rl_function_dumper (rl_explicit_arg);
-  rl_on_new_line ();
-  return (0);
-}
-
-/* Print all of the functions and their bindings to rl_outstream.  If
-   PRINT_READABLY is non-zero, then print the output in such a way
-   that it can be read back in. */
-void
-rl_function_dumper (print_readably)
-     int print_readably;
-{
-  register int i;
-  char **rl_funmap_names (), **names;
-  char *name;
-
-  names = rl_funmap_names ();
-
-  fprintf (rl_outstream, "\n");
-
-  for (i = 0; name = names[i]; i++)
-    {
-      Function *function;
-      char **invokers;
-
-      function = rl_named_function (name);
-      invokers = invoking_keyseqs_in_map (function, keymap);
-
-      if (print_readably)
-       {
-         if (!invokers)
-           fprintf (rl_outstream, "# %s (not bound)\n", name);
-         else
-           {
-             register int j;
-
-             for (j = 0; invokers[j]; j++)
-               {
-                 fprintf (rl_outstream, "\"%s\": %s\n",
-                          invokers[j], name);
-                 free (invokers[j]);
-               }
-
-             free (invokers);
-           }
-       }
-      else
-       {
-         if (!invokers)
-           fprintf (rl_outstream, "%s is not bound to any keys\n",
-                    name);
-         else
-           {
-             register int j;
-
-             fprintf (rl_outstream, "%s can be found on ", name);
-
-             for (j = 0; invokers[j] && j < 5; j++)
-               {
-                 fprintf (rl_outstream, "\"%s\"%s", invokers[j],
-                          invokers[j + 1] ? ", " : ".\n");
-               }
-
-             if (j == 5 && invokers[j])
-               fprintf (rl_outstream, "...\n");
-
-             for (j = 0; invokers[j]; j++)
-               free (invokers[j]);
-
-             free (invokers);
-           }
-       }
-    }
-}
-
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     String Utility Functions                    */
-/*                                                                 */
-/* **************************************************************** */
-
-static char *strindex ();
-
-/* Return pointer to first occurance in STRING1 of any character from STRING2,
-   or NULL if no occurance found. */
-static char *
-strpbrk (string1, string2)
-     char *string1, *string2;
-{
-  register char *scan;
-
-  for (; *string1 != '\0'; string1++)
-    {
-      for (scan = string2; *scan != '\0'; scan++)
-       {
-         if (*string1 == *scan)
-           {
-             return (string1);
-           }
-       }
-    }
-  return (NULL);
-}
-
-/* Return non-zero if any members of ARRAY are a substring in STRING. */
-static int
-substring_member_of_array (string, array)
-     char *string, **array;
-{
-  while (*array)
-    {
-      if (strindex (string, *array))
-       return (1);
-      array++;
-    }
-  return (0);
-}
-
-/* Whoops, Unix doesn't have strnicmp. */
-
-/* Compare at most COUNT characters from string1 to string2.  Case
-   doesn't matter. */
-static int
-strnicmp (string1, string2, count)
-     char *string1, *string2;
-{
-  register char ch1, ch2;
-
-  while (count)
-    {
-      ch1 = *string1++;
-      ch2 = *string2++;
-      if (to_upper(ch1) == to_upper(ch2))
-       count--;
-      else break;
-    }
-  return (count);
-}
-
-/* strcmp (), but caseless. */
-static int
-stricmp (string1, string2)
-     char *string1, *string2;
-{
-  register char ch1, ch2;
-
-  while (*string1 && *string2)
-    {
-      ch1 = *string1++;
-      ch2 = *string2++;
-      if (to_upper(ch1) != to_upper(ch2))
-       return (1);
-    }
-  return (*string1 | *string2);
-}
-
-/* Determine if s2 occurs in s1.  If so, return a pointer to the
-   match in s1.  The compare is case insensitive. */
-static char *
-strindex (s1, s2)
-     register char *s1, *s2;
-{
-  register int i, l = strlen (s2);
-  register int len = strlen (s1);
-
-  for (i = 0; (len - i) >= l; i++)
-    if (strnicmp (&s1[i], s2, l) == 0)
-      return (s1 + i);
-  return ((char *)NULL);
-}
-
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     USG (System V) Support                      */
-/*                                                                 */
-/* **************************************************************** */
-
-/* When compiling and running in the `Posix' environment, Ultrix does
-   not restart system calls, so this needs to do it. */
-int
-rl_getc (stream)
-     FILE *stream;
-{
-  int result;
-  unsigned char c;
-
-#ifdef __GO32__
-  if (isatty(0))
-    return getkey();
-#endif /* __GO32__ */
-
-  while (1)
-    {
-      result = read (fileno (stream), &c, sizeof (char));
-
-      if (result == sizeof (char))
-       return (c);
-
-      /* If zero characters are returned, then the file that we are
-        reading from is empty!  Return EOF in that case. */
-      if (result == 0)
-       return (EOF);
+#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */
 
 #ifndef __GO32__
       /* If the error that we received was SIGINT, then try again,
diff --git a/readline/rldefs.h b/readline/rldefs.h
new file mode 100644 (file)
index 0000000..83411bc
--- /dev/null
@@ -0,0 +1,250 @@
+/* rldefs.h -- an attempt to isolate some of the system-specific defines
+   for readline.  This should be included after any files that define
+   system-specific constants like _POSIX_VERSION or USG. */
+
+/* Copyright (C) 1987,1989 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
+   for it.
+
+   The 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 1, or (at your option)
+   any later version.
+
+   The 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLDEFS_H)
+#define _RLDEFS_H
+
+#if defined (__GNUC__)
+#  undef alloca
+#  define alloca __builtin_alloca
+#else
+#  if defined (sparc) || defined (HAVE_ALLOCA_H)
+#    include <alloca.h>
+#  endif
+#endif
+
+#define NEW_TTY_DRIVER
+#define HAVE_BSD_SIGNALS
+/* #define USE_XON_XOFF */
+
+#ifdef __MSDOS__
+#undef NEW_TTY_DRIVER
+#undef HAVE_BSD_SIGNALS
+#endif
+
+#if defined (__linux__)
+#  include <termcap.h>
+#endif /* __linux__ */
+
+/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
+#if defined (USG) && !defined (hpux)
+#  undef HAVE_BSD_SIGNALS
+#endif
+
+/* System V machines use termio. */
+#if !defined (_POSIX_VERSION)
+#  if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX)
+#    undef NEW_TTY_DRIVER
+#    define TERMIO_TTY_DRIVER
+#    include <termio.h>
+#    if !defined (TCOON)
+#      define TCOON 1
+#    endif
+#  endif /* USG || hpux || Xenix || sgi || DUGX */
+#endif /* !_POSIX_VERSION */
+
+/* Posix systems use termios and the Posix signal functions. */
+#if defined (_POSIX_VERSION)
+#  if !defined (TERMIOS_MISSING)
+#    undef NEW_TTY_DRIVER
+#    define TERMIOS_TTY_DRIVER
+#    include <termios.h>
+#  endif /* !TERMIOS_MISSING */
+#  define HAVE_POSIX_SIGNALS
+#  if !defined (O_NDELAY)
+#    define O_NDELAY O_NONBLOCK        /* Posix-style non-blocking i/o */
+#  endif /* O_NDELAY */
+#endif /* _POSIX_VERSION */
+
+/* System V.3 machines have the old 4.1 BSD `reliable' signal interface. */
+#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
+#  if defined (USGr3)
+#    if !defined (HAVE_USG_SIGHOLD)
+#      define HAVE_USG_SIGHOLD
+#    endif /* !HAVE_USG_SIGHOLD */
+#  endif /* USGr3 */
+#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
+
+/* Other (BSD) machines use sgtty. */
+#if defined (NEW_TTY_DRIVER)
+#  include <sgtty.h>
+#endif
+
+/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
+   it is not already defined.  It is used both to determine if a
+   special character is disabled and to disable certain special
+   characters.  Posix systems should set to 0, USG systems to -1. */
+#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
+#  if defined (_POSIX_VERSION)
+#    define _POSIX_VDISABLE 0
+#  else /* !_POSIX_VERSION */
+#    define _POSIX_VDISABLE -1
+#  endif /* !_POSIX_VERSION */
+#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
+
+#if 1
+#  define D_NAMLEN(d) strlen ((d)->d_name)
+#else /* !1 */
+
+#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3))
+#  if !defined (HAVE_DIRENT_H)
+#    define HAVE_DIRENT_H
+#  endif /* !HAVE_DIRENT_H */
+#endif /* !SHELL && (_POSIX_VERSION || USGr3) */
+
+#if defined (HAVE_DIRENT_H)
+#  include <dirent.h>
+#  if !defined (direct)
+#    define direct dirent
+#  endif /* !direct */
+#  define D_NAMLEN(d) strlen ((d)->d_name)
+#else /* !HAVE_DIRENT_H */
+#  define D_NAMLEN(d) ((d)->d_namlen)
+#  if defined (USG)
+#    if defined (Xenix)
+#      include <sys/ndir.h>
+#    else /* !Xenix (but USG...) */
+#      include "ndir.h"
+#    endif /* !Xenix */
+#  else /* !USG */
+#    include <sys/dir.h>
+#  endif /* !USG */
+#endif /* !HAVE_DIRENT_H */
+#endif /* !1 */
+
+#if defined (USG) && defined (TIOCGWINSZ) && !defined (Linux)
+#  include <sys/stream.h>
+#  if defined (HAVE_SYS_PTEM_H)
+#    include <sys/ptem.h>
+#  endif /* HAVE_SYS_PTEM_H */
+#  if defined (HAVE_SYS_PTE_H)
+#    include <sys/pte.h>
+#  endif /* HAVE_SYS_PTE_H */
+#endif /* USG && TIOCGWINSZ && !Linux */
+
+/* Posix macro to check file in statbuf for directory-ness.
+   This requires that <sys/stat.h> be included before this test. */
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif
+
+/* Decide which flavor of the header file describing the C library
+   string functions to include and include it. */
+
+#if defined (USG) || defined (NeXT)
+#  if !defined (HAVE_STRING_H)
+#    define HAVE_STRING_H
+#  endif /* !HAVE_STRING_H */
+#endif /* USG || NeXT */
+
+#if defined (HAVE_STRING_H)
+#  include <string.h>
+#else /* !HAVE_STRING_H */
+#  include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+#if defined (HAVE_VARARGS_H)
+#  include <varargs.h>
+#endif /* HAVE_VARARGS_H */
+
+/* This definition is needed by readline.c, rltty.c, and signals.c. */
+/* If on, then readline handles signals in a way that doesn't screw. */
+#define HANDLE_SIGNALS
+
+#if !defined (emacs_mode)
+#  define no_mode -1
+#  define vi_mode 0
+#  define emacs_mode 1
+#endif
+
+/* Define some macros for dealing with assorted signalling disciplines.
+
+   These macros provide a way to use signal blocking and disabling
+   without smothering your code in a pile of #ifdef's.
+
+   SIGNALS_UNBLOCK;                    Stop blocking all signals.
+
+   {
+     SIGNALS_DECLARE_SAVED (name);     Declare a variable to save the 
+                                       signal blocking state.
+       ...
+     SIGNALS_BLOCK (SIGSTOP, name);    Block a signal, and save the previous
+                                       state for restoration later.
+       ...
+     SIGNALS_RESTORE (name);           Restore previous signals.
+   }
+
+*/
+
+#ifdef HAVE_POSIX_SIGNALS
+                                                       /* POSIX signals */
+
+#define        SIGNALS_UNBLOCK \
+      do { sigset_t set;       \
+       sigemptyset (&set);     \
+       sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);      \
+      } while (0)
+
+#define        SIGNALS_DECLARE_SAVED(name)     sigset_t name
+
+#define        SIGNALS_BLOCK(SIG, saved)       \
+       do { sigset_t set;              \
+         sigemptyset (&set);           \
+         sigaddset (&set, SIG);        \
+         sigprocmask (SIG_BLOCK, &set, &saved);        \
+       } while (0)
+
+#define        SIGNALS_RESTORE(saved)          \
+  sigprocmask (SIG_SETMASK, &saved, (sigset_t *)NULL)
+
+
+#else  /* HAVE_POSIX_SIGNALS */
+#ifdef HAVE_BSD_SIGNALS
+                                                       /* BSD signals */
+
+#define        SIGNALS_UNBLOCK                 sigsetmask (0)
+#define        SIGNALS_DECLARE_SAVED(name)     int name
+#define        SIGNALS_BLOCK(SIG, saved)       saved = sigblock (sigmask (SIG))
+#define        SIGNALS_RESTORE(saved)          sigsetmask (saved)
+
+
+#else  /* HAVE_BSD_SIGNALS */
+                                                       /* None of the Above */
+
+#define        SIGNALS_UNBLOCK                 /* nothing */
+#define        SIGNALS_DECLARE_SAVED(name)     /* nothing */
+#define        SIGNALS_BLOCK(SIG, saved)       /* nothing */
+#define        SIGNALS_RESTORE(saved)          /* nothing */
+
+
+#endif /* HAVE_BSD_SIGNALS */
+#endif /* HAVE_POSIX_SIGNALS */
+
+/*  End of signal handling definitions.  */
+#endif /* !_RLDEFS_H */
diff --git a/readline/search.c b/readline/search.c
new file mode 100644 (file)
index 0000000..ea98c6f
--- /dev/null
@@ -0,0 +1,271 @@
+/* search.c - code for non-incremental searching in emacs and vi modes. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This file is part of the Readline Library (the Library), a set of
+   routines for providing Emacs style line input to programs that ask
+   for it.
+
+   The 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 1, or (at your option)
+   any later version.
+
+   The 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,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#if defined (__GNUC__)
+#  define alloca __builtin_alloca
+#else
+#  if defined (sparc) || defined (HAVE_ALLOCA_H)
+#    include <alloca.h>
+#  endif
+#endif
+
+#include "readline.h"
+#include "history.h"
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables imported from readline.c */
+extern int rl_point, rl_end, rl_line_buffer_len;
+extern Keymap _rl_keymap;
+extern char *rl_prompt;
+extern char *rl_line_buffer;
+extern HIST_ENTRY *saved_line_for_history;
+
+static char *noninc_search_string = (char *) NULL;
+static int noninc_history_pos = 0;
+
+/* Search the history list for STRING starting at absolute history position
+   POS.  If STRING begins with `^', the search must match STRING at the
+   beginning of a history line, otherwise a full substring match is performed
+   for STRING.  DIR < 0 means to search backwards through the history list,
+   DIR >= 0 means to search forward. */
+static int
+noninc_search_from_pos (string, pos, dir)
+     char *string;
+     int pos, dir;
+{
+  int ret, old;
+
+  old = where_history ();
+  history_set_pos (pos);
+
+  if (*string == '^')
+    ret = history_search_prefix (string + 1, dir);
+  else
+    ret = history_search (string, dir);
+
+  if (ret != -1)
+    ret = where_history ();
+
+  history_set_pos (old);
+  return (ret);
+}
+
+/* Search for a line in the history containing STRING.  If DIR is < 0, the
+   search is backwards through previous entries, else through subsequent
+   entries. */
+static void
+noninc_dosearch (string, dir)
+     char *string;
+     int dir;
+{
+  int oldpos, pos;
+  HIST_ENTRY *entry;
+
+  if (string == 0 || *string == 0 || noninc_history_pos < 0)
+    {
+      ding ();
+      return;
+    }
+
+  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
+  if (pos == -1)
+    {
+      /* Search failed, current history position unchanged. */
+      maybe_unsave_line ();
+      rl_clear_message ();
+      rl_point = 0;
+      ding ();
+      return;
+    }
+
+  noninc_history_pos = pos;
+
+  oldpos = where_history ();
+  history_set_pos (noninc_history_pos);
+  entry = current_history ();
+  history_set_pos (oldpos);
+
+  {
+    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_undo_list = (UNDO_LIST *)entry->data;
+  rl_end = strlen (rl_line_buffer);
+  rl_point = 0;
+  rl_clear_message ();
+
+  if (saved_line_for_history)
+    free_history_entry (saved_line_for_history);
+  saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Search non-interactively through the history list.  DIR < 0 means to
+   search backwards through the history of previous commands; otherwise
+   the search is for commands subsequent to the current position in the
+   history list.  PCHAR is the character to use for prompting when reading
+   the search string; if not specified (0), it defaults to `:'. */
+static void
+noninc_search (dir, pchar)
+     int dir;
+     int pchar;
+{
+  int saved_point, c, pmtlen;
+  char *p;
+
+  maybe_save_line ();
+  saved_point = rl_point;
+
+  /* Use the line buffer to read the search string. */
+  rl_line_buffer[0] = 0;
+  rl_end = rl_point = 0;
+
+  pmtlen = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
+  p = (char *)alloca (2 + pmtlen);
+  if (pmtlen)
+    strcpy (p, rl_prompt);
+  p[pmtlen] = pchar ? pchar : ':';
+  p[pmtlen + 1]  = '\0';
+
+  rl_message (p, 0, 0);
+
+  /* Read the search string. */
+  while (c = rl_read_key ())
+    {
+      switch (c)
+       {
+       case CTRL('H'):
+       case RUBOUT:
+         if (rl_point == 0)
+           {
+             maybe_unsave_line ();
+             rl_clear_message ();
+             rl_point = saved_point;
+             return;
+           }
+         /* FALLTHROUGH */
+
+       case CTRL('W'):
+       case CTRL('U'):
+         rl_dispatch (c, _rl_keymap);
+         break;
+
+       case RETURN:
+       case NEWLINE:
+         goto dosearch;
+         /* NOTREACHED */
+         break;
+
+       case CTRL('C'):
+       case CTRL('G'):
+         maybe_unsave_line ();
+         rl_clear_message ();
+         rl_point = saved_point;
+         ding ();
+         return;
+
+       default:
+         rl_insert (1, c);
+         break;
+       }
+      rl_redisplay ();
+    }
+
+ dosearch:
+  /* 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. */
+  if (rl_point == 0)
+    {
+      if (!noninc_search_string)
+       {
+         ding ();
+         return;
+       }
+    }
+  else
+    {
+      /* We want to start the search from the current history position. */
+      noninc_history_pos = where_history ();
+      if (noninc_search_string)
+       free (noninc_search_string);
+      noninc_search_string = savestring (rl_line_buffer);
+    }
+
+  noninc_dosearch (noninc_search_string, dir);
+}
+
+/* Search forward through the history list for a string.  If the vi-mode
+   code calls this, KEY will be `?'. */
+rl_noninc_forward_search (count, key)
+     int count, key;
+{
+  if (key == '?')
+    noninc_search (1, '?');
+  else
+    noninc_search (1, 0);
+}
+
+/* Reverse search the history list for a string.  If the vi-mode code
+   calls this, KEY will be `/'. */
+rl_noninc_reverse_search (count, key)
+     int count, key;
+{
+  if (key == '/')
+    noninc_search (-1, '/');
+  else
+    noninc_search (-1, 0);
+}
+
+/* Search forward through the history list for the last string searched
+   for.  If there is no saved search string, abort. */
+rl_noninc_forward_search_again (count, key)
+     int count, key;
+{
+  if (!noninc_search_string)
+    {
+      ding ();
+      return (-1);
+    }
+  noninc_dosearch (noninc_search_string, 1);
+}
+
+/* Reverse search in the history list for the last string searched
+   for.  If there is no saved search string, abort. */
+rl_noninc_reverse_search_again (count, key)
+     int count, key;
+{
+  if (!noninc_search_string)
+    {
+      ding ();
+      return (-1);
+    }
+  noninc_dosearch (noninc_search_string, -1);
+}
diff --git a/readline/tilde.c b/readline/tilde.c
new file mode 100644 (file)
index 0000000..22890f4
--- /dev/null
@@ -0,0 +1,396 @@
+/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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 1, or (at your option) any
+   later version.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (__GNUC__)
+#  undef alloca
+#  define alloca __builtin_alloca
+#else /* !__GNUC__ */
+#  if defined (_AIX)
+     #pragma alloca
+#  else /* !_AIX */
+#    if defined (HAVE_ALLOCA_H)
+#      include <alloca.h>
+#    endif /* HAVE_ALLOCA_H */
+#  endif /* !AIX */
+#endif /* !__GNUC__ */
+
+#if defined (HAVE_STRING_H)
+#  include <string.h>
+#else /* !HAVE_STRING_H */
+#  include <strings.h>
+#endif /* !HAVE_STRING_H */  
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <tilde/tilde.h>
+#include <pwd.h>
+
+#if !defined (sgi) && !defined (isc386)
+extern struct passwd *getpwnam (), *getpwuid ();
+#endif /* !sgi */
+
+#if !defined (savestring)
+extern char *xmalloc ();
+#  ifndef strcpy
+extern char *strcpy ();
+#  endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif /* !savestring */
+
+#if !defined (NULL)
+#  if defined (__STDC__)
+#    define NULL ((void *) 0)
+#  else
+#    define NULL 0x0
+#  endif /* !__STDC__ */
+#endif /* !NULL */
+
+#if defined (TEST) || defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* TEST || STATIC_MALLOC */
+
+/* The default value of tilde_additional_prefixes.  This is set to
+   whitespace preceding a tilde so that simple programs which do not
+   perform any word separation get desired behaviour. */
+static char *default_prefixes[] =
+  { " ~", "\t~", (char *)NULL };
+
+/* The default value of tilde_additional_suffixes.  This is set to
+   whitespace or newline so that simple programs which do not
+   perform any word separation get desired behaviour. */
+static char *default_suffixes[] =
+  { " ", "\n", (char *)NULL };
+
+/* If non-null, this contains the address of a function to call if the
+   standard meaning for expanding a tilde fails.  The function is called
+   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if there is no expansion. */
+Function *tilde_expansion_failure_hook = (Function *)NULL;
+
+/* When non-null, this is a NULL terminated array of strings which
+   are duplicates for a tilde prefix.  Bash uses this to expand
+   `=~' and `:~'. */
+char **tilde_additional_prefixes = default_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+   the end of a username, instead of just "/".  Bash sets this to
+   `:' and `=~'. */
+char **tilde_additional_suffixes = default_suffixes;
+
+/* Find the start of a tilde expansion in STRING, and return the index of
+   the tilde which starts the expansion.  Place the length of the text
+   which identified this tilde starter in LEN, excluding the tilde itself. */
+static int
+tilde_find_prefix (string, len)
+     char *string;
+     int *len;
+{
+  register int i, j, string_len;
+  register char **prefixes = tilde_additional_prefixes;
+
+  string_len = strlen (string);
+  *len = 0;
+
+  if (!*string || *string == '~')
+    return (0);
+
+  if (prefixes)
+    {
+      for (i = 0; i < string_len; i++)
+       {
+         for (j = 0; prefixes[j]; j++)
+           {
+             if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
+               {
+                 *len = strlen (prefixes[j]) - 1;
+                 return (i + *len);
+               }
+           }
+       }
+    }
+  return (string_len);
+}
+
+/* Find the end of a tilde expansion in STRING, and return the index of
+   the character which ends the tilde definition.  */
+static int
+tilde_find_suffix (string)
+     char *string;
+{
+  register int i, j, string_len;
+  register char **suffixes = tilde_additional_suffixes;
+
+  string_len = strlen (string);
+
+  for (i = 0; i < string_len; i++)
+    {
+      if (string[i] == '/' || !string[i])
+       break;
+
+      for (j = 0; suffixes && suffixes[j]; j++)
+       {
+         if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
+           return (i);
+       }
+    }
+  return (i);
+}
+
+/* Return a new string which is the result of tilde expanding STRING. */
+char *
+tilde_expand (string)
+     char *string;
+{
+  char *result, *tilde_expand_word ();
+  int result_size, result_index;
+
+  result_size = result_index = 0;
+  result = (char *)NULL;
+
+  /* Scan through STRING expanding tildes as we come to them. */
+  while (1)
+    {
+      register int start, end;
+      char *tilde_word, *expansion;
+      int len;
+
+      /* Make START point to the tilde which starts the expansion. */
+      start = tilde_find_prefix (string, &len);
+
+      /* Copy the skipped text into the result. */
+      if ((result_index + start + 1) > result_size)
+       result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
+
+      strncpy (result + result_index, string, start);
+      result_index += start;
+
+      /* Advance STRING to the starting tilde. */
+      string += start;
+
+      /* Make END be the index of one after the last character of the
+        username. */
+      end = tilde_find_suffix (string);
+
+      /* If both START and END are zero, we are all done. */
+      if (!start && !end)
+       break;
+
+      /* Expand the entire tilde word, and copy it into RESULT. */
+      tilde_word = (char *)xmalloc (1 + end);
+      strncpy (tilde_word, string, end);
+      tilde_word[end] = '\0';
+      string += end;
+
+      expansion = tilde_expand_word (tilde_word);
+      free (tilde_word);
+
+      len = strlen (expansion);
+      if ((result_index + len + 1) > result_size)
+       result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
+
+      strcpy (result + result_index, expansion);
+      result_index += len;
+      free (expansion);
+    }
+
+  result[result_index] = '\0';
+
+  return (result);
+}
+
+/* Do the work of tilde expansion on FILENAME.  FILENAME starts with a
+   tilde.  If there is no expansion, call tilde_expansion_failure_hook. */
+char *
+tilde_expand_word (filename)
+     char *filename;
+{
+  char *dirname;
+
+  dirname = filename ? savestring (filename) : (char *)NULL;
+
+  if (dirname && *dirname == '~')
+    {
+      char *temp_name;
+      if (!dirname[1] || dirname[1] == '/')
+       {
+         /* Prepend $HOME to the rest of the string. */
+         char *temp_home = (char *)getenv ("HOME");
+
+         /* If there is no HOME variable, look up the directory in
+            the password database. */
+         if (!temp_home)
+           {
+             struct passwd *entry;
+
+             entry = getpwuid (getuid ());
+             if (entry)
+               temp_home = entry->pw_dir;
+           }
+
+         temp_name = (char *)alloca (1 + strlen (&dirname[1])
+                                     + (temp_home ? strlen (temp_home) : 0));
+         temp_name[0] = '\0';
+         if (temp_home)
+           strcpy (temp_name, temp_home);
+         strcat (temp_name, &dirname[1]);
+         free (dirname);
+         dirname = savestring (temp_name);
+       }
+      else
+       {
+         struct passwd *user_entry;
+         char *username = (char *)alloca (257);
+         int i, c;
+
+         for (i = 1; c = dirname[i]; i++)
+           {
+             if (c == '/')
+               break;
+             else
+               username[i - 1] = c;
+           }
+         username[i - 1] = '\0';
+
+         if (!(user_entry = getpwnam (username)))
+           {
+             /* If the calling program has a special syntax for
+                expanding tildes, and we couldn't find a standard
+                expansion, then let them try. */
+             if (tilde_expansion_failure_hook)
+               {
+                 char *expansion;
+
+                 expansion =
+                   (char *)(*tilde_expansion_failure_hook) (username);
+
+                 if (expansion)
+                   {
+                     temp_name = (char *)alloca (1 + strlen (expansion)
+                                                 + strlen (&dirname[i]));
+                     strcpy (temp_name, expansion);
+                     strcat (temp_name, &dirname[i]);
+                     free (expansion);
+                     goto return_name;
+                   }
+               }
+             /* We shouldn't report errors. */
+           }
+         else
+           {
+             temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir)
+                                         + strlen (&dirname[i]));
+             strcpy (temp_name, user_entry->pw_dir);
+             strcat (temp_name, &dirname[i]);
+           return_name:
+             free (dirname);
+             dirname = savestring (temp_name);
+           }
+           endpwent ();
+       }
+    }
+  return (dirname);
+}
+
+\f
+#if defined (TEST)
+#undef NULL
+#include <stdio.h>
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *result, line[512];
+  int done = 0;
+
+  while (!done)
+    {
+      printf ("~expand: ");
+      fflush (stdout);
+
+      if (!gets (line))
+       strcpy (line, "done");
+
+      if ((strcmp (line, "done") == 0) ||
+         (strcmp (line, "quit") == 0) ||
+         (strcmp (line, "exit") == 0))
+       {
+         done = 1;
+         break;
+       }
+
+      result = tilde_expand (line);
+      printf ("  --> %s\n", result);
+      free (result);
+    }
+  exit (0);
+}
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp;
+
+  if (!pointer)
+    temp = (char *)malloc (bytes);
+  else
+    temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "readline: Out of virtual memory!\n");
+  abort ();
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -DTEST -o tilde tilde.c"
+ * end:
+ */
+#endif /* TEST */
diff --git a/readline/tilde.h b/readline/tilde.h
new file mode 100644 (file)
index 0000000..4f808fe
--- /dev/null
@@ -0,0 +1,33 @@
+/* tilde.h: Externally available variables and function in libtilde.a. */
+
+/* Function pointers can be declared as (Function *)foo. */
+#if !defined (__FUNCTION_DEF)
+#  define __FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* If non-null, this contains the address of a function to call if the
+   standard meaning for expanding a tilde fails.  The function is called
+   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if there is no expansion. */
+extern Function *tilde_expansion_failure_hook;
+
+/* When non-null, this is a NULL terminated array of strings which
+   are duplicates for a tilde prefix.  Bash uses this to expand
+   `=~' and `:~'. */
+extern char **tilde_additional_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+   the end of a username, instead of just "/".  Bash sets this to
+   `:' and `=~'. */
+extern char **tilde_additional_suffixes;
+
+/* Return a new string which is the result of tilde expanding STRING. */
+extern char *tilde_expand ();
+
+/* Do the work of tilde expansion on FILENAME.  FILENAME starts with a
+   tilde.  If there is no expansion, call tilde_expansion_failure_hook. */
+extern char *tilde_expand_word ();
diff --git a/readline/xmalloc.c b/readline/xmalloc.c
new file mode 100644 (file)
index 0000000..0ed49dd
--- /dev/null
@@ -0,0 +1,76 @@
+/* xmalloc.c -- safe versions of malloc and realloc */
+
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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 1, or (at your option) any
+   later version.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (ALREADY_HAVE_XMALLOC)
+#else
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+static void memory_error_and_abort ();
+
+/* **************************************************************** */
+/*                                                                 */
+/*                Memory Allocation and Deallocation.              */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Return a pointer to free()able block of memory large enough
+   to hold BYTES number of bytes.  If the memory cannot be allocated,
+   print an error message and abort. */
+char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ("xmalloc");
+  return (temp);
+}
+
+char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp;
+
+  if (!pointer)
+    temp = (char *)malloc (bytes);
+  else
+    temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ("xrealloc");
+  return (temp);
+}
+
+static void
+memory_error_and_abort (fname)
+     char *fname;
+{
+  fprintf (stderr, "%s: Out of virtual memory!\n", fname);
+  abort ();
+}
+#endif /* !ALREADY_HAVE_XMALLOC */
This page took 0.127343 seconds and 4 git commands to generate.