+
+/* This is the function that Fwhere_is_internal calls using map_char_table.
+ ARGS has the form
+ (((DEFINITION . NOINDIRECT) . (KEYMAP . RESULT))
+ .
+ ((THIS . LAST) . (NOMENUS . LAST_IS_META)))
+ Since map_char_table doesn't really use the return value from this function,
+ we the result append to RESULT, the slot in ARGS.
+
+ This function can GC because it calls where_is_internal_1 which can
+ GC. */
+
+static void
+where_is_internal_2 (args, key, binding)
+ Lisp_Object args, key, binding;
+{
+ Lisp_Object definition, noindirect, keymap, this, last;
+ Lisp_Object result, sequence;
+ int nomenus, last_is_meta;
+ struct gcpro gcpro1, gcpro2, gcpro3;
+
+ GCPRO3 (args, key, binding);
+ result = XCDR (XCDR (XCAR (args)));
+ definition = XCAR (XCAR (XCAR (args)));
+ noindirect = XCDR (XCAR (XCAR (args)));
+ keymap = XCAR (XCDR (XCAR (args)));
+ this = XCAR (XCAR (XCDR (args)));
+ last = XCDR (XCAR (XCDR (args)));
+ nomenus = XFASTINT (XCAR (XCDR (XCDR (args))));
+ last_is_meta = XFASTINT (XCDR (XCDR (XCDR (args))));
+
+ sequence = where_is_internal_1 (binding, key, definition, noindirect, keymap,
+ this, last, nomenus, last_is_meta);
+
+ if (!NILP (sequence))
+ XCDR (XCDR (XCAR (args))) = Fcons (sequence, result);
+
+ UNGCPRO;
+}
+
+
+/* This function can GC.because Flookup_key calls get_keymap_1 with
+ non-zero argument AUTOLOAD. */
+
+static Lisp_Object
+where_is_internal_1 (binding, key, definition, noindirect, keymap, this, last,
+ nomenus, last_is_meta)
+ Lisp_Object binding, key, definition, noindirect, keymap, this, last;
+ int nomenus, last_is_meta;
+{
+ Lisp_Object sequence;
+ int keymap_specified = !NILP (keymap);
+ struct gcpro gcpro1, gcpro2;
+
+ /* Search through indirections unless that's not wanted. */
+ if (NILP (noindirect))
+ {
+ if (nomenus)
+ {
+ while (1)
+ {
+ Lisp_Object map, tem;
+ /* If the contents are (KEYMAP . ELEMENT), go indirect. */
+ map = get_keymap_1 (Fcar_safe (definition), 0, 0);
+ tem = Fkeymapp (map);
+ if (!NILP (tem))
+ definition = access_keymap (map, Fcdr (definition), 0, 0);
+ else
+ break;
+ }
+ /* If the contents are (menu-item ...) or (STRING ...), reject. */
+ if (CONSP (definition)
+ && (EQ (XCAR (definition),Qmenu_item)
+ || STRINGP (XCAR (definition))))
+ return Qnil;
+ }
+ else
+ binding = get_keyelt (binding, 0);
+ }
+
+ /* End this iteration if this element does not match
+ the target. */
+
+ if (CONSP (definition))
+ {
+ Lisp_Object tem;
+ tem = Fequal (binding, definition);
+ if (NILP (tem))
+ return Qnil;
+ }
+ else
+ if (!EQ (binding, definition))
+ return Qnil;
+
+ /* We have found a match.
+ Construct the key sequence where we found it. */
+ if (INTEGERP (key) && last_is_meta)
+ {
+ sequence = Fcopy_sequence (this);
+ Faset (sequence, last, make_number (XINT (key) | meta_modifier));
+ }
+ else
+ sequence = append_key (this, key);
+
+ /* 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. */
+ GCPRO2 (sequence, binding);
+ if (keymap_specified)
+ {
+ binding = Flookup_key (keymap, sequence, Qnil);
+ if (!NILP (binding) && !INTEGERP (binding))
+ {
+ if (CONSP (definition))
+ {
+ Lisp_Object tem;
+ tem = Fequal (binding, definition);
+ if (NILP (tem))
+ RETURN_UNGCPRO (Qnil);
+ }
+ else
+ if (!EQ (binding, definition))
+ RETURN_UNGCPRO (Qnil);
+ }
+ }
+ else
+ {
+ binding = Fkey_binding (sequence, Qnil);
+ if (!EQ (binding, definition))
+ RETURN_UNGCPRO (Qnil);
+ }
+
+ RETURN_UNGCPRO (sequence);
+}