Release 2.33.1
[external/binutils.git] / readline / bind.c
index 6a6424e..57ae10f 100644 (file)
@@ -1,26 +1,30 @@
 /* bind.c -- key binding and startup file support for the readline library. */
 
-/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2017 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 2, 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,
-   59 Temple Place, Suite 330, Boston, MA 02111 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
@@ -68,29 +72,58 @@ extern char *strchr (), *strrchr ();
 /* Variables exported by this file. */
 Keymap rl_binding_keymap;
 
-static int _rl_read_init_file __P((char *, int));
-static int glean_key_from_name __P((char *));
-static int substring_member_of_array __P((char *, char **));
+static int _rl_skip_to_delim PARAMS((char *, int, int));
+
+#if defined (USE_VARARGS) && defined (PREFER_STDARG)
+static void _rl_init_file_error (const char *, ...)  __attribute__((__format__ (printf, 1, 2)));
+#else
+static void _rl_init_file_error ();
+#endif
+
+static rl_command_func_t *_rl_function_of_keyseq_internal PARAMS((const char *, size_t, Keymap, int *));
+
+static char *_rl_read_file PARAMS((char *, size_t *));
+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 *));
+static int find_string_var PARAMS((const char *));
+
+static const char *boolean_varname PARAMS((int));
+static const char *string_varname PARAMS((int));
+
+static char *_rl_get_string_variable_value PARAMS((const char *));
+static int substring_member_of_array PARAMS((const char *, const char * const *));
+
+static int _rl_get_keymap_by_name PARAMS((const char *));
+static int _rl_get_keymap_by_map PARAMS((Keymap));
 
 static int currently_reading_init_file;
 
 /* used only in this file */
 static int _rl_prefer_visible_bell = 1;
 
+#define OP_EQ  1
+#define OP_NE  2
+#define OP_GT  3
+#define OP_GE  4
+#define OP_LT  5
+#define OP_LE  6
+
+#define OPSTART(c)     ((c) == '=' || (c) == '!' || (c) == '<' || (c) == '>')
+#define CMPSTART(c)    ((c) == '=' || (c) == '!')
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     Binding keys                                */
 /*                                                                 */
 /* **************************************************************** */
 
-/* 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;
-     int key;
+rl_add_defun (const char *name, rl_command_func_t *function, int key)
 {
   if (key != -1)
     rl_bind_key (key, function);
@@ -100,10 +133,11 @@ rl_add_defun (name, function, key)
 
 /* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
 int
-rl_bind_key (key, function)
-     int key;
-     Function *function;
+rl_bind_key (int key, rl_command_func_t *function)
 {
+  char keyseq[3];
+  int l;
+
   if (key < 0)
     return (key);
 
@@ -122,8 +156,24 @@ rl_bind_key (key, function)
       return (key);
     }
 
-  _rl_keymap[key].type = ISFUNC;
-  _rl_keymap[key].function = function;
+  /* If it's bound to a function or macro, just overwrite.  Otherwise we have
+     to treat it as a key sequence so rl_generic_bind handles shadow keymaps
+     for us.  If we are binding '\' make sure to escape it so it makes it
+     through the call to rl_translate_keyseq. */
+  if (_rl_keymap[key].type != ISKMAP)
+    {
+      _rl_keymap[key].type = ISFUNC;
+      _rl_keymap[key].function = function;
+    }
+  else
+    {
+      l = 0;
+      if (key == '\\')
+       keyseq[l++] = '\\';
+      keyseq[l++] = key;
+      keyseq[l] = '\0';
+      rl_bind_keyseq (keyseq, function);
+    }
   rl_binding_keymap = _rl_keymap;
   return (0);
 }
@@ -131,10 +181,7 @@ rl_bind_key (key, function)
 /* 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;
+rl_bind_key_in_map (int key, rl_command_func_t *function, Keymap map)
 {
   int result;
   Keymap oldmap;
@@ -146,30 +193,45 @@ rl_bind_key_in_map (key, function, map)
   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. */
+int
+rl_bind_key_if_unbound_in_map (int key, rl_command_func_t *default_func, Keymap kmap)
+{
+  char *keyseq;
+
+  keyseq = rl_untranslate_keyseq ((unsigned char)key);
+  return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap));
+}
+
+int
+rl_bind_key_if_unbound (int key, rl_command_func_t *default_func)
+{
+  char *keyseq;
+
+  keyseq = rl_untranslate_keyseq ((unsigned char)key);
+  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. */
+   Returns non-zero in case of error.  This is not the same as self-insert;
+   this makes it a dead key. */
 int
-rl_unbind_key (key)
-     int key;
+rl_unbind_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.
-   Returns non-zero in case of error. */
+/* 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;
+rl_unbind_key_in_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)
-     Function *func;
-     Keymap map;
+rl_unbind_function_in_map (rl_command_func_t *func, Keymap map)
 {
   register int i, rval;
 
@@ -177,19 +239,18 @@ rl_unbind_function_in_map (func, map)
     {
       if (map[i].type == ISFUNC && map[i].function == func)
        {
-         map[i].function = (Function *)NULL;
+         map[i].function = (rl_command_func_t *)NULL;
          rval = 1;
        }
     }
   return rval;
 }
 
+/* Unbind all keys bound to COMMAND, which is a bindable command name, in MAP */
 int
-rl_unbind_command_in_map (command, map)
-     char *command;
-     Keymap map;
+rl_unbind_command_in_map (const char *command, Keymap map)
 {
-  Function *func;
+  rl_command_func_t *func;
 
   func = rl_named_function (command);
   if (func == 0)
@@ -198,24 +259,75 @@ rl_unbind_command_in_map (command, 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 (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_set_key (keyseq, function, map)
-     char *keyseq;
-     Function *function;
-     Keymap map;
+rl_bind_keyseq_in_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 (const char *keyseq, rl_command_func_t *function, Keymap 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 (const char *keyseq, rl_command_func_t *default_func, Keymap kmap)
+{
+  rl_command_func_t *func;
+  char *keys;
+  int keys_len;
+
+  if (keyseq)
+    {
+      /* Handle key sequences that require translations and `raw' ones that
+        don't. This might be a problem with backslashes. */
+      keys = (char *)xmalloc (1 + (2 * strlen (keyseq)));
+      if (rl_translate_keyseq (keyseq, keys, &keys_len))
+       {
+         xfree (keys);
+         return -1;
+       }
+      func = rl_function_of_keyseq_len (keys, keys_len, kmap, (int *)NULL);
+      xfree (keys);
+#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 (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;
-     Keymap map;
+rl_macro_bind (const char *keyseq, const char *macro, Keymap map)
 {
   char *macro_keys;
   int macro_keys_len;
@@ -224,7 +336,7 @@ rl_macro_bind (keyseq, macro, map)
 
   if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
     {
-      free (macro_keys);
+      xfree (macro_keys);
       return -1;
     }
   rl_generic_bind (ISMACR, keyseq, macro_keys, map);
@@ -237,70 +349,140 @@ rl_macro_bind (keyseq, macro, map)
    a macro (ISMACR), or a keymap (ISKMAP).  This makes new keymaps
    as necessary.  The initial place to do bindings is in MAP. */
 int
-rl_generic_bind (type, keyseq, data, map)
-     int type;
-     char *keyseq, *data;
-     Keymap map;
+rl_generic_bind (int type, const char *keyseq, char *data, Keymap map)
 {
   char *keys;
-  int keys_len;
+  int keys_len, prevkey;
   register int i;
+  KEYMAP_ENTRY k;
+  Keymap prevmap;  
+
+  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);
+       xfree (data);
       return -1;
     }
 
-  keys = xmalloc (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))
     {
-      free (keys);
+      xfree (keys);
       return -1;
     }
 
+  prevmap = map;
+  prevkey = keys[0];
+
   /* 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;
+
+      if (i > 0)
+       prevkey = 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 = FUNCTION_TO_KEYMAP (map, ESC);
+           {
+             prevmap = map;
+             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 = KEYMAP_TO_FUNCTION (rl_make_bare_keymap());
            }
+         prevmap = map;
          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;
+           }
        }
       else
        {
          if (map[ic].type == ISMACR)
-           free ((char *)map[ic].function);
+           xfree ((char *)map[ic].function);
+         else if (map[ic].type == ISKMAP)
+           {
+             prevmap = map;
+             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 = KEYMAP_TO_FUNCTION (data);
          map[ic].type = type;
        }
 
       rl_binding_keymap = map;
+
+    }
+
+  /* If we unbound a key (type == ISFUNC, data == 0), and the prev keymap
+     points to the keymap where we unbound the key (sanity check), and the
+     current binding keymap is empty (rl_empty_keymap() returns non-zero),
+     and the binding keymap has ANYOTHERKEY set with type == ISFUNC
+     (overridden function), delete the now-empty keymap, take the previously-
+     overridden function and remove the override. */
+  /* Right now, this only works one level back. */
+  if (type == ISFUNC && data == 0 &&
+      prevmap[prevkey].type == ISKMAP &&
+      (FUNCTION_TO_KEYMAP(prevmap, prevkey) == rl_binding_keymap) &&
+      rl_binding_keymap[ANYOTHERKEY].type == ISFUNC &&
+      rl_empty_keymap (rl_binding_keymap))
+    {
+      prevmap[prevkey].type = rl_binding_keymap[ANYOTHERKEY].type;
+      prevmap[prevkey].function = rl_binding_keymap[ANYOTHERKEY].function;
+      rl_discard_keymap (rl_binding_keymap);
+      rl_binding_keymap = prevmap;
     }
-  free (keys);
+
+  xfree (keys);
   return 0;
 }
 
@@ -308,9 +490,7 @@ rl_generic_bind (type, keyseq, data, map)
    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;
-     int *len;
+rl_translate_keyseq (const char *seq, char *array, int *len)
 {
   register int i, c, l, temp;
 
@@ -321,7 +501,10 @@ rl_translate_keyseq (seq, array, len)
          c = seq[++i];
 
          if (c == 0)
-           break;
+           {
+             array[l++] = '\\';        /* preserve trailing backslash */
+             break;
+           }
 
          /* Handle \C- and \M- prefixes. */
          if ((c == 'C' || c == 'M') && seq[i + 1] == '-')
@@ -329,16 +512,30 @@ rl_translate_keyseq (seq, array, len)
              /* Handle special case of backwards define. */
              if (strncmp (&seq[i], "C-\\M-", 5) == 0)
                {
-                 array[l++] = ESC;
+                 array[l++] = ESC;     /* ESC is meta-prefix */
                  i += 5;
                  array[l++] = CTRL (_rl_to_upper (seq[i]));
-                 if (seq[i] == '\0')
-                   i--;
                }
              else if (c == 'M')
                {
-                 i++;
-                 array[l++] = ESC;     /* XXX */
+                 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')
                {
@@ -346,6 +543,8 @@ rl_translate_keyseq (seq, array, len)
                  /* Special hack for C-?... */
                  array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
                }
+             if (seq[i] == '\0')
+               break;
              continue;
            }         
 
@@ -388,19 +587,19 @@ rl_translate_keyseq (seq, array, len)
            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++)
+             for (temp = 2, c -= '0'; ISOCTAL ((unsigned char)seq[i]) && temp--; i++)
                c = (c * 8) + OCTVALUE (seq[i]);
              i--;      /* auto-increment in for loop */
-             array[l++] = c % (largest_char + 1);
+             array[l++] = c & largest_char;
              break;
            case 'x':
              i++;
-             for (temp = 3, c = 0; isxdigit (seq[i]) && temp--; i++)
+             for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++)
                c = (c * 16) + HEXVALUE (seq[i]);
-             if (temp == 3)
+             if (temp == 2)
                c = 'x';
              i--;      /* auto-increment in for loop */
-             array[l++] = c % (largest_char + 1);
+             array[l++] = c & largest_char;
              break;
            default:    /* backslashes before non-special chars just add the char */
              array[l++] = c;
@@ -417,9 +616,40 @@ rl_translate_keyseq (seq, array, len)
   return (0);
 }
 
+static int
+_rl_isescape (int c)
+{
+  switch (c)
+    {
+    case '\007':
+    case '\b':
+    case '\f':
+    case '\n':
+    case '\r':
+    case TAB:
+    case 0x0b:  return (1);
+    default: return (0);
+    }
+}
+
+static int
+_rl_escchar (int c)
+{
+  switch (c)
+    {
+    case '\007':  return ('a');
+    case '\b':  return ('b');
+    case '\f':  return ('f');
+    case '\n':  return ('n');
+    case '\r':  return ('r');
+    case TAB:  return ('t');
+    case 0x0b:  return ('v');
+    default: return (c);
+    }
+}
+
 char *
-rl_untranslate_keyseq (seq)
-     int seq;
+rl_untranslate_keyseq (int seq)
 {
   static char kseq[16];
   int i, c;
@@ -433,6 +663,11 @@ rl_untranslate_keyseq (seq)
       kseq[i++] = '-';
       c = UNMETA (c);
     }
+  else if (c == ESC)
+    {
+      kseq[i++] = '\\';
+      c = 'e';
+    }
   else if (CTRL_CHAR (c))
     {
       kseq[i++] = '\\';
@@ -463,14 +698,13 @@ rl_untranslate_keyseq (seq)
   return kseq;
 }
 
-static char *
-_rl_untranslate_macro_value (seq)
-     char *seq;
+char *
+_rl_untranslate_macro_value (char *seq, int use_escapes)
 {
   char *ret, *r, *s;
   int c;
 
-  r = ret = xmalloc (7 * strlen (seq) + 1);
+  r = ret = (char *)xmalloc (7 * strlen (seq) + 1);
   for (s = seq; *s; s++)
     {
       c = *s;
@@ -481,12 +715,22 @@ _rl_untranslate_macro_value (seq)
          *r++ = '-';
          c = UNMETA (c);
        }
-      else if (CTRL_CHAR (c) && c != ESC)
+      else if (c == ESC)
        {
          *r++ = '\\';
-         *r++ = 'C';
-         *r++ = '-';
-         c = _rl_to_lower (UNCTRL (c));
+         c = 'e';
+       }
+      else if (CTRL_CHAR (c))
+       {
+         *r++ = '\\';
+         if (use_escapes && _rl_isescape (c))
+           c = _rl_escchar (c);
+         else
+           {
+             *r++ = 'C';
+             *r++ = '-';
+             c = _rl_to_lower (UNCTRL (c));
+           }
        }
       else if (c == RUBOUT)
        {
@@ -513,9 +757,8 @@ _rl_untranslate_macro_value (seq)
 /* 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;
+rl_command_func_t *
+rl_named_function (const char *string)
 {
   register int i;
 
@@ -524,7 +767,7 @@ rl_named_function (string)
   for (i = 0; funmap[i]; i++)
     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
@@ -532,42 +775,41 @@ 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_function_of_keyseq (keyseq, map, type)
-     char *keyseq;
-     Keymap map;
-     int *type;
+static rl_command_func_t *
+_rl_function_of_keyseq_internal (const char *keyseq, size_t len, Keymap map, int *type)
 {
   register int i;
 
-  if (!map)
+  if (map == 0)
     map = _rl_keymap;
 
-  for (i = 0; keyseq && keyseq[i]; i++)
+  for (i = 0; keyseq && i < len; 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 = FUNCTION_TO_KEYMAP (map, ESC);
-             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;
@@ -577,7 +819,12 @@ rl_function_of_keyseq (keyseq, map, type)
          else
            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;
@@ -585,14 +832,26 @@ rl_function_of_keyseq (keyseq, map, type)
          return (map[ic].function);
        }
     }
-  return ((Function *) NULL);
+  return ((rl_command_func_t *) NULL);
+}
+
+rl_command_func_t *
+rl_function_of_keyseq (const char *keyseq, Keymap map, int *type)
+{
+  return _rl_function_of_keyseq_internal (keyseq, strlen (keyseq), map, type);
+}
+
+rl_command_func_t *
+rl_function_of_keyseq_len (const char *keyseq, size_t len, Keymap map, int *type)
+{
+  return _rl_function_of_keyseq_internal (keyseq, len, map, type);
 }
 
 /* The last key bindings file read. */
 static char *last_readline_init_file = (char *)NULL;
 
 /* The file we're currently reading key bindings from. */
-static char *current_readline_init_file;
+static const char *current_readline_init_file;
 static int current_readline_init_include_level;
 static int current_readline_init_lineno;
 
@@ -600,17 +859,20 @@ static int current_readline_init_lineno;
    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;
+_rl_read_file (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 = -1;
+  if (((file = open (filename, O_RDONLY, 0666)) < 0) || (fstat (file, &finfo) < 0))
+    {
+      if (file >= 0)
+       close (file);
+      return ((char *)NULL);
+    }
 
   file_size = (size_t)finfo.st_size;
 
@@ -630,36 +892,27 @@ _rl_read_file (filename, sizep)
   i = read (file, buffer, file_size);
   close (file);
 
-#if 0
-  if (i < file_size)
-#else
   if (i < 0)
-#endif
     {
-      free (buffer);
+      xfree (buffer);
       return ((char *)NULL);
     }
 
-#if 0
-  buffer[file_size] = '\0';
-  if (sizep)
-    *sizep = file_size;
-#else
+  RL_CHECK_SIGNALS ();
+
   buffer[i] = '\0';
   if (sizep)
     *sizep = i;
-#endif
 
   return (buffer);
 }
 
 /* Re-read the current keybindings file. */
 int
-rl_re_read_init_file (count, ignore)
-     int count, ignore;
+rl_re_read_init_file (int count, int ignore)
 {
   int r;
-  r = rl_read_init_file ((char *)NULL);
+  r = rl_read_init_file ((const char *)NULL);
   rl_set_keymap_from_edit_mode ();
   return r;
 }
@@ -669,25 +922,26 @@ rl_re_read_init_file (count, ignore)
      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;
+rl_read_init_file (const char *filename)
 {
   /* Default the filename. */
   if (filename == 0)
+    filename = last_readline_init_file;
+  if (filename == 0)
+    filename = sh_get_env_value ("INPUTRC");
+  if (filename == 0 || *filename == 0)
     {
-      filename = last_readline_init_file;
-      if (filename == 0)
-        filename = get_env_value ("INPUTRC");
-      if (filename == 0)
-       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;
     }
 
-  if (*filename == 0)
-    filename = DEFAULT_INPUTRC;
-
 #if defined (__MSDOS__)
   if (_rl_read_init_file (filename, 0) == 0)
     return 0;
@@ -697,9 +951,7 @@ rl_read_init_file (filename)
 }
 
 static int
-_rl_read_init_file (filename, include_level)
-     char *filename;
-     int include_level;
+_rl_read_init_file (const char *filename, int include_level)
 {
   register int i;
   char *buffer, *openname, *line, *end;
@@ -710,8 +962,9 @@ _rl_read_init_file (filename, include_level)
 
   openname = tilde_expand (filename);
   buffer = _rl_read_file (openname, &file_size);
-  free (openname);
+  xfree (openname);
 
+  RL_CHECK_SIGNALS ();
   if (buffer == 0)
     return (errno);
   
@@ -733,7 +986,7 @@ _rl_read_init_file (filename, include_level)
       /* Find the end of this line. */
       for (i = 0; line + i != end && line[i] != '\n'; i++);
 
-#if defined (__CYGWIN32__)
+#if defined (__CYGWIN__)
       /* ``Be liberal in what you accept.'' */
       if (line[i] == '\n' && line[i-1] == '\r')
        line[i - 1] = '\0';
@@ -758,20 +1011,97 @@ _rl_read_init_file (filename, include_level)
       current_readline_init_lineno++;
     }
 
-  free (buffer);
+  xfree (buffer);
   currently_reading_init_file = 0;
   return (0);
 }
 
 static void
-_rl_init_file_error (msg)
-     char *msg;
+#if defined (PREFER_STDARG)
+_rl_init_file_error (const char *format, ...)
+#else
+_rl_init_file_error (va_alist)
+     va_dcl
+#endif
 {
+  va_list args;
+#if defined (PREFER_VARARGS)
+  char *format;
+#endif
+
+#if defined (PREFER_STDARG)
+  va_start (args, format);
+#else
+  va_start (args);
+  format = va_arg (args, char *);
+#endif
+
+  fprintf (stderr, "readline: ");
   if (currently_reading_init_file)
-    fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file,
-                    current_readline_init_lineno, msg);
-  else
-    fprintf (stderr, "readline: %s\n", msg);
+    fprintf (stderr, "%s: line %d: ", current_readline_init_file,
+                    current_readline_init_lineno);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+  fflush (stderr);
+
+  va_end (args);
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Parser Helper Functions                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static int
+parse_comparison_op (s, indp)
+     const char *s;
+     int *indp;
+{
+  int i, peekc, op;
+
+  if (OPSTART (s[*indp]) == 0)
+    return -1;
+  i = *indp;
+  peekc = s[i] ? s[i+1] : 0;
+  op = -1;
+
+  if (s[i] == '=')
+    {
+      op = OP_EQ;
+      if (peekc == '=')
+        i++;
+      i++;
+    }
+  else if (s[i] == '!' && peekc == '=')
+    {
+      op = OP_NE;
+      i += 2;
+    }
+  else if (s[i] == '<' && peekc == '=')
+    {
+      op = OP_LE;
+      i += 2;
+    }
+  else if (s[i] == '>' && peekc == '=')
+    {
+      op = OP_GE;
+      i += 2;
+    }
+  else if (s[i] == '<')
+    {
+      op = OP_LT;
+      i += 1;
+    }
+  else if (s[i] == '>')
+    {
+      op = OP_GT;
+      i += 1;
+    }
+
+  *indp = i;
+  return op;        
 }
 
 /* **************************************************************** */
@@ -780,10 +1110,21 @@ _rl_init_file_error (msg)
 /*                                                                 */
 /* **************************************************************** */
 
+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;
@@ -793,10 +1134,11 @@ static int if_stack_size;
 /* Push _rl_parsing_conditionalized_out, and set parser state based
    on ARGS. */
 static int
-parser_if (args)
-     char *args;
+parser_if (char *args)
 {
-  register int i;
+  int i, llen, boolvar, strvar;
+
+  boolvar = strvar = -1;
 
   /* Push parser state. */
   if (if_stack_depth + 1 >= if_stack_size)
@@ -813,6 +1155,8 @@ parser_if (args)
   if (_rl_parsing_conditionalized_out)
     return 0;
 
+  llen = strlen (args);
+
   /* Isolate first argument. */
   for (i = 0; args[i] && !whitespace (args[i]); i++);
 
@@ -838,7 +1182,7 @@ parser_if (args)
         `$if term=sun-cmd' into their .inputrc. */
       _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) &&
                                        _rl_stricmp (args + 5, rl_terminal_name);
-      free (tname);
+      xfree (tname);
     }
 #if defined (VI_MODE)
   else if (_rl_strnicmp (args, "mode=", 5) == 0)
@@ -855,10 +1199,138 @@ parser_if (args)
       _rl_parsing_conditionalized_out = mode != rl_editing_mode;
     }
 #endif /* VI_MODE */
+  else if (_rl_strnicmp (args, "version", 7) == 0)
+    {
+      int rlversion, versionarg, op, previ, major, minor;
+
+      _rl_parsing_conditionalized_out = 1;
+      rlversion = RL_VERSION_MAJOR*10 + RL_VERSION_MINOR;
+      /* if "version" is separated from the operator by whitespace, or the
+         operand is separated from the operator by whitespace, restore it.
+         We're more liberal with allowed whitespace for this variable. */
+      if (i > 0 && i <= llen && args[i-1] == '\0')
+        args[i-1] = ' ';
+      args[llen] = '\0';               /* just in case */
+      for (i = 7; whitespace (args[i]); i++)
+       ;
+      if (OPSTART(args[i]) == 0)
+       {
+         _rl_init_file_error ("comparison operator expected, found `%s'", args[i] ? args + i : "end-of-line");
+         return 0;
+       }
+      previ = i;
+      op = parse_comparison_op (args, &i);
+      if (op <= 0)
+       {
+         _rl_init_file_error ("comparison operator expected, found `%s'", args+previ);
+         return 0;
+       }
+      for ( ; args[i] && whitespace (args[i]); i++)
+       ;
+      if (args[i] == 0 || _rl_digit_p (args[i]) == 0)
+       {
+         _rl_init_file_error ("numeric argument expected, found `%s'", args+i);
+         return 0;
+       }
+      major = minor = 0;
+      previ = i;
+      for ( ; args[i] && _rl_digit_p (args[i]); i++)
+       major = major*10 + _rl_digit_value (args[i]);
+      if (args[i] == '.')
+       {
+         if (args[i + 1] && _rl_digit_p (args [i + 1]) == 0)
+           {
+             _rl_init_file_error ("numeric argument expected, found `%s'", args+previ);
+             return 0;
+           }
+         for (++i; args[i] && _rl_digit_p (args[i]); i++)
+           minor = minor*10 + _rl_digit_value (args[i]);
+       }
+      /* optional - check for trailing garbage on the line, allow whitespace
+        and a trailing comment */
+      previ = i;
+      for ( ; args[i] && whitespace (args[i]); i++)
+       ;
+      if (args[i] && args[i] != '#')
+       {
+         _rl_init_file_error ("trailing garbage on line: `%s'", args+previ);
+         return 0;
+       }
+      versionarg = major*10 + minor;
+
+      switch (op)
+       {
+       case OP_EQ:
+         _rl_parsing_conditionalized_out = rlversion == versionarg;
+         break;
+       case OP_NE:
+         _rl_parsing_conditionalized_out = rlversion != versionarg;
+         break;
+       case OP_GT:
+         _rl_parsing_conditionalized_out = rlversion > versionarg;
+         break;
+       case OP_GE:
+         _rl_parsing_conditionalized_out = rlversion >= versionarg;
+         break;
+       case OP_LT:
+         _rl_parsing_conditionalized_out = rlversion < versionarg;
+         break;
+       case OP_LE:
+         _rl_parsing_conditionalized_out = rlversion <= versionarg;
+         break;
+       }
+    }
   /* Check to see if the first word in ARGS is the same as the
      value stored in rl_readline_name. */
   else if (_rl_stricmp (args, rl_readline_name) == 0)
     _rl_parsing_conditionalized_out = 0;
+  else if ((boolvar = find_boolean_var (args)) >= 0 || (strvar = find_string_var (args)) >= 0)
+    {
+      int op, previ;
+      size_t vlen;
+      const char *vname;
+      char *valuearg, *vval, prevc;
+
+      _rl_parsing_conditionalized_out = 1;
+      vname = (boolvar >= 0) ? boolean_varname (boolvar) : string_varname (strvar);
+      vlen = strlen (vname);
+      if (i > 0 && i <= llen && args[i-1] == '\0')
+        args[i-1] = ' ';
+      args[llen] = '\0';               /* just in case */
+      for (i = vlen; whitespace (args[i]); i++)
+       ;
+      if (CMPSTART(args[i]) == 0)
+       {
+         _rl_init_file_error ("equality comparison operator expected, found `%s'", args[i] ? args + i : "end-of-line");
+         return 0;
+       }
+      previ = i;
+      op = parse_comparison_op (args, &i);
+      if (op != OP_EQ && op != OP_NE)
+       {
+         _rl_init_file_error ("equality comparison operator expected, found `%s'", args+previ);
+         return 0;
+       }
+      for ( ; args[i] && whitespace (args[i]); i++)
+       ;
+      if (args[i] == 0)
+       {
+         _rl_init_file_error ("argument expected, found `%s'", args+i);
+         return 0;
+       }
+      previ = i;
+      valuearg = args + i;
+      for ( ; args[i] && whitespace (args[i]) == 0; i++)
+       ;
+      prevc = args[i];
+      args[i] = '\0';          /* null-terminate valuearg */
+      vval = rl_variable_value (vname);
+      if (op == OP_EQ)
+        _rl_parsing_conditionalized_out = _rl_stricmp (vval, valuearg) != 0;
+      else if (op == OP_NE)
+        _rl_parsing_conditionalized_out = _rl_stricmp (vval, valuearg) == 0;
+      args[i] = prevc;
+    }
   else
     _rl_parsing_conditionalized_out = 1;
   return 0;
@@ -866,8 +1338,7 @@ parser_if (args)
 
 /* Invert the current parser state if there is anything on the stack. */
 static int
-parser_else (args)
-     char *args;
+parser_else (char *args)
 {
   register int i;
 
@@ -877,9 +1348,15 @@ parser_else (args)
       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;
 
@@ -891,8 +1368,7 @@ parser_else (args)
 /* Terminate a conditional, popping the value of
    _rl_parsing_conditionalized_out from the stack. */
 static int
-parser_endif (args)
-     char *args;
+parser_endif (char *args)
 {
   if (if_stack_depth)
     _rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
@@ -902,10 +1378,10 @@ parser_endif (args)
 }
 
 static int
-parser_include (args)
-     char *args;
+parser_include (char *args)
 {
-  char *old_init_file, *e;
+  const char *old_init_file;
+  char *e;
   int old_line_number, old_include_level, r;
 
   if (_rl_parsing_conditionalized_out)
@@ -918,7 +1394,7 @@ parser_include (args)
   e = strchr (args, '\n');
   if (e)
     *e = '\0';
-  r = _rl_read_init_file (args, old_include_level + 1);
+  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;
@@ -928,22 +1404,21 @@ parser_include (args)
 }
   
 /* 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 },
   { "include", parser_include },
-  { (char *)0x0, (Function *)0x0 }
+  { (char *)0x0, (_rl_parser_func_t *)0x0 }
 };
 
 /* Handle a parser directive.  STATEMENT is the line of the directive
    without any leading `$'. */
 static int
-handle_parser_directive (statement)
-     char *statement;
+handle_parser_directive (char *statement)
 {
   register int i;
   char *directive, *args;
@@ -973,26 +1448,55 @@ handle_parser_directive (statement)
       }
 
   /* display an error message about the unknown parser directive */
-  _rl_init_file_error ("unknown parser directive");
+  _rl_init_file_error ("%s: unknown parser directive", directive);
   return (1);
 }
 
+/* Start at STRING[START] and look for DELIM.  Return I where STRING[I] ==
+   DELIM or STRING[I] == 0.  DELIM is usually a double quote. */
+static int
+_rl_skip_to_delim (char *string, int start, int delim)
+{
+  int i, c, passc;
+
+  for (i = start,passc = 0; c = string[i]; i++)
+    {
+      if (passc)
+       {
+         passc = 0;
+         if (c == 0)
+           break;
+         continue;
+       }
+
+      if (c == '\\')
+       {
+         passc = 1;
+         continue;
+       }
+
+      if (c == delim)
+       break;
+    }
+
+  return i;
+}
+
 /* 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;
+rl_parse_and_bind (char *string)
 {
   char *funname, *kname;
   register int c, i;
-  int key, equivalency;
+  int key, equivalency, foundmod, foundsep;
 
   while (string && whitespace (*string))
     string++;
 
-  if (!string || !*string || *string == '#')
+  if (string == 0 || *string == 0 || *string == '#')
     return 0;
 
   /* If this is a parser directive, act on it. */
@@ -1012,38 +1516,31 @@ rl_parse_and_bind (string)
      backslash to quote characters in the key expression. */
   if (*string == '"')
     {
-      int passc = 0;
+      i = _rl_skip_to_delim (string, 1, '"');
 
-      for (i = 1; c = string[i]; i++)
-       {
-         if (passc)
-           {
-             passc = 0;
-             continue;
-           }
-
-         if (c == '\\')
-           {
-             passc++;
-             continue;
-           }
-
-         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");
+          _rl_init_file_error ("%s: no closing `\"' in key binding", string);
           return 1;
         }
+      else
+        i++;   /* skip past closing double quote */
     }
 
   /* Advance to the colon (:) or whitespace which separates the two objects. */
   for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
 
+  if (i == 0)
+    {
+      _rl_init_file_error ("`%s': invalid key binding: missing key sequence", string);
+      return 1;
+    }
+
   equivalency = (c == ':' && string[i + 1] == '=');
 
+  foundsep = c != 0;
+
   /* Mark the end of the command (or keyname). */
   if (string[i])
     string[i++] = '\0';
@@ -1055,19 +1552,46 @@ rl_parse_and_bind (string)
   /* If this is a command to set a variable, then do that. */
   if (_rl_stricmp (string, "set") == 0)
     {
-      char *var = string + i;
-      char *value;
+      char *var, *value, *e;
+      int s;
 
+      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++;
+      while (*value && whitespace (*value) == 0) value++;
       if (*value)
        *value++ = '\0';
       while (*value && whitespace (*value)) value++;
 
+      /* Strip trailing whitespace from values of boolean variables. */
+      if (find_boolean_var (var) >= 0)
+       {
+         /* remove trailing whitespace */
+remove_trailing:
+         e = value + strlen (value) - 1;
+         while (e >= value && whitespace (*e))
+           e--;
+         e++;          /* skip back to whitespace or EOS */
+         
+         if (*e && e >= value)
+           *e = '\0';
+       }
+      else if ((i = find_string_var (var)) >= 0)
+       {
+         /* Allow quoted strings in variable values */
+         if (*value == '"')
+           {
+             i = _rl_skip_to_delim (value, 1, *value);
+             value[i] = '\0';
+             value++;  /* skip past the quote */
+           }
+         else
+           goto remove_trailing;
+       }
+       
       rl_variable_bind (var, value);
       return 0;
     }
@@ -1088,31 +1612,18 @@ rl_parse_and_bind (string)
      the quoted string delimiter, like the shell. */
   if (*funname == '\'' || *funname == '"')
     {
-      int delimiter = string[i++], passc;
-
-      for (passc = 0; c = string[i]; i++)
+      i = _rl_skip_to_delim (string, i+1, *funname);
+      if (string[i])
+       i++;
+      else
        {
-         if (passc)
-           {
-             passc = 0;
-             continue;
-           }
-
-         if (c == '\\')
-           {
-             passc = 1;
-             continue;
-           }
-
-         if (c == delimiter)
-           break;
+         _rl_init_file_error ("`%s': missing closing quote for macro", funname);
+         return 1;
        }
-      if (c)
-       i++;
     }
 
   /* Advance to the end of the string.  */
-  for (; string[i] && !whitespace (string[i]); i++);
+  for (; string[i] && whitespace (string[i]) == 0; i++);
 
   /* No extra whitespace at the end of the string. */
   string[i] = '\0';
@@ -1124,14 +1635,20 @@ rl_parse_and_bind (string)
       return 0;
     }
 
+  if (foundsep == 0)
+    {
+      _rl_init_file_error ("%s: no key sequence terminator", string);
+      return 1;
+    }
+
   /* 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;
       register int j, k, passc;
 
-      seq = xmalloc (1 + strlen (string));
+      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.
@@ -1164,15 +1681,15 @@ 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));
 
-      free (seq);
+      xfree (seq);
       return 0;
     }
 
   /* Get the actual character we want to deal with. */
   kname = strrchr (string, '-');
-  if (!kname)
+  if (kname == 0)
     kname = string;
   else
     kname++;
@@ -1180,16 +1697,29 @@ 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 (_rl_to_upper (key));
+  foundmod = 0;
+  if (substring_member_of_array (string, _rl_possible_control_prefixes))
+    {
+      key = CTRL (_rl_to_upper (key));
+      foundmod = 1;
+    }
 
-  if (substring_member_of_array (string, possible_meta_prefixes))
-    key = META (key);
+  if (substring_member_of_array (string, _rl_possible_meta_prefixes))
+    {
+      key = META (key);
+      foundmod = 1;
+    }
+
+  if (foundmod == 0 && kname != string)
+    {
+      _rl_init_file_error ("%s: unknown key modifier", string);
+      return 1;
+    }
 
   /* Temporary.  Handle old-style keyname with macro-binding. */
   if (*funname == '\'' || *funname == '"')
     {
-      unsigned char useq[2];
+      char useq[2];
       int fl = strlen (funname);
 
       useq[0] = key; useq[1] = '\0';
@@ -1211,6 +1741,7 @@ rl_parse_and_bind (string)
 #endif /* PREFIX_META_HACK */
   else
     rl_bind_key (key, rl_named_function (funname));
+
   return 0;
 }
 
@@ -1220,35 +1751,53 @@ rl_parse_and_bind (string)
 
 #define V_SPECIAL      0x1
 
-static struct {
-  char *name;
+static const struct {
+  const char * const name;
   int *value;
   int flags;
 } boolean_varlist [] = {
+  { "bind-tty-special-chars",  &_rl_bind_stty_chars,           0 },
   { "blink-matching-paren",    &rl_blink_matching_paren,       V_SPECIAL },
+  { "byte-oriented",           &rl_byte_oriented,              0 },
+#if defined (COLOR_SUPPORT)
+  { "colored-completion-prefix",&_rl_colored_completion_prefix,        0 },
+  { "colored-stats",           &_rl_colored_stats,             0 },
+#endif
   { "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-bracketed-paste",  &_rl_enable_bracketed_paste,    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 },
+  { "show-mode-in-prompt",     &_rl_show_mode_in_prompt,       0 },
+  { "skip-completed-text",     &_rl_skip_completed_text,       0 },
 #if defined (VISIBLE_STATS)
   { "visible-stats",           &rl_visible_stats,              0 },
 #endif /* VISIBLE_STATS */
-  { (char *)NULL, (int *)NULL }
+  { (char *)NULL, (int *)NULL, 0 }
 };
 
 static int
-find_boolean_var (name)
-     char *name;
+find_boolean_var (const char *name)
 {
   register int i;
 
@@ -1258,14 +1807,19 @@ find_boolean_var (name)
   return -1;
 }
 
+static const char *
+boolean_varname (int i)
+{
+  return ((i >= 0) ? boolean_varlist[i].name : (char *)NULL);
+}  
+
 /* 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;
+hack_special_boolean_var (int i)
 {
-  char *name;
+  const char *name;
 
   name = boolean_varlist[i].name;
 
@@ -1278,8 +1832,12 @@ hack_special_boolean_var (i)
       else
        _rl_bell_preference = AUDIBLE_BELL;
     }
+  else if (_rl_stricmp (name, "show-mode-in-prompt") == 0)
+    _rl_reset_prompt ();
 }
 
+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
@@ -1292,30 +1850,43 @@ hack_special_boolean_var (i)
 #define V_INT          2
 
 /* Forward declarations */
-static int sv_bell_style __P((char *));
-static int sv_combegin __P((char *));
-static int sv_compquery __P((char *));
-static int sv_editmode __P((char *));
-static int sv_isrchterm __P((char *));
-static int sv_keymap __P((char *));
-
-static struct {
-  char *name;
+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_emacs_modestr 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 int sv_seqtimeout PARAMS((const char *));
+static int sv_viins_modestr PARAMS((const char *));
+static int sv_vicmd_modestr PARAMS((const char *));
+
+static const struct {
+  const char * const name;
   int flags;
-  Function *set_func;
+  _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 },
+  { "emacs-mode-string", V_STRING,     sv_emacs_modestr },  
+  { "history-size",    V_INT,          sv_histsize },
   { "isearch-terminators", V_STRING,   sv_isrchterm },
   { "keymap",          V_STRING,       sv_keymap },
-  { (char *)NULL,      0 }
+  { "keyseq-timeout",  V_INT,          sv_seqtimeout },
+  { "vi-cmd-mode-string", V_STRING,    sv_vicmd_modestr }, 
+  { "vi-ins-mode-string", V_STRING,    sv_viins_modestr }, 
+  { (char *)NULL,      0, (_rl_sv_func_t *)0 }
 };
 
 static int
-find_string_var (name)
-     char *name;
+find_string_var (const char *name)
 {
   register int i;
 
@@ -1325,21 +1896,43 @@ find_string_var (name)
   return -1;
 }
 
+static const char *
+string_varname (int i)
+{
+  return ((i >= 0) ? string_varlist[i].name : (char *)NULL);
+}  
+
 /* 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
+   the value is null or empty, `on' (case-insensitive), or "1".  Any other
    values result in 0 (false). */
 static int
-bool_to_int (value)
-     char *value;
+bool_to_int (const char *value)
 {
   return (value == 0 || *value == '\0' ||
                (_rl_stricmp (value, "on") == 0) ||
                (value[0] == '1' && value[1] == '\0'));
 }
 
+char *
+rl_variable_value (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");
+
+  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)
-     char *name, *value;
+rl_variable_bind (const char *name, const char *value)
 {
   register int i;
   int  v;
@@ -1356,18 +1949,21 @@ rl_variable_bind (name, value)
 
   i = find_string_var (name);
 
-  /* For the time being, unknown variable names or string names without a
-     handler function are simply ignored. */
+  /* For the time being, string names without a handler function are simply
+     ignored. */
   if (i < 0 || string_varlist[i].set_func == 0)
-    return 0;
+    {
+      if (i < 0)
+       _rl_init_file_error ("%s: unknown variable name", name);
+      return 0;
+    }
 
   v = (*string_varlist[i].set_func) (value);
   return v;
 }
 
 static int
-sv_editmode (value)
-     char *value;
+sv_editmode (const char *value)
 {
   if (_rl_strnicmp (value, "vi", 2) == 0)
     {
@@ -1387,8 +1983,7 @@ sv_editmode (value)
 }
 
 static int
-sv_combegin (value)
-     char *value;
+sv_combegin (const char *value)
 {
   if (value && *value)
     {
@@ -1400,8 +1995,22 @@ sv_combegin (value)
 }
 
 static int
-sv_compquery (value)
-     char *value;
+sv_dispprefix (const char *value)
+{
+  int nval = 0;
+
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       nval = 0;
+    }
+  _rl_completion_prefix_display_length = nval;
+  return 0;
+}
+
+static int
+sv_compquery (const char *value)
 {
   int nval = 100;
 
@@ -1416,8 +2025,38 @@ sv_compquery (value)
 }
 
 static int
-sv_keymap (value)
-     char *value;
+sv_compwidth (const char *value)
+{
+  int nval = -1;
+
+  if (value && *value)
+    nval = atoi (value);
+
+  _rl_completion_columns = nval;
+  return 0;
+}
+
+static int
+sv_histsize (const char *value)
+{
+  int nval;
+
+  nval = 500;
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       {
+         unstifle_history ();
+         return 0;
+       }
+    }
+  stifle_history (nval);
+  return 0;
+}
+
+static int
+sv_keymap (const char *value)
 {
   Keymap kmap;
 
@@ -1430,28 +2069,40 @@ sv_keymap (value)
   return 1;
 }
 
-#define _SET_BELL(v)   do { _rl_bell_preference = v; return 0; } while (0)
+static int
+sv_seqtimeout (const char *value)
+{
+  int nval;
+
+  nval = 0;
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       nval = 0;
+    }
+  _rl_keyseq_timeout = nval;
+  return 0;
+}
 
 static int
-sv_bell_style (value)
-     char *value;
+sv_bell_style (const char *value)
 {
   if (value == 0 || *value == '\0')
-    _SET_BELL (AUDIBLE_BELL);
+    _rl_bell_preference = AUDIBLE_BELL;
   else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0)
-    _SET_BELL (NO_BELL);
+    _rl_bell_preference = NO_BELL;
   else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0)
-    _SET_BELL (AUDIBLE_BELL);
+    _rl_bell_preference = AUDIBLE_BELL;
   else if (_rl_stricmp (value, "visible") == 0)
-    _SET_BELL (VISIBLE_BELL);
+    _rl_bell_preference = VISIBLE_BELL;
   else
     return 1;
+  return 0;
 }
-#undef _SET_BELL
 
 static int
-sv_isrchterm (value)
-     char *value;
+sv_isrchterm (const char *value)
 {
   int beg, end, delim;
   char *v;
@@ -1470,30 +2121,116 @@ sv_isrchterm (value)
     }
   else
     {
-      for (beg = end = 0; whitespace (v[end]) == 0; end++)
+      for (beg = end = 0; v[end] && whitespace (v[end]) == 0; end++)
        ;
     }
 
   v[end] = '\0';
 
   /* The value starts at v + beg.  Translate it into a character string. */
-  _rl_isearch_terminators = (unsigned char *)xmalloc (2 * strlen (v) + 1);
+  _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1);
   rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end);
   _rl_isearch_terminators[end] = '\0';
 
-  free (v);
+  xfree (v);
   return 0;
 }
-      
+
+extern char *_rl_emacs_mode_str;
+
+static int
+sv_emacs_modestr (const char *value)
+{
+  if (value && *value)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_emacs_mode_str, &_rl_emacs_modestr_len);
+      _rl_emacs_mode_str[_rl_emacs_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = (char *)xmalloc (1);
+      _rl_emacs_mode_str[_rl_emacs_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = 0;  /* prompt_modestr does the right thing */
+      _rl_emacs_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
+static int
+sv_viins_modestr (const char *value)
+{
+  if (value && *value)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_vi_ins_mode_str, &_rl_vi_ins_modestr_len);
+      _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = (char *)xmalloc (1);
+      _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = 0; /* prompt_modestr does the right thing */
+      _rl_vi_ins_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
+static int
+sv_vicmd_modestr (const char *value)
+{
+  if (value && *value)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_vi_cmd_mode_str, &_rl_vi_cmd_modestr_len);
+      _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = (char *)xmalloc (1);
+      _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = 0; /* prompt_modestr does the right thing */
+      _rl_vi_cmd_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
 /* 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' },
@@ -1509,8 +2246,7 @@ static assoc_list name_key_alist[] = {
 };
 
 static int
-glean_key_from_name (name)
-     char *name;
+glean_key_from_name (char *name)
 {
   register int i;
 
@@ -1522,10 +2258,12 @@ glean_key_from_name (name)
 }
 
 /* Auxiliary functions to manage keymaps. */
-static struct {
+struct name_and_keymap {
   char *name;
   Keymap map;
-} keymap_names[] = {
+};
+
+static struct name_and_keymap builtin_keymap_names[] = {
   { "emacs", emacs_standard_keymap },
   { "emacs-standard", emacs_standard_keymap },
   { "emacs-meta", emacs_meta_keymap },
@@ -1539,45 +2277,116 @@ static struct {
   { (char *)0x0, (Keymap)0x0 }
 };
 
-Keymap
-rl_get_keymap_by_name (name)
-     char *name;
+/* -1 for NULL entry */
+#define NUM_BUILTIN_KEYMAPS (sizeof (builtin_keymap_names) / sizeof (builtin_keymap_names[0]) - 1)
+
+static struct name_and_keymap *keymap_names = builtin_keymap_names;
+
+static int
+_rl_get_keymap_by_name (const 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);
+    if (_rl_stricmp (name, keymap_names[i].name) == 0)
+      return (i);
+  return -1;
 }
 
-char *
-rl_get_keymap_name (map)
-     Keymap map;
+Keymap
+rl_get_keymap_by_name (const char *name)
+{
+  int i;
+
+  i = _rl_get_keymap_by_name (name);
+  return ((i >= 0) ? keymap_names[i].map : (Keymap) NULL);
+}
+
+static int
+_rl_get_keymap_by_map (Keymap map)
 {
   register int i;
+
   for (i = 0; keymap_names[i].name; i++)
     if (map == keymap_names[i].map)
-      return (keymap_names[i].name);
-  return ((char *)NULL);
+      return (i);
+  return -1;
 }
-  
+
+char *
+rl_get_keymap_name (Keymap map)
+{
+  int i;
+
+  i = _rl_get_keymap_by_map (map);
+  return ((i >= 0) ? keymap_names[i].name : (char *)NULL);
+}
+
+int
+rl_set_keymap_name (const char *name, Keymap map)
+{
+  int i, ni, mi;
+
+  /* First check whether or not we're trying to rename a builtin keymap */
+  mi = _rl_get_keymap_by_map (map);
+  if (mi >= 0 && mi < NUM_BUILTIN_KEYMAPS)
+    return -1;
+
+  /* Then reject attempts to set one of the builtin names to a new map */
+  ni = _rl_get_keymap_by_name (name);
+  if (ni >= 0 && ni < NUM_BUILTIN_KEYMAPS)
+    return -1;
+
+  /* Renaming a keymap we already added */
+  if (mi >= 0) /* XXX - could be >= NUM_BUILTIN_KEYMAPS */
+    {
+      xfree (keymap_names[mi].name);
+      keymap_names[mi].name = savestring (name);
+      return mi;
+    }
+
+  /* Associating new keymap with existing name */
+  if (ni >= 0)
+    {
+      keymap_names[ni].map = map;
+      return ni;
+    }
+
+  for (i = 0; keymap_names[i].name; i++)
+    ;
+
+  if (keymap_names == builtin_keymap_names)
+    {
+      keymap_names = xmalloc ((i + 2) * sizeof (struct name_and_keymap));
+      memcpy (keymap_names, builtin_keymap_names, i * sizeof (struct name_and_keymap));
+    }
+  else
+    keymap_names = xrealloc (keymap_names, (i + 2) * sizeof (struct name_and_keymap));
+
+  keymap_names[i].name = savestring (name);
+  keymap_names[i].map = map;
+
+  keymap_names[i+1].name = NULL;
+  keymap_names[i+1].map = NULL;
+
+  return i;
+}
+
 void
-rl_set_keymap (map)
-     Keymap map;
+rl_set_keymap (Keymap map)
 {
   if (map)
     _rl_keymap = map;
 }
 
 Keymap
-rl_get_keymap ()
+rl_get_keymap (void)
 {
   return (_rl_keymap);
 }
 
 void
-rl_set_keymap_from_edit_mode ()
+rl_set_keymap_from_edit_mode (void)
 {
   if (rl_editing_mode == emacs_mode)
     _rl_keymap = emacs_standard_keymap;
@@ -1588,7 +2397,7 @@ rl_set_keymap_from_edit_mode ()
 }
 
 char *
-rl_get_keymap_name_from_edit_mode ()
+rl_get_keymap_name_from_edit_mode (void)
 {
   if (rl_editing_mode == emacs_mode)
     return "emacs";
@@ -1609,14 +2418,14 @@ rl_get_keymap_name_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 ()
+rl_list_funmap_names (void)
 {
   register int i;
-  char **funmap_names;
+  const char **funmap_names;
 
   funmap_names = rl_funmap_names ();
 
@@ -1626,12 +2435,11 @@ rl_list_funmap_names ()
   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;
+_rl_get_keyname (int key)
 {
   char *keyname;
   int i, c;
@@ -1643,17 +2451,18 @@ _rl_get_keyname (key)
      pairs for possible inclusion in an inputrc file, we don't want to
      do any special meta processing on KEY. */
 
-#if 0
+#if 1
+  /* XXX - Experimental */
   /* We might want to do this, but the old version of the code did not. */
 
   /* If this is an escape character, we don't want to do any more processing.
      Just add the special ESC key sequence and return. */
   if (c == ESC)
     {
-      keyseq[0] = '\\';
-      keyseq[1] = 'e';
-      keyseq[2] = '\0';
-      return keyseq;
+      keyname[0] = '\\';
+      keyname[1] = 'e';
+      keyname[2] = '\0';
+      return keyname;
     }
 #endif
 
@@ -1705,9 +2514,7 @@ _rl_get_keyname (key)
 /* Return a NULL terminated array of strings which represent the key
    sequences that are used to invoke FUNCTION in MAP. */
 char **
-rl_invoking_keyseqs_in_map (function, map)
-     Function *function;
-     Keymap map;
+rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map)
 {
   register int key;
   char **result;
@@ -1735,7 +2542,7 @@ rl_invoking_keyseqs_in_map (function, map)
              if (result_index + 2 > result_size)
                {
                  result_size += 10;
-                 result = (char **) xrealloc (result, result_size * sizeof (char *));
+                 result = (char **)xrealloc (result, result_size * sizeof (char *));
                }
 
              result[result_index++] = keyname;
@@ -1764,7 +2571,16 @@ rl_invoking_keyseqs_in_map (function, map)
                char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
 
                if (key == ESC)
-                 sprintf (keyname, "\\e");
+                 {
+                   /* 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
+                     sprintf (keyname, "\\e");
+                 }
                else if (CTRL_CHAR (key))
                  sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key)));
                else if (key == RUBOUT)
@@ -1782,19 +2598,19 @@ rl_invoking_keyseqs_in_map (function, map)
                  }
                
                strcat (keyname, seqs[i]);
-               free (seqs[i]);
+               xfree (seqs[i]);
 
                if (result_index + 2 > result_size)
                  {
                    result_size += 10;
-                   result = (char **) xrealloc (result, result_size * sizeof (char *));
+                   result = (char **)xrealloc (result, result_size * sizeof (char *));
                  }
 
                result[result_index++] = keyname;
                result[result_index] = (char *)NULL;
              }
 
-           free (seqs);
+           xfree (seqs);
          }
          break;
        }
@@ -1805,8 +2621,7 @@ rl_invoking_keyseqs_in_map (function, map)
 /* 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;
+rl_invoking_keyseqs (rl_command_func_t *function)
 {
   return (rl_invoking_keyseqs_in_map (function, _rl_keymap));
 }
@@ -1815,12 +2630,11 @@ rl_invoking_keyseqs (function)
    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;
+rl_function_dumper (int print_readably)
 {
   register int i;
-  char **names;
-  char *name;
+  const char **names;
+  const char *name;
 
   names = rl_funmap_names ();
 
@@ -1828,7 +2642,7 @@ 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);
@@ -1846,10 +2660,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
@@ -1873,20 +2687,21 @@ 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);
            }
        }
     }
+
+  xfree (names);
 }
 
 /* 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;
+rl_dump_functions (int count, int key)
 {
   if (rl_dispatching)
     fprintf (rl_outstream, "\r\n");
@@ -1896,10 +2711,7 @@ rl_dump_functions (count, key)
 }
 
 static void
-_rl_macro_dumper_internal (print_readably, map, prefix)
-     int print_readably;
-     Keymap map;
-     char *prefix;
+_rl_macro_dumper_internal (int print_readably, Keymap map, char *prefix)
 {
   register int key;
   char *keyname, *out;
@@ -1911,11 +2723,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
        {
        case ISMACR:
          keyname = _rl_get_keyname (key);
-#if 0
-         out = (char *)map[key].function;
-#else
-         out = _rl_untranslate_macro_value ((char *)map[key].function);
-#endif
+         out = _rl_untranslate_macro_value ((char *)map[key].function, 0);
+
          if (print_readably)
            fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
                                                         keyname,
@@ -1924,10 +2733,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
            fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",
                                                        keyname,
                                                        out ? out : "");
-         free (keyname);
-#if 1
-         free (out);
-#endif
+         xfree (keyname);
+         xfree (out);
          break;
        case ISFUNC:
          break;
@@ -1935,7 +2742,7 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
          prefix_len = prefix ? strlen (prefix) : 0;
          if (key == ESC)
            {
-             keyname = xmalloc (3 + prefix_len);
+             keyname = (char *)xmalloc (3 + prefix_len);
              if (prefix)
                strcpy (keyname, prefix);
              keyname[prefix_len] = '\\';
@@ -1947,31 +2754,29 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
              keyname = _rl_get_keyname (key);
              if (prefix)
                {
-                 out = xmalloc (strlen (keyname) + prefix_len + 1);
+                 out = (char *)xmalloc (strlen (keyname) + prefix_len + 1);
                  strcpy (out, prefix);
                  strcpy (out + prefix_len, keyname);
-                 free (keyname);
+                 xfree (keyname);
                  keyname = out;
                }
            }
 
          _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname);
-         free (keyname);
+         xfree (keyname);
          break;
        }
     }
 }
 
 void
-rl_macro_dumper (print_readably)
-     int print_readably;
+rl_macro_dumper (int print_readably)
 {
   _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL);
 }
 
 int
-rl_dump_macros (count, key)
-     int count, key;
+rl_dump_macros (int count, int key)
 {
   if (rl_dispatching)
     fprintf (rl_outstream, "\r\n");
@@ -1980,12 +2785,91 @@ rl_dump_macros (count, key)
   return (0);
 }
 
+static char *
+_rl_get_string_variable_value (const char *name)
+{
+  static char numbuf[32];
+  char *ret;
+
+  if (_rl_stricmp (name, "bell-style") == 0)
+    {
+      switch (_rl_bell_preference)
+       {
+         case NO_BELL:
+           return "none";
+         case VISIBLE_BELL:
+           return "visible";
+         case AUDIBLE_BELL:
+         default:
+           return "audible";
+       }
+    }
+  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, 0);
+      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 if (_rl_stricmp (name, "keyseq-timeout") == 0)
+    {
+      sprintf (numbuf, "%d", _rl_keyseq_timeout);    
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "emacs-mode-string") == 0)
+    return (_rl_emacs_mode_str ? _rl_emacs_mode_str : RL_EMACS_MODESTR_DEFAULT);
+  else if (_rl_stricmp (name, "vi-cmd-mode-string") == 0)
+    return (_rl_vi_cmd_mode_str ? _rl_vi_cmd_mode_str : RL_VI_CMD_MODESTR_DEFAULT);
+  else if (_rl_stricmp (name, "vi-ins-mode-string") == 0)
+    return (_rl_vi_ins_mode_str ? _rl_vi_ins_mode_str : RL_VI_INS_MODESTR_DEFAULT);
+  else
+    return (0);
+}
+
 void
-rl_variable_dumper (print_readably)
-     int print_readably;
+rl_variable_dumper (int print_readably)
 {
   int i;
-  char *kname;
+  char *v;
 
   for (i = 0; boolean_varlist[i].name; i++)
     {
@@ -1997,62 +2881,15 @@ rl_variable_dumper (print_readably)
                               *boolean_varlist[i].value ? "on" : "off");
     }
 
-  /* bell-style */
-  switch (_rl_bell_preference)
-    {
-    case NO_BELL:
-      kname = "none"; break;
-    case VISIBLE_BELL:
-      kname = "visible"; break;
-    case AUDIBLE_BELL:
-    default:
-      kname = "audible"; break;
-    }
-  if (print_readably)
-    fprintf (rl_outstream, "set bell-style %s\n", kname);
-  else
-    fprintf (rl_outstream, "bell-style is set to `%s'\n", kname);
-
-  /* comment-begin */
-  if (print_readably)
-    fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT);
-  else
-    fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : "");
-
-  /* completion-query-items */
-  if (print_readably)
-    fprintf (rl_outstream, "set completion-query-items %d\n", rl_completion_query_items);
-  else
-    fprintf (rl_outstream, "completion-query-items is set to `%d'\n", rl_completion_query_items);
-
-  /* editing-mode */
-  if (print_readably)
-    fprintf (rl_outstream, "set editing-mode %s\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi");
-  else
-    fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi");
-
-  /* keymap */
-  kname = rl_get_keymap_name (_rl_keymap);
-  if (kname == 0)
-    kname = rl_get_keymap_name_from_edit_mode ();
-  if (print_readably)
-    fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none");
-  else
-    fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none");
-
-  /* isearch-terminators */
-  if (_rl_isearch_terminators)
+  for (i = 0; string_varlist[i].name; i++)
     {
-      char *disp;
-
-      disp = _rl_untranslate_macro_value (_rl_isearch_terminators);
-
+      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 isearch-terminators \"%s\"\n", disp);
+        fprintf (rl_outstream, "set %s %s\n", string_varlist[i].name, v);
       else
-       fprintf (rl_outstream, "isearch-terminators is set to \"%s\"\n", disp);
-
-      free (disp);
+        fprintf (rl_outstream, "%s is set to `%s'\n", string_varlist[i].name, v);
     }
 }
 
@@ -2060,8 +2897,7 @@ rl_variable_dumper (print_readably)
    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;
+rl_dump_variables (int count, int key)
 {
   if (rl_dispatching)
     fprintf (rl_outstream, "\r\n");
@@ -2070,26 +2906,9 @@ rl_dump_variables (count, key)
   return (0);
 }
 
-/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */
-void
-_rl_bind_if_unbound (keyseq, default_func)
-     char *keyseq;
-     Function *default_func;
-{
-  Function *func;
-
-  if (keyseq)
-    {
-      func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL);
-      if (!func || func == rl_do_lowercase_version)
-       rl_set_key (keyseq, default_func, _rl_keymap);
-    }
-}
-
 /* Return non-zero if any members of ARRAY are a substring in STRING. */
 static int
-substring_member_of_array (string, array)
-     char *string, **array;
+substring_member_of_array (const char *string, const char * const *array)
 {
   while (*array)
     {