Cleanup process.c.
[bpt/emacs.git] / src / keymap.c
index 2edad90..175c39c 100644 (file)
@@ -1,14 +1,14 @@
 /* Manipulation of keymaps
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
                  1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs 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, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,19 +16,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include <config.h>
 #include <stdio.h>
-#if HAVE_ALLOCA_H
-# include <alloca.h>
-#endif
+#include <setjmp.h>
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
+#include "character.h"
 #include "charset.h"
 #include "keyboard.h"
 #include "frame.h"
@@ -75,7 +72,7 @@ Lisp_Object Vminibuffer_local_filename_completion_map;
 
 /* keymap used for minibuffers when doing completion in filenames
    with require-match*/
-Lisp_Object Vminibuffer_local_must_match_filename_map;
+Lisp_Object Vminibuffer_local_filename_must_match_map;
 
 /* keymap used for minibuffers when doing completion and require a match */
 /* was MinibufLocalMustMatchMap */
@@ -98,6 +95,7 @@ Lisp_Object Vemulation_mode_map_alists;
 Lisp_Object Vdefine_key_rebound_commands;
 
 Lisp_Object Qkeymapp, Qkeymap, Qnon_ascii, Qmenu_item, Qremap;
+Lisp_Object QCadvertised_binding;
 
 /* Alist of elements like (DEL . "\d").  */
 static Lisp_Object exclude_keys;
@@ -105,32 +103,25 @@ static Lisp_Object exclude_keys;
 /* Pre-allocated 2-element vector for Fcommand_remapping to use.  */
 static Lisp_Object command_remapping_vector;
 
-/* A char with the CHAR_META bit set in a vector or the 0200 bit set
-   in a string key sequence is equivalent to prefixing with this
-   character.  */
-extern Lisp_Object meta_prefix_char;
-
-extern Lisp_Object Voverriding_local_map;
-
 /* Hash table used to cache a reverse-map to speed up calls to where-is.  */
 static Lisp_Object where_is_cache;
 /* Which keymaps are reverse-stored in the cache.  */
 static Lisp_Object where_is_cache_keymaps;
 
-static Lisp_Object store_in_keymap P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
-static void fix_submap_inheritance P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
-
-static Lisp_Object define_as_prefix P_ ((Lisp_Object, Lisp_Object));
-static void describe_command P_ ((Lisp_Object, Lisp_Object));
-static void describe_translation P_ ((Lisp_Object, Lisp_Object));
-static void describe_map P_ ((Lisp_Object, Lisp_Object,
-                             void (*) P_ ((Lisp_Object, Lisp_Object)),
-                             int, Lisp_Object, Lisp_Object*, int, int));
-static void describe_vector P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
-                                void (*) (Lisp_Object, Lisp_Object), int,
-                                Lisp_Object, Lisp_Object, int *,
-                                int, int, int));
-static void silly_event_symbol_error P_ ((Lisp_Object));
+static Lisp_Object store_in_keymap (Lisp_Object, Lisp_Object, Lisp_Object);
+static void fix_submap_inheritance (Lisp_Object, Lisp_Object, Lisp_Object);
+
+static Lisp_Object define_as_prefix (Lisp_Object, Lisp_Object);
+static void describe_command (Lisp_Object, Lisp_Object);
+static void describe_translation (Lisp_Object, Lisp_Object);
+static void describe_map (Lisp_Object, Lisp_Object,
+                          void (*) (Lisp_Object, Lisp_Object),
+                         int, Lisp_Object, Lisp_Object*, int, int);
+static void describe_vector (Lisp_Object, Lisp_Object, Lisp_Object,
+                             void (*) (Lisp_Object, Lisp_Object), int,
+                             Lisp_Object, Lisp_Object, int *,
+                             int, int, int);
+static void silly_event_symbol_error (Lisp_Object);
 \f
 /* Keymap object support - constructors and predicates.                        */
 
@@ -144,8 +135,7 @@ input stream.  Initially, ALIST is nil.
 
 The optional arg STRING supplies a menu name for the keymap
 in case you use it as a menu with `x-popup-menu'.  */)
-     (string)
-     Lisp_Object string;
+  (Lisp_Object string)
 {
   Lisp_Object tail;
   if (!NILP (string))
@@ -165,11 +155,14 @@ Initially the alist is nil.
 
 The optional arg STRING supplies a menu name for the keymap
 in case you use it as a menu with `x-popup-menu'.  */)
-     (string)
-     Lisp_Object string;
+  (Lisp_Object string)
 {
   if (!NILP (string))
-    return Fcons (Qkeymap, Fcons (string, Qnil));
+    {
+      if (!NILP (Vpurify_flag))
+       string = Fpurecopy (string);
+      return Fcons (Qkeymap, Fcons (string, Qnil));
+    }
   return Fcons (Qkeymap, Qnil);
 }
 
@@ -181,21 +174,15 @@ in case you use it as a menu with `x-popup-menu'.  */)
    initial_define_key (control_x_map, Ctl('X'), "exchange-point-and-mark");  */
 
 void
-initial_define_key (keymap, key, defname)
-     Lisp_Object keymap;
-     int key;
-     char *defname;
+initial_define_key (Lisp_Object keymap, int key, char *defname)
 {
-  store_in_keymap (keymap, make_number (key), intern (defname));
+  store_in_keymap (keymap, make_number (key), intern_c_string (defname));
 }
 
 void
-initial_define_lispy_key (keymap, keyname, defname)
-     Lisp_Object keymap;
-     char *keyname;
-     char *defname;
+initial_define_lispy_key (Lisp_Object keymap, char *keyname, char *defname)
 {
-  store_in_keymap (keymap, intern (keyname), intern (defname));
+  store_in_keymap (keymap, intern_c_string (keyname), intern_c_string (defname));
 }
 
 DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
@@ -206,8 +193,7 @@ or a symbol whose function definition is itself a keymap.
 ALIST elements look like (CHAR . DEFN) or (SYMBOL . DEFN);
 a vector of densely packed bindings for small character codes
 is also allowed as an element.  */)
-     (object)
-     Lisp_Object object;
+  (Lisp_Object object)
 {
   return (KEYMAPP (object) ? Qt : Qnil);
 }
@@ -216,8 +202,7 @@ DEFUN ("keymap-prompt", Fkeymap_prompt, Skeymap_prompt, 1, 1, 0,
        doc: /* Return the prompt-string of a keymap MAP.
 If non-nil, the prompt is shown in the echo-area
 when reading a key-sequence to be looked-up in this keymap.  */)
-     (map)
-     Lisp_Object map;
+  (Lisp_Object map)
 {
   map = get_keymap (map, 0, 0);
   while (CONSP (map))
@@ -253,9 +238,7 @@ when reading a key-sequence to be looked-up in this keymap.  */)
    do_autoload which can GC.  */
 
 Lisp_Object
-get_keymap (object, error, autoload)
-     Lisp_Object object;
-     int error, autoload;
+get_keymap (Lisp_Object object, int error, int autoload)
 {
   Lisp_Object tem;
 
@@ -292,7 +275,7 @@ get_keymap (object, error, autoload)
                  goto autoload_retry;
                }
              else
-               return Qt;
+               return object;
            }
        }
     }
@@ -307,9 +290,7 @@ get_keymap (object, error, autoload)
    We assume that KEYMAP is a valid keymap.  */
 
 Lisp_Object
-keymap_parent (keymap, autoload)
-     Lisp_Object keymap;
-     int autoload;
+keymap_parent (Lisp_Object keymap, int autoload)
 {
   Lisp_Object list;
 
@@ -328,17 +309,16 @@ keymap_parent (keymap, autoload)
 }
 
 DEFUN ("keymap-parent", Fkeymap_parent, Skeymap_parent, 1, 1, 0,
-       doc: /* Return the parent keymap of KEYMAP.  */)
-     (keymap)
-     Lisp_Object keymap;
+       doc: /* Return the parent keymap of KEYMAP.
+If KEYMAP has no parent, return nil.  */)
+  (Lisp_Object keymap)
 {
   return keymap_parent (keymap, 1);
 }
 
 /* Check whether MAP is one of MAPS parents.  */
 int
-keymap_memberp (map, maps)
-     Lisp_Object map, maps;
+keymap_memberp (Lisp_Object map, Lisp_Object maps)
 {
   if (NILP (map)) return 0;
   while (KEYMAPP (maps) && !EQ (map, maps))
@@ -351,8 +331,7 @@ keymap_memberp (map, maps)
 DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
        doc: /* Modify KEYMAP to set its parent map to PARENT.
 Return PARENT.  PARENT should be nil or another keymap.  */)
-     (keymap, parent)
-     Lisp_Object keymap, parent;
+  (Lisp_Object keymap, Lisp_Object parent)
 {
   Lisp_Object list, prev;
   struct gcpro gcpro1, gcpro2;
@@ -422,11 +401,7 @@ Return PARENT.  PARENT should be nil or another keymap.  */)
 
       if (CHAR_TABLE_P (XCAR (list)))
        {
-         int indices[3];
-
-         map_char_table (fix_submap_inheritance, Qnil,
-                         XCAR (list), XCAR (list),
-                         keymap, 0, indices);
+         map_char_table (fix_submap_inheritance, Qnil, XCAR (list), keymap);
        }
     }
 
@@ -438,8 +413,7 @@ Return PARENT.  PARENT should be nil or another keymap.  */)
    make sure that SUBMAP inherits that definition as its own parent.  */
 
 static void
-fix_submap_inheritance (map, event, submap)
-     Lisp_Object map, event, submap;
+fix_submap_inheritance (Lisp_Object map, Lisp_Object event, Lisp_Object submap)
 {
   Lisp_Object map_parent, parent_entry;
 
@@ -501,12 +475,7 @@ fix_submap_inheritance (map, event, submap)
    If NOINHERIT, don't accept a subkeymap found in an inherited keymap.  */
 
 Lisp_Object
-access_keymap (map, idx, t_ok, noinherit, autoload)
-     Lisp_Object map;
-     Lisp_Object idx;
-     int t_ok;
-     int noinherit;
-     int autoload;
+access_keymap (Lisp_Object map, Lisp_Object idx, int t_ok, int noinherit, int autoload)
 {
   Lisp_Object val;
 
@@ -566,11 +535,6 @@ access_keymap (map, idx, t_ok, noinherit, autoload)
 
     GCPRO4 (map, tail, idx, t_binding);
 
-    /* If `t_ok' is 2, both `t' and generic-char bindings are accepted.
-       If it is 1, only generic-char bindings are accepted.
-       Otherwise, neither are.  */
-    t_ok = t_ok ? 2 : 0;
-
     for (tail = XCDR (map);
         (CONSP (tail)
          || (tail = get_keymap (tail, 0, autoload), CONSP (tail)));
@@ -592,29 +556,11 @@ access_keymap (map, idx, t_ok, noinherit, autoload)
 
            if (EQ (key, idx))
              val = XCDR (binding);
-           else if (t_ok
-                    && INTEGERP (idx)
-                    && (XINT (idx) & CHAR_MODIFIER_MASK) == 0
-                    && INTEGERP (key)
-                    && (XINT (key) & CHAR_MODIFIER_MASK) == 0
-                    && !SINGLE_BYTE_CHAR_P (XINT (idx))
-                    && !SINGLE_BYTE_CHAR_P (XINT (key))
-                    && CHAR_VALID_P (XINT (key), 1)
-                    && !CHAR_VALID_P (XINT (key), 0)
-                    && (CHAR_CHARSET (XINT (key))
-                        == CHAR_CHARSET (XINT (idx))))
+           else if (t_ok && EQ (key, Qt))
              {
-               /* KEY is the generic character of the charset of IDX.
-                  Use KEY's binding if there isn't a binding for IDX
-                  itself.  */
                t_binding = XCDR (binding);
                t_ok = 0;
              }
-           else if (t_ok > 1 && EQ (key, Qt))
-             {
-               t_binding = XCDR (binding);
-               t_ok = 1;
-             }
          }
        else if (VECTORP (binding))
          {
@@ -658,10 +604,7 @@ access_keymap (map, idx, t_ok, noinherit, autoload)
 }
 
 static void
-map_keymap_item (fun, args, key, val, data)
-     map_keymap_function_t fun;
-     Lisp_Object args, key, val;
-     void *data;
+map_keymap_item (map_keymap_function_t fun, Lisp_Object args, Lisp_Object key, Lisp_Object val, void *data)
 {
   /* We should maybe try to detect bindings shadowed by previous
      ones and things like that.  */
@@ -671,37 +614,35 @@ map_keymap_item (fun, args, key, val, data)
 }
 
 static void
-map_keymap_char_table_item (args, key, val)
-     Lisp_Object args, key, val;
+map_keymap_char_table_item (Lisp_Object args, Lisp_Object key, Lisp_Object val)
 {
   if (!NILP (val))
     {
       map_keymap_function_t fun = XSAVE_VALUE (XCAR (args))->pointer;
       args = XCDR (args);
+      /* If the key is a range, make a copy since map_char_table modifies
+        it in place.  */
+      if (CONSP (key))
+       key = Fcons (XCAR (key), XCDR (key));
       map_keymap_item (fun, XCDR (args), key, val,
                       XSAVE_VALUE (XCAR (args))->pointer);
     }
 }
 
-/* Call FUN for every binding in MAP.
-   FUN is called with 4 arguments: FUN (KEY, BINDING, ARGS, DATA).
-   AUTOLOAD if non-zero means that we can autoload keymaps if necessary.  */
-void
-map_keymap (map, fun, args, data, autoload)
-     map_keymap_function_t fun;
-     Lisp_Object map, args;
-     void *data;
-     int autoload;
+/* Call FUN for every binding in MAP and stop at (and return) the parent.
+   FUN is called with 4 arguments: FUN (KEY, BINDING, ARGS, DATA).  */
+Lisp_Object
+map_keymap_internal (Lisp_Object map,
+                    map_keymap_function_t fun,
+                    Lisp_Object args,
+                    void *data)
 {
   struct gcpro gcpro1, gcpro2, gcpro3;
-  Lisp_Object tail;
+  Lisp_Object tail
+    = (CONSP (map) && EQ (Qkeymap, XCAR (map))) ? XCDR (map) : map;
 
-  tail = Qnil;
   GCPRO3 (map, args, tail);
-  map = get_keymap (map, 1, autoload);
-  for (tail = (CONSP (map) && EQ (Qkeymap, XCAR (map))) ? XCDR (map) : map;
-       CONSP (tail) || (tail = get_keymap (tail, 0, autoload), CONSP (tail));
-       tail = XCDR (tail))
+  for (; CONSP (tail) && !EQ (Qkeymap, XCAR (tail)); tail = XCDR (tail))
     {
       Lisp_Object binding = XCAR (tail);
 
@@ -721,46 +662,83 @@ map_keymap (map, fun, args, data, autoload)
        }
       else if (CHAR_TABLE_P (binding))
        {
-         int indices[3];
-         map_char_table (map_keymap_char_table_item, Qnil, binding, binding,
+         map_char_table (map_keymap_char_table_item, Qnil, binding,
                          Fcons (make_save_value (fun, 0),
                                 Fcons (make_save_value (data, 0),
-                                       args)),
-                         0, indices);
+                                       args)));
        }
     }
   UNGCPRO;
+  return tail;
 }
 
 static void
-map_keymap_call (key, val, fun, dummy)
-     Lisp_Object key, val, fun;
-     void *dummy;
+map_keymap_call (Lisp_Object key, Lisp_Object val, Lisp_Object fun, void *dummy)
 {
   call2 (fun, key, val);
 }
 
+/* Same as map_keymap_internal, but doesn't traverses parent keymaps as well.
+   A non-zero AUTOLOAD indicates that autoloaded keymaps should be loaded.  */
+void
+map_keymap (Lisp_Object map, map_keymap_function_t fun, Lisp_Object args, void *data, int autoload)
+{
+  struct gcpro gcpro1;
+  GCPRO1 (args);
+  map = get_keymap (map, 1, autoload);
+  while (CONSP (map))
+    {
+      map = map_keymap_internal (map, fun, args, data);
+      map = get_keymap (map, 0, autoload);
+    }
+  UNGCPRO;
+}
+
+Lisp_Object Qkeymap_canonicalize;
+
+/* Same as map_keymap, but does it right, properly eliminating duplicate
+   bindings due to inheritance.   */
+void
+map_keymap_canonical (Lisp_Object map, map_keymap_function_t fun, Lisp_Object args, void *data)
+{
+  struct gcpro gcpro1;
+  GCPRO1 (args);
+  /* map_keymap_canonical may be used from redisplay (e.g. when building menus)
+     so be careful to ignore errors and to inhibit redisplay.  */
+  map = safe_call1 (Qkeymap_canonicalize, map);
+  /* No need to use `map_keymap' here because canonical map has no parent.  */
+  map_keymap_internal (map, fun, args, data);
+  UNGCPRO;
+}
+
+DEFUN ("map-keymap-internal", Fmap_keymap_internal, Smap_keymap_internal, 2, 2, 0,
+       doc: /* Call FUNCTION once for each event binding in KEYMAP.
+FUNCTION is called with two arguments: the event that is bound, and
+the definition it is bound to.  The event may be a character range.
+If KEYMAP has a parent, this function returns it without processing it.  */)
+  (Lisp_Object function, Lisp_Object keymap)
+{
+  struct gcpro gcpro1;
+  GCPRO1 (function);
+  keymap = get_keymap (keymap, 1, 1);
+  keymap = map_keymap_internal (keymap, map_keymap_call, function, NULL);
+  UNGCPRO;
+  return keymap;
+}
+
 DEFUN ("map-keymap", Fmap_keymap, Smap_keymap, 2, 3, 0,
        doc: /* Call FUNCTION once for each event binding in KEYMAP.
 FUNCTION is called with two arguments: the event that is bound, and
-the definition it is bound to.  If the event is an integer, it may be
-a generic character (see Info node `(elisp)Splitting Characters'), and
-that means that all actual character events belonging to that generic
-character are bound to the definition.
+the definition it is bound to.  The event may be a character range.
 
 If KEYMAP has a parent, the parent's bindings are included as well.
 This works recursively: if the parent has itself a parent, then the
 grandparent's bindings are also included and so on.
 usage: (map-keymap FUNCTION KEYMAP)  */)
-     (function, keymap, sort_first)
-     Lisp_Object function, keymap, sort_first;
+  (Lisp_Object function, Lisp_Object keymap, Lisp_Object sort_first)
 {
-  if (INTEGERP (function))
-    /* We have to stop integers early since map_keymap gives them special
-       significance.  */
-    xsignal1 (Qinvalid_function, function);
   if (! NILP (sort_first))
-    return call3 (intern ("map-keymap-internal"), function, keymap, Qt);
+    return call2 (intern ("map-keymap-sorted"), function, keymap);
 
   map_keymap (keymap, map_keymap_call, function, NULL, 1);
   return Qnil;
@@ -781,9 +759,7 @@ usage: (map-keymap FUNCTION KEYMAP)  */)
    This can GC because menu_item_eval_property calls Feval.  */
 
 Lisp_Object
-get_keyelt (object, autoload)
-     Lisp_Object object;
-     int autoload;
+get_keyelt (Lisp_Object object, int autoload)
 {
   while (1)
     {
@@ -863,10 +839,7 @@ get_keyelt (object, autoload)
 }
 
 static Lisp_Object
-store_in_keymap (keymap, idx, def)
-     Lisp_Object keymap;
-     register Lisp_Object idx;
-     Lisp_Object def;
+store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 {
   /* Flush any reverse-map cache.  */
   where_is_cache = Qnil;
@@ -881,10 +854,15 @@ store_in_keymap (keymap, idx, def)
   if (!CONSP (keymap) || !EQ (XCAR (keymap), Qkeymap))
     error ("attempt to define a key in a non-keymap");
 
-  /* If idx is a list (some sort of mouse click, perhaps?),
-     the index we want to use is the car of the list, which
-     ought to be a symbol.  */
-  idx = EVENT_HEAD (idx);
+  /* If idx is a cons, and the car part is a character, idx must be of
+     the form (FROM-CHAR . TO-CHAR).  */
+  if (CONSP (idx) && CHARACTERP (XCAR (idx)))
+    CHECK_CHARACTER_CDR (idx);
+  else
+    /* If idx is a list (some sort of mouse click, perhaps?),
+       the index we want to use is the car of the list, which
+       ought to be a symbol.  */
+    idx = EVENT_HEAD (idx);
 
   /* If idx is a symbol, it might have modifiers, which need to
      be put in the canonical order.  */
@@ -921,6 +899,19 @@ store_in_keymap (keymap, idx, def)
                ASET (elt, XFASTINT (idx), def);
                return def;
              }
+           else if (CONSP (idx) && CHARACTERP (XCAR (idx)))
+             {
+               int from = XFASTINT (XCAR (idx));
+               int to = XFASTINT (XCDR (idx));
+
+               if (to >= ASIZE (elt))
+                 to = ASIZE (elt) - 1;
+               for (; from <= to; from++)
+                 ASET (elt, from, def);
+               if (to == XFASTINT (XCDR (idx)))
+                 /* We have defined all keys in IDX.  */
+                 return def;
+             }
            insertion_point = tail;
          }
        else if (CHAR_TABLE_P (elt))
@@ -937,6 +928,11 @@ store_in_keymap (keymap, idx, def)
                       NILP (def) ? Qt : def);
                return def;
              }
+           else if (CONSP (idx) && CHARACTERP (XCAR (idx)))
+             {
+               Fset_char_table_range (elt, idx, NILP (def) ? Qt : def);
+               return def;
+             }
            insertion_point = tail;
          }
        else if (CONSP (elt))
@@ -947,6 +943,19 @@ store_in_keymap (keymap, idx, def)
                XSETCDR (elt, def);
                return def;
              }
+           else if (CONSP (idx) && CHARACTERP (XCAR (idx)))
+             {
+               int from = XFASTINT (XCAR (idx));
+               int to = XFASTINT (XCDR (idx));
+
+               if (from <= XFASTINT (XCAR (elt))
+                   && to >= XFASTINT (XCAR (elt)))
+                 {
+                   XSETCDR (elt, def);
+                   if (from == to)
+                     return def;
+                 }
+             }
          }
        else if (EQ (elt, Qkeymap))
          /* If we find a 'keymap' symbol in the spine of KEYMAP,
@@ -961,9 +970,22 @@ store_in_keymap (keymap, idx, def)
   keymap_end:
     /* We have scanned the entire keymap, and not found a binding for
        IDX.  Let's add one.  */
-    CHECK_IMPURE (insertion_point);
-    XSETCDR (insertion_point,
-            Fcons (Fcons (idx, def), XCDR (insertion_point)));
+    {
+      Lisp_Object elt;
+
+      if (CONSP (idx) && CHARACTERP (XCAR (idx)))
+       {
+         /* IDX specifies a range of characters, and not all of them
+            were handled yet, which means this keymap doesn't have a
+            char-table.  So, we insert a char-table now.  */
+         elt = Fmake_char_table (Qkeymap, Qnil);
+         Fset_char_table_range (elt, idx, NILP (def) ? Qt : def);
+       }
+      else
+       elt = Fcons (idx, def);
+      CHECK_IMPURE (insertion_point);
+      XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
+    }
   }
 
   return def;
@@ -972,8 +994,7 @@ store_in_keymap (keymap, idx, def)
 EXFUN (Fcopy_keymap, 1);
 
 Lisp_Object
-copy_keymap_item (elt)
-     Lisp_Object elt;
+copy_keymap_item (Lisp_Object elt)
 {
   Lisp_Object res, tem;
 
@@ -1046,10 +1067,9 @@ copy_keymap_item (elt)
 }
 
 static void
-copy_keymap_1 (chartable, idx, elt)
-     Lisp_Object chartable, idx, elt;
+copy_keymap_1 (Lisp_Object chartable, Lisp_Object idx, Lisp_Object elt)
 {
-  Faset (chartable, idx, copy_keymap_item (elt));
+  Fset_char_table_range (chartable, idx, copy_keymap_item (elt));
 }
 
 DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0,
@@ -1059,8 +1079,7 @@ but changing either the copy or KEYMAP does not affect the other.
 Any key definitions that are subkeymaps are recursively copied.
 However, a key definition which is a symbol whose definition is a keymap
 is not copied.  */)
-     (keymap)
-     Lisp_Object keymap;
+  (Lisp_Object keymap)
 {
   register Lisp_Object copy, tail;
   keymap = get_keymap (keymap, 1, 0);
@@ -1072,9 +1091,8 @@ is not copied.  */)
       Lisp_Object elt = XCAR (keymap);
       if (CHAR_TABLE_P (elt))
        {
-         int indices[3];
          elt = Fcopy_sequence (elt);
-         map_char_table (copy_keymap_1, Qnil, elt, elt, elt, 0, indices);
+         map_char_table (copy_keymap_1, Qnil, elt, elt);
        }
       else if (VECTORP (elt))
        {
@@ -1101,11 +1119,13 @@ DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
        doc: /* In KEYMAP, define key sequence KEY as DEF.
 KEYMAP is a keymap.
 
-KEY is a string or a vector of symbols and characters meaning a
+KEY is a string or a vector of symbols and characters, representing a
 sequence of keystrokes and events.  Non-ASCII characters with codes
-above 127 (such as ISO Latin-1) can be included if you use a vector.
-Using [t] for KEY creates a default definition, which applies to any
-event type that has no other definition in this keymap.
+above 127 (such as ISO Latin-1) can be represented by vectors.
+Two types of vector have special meanings:
+ [remap COMMAND] remaps any key binding for COMMAND.
+ [t] creates a default definition, which applies to any event with no
+    other definition in KEYMAP.
 
 DEF is anything that can be a key's definition:
  nil (means key is undefined in this keymap),
@@ -1124,10 +1144,7 @@ DEF is anything that can be a key's definition:
 If KEYMAP is a sparse keymap with a binding for KEY, the existing
 binding is altered.  If there is no binding for KEY, the new pair
 binding KEY to DEF is added at the front of KEYMAP.  */)
-     (keymap, key, def)
-     Lisp_Object keymap;
-     Lisp_Object key;
-     Lisp_Object def;
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object def)
 {
   register int idx;
   register Lisp_Object c;
@@ -1171,8 +1188,15 @@ binding KEY to DEF is added at the front of KEYMAP.  */)
     {
       c = Faref (key, make_number (idx));
 
-      if (CONSP (c) && lucid_event_type_list_p (c))
-       c = Fevent_convert_list (c);
+      if (CONSP (c))
+       {
+         /* C may be a Lucid style event type list or a cons (FROM .
+            TO) specifying a range of characters.  */
+         if (lucid_event_type_list_p (c))
+           c = Fevent_convert_list (c);
+         else if (CHARACTERP (XCAR (c)))
+           CHECK_CHARACTER_CDR (c);
+       }
 
       if (SYMBOLP (c))
        silly_event_symbol_error (c);
@@ -1193,8 +1217,11 @@ binding KEY to DEF is added at the front of KEYMAP.  */)
          idx++;
        }
 
-      if (!INTEGERP (c) && !SYMBOLP (c) && !CONSP (c))
-       error ("Key sequence contains invalid event");
+      if (!INTEGERP (c) && !SYMBOLP (c)
+         && (!CONSP (c)
+             /* If C is a range, it must be a leaf.  */
+             || (INTEGERP (XCAR (c)) && idx != length)))
+       message_with_string ("Key sequence contains invalid event %s", c, 1);
 
       if (idx == length)
        RETURN_UNGCPRO (store_in_keymap (keymap, c, def));
@@ -1233,8 +1260,7 @@ ignored if POSITION is non-nil.
 If the optional argument KEYMAPS is non-nil, it should be a list of
 keymaps to search for command remapping.  Otherwise, search for the
 remapping in all currently active keymaps.  */)
-     (command, position, keymaps)
-     Lisp_Object command, position, keymaps;
+  (Lisp_Object command, Lisp_Object position, Lisp_Object keymaps)
 {
   if (!SYMBOLP (command))
     return Qnil;
@@ -1276,10 +1302,7 @@ bindings, used when nothing else in the keymap applies; this makes it
 usable as a general function for probing keymaps.  However, if the
 third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
 recognize the default bindings, just as `read-key-sequence' does.  */)
-     (keymap, key, accept_default)
-     Lisp_Object keymap;
-     Lisp_Object key;
-     Lisp_Object accept_default;
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   register int idx;
   register Lisp_Object cmd;
@@ -1312,7 +1335,7 @@ recognize the default bindings, just as `read-key-sequence' does.  */)
       /* Allow string since binding for `menu-bar-select-buffer'
         includes the buffer name in the key sequence.  */
       if (!INTEGERP (c) && !SYMBOLP (c) && !CONSP (c) && !STRINGP (c))
-       error ("Key sequence contains invalid event");
+       message_with_string ("Key sequence contains invalid event %s", c, 1);
 
       cmd = access_keymap (keymap, c, t_ok, 0, 1);
       if (idx == length)
@@ -1331,8 +1354,7 @@ recognize the default bindings, just as `read-key-sequence' does.  */)
    Return the keymap.  */
 
 static Lisp_Object
-define_as_prefix (keymap, c)
-     Lisp_Object keymap, c;
+define_as_prefix (Lisp_Object keymap, Lisp_Object c)
 {
   Lisp_Object cmd;
 
@@ -1349,8 +1371,7 @@ define_as_prefix (keymap, c)
 /* Append a key to the end of a key sequence.  We always make a vector.  */
 
 Lisp_Object
-append_key (key_sequence, key)
-     Lisp_Object key_sequence, key;
+append_key (Lisp_Object key_sequence, Lisp_Object key)
 {
   Lisp_Object args[2];
 
@@ -1364,8 +1385,7 @@ append_key (key_sequence, key)
    signal an error if is a mistake such as RET or M-RET or C-DEL, etc.  */
 
 static void
-silly_event_symbol_error (c)
-     Lisp_Object c;
+silly_event_symbol_error (Lisp_Object c)
 {
   Lisp_Object parsed, base, name, assoc;
   int modifiers;
@@ -1434,8 +1454,7 @@ static int cmm_size = 0;
    list, let the key sequence be read, and hope some other piece of
    code signals the error.  */
 int
-current_minor_maps (modeptr, mapptr)
-     Lisp_Object **modeptr, **mapptr;
+current_minor_maps (Lisp_Object **modeptr, Lisp_Object **mapptr)
 {
   int i = 0;
   int list_number = 0;
@@ -1494,7 +1513,8 @@ current_minor_maps (modeptr, mapptr)
                  {
                    if (cmm_modes)
                      {
-                       bcopy (cmm_modes, newmodes, cmm_size * sizeof cmm_modes[0]);
+                       memcpy (newmodes, cmm_modes,
+                               cmm_size * sizeof cmm_modes[0]);
                        free (cmm_modes);
                      }
                    cmm_modes = newmodes;
@@ -1505,7 +1525,8 @@ current_minor_maps (modeptr, mapptr)
                  {
                    if (cmm_maps)
                      {
-                       bcopy (cmm_maps, newmaps, cmm_size * sizeof cmm_maps[0]);
+                       memcpy (newmaps, cmm_maps,
+                               cmm_size * sizeof cmm_maps[0]);
                        free (cmm_maps);
                      }
                    cmm_maps = newmaps;
@@ -1539,8 +1560,7 @@ DEFUN ("current-active-maps", Fcurrent_active_maps, Scurrent_active_maps,
 OLP if non-nil indicates that we should obey `overriding-local-map' and
 `overriding-terminal-local-map'.  POSITION can specify a click position
 like in the respective argument of `key-binding'. */)
-    (olp, position)
-    Lisp_Object olp, position;
+  (Lisp_Object olp, Lisp_Object position)
 {
   int count = SPECPDL_INDEX ();
 
@@ -1549,13 +1569,13 @@ like in the respective argument of `key-binding'. */)
   /* If a mouse click position is given, our variables are based on
      the buffer clicked on, not the current buffer.  So we may have to
      switch the buffer here. */
-  
+
   if (CONSP (position))
     {
       Lisp_Object window;
-      
+
       window = POSN_WINDOW (position);
-         
+
       if (WINDOWP (window)
          && BUFFERP (XWINDOW (window)->buffer)
          && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
@@ -1567,14 +1587,14 @@ like in the respective argument of `key-binding'. */)
             would not be a problem here, but it is easier to keep
             things the same.
          */
-             
+
          record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
-         
+
          set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
        }
     }
 
-  keymaps = Fcons (current_global_map, Qnil);  
+  keymaps = Fcons (current_global_map, Qnil);
 
   if (!NILP (olp))
     {
@@ -1601,8 +1621,8 @@ like in the respective argument of `key-binding'. */)
       /* Get the buffer local maps, possibly overriden by text or
         overlay properties */
 
-      local_map = get_local_map (pt, current_buffer, Qlocal_map); 
-      keymap = get_local_map (pt, current_buffer, Qkeymap); 
+      local_map = get_local_map (pt, current_buffer, Qlocal_map);
+      keymap = get_local_map (pt, current_buffer, Qkeymap);
 
       if (CONSP (position))
        {
@@ -1610,7 +1630,7 @@ like in the respective argument of `key-binding'. */)
 
          /* For a mouse click, get the local text-property keymap
             of the place clicked on, rather than point.  */
-         
+
          if (POSN_INBUFFER_P (position))
            {
              Lisp_Object pos;
@@ -1621,7 +1641,7 @@ like in the respective argument of `key-binding'. */)
                {
                  local_map = get_local_map (XINT (pos),
                                             current_buffer, Qlocal_map);
-                 
+
                  keymap = get_local_map (XINT (pos),
                                          current_buffer, Qkeymap);
                }
@@ -1632,12 +1652,12 @@ like in the respective argument of `key-binding'. */)
             string displayed via the `display' property,
             consider `local-map' and `keymap' properties of
             that string.  */
-         
+
          if (string = POSN_STRING (position),
              (CONSP (string) && STRINGP (XCAR (string))))
            {
              Lisp_Object pos, map;
-             
+
              pos = XCDR (string);
              string = XCAR (string);
              if (INTEGERP (pos)
@@ -1653,7 +1673,7 @@ like in the respective argument of `key-binding'. */)
                    keymap = map;
                }
            }
-         
+
        }
 
       if (!NILP (local_map))
@@ -1703,8 +1723,7 @@ occurs in the keymaps associated with it instead of KEY.  It can also
 be a number or marker, in which case the keymap properties at the
 specified buffer position instead of point are used.
   */)
-    (key, accept_default, no_remap, position)
-    Lisp_Object key, accept_default, no_remap, position;
+  (Lisp_Object key, Lisp_Object accept_default, Lisp_Object no_remap, Lisp_Object position)
 {
   Lisp_Object *maps, value;
   int nmaps, i;
@@ -1894,8 +1913,7 @@ The binding is probably a symbol with a function definition.
 
 If optional argument ACCEPT-DEFAULT is non-nil, recognize default
 bindings; see the description of `lookup-key' for more details about this.  */)
-     (keys, accept_default)
-     Lisp_Object keys, accept_default;
+  (Lisp_Object keys, Lisp_Object accept_default)
 {
   register Lisp_Object map;
   map = current_buffer->keymap;
@@ -1915,8 +1933,7 @@ This function's return values are the same as those of `lookup-key'
 
 If optional argument ACCEPT-DEFAULT is non-nil, recognize default
 bindings; see the description of `lookup-key' for more details about this.  */)
-     (keys, accept_default)
-     Lisp_Object keys, accept_default;
+  (Lisp_Object keys, Lisp_Object accept_default)
 {
   return Flookup_key (current_global_map, keys, accept_default);
 }
@@ -1935,8 +1952,7 @@ that come after prefix bindings.
 
 If optional argument ACCEPT-DEFAULT is non-nil, recognize default
 bindings; see the description of `lookup-key' for more details about this.  */)
-     (key, accept_default)
-     Lisp_Object key, accept_default;
+  (Lisp_Object key, Lisp_Object accept_default)
 {
   Lisp_Object *modes, *maps;
   int nmaps;
@@ -1975,8 +1991,7 @@ as a function.
 The third optional argument NAME, if given, supplies a menu name
 string for the map.  This is required to use the keymap as a menu.
 This function returns COMMAND.  */)
-     (command, mapvar, name)
-     Lisp_Object command, mapvar, name;
+  (Lisp_Object command, Lisp_Object mapvar, Lisp_Object name)
 {
   Lisp_Object map;
   map = Fmake_sparse_keymap (name);
@@ -1990,8 +2005,7 @@ This function returns COMMAND.  */)
 
 DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0,
        doc: /* Select KEYMAP as the global keymap.  */)
-     (keymap)
-     Lisp_Object keymap;
+  (Lisp_Object keymap)
 {
   keymap = get_keymap (keymap, 1, 1);
   current_global_map = keymap;
@@ -2002,8 +2016,7 @@ DEFUN ("use-global-map", Fuse_global_map, Suse_global_map, 1, 1, 0,
 DEFUN ("use-local-map", Fuse_local_map, Suse_local_map, 1, 1, 0,
        doc: /* Select KEYMAP as the local keymap.
 If KEYMAP is nil, that means no local keymap.  */)
-     (keymap)
-     Lisp_Object keymap;
+  (Lisp_Object keymap)
 {
   if (!NILP (keymap))
     keymap = get_keymap (keymap, 1, 1);
@@ -2014,22 +2027,23 @@ If KEYMAP is nil, that means no local keymap.  */)
 }
 
 DEFUN ("current-local-map", Fcurrent_local_map, Scurrent_local_map, 0, 0, 0,
-       doc: /* Return current buffer's local keymap, or nil if it has none.  */)
-     ()
+       doc: /* Return current buffer's local keymap, or nil if it has none.
+Normally the local keymap is set by the major mode with `use-local-map'.  */)
+  (void)
 {
   return current_buffer->keymap;
 }
 
 DEFUN ("current-global-map", Fcurrent_global_map, Scurrent_global_map, 0, 0, 0,
        doc: /* Return the current global keymap.  */)
-     ()
+  (void)
 {
   return current_global_map;
 }
 
 DEFUN ("current-minor-mode-maps", Fcurrent_minor_mode_maps, Scurrent_minor_mode_maps, 0, 0, 0,
        doc: /* Return a list of keymaps for the minor modes of the current buffer.  */)
-     ()
+  (void)
 {
   Lisp_Object *maps;
   int nmaps = current_minor_maps (0, &maps);
@@ -2046,10 +2060,8 @@ struct accessible_keymaps_data {
 };
 
 static void
-accessible_keymaps_1 (key, cmd, args, data)
-     Lisp_Object key, cmd, args;
-     /* Use void* to be compatible with map_keymap_function_t.  */
-     void *data;
+accessible_keymaps_1 (Lisp_Object key, Lisp_Object cmd, Lisp_Object args, void *data)
+/* Use void* data to be compatible with map_keymap_function_t.  */
 {
   struct accessible_keymaps_data *d = data; /* Cast! */
   Lisp_Object maps = d->maps;
@@ -2119,8 +2131,7 @@ KEYS starting from KEYMAP gets you to MAP.  These elements are ordered
 so that the KEYS increase in length.  The first element is ([] . KEYMAP).
 An optional argument PREFIX, if non-nil, should be a key sequence;
 then the value includes only maps for prefixes that start with PREFIX.  */)
-     (keymap, prefix)
-     Lisp_Object keymap, prefix;
+  (Lisp_Object keymap, Lisp_Object prefix)
 {
   Lisp_Object maps, tail;
   int prefixlen = XINT (Flength (prefix));
@@ -2208,8 +2219,7 @@ DEFUN ("key-description", Fkey_description, Skey_description, 1, 2, 0,
 Optional arg PREFIX is the sequence of keys leading up to KEYS.
 Control characters turn into "C-foo" sequences, meta into "M-foo",
 spaces are put between sequence elements, etc.  */)
-  (keys, prefix)
-     Lisp_Object keys, prefix;
+  (Lisp_Object keys, Lisp_Object prefix)
 {
   int len = 0;
   int i, i_byte;
@@ -2270,7 +2280,7 @@ spaces are put between sequence elements, etc.  */)
        }
       else if (VECTORP (list))
        {
-         key = AREF (list, i++);
+         key = AREF (list, i); i++;
        }
       else
        {
@@ -2307,21 +2317,16 @@ spaces are put between sequence elements, etc.  */)
 
 
 char *
-push_key_description (c, p, force_multibyte)
-     register unsigned int c;
-     register char *p;
-     int force_multibyte;
+push_key_description (register unsigned int c, register char *p, int force_multibyte)
 {
   unsigned c2;
-  int valid_p;
 
   /* Clear all the meaningless bits above the meta bit.  */
   c &= meta_modifier | ~ - meta_modifier;
   c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier
             | meta_modifier | shift_modifier | super_modifier);
 
-  valid_p = SINGLE_BYTE_CHAR_P (c2) || char_valid_p (c2, 0);
-  if (! valid_p)
+  if (! CHARACTERP (make_number (c2)))
     {
       /* KEY_DESCRIPTION_SIZE is large enough for this.  */
       p += sprintf (p, "[%d]", c);
@@ -2415,25 +2420,12 @@ push_key_description (c, p, force_multibyte)
     }
   else
     {
-      if (force_multibyte)
-       {
-         if (SINGLE_BYTE_CHAR_P (c))
-           c = unibyte_char_to_multibyte (c);
-         p += CHAR_STRING (c, p);
-       }
-      else if (NILP (current_buffer->enable_multibyte_characters))
-       {
-         int bit_offset;
-         *p++ = '\\';
-         /* The biggest character code uses 19 bits.  */
-         for (bit_offset = 18; bit_offset >= 0; bit_offset -= 3)
-           {
-             if (c >= (1 << bit_offset))
-               *p++ = ((c & (7 << bit_offset)) >> bit_offset) + '0';
-           }
-       }
+      /* Now we are sure that C is a valid character code.  */
+      if (NILP (current_buffer->enable_multibyte_characters)
+         && ! force_multibyte)
+       *p++ = multibyte_char_to_unibyte (c, Qnil);
       else
-       p += CHAR_STRING (c, p);
+       p += CHAR_STRING (c, (unsigned char *) p);
     }
 
   return p;
@@ -2447,8 +2439,7 @@ DEFUN ("single-key-description", Fsingle_key_description,
 Control characters turn into C-whatever, etc.
 Optional argument NO-ANGLES non-nil means don't put angle brackets
 around function keys and event symbols.  */)
-     (key, no_angles)
-     Lisp_Object key, no_angles;
+  (Lisp_Object key, Lisp_Object no_angles)
 {
   if (CONSP (key) && lucid_event_type_list_p (key))
     key = Fevent_convert_list (key);
@@ -2457,56 +2448,10 @@ around function keys and event symbols.  */)
 
   if (INTEGERP (key))          /* Normal character */
     {
-      unsigned int charset, c1, c2;
-      int without_bits = XINT (key) & ~((-1) << CHARACTERBITS);
-
-      if (SINGLE_BYTE_CHAR_P (without_bits))
-       charset = 0;
-      else
-       SPLIT_CHAR (without_bits, charset, c1, c2);
-
-      if (! CHAR_VALID_P (without_bits, 1))
-       {
-         char buf[256];
-
-         sprintf (buf, "Invalid char code %ld", XINT (key));
-         return build_string (buf);
-       }
-      else if (charset
-              && ((c1 == 0 && c2 == -1) || c2 == 0))
-       {
-         /* Handle a generic character.  */
-         Lisp_Object name;
-         char buf[256];
-
-         name = CHARSET_TABLE_INFO (charset, CHARSET_SHORT_NAME_IDX);
-         CHECK_STRING (name);
-         if (c1 == 0)
-           /* Only a charset is specified.   */
-           sprintf (buf, "Generic char %d: all of ", without_bits);
-         else
-           /* 1st code-point of 2-dimensional charset is specified.   */
-           sprintf (buf, "Generic char %d: row %d of ", without_bits, c1);
-         return concat2 (build_string (buf), name);
-       }
-      else
-       {
-         char tem[KEY_DESCRIPTION_SIZE], *end;
-         int nbytes, nchars;
-         Lisp_Object string;
+      char tem[KEY_DESCRIPTION_SIZE];
 
-         end = push_key_description (XUINT (key), tem, 1);
-         nbytes = end - tem;
-         nchars = multibyte_chars_in_text (tem, nbytes);
-         if (nchars == nbytes)
-           {
-             *end = '\0';
-             string = build_string (tem);
-           }
-         else
-           string = make_multibyte_string (tem, nchars, nbytes);
-         return string;
-       }
+      *push_key_description (XUINT (key), tem, 1) = 0;
+      return build_string (tem);
     }
   else if (SYMBOLP (key))      /* Function key or event-symbol */
     {
@@ -2528,9 +2473,7 @@ around function keys and event symbols.  */)
 }
 
 char *
-push_text_char_description (c, p)
-     register unsigned int c;
-     register char *p;
+push_text_char_description (register unsigned int c, register char *p)
 {
   if (c >= 0200)
     {
@@ -2562,8 +2505,7 @@ Control characters turn into "^char", etc.  This differs from
 Also, this function recognizes the 2**7 bit as the Meta character,
 whereas `single-key-description' uses the 2**27 bit for Meta.
 See Info node `(elisp)Describing Characters' for examples.  */)
-     (character)
-     Lisp_Object character;
+  (Lisp_Object character)
 {
   /* Currently MAX_MULTIBYTE_LENGTH is 4 (< 6).  */
   unsigned char str[6];
@@ -2572,7 +2514,7 @@ See Info node `(elisp)Describing Characters' for examples.  */)
   CHECK_NUMBER (character);
 
   c = XINT (character);
-  if (!SINGLE_BYTE_CHAR_P (c))
+  if (!ASCII_CHAR_P (c))
     {
       int len = CHAR_STRING (c, str);
 
@@ -2584,14 +2526,17 @@ See Info node `(elisp)Describing Characters' for examples.  */)
   return build_string (str);
 }
 
-/* Return non-zero if SEQ contains only ASCII characters, perhaps with
-   a meta bit.  */
+static int where_is_preferred_modifier;
+
+/* Return 0 if SEQ uses non-preferred modifiers or non-char events.
+   Else, return 2 if SEQ uses the where_is_preferred_modifier,
+   and 1 otherwise.  */
 static int
-ascii_sequence_p (seq)
-     Lisp_Object seq;
+preferred_sequence_p (Lisp_Object seq)
 {
   int i;
   int len = XINT (Flength (seq));
+  int result = 1;
 
   for (i = 0; i < len; i++)
     {
@@ -2600,27 +2545,35 @@ ascii_sequence_p (seq)
       XSETFASTINT (ii, i);
       elt = Faref (seq, ii);
 
-      if (!INTEGERP (elt)
-         || (XUINT (elt) & ~CHAR_META) >= 0x80)
+      if (!INTEGERP (elt))
        return 0;
+      else
+       {
+         int modifiers = XUINT (elt) & (CHAR_MODIFIER_MASK & ~CHAR_META);
+         if (modifiers == where_is_preferred_modifier)
+           result = 2;
+         else if (modifiers)
+           return 0;
+       }
     }
 
-  return 1;
+  return result;
 }
 
 \f
 /* where-is - finding a command in a set of keymaps.                   */
 
-static Lisp_Object where_is_internal ();
-static void where_is_internal_1 P_ ((Lisp_Object key, Lisp_Object binding,
-                                    Lisp_Object args, void *data));
+static void where_is_internal_1 (Lisp_Object key, Lisp_Object binding,
+                                 Lisp_Object args, void *data);
 
 /* Like Flookup_key, but uses a list of keymaps SHADOW instead of a single map.
-   Returns the first non-nil binding found in any of those maps.  */
+   Returns the first non-nil binding found in any of those maps.
+   If REMAP is true, pass the result of the lookup through command
+   remapping before returning it.  */
 
 static Lisp_Object
-shadow_lookup (shadow, key, flag)
-     Lisp_Object shadow, key, flag;
+shadow_lookup (Lisp_Object shadow, Lisp_Object key, Lisp_Object flag,
+              int remap)
 {
   Lisp_Object tail, value;
 
@@ -2635,7 +2588,15 @@ shadow_lookup (shadow, key, flag)
            return Qnil;
        }
       else if (!NILP (value))
-       return value;
+       {
+         Lisp_Object remapping;
+         if (remap && SYMBOLP (value)
+             && (remapping = Fcommand_remapping (value, Qnil, shadow),
+                 !NILP (remapping)))
+           return remapping;
+         else
+           return value;
+       }
     }
   return Qnil;
 }
@@ -2643,23 +2604,49 @@ shadow_lookup (shadow, key, flag)
 static Lisp_Object Vmouse_events;
 
 struct where_is_internal_data {
-  Lisp_Object definition, noindirect, this, last;
-  int last_is_meta;
+  Lisp_Object definition, this, last;
+  int last_is_meta, noindirect;
   Lisp_Object sequences;
 };
 
-/* This function can GC if Flookup_key autoloads any keymaps.  */
+/* This function can't GC, AFAIK.  */
+/* Return the list of bindings found.  This list is ordered "longest
+   to shortest".  It may include bindings that are actually shadowed
+   by others, as well as duplicate bindings and remapping bindings.
+   The list returned is potentially shared with where_is_cache, so
+   be careful not to modify it via side-effects.  */
 
 static Lisp_Object
-where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
-     Lisp_Object definition, keymaps;
-     Lisp_Object firstonly, noindirect, no_remap;
+where_is_internal (Lisp_Object definition, Lisp_Object keymaps,
+                  int noindirect, int nomenus)
 {
   Lisp_Object maps = Qnil;
-  Lisp_Object found, sequences;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-  /* 1 means ignore all menu bindings entirely.  */
-  int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
+  Lisp_Object found;
+  struct where_is_internal_data data;
+
+  /* Only important use of caching is for the menubar
+     (i.e. where-is-internal called with (def nil t nil nil)).  */
+  if (nomenus && !noindirect)
+    {
+      /* Check heuristic-consistency of the cache.  */
+      if (NILP (Fequal (keymaps, where_is_cache_keymaps)))
+       where_is_cache = Qnil;
+
+      if (NILP (where_is_cache))
+       {
+         /* We need to create the cache.  */
+         Lisp_Object args[2];
+         where_is_cache = Fmake_hash_table (0, args);
+         where_is_cache_keymaps = Qt;
+       }
+      else
+       /* We can reuse the cache.  */
+       return Fgethash (definition, where_is_cache, Qnil);
+    }
+  else
+    /* Kill the cache so that where_is_internal_1 doesn't think
+       we're filling it up.  */
+    where_is_cache = Qnil;
 
   found = keymaps;
   while (CONSP (found))
@@ -2670,22 +2657,11 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
       found = XCDR (found);
     }
 
-  GCPRO5 (definition, keymaps, maps, found, sequences);
-  found = Qnil;
-  sequences = Qnil;
-
-  /* If this command is remapped, then it has no key bindings
-     of its own.  */
-  if (NILP (no_remap)
-      && SYMBOLP (definition)
-      && !NILP (Fcommand_remapping (definition, Qnil, keymaps)))
-    RETURN_UNGCPRO (Qnil);
-
+  data.sequences = Qnil;
   for (; CONSP (maps); maps = XCDR (maps))
     {
       /* Key sequence to reach map, and the map that it reaches */
       register Lisp_Object this, map, tem;
-      struct where_is_internal_data data;
 
       /* In order to fold [META-PREFIX-CHAR CHAR] sequences into
         [M-CHAR] sequences, check if last character of the sequence
@@ -2699,7 +2675,7 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
       last_is_meta = (XINT (last) >= 0
                      && EQ (Faref (this, last), meta_prefix_char));
 
-      /* if (nomenus && !ascii_sequence_p (this)) */
+      /* if (nomenus && !preferred_sequence_p (this)) */
       if (nomenus && XINT (last) >= 0
          && SYMBOLP (tem = Faref (this, make_number (0)))
          && !NILP (Fmemq (XCAR (parse_modifiers (tem)), Vmouse_events)))
@@ -2715,105 +2691,27 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
       data.this = this;
       data.last = last;
       data.last_is_meta = last_is_meta;
-      data.sequences = Qnil;
 
       if (CONSP (map))
        map_keymap (map, where_is_internal_1, Qnil, &data, 0);
-
-      sequences = data.sequences;
-
-      while (CONSP (sequences))
-       {
-         Lisp_Object sequence, remapped, function;
-         
-         sequence = XCAR (sequences);
-         sequences = XCDR (sequences);
-
-         /* If the current sequence is a command remapping with
-            format [remap COMMAND], find the key sequences
-            which run COMMAND, and use those sequences instead.  */
-         remapped = Qnil;
-         if (NILP (no_remap)
-             && VECTORP (sequence) && XVECTOR (sequence)->size == 2
-             && EQ (AREF (sequence, 0), Qremap)
-             && (function = AREF (sequence, 1), SYMBOLP (function)))
-           {
-             Lisp_Object remapped1;
-             
-             remapped1 = where_is_internal (function, keymaps, firstonly, noindirect, Qt);
-             if (CONSP (remapped1))
-               {
-                 /* Verify that this key binding actually maps to the
-                    remapped command (see below).  */
-                 if (!EQ (shadow_lookup (keymaps, XCAR (remapped1), Qnil), function))
-                   continue;
-                 sequence = XCAR (remapped1);
-                 remapped = XCDR (remapped1);
-                 goto record_sequence;
-               }
-           }
-
-         /* Verify that this key binding is not shadowed by another
-            binding for the same key, before we say it exists.
-
-            Mechanism: look for local definition of this key and if
-            it is defined and does not match what we found then
-            ignore this key.
-
-            Either nil or number as value from Flookup_key
-            means undefined.  */
-         if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition))
-           continue;
-
-       record_sequence:
-         /* Don't annoy user with strings from a menu such as
-            Select Paste.  Change them all to "(any string)",
-            so that there seems to be only one menu item
-            to report. */
-         if (! NILP (sequence))
-           {
-             Lisp_Object tem;
-             tem = Faref (sequence, make_number (XVECTOR (sequence)->size - 1));
-             if (STRINGP (tem))
-               Faset (sequence, make_number (XVECTOR (sequence)->size - 1),
-                      build_string ("(any string)"));
-           }
-
-         /* It is a true unshadowed match.  Record it, unless it's already
-            been seen (as could happen when inheriting keymaps).  */
-         if (NILP (Fmember (sequence, found)))
-           found = Fcons (sequence, found);
-
-         /* If firstonly is Qnon_ascii, then we can return the first
-            binding we find.  If firstonly is not Qnon_ascii but not
-            nil, then we should return the first ascii-only binding
-            we find.  */
-         if (EQ (firstonly, Qnon_ascii))
-           RETURN_UNGCPRO (sequence);
-         else if (!NILP (firstonly) && ascii_sequence_p (sequence))
-           RETURN_UNGCPRO (sequence);
-
-         if (CONSP (remapped))
-           {
-             sequence = XCAR (remapped);
-             remapped = XCDR (remapped);
-             goto record_sequence;
-           }
-       }
     }
 
-  UNGCPRO;
-
-  found = Fnreverse (found);
+  if (nomenus && !noindirect)
+    { /* Remember for which keymaps this cache was built.
+        We do it here (late) because we want to keep where_is_cache_keymaps
+        set to t while the cache isn't fully filled.  */
+      where_is_cache_keymaps = keymaps;
+      /* During cache-filling, data.sequences is not filled by
+        where_is_internal_1.  */
+      return Fgethash (definition, where_is_cache, Qnil);
+    }
+  else
+    return data.sequences;
+}
 
-  /* firstonly may have been t, but we may have gone all the way through
-     the keymaps without finding an all-ASCII key sequence.  So just
-     return the best we could find.  */
-  if (!NILP (firstonly))
-    return Fcar (found);
+static Lisp_Object Vwhere_is_preferred_modifier;
 
-  return found;
-}
+/* This function can GC if Flookup_key autoloads any keymaps.  */
 
 DEFUN ("where-is-internal", Fwhere_is_internal, Swhere_is_internal, 1, 5, 0,
        doc: /* Return list of keys that invoke DEFINITION.
@@ -2825,7 +2723,8 @@ If optional 3rd arg FIRSTONLY is non-nil, return the first key sequence found,
 rather than a list of all possible key sequences.
 If FIRSTONLY is the symbol `non-ascii', return the first binding found,
 no matter what it is.
-If FIRSTONLY has another non-nil value, prefer sequences of ASCII characters
+If FIRSTONLY has another non-nil value, prefer bindings
+that use the modifier key specified in `where-is-preferred-modifier'
 \(or their meta variants) and entirely reject menu bindings.
 
 If optional 4th arg NOINDIRECT is non-nil, don't follow indirections
@@ -2835,14 +2734,30 @@ indirect definition itself.
 If optional 5th arg NO-REMAP is non-nil, don't search for key sequences
 that invoke a command which is remapped to DEFINITION, but include the
 remapped command in the returned list.  */)
-     (definition, keymap, firstonly, noindirect, no_remap)
-     Lisp_Object definition, keymap;
-     Lisp_Object firstonly, noindirect, no_remap;
+  (Lisp_Object definition, Lisp_Object keymap, Lisp_Object firstonly, Lisp_Object noindirect, Lisp_Object no_remap)
 {
-  Lisp_Object sequences, keymaps;
+  /* The keymaps in which to search.  */
+  Lisp_Object keymaps;
+  /* Potentially relevant bindings in "shortest to longest" order.  */
+  Lisp_Object sequences = Qnil;
+    /* Actually relevant bindings.  */
+  Lisp_Object found = Qnil;
   /* 1 means ignore all menu bindings entirely.  */
   int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
-  Lisp_Object result;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
+  /* List of sequences found via remapping.  Keep them in a separate
+     variable, so as to push them later, since we prefer
+     non-remapped binding.  */
+  Lisp_Object remapped_sequences = Qnil;
+  /* Whether or not we're handling remapped sequences.  This is needed
+     because remapping is not done recursively by Fcommand_remapping: you
+     can't remap a remapped command.  */
+  int remapped = 0;
+  Lisp_Object tem = Qnil;
+
+  /* Refresh the C version of the modifier preference.  */
+  where_is_preferred_modifier
+    = parse_solitary_modifier (Vwhere_is_preferred_modifier);
 
   /* Find the relevant keymaps.  */
   if (CONSP (keymap) && KEYMAPP (XCAR (keymap)))
@@ -2852,87 +2767,151 @@ remapped command in the returned list.  */)
   else
     keymaps = Fcurrent_active_maps (Qnil, Qnil);
 
-  /* Only use caching for the menubar (i.e. called with (def nil t nil).
-     We don't really need to check `keymap'.  */
-  if (nomenus && NILP (noindirect) && NILP (keymap))
+  GCPRO6 (definition, keymaps, found, sequences, remapped_sequences, tem);
+
+  tem = Fcommand_remapping (definition, Qnil, keymaps);
+  /* If `definition' is remapped to tem', then OT1H no key will run
+     that command (since they will run `tem' instead), so we should
+     return nil; but OTOH all keys bound to `definition' (or to `tem')
+     will run the same command.
+     So for menu-shortcut purposes, we want to find all the keys bound (maybe
+     via remapping) to `tem'.  But for the purpose of finding the keys that
+     run `definition', then we'd want to just return nil.
+     We choose to make it work right for menu-shortcuts, since it's the most
+     common use.
+     Known bugs: if you remap switch-to-buffer to toto, C-h f switch-to-buffer
+     will tell you that switch-to-buffer is bound to C-x b even though C-x b
+     will run toto instead.  And if `toto' is itself remapped to forward-char,
+     then C-h f toto will tell you that it's bound to C-f even though C-f does
+     not run toto and it won't tell you that C-x b does run toto.  */
+  if (NILP (no_remap) && !NILP (tem))
+    definition = tem;
+
+  if (SYMBOLP (definition)
+      && !NILP (firstonly)
+      && !NILP (tem = Fget (definition, QCadvertised_binding)))
+    {
+      /* We have a list of advertized bindings.  */
+      while (CONSP (tem))
+       if (EQ (shadow_lookup (keymaps, XCAR (tem), Qnil, 0), definition))
+         return XCAR (tem);
+       else
+         tem = XCDR (tem);
+      if (EQ (shadow_lookup (keymaps, tem, Qnil, 0), definition))
+       return tem;
+    }
+
+  sequences = Freverse (where_is_internal (definition, keymaps,
+                                          !NILP (noindirect), nomenus));
+
+  while (CONSP (sequences)
+        /* If we're at the end of the `sequences' list and we haven't
+           considered remapped sequences yet, copy them over and
+           process them.  */
+        || (!remapped && (sequences = remapped_sequences,
+                          remapped = 1),
+            CONSP (sequences)))
     {
-      Lisp_Object *defns;
-      int i, j, n;
-      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+      Lisp_Object sequence, function;
 
-      /* Check heuristic-consistency of the cache.  */
-      if (NILP (Fequal (keymaps, where_is_cache_keymaps)))
-       where_is_cache = Qnil;
+      sequence = XCAR (sequences);
+      sequences = XCDR (sequences);
 
-      if (NILP (where_is_cache))
-       {
-         /* We need to create the cache.  */
-         Lisp_Object args[2];
-         where_is_cache = Fmake_hash_table (0, args);
-         where_is_cache_keymaps = Qt;
+      /* Verify that this key binding is not shadowed by another
+        binding for the same key, before we say it exists.
 
-         /* Fill in the cache.  */
-         GCPRO5 (definition, keymaps, firstonly, noindirect, no_remap);
-         where_is_internal (definition, keymaps, firstonly, noindirect, no_remap);
-         UNGCPRO;
+        Mechanism: look for local definition of this key and if
+        it is defined and does not match what we found then
+        ignore this key.
 
-         where_is_cache_keymaps = keymaps;
+        Either nil or number as value from Flookup_key
+        means undefined.  */
+      if (NILP (Fequal (shadow_lookup (keymaps, sequence, Qnil, remapped),
+                       definition)))
+       continue;
+
+      /* If the current sequence is a command remapping with
+        format [remap COMMAND], find the key sequences
+        which run COMMAND, and use those sequences instead.  */
+      if (NILP (no_remap) && !remapped
+         && VECTORP (sequence) && ASIZE (sequence) == 2
+         && EQ (AREF (sequence, 0), Qremap)
+         && (function = AREF (sequence, 1), SYMBOLP (function)))
+       {
+         Lisp_Object seqs = where_is_internal (function, keymaps,
+                                               !NILP (noindirect), nomenus);
+         remapped_sequences = nconc2 (Freverse (seqs), remapped_sequences);
+         continue;
        }
 
-      /* We want to process definitions from the last to the first.
-        Instead of consing, copy definitions to a vector and step
-        over that vector.  */
-      sequences = Fgethash (definition, where_is_cache, Qnil);
-      n = XINT (Flength (sequences));
-      defns = (Lisp_Object *) alloca (n * sizeof *defns);
-      for (i = 0; CONSP (sequences); sequences = XCDR (sequences))
-       defns[i++] = XCAR (sequences);
-
-      /* Verify that the key bindings are not shadowed.  Note that
-        the following can GC.  */
-      GCPRO2 (definition, keymaps);
-      result = Qnil;
-      j = -1;
-      for (i = n - 1; i >= 0; --i)
-       if (EQ (shadow_lookup (keymaps, defns[i], Qnil), definition))
-         {
-           if (ascii_sequence_p (defns[i]))
-             break;
-           else if (j < 0)
-             j = i;
-         }
+      /* Don't annoy user with strings from a menu such as the
+        entries from the "Edit => Paste from Kill Menu".
+        Change them all to "(any string)", so that there
+        seems to be only one menu item to report.  */
+      if (! NILP (sequence))
+       {
+         Lisp_Object tem;
+         tem = Faref (sequence, make_number (ASIZE (sequence) - 1));
+         if (STRINGP (tem))
+           Faset (sequence, make_number (ASIZE (sequence) - 1),
+                  build_string ("(any string)"));
+       }
 
-      result = i >= 0 ? defns[i] : (j >= 0 ? defns[j] : Qnil);
-      UNGCPRO;
+      /* It is a true unshadowed match.  Record it, unless it's already
+        been seen (as could happen when inheriting keymaps).  */
+      if (NILP (Fmember (sequence, found)))
+       found = Fcons (sequence, found);
+
+      /* If firstonly is Qnon_ascii, then we can return the first
+        binding we find.  If firstonly is not Qnon_ascii but not
+        nil, then we should return the first ascii-only binding
+        we find.  */
+      if (EQ (firstonly, Qnon_ascii))
+       RETURN_UNGCPRO (sequence);
+      else if (!NILP (firstonly)
+              && 2 == preferred_sequence_p (sequence))
+       RETURN_UNGCPRO (sequence);
     }
+
+  UNGCPRO;
+
+  found = Fnreverse (found);
+
+  /* firstonly may have been t, but we may have gone all the way through
+     the keymaps without finding an all-ASCII key sequence.  So just
+     return the best we could find.  */
+  if (NILP (firstonly))
+    return found;
+  else if (where_is_preferred_modifier == 0)
+    return Fcar (found);
   else
-    {
-      /* Kill the cache so that where_is_internal_1 doesn't think
-        we're filling it up.  */
-      where_is_cache = Qnil;
-      result = where_is_internal (definition, keymaps, firstonly, noindirect, no_remap);
+    { /* Maybe we did not find a preferred_modifier binding, but we did find
+        some ASCII binding.  */
+      Lisp_Object bindings = found;
+      while (CONSP (bindings))
+       if (preferred_sequence_p (XCAR (bindings)))
+         return XCAR (bindings);
+       else
+         bindings = XCDR (bindings);
+      return Fcar (found);
     }
-
-  return result;
 }
 
 /* This function can GC because get_keyelt can.  */
 
 static void
-where_is_internal_1 (key, binding, args, data)
-     Lisp_Object key, binding, args;
-     void *data;
+where_is_internal_1 (Lisp_Object key, Lisp_Object binding, Lisp_Object args, void *data)
 {
   struct where_is_internal_data *d = data; /* Cast! */
   Lisp_Object definition = d->definition;
-  Lisp_Object noindirect = d->noindirect;
+  int noindirect = d->noindirect;
   Lisp_Object this = d->this;
   Lisp_Object last = d->last;
   int last_is_meta = d->last_is_meta;
   Lisp_Object sequence;
 
   /* Search through indirections unless that's not wanted.  */
-  if (NILP (noindirect))
+  if (!noindirect)
     binding = get_keyelt (binding, 0);
 
   /* End this iteration if this element does not match
@@ -2951,7 +2930,11 @@ where_is_internal_1 (key, binding, args, data)
       Faset (sequence, last, make_number (XINT (key) | meta_modifier));
     }
   else
-    sequence = append_key (this, key);
+    {
+      if (CONSP (key))
+       key = Fcons (XCAR (key), XCDR (key));
+      sequence = append_key (this, key);
+    }
 
   if (!NILP (where_is_cache))
     {
@@ -2972,8 +2955,7 @@ The optional argument PREFIX, if non-nil, should be a key sequence;
 then we display only bindings that start with that prefix.
 The optional argument MENUS, if non-nil, says to mention menu bindings.
 \(Ordinarily these are omitted from the output.)  */)
-     (buffer, prefix, menus)
-     Lisp_Object buffer, prefix, menus;
+  (Lisp_Object buffer, Lisp_Object prefix, Lisp_Object menus)
 {
   Lisp_Object outbuf, shadow;
   int nomenu = NILP (menus);
@@ -3078,18 +3060,18 @@ You type        Translation\n\
          char *title, *p;
 
          if (!SYMBOLP (modes[i]))
-           abort();
+           abort ();
 
          p = title = (char *) alloca (42 + SCHARS (SYMBOL_NAME (modes[i])));
          *p++ = '\f';
          *p++ = '\n';
          *p++ = '`';
-         bcopy (SDATA (SYMBOL_NAME (modes[i])), p,
-                SCHARS (SYMBOL_NAME (modes[i])));
+         memcpy (p, SDATA (SYMBOL_NAME (modes[i])),
+                 SCHARS (SYMBOL_NAME (modes[i])));
          p += SCHARS (SYMBOL_NAME (modes[i]));
          *p++ = '\'';
-         bcopy (" Minor Mode Bindings", p, sizeof (" Minor Mode Bindings") - 1);
-         p += sizeof (" Minor Mode Bindings") - 1;
+         memcpy (p, " Minor Mode Bindings", strlen (" Minor Mode Bindings"));
+         p += strlen (" Minor Mode Bindings");
          *p = 0;
 
          describe_map_tree (maps[i], 1, shadow, prefix,
@@ -3151,15 +3133,9 @@ You type        Translation\n\
    don't omit it; instead, mention it but say it is shadowed.  */
 
 void
-describe_map_tree (startmap, partial, shadow, prefix, title, nomenu, transl,
-                  always_title, mention_shadow)
-     Lisp_Object startmap, shadow, prefix;
-     int partial;
-     char *title;
-     int nomenu;
-     int transl;
-     int always_title;
-     int mention_shadow;
+describe_map_tree (Lisp_Object startmap, int partial, Lisp_Object shadow,
+                  Lisp_Object prefix, char *title, int nomenu, int transl,
+                  int always_title, int mention_shadow)
 {
   Lisp_Object maps, orig_maps, seen, sub_shadows;
   struct gcpro gcpro1, gcpro2, gcpro3;
@@ -3275,8 +3251,7 @@ key             binding\n\
 static int previous_description_column;
 
 static void
-describe_command (definition, args)
-     Lisp_Object definition, args;
+describe_command (Lisp_Object definition, Lisp_Object args)
 {
   register Lisp_Object tem1;
   int column = (int) current_column (); /* iftc */
@@ -3312,8 +3287,7 @@ describe_command (definition, args)
 }
 
 static void
-describe_translation (definition, args)
-     Lisp_Object definition, args;
+describe_translation (Lisp_Object definition, Lisp_Object args)
 {
   register Lisp_Object tem1;
 
@@ -3346,8 +3320,7 @@ struct describe_map_elt { Lisp_Object event; Lisp_Object definition; int shadowe
    the event field.  */
 
 static int
-describe_map_compare (aa, bb)
-     const void *aa, *bb;
+describe_map_compare (const void *aa, const void *bb)
 {
   const struct describe_map_elt *a = aa, *b = bb;
   if (INTEGERP (a->event) && INTEGERP (b->event))
@@ -3369,16 +3342,10 @@ describe_map_compare (aa, bb)
    PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above.  */
 
 static void
-describe_map (map, prefix, elt_describer, partial, shadow,
-             seen, nomenu, mention_shadow)
-     register Lisp_Object map;
-     Lisp_Object prefix;
-     void (*elt_describer) P_ ((Lisp_Object, Lisp_Object));
-     int partial;
-     Lisp_Object shadow;
-     Lisp_Object *seen;
-     int nomenu;
-     int mention_shadow;
+describe_map (Lisp_Object map, Lisp_Object prefix,
+             void (*elt_describer) (Lisp_Object, Lisp_Object),
+             int partial, Lisp_Object shadow,
+             Lisp_Object *seen, int nomenu, int mention_shadow)
 {
   Lisp_Object tail, definition, event;
   Lisp_Object tem;
@@ -3405,14 +3372,16 @@ describe_map (map, prefix, elt_describer, partial, shadow,
   kludge = Fmake_vector (make_number (1), Qnil);
   definition = Qnil;
 
+  GCPRO3 (prefix, definition, kludge);
+
+  map = call1 (Qkeymap_canonicalize, map);
+
   for (tail = map; CONSP (tail); tail = XCDR (tail))
     length_needed++;
 
   vect = ((struct describe_map_elt *)
          alloca (sizeof (struct describe_map_elt) * length_needed));
 
-  GCPRO3 (prefix, definition, kludge);
-
   for (tail = map; CONSP (tail); tail = XCDR (tail))
     {
       QUIT;
@@ -3453,7 +3422,7 @@ describe_map (map, prefix, elt_describer, partial, shadow,
          ASET (kludge, 0, event);
          if (!NILP (shadow))
            {
-             tem = shadow_lookup (shadow, kludge, Qt);
+             tem = shadow_lookup (shadow, kludge, Qt, 0);
              if (!NILP (tem))
                {
                  /* If both bindings are keymaps, this key is a prefix key,
@@ -3555,8 +3524,7 @@ describe_map (map, prefix, elt_describer, partial, shadow,
 }
 
 static void
-describe_vector_princ (elt, fun)
-     Lisp_Object elt, fun;
+describe_vector_princ (Lisp_Object elt, Lisp_Object fun)
 {
   Findent_to (make_number (16), make_number (1));
   call1 (fun, elt);
@@ -3567,8 +3535,7 @@ DEFUN ("describe-vector", Fdescribe_vector, Sdescribe_vector, 1, 2, 0,
        doc: /* Insert a description of contents of VECTOR.
 This is text showing the elements of vector matched against indices.
 DESCRIBER is the output function used; nil means use `princ'.  */)
-     (vector, describer)
-     Lisp_Object vector, describer;
+  (Lisp_Object vector, Lisp_Object describer)
 {
   int count = SPECPDL_INDEX ();
   if (NILP (describer))
@@ -3607,51 +3574,37 @@ DESCRIBER is the output function used; nil means use `princ'.  */)
    If the definition in effect in the whole map does not match
    the one in this vector, we ignore this one.
 
-   When describing a sub-char-table, INDICES is a list of
-   indices at higher levels in this char-table,
-   and CHAR_TABLE_DEPTH says how many levels down we have gone.
+   ARGS is simply passed as the second argument to ELT_DESCRIBER.
+
+   INDICES and CHAR_TABLE_DEPTH are ignored.  They will be removed in
+   the near future.
 
    KEYMAP_P is 1 if vector is known to be a keymap, so map ESC to M-.
 
    ARGS is simply passed as the second argument to ELT_DESCRIBER.  */
 
 static void
-describe_vector (vector, prefix, args, elt_describer,
-                partial, shadow, entire_map,
-                indices, char_table_depth, keymap_p,
-                mention_shadow)
-     register Lisp_Object vector;
-     Lisp_Object prefix, args;
-     void (*elt_describer) P_ ((Lisp_Object, Lisp_Object));
-     int partial;
-     Lisp_Object shadow;
-     Lisp_Object entire_map;
-     int *indices;
-     int char_table_depth;
-     int keymap_p;
-     int mention_shadow;
+describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
+                void (*elt_describer) (Lisp_Object, Lisp_Object),
+                int partial, Lisp_Object shadow, Lisp_Object entire_map,
+                int *indices, int char_table_depth, int keymap_p,
+                int mention_shadow)
 {
   Lisp_Object definition;
   Lisp_Object tem2;
   Lisp_Object elt_prefix = Qnil;
-  register int i;
+  int i;
   Lisp_Object suppress;
   Lisp_Object kludge;
   int first = 1;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   /* Range of elements to be handled.  */
-  int from, to;
-  /* A flag to tell if a leaf in this level of char-table is not a
-     generic character (i.e. a complete multibyte character).  */
-  int complete_char;
-  int character;
+  int from, to, stop;
+  Lisp_Object character;
   int starting_i;
 
   suppress = Qnil;
 
-  if (indices == 0)
-    indices = (int *) alloca (3 * sizeof (int));
-
   definition = Qnil;
 
   if (!keymap_p)
@@ -3675,61 +3628,38 @@ describe_vector (vector, prefix, args, elt_describer,
   if (partial)
     suppress = intern ("suppress-keymap");
 
+  from = 0;
   if (CHAR_TABLE_P (vector))
-    {
-      if (char_table_depth == 0)
-       {
-         /* VECTOR is a top level char-table.  */
-         complete_char = 1;
-         from = 0;
-         to = CHAR_TABLE_ORDINARY_SLOTS;
-       }
-      else
-       {
-         /* VECTOR is a sub char-table.  */
-         if (char_table_depth >= 3)
-           /* A char-table is never that deep.  */
-           error ("Too deep char table");
-
-         complete_char
-           = (CHARSET_VALID_P (indices[0])
-              && ((CHARSET_DIMENSION (indices[0]) == 1
-                   && char_table_depth == 1)
-                  || char_table_depth == 2));
-
-         /* Meaningful elements are from 32th to 127th.  */
-         from = 32;
-         to = SUB_CHAR_TABLE_ORDINARY_SLOTS;
-       }
-    }
+    stop = MAX_5_BYTE_CHAR + 1, to = MAX_CHAR + 1;
   else
-    {
-      /* This does the right thing for ordinary vectors.  */
-
-      complete_char = 1;
-      from = 0;
-      to = XVECTOR (vector)->size;
-    }
+    stop = to = XVECTOR (vector)->size;
 
-  for (i = from; i < to; i++)
+  for (i = from; ; i++)
     {
       int this_shadowed = 0;
+      int range_beg, range_end;
+      Lisp_Object val;
+
       QUIT;
 
-      if (CHAR_TABLE_P (vector))
+      if (i == stop)
        {
-         if (char_table_depth == 0 && i >= CHAR_TABLE_SINGLE_BYTE_SLOTS)
-           complete_char = 0;
+         if (i == to)
+           break;
+         stop = to;
+       }
 
-         if (i >= CHAR_TABLE_SINGLE_BYTE_SLOTS
-             && !CHARSET_DEFINED_P (i - 128))
-           continue;
+      starting_i = i;
 
-         definition
-           = get_keyelt (XCHAR_TABLE (vector)->contents[i], 0);
+      if (CHAR_TABLE_P (vector))
+       {
+         range_beg = i;
+         i = stop - 1;
+         val = char_table_ref_and_range (vector, range_beg, &range_beg, &i);
        }
       else
-       definition = get_keyelt (AREF (vector, i), 0);
+       val = AREF (vector, i);
+      definition = get_keyelt (val, 0);
 
       if (NILP (definition)) continue;
 
@@ -3743,35 +3673,15 @@ describe_vector (vector, prefix, args, elt_describer,
          if (!NILP (tem)) continue;
        }
 
-      /* Set CHARACTER to the character this entry describes, if any.
-        Also update *INDICES.  */
-      if (CHAR_TABLE_P (vector))
-       {
-         indices[char_table_depth] = i;
-
-         if (char_table_depth == 0)
-           {
-             character = i;
-             indices[0] = i - 128;
-           }
-         else if (complete_char)
-           {
-             character = MAKE_CHAR (indices[0], indices[1], indices[2]);
-           }
-         else
-           character = 0;
-       }
-      else
-       character = i;
-
-      ASET (kludge, 0, make_number (character));
+      character = make_number (starting_i);
+      ASET (kludge, 0, character);
 
       /* If this binding is shadowed by some other map, ignore it.  */
-      if (!NILP (shadow) && complete_char)
+      if (!NILP (shadow))
        {
          Lisp_Object tem;
 
-         tem = shadow_lookup (shadow, kludge, Qt);
+         tem = shadow_lookup (shadow, kludge, Qt, 0);
 
          if (!NILP (tem))
            {
@@ -3784,7 +3694,7 @@ describe_vector (vector, prefix, args, elt_describer,
 
       /* Ignore this definition if it is shadowed by an earlier
         one in the same keymap.  */
-      if (!NILP (entire_map) && complete_char)
+      if (!NILP (entire_map))
        {
          Lisp_Object tem;
 
@@ -3796,97 +3706,38 @@ describe_vector (vector, prefix, args, elt_describer,
 
       if (first)
        {
-         if (char_table_depth == 0)
-           insert ("\n", 1);
+         insert ("\n", 1);
          first = 0;
        }
 
-      /* For a sub char-table, show the depth by indentation.
-        CHAR_TABLE_DEPTH can be greater than 0 only for a char-table.  */
-      if (char_table_depth > 0)
-       insert ("    ", char_table_depth * 2); /* depth is 1 or 2.  */
-
       /* Output the prefix that applies to every entry in this map.  */
       if (!NILP (elt_prefix))
        insert1 (elt_prefix);
 
-      /* Insert or describe the character this slot is for,
-        or a description of what it is for.  */
-      if (SUB_CHAR_TABLE_P (vector))
-       {
-         if (complete_char)
-           insert_char (character);
-         else
-           {
-             /* We need an octal representation for this block of
-                 characters.  */
-             char work[16];
-             sprintf (work, "(row %d)", i);
-             insert (work, strlen (work));
-           }
-       }
-      else if (CHAR_TABLE_P (vector))
-       {
-         if (complete_char)
-           insert1 (Fkey_description (kludge, prefix));
-         else
-           {
-             /* Print the information for this character set.  */
-             insert_string ("<");
-             tem2 = CHARSET_TABLE_INFO (i - 128, CHARSET_SHORT_NAME_IDX);
-             if (STRINGP (tem2))
-               insert_from_string (tem2, 0, 0, SCHARS (tem2),
-                                   SBYTES (tem2), 0);
-             else
-               insert ("?", 1);
-             insert (">", 1);
-           }
-       }
-      else
-       {
-         insert1 (Fkey_description (kludge, prefix));
-       }
-
-      /* If we find a sub char-table within a char-table,
-        scan it recursively; it defines the details for
-        a character set or a portion of a character set.  */
-      if (CHAR_TABLE_P (vector) && SUB_CHAR_TABLE_P (definition))
-       {
-         insert ("\n", 1);
-         describe_vector (definition, prefix, args, elt_describer,
-                          partial, shadow, entire_map,
-                          indices, char_table_depth + 1, keymap_p,
-                          mention_shadow);
-         continue;
-       }
-
-      starting_i = i;
+      insert1 (Fkey_description (kludge, prefix));
 
       /* Find all consecutive characters or rows that have the same
-         definition.  But, for elements of a top level char table, if
-         they are for charsets, we had better describe one by one even
-         if they have the same definition.  */
+         definition.  But, VECTOR is a char-table, we had better put a
+         boundary between normal characters (-#x3FFF7F) and 8-bit
+         characters (#x3FFF80-).  */
       if (CHAR_TABLE_P (vector))
        {
-         int limit = to;
-
-         if (char_table_depth == 0)
-           limit = CHAR_TABLE_SINGLE_BYTE_SLOTS;
-
-         while (i + 1 < limit
-                && (tem2 = get_keyelt (XCHAR_TABLE (vector)->contents[i + 1], 0),
-                    !NILP (tem2))
+         while (i + 1 < stop
+                && (range_beg = i + 1, range_end = stop - 1,
+                  val = char_table_ref_and_range (vector, range_beg,
+                                                  &range_beg, &range_end),
+                  tem2 = get_keyelt (val, 0),
+                  !NILP (tem2))
                 && !NILP (Fequal (tem2, definition)))
-           i++;
+           i = range_end;
        }
       else
-       while (i + 1 < to
+       while (i + 1 < stop
               && (tem2 = get_keyelt (AREF (vector, i + 1), 0),
                   !NILP (tem2))
               && !NILP (Fequal (tem2, definition)))
          i++;
 
-
       /* If we have a range of more than one character,
         print where the range reaches to.  */
 
@@ -3899,31 +3750,7 @@ describe_vector (vector, prefix, args, elt_describer,
          if (!NILP (elt_prefix))
            insert1 (elt_prefix);
 
-         if (CHAR_TABLE_P (vector))
-           {
-             if (char_table_depth == 0)
-               {
-                 insert1 (Fkey_description (kludge, prefix));
-               }
-             else if (complete_char)
-               {
-                 indices[char_table_depth] = i;
-                 character = MAKE_CHAR (indices[0], indices[1], indices[2]);
-                 insert_char (character);
-               }
-             else
-               {
-                 /* We need an octal representation for this block of
-                    characters.  */
-                 char work[16];
-                 sprintf (work, "(row %d)", i);
-                 insert (work, strlen (work));
-               }
-           }
-         else
-           {
-             insert1 (Fkey_description (kludge, prefix));
-           }
+         insert1 (Fkey_description (kludge, prefix));
        }
 
       /* Print a description of the definition of this character.
@@ -3939,11 +3766,11 @@ describe_vector (vector, prefix, args, elt_describer,
        }
     }
 
-  /* For (sub) char-table, print `defalt' slot at last.  */
-  if (CHAR_TABLE_P (vector) && !NILP (XCHAR_TABLE (vector)->defalt))
+  if (CHAR_TABLE_P (vector) && ! NILP (XCHAR_TABLE (vector)->defalt))
     {
-      insert ("    ", char_table_depth * 2);
-      insert_string ("<<default>>");
+      if (!NILP (elt_prefix))
+       insert1 (elt_prefix);
+      insert ("default", 7);
       (*elt_describer) (XCHAR_TABLE (vector)->defalt, args);
     }
 
@@ -3955,8 +3782,7 @@ static Lisp_Object apropos_predicate;
 static Lisp_Object apropos_accumulate;
 
 static void
-apropos_accum (symbol, string)
-     Lisp_Object symbol, string;
+apropos_accum (Lisp_Object symbol, Lisp_Object string)
 {
   register Lisp_Object tem;
 
@@ -3972,8 +3798,7 @@ DEFUN ("apropos-internal", Fapropos_internal, Sapropos_internal, 1, 2, 0,
 If optional 2nd arg PREDICATE is non-nil, (funcall PREDICATE SYMBOL) is done
 for each symbol and a symbol is mentioned only if that returns non-nil.
 Return list of symbols found.  */)
-     (regexp, predicate)
-     Lisp_Object regexp, predicate;
+  (Lisp_Object regexp, Lisp_Object predicate)
 {
   Lisp_Object tem;
   CHECK_STRING (regexp);
@@ -3987,15 +3812,18 @@ Return list of symbols found.  */)
 }
 \f
 void
-syms_of_keymap ()
+syms_of_keymap (void)
 {
-  Qkeymap = intern ("keymap");
+  Qkeymap = intern_c_string ("keymap");
   staticpro (&Qkeymap);
   staticpro (&apropos_predicate);
   staticpro (&apropos_accumulate);
   apropos_predicate = Qnil;
   apropos_accumulate = Qnil;
 
+  Qkeymap_canonicalize = intern_c_string ("keymap-canonicalize");
+  staticpro (&Qkeymap_canonicalize);
+
   /* Now we are ready to set up this property, so we can
      create char tables.  */
   Fput (Qkeymap, Qchar_table_extra_slots, make_number (0));
@@ -4005,26 +3833,26 @@ syms_of_keymap ()
      pointed to by a C variable */
 
   global_map = Fmake_keymap (Qnil);
-  Fset (intern ("global-map"), global_map);
+  Fset (intern_c_string ("global-map"), global_map);
 
   current_global_map = global_map;
   staticpro (&global_map);
   staticpro (&current_global_map);
 
   meta_map = Fmake_keymap (Qnil);
-  Fset (intern ("esc-map"), meta_map);
-  Ffset (intern ("ESC-prefix"), meta_map);
+  Fset (intern_c_string ("esc-map"), meta_map);
+  Ffset (intern_c_string ("ESC-prefix"), meta_map);
 
   control_x_map = Fmake_keymap (Qnil);
-  Fset (intern ("ctl-x-map"), control_x_map);
-  Ffset (intern ("Control-X-prefix"), control_x_map);
+  Fset (intern_c_string ("ctl-x-map"), control_x_map);
+  Ffset (intern_c_string ("Control-X-prefix"), control_x_map);
 
   exclude_keys
-    = Fcons (Fcons (build_string ("DEL"), build_string ("\\d")),
-            Fcons (Fcons (build_string ("TAB"), build_string ("\\t")),
-                   Fcons (Fcons (build_string ("RET"), build_string ("\\r")),
-                          Fcons (Fcons (build_string ("ESC"), build_string ("\\e")),
-                                 Fcons (Fcons (build_string ("SPC"), build_string (" ")),
+    = pure_cons (pure_cons (make_pure_c_string ("DEL"), make_pure_c_string ("\\d")),
+                pure_cons (pure_cons (make_pure_c_string ("TAB"), make_pure_c_string ("\\t")),
+                   pure_cons (pure_cons (make_pure_c_string ("RET"), make_pure_c_string ("\\r")),
+                          pure_cons (pure_cons (make_pure_c_string ("ESC"), make_pure_c_string ("\\e")),
+                                 pure_cons (pure_cons (make_pure_c_string ("SPC"), make_pure_c_string (" ")),
                                         Qnil)))));
   staticpro (&exclude_keys);
 
@@ -4062,11 +3890,11 @@ don't alter it yourself.  */);
   Fset_keymap_parent (Vminibuffer_local_must_match_map,
                      Vminibuffer_local_completion_map);
 
-  DEFVAR_LISP ("minibuffer-local-must-match-filename-map",
-              &Vminibuffer_local_must_match_filename_map,
+  DEFVAR_LISP ("minibuffer-local-filename-must-match-map",
+              &Vminibuffer_local_filename_must_match_map,
               doc: /* Local keymap for minibuffer input with completion for filenames with exact match.  */);
-  Vminibuffer_local_must_match_filename_map = Fmake_sparse_keymap (Qnil);
-  Fset_keymap_parent (Vminibuffer_local_must_match_filename_map,
+  Vminibuffer_local_filename_must_match_map = Fmake_sparse_keymap (Qnil);
+  Fset_keymap_parent (Vminibuffer_local_filename_must_match_map,
                      Vminibuffer_local_must_match_map);
 
   DEFVAR_LISP ("minor-mode-map-alist", &Vminor_mode_map_alist,
@@ -4093,37 +3921,49 @@ the same way.  The "active" keymaps in each alist are used before
 `minor-mode-map-alist' and `minor-mode-overriding-map-alist'.  */);
   Vemulation_mode_map_alists = Qnil;
 
+  DEFVAR_LISP ("where-is-preferred-modifier", &Vwhere_is_preferred_modifier,
+              doc: /* Preferred modifier to use for `where-is'.
+When a single binding is requested, `where-is' will return one that
+uses this modifier if possible.  If nil, or if no such binding exists,
+bindings using keys without modifiers (or only with meta) will be
+preferred.  */);
+  Vwhere_is_preferred_modifier = Qnil;
+  where_is_preferred_modifier = 0;
+
   staticpro (&Vmouse_events);
-  Vmouse_events = Fcons (intern ("menu-bar"),
-                 Fcons (intern ("tool-bar"),
-                 Fcons (intern ("header-line"),
-                 Fcons (intern ("mode-line"),
-                 Fcons (intern ("mouse-1"),
-                 Fcons (intern ("mouse-2"),
-                 Fcons (intern ("mouse-3"),
-                 Fcons (intern ("mouse-4"),
-                 Fcons (intern ("mouse-5"),
-                        Qnil)))))))));
-
-
-  Qsingle_key_description = intern ("single-key-description");
+  Vmouse_events = pure_cons (intern_c_string ("menu-bar"),
+                 pure_cons (intern_c_string ("tool-bar"),
+                 pure_cons (intern_c_string ("header-line"),
+                 pure_cons (intern_c_string ("mode-line"),
+                 pure_cons (intern_c_string ("mouse-1"),
+                 pure_cons (intern_c_string ("mouse-2"),
+                 pure_cons (intern_c_string ("mouse-3"),
+                 pure_cons (intern_c_string ("mouse-4"),
+                 pure_cons (intern_c_string ("mouse-5"),
+                            Qnil)))))))));
+
+
+  Qsingle_key_description = intern_c_string ("single-key-description");
   staticpro (&Qsingle_key_description);
 
-  Qkey_description = intern ("key-description");
+  Qkey_description = intern_c_string ("key-description");
   staticpro (&Qkey_description);
 
-  Qkeymapp = intern ("keymapp");
+  Qkeymapp = intern_c_string ("keymapp");
   staticpro (&Qkeymapp);
 
-  Qnon_ascii = intern ("non-ascii");
+  Qnon_ascii = intern_c_string ("non-ascii");
   staticpro (&Qnon_ascii);
 
-  Qmenu_item = intern ("menu-item");
+  Qmenu_item = intern_c_string ("menu-item");
   staticpro (&Qmenu_item);
 
-  Qremap = intern ("remap");
+  Qremap = intern_c_string ("remap");
   staticpro (&Qremap);
 
+  QCadvertised_binding = intern_c_string (":advertised-binding");
+  staticpro (&QCadvertised_binding);
+
   command_remapping_vector = Fmake_vector (make_number (2), Qremap);
   staticpro (&command_remapping_vector);
 
@@ -4138,6 +3978,7 @@ the same way.  The "active" keymaps in each alist are used before
   defsubr (&Sset_keymap_parent);
   defsubr (&Smake_keymap);
   defsubr (&Smake_sparse_keymap);
+  defsubr (&Smap_keymap_internal);
   defsubr (&Smap_keymap);
   defsubr (&Scopy_keymap);
   defsubr (&Scommand_remapping);
@@ -4165,10 +4006,10 @@ the same way.  The "active" keymaps in each alist are used before
 }
 
 void
-keys_of_keymap ()
+keys_of_keymap (void)
 {
   initial_define_key (global_map, 033, "ESC-prefix");
-  initial_define_key (global_map, Ctl('X'), "Control-X-prefix");
+  initial_define_key (global_map, Ctl ('X'), "Control-X-prefix");
 }
 
 /* arch-tag: 6dd15c26-7cf1-41c4-b904-f42f7ddda463