1 /* infodoc.c -- Functions which build documentation nodes.
2 $Id: infodoc.c,v 1.28 2002/02/27 13:37:33 karl Exp $
4 Copyright (C) 1993, 97, 98, 99, 2001, 02 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox (bfox@ai.mit.edu). */
25 /* HELP_NODE_GETS_REGENERATED is always defined now that keys may get
26 rebound, or other changes in the help text may occur. */
27 #define HELP_NODE_GETS_REGENERATED 1
29 /* The name of the node used in the help window. */
30 static char *info_help_nodename = "*Info Help*";
32 /* A node containing printed key bindings and their documentation. */
33 static NODE *internal_info_help_node = (NODE *)NULL;
35 /* A pointer to the contents of the help node. */
36 static char *internal_info_help_node_contents = (char *)NULL;
38 /* The (more or less) static text which appears in the internal info
39 help node. The actual key bindings are inserted. Keep the
40 underlines (****, etc.) in the same N_ call as the text lines they
41 refer to, so translations can make the number of *'s or -'s match. */
44 static char *info_internal_help_text[] = {
45 N_("Basic Commands in Info Windows\n\
46 ******************************\n"),
48 N_("\\%-10[quit-help] Quit this help.\n"),
49 N_("\\%-10[quit] Quit Info altogether.\n"),
50 N_("\\%-10[get-info-help-node] Invoke the Info tutorial.\n"),
52 N_("Selecting other nodes:\n\
53 ----------------------\n"),
54 N_("\\%-10[next-node] Move to the \"next\" node of this node.\n"),
55 N_("\\%-10[prev-node] Move to the \"previous\" node of this node.\n"),
56 N_("\\%-10[up-node] Move \"up\" from this node.\n"),
57 N_("\\%-10[menu-item] Pick menu item specified by name.\n\
58 Picking a menu item causes another node to be selected.\n"),
59 N_("\\%-10[xref-item] Follow a cross reference. Reads name of reference.\n"),
60 N_("\\%-10[history-node] Move to the last node seen in this window.\n"),
61 N_("\\%-10[move-to-next-xref] Skip to next hypertext link within this node.\n"),
62 N_("\\%-10[move-to-prev-xref] Skip to previous hypertext link within this node.\n"),
63 N_("\\%-10[select-reference-this-line] Follow the hypertext link under cursor.\n"),
64 N_("\\%-10[dir-node] Move to the `directory' node. Equivalent to `\\[goto-node] (DIR)'.\n"),
65 N_("\\%-10[top-node] Move to the Top node. Equivalent to `\\[goto-node] Top'.\n"),
67 N_("Moving within a node:\n\
68 ---------------------\n"),
69 N_("\\%-10[scroll-forward] Scroll forward a page.\n"),
70 N_("\\%-10[scroll-backward] Scroll backward a page.\n"),
71 N_("\\%-10[beginning-of-node] Go to the beginning of this node.\n"),
72 N_("\\%-10[end-of-node] Go to the end of this node.\n"),
73 N_("\\%-10[scroll-forward] Scroll forward 1 line.\n"),
74 N_("\\%-10[scroll-backward] Scroll backward 1 line.\n"),
76 N_("Other commands:\n\
78 N_("\\%-10[menu-digit] Pick first ... ninth item in node's menu.\n"),
79 N_("\\%-10[last-menu-item] Pick last item in node's menu.\n"),
80 N_("\\%-10[index-search] Search for a specified string in the index entries of this Info\n\
81 file, and select the node referenced by the first entry found.\n"),
82 N_("\\%-10[goto-node] Move to node specified by name.\n\
83 You may include a filename as well, as in (FILENAME)NODENAME.\n"),
84 N_("\\%-10[search] Search forward for a specified string\n\
85 and select the node in which the next occurrence is found.\n"),
86 N_("\\%-10[search-backward] Search backward for a specified string\n\
87 and select the node in which the previous occurrence is found.\n"),
93 static char *info_internal_help_text[] = {
94 N_("Basic Commands in Info Windows\n\
95 ******************************\n"),
97 N_(" %-10s Quit this help.\n"),
98 N_(" %-10s Quit Info altogether.\n"),
99 N_(" %-10s Invoke the Info tutorial.\n"),
101 N_("Selecting other nodes:\n\
102 ----------------------\n",
103 N_(" %-10s Move to the `next' node of this node.\n"),
104 N_(" %-10s Move to the `previous' node of this node.\n"),
105 N_(" %-10s Move `up' from this node.\n"),
106 N_(" %-10s Pick menu item specified by name.\n"),
107 N_(" Picking a menu item causes another node to be selected.\n"),
108 N_(" %-10s Follow a cross reference. Reads name of reference.\n"),
109 N_(" %-10s Move to the last node seen in this window.\n"),
110 N_(" %-10s Skip to next hypertext link within this node.\n"),
111 N_(" %-10s Follow the hypertext link under cursor.\n"),
112 N_(" %-10s Move to the `directory' node. Equivalent to `g (DIR)'.\n"),
113 N_(" %-10s Move to the Top node. Equivalent to `g Top'.\n"),
115 N_("Moving within a node:\n\
116 ---------------------\n"),
117 N_(" %-10s Scroll forward a page.\n"),
118 N_(" %-10s Scroll backward a page.\n"),
119 N_(" %-10s Go to the beginning of this node.\n"),
120 N_(" %-10s Go to the end of this node.\n"),
121 N_(" %-10s Scroll forward 1 line.\n"),
122 N_(" %-10s Scroll backward 1 line.\n"),
124 N_("Other commands:\n\
126 N_(" %-10s Pick first ... ninth item in node's menu.\n"),
127 N_(" %-10s Pick last item in node's menu.\n"),
128 N_(" %-10s Search for a specified string in the index entries of this Info\n"),
129 N_(" file, and select the node referenced by the first entry found.\n"),
130 N_(" %-10s Move to node specified by name.\n"),
131 N_(" You may include a filename as well, as in (FILENAME)NODENAME.\n"),
132 N_(" %-10s Search forward for a specified string,\n"),
133 N_(" and select the node in which the next occurrence is found.\n"),
134 N_(" %-10s Search backward for a specified string\n"),
135 N_(" and select the node in which the next occurrence is found.\n"),
139 static char *info_help_keys_text[][2] = {
143 { "CTRL-x 0", "CTRL-x 0" },
153 { "ESC 1 SPC", "RET" },
154 { "ESC 1 DEL", "y" },
166 { "RET", "CTRL-x RET" },
172 { "1-9", "ESC 1-9" },
185 #endif /* !INFOKEY */
187 static char *where_is_internal ();
190 dump_map_to_message_buffer (prefix, map)
195 unsigned prefix_len = strlen (prefix);
196 char *new_prefix = (char *)xmalloc (prefix_len + 2);
198 strncpy (new_prefix, prefix, prefix_len);
199 new_prefix[prefix_len + 1] = '\0';
201 for (i = 0; i < 256; i++)
203 new_prefix[prefix_len] = i;
204 if (map[i].type == ISKMAP)
206 dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
208 else if (map[i].function)
213 doc = function_documentation (map[i].function);
214 name = function_name (map[i].function);
219 /* Find out if there is a series of identical functions, as in
221 for (last = i + 1; last < 256; last++)
222 if ((map[last].type != ISFUNC) ||
223 (map[last].function != map[i].function))
228 printf_to_message_buffer ("%s .. ", pretty_keyseq (new_prefix));
229 new_prefix[prefix_len] = last - 1;
230 printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix));
234 printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix));
236 #if defined (NAMED_FUNCTIONS)
237 /* Print the name of the function, and some padding before the
238 documentation string is printed. */
241 int desired_doc_start = 40; /* Must be multiple of 8. */
243 printf_to_message_buffer ("(%s)", name);
244 length_so_far = message_buffer_length_this_line ();
246 if ((desired_doc_start + strlen (doc)) >= the_screen->width)
247 printf_to_message_buffer ("\n ");
250 while (length_so_far < desired_doc_start)
252 printf_to_message_buffer ("\t");
253 length_so_far += character_width ('\t', length_so_far);
257 #endif /* NAMED_FUNCTIONS */
258 printf_to_message_buffer ("%s\n", doc);
264 /* How to create internal_info_help_node. HELP_IS_ONLY_WINDOW_P says
265 whether we're going to end up in a second (or more) window of our
266 own, or whether there's only one window and we're going to usurp it.
267 This determines how to quit the help window. Maybe we should just
268 make q do the right thing in both cases. */
271 create_internal_info_help_node (help_is_only_window_p)
272 int help_is_only_window_p;
276 char *contents = NULL;
279 #ifndef HELP_NODE_GETS_REGENERATED
280 if (internal_info_help_node_contents)
281 contents = internal_info_help_node_contents;
282 #endif /* !HELP_NODE_GETS_REGENERATED */
286 int printed_one_mx = 0;
288 initialize_message_buffer ();
290 for (i = 0; info_internal_help_text[i]; i++)
293 printf_to_message_buffer (replace_in_documentation (
294 _(info_internal_help_text[i]), help_is_only_window_p));
296 /* Don't translate blank lines, gettext outputs the po file
297 header in that case. We want a blank line. */
298 char *msg = *(info_internal_help_text[i])
299 ? _(info_internal_help_text[i])
300 : info_internal_help_text[i];
301 char *key = info_help_keys_text[i][vi_keys_p];
303 /* If we have only one window (because the window size was too
304 small to split it), CTRL-x 0 doesn't work to `quit' help. */
305 if (STREQ (key, "CTRL-x 0") && help_is_only_window_p)
308 printf_to_message_buffer (msg, key);
309 #endif /* !INFOKEY */
312 printf_to_message_buffer ("---------------------\n\n");
313 printf_to_message_buffer (_("The current search path is:\n"));
314 printf_to_message_buffer (" %s\n", infopath);
315 printf_to_message_buffer ("---------------------\n\n");
316 printf_to_message_buffer (_("Commands available in Info windows:\n\n"));
317 dump_map_to_message_buffer ("", info_keymap);
318 printf_to_message_buffer ("---------------------\n\n");
319 printf_to_message_buffer (_("Commands available in the echo area:\n\n"));
320 dump_map_to_message_buffer ("", echo_area_keymap);
322 #if defined (NAMED_FUNCTIONS)
323 /* Get a list of commands which have no keystroke equivs. */
324 exec_keys = where_is (info_keymap, InfoCmd(info_execute_command));
326 exec_keys = xstrdup (exec_keys);
327 for (i = 0; function_doc_array[i].func; i++)
329 InfoCommand *cmd = DocInfoCmd(&function_doc_array[i]);
331 if (InfoFunction(cmd) != info_do_lowercase_version
332 && !where_is_internal (info_keymap, cmd)
333 && !where_is_internal (echo_area_keymap, cmd))
337 printf_to_message_buffer ("---------------------\n\n");
338 if (exec_keys && exec_keys[0])
339 printf_to_message_buffer
340 (_("The following commands can only be invoked via %s:\n\n"), exec_keys);
342 printf_to_message_buffer
343 (_("The following commands cannot be invoked at all:\n\n"));
347 printf_to_message_buffer
350 function_doc_array[i].func_name,
351 replace_in_documentation (strlen (function_doc_array[i].doc)
352 ? _(function_doc_array[i].doc)
360 printf_to_message_buffer ("\n");
362 maybe_free (exec_keys);
363 #endif /* NAMED_FUNCTIONS */
365 printf_to_message_buffer
366 ("%s", replace_in_documentation
367 (_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
368 node = message_buffer_to_node ();
369 internal_info_help_node_contents = node->contents;
373 /* We already had the right contents, so simply use them. */
374 node = build_message_node ("", 0, 0);
375 free (node->contents);
376 node->contents = contents;
377 node->nodelen = 1 + strlen (contents);
380 internal_info_help_node = node;
382 /* Do not GC this node's contents. It never changes, and we never need
383 to delete it once it is made. If you change some things (such as
384 placing information about dynamic variables in the help text) then
385 you will need to allow the contents to be gc'd, and you will have to
386 arrange to always regenerate the help node. */
387 #if defined (HELP_NODE_GETS_REGENERATED)
388 add_gcable_pointer (internal_info_help_node->contents);
391 name_internal_node (internal_info_help_node, info_help_nodename);
393 /* Even though this is an internal node, we don't want the window
394 system to treat it specially. So we turn off the internalness
396 internal_info_help_node->flags &= ~N_IsInternal;
399 /* Return a window which is the window showing help in this Info. */
401 /* If the eligible window's height is >= this, split it to make the help
402 window. Otherwise display the help window in the current window. */
403 #define HELP_SPLIT_SIZE 24
406 info_find_or_create_help_window ()
408 int help_is_only_window_p;
409 WINDOW *eligible = NULL;
410 WINDOW *help_window = get_window_of_node (internal_info_help_node);
412 /* If we couldn't find the help window, then make it. */
418 for (window = windows; window; window = window->next)
420 if (window->height > max)
422 max = window->height;
430 #ifndef HELP_NODE_GETS_REGENERATED
432 /* help window is static, just return it. */
434 #endif /* not HELP_NODE_GETS_REGENERATED */
436 /* Make sure that we have a node containing the help text. The
437 argument is false if help will be the only window (so l must be used
438 to quit help), true if help will be one of several visible windows
439 (so CTRL-x 0 must be used to quit help). */
440 help_is_only_window_p
441 = (help_window && !windows->next
442 || !help_window && eligible->height < HELP_SPLIT_SIZE);
443 create_internal_info_help_node (help_is_only_window_p);
445 /* Either use the existing window to display the help node, or create
446 a new window if there was no existing help window. */
448 { /* Split the largest window into 2 windows, and show the help text
450 if (eligible->height >= HELP_SPLIT_SIZE)
452 active_window = eligible;
453 help_window = window_make_window (internal_info_help_node);
457 set_remembered_pagetop_and_point (active_window);
458 window_set_node_of_window (active_window, internal_info_help_node);
459 help_window = active_window;
463 { /* Case where help node always gets regenerated, and we have an
464 existing window in which to place the node. */
465 if (active_window != help_window)
467 set_remembered_pagetop_and_point (active_window);
468 active_window = help_window;
470 window_set_node_of_window (active_window, internal_info_help_node);
472 remember_window_and_node (help_window, help_window->node);
476 /* Create or move to the help window. */
477 DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
481 help_window = info_find_or_create_help_window ();
484 active_window = help_window;
485 active_window->flags |= W_UpdateWindow;
489 info_error (msg_cant_make_help);
493 /* Show the Info help node. This means that the "info" file is installed
494 where it can easily be found on your system. */
495 DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
500 /* If there is a window on the screen showing the node "(info)Help" or
501 the node "(info)Help-Small-Screen", simply select that window. */
505 for (win = windows; win; win = win->next)
507 if (win->node && win->node->filename &&
509 (filename_non_directory (win->node->filename), "info") == 0) &&
510 ((strcmp (win->node->nodename, "Help") == 0) ||
511 (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
519 /* If the current window is small, show the small screen help. */
520 if (active_window->height < 24)
521 nodename = "Help-Small-Screen";
525 /* Try to get the info file for Info. */
526 node = info_get_node ("Info", nodename);
530 if (info_recent_file_error)
531 info_error (info_recent_file_error);
533 info_error (msg_cant_file_node, "Info", nodename);
537 /* If the current window is very large (greater than 45 lines),
538 then split it and show the help node in another window.
539 Otherwise, use the current window. */
541 if (active_window->height > 45)
542 active_window = window_make_window (node);
545 set_remembered_pagetop_and_point (active_window);
546 window_set_node_of_window (active_window, node);
549 remember_window_and_node (active_window, node);
553 /* **************************************************************** */
555 /* Groveling Info Keymaps and Docs */
557 /* **************************************************************** */
559 /* Return the documentation associated with the Info command FUNCTION. */
561 function_documentation (cmd)
566 #if defined (INFOKEY)
574 for (i = 0; function_doc_array[i].func; i++)
575 if (InfoFunction(cmd) == function_doc_array[i].func)
578 doc = function_doc_array[i].func ? function_doc_array[i].doc : "";
580 #endif /* !INFOKEY */
582 return replace_in_documentation ((strlen (doc) == 0) ? doc : _(doc));
585 #if defined (NAMED_FUNCTIONS)
586 /* Return the user-visible name of the function associated with the
587 Info command FUNCTION. */
592 #if defined (INFOKEY)
594 return cmd->func_name;
600 for (i = 0; function_doc_array[i].func; i++)
601 if (InfoFunction(cmd) == function_doc_array[i].func)
604 return (function_doc_array[i].func_name);
606 #endif /* !INFOKEY */
609 /* Return a pointer to the info command for function NAME. */
611 named_function (name)
616 for (i = 0; function_doc_array[i].func; i++)
617 if (strcmp (function_doc_array[i].func_name, name) == 0)
620 return (DocInfoCmd(&function_doc_array[i]));
622 #endif /* NAMED_FUNCTIONS */
624 /* Return the documentation associated with KEY in MAP. */
626 key_documentation (key, map)
630 InfoCommand *function = map[key].function;
633 return (function_documentation (function));
635 return ((char *)NULL);
638 DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
641 unsigned char keystroke;
646 map = window->keymap;
650 message_in_echo_area (_("Describe key: %s"), pretty_keyseq (keys));
651 keystroke = info_get_input_char ();
652 unmessage_in_echo_area ();
654 #if !defined (INFOKEY)
655 if (Meta_p (keystroke))
657 if (map[ESC].type != ISKMAP)
659 window_message_in_echo_area
660 (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
665 keystroke = UnMeta (keystroke);
666 map = (Keymap)map[ESC].function;
668 #endif /* !INFOKEY */
670 /* Add the KEYSTROKE to our list. */
674 if (map[keystroke].function == (InfoCommand *)NULL)
676 message_in_echo_area (_("%s is undefined."), pretty_keyseq (keys));
679 else if (map[keystroke].type == ISKMAP)
681 map = (Keymap)map[keystroke].function;
686 char *keyname, *message, *fundoc, *funname = "";
688 #if defined (INFOKEY)
689 /* If the key is bound to do-lowercase-version, but its
690 lower-case variant is undefined, say that this key is
691 also undefined. This is especially important for unbound
692 edit keys that emit an escape sequence: it's terribly
693 confusing to see a message "Home (do-lowercase-version)"
694 or some such when Home is unbound. */
695 if (InfoFunction(map[keystroke].function) == info_do_lowercase_version)
697 unsigned char lowerkey = Meta_p(keystroke)
698 ? Meta (tolower (UnMeta (keystroke)))
699 : tolower (keystroke);
701 if (map[lowerkey].function == (InfoCommand *)NULL)
703 message_in_echo_area (_("%s is undefined."),
704 pretty_keyseq (keys));
710 keyname = pretty_keyseq (keys);
712 #if defined (NAMED_FUNCTIONS)
713 funname = function_name (map[keystroke].function);
714 #endif /* NAMED_FUNCTIONS */
716 fundoc = function_documentation (map[keystroke].function);
718 message = (char *)xmalloc
719 (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
721 #if defined (NAMED_FUNCTIONS)
722 sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
724 sprintf (message, _("%s is defined to %s."), keyname, fundoc);
725 #endif /* !NAMED_FUNCTIONS */
727 window_message_in_echo_area ("%s", message);
734 /* Return the pretty printable name of a single character. */
739 static char rep_buffer[30];
746 rep = pretty_keyname (UnMeta (key));
748 #if defined (INFOKEY)
749 sprintf (temp, "M-%s", rep);
751 sprintf (temp, "ESC %s", rep);
752 #endif /* !INFOKEY */
753 strcpy (rep_buffer, temp);
756 else if (Control_p (key))
760 case '\n': rep = "LFD"; break;
761 case '\t': rep = "TAB"; break;
762 case '\r': rep = "RET"; break;
763 case ESC: rep = "ESC"; break;
766 sprintf (rep_buffer, "C-%c", UnControl (key));
774 case ' ': rep = "SPC"; break;
775 case DEL: rep = "DEL"; break;
778 rep_buffer[1] = '\0';
785 /* Return the pretty printable string which represents KEYSEQ. */
787 static void pretty_keyseq_internal ();
790 pretty_keyseq (keyseq)
793 static char keyseq_rep[200];
795 keyseq_rep[0] = '\0';
797 pretty_keyseq_internal (keyseq, keyseq_rep);
802 pretty_keyseq_internal (keyseq, rep)
805 if (term_kP && strncmp(keyseq, term_kP, strlen(term_kP)) == 0)
808 keyseq += strlen(term_kP);
810 else if (term_kN && strncmp(keyseq, term_kN, strlen(term_kN)) == 0)
813 keyseq += strlen(term_kN);
816 else if (term_kh && strncmp(keyseq, term_kh, strlen(term_kh)) == 0)
819 keyseq += strlen(term_kh);
821 else if (term_ke && strncmp(keyseq, term_ke, strlen(term_ke)) == 0)
824 keyseq += strlen(term_ke);
826 else if (term_ki && strncmp(keyseq, term_ki, strlen(term_ki)) == 0)
829 keyseq += strlen(term_ki);
831 else if (term_kx && strncmp(keyseq, term_kx, strlen(term_kx)) == 0)
834 keyseq += strlen(term_kx);
837 else if (term_ku && strncmp(keyseq, term_ku, strlen(term_ku)) == 0)
840 keyseq += strlen(term_ku);
842 else if (term_kd && strncmp(keyseq, term_kd, strlen(term_kd)) == 0)
845 keyseq += strlen(term_kd);
847 else if (term_kl && strncmp(keyseq, term_kl, strlen(term_kl)) == 0)
850 keyseq += strlen(term_kl);
852 else if (term_kr && strncmp(keyseq, term_kr, strlen(term_kr)) == 0)
854 strcpy(rep, "Right");
855 keyseq += strlen(term_kr);
859 strcpy (rep, pretty_keyname (keyseq[0]));
865 pretty_keyseq_internal (keyseq, rep + strlen(rep));
869 /* Return a pointer to the last character in s that is found in f. */
874 register const char *e = s + strlen(s);
875 register const char *t;
886 /* Replace the names of functions with the key that invokes them. */
888 replace_in_documentation (string, help_is_only_window_p)
890 int help_is_only_window_p;
892 unsigned reslen = strlen (string);
893 register int i, start, next;
894 static char *result = (char *)NULL;
897 result = (char *)xmalloc (1 + reslen);
899 i = next = start = 0;
901 /* Skip to the beginning of a replaceable function. */
902 for (i = start; string[i]; i++)
906 /* Is this the start of a replaceable function name? */
907 if (string[i] == '\\')
915 if (string[++j] == '-')
917 if (isdigit(string[j]))
919 min = atoi(string + j);
920 while (isdigit(string[j]))
922 if (string[j] == '.' && isdigit(string[j + 1]))
925 max = atoi(string + j);
926 while (isdigit(string[j]))
929 fmt = (char *)xmalloc (j - i + 2);
930 strncpy (fmt, string + i + 1, j - i);
931 fmt[j - i - 1] = 's';
937 if (string[j] == '[')
941 char *rep_name, *fun_name, *rep;
942 InfoCommand *command;
946 /* Copy in the old text. */
947 strncpy (result + next, string + start, i - start);
951 /* Look for an optional numeric arg. */
953 if (isdigit(string[i])
954 || (string[i] == '-' && isdigit(string[i + 1])) )
956 arg = atoi(string + i);
957 if (string[i] == '-')
959 while (isdigit(string[i]))
964 /* Move to the end of the function name. */
965 for (i = start; string[i] && (string[i] != ']'); i++);
967 rep_name = (char *)xmalloc (1 + i - start);
968 strncpy (rep_name, string + start, i - start);
969 rep_name[i - start] = '\0';
971 /* If we have only one window (because the window size was too
972 small to split it), we have to quit help by going back one
973 noew in the history list, not deleting the window. */
974 if (strcmp (rep_name, "quit-help") == 0)
975 fun_name = help_is_only_window_p ? "history-node"
980 /* Find a key which invokes this function in the info_keymap. */
981 command = named_function (fun_name);
985 /* If the internal documentation string fails, there is a
986 serious problem with the associated command's documentation.
987 We croak so that it can be fixed immediately. */
995 argrep = where_is (info_keymap, InfoCmd(info_add_digit_to_numeric_arg));
996 p = argrep ? strrpbrk (argrep, "0123456789-") : NULL;
999 argstr = (char *)xmalloc (p - argrep + 21);
1000 strncpy (argstr, argrep, p - argrep);
1001 sprintf (argstr + (p - argrep), "%d", arg);
1006 rep = command ? where_is (info_keymap, command) : NULL;
1009 replen = (argstr ? strlen (argstr) + 1 : 0) + strlen (rep);
1010 repstr = (char *)xmalloc (replen);
1014 strcat(repstr, argstr);
1015 strcat(repstr, " ");
1018 strcat(repstr, rep);
1027 if (next + replen > reslen)
1029 reslen = next + replen + 1;
1030 result = (char *)xrealloc (result, reslen + 1);
1034 sprintf (result + next, fmt, repstr);
1036 strcpy (result + next, repstr);
1038 next = strlen (result);
1049 strcpy (result + next, string + start);
1053 /* Return a string of characters which could be typed from the keymap
1054 MAP to invoke FUNCTION. */
1055 static char *where_is_rep = (char *)NULL;
1056 static int where_is_rep_index = 0;
1057 static int where_is_rep_size = 0;
1066 if (!where_is_rep_size)
1067 where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
1068 where_is_rep_index = 0;
1070 rep = where_is_internal (map, cmd);
1072 /* If it couldn't be found, return "M-x Foo" (or equivalent). */
1077 name = function_name (cmd);
1079 return NULL; /* no such function */
1081 rep = where_is_internal (map, InfoCmd(info_execute_command));
1083 return ""; /* function exists but can't be got to by user */
1085 sprintf (where_is_rep, "%s %s", rep, name);
1092 /* Return the printed rep of the keystrokes that invoke FUNCTION,
1093 as found in MAP, or NULL. */
1095 where_is_internal (map, cmd)
1099 #if defined(INFOKEY)
1101 register FUNCTION_KEYSEQ *k;
1103 for (k = cmd->keys; k; k = k->next)
1105 return pretty_keyseq (k->keyseq);
1109 #else /* !INFOKEY */
1113 /* If the function is directly invokable in MAP, return the representation
1114 of that keystroke. */
1115 for (i = 0; i < 256; i++)
1116 if ((map[i].type == ISFUNC) && map[i].function == cmd)
1118 sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
1119 return (where_is_rep);
1122 /* Okay, search subsequent maps for this function. */
1123 for (i = 0; i < 256; i++)
1125 if (map[i].type == ISKMAP)
1127 int saved_index = where_is_rep_index;
1130 sprintf (where_is_rep + where_is_rep_index, "%s ",
1131 pretty_keyname (i));
1133 where_is_rep_index = strlen (where_is_rep);
1134 rep = where_is_internal ((Keymap)map[i].function, cmd);
1137 return (where_is_rep);
1139 where_is_rep_index = saved_index;
1145 #endif /* INFOKEY */
1148 extern char *read_function_name ();
1150 DECLARE_INFO_COMMAND (info_where_is,
1151 _("Show what to type to execute a given command"))
1155 command_name = read_function_name (_("Where is command: "), window);
1159 info_abort_key (active_window, count, key);
1165 InfoCommand *command;
1167 command = named_function (command_name);
1173 location = where_is (active_window->keymap, command);
1175 if (!location || !location[0])
1177 info_error (_("`%s' is not on any keys"), command_name);
1181 if (strstr (location, function_name (command)))
1182 window_message_in_echo_area
1183 (_("%s can only be invoked via %s."), command_name, location);
1185 window_message_in_echo_area
1186 (_("%s can be invoked via %s."), command_name, location);
1190 info_error (_("There is no function named `%s'"), command_name);
1193 free (command_name);