Support R_SPARC_WDISP10 and R_SPARC_H34.
[external/binutils.git] / readline / bind.c
index a7ffe25..a939528 100644 (file)
@@ -1,39 +1,59 @@
 /* bind.c -- key binding and startup file support for the readline library. */
 
-/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2010 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.
+   This file is part of the GNU Readline Library (Readline), 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
+   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 3 of the License, 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
+   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.
 
-   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. */
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (__TANDEM)
+#  include <floss.h>
+#endif
+
+#if defined (HAVE_CONFIG_H)
+#  include <config.h>
+#endif
 
-#include "sysdep.h"
 #include <stdio.h>
 #include <sys/types.h>
 #include <fcntl.h>
-#ifndef        NO_SYS_FILE
-#include <sys/file.h>
-#endif
+#if defined (HAVE_SYS_FILE_H)
+#  include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+#  include <stdlib.h>
+#else
+#  include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
 
 #include <errno.h>
-/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
+#include "posixstat.h"
+
 /* System-specific feature definitions and include files. */
 #include "rldefs.h"
 
@@ -41,42 +61,30 @@ extern int errno;
 #include "readline.h"
 #include "history.h"
 
+#include "rlprivate.h"
+#include "rlshell.h"
+#include "xmalloc.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;
+/* Variables exported by this file. */
+Keymap rl_binding_keymap;
 
-extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+static char *_rl_read_file PARAMS((char *, size_t *));
+static void _rl_init_file_error PARAMS((const char *));
+static int _rl_read_init_file PARAMS((const char *, int));
+static int glean_key_from_name PARAMS((char *));
+static int find_boolean_var PARAMS((const char *));
 
-extern char **rl_funmap_names ();
+static char *_rl_get_string_variable_value PARAMS((const char *));
+static int substring_member_of_array PARAMS((const char *, const char * const *));
 
-static void rl_generic_bind ();
-static int glean_key_from_name ();
-static int stricmp (), strnicmp ();
+static int currently_reading_init_file;
 
-#if defined (STATIC_MALLOC)
-static char *xmalloc (), *xrealloc ();
-#else
-extern char *xmalloc (), *xrealloc ();
-#endif /* STATIC_MALLOC */
+/* used only in this file */
+static int _rl_prefer_visible_bell = 1;
 
 /* **************************************************************** */
 /*                                                                 */
@@ -84,24 +92,26 @@ extern char *xmalloc (), *xrealloc ();
 /*                                                                 */
 /* **************************************************************** */
 
-/* rl_add_defun (char *name, Function *function, int key)
+/* rl_add_defun (char *name, rl_command_func_t *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. */
+int
 rl_add_defun (name, function, key)
-     char *name;
-     Function *function;
+     const char *name;
+     rl_command_func_t *function;
      int key;
 {
   if (key != -1)
     rl_bind_key (key, function);
   rl_add_funmap_entry (name, function);
+  return 0;
 }
 
 /* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
 int
 rl_bind_key (key, function)
      int key;
-     Function *function;
+     rl_command_func_t *function;
 {
   if (key < 0)
     return (key);
@@ -110,8 +120,9 @@ rl_bind_key (key, function)
     {
       if (_rl_keymap[ESC].type == ISKMAP)
        {
-         Keymap escmap = (Keymap)_rl_keymap[ESC].function;
+         Keymap escmap;
 
+         escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC);
          key = UNMETA (key);
          escmap[key].type = ISFUNC;
          escmap[key].function = function;
@@ -122,6 +133,7 @@ rl_bind_key (key, function)
 
   _rl_keymap[key].type = ISFUNC;
   _rl_keymap[key].function = function;
+  rl_binding_keymap = _rl_keymap;
   return (0);
 }
 
@@ -130,25 +142,54 @@ rl_bind_key (key, function)
 int
 rl_bind_key_in_map (key, function, map)
      int key;
-     Function *function;
+     rl_command_func_t *function;
      Keymap map;
 {
   int result;
-  Keymap oldmap = _rl_keymap;
+  Keymap oldmap;
 
+  oldmap = _rl_keymap;
   _rl_keymap = map;
   result = rl_bind_key (key, function);
   _rl_keymap = oldmap;
   return (result);
 }
 
+/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound.  Right
+   now, this is always used to attempt to bind the arrow keys, hence the
+   check for rl_vi_movement_mode. */
+int
+rl_bind_key_if_unbound_in_map (key, default_func, kmap)
+     int key;
+     rl_command_func_t *default_func;
+     Keymap kmap;
+{
+  char keyseq[2];
+
+  keyseq[0] = (unsigned char)key;
+  keyseq[1] = '\0';
+  return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap));
+}
+
+int
+rl_bind_key_if_unbound (key, default_func)
+     int key;
+     rl_command_func_t *default_func;
+{
+  char keyseq[2];
+
+  keyseq[0] = (unsigned char)key;
+  keyseq[1] = '\0';
+  return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap));
+}
+
 /* 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));
+  return (rl_bind_key (key, (rl_command_func_t *)NULL));
 }
 
 /* Make KEY do nothing in MAP.
@@ -158,25 +199,114 @@ rl_unbind_key_in_map (key, map)
      int key;
      Keymap map;
 {
-  return (rl_bind_key_in_map (key, (Function *)NULL, map));
+  return (rl_bind_key_in_map (key, (rl_command_func_t *)NULL, map));
+}
+
+/* Unbind all keys bound to FUNCTION in MAP. */
+int
+rl_unbind_function_in_map (func, map)
+     rl_command_func_t *func;
+     Keymap map;
+{
+  register int i, rval;
+
+  for (i = rval = 0; i < KEYMAP_SIZE; i++)
+    {
+      if (map[i].type == ISFUNC && map[i].function == func)
+       {
+         map[i].function = (rl_command_func_t *)NULL;
+         rval = 1;
+       }
+    }
+  return rval;
+}
+
+int
+rl_unbind_command_in_map (command, map)
+     const char *command;
+     Keymap map;
+{
+  rl_command_func_t *func;
+
+  func = rl_named_function (command);
+  if (func == 0)
+    return 0;
+  return (rl_unbind_function_in_map (func, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   FUNCTION, starting in the current keymap.  This makes new
+   keymaps as necessary. */
+int
+rl_bind_keyseq (keyseq, function)
+     const char *keyseq;
+     rl_command_func_t *function;
+{
+  return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap));
 }
 
 /* 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. */
+int
+rl_bind_keyseq_in_map (keyseq, function, map)
+     const char *keyseq;
+     rl_command_func_t *function;
+     Keymap map;
+{
+  return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map));
+}
+
+/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */
+int
 rl_set_key (keyseq, function, map)
-     char *keyseq;
-     Function *function;
+     const char *keyseq;
+     rl_command_func_t *function;
      Keymap map;
 {
-  rl_generic_bind (ISFUNC, keyseq, function, map);
+  return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map));
+}
+
+/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound.  Right
+   now, this is always used to attempt to bind the arrow keys, hence the
+   check for rl_vi_movement_mode. */
+int
+rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap)
+     const char *keyseq;
+     rl_command_func_t *default_func;
+     Keymap kmap;
+{
+  rl_command_func_t *func;
+
+  if (keyseq)
+    {
+      func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL);
+#if defined (VI_MODE)
+      if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode)
+#else
+      if (!func || func == rl_do_lowercase_version)
+#endif
+       return (rl_bind_keyseq_in_map (keyseq, default_func, kmap));
+      else
+       return 1;
+    }
+  return 0;
+}
+
+int
+rl_bind_keyseq_if_unbound (keyseq, default_func)
+     const char *keyseq;
+     rl_command_func_t *default_func;
+{
+  return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap));
 }
 
 /* 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. */
+int
 rl_macro_bind (keyseq, macro, map)
-     char *keyseq, *macro;
+     const char *keyseq, *macro;
      Keymap map;
 {
   char *macro_keys;
@@ -186,10 +316,11 @@ rl_macro_bind (keyseq, macro, map)
 
   if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
     {
-      free (macro_keys);
-      return;
+      xfree (macro_keys);
+      return -1;
     }
   rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+  return 0;
 }
 
 /* Bind the key sequence represented by the string KEYSEQ to
@@ -197,123 +328,237 @@ rl_macro_bind (keyseq, macro, map)
    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
+int
 rl_generic_bind (type, keyseq, data, map)
      int type;
-     char *keyseq, *data;
+     const char *keyseq;
+     char *data;
      Keymap map;
 {
   char *keys;
   int keys_len;
   register int i;
+  KEYMAP_ENTRY k;
+
+  k.function = 0;
 
   /* If no keys to bind to, exit right away. */
-  if (!keyseq || !*keyseq)
+  if (keyseq == 0 || *keyseq == 0)
     {
       if (type == ISMACR)
-       free (data);
-      return;
+       xfree (data);
+      return -1;
     }
 
-  keys = (char *)alloca (1 + (2 * strlen (keyseq)));
+  keys = (char *)xmalloc (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;
+    {
+      xfree (keys);
+      return -1;
+    }
 
   /* Bind keys, making new keymaps as necessary. */
   for (i = 0; i < keys_len; i++)
     {
-      int ic = (int) ((unsigned char)keys[i]);
+      unsigned char uc = keys[i];
+      int ic;
+
+      ic = uc;
+      if (ic < 0 || ic >= KEYMAP_SIZE)
+        {
+          xfree (keys);
+         return -1;
+        }
 
-      if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic))
+      if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
        {
          ic = UNMETA (ic);
          if (map[ESC].type == ISKMAP)
-           map = (Keymap) map[ESC].function;
+           map = FUNCTION_TO_KEYMAP (map, ESC);
        }
 
       if ((i + 1) < keys_len)
        {
          if (map[ic].type != ISKMAP)
            {
-             if (map[ic].type == ISMACR)
-               free ((char *)map[ic].function);
+             /* We allow subsequences of keys.  If a keymap is being
+                created that will `shadow' an existing function or macro
+                key binding, we save that keybinding into the ANYOTHERKEY
+                index in the new map.  The dispatch code will look there
+                to find the function to execute if the subsequence is not
+                matched.  ANYOTHERKEY was chosen to be greater than
+                UCHAR_MAX. */
+             k = map[ic];
 
              map[ic].type = ISKMAP;
-             map[ic].function = (Function *)rl_make_bare_keymap ();
+             map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap());
+           }
+         map = FUNCTION_TO_KEYMAP (map, ic);
+         /* The dispatch code will return this function if no matching
+            key sequence is found in the keymap.  This (with a little
+            help from the dispatch code in readline.c) allows `a' to be
+            mapped to something, `abc' to be mapped to something else,
+            and the function bound  to `a' to be executed when the user
+            types `abx', leaving `bx' in the input queue. */
+         if (k.function && ((k.type == ISFUNC && k.function != rl_do_lowercase_version) || k.type == ISMACR))
+           {
+             map[ANYOTHERKEY] = k;
+             k.function = 0;
            }
-         map = (Keymap)map[ic].function;
        }
       else
        {
          if (map[ic].type == ISMACR)
-           free ((char *)map[ic].function);
+           xfree ((char *)map[ic].function);
+         else if (map[ic].type == ISKMAP)
+           {
+             map = FUNCTION_TO_KEYMAP (map, ic);
+             ic = ANYOTHERKEY;
+             /* If we're trying to override a keymap with a null function
+                (e.g., trying to unbind it), we can't use a null pointer
+                here because that's indistinguishable from having not been
+                overridden.  We use a special bindable function that does
+                nothing. */
+             if (type == ISFUNC && data == 0)
+               data = (char *)_rl_null_function;
+           }
 
-         map[ic].function = (Function *)data;
+         map[ic].function = KEYMAP_TO_FUNCTION (data);
          map[ic].type = type;
        }
+
+      rl_binding_keymap = map;
     }
+  xfree (keys);
+  return 0;
 }
 
 /* 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. */
+int
 rl_translate_keyseq (seq, array, len)
-     char *seq, *array;
+     const char *seq;
+     char *array;
      int *len;
 {
-  register int i, c, l = 0;
+  register int i, c, l, temp;
 
-  for (i = 0; c = seq[i]; i++)
+  for (i = l = 0; c = seq[i]; i++)
     {
       if (c == '\\')
        {
          c = seq[++i];
 
-         if (!c)
+         if (c == 0)
            break;
 
-         if (((c == 'C' || c == 'M') &&  seq[i + 1] == '-') ||
-             (c == 'e'))
+         /* Handle \C- and \M- prefixes. */
+         if ((c == 'C' || c == 'M') && seq[i + 1] == '-')
            {
              /* Handle special case of backwards define. */
              if (strncmp (&seq[i], "C-\\M-", 5) == 0)
                {
-                 array[l++] = ESC;
+                 array[l++] = ESC;     /* ESC is meta-prefix */
                  i += 5;
-                 array[l++] = CTRL (to_upper (seq[i]));
-                 if (!seq[i])
+                 array[l++] = CTRL (_rl_to_upper (seq[i]));
+                 if (seq[i] == '\0')
                    i--;
-                 continue;
                }
-
-             switch (c)
+             else if (c == 'M')
+               {
+                 i++;          /* seq[i] == '-' */
+                 /* XXX - obey convert-meta setting */
+                 if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP)
+                   array[l++] = ESC;   /* ESC is meta-prefix */
+                 else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-')
+                   {
+                     i += 4;
+                     temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
+                     array[l++] = META (temp);
+                   }
+                 else
+                   {
+                     /* This doesn't yet handle things like \M-\a, which may
+                        or may not have any reasonable meaning.  You're
+                        probably better off using straight octal or hex. */
+                     i++;
+                     array[l++] = META (seq[i]);
+                   }
+               }
+             else if (c == '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;
+                 array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
                }
-
              continue;
+           }         
+
+         /* Translate other backslash-escaped characters.  These are the
+            same escape sequences that bash's `echo' and `printf' builtins
+            handle, with the addition of \d -> RUBOUT.  A backslash
+            preceding a character that is not special is stripped. */
+         switch (c)
+           {
+           case 'a':
+             array[l++] = '\007';
+             break;
+           case 'b':
+             array[l++] = '\b';
+             break;
+           case 'd':
+             array[l++] = RUBOUT;      /* readline-specific */
+             break;
+           case 'e':
+             array[l++] = ESC;
+             break;
+           case 'f':
+             array[l++] = '\f';
+             break;
+           case 'n':
+             array[l++] = NEWLINE;
+             break;
+           case 'r':
+             array[l++] = RETURN;
+             break;
+           case 't':
+             array[l++] = TAB;
+             break;
+           case 'v':
+             array[l++] = 0x0B;
+             break;
+           case '\\':
+             array[l++] = '\\';
+             break;
+           case '0': case '1': case '2': case '3':
+           case '4': case '5': case '6': case '7':
+             i++;
+             for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++)
+               c = (c * 8) + OCTVALUE (seq[i]);
+             i--;      /* auto-increment in for loop */
+             array[l++] = c & largest_char;
+             break;
+           case 'x':
+             i++;
+             for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++)
+               c = (c * 16) + HEXVALUE (seq[i]);
+             if (temp == 2)
+               c = 'x';
+             i--;      /* auto-increment in for loop */
+             array[l++] = c & largest_char;
+             break;
+           default:    /* backslashes before non-special chars just add the char */
+             array[l++] = c;
+             break;    /* the backslash is stripped */
            }
+         continue;
        }
+
       array[l++] = c;
     }
 
@@ -322,21 +567,124 @@ rl_translate_keyseq (seq, array, len)
   return (0);
 }
 
+char *
+rl_untranslate_keyseq (seq)
+     int seq;
+{
+  static char kseq[16];
+  int i, c;
+
+  i = 0;
+  c = seq;
+  if (META_CHAR (c))
+    {
+      kseq[i++] = '\\';
+      kseq[i++] = 'M';
+      kseq[i++] = '-';
+      c = UNMETA (c);
+    }
+  else if (c == ESC)
+    {
+      kseq[i++] = '\\';
+      c = 'e';
+    }
+  else if (CTRL_CHAR (c))
+    {
+      kseq[i++] = '\\';
+      kseq[i++] = 'C';
+      kseq[i++] = '-';
+      c = _rl_to_lower (UNCTRL (c));
+    }
+  else if (c == RUBOUT)
+    {
+      kseq[i++] = '\\';
+      kseq[i++] = 'C';
+      kseq[i++] = '-';
+      c = '?';
+    }
+
+  if (c == ESC)
+    {
+      kseq[i++] = '\\';
+      c = 'e';
+    }
+  else if (c == '\\' || c == '"')
+    {
+      kseq[i++] = '\\';
+    }
+
+  kseq[i++] = (unsigned char) c;
+  kseq[i] = '\0';
+  return kseq;
+}
+
+static char *
+_rl_untranslate_macro_value (seq)
+     char *seq;
+{
+  char *ret, *r, *s;
+  int c;
+
+  r = ret = (char *)xmalloc (7 * strlen (seq) + 1);
+  for (s = seq; *s; s++)
+    {
+      c = *s;
+      if (META_CHAR (c))
+       {
+         *r++ = '\\';
+         *r++ = 'M';
+         *r++ = '-';
+         c = UNMETA (c);
+       }
+      else if (c == ESC)
+       {
+         *r++ = '\\';
+         c = 'e';
+       }
+      else if (CTRL_CHAR (c))
+       {
+         *r++ = '\\';
+         *r++ = 'C';
+         *r++ = '-';
+         c = _rl_to_lower (UNCTRL (c));
+       }
+      else if (c == RUBOUT)
+       {
+         *r++ = '\\';
+         *r++ = 'C';
+         *r++ = '-';
+         c = '?';
+       }
+
+      if (c == ESC)
+       {
+         *r++ = '\\';
+         c = 'e';
+       }
+      else if (c == '\\' || c == '"')
+       *r++ = '\\';
+
+      *r++ = (unsigned char)c;
+    }
+  *r = '\0';
+  return ret;
+}
+
 /* 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_command_func_t *
 rl_named_function (string)
-     char *string;
+     const char *string;
 {
   register int i;
 
   rl_initialize_funmap ();
 
   for (i = 0; funmap[i]; i++)
-    if (stricmp (funmap[i]->name, string) == 0)
+    if (_rl_stricmp (funmap[i]->name, string) == 0)
       return (funmap[i]->function);
-  return ((Function *)NULL);
+  return ((rl_command_func_t *)NULL);
 }
 
 /* Return the function (or macro) definition which would be invoked via
@@ -344,42 +692,44 @@ rl_named_function (string)
    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_command_func_t *
 rl_function_of_keyseq (keyseq, map, type)
-     char *keyseq;
+     const char *keyseq;
      Keymap map;
      int *type;
 {
   register int i;
 
-  if (!map)
+  if (map == 0)
     map = _rl_keymap;
 
   for (i = 0; keyseq && keyseq[i]; i++)
     {
-      int ic = keyseq[i];
+      unsigned char ic = keyseq[i];
 
       if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
        {
-         if (map[ESC].type != ISKMAP)
+         if (map[ESC].type == ISKMAP)
+           {
+             map = FUNCTION_TO_KEYMAP (map, ESC);
+             ic = UNMETA (ic);
+           }
+         /* XXX - should we just return NULL here, since this obviously
+            doesn't match? */
+         else
            {
              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 (keyseq[i + 1] == '\0')
            {
              if (type)
                *type = ISKMAP;
@@ -387,9 +737,14 @@ rl_function_of_keyseq (keyseq, map, type)
              return (map[ic].function);
            }
          else
-           map = (Keymap)map[ic].function;
+           map = FUNCTION_TO_KEYMAP (map, ic);
        }
-      else
+      /* If we're not at the end of the key sequence, and the current key
+        is bound to something other than a keymap, then the entire key
+        sequence is not bound. */
+      else if (map[ic].type != ISKMAP && keyseq[i+1])
+       return ((rl_command_func_t *)NULL);
+      else     /* map[ic].type != ISKMAP && keyseq[i+1] == 0 */
        {
          if (type)
            *type = map[ic].type;
@@ -397,112 +752,216 @@ rl_function_of_keyseq (keyseq, map, type)
          return (map[ic].function);
        }
     }
+  return ((rl_command_func_t *) NULL);
 }
 
 /* The last key bindings file read. */
 static char *last_readline_init_file = (char *)NULL;
 
+/* The file we're currently reading key bindings from. */
+static const char *current_readline_init_file;
+static int current_readline_init_include_level;
+static int current_readline_init_lineno;
+
+/* Read FILENAME into a locally-allocated buffer and return the buffer.
+   The size of the buffer is returned in *SIZEP.  Returns NULL if any
+   errors were encountered. */
+static char *
+_rl_read_file (filename, sizep)
+     char *filename;
+     size_t *sizep;
+{
+  struct stat finfo;
+  size_t file_size;
+  char *buffer;
+  int i, file;
+
+  if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0)
+    return ((char *)NULL);
+
+  file_size = (size_t)finfo.st_size;
+
+  /* check for overflow on very large files */
+  if (file_size != finfo.st_size || file_size + 1 < file_size)
+    {
+      if (file >= 0)
+       close (file);
+#if defined (EFBIG)
+      errno = EFBIG;
+#endif
+      return ((char *)NULL);
+    }
+
+  /* Read the file into BUFFER. */
+  buffer = (char *)xmalloc (file_size + 1);
+  i = read (file, buffer, file_size);
+  close (file);
+
+  if (i < 0)
+    {
+      xfree (buffer);
+      return ((char *)NULL);
+    }
+
+  RL_CHECK_SIGNALS ();
+
+  buffer[i] = '\0';
+  if (sizep)
+    *sizep = i;
+
+  return (buffer);
+}
+
 /* Re-read the current keybindings file. */
+int
 rl_re_read_init_file (count, ignore)
      int count, ignore;
 {
-  rl_read_init_file ((char *)NULL);
+  int r;
+  r = rl_read_init_file ((const char *)NULL);
+  rl_set_keymap_from_edit_mode ();
+  return r;
 }
 
-/* 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. */
+   to the first non-null filename from this list:
+     1. the filename used for the previous call
+     2. the value of the shell variable `INPUTRC'
+     3. ~/.inputrc
+     4. /etc/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;
+     const char *filename;
 {
-  register int i;
-  char *buffer, *openname, *line, *end;
-  struct stat finfo;
-  int file;
-
   /* Default the filename. */
-  if (!filename)
+  if (filename == 0)
+    filename = last_readline_init_file;
+  if (filename == 0)
+    filename = sh_get_env_value ("INPUTRC");
+  if (filename == 0 || *filename == 0)
     {
-      if (last_readline_init_file)
-       filename = last_readline_init_file;
-      else
-       filename = DEFAULT_INPUTRC;
+      filename = DEFAULT_INPUTRC;
+      /* Try to read DEFAULT_INPUTRC; fall back to SYS_INPUTRC on failure */
+      if (_rl_read_init_file (filename, 0) == 0)
+       return 0;
+      filename = SYS_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 defined (__MSDOS__)
+  if (_rl_read_init_file (filename, 0) == 0)
+    return 0;
+  filename = "~/_inputrc";
+#endif
+  return (_rl_read_init_file (filename, 0));
+}
 
-  if (last_readline_init_file)
-    free (last_readline_init_file);
+static int
+_rl_read_init_file (filename, include_level)
+     const char *filename;
+     int include_level;
+{
+  register int i;
+  char *buffer, *openname, *line, *end;
+  size_t file_size;
 
-  last_readline_init_file = savestring (filename);
+  current_readline_init_file = filename;
+  current_readline_init_include_level = include_level;
 
-  /* Read the file into BUFFER. */
-  buffer = (char *)xmalloc ((int)finfo.st_size + 1);
-  i = read (file, buffer, finfo.st_size);
-  close (file);
+  openname = tilde_expand (filename);
+  buffer = _rl_read_file (openname, &file_size);
+  xfree (openname);
 
-  if (i != finfo.st_size)
+  RL_CHECK_SIGNALS ();
+  if (buffer == 0)
     return (errno);
+  
+  if (include_level == 0 && filename != last_readline_init_file)
+    {
+      FREE (last_readline_init_file);
+      last_readline_init_file = savestring (filename);
+    }
+
+  currently_reading_init_file = 1;
 
   /* Loop over the lines in the file.  Lines that start with `#' are
      comments; all other lines are commands for readline initialization. */
+  current_readline_init_lineno = 1;
   line = buffer;
-  end = buffer + finfo.st_size;
+  end = buffer + file_size;
   while (line < end)
     {
       /* Find the end of this line. */
       for (i = 0; line + i != end && line[i] != '\n'; i++);
 
+#if defined (__CYGWIN__)
+      /* ``Be liberal in what you accept.'' */
+      if (line[i] == '\n' && line[i-1] == '\r')
+       line[i - 1] = '\0';
+#endif
+
       /* Mark end of line. */
       line[i] = '\0';
 
+      /* Skip leading whitespace. */
+      while (*line && whitespace (*line))
+        {
+         line++;
+         i--;
+        }
+
       /* 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;
+      current_readline_init_lineno++;
     }
-  free (buffer);
+
+  xfree (buffer);
+  currently_reading_init_file = 0;
   return (0);
 }
 
+static void
+_rl_init_file_error (msg)
+     const char *msg;
+{
+  if (currently_reading_init_file)
+    _rl_errmsg ("%s: line %d: %s\n", current_readline_init_file,
+                    current_readline_init_lineno, msg);
+  else
+    _rl_errmsg ("%s", msg);
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Parser Directives                           */
 /*                                                                 */
 /* **************************************************************** */
 
+typedef int _rl_parser_func_t PARAMS((char *));
+
+/* Things that mean `Control'. */
+const char * const _rl_possible_control_prefixes[] = {
+  "Control-", "C-", "CTRL-", (const char *)NULL
+};
+
+const char * const _rl_possible_meta_prefixes[] = {
+  "Meta", "M-", (const char *)NULL
+};
+
 /* Conditionals. */
 
 /* Calling programs set this to have their argv[0]. */
-char *rl_readline_name = "other";
+const 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;
+static int if_stack_depth;
+static int if_stack_size;
 
 /* Push _rl_parsing_conditionalized_out, and set parser state based
    on ARGS. */
@@ -533,16 +992,16 @@ parser_if (args)
   if (args[i])
     args[i++] = '\0';
 
-  /* Handle "if term=foo" and "if mode=emacs" constructs.  If this
+  /* 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)
+  if (rl_terminal_name && _rl_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, '-');
+      tem = strchr (tname, '-');
       if (tem)
        *tem = '\0';
 
@@ -550,35 +1009,28 @@ parser_if (args)
         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);
+      _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) &&
+                                       _rl_stricmp (args + 5, rl_terminal_name);
+      xfree (tname);
     }
 #if defined (VI_MODE)
-  else if (strnicmp (args, "mode=", 5) == 0)
+  else if (_rl_strnicmp (args, "mode=", 5) == 0)
     {
       int mode;
 
-      if (stricmp (args + 5, "emacs") == 0)
+      if (_rl_stricmp (args + 5, "emacs") == 0)
        mode = emacs_mode;
-      else if (stricmp (args + 5, "vi") == 0)
+      else if (_rl_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;
+      _rl_parsing_conditionalized_out = mode != rl_editing_mode;
     }
 #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)
+  else if (_rl_stricmp (args, rl_readline_name) == 0)
     _rl_parsing_conditionalized_out = 0;
   else
     _rl_parsing_conditionalized_out = 1;
@@ -592,15 +1044,21 @@ parser_else (args)
 {
   register int i;
 
-  if (!if_stack_depth)
+  if (if_stack_depth == 0)
     {
-      /* Error message? */
+      _rl_init_file_error ("$else found without matching $if");
       return 0;
     }
 
+#if 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++)
+#else
+  /* Check the previous (n) levels of the stack to make sure that
+     we haven't previously turned off parsing. */
+  for (i = 0; i < if_stack_depth; i++)
+#endif
     if (if_stack[i] == 1)
       return 0;
 
@@ -618,21 +1076,47 @@ parser_endif (args)
   if (if_stack_depth)
     _rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
   else
-    {
-      /* *** What, no error message? *** */
-    }
+    _rl_init_file_error ("$endif without matching $if");
   return 0;
 }
 
+static int
+parser_include (args)
+     char *args;
+{
+  const char *old_init_file;
+  char *e;
+  int old_line_number, old_include_level, r;
+
+  if (_rl_parsing_conditionalized_out)
+    return (0);
+
+  old_init_file = current_readline_init_file;
+  old_line_number = current_readline_init_lineno;
+  old_include_level = current_readline_init_include_level;
+
+  e = strchr (args, '\n');
+  if (e)
+    *e = '\0';
+  r = _rl_read_init_file ((const char *)args, old_include_level + 1);
+
+  current_readline_init_file = old_init_file;
+  current_readline_init_lineno = old_line_number;
+  current_readline_init_include_level = old_include_level;
+
+  return r;
+}
+  
 /* Associate textual names with actual functions. */
-static struct {
-  char *name;
-  Function *function;
+static const struct {
+  const char * const name;
+  _rl_parser_func_t *function;
 } parser_directives [] = {
   { "if", parser_if },
   { "endif", parser_endif },
   { "else", parser_else },
-  { (char *)0x0, (Function *)0x0 }
+  { "include", parser_include },
+  { (char *)0x0, (_rl_parser_func_t *)0x0 }
 };
 
 /* Handle a parser directive.  STATEMENT is the line of the directive
@@ -662,25 +1146,22 @@ handle_parser_directive (statement)
 
   /* Lookup the command, and act on it. */
   for (i = 0; parser_directives[i].name; i++)
-    if (stricmp (directive, parser_directives[i].name) == 0)
+    if (_rl_stricmp (directive, parser_directives[i].name) == 0)
       {
        (*parser_directives[i].function) (args);
        return (0);
       }
 
-  /* *** Should an error message be output? */
+  /* display an error message about the unknown parser directive */
+  _rl_init_file_error ("unknown parser directive");
   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. */
+int
 rl_parse_and_bind (string)
      char *string;
 {
@@ -692,18 +1173,18 @@ rl_parse_and_bind (string)
     string++;
 
   if (!string || !*string || *string == '#')
-    return;
+    return 0;
 
   /* If this is a parser directive, act on it. */
   if (*string == '$')
     {
       handle_parser_directive (&string[1]);
-      return;
+      return 0;
     }
 
   /* If we aren't supposed to be parsing right now, then we're done. */
   if (_rl_parsing_conditionalized_out)
-    return;
+    return 0;
 
   i = 0;
   /* If this keyname is a complex key expression surrounded by quotes,
@@ -730,6 +1211,12 @@ rl_parse_and_bind (string)
          if (c == '"')
            break;
        }
+      /* If we didn't find a closing quote, abort the line. */
+      if (string[i] == '\0')
+        {
+          _rl_init_file_error ("no closing `\"' in key binding");
+          return 1;
+        }
     }
 
   /* Advance to the colon (:) or whitespace which separates the two objects. */
@@ -746,23 +1233,37 @@ rl_parse_and_bind (string)
     string[i++] = '\0';
 
   /* If this is a command to set a variable, then do that. */
-  if (stricmp (string, "set") == 0)
+  if (_rl_stricmp (string, "set") == 0)
     {
-      char *var = string + i;
-      char *value;
+      char *var, *value, *e;
 
+      var = string + i;
       /* Make VAR point to start of variable name. */
       while (*var && whitespace (*var)) var++;
 
-      /* Make value point to start of value string. */
+      /* Make VALUE point to start of value string. */
       value = var;
       while (*value && !whitespace (*value)) value++;
       if (*value)
        *value++ = '\0';
       while (*value && whitespace (*value)) value++;
 
+      /* Strip trailing whitespace from values to boolean variables.  Temp
+        fix until I get a real quoted-string parser here. */
+      i = find_boolean_var (var);
+      if (i >= 0)
+       {
+         /* remove trailing whitespace */
+         e = value + strlen (value) - 1;
+         while (e >= value && whitespace (*e))
+           e--;
+         e++;          /* skip back to whitespace or EOS */
+         if (*e && e >= value)
+           *e = '\0';
+       }
+
       rl_variable_bind (var, value);
-      return;
+      return 0;
     }
 
   /* Skip any whitespace between keyname and funname. */
@@ -781,10 +1282,10 @@ rl_parse_and_bind (string)
      the quoted string delimiter, like the shell. */
   if (*funname == '\'' || *funname == '"')
     {
-      int delimiter = string[i++];
-      int passc = 0;
+      int delimiter, passc;
 
-      for (; c = string[i]; i++)
+      delimiter = string[i++];
+      for (passc = 0; c = string[i]; i++)
        {
          if (passc)
            {
@@ -815,18 +1316,18 @@ rl_parse_and_bind (string)
      whatever the right-hand evaluates to, including keymaps. */
   if (equivalency)
     {
-      return;
+      return 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. */
+     rl_bind_keyseq ().  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;
+      char *seq;
+      register int j, k, passc;
 
-      for (j = 1; string[j]; j++)
+      seq = (char *)xmalloc (1 + strlen (string));
+      for (j = 1, k = passc = 0; string[j]; j++)
        {
          /* Allow backslash to quote characters, but leave them in place.
             This allows a string to end with a backslash quoting another
@@ -858,13 +1359,14 @@ rl_parse_and_bind (string)
          rl_macro_bind (seq, &funname[1], _rl_keymap);
        }
       else
-       rl_set_key (seq, rl_named_function (funname), _rl_keymap);
+       rl_bind_keyseq (seq, rl_named_function (funname));
 
-      return;
+      xfree (seq);
+      return 0;
     }
 
   /* Get the actual character we want to deal with. */
-  kname = (char*) strrchr (string, '-');
+  kname = strrchr (string, '-');
   if (!kname)
     kname = string;
   else
@@ -873,27 +1375,27 @@ rl_parse_and_bind (string)
   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, _rl_possible_control_prefixes))
+    key = CTRL (_rl_to_upper (key));
 
-  if (substring_member_of_array (string, possible_meta_prefixes))
+  if (substring_member_of_array (string, _rl_possible_meta_prefixes))
     key = META (key);
 
   /* Temporary.  Handle old-style keyname with macro-binding. */
   if (*funname == '\'' || *funname == '"')
     {
-      char seq[2];
+      char useq[2];
       int fl = strlen (funname);
 
-      seq[0] = key; seq[1] = '\0';
+      useq[0] = key; useq[1] = '\0';
       if (fl && funname[fl - 1] == *funname)
        funname[fl - 1] = '\0';
 
-      rl_macro_bind (seq, &funname[1], _rl_keymap);
+      rl_macro_bind (useq, &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)
+  else if (_rl_stricmp (funname, "prefix-meta") == 0)
     {
       char seq[2];
 
@@ -904,112 +1406,372 @@ rl_parse_and_bind (string)
 #endif /* PREFIX_META_HACK */
   else
     rl_bind_key (key, rl_named_function (funname));
+  return 0;
 }
 
 /* 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;
+#define V_SPECIAL      0x1
+
+static const struct {
+  const char * const name;
   int *value;
+  int flags;
 } 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 },
+  { "bind-tty-special-chars",  &_rl_bind_stty_chars,           0 },
+  { "blink-matching-paren",    &rl_blink_matching_paren,       V_SPECIAL },
+  { "byte-oriented",           &rl_byte_oriented,              0 },
+  { "completion-ignore-case",  &_rl_completion_case_fold,      0 },
+  { "completion-map-case",     &_rl_completion_case_map,       0 },
+  { "convert-meta",            &_rl_convert_meta_chars_to_ascii, 0 },
+  { "disable-completion",      &rl_inhibit_completion,         0 },
+  { "echo-control-characters", &_rl_echo_control_chars,        0 },
+  { "enable-keypad",           &_rl_enable_keypad,             0 },
+  { "enable-meta-key",         &_rl_enable_meta,               0 },
+  { "expand-tilde",            &rl_complete_with_tilde_expansion, 0 },
+  { "history-preserve-point",  &_rl_history_preserve_point,    0 },
+  { "horizontal-scroll-mode",  &_rl_horizontal_scroll_mode,    0 },
+  { "input-meta",              &_rl_meta_flag,                 0 },
+  { "mark-directories",                &_rl_complete_mark_directories, 0 },
+  { "mark-modified-lines",     &_rl_mark_modified_lines,       0 },
+  { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 },
+  { "match-hidden-files",      &_rl_match_hidden_files,        0 },
+  { "menu-complete-display-prefix", &_rl_menu_complete_prefix_first, 0 },
+  { "meta-flag",               &_rl_meta_flag,                 0 },
+  { "output-meta",             &_rl_output_meta_chars,         0 },
+  { "page-completions",                &_rl_page_completions,          0 },
+  { "prefer-visible-bell",     &_rl_prefer_visible_bell,       V_SPECIAL },
+  { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 },
+  { "revert-all-at-newline",   &_rl_revert_all_at_newline,     0 },
+  { "show-all-if-ambiguous",   &_rl_complete_show_all,         0 },
+  { "show-all-if-unmodified",  &_rl_complete_show_unmodified,  0 },
+  { "skip-completed-text",     &_rl_skip_completed_text,       0 },
 #if defined (VISIBLE_STATS)
-  { "visible-stats",           &rl_visible_stats },
+  { "visible-stats",           &rl_visible_stats,              0 },
 #endif /* VISIBLE_STATS */
-  { "expand-tilde",            &rl_complete_with_tilde_expansion },
-  { (char *)NULL, (int *)NULL }
+  { (char *)NULL, (int *)NULL, 0 }
 };
 
-rl_variable_bind (name, value)
-     char *name, *value;
+static int
+find_boolean_var (name)
+     const char *name;
 {
   register int i;
 
-  /* Check for simple variables first. */
   for (i = 0; boolean_varlist[i].name; i++)
+    if (_rl_stricmp (name, boolean_varlist[i].name) == 0)
+      return i;
+  return -1;
+}
+
+/* Hooks for handling special boolean variables, where a
+   function needs to be called or another variable needs
+   to be changed when they're changed. */
+static void
+hack_special_boolean_var (i)
+     int i;
+{
+  const char *name;
+
+  name = boolean_varlist[i].name;
+
+  if (_rl_stricmp (name, "blink-matching-paren") == 0)
+    _rl_enable_paren_matching (rl_blink_matching_paren);
+  else if (_rl_stricmp (name, "prefer-visible-bell") == 0)
     {
-      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;
-       }
+      if (_rl_prefer_visible_bell)
+       _rl_bell_preference = VISIBLE_BELL;
+      else
+       _rl_bell_preference = AUDIBLE_BELL;
     }
+}
+
+typedef int _rl_sv_func_t PARAMS((const char *));
+
+/* These *must* correspond to the array indices for the appropriate
+   string variable.  (Though they're not used right now.) */
+#define V_BELLSTYLE    0
+#define V_COMBEGIN     1
+#define V_EDITMODE     2
+#define V_ISRCHTERM    3
+#define V_KEYMAP       4
+
+#define        V_STRING        1
+#define V_INT          2
+
+/* Forward declarations */
+static int sv_bell_style PARAMS((const char *));
+static int sv_combegin PARAMS((const char *));
+static int sv_dispprefix PARAMS((const char *));
+static int sv_compquery PARAMS((const char *));
+static int sv_compwidth PARAMS((const char *));
+static int sv_editmode PARAMS((const char *));
+static int sv_histsize PARAMS((const char *));
+static int sv_isrchterm PARAMS((const char *));
+static int sv_keymap PARAMS((const char *));
+
+static const struct {
+  const char * const name;
+  int flags;
+  _rl_sv_func_t *set_func;
+} string_varlist[] = {
+  { "bell-style",      V_STRING,       sv_bell_style },
+  { "comment-begin",   V_STRING,       sv_combegin },
+  { "completion-display-width", V_INT, sv_compwidth },
+  { "completion-prefix-display-length", V_INT, sv_dispprefix },
+  { "completion-query-items", V_INT,   sv_compquery },
+  { "editing-mode",    V_STRING,       sv_editmode },
+  { "history-size",    V_INT,          sv_histsize },
+  { "isearch-terminators", V_STRING,   sv_isrchterm },
+  { "keymap",          V_STRING,       sv_keymap },
+  { (char *)NULL,      0, (_rl_sv_func_t *)0 }
+};
+
+static int
+find_string_var (name)
+     const char *name;
+{
+  register int i;
+
+  for (i = 0; string_varlist[i].name; i++)
+    if (_rl_stricmp (name, string_varlist[i].name) == 0)
+      return i;
+  return -1;
+}
 
-  /* Not a boolean variable, so check for specials. */
+/* A boolean value that can appear in a `set variable' command is true if
+   the value is null or empty, `on' (case-insenstive), or "1".  Any other
+   values result in 0 (false). */
+static int
+bool_to_int (value)
+     const char *value;
+{
+  return (value == 0 || *value == '\0' ||
+               (_rl_stricmp (value, "on") == 0) ||
+               (value[0] == '1' && value[1] == '\0'));
+}
+
+char *
+rl_variable_value (name)
+     const char *name;
+{
+  register int i;
+
+  /* Check for simple variables first. */
+  i = find_boolean_var (name);
+  if (i >= 0)
+    return (*boolean_varlist[i].value ? "on" : "off");
 
-  /* Editing mode change? */
-  if (stricmp (name, "editing-mode") == 0)
+  i = find_string_var (name);
+  if (i >= 0)
+    return (_rl_get_string_variable_value (string_varlist[i].name));
+
+  /* Unknown variable names return NULL. */
+  return 0;
+}
+
+int
+rl_variable_bind (name, value)
+     const char *name, *value;
+{
+  register int i;
+  int  v;
+
+  /* Check for simple variables first. */
+  i = find_boolean_var (name);
+  if (i >= 0)
+    {
+      *boolean_varlist[i].value = bool_to_int (value);
+      if (boolean_varlist[i].flags & V_SPECIAL)
+       hack_special_boolean_var (i);
+      return 0;
+    }
+
+  i = find_string_var (name);
+
+  /* For the time being, unknown variable names or string names without a
+     handler function are simply ignored. */
+  if (i < 0 || string_varlist[i].set_func == 0)
+    return 0;
+
+  v = (*string_varlist[i].set_func) (value);
+  return v;
+}
+
+static int
+sv_editmode (value)
+     const char *value;
+{
+  if (_rl_strnicmp (value, "vi", 2) == 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 */
+      _rl_keymap = vi_insertion_keymap;
+      rl_editing_mode = vi_mode;
 #endif /* VI_MODE */
-       }
-      else if (strnicmp (value, "emacs", 5) == 0)
-       {
-         _rl_keymap = emacs_standard_keymap;
-         rl_editing_mode = emacs_mode;
-       }
+      return 0;
+    }
+  else if (_rl_strnicmp (value, "emacs", 5) == 0)
+    {
+      _rl_keymap = emacs_standard_keymap;
+      rl_editing_mode = emacs_mode;
+      return 0;
     }
+  return 1;
+}
 
-  /* Comment string change? */
-  else if (stricmp (name, "comment-begin") == 0)
+static int
+sv_combegin (value)
+     const char *value;
+{
+  if (value && *value)
     {
-#if defined (VI_MODE)
-      extern char *rl_vi_comment_begin;
+      FREE (_rl_comment_begin);
+      _rl_comment_begin = savestring (value);
+      return 0;
+    }
+  return 1;
+}
 
-      if (*value)
-       {
-         if (rl_vi_comment_begin)
-           free (rl_vi_comment_begin);
+static int
+sv_dispprefix (value)
+     const char *value;
+{
+  int nval = 0;
 
-         rl_vi_comment_begin = savestring (value);
-       }
-#endif /* VI_MODE */
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       nval = 0;
     }
-  else if (stricmp (name, "completion-query-items") == 0)
+  _rl_completion_prefix_display_length = nval;
+  return 0;
+}
+
+static int
+sv_compquery (value)
+     const char *value;
+{
+  int nval = 100;
+
+  if (value && *value)
     {
-      int nval = 100;
-      if (*value)
-       {
-         nval = atoi (value);
-         if (nval < 0)
-           nval = 0;
-       }
-      rl_completion_query_items = nval;
+      nval = atoi (value);
+      if (nval < 0)
+       nval = 0;
+    }
+  rl_completion_query_items = nval;
+  return 0;
+}
+
+static int
+sv_compwidth (value)
+     const char *value;
+{
+  int nval = -1;
+
+  if (value && *value)
+    nval = atoi (value);
+
+  _rl_completion_columns = nval;
+  return 0;
+}
+
+static int
+sv_histsize (value)
+     const char *value;
+{
+  int nval = 500;
+
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       return 1;
     }
+  stifle_history (nval);
+  return 0;
+}
+
+static int
+sv_keymap (value)
+     const char *value;
+{
+  Keymap kmap;
+
+  kmap = rl_get_keymap_by_name (value);
+  if (kmap)
+    {
+      rl_set_keymap (kmap);
+      return 0;
+    }
+  return 1;
 }
 
+static int
+sv_bell_style (value)
+     const char *value;
+{
+  if (value == 0 || *value == '\0')
+    _rl_bell_preference = AUDIBLE_BELL;
+  else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0)
+    _rl_bell_preference = NO_BELL;
+  else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0)
+    _rl_bell_preference = AUDIBLE_BELL;
+  else if (_rl_stricmp (value, "visible") == 0)
+    _rl_bell_preference = VISIBLE_BELL;
+  else
+    return 1;
+  return 0;
+}
+
+static int
+sv_isrchterm (value)
+     const char *value;
+{
+  int beg, end, delim;
+  char *v;
+
+  if (value == 0)
+    return 1;
+
+  /* Isolate the value and translate it into a character string. */
+  v = savestring (value);
+  FREE (_rl_isearch_terminators);
+  if (v[0] == '"' || v[0] == '\'')
+    {
+      delim = v[0];
+      for (beg = end = 1; v[end] && v[end] != delim; end++)
+       ;
+    }
+  else
+    {
+      for (beg = end = 0; whitespace (v[end]) == 0; end++)
+       ;
+    }
+
+  v[end] = '\0';
+
+  /* The value starts at v + beg.  Translate it into a character string. */
+  _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1);
+  rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end);
+  _rl_isearch_terminators[end] = '\0';
+
+  xfree (v);
+  return 0;
+}
+      
 /* Return the character which matches NAME.
    For example, `Space' returns ' '. */
 
 typedef struct {
-  char *name;
+  const char * const name;
   int value;
 } assoc_list;
 
-static assoc_list name_key_alist[] = {
+static const assoc_list name_key_alist[] = {
   { "DEL", 0x7f },
   { "ESC", '\033' },
   { "Escape", '\033' },
@@ -1031,15 +1793,15 @@ glean_key_from_name (name)
   register int i;
 
   for (i = 0; name_key_alist[i].name; i++)
-    if (stricmp (name, name_key_alist[i].name) == 0)
+    if (_rl_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;
+static const struct {
+  const char * const name;
   Keymap map;
 } keymap_names[] = {
   { "emacs", emacs_standard_keymap },
@@ -1057,16 +1819,27 @@ static struct {
 
 Keymap
 rl_get_keymap_by_name (name)
-     char *name;
+     const char *name;
 {
   register int i;
 
   for (i = 0; keymap_names[i].name; i++)
-    if (strcmp (name, keymap_names[i].name) == 0)
+    if (_rl_stricmp (name, keymap_names[i].name) == 0)
       return (keymap_names[i].map);
   return ((Keymap) NULL);
 }
 
+char *
+rl_get_keymap_name (map)
+     Keymap map;
+{
+  register int i;
+  for (i = 0; keymap_names[i].name; i++)
+    if (map == keymap_names[i].map)
+      return ((char *)keymap_names[i].name);
+  return ((char *)NULL);
+}
+  
 void
 rl_set_keymap (map)
      Keymap map;
@@ -1086,10 +1859,25 @@ rl_set_keymap_from_edit_mode ()
 {
   if (rl_editing_mode == emacs_mode)
     _rl_keymap = emacs_standard_keymap;
+#if defined (VI_MODE)
   else if (rl_editing_mode == vi_mode)
     _rl_keymap = vi_insertion_keymap;
+#endif /* VI_MODE */
 }
-\f
+
+char *
+rl_get_keymap_name_from_edit_mode ()
+{
+  if (rl_editing_mode == emacs_mode)
+    return "emacs";
+#if defined (VI_MODE)
+  else if (rl_editing_mode == vi_mode)
+    return "vi";
+#endif /* VI_MODE */
+  else
+    return "none";
+}
+
 /* **************************************************************** */
 /*                                                                 */
 /*               Key Binding and Function Information              */
@@ -1099,15 +1887,14 @@ rl_set_keymap_from_edit_mode ()
 /* 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 (). */
+   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;
+rl_list_funmap_names ()
 {
   register int i;
-  char **funmap_names;
+  const char **funmap_names;
 
   funmap_names = rl_funmap_names ();
 
@@ -1117,14 +1904,88 @@ rl_list_funmap_names (ignore)
   for (i = 0; funmap_names[i]; i++)
     fprintf (rl_outstream, "%s\n", funmap_names[i]);
 
-  free (funmap_names);
+  xfree (funmap_names);
+}
+
+static char *
+_rl_get_keyname (key)
+     int key;
+{
+  char *keyname;
+  int i, c;
+
+  keyname = (char *)xmalloc (8);
+
+  c = key;
+  /* Since this is going to be used to write out keysequence-function
+     pairs for possible inclusion in an inputrc file, we don't want to
+     do any special meta processing on KEY. */
+
+#if 1
+  /* XXX - Experimental */
+  /* We might want to do this, but the old version of the code did not. */
+
+  /* If this is an escape character, we don't want to do any more processing.
+     Just add the special ESC key sequence and return. */
+  if (c == ESC)
+    {
+      keyname[0] = '\\';
+      keyname[1] = 'e';
+      keyname[2] = '\0';
+      return keyname;
+    }
+#endif
+
+  /* RUBOUT is translated directly into \C-? */
+  if (key == RUBOUT)
+    {
+      keyname[0] = '\\';
+      keyname[1] = 'C';
+      keyname[2] = '-';
+      keyname[3] = '?';
+      keyname[4] = '\0';
+      return keyname;
+    }
+
+  i = 0;
+  /* Now add special prefixes needed for control characters.  This can
+     potentially change C. */
+  if (CTRL_CHAR (c))
+    {
+      keyname[i++] = '\\';
+      keyname[i++] = 'C';
+      keyname[i++] = '-';
+      c = _rl_to_lower (UNCTRL (c));
+    }
+
+  /* XXX experimental code.  Turn the characters that are not ASCII or
+     ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237).
+     This changes C. */
+  if (c >= 128 && c <= 159)
+    {
+      keyname[i++] = '\\';
+      keyname[i++] = '2';
+      c -= 128;
+      keyname[i++] = (c / 8) + '0';
+      c = (c % 8) + '0';
+    }
+
+  /* Now, if the character needs to be quoted with a backslash, do that. */
+  if (c == '\\' || c == '"')
+    keyname[i++] = '\\';
+
+  /* Now add the key, terminate the string, and return it. */
+  keyname[i++] = (char) c;
+  keyname[i] = '\0';
+
+  return keyname;
 }
 
 /* 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;
+char **
+rl_invoking_keyseqs_in_map (function, map)
+     rl_command_func_t *function;
      Keymap map;
 {
   register int key;
@@ -1134,7 +1995,7 @@ invoking_keyseqs_in_map (function, map)
   result = (char **)NULL;
   result_index = result_size = 0;
 
-  for (key = 0; key < 128; key++)
+  for (key = 0; key < KEYMAP_SIZE; key++)
     {
       switch (map[key].type)
        {
@@ -1146,27 +2007,15 @@ invoking_keyseqs_in_map (function, map)
             then add the current KEY to the list of invoking keys. */
          if (map[key].function == function)
            {
-             char *keyname = (char *)xmalloc (5);
+             char *keyname;
 
-             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';
-               }
+             keyname = _rl_get_keyname (key);
 
              if (result_index + 2 > result_size)
-               result = (char **) xrealloc
-                 (result, (result_size += 10) * sizeof (char *));
+               {
+                 result_size += 10;
+                 result = (char **)xrealloc (result, result_size * sizeof (char *));
+               }
 
              result[result_index++] = keyname;
              result[result_index] = (char *)NULL;
@@ -1175,50 +2024,65 @@ invoking_keyseqs_in_map (function, map)
 
        case ISKMAP:
          {
-           char **seqs = (char **)NULL;
+           char **seqs;
+           register int i;
 
            /* 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);
+               rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key));
+           else
+             break;
+
+           if (seqs == 0)
+             break;
 
-           if (seqs)
+           for (i = 0; seqs[i]; i++)
              {
-               register int i;
+               char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
 
-               for (i = 0; seqs[i]; i++)
+               if (key == ESC)
                  {
-                   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';
-                     }
+                   /* If ESC is the meta prefix and we're converting chars
+                      with the eighth bit set to ESC-prefixed sequences, then
+                      we can use \M-.  Otherwise we need to use the sequence
+                      for ESC. */
+                   if (_rl_convert_meta_chars_to_ascii && map[ESC].type == ISKMAP)
+                     sprintf (keyname, "\\M-");
                    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 *));
+                     sprintf (keyname, "\\e");
+                 }
+               else if (CTRL_CHAR (key))
+                 sprintf (keyname, "\\C-%c", _rl_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]);
+               xfree (seqs[i]);
 
-                   result[result_index++] = keyname;
-                   result[result_index] = (char *)NULL;
+               if (result_index + 2 > result_size)
+                 {
+                   result_size += 10;
+                   result = (char **)xrealloc (result, result_size * sizeof (char *));
                  }
+
+               result[result_index++] = keyname;
+               result[result_index] = (char *)NULL;
              }
+
+           xfree (seqs);
          }
          break;
        }
@@ -1230,23 +2094,9 @@ invoking_keyseqs_in_map (function, map)
    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;
+     rl_command_func_t *function;
 {
-  void rl_function_dumper ();
-
-  rl_function_dumper (rl_explicit_arg);
-  rl_on_new_line ();
-  return (0);
+  return (rl_invoking_keyseqs_in_map (function, _rl_keymap));
 }
 
 /* Print all of the functions and their bindings to rl_outstream.  If
@@ -1257,8 +2107,8 @@ rl_function_dumper (print_readably)
      int print_readably;
 {
   register int i;
-  char **names;
-  char *name;
+  const char **names;
+  const char *name;
 
   names = rl_funmap_names ();
 
@@ -1266,11 +2116,11 @@ rl_function_dumper (print_readably)
 
   for (i = 0; name = names[i]; i++)
     {
-      Function *function;
+      rl_command_func_t *function;
       char **invokers;
 
       function = rl_named_function (name);
-      invokers = invoking_keyseqs_in_map (function, _rl_keymap);
+      invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap);
 
       if (print_readably)
        {
@@ -1284,10 +2134,10 @@ rl_function_dumper (print_readably)
                {
                  fprintf (rl_outstream, "\"%s\": %s\n",
                           invokers[j], name);
-                 free (invokers[j]);
+                 xfree (invokers[j]);
                }
 
-             free (invokers);
+             xfree (invokers);
            }
        }
       else
@@ -1311,86 +2161,233 @@ rl_function_dumper (print_readably)
                fprintf (rl_outstream, "...\n");
 
              for (j = 0; invokers[j]; j++)
-               free (invokers[j]);
+               xfree (invokers[j]);
 
-             free (invokers);
+             xfree (invokers);
            }
        }
     }
+  free (names);
 }
 
-\f
-/* **************************************************************** */
-/*                                                                 */
-/*                     String Utility Functions                    */
-/*                                                                 */
-/* **************************************************************** */
-
-static char *strindex ();
+/* 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, key)
+     int count, key;
+{
+  if (rl_dispatching)
+    fprintf (rl_outstream, "\r\n");
+  rl_function_dumper (rl_explicit_arg);
+  rl_on_new_line ();
+  return (0);
+}
 
-/* Return non-zero if any members of ARRAY are a substring in STRING. */
-static int
-substring_member_of_array (string, array)
-     char *string, **array;
+static void
+_rl_macro_dumper_internal (print_readably, map, prefix)
+     int print_readably;
+     Keymap map;
+     char *prefix;
 {
-  while (*array)
+  register int key;
+  char *keyname, *out;
+  int prefix_len;
+
+  for (key = 0; key < KEYMAP_SIZE; key++)
     {
-      if (strindex (string, *array))
-       return (1);
-      array++;
+      switch (map[key].type)
+       {
+       case ISMACR:
+         keyname = _rl_get_keyname (key);
+         out = _rl_untranslate_macro_value ((char *)map[key].function);
+
+         if (print_readably)
+           fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
+                                                        keyname,
+                                                        out ? out : "");
+         else
+           fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",
+                                                       keyname,
+                                                       out ? out : "");
+         xfree (keyname);
+         xfree (out);
+         break;
+       case ISFUNC:
+         break;
+       case ISKMAP:
+         prefix_len = prefix ? strlen (prefix) : 0;
+         if (key == ESC)
+           {
+             keyname = (char *)xmalloc (3 + prefix_len);
+             if (prefix)
+               strcpy (keyname, prefix);
+             keyname[prefix_len] = '\\';
+             keyname[prefix_len + 1] = 'e';
+             keyname[prefix_len + 2] = '\0';
+           }
+         else
+           {
+             keyname = _rl_get_keyname (key);
+             if (prefix)
+               {
+                 out = (char *)xmalloc (strlen (keyname) + prefix_len + 1);
+                 strcpy (out, prefix);
+                 strcpy (out + prefix_len, keyname);
+                 xfree (keyname);
+                 keyname = out;
+               }
+           }
+
+         _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname);
+         xfree (keyname);
+         break;
+       }
     }
-  return (0);
 }
 
-/* Whoops, Unix doesn't have strnicmp. */
+void
+rl_macro_dumper (print_readably)
+     int print_readably;
+{
+  _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL);
+}
+
+int
+rl_dump_macros (count, key)
+     int count, key;
+{
+  if (rl_dispatching)
+    fprintf (rl_outstream, "\r\n");
+  rl_macro_dumper (rl_explicit_arg);
+  rl_on_new_line ();
+  return (0);
+}
 
-/* Compare at most COUNT characters from string1 to string2.  Case
-   doesn't matter. */
-static int
-strnicmp (string1, string2, count)
-     char *string1, *string2;
+static char *
+_rl_get_string_variable_value (name)
+     const char *name;
 {
-  register char ch1, ch2;
+  static char numbuf[32];
+  char *ret;
 
-  while (count)
+  if (_rl_stricmp (name, "bell-style") == 0)
     {
-      ch1 = *string1++;
-      ch2 = *string2++;
-      if (to_upper(ch1) == to_upper(ch2))
-       count--;
-      else break;
+      switch (_rl_bell_preference)
+       {
+         case NO_BELL:
+           return "none";
+         case VISIBLE_BELL:
+           return "visible";
+         case AUDIBLE_BELL:
+         default:
+           return "audible";
+       }
     }
-  return (count);
+  else if (_rl_stricmp (name, "comment-begin") == 0)
+    return (_rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT);
+  else if (_rl_stricmp (name, "completion-display-width") == 0)
+    {
+      sprintf (numbuf, "%d", _rl_completion_columns);
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "completion-prefix-display-length") == 0)
+    {
+      sprintf (numbuf, "%d", _rl_completion_prefix_display_length);
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "completion-query-items") == 0)
+    {
+      sprintf (numbuf, "%d", rl_completion_query_items);
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "editing-mode") == 0)
+    return (rl_get_keymap_name_from_edit_mode ());
+  else if (_rl_stricmp (name, "history-size") == 0)
+    {
+      sprintf (numbuf, "%d", history_is_stifled() ? history_max_entries : 0);
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "isearch-terminators") == 0)
+    {
+      if (_rl_isearch_terminators == 0)
+       return 0;
+      ret = _rl_untranslate_macro_value (_rl_isearch_terminators);
+      if (ret)
+       {
+         strncpy (numbuf, ret, sizeof (numbuf) - 1);
+         xfree (ret);
+         numbuf[sizeof(numbuf) - 1] = '\0';
+       }
+      else
+       numbuf[0] = '\0';
+      return numbuf;
+    }
+  else if (_rl_stricmp (name, "keymap") == 0)
+    {
+      ret = rl_get_keymap_name (_rl_keymap);
+      if (ret == 0)
+       ret = rl_get_keymap_name_from_edit_mode ();
+      return (ret ? ret : "none");
+    }
+  else
+    return (0);
 }
 
-/* strcmp (), but caseless. */
-static int
-stricmp (string1, string2)
-     char *string1, *string2;
+void
+rl_variable_dumper (print_readably)
+     int print_readably;
 {
-  register char ch1, ch2;
+  int i;
+  char *v;
 
-  while (*string1 && *string2)
+  for (i = 0; boolean_varlist[i].name; i++)
     {
-      ch1 = *string1++;
-      ch2 = *string2++;
-      if (to_upper(ch1) != to_upper(ch2))
-       return (1);
+      if (print_readably)
+        fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name,
+                              *boolean_varlist[i].value ? "on" : "off");
+      else
+        fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name,
+                              *boolean_varlist[i].value ? "on" : "off");
+    }
+
+  for (i = 0; string_varlist[i].name; i++)
+    {
+      v = _rl_get_string_variable_value (string_varlist[i].name);
+      if (v == 0)      /* _rl_isearch_terminators can be NULL */
+       continue;
+      if (print_readably)
+        fprintf (rl_outstream, "set %s %s\n", string_varlist[i].name, v);
+      else
+        fprintf (rl_outstream, "%s is set to `%s'\n", string_varlist[i].name, v);
     }
-  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;
+/* Print all of the current variables and their values 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_variables (count, key)
+     int count, key;
 {
-  register int i, l = strlen (s2);
-  register int len = strlen (s1);
+  if (rl_dispatching)
+    fprintf (rl_outstream, "\r\n");
+  rl_variable_dumper (rl_explicit_arg);
+  rl_on_new_line ();
+  return (0);
+}
 
-  for (i = 0; (len - i) >= l; i++)
-    if (strnicmp (&s1[i], s2, l) == 0)
-      return (s1 + i);
-  return ((char *)NULL);
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+     const char *string;
+     const char * const *array;
+{
+  while (*array)
+    {
+      if (_rl_strindex (string, *array))
+       return (1);
+      array++;
+    }
+  return (0);
 }