+\f
+/* Construct the vectors that describe a menu
+ and store them in *VECTOR, *PANES, *NAMES, *ENABLES and *ITEMS.
+ Each of those four values is a vector indexed by pane number.
+ Return the number of panes.
+
+ KEYMAPS is a vector of keymaps. NMAPS gives the length of KEYMAPS. */
+
+int
+keymap_panes (vector, panes, names, enables, items, prefixes, keymaps, nmaps)
+ Lisp_Object ***vector; /* RETURN all menu objects */
+ char ***panes; /* RETURN pane names */
+ char ****names; /* RETURN all line names */
+ int ***enables; /* RETURN enable-flags of lines */
+ int **items; /* RETURN number of items per pane */
+ Lisp_Object **prefixes; /* RETURN vector of prefix keys, per pane */
+ Lisp_Object *keymaps;
+ int nmaps;
+{
+ /* Number of panes we have made. */
+ int p = 0;
+ /* Number of panes we have space for. */
+ int npanes_allocated = nmaps;
+ int mapno;
+
+ if (npanes_allocated < 4)
+ npanes_allocated = 4;
+
+ /* Make space for an estimated number of panes. */
+ *vector = (Lisp_Object **) xmalloc (npanes_allocated * sizeof (Lisp_Object *));
+ *panes = (char **) xmalloc (npanes_allocated * sizeof (char *));
+ *items = (int *) xmalloc (npanes_allocated * sizeof (int));
+ *names = (char ***) xmalloc (npanes_allocated * sizeof (char **));
+ *enables = (int **) xmalloc (npanes_allocated * sizeof (int *));
+ *prefixes = (Lisp_Object *) xmalloc (npanes_allocated * sizeof (Lisp_Object));
+
+ /* Loop over the given keymaps, making a pane for each map.
+ But don't make a pane that is empty--ignore that map instead.
+ P is the number of panes we have made so far. */
+ for (mapno = 0; mapno < nmaps; mapno++)
+ single_keymap_panes (keymaps[mapno], panes, vector, names, enables, items,
+ prefixes, &p, &npanes_allocated, "");
+
+ /* Return the number of panes. */
+ return p;
+}
+
+/* This is a recursive subroutine of the previous function.
+ It handles one keymap, KEYMAP.
+ The other arguments are passed along
+ or point to local variables of the previous function. */
+
+single_keymap_panes (keymap, panes, vector, names, enables, items, prefixes,
+ p_ptr, npanes_allocated_ptr, pane_name)
+ Lisp_Object keymap;
+ Lisp_Object ***vector; /* RETURN all menu objects */
+ char ***panes; /* RETURN pane names */
+ char ****names; /* RETURN all line names */
+ int ***enables; /* RETURN enable flags of lines */
+ int **items; /* RETURN number of items per pane */
+ Lisp_Object **prefixes; /* RETURN vector of prefix keys, per pane */
+ int *p_ptr;
+ int *npanes_allocated_ptr;
+ char *pane_name;
+{
+ int i;
+ Lisp_Object pending_maps;
+ Lisp_Object tail, item, item1, item2, table;
+
+ pending_maps = Qnil;
+
+ /* Make sure we have room for another pane. */
+ if (*p_ptr == *npanes_allocated_ptr)
+ {
+ *npanes_allocated_ptr *= 2;
+
+ *vector
+ = (Lisp_Object **) xrealloc (*vector,
+ *npanes_allocated_ptr * sizeof (Lisp_Object *));
+ *panes
+ = (char **) xrealloc (*panes,
+ *npanes_allocated_ptr * sizeof (char *));
+ *items
+ = (int *) xrealloc (*items,
+ *npanes_allocated_ptr * sizeof (int));
+ *prefixes
+ = (Lisp_Object *) xrealloc (*prefixes,
+ (*npanes_allocated_ptr
+ * sizeof (Lisp_Object)));
+ *names
+ = (char ***) xrealloc (*names,
+ *npanes_allocated_ptr * sizeof (char **));
+ *enables
+ = (int **) xrealloc (*enables,
+ *npanes_allocated_ptr * sizeof (int *));
+ }
+
+ /* When a menu comes from keymaps, don't give names to the panes. */
+ (*panes)[*p_ptr] = pane_name;
+
+ /* Normally put nil as pane's prefix key.
+ Caller will override this if appropriate. */
+ (*prefixes)[*p_ptr] = Qnil;
+
+ /* Get the length of the list level of the keymap. */
+ i = XFASTINT (Flength (keymap));
+
+ /* Add in lengths of any arrays. */
+ for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
+ if (XTYPE (XCONS (tail)->car) == Lisp_Vector)
+ i += XVECTOR (XCONS (tail)->car)->size;
+
+ /* Create vectors for the names and values of the items in the pane.
+ I is an upper bound for the number of items. */
+ (*vector)[*p_ptr] = (Lisp_Object *) xmalloc (i * sizeof (Lisp_Object));
+ (*names)[*p_ptr] = (char **) xmalloc (i * sizeof (char *));
+ (*enables)[*p_ptr] = (int *) xmalloc (i * sizeof (int));
+
+ /* I is now the index of the next unused slots. */
+ i = 0;
+ for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
+ {
+ /* Look at each key binding, and if it has a menu string,
+ make a menu item from it. */
+ item = XCONS (tail)->car;
+ if (XTYPE (item) == Lisp_Cons)
+ {
+ item1 = XCONS (item)->cdr;
+ if (XTYPE (item1) == Lisp_Cons)
+ {
+ item2 = XCONS (item1)->car;
+ if (XTYPE (item2) == Lisp_String)
+ {
+ Lisp_Object def, tem;
+ Lisp_Object enabled;
+
+ def = Fcdr (item1);
+ enabled = Qt;
+ if (XTYPE (def) == Lisp_Symbol)
+ {
+ /* No property, or nil, means enable.
+ Otherwise, enable if value is not nil. */
+ tem = Fget (def, Qmenu_enable);
+ if (!NILP (tem))
+ enabled = Feval (tem);
+ }
+ tem = Fkeymapp (def);
+ if (XSTRING (item2)->data[0] == '@' && !NILP (tem))
+ pending_maps = Fcons (Fcons (def, Fcons (item2, XCONS (item)->car)),
+ pending_maps);
+ else
+ {
+ (*names)[*p_ptr][i] = (char *) XSTRING (item2)->data;
+ /* The menu item "value" is the key bound here. */
+ (*vector)[*p_ptr][i] = XCONS (item)->car;
+ (*enables)[*p_ptr][i]
+ = (NILP (def) ? -1 : !NILP (enabled) ? 1 : 0);
+ i++;
+ }
+ }
+ }
+ }
+ else if (XTYPE (item) == Lisp_Vector)
+ {
+ /* Loop over the char values represented in the vector. */
+ int len = XVECTOR (item)->size;
+ int c;
+ for (c = 0; c < len; c++)
+ {
+ Lisp_Object character;
+ XFASTINT (character) = c;
+ item1 = XVECTOR (item)->contents[c];
+ if (XTYPE (item1) == Lisp_Cons)
+ {
+ item2 = XCONS (item1)->car;
+ if (XTYPE (item2) == Lisp_String)
+ {
+ Lisp_Object tem;
+ Lisp_Object def;
+ Lisp_Object enabled;
+
+ def = Fcdr (item1);
+ enabled = Qt;
+ if (XTYPE (def) == Lisp_Symbol)
+ {
+ tem = Fget (def, Qmenu_enable);
+ /* No property, or nil, means enable.
+ Otherwise, enable if value is not nil. */
+ if (!NILP (tem))
+ enabled = Feval (tem);
+ }
+
+ tem = Fkeymapp (def);
+ if (XSTRING (item2)->data[0] == '@' && !NILP (tem))
+ pending_maps = Fcons (Fcons (def, Fcons (item2, character)),
+ pending_maps);
+ else
+ {
+ (*names)[*p_ptr][i] = (char *) XSTRING (item2)->data;
+ /* The menu item "value" is the key bound here. */
+ (*vector)[*p_ptr][i] = character;
+ (*enables)[*p_ptr][i]
+ = (NILP (def) ? -1 : !NILP (enabled) ? 1 : 0);
+ i++;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Record the number of items in the pane. */
+ (*items)[*p_ptr] = i;
+
+ /* If we just made an empty pane, get rid of it. */
+ if (i == 0)
+ {
+ xfree ((*vector)[*p_ptr]);
+ xfree ((*names)[*p_ptr]);
+ xfree ((*enables)[*p_ptr]);
+ }
+ /* Otherwise, advance past it. */
+ else
+ (*p_ptr)++;
+
+ /* Process now any submenus which want to be panes at this level. */
+ while (!NILP (pending_maps))
+ {
+ Lisp_Object elt, eltcdr;
+ int panenum = *p_ptr;
+ elt = Fcar (pending_maps);
+ eltcdr = XCONS (elt)->cdr;
+ single_keymap_panes (Fcar (elt), panes, vector, names, enables, items,
+ prefixes, p_ptr, npanes_allocated_ptr,
+ /* Add 1 to discard the @. */
+ (char *) XSTRING (XCONS (eltcdr)->car)->data + 1);
+ (*prefixes)[panenum] = XCONS (eltcdr)->cdr;
+ pending_maps = Fcdr (pending_maps);
+ }
+}
+\f
+/* Construct the vectors that describe a menu
+ and store them in *VECTOR, *PANES, *NAMES, *ENABLES and *ITEMS.
+ Each of those four values is a vector indexed by pane number.
+ Return the number of panes.