1114472Sru/* infodoc.c -- functions which build documentation nodes. 2146515Sru $Id: infodoc.c,v 1.8 2004/04/11 17:56:45 karl Exp $ 321495Sjmacd 4146515Sru Copyright (C) 1993, 1997, 1998, 1999, 2001, 2002, 2003, 2004 Free Software 5114472Sru Foundation, Inc. 621495Sjmacd 721495Sjmacd This program is free software; you can redistribute it and/or modify 821495Sjmacd it under the terms of the GNU General Public License as published by 921495Sjmacd the Free Software Foundation; either version 2, or (at your option) 1021495Sjmacd any later version. 1121495Sjmacd 1221495Sjmacd This program is distributed in the hope that it will be useful, 1321495Sjmacd but WITHOUT ANY WARRANTY; without even the implied warranty of 1421495Sjmacd MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1521495Sjmacd GNU General Public License for more details. 1621495Sjmacd 1721495Sjmacd You should have received a copy of the GNU General Public License 1821495Sjmacd along with this program; if not, write to the Free Software 1921495Sjmacd Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2021495Sjmacd 2121495Sjmacd Written by Brian Fox (bfox@ai.mit.edu). */ 2221495Sjmacd 2321495Sjmacd#include "info.h" 2493139Sru#include "funs.h" 2521495Sjmacd 2656160Sru/* HELP_NODE_GETS_REGENERATED is always defined now that keys may get 2756160Sru rebound, or other changes in the help text may occur. */ 2856160Sru#define HELP_NODE_GETS_REGENERATED 1 2921495Sjmacd 3021495Sjmacd/* The name of the node used in the help window. */ 3121495Sjmacdstatic char *info_help_nodename = "*Info Help*"; 3221495Sjmacd 3321495Sjmacd/* A node containing printed key bindings and their documentation. */ 3421495Sjmacdstatic NODE *internal_info_help_node = (NODE *)NULL; 3521495Sjmacd 3621495Sjmacd/* A pointer to the contents of the help node. */ 3721495Sjmacdstatic char *internal_info_help_node_contents = (char *)NULL; 3821495Sjmacd 3993139Sru/* The (more or less) static text which appears in the internal info 40116525Sru help node. The actual key bindings are inserted. Keep the 4193139Sru underlines (****, etc.) in the same N_ call as the text lines they 4293139Sru refer to, so translations can make the number of *'s or -'s match. */ 4393139Sru#if defined(INFOKEY) 4493139Sru 4521495Sjmacdstatic char *info_internal_help_text[] = { 4693139Sru N_("Basic Commands in Info Windows\n\ 4793139Sru******************************\n"), 4856160Sru "\n", 4993139Sru N_("\\%-10[quit-help] Quit this help.\n"), 5093139Sru N_("\\%-10[quit] Quit Info altogether.\n"), 5193139Sru N_("\\%-10[get-info-help-node] Invoke the Info tutorial.\n"), 5293139Sru "\n", 5393139Sru N_("Selecting other nodes:\n\ 5493139Sru----------------------\n"), 5593139Sru N_("\\%-10[next-node] Move to the \"next\" node of this node.\n"), 5693139Sru N_("\\%-10[prev-node] Move to the \"previous\" node of this node.\n"), 5793139Sru N_("\\%-10[up-node] Move \"up\" from this node.\n"), 5893139Sru N_("\\%-10[menu-item] Pick menu item specified by name.\n\ 5993139Sru Picking a menu item causes another node to be selected.\n"), 6093139Sru N_("\\%-10[xref-item] Follow a cross reference. Reads name of reference.\n"), 6193139Sru N_("\\%-10[history-node] Move to the last node seen in this window.\n"), 6293139Sru N_("\\%-10[move-to-next-xref] Skip to next hypertext link within this node.\n"), 6393139Sru N_("\\%-10[move-to-prev-xref] Skip to previous hypertext link within this node.\n"), 6493139Sru N_("\\%-10[select-reference-this-line] Follow the hypertext link under cursor.\n"), 6593139Sru N_("\\%-10[dir-node] Move to the `directory' node. Equivalent to `\\[goto-node] (DIR)'.\n"), 6693139Sru N_("\\%-10[top-node] Move to the Top node. Equivalent to `\\[goto-node] Top'.\n"), 6793139Sru "\n", 6893139Sru N_("Moving within a node:\n\ 6993139Sru---------------------\n"), 70114472Sru N_("\\%-10[beginning-of-node] Go to the beginning of this node.\n"), 71114472Sru N_("\\%-10[end-of-node] Go to the end of this node.\n"), 72114472Sru N_("\\%-10[next-line] Scroll forward 1 line.\n"), 73114472Sru N_("\\%-10[prev-line] Scroll backward 1 line.\n"), 7493139Sru N_("\\%-10[scroll-forward] Scroll forward a page.\n"), 7593139Sru N_("\\%-10[scroll-backward] Scroll backward a page.\n"), 7693139Sru "\n", 7793139Sru N_("Other commands:\n\ 7893139Sru---------------\n"), 7993139Sru N_("\\%-10[menu-digit] Pick first ... ninth item in node's menu.\n"), 8093139Sru N_("\\%-10[last-menu-item] Pick last item in node's menu.\n"), 8193139Sru N_("\\%-10[index-search] Search for a specified string in the index entries of this Info\n\ 8293139Sru file, and select the node referenced by the first entry found.\n"), 8393139Sru N_("\\%-10[goto-node] Move to node specified by name.\n\ 8493139Sru You may include a filename as well, as in (FILENAME)NODENAME.\n"), 8593139Sru N_("\\%-10[search] Search forward for a specified string\n\ 8693139Sru and select the node in which the next occurrence is found.\n"), 8793139Sru N_("\\%-10[search-backward] Search backward for a specified string\n\ 8893139Sru and select the node in which the previous occurrence is found.\n"), 8993139Sru NULL 9093139Sru}; 9193139Sru 9293139Sru#else /* !INFOKEY */ 9393139Sru 9493139Srustatic char *info_internal_help_text[] = { 9593139Sru N_("Basic Commands in Info Windows\n\ 9693139Sru******************************\n"), 9793139Sru "\n", 9856160Sru N_(" %-10s Quit this help.\n"), 9956160Sru N_(" %-10s Quit Info altogether.\n"), 10056160Sru N_(" %-10s Invoke the Info tutorial.\n"), 10156160Sru "\n", 10293139Sru N_("Selecting other nodes:\n\ 10393139Sru----------------------\n", 10456160Sru N_(" %-10s Move to the `next' node of this node.\n"), 10556160Sru N_(" %-10s Move to the `previous' node of this node.\n"), 10656160Sru N_(" %-10s Move `up' from this node.\n"), 10756160Sru N_(" %-10s Pick menu item specified by name.\n"), 10856160Sru N_(" Picking a menu item causes another node to be selected.\n"), 10956160Sru N_(" %-10s Follow a cross reference. Reads name of reference.\n"), 11056160Sru N_(" %-10s Move to the last node seen in this window.\n"), 11156160Sru N_(" %-10s Skip to next hypertext link within this node.\n"), 11256160Sru N_(" %-10s Follow the hypertext link under cursor.\n"), 11356160Sru N_(" %-10s Move to the `directory' node. Equivalent to `g (DIR)'.\n"), 11456160Sru N_(" %-10s Move to the Top node. Equivalent to `g Top'.\n"), 11556160Sru "\n", 11693139Sru N_("Moving within a node:\n\ 11793139Sru---------------------\n"), 11893139Sru N_(" %-10s Scroll forward a page.\n"), 11993139Sru N_(" %-10s Scroll backward a page.\n"), 12093139Sru N_(" %-10s Go to the beginning of this node.\n"), 12193139Sru N_(" %-10s Go to the end of this node.\n"), 12293139Sru N_(" %-10s Scroll forward 1 line.\n"), 12393139Sru N_(" %-10s Scroll backward 1 line.\n"), 12493139Sru "\n", 12593139Sru N_("Other commands:\n\ 12693139Sru---------------\n"), 12756160Sru N_(" %-10s Pick first ... ninth item in node's menu.\n"), 12856160Sru N_(" %-10s Pick last item in node's menu.\n"), 12956160Sru N_(" %-10s Search for a specified string in the index entries of this Info\n"), 13056160Sru N_(" file, and select the node referenced by the first entry found.\n"), 13156160Sru N_(" %-10s Move to node specified by name.\n"), 13256160Sru N_(" You may include a filename as well, as in (FILENAME)NODENAME.\n"), 13393139Sru N_(" %-10s Search forward for a specified string,\n"), 13456160Sru N_(" and select the node in which the next occurrence is found.\n"), 13593139Sru N_(" %-10s Search backward for a specified string\n"), 13656160Sru N_(" and select the node in which the next occurrence is found.\n"), 13742660Smarkm NULL 13821495Sjmacd}; 13921495Sjmacd 14056160Srustatic char *info_help_keys_text[][2] = { 14156160Sru { "", "" }, 14256160Sru { "", "" }, 14356160Sru { "", "" }, 14456160Sru { "CTRL-x 0", "CTRL-x 0" }, 14556160Sru { "q", "q" }, 14656160Sru { "h", "ESC h" }, 14756160Sru { "", "" }, 14856160Sru { "", "" }, 14956160Sru { "", "" }, 15056160Sru { "SPC", "SPC" }, 15156160Sru { "DEL", "b" }, 15256160Sru { "b", "ESC b" }, 15356160Sru { "e", "ESC e" }, 15456160Sru { "ESC 1 SPC", "RET" }, 15556160Sru { "ESC 1 DEL", "y" }, 15656160Sru { "", "" }, 15756160Sru { "", "" }, 15856160Sru { "", "" }, 15956160Sru { "n", "CTRL-x n" }, 16056160Sru { "p", "CTRL-x p" }, 16156160Sru { "u", "CTRL-x u" }, 16256160Sru { "m", "ESC m" }, 16356160Sru { "", "" }, 16456160Sru { "f", "ESC f" }, 16556160Sru { "l", "l" }, 16656160Sru { "TAB", "TAB" }, 16756160Sru { "RET", "CTRL-x RET" }, 16856160Sru { "d", "ESC d" }, 16956160Sru { "t", "ESC t" }, 17056160Sru { "", "" }, 17156160Sru { "", "" }, 17256160Sru { "", "" }, 17356160Sru { "1-9", "ESC 1-9" }, 17456160Sru { "0", "ESC 0" }, 17556160Sru { "i", "CTRL-x i" }, 17656160Sru { "", "" }, 17756160Sru { "g", "CTRL-x g" }, 17856160Sru { "", "" }, 17956160Sru { "s", "/" }, 18056160Sru { "", "" }, 18156160Sru { "ESC - s", "?" }, 18256160Sru { "", "" }, 18356160Sru NULL 18456160Sru}; 18556160Sru 18693139Sru#endif /* !INFOKEY */ 18721495Sjmacd 188146515Srustatic char *where_is_internal (Keymap map, InfoCommand *cmd); 18993139Sru 19021495Sjmacdvoid 191146515Srudump_map_to_message_buffer (char *prefix, Keymap map) 19221495Sjmacd{ 19321495Sjmacd register int i; 19493139Sru unsigned prefix_len = strlen (prefix); 19593139Sru char *new_prefix = (char *)xmalloc (prefix_len + 2); 19621495Sjmacd 19793139Sru strncpy (new_prefix, prefix, prefix_len); 19893139Sru new_prefix[prefix_len + 1] = '\0'; 19993139Sru 20021495Sjmacd for (i = 0; i < 256; i++) 20121495Sjmacd { 20293139Sru new_prefix[prefix_len] = i; 20321495Sjmacd if (map[i].type == ISKMAP) 20442660Smarkm { 20542660Smarkm dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function); 20642660Smarkm } 20721495Sjmacd else if (map[i].function) 20842660Smarkm { 20942660Smarkm register int last; 21042660Smarkm char *doc, *name; 21121495Sjmacd 21242660Smarkm doc = function_documentation (map[i].function); 21342660Smarkm name = function_name (map[i].function); 21421495Sjmacd 21542660Smarkm if (!*doc) 21642660Smarkm continue; 21721495Sjmacd 21842660Smarkm /* Find out if there is a series of identical functions, as in 21942660Smarkm ea_insert (). */ 22042660Smarkm for (last = i + 1; last < 256; last++) 22142660Smarkm if ((map[last].type != ISFUNC) || 22242660Smarkm (map[last].function != map[i].function)) 22342660Smarkm break; 22421495Sjmacd 22542660Smarkm if (last - 1 != i) 22642660Smarkm { 227146515Sru printf_to_message_buffer ("%s .. ", pretty_keyseq (new_prefix), 228146515Sru NULL, NULL); 229114472Sru new_prefix[prefix_len] = last - 1; 230146515Sru printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix), 231146515Sru NULL, NULL); 23242660Smarkm i = last - 1; 23342660Smarkm } 23442660Smarkm else 235146515Sru printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix), 236146515Sru NULL, NULL); 23721495Sjmacd 23821495Sjmacd#if defined (NAMED_FUNCTIONS) 23942660Smarkm /* Print the name of the function, and some padding before the 24042660Smarkm documentation string is printed. */ 24142660Smarkm { 24242660Smarkm int length_so_far; 24342660Smarkm int desired_doc_start = 40; /* Must be multiple of 8. */ 24421495Sjmacd 245146515Sru printf_to_message_buffer ("(%s)", name, NULL, NULL); 24642660Smarkm length_so_far = message_buffer_length_this_line (); 24721495Sjmacd 248146515Sru if ((desired_doc_start + strlen (doc)) 249146515Sru >= (unsigned int) the_screen->width) 250146515Sru printf_to_message_buffer ("\n ", NULL, NULL, NULL); 25142660Smarkm else 25242660Smarkm { 25342660Smarkm while (length_so_far < desired_doc_start) 25442660Smarkm { 255146515Sru printf_to_message_buffer ("\t", NULL, NULL, NULL); 25642660Smarkm length_so_far += character_width ('\t', length_so_far); 25742660Smarkm } 25842660Smarkm } 25942660Smarkm } 26021495Sjmacd#endif /* NAMED_FUNCTIONS */ 261146515Sru printf_to_message_buffer ("%s\n", doc, NULL, NULL); 26242660Smarkm } 26321495Sjmacd } 26493139Sru free (new_prefix); 26521495Sjmacd} 26621495Sjmacd 26756160Sru/* How to create internal_info_help_node. HELP_IS_ONLY_WINDOW_P says 26856160Sru whether we're going to end up in a second (or more) window of our 26956160Sru own, or whether there's only one window and we're going to usurp it. 27056160Sru This determines how to quit the help window. Maybe we should just 27156160Sru make q do the right thing in both cases. */ 27256160Sru 27321495Sjmacdstatic void 274146515Srucreate_internal_info_help_node (int help_is_only_window_p) 27521495Sjmacd{ 27621495Sjmacd register int i; 27721495Sjmacd NODE *node; 27856160Sru char *contents = NULL; 27993139Sru char *exec_keys; 28021495Sjmacd 28156160Sru#ifndef HELP_NODE_GETS_REGENERATED 28221495Sjmacd if (internal_info_help_node_contents) 28321495Sjmacd contents = internal_info_help_node_contents; 28421495Sjmacd#endif /* !HELP_NODE_GETS_REGENERATED */ 28521495Sjmacd 28621495Sjmacd if (!contents) 28721495Sjmacd { 28821495Sjmacd int printed_one_mx = 0; 28921495Sjmacd 29021495Sjmacd initialize_message_buffer (); 29121495Sjmacd 29221495Sjmacd for (i = 0; info_internal_help_text[i]; i++) 29356160Sru { 29493139Sru#ifdef INFOKEY 295146515Sru printf_to_message_buffer (replace_in_documentation 296146515Sru ((char *) _(info_internal_help_text[i]), help_is_only_window_p), 297146515Sru NULL, NULL, NULL); 29893139Sru#else 29956160Sru /* Don't translate blank lines, gettext outputs the po file 30056160Sru header in that case. We want a blank line. */ 30156160Sru char *msg = *(info_internal_help_text[i]) 30256160Sru ? _(info_internal_help_text[i]) 30356160Sru : info_internal_help_text[i]; 30456160Sru char *key = info_help_keys_text[i][vi_keys_p]; 305116525Sru 30656160Sru /* If we have only one window (because the window size was too 30756160Sru small to split it), CTRL-x 0 doesn't work to `quit' help. */ 30856160Sru if (STREQ (key, "CTRL-x 0") && help_is_only_window_p) 30956160Sru key = "l"; 31021495Sjmacd 311146515Sru printf_to_message_buffer (msg, key, NULL, NULL); 31293139Sru#endif /* !INFOKEY */ 31356160Sru } 31456160Sru 315146515Sru printf_to_message_buffer ("---------------------\n\n", NULL, NULL, NULL); 316146515Sru printf_to_message_buffer ((char *) _("The current search path is:\n"), 317146515Sru NULL, NULL, NULL); 318146515Sru printf_to_message_buffer (" %s\n", infopath, NULL, NULL); 319146515Sru printf_to_message_buffer ("---------------------\n\n", NULL, NULL, NULL); 320146515Sru printf_to_message_buffer ((char *) _("Commands available in Info windows:\n\n"), 321146515Sru NULL, NULL, NULL); 32221495Sjmacd dump_map_to_message_buffer ("", info_keymap); 323146515Sru printf_to_message_buffer ("---------------------\n\n", NULL, NULL, NULL); 324146515Sru printf_to_message_buffer ((char *) _("Commands available in the echo area:\n\n"), 325146515Sru NULL, NULL, NULL); 32621495Sjmacd dump_map_to_message_buffer ("", echo_area_keymap); 32721495Sjmacd 32821495Sjmacd#if defined (NAMED_FUNCTIONS) 32993139Sru /* Get a list of commands which have no keystroke equivs. */ 33093139Sru exec_keys = where_is (info_keymap, InfoCmd(info_execute_command)); 33193139Sru if (exec_keys) 33293139Sru exec_keys = xstrdup (exec_keys); 33321495Sjmacd for (i = 0; function_doc_array[i].func; i++) 33442660Smarkm { 33593139Sru InfoCommand *cmd = DocInfoCmd(&function_doc_array[i]); 33621495Sjmacd 337146515Sru if (InfoFunction(cmd) != (VFunction *) info_do_lowercase_version 338114472Sru && !where_is_internal (info_keymap, cmd) 33993139Sru && !where_is_internal (echo_area_keymap, cmd)) 34042660Smarkm { 34142660Smarkm if (!printed_one_mx) 34242660Smarkm { 343146515Sru printf_to_message_buffer ("---------------------\n\n", 344146515Sru NULL, NULL, NULL); 345114472Sru if (exec_keys && exec_keys[0]) 346114472Sru printf_to_message_buffer 347146515Sru ((char *) _("The following commands can only be invoked via %s:\n\n"), 348146515Sru exec_keys, NULL, NULL); 349114472Sru else 350114472Sru printf_to_message_buffer 351146515Sru ((char *) _("The following commands cannot be invoked at all:\n\n"), 352146515Sru NULL, NULL, NULL); 35342660Smarkm printed_one_mx = 1; 35442660Smarkm } 35521495Sjmacd 35642660Smarkm printf_to_message_buffer 35793139Sru ("%s %s\n %s\n", 358114472Sru exec_keys, 35942660Smarkm function_doc_array[i].func_name, 36056160Sru replace_in_documentation (strlen (function_doc_array[i].doc) 361146515Sru ? (char *) _(function_doc_array[i].doc) : "", 0) 362114472Sru ); 36356160Sru 36442660Smarkm } 36542660Smarkm } 36621495Sjmacd 36721495Sjmacd if (printed_one_mx) 368146515Sru printf_to_message_buffer ("\n", NULL, NULL, NULL); 36993139Sru 37093139Sru maybe_free (exec_keys); 37121495Sjmacd#endif /* NAMED_FUNCTIONS */ 37221495Sjmacd 37321495Sjmacd printf_to_message_buffer 37442660Smarkm ("%s", replace_in_documentation 375146515Sru ((char *) _("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n"), 0), 376146515Sru NULL, NULL); 37721495Sjmacd node = message_buffer_to_node (); 37821495Sjmacd internal_info_help_node_contents = node->contents; 37921495Sjmacd } 38021495Sjmacd else 38121495Sjmacd { 38221495Sjmacd /* We already had the right contents, so simply use them. */ 38321495Sjmacd node = build_message_node ("", 0, 0); 38421495Sjmacd free (node->contents); 38521495Sjmacd node->contents = contents; 38621495Sjmacd node->nodelen = 1 + strlen (contents); 38721495Sjmacd } 38821495Sjmacd 38921495Sjmacd internal_info_help_node = node; 39021495Sjmacd 39121495Sjmacd /* Do not GC this node's contents. It never changes, and we never need 39221495Sjmacd to delete it once it is made. If you change some things (such as 39321495Sjmacd placing information about dynamic variables in the help text) then 39421495Sjmacd you will need to allow the contents to be gc'd, and you will have to 39521495Sjmacd arrange to always regenerate the help node. */ 39621495Sjmacd#if defined (HELP_NODE_GETS_REGENERATED) 39721495Sjmacd add_gcable_pointer (internal_info_help_node->contents); 39821495Sjmacd#endif 39921495Sjmacd 40021495Sjmacd name_internal_node (internal_info_help_node, info_help_nodename); 40121495Sjmacd 40221495Sjmacd /* Even though this is an internal node, we don't want the window 40321495Sjmacd system to treat it specially. So we turn off the internalness 40421495Sjmacd of it here. */ 40521495Sjmacd internal_info_help_node->flags &= ~N_IsInternal; 40621495Sjmacd} 40721495Sjmacd 40821495Sjmacd/* Return a window which is the window showing help in this Info. */ 40956160Sru 41056160Sru/* If the eligible window's height is >= this, split it to make the help 41156160Sru window. Otherwise display the help window in the current window. */ 41256160Sru#define HELP_SPLIT_SIZE 24 41356160Sru 41421495Sjmacdstatic WINDOW * 415146515Sruinfo_find_or_create_help_window (void) 41621495Sjmacd{ 41756160Sru int help_is_only_window_p; 41856160Sru WINDOW *eligible = NULL; 41956160Sru WINDOW *help_window = get_window_of_node (internal_info_help_node); 42021495Sjmacd 42121495Sjmacd /* If we couldn't find the help window, then make it. */ 42221495Sjmacd if (!help_window) 42321495Sjmacd { 42456160Sru WINDOW *window; 42521495Sjmacd int max = 0; 42621495Sjmacd 42721495Sjmacd for (window = windows; window; window = window->next) 42842660Smarkm { 42942660Smarkm if (window->height > max) 43042660Smarkm { 43142660Smarkm max = window->height; 43242660Smarkm eligible = window; 43342660Smarkm } 43442660Smarkm } 43521495Sjmacd 43621495Sjmacd if (!eligible) 43756160Sru return NULL; 43821495Sjmacd } 43956160Sru#ifndef HELP_NODE_GETS_REGENERATED 44021495Sjmacd else 44156160Sru /* help window is static, just return it. */ 44256160Sru return help_window; 44356160Sru#endif /* not HELP_NODE_GETS_REGENERATED */ 44421495Sjmacd 44556160Sru /* Make sure that we have a node containing the help text. The 44656160Sru argument is false if help will be the only window (so l must be used 44756160Sru to quit help), true if help will be one of several visible windows 44856160Sru (so CTRL-x 0 must be used to quit help). */ 449146515Sru help_is_only_window_p = ((help_window && !windows->next) 450146515Sru || (!help_window && eligible->height < HELP_SPLIT_SIZE)); 45156160Sru create_internal_info_help_node (help_is_only_window_p); 45221495Sjmacd 45321495Sjmacd /* Either use the existing window to display the help node, or create 45421495Sjmacd a new window if there was no existing help window. */ 45521495Sjmacd if (!help_window) 45656160Sru { /* Split the largest window into 2 windows, and show the help text 45742660Smarkm in that window. */ 45856160Sru if (eligible->height >= HELP_SPLIT_SIZE) 45942660Smarkm { 46042660Smarkm active_window = eligible; 46142660Smarkm help_window = window_make_window (internal_info_help_node); 46242660Smarkm } 46321495Sjmacd else 46442660Smarkm { 46542660Smarkm set_remembered_pagetop_and_point (active_window); 46642660Smarkm window_set_node_of_window (active_window, internal_info_help_node); 46742660Smarkm help_window = active_window; 46842660Smarkm } 46921495Sjmacd } 47021495Sjmacd else 47156160Sru { /* Case where help node always gets regenerated, and we have an 47242660Smarkm existing window in which to place the node. */ 47321495Sjmacd if (active_window != help_window) 47442660Smarkm { 47542660Smarkm set_remembered_pagetop_and_point (active_window); 47642660Smarkm active_window = help_window; 47742660Smarkm } 47821495Sjmacd window_set_node_of_window (active_window, internal_info_help_node); 47921495Sjmacd } 48021495Sjmacd remember_window_and_node (help_window, help_window->node); 48156160Sru return help_window; 48221495Sjmacd} 48321495Sjmacd 48421495Sjmacd/* Create or move to the help window. */ 48542660SmarkmDECLARE_INFO_COMMAND (info_get_help_window, _("Display help message")) 48621495Sjmacd{ 48721495Sjmacd WINDOW *help_window; 48821495Sjmacd 48921495Sjmacd help_window = info_find_or_create_help_window (); 49021495Sjmacd if (help_window) 49121495Sjmacd { 49221495Sjmacd active_window = help_window; 49321495Sjmacd active_window->flags |= W_UpdateWindow; 49421495Sjmacd } 49521495Sjmacd else 49621495Sjmacd { 497146515Sru info_error ((char *) msg_cant_make_help, NULL, NULL); 49821495Sjmacd } 49921495Sjmacd} 50021495Sjmacd 50121495Sjmacd/* Show the Info help node. This means that the "info" file is installed 50221495Sjmacd where it can easily be found on your system. */ 50342660SmarkmDECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'")) 50421495Sjmacd{ 50521495Sjmacd NODE *node; 50621495Sjmacd char *nodename; 50721495Sjmacd 50821495Sjmacd /* If there is a window on the screen showing the node "(info)Help" or 50921495Sjmacd the node "(info)Help-Small-Screen", simply select that window. */ 51021495Sjmacd { 51121495Sjmacd WINDOW *win; 51221495Sjmacd 51321495Sjmacd for (win = windows; win; win = win->next) 51421495Sjmacd { 51542660Smarkm if (win->node && win->node->filename && 51642660Smarkm (strcasecmp 51742660Smarkm (filename_non_directory (win->node->filename), "info") == 0) && 51842660Smarkm ((strcmp (win->node->nodename, "Help") == 0) || 51942660Smarkm (strcmp (win->node->nodename, "Help-Small-Screen") == 0))) 52042660Smarkm { 52142660Smarkm active_window = win; 52242660Smarkm return; 52342660Smarkm } 52421495Sjmacd } 52521495Sjmacd } 52621495Sjmacd 52721495Sjmacd /* If the current window is small, show the small screen help. */ 52821495Sjmacd if (active_window->height < 24) 52921495Sjmacd nodename = "Help-Small-Screen"; 53021495Sjmacd else 53121495Sjmacd nodename = "Help"; 53221495Sjmacd 53321495Sjmacd /* Try to get the info file for Info. */ 53421495Sjmacd node = info_get_node ("Info", nodename); 53521495Sjmacd 53621495Sjmacd if (!node) 53721495Sjmacd { 53821495Sjmacd if (info_recent_file_error) 539146515Sru info_error (info_recent_file_error, NULL, NULL); 54021495Sjmacd else 541146515Sru info_error ((char *) msg_cant_file_node, "Info", nodename); 54221495Sjmacd } 54321495Sjmacd else 54421495Sjmacd { 54521495Sjmacd /* If the current window is very large (greater than 45 lines), 54642660Smarkm then split it and show the help node in another window. 54742660Smarkm Otherwise, use the current window. */ 54821495Sjmacd 54921495Sjmacd if (active_window->height > 45) 55042660Smarkm active_window = window_make_window (node); 55121495Sjmacd else 55242660Smarkm { 55342660Smarkm set_remembered_pagetop_and_point (active_window); 55442660Smarkm window_set_node_of_window (active_window, node); 55542660Smarkm } 55621495Sjmacd 55721495Sjmacd remember_window_and_node (active_window, node); 55821495Sjmacd } 55921495Sjmacd} 56021495Sjmacd 56121495Sjmacd/* **************************************************************** */ 56242660Smarkm/* */ 56342660Smarkm/* Groveling Info Keymaps and Docs */ 56442660Smarkm/* */ 56521495Sjmacd/* **************************************************************** */ 56621495Sjmacd 56721495Sjmacd/* Return the documentation associated with the Info command FUNCTION. */ 56821495Sjmacdchar * 569146515Srufunction_documentation (InfoCommand *cmd) 57021495Sjmacd{ 57193139Sru char *doc; 57293139Sru 57393139Sru#if defined (INFOKEY) 57493139Sru 57593139Sru doc = cmd->doc; 57693139Sru 57793139Sru#else /* !INFOKEY */ 57893139Sru 57921495Sjmacd register int i; 58021495Sjmacd 58121495Sjmacd for (i = 0; function_doc_array[i].func; i++) 58293139Sru if (InfoFunction(cmd) == function_doc_array[i].func) 58321495Sjmacd break; 58421495Sjmacd 58593139Sru doc = function_doc_array[i].func ? function_doc_array[i].doc : ""; 58693139Sru 58793139Sru#endif /* !INFOKEY */ 58893139Sru 589146515Sru return replace_in_documentation ((strlen (doc) == 0) ? doc : (char *) _(doc), 0); 59021495Sjmacd} 59121495Sjmacd 59221495Sjmacd#if defined (NAMED_FUNCTIONS) 59321495Sjmacd/* Return the user-visible name of the function associated with the 59421495Sjmacd Info command FUNCTION. */ 59521495Sjmacdchar * 596146515Srufunction_name (InfoCommand *cmd) 59793139Sru{ 59893139Sru#if defined (INFOKEY) 59921495Sjmacd 60093139Sru return cmd->func_name; 60193139Sru 60293139Sru#else /* !INFOKEY */ 60393139Sru 60421495Sjmacd register int i; 60521495Sjmacd 60621495Sjmacd for (i = 0; function_doc_array[i].func; i++) 60793139Sru if (InfoFunction(cmd) == function_doc_array[i].func) 60821495Sjmacd break; 60921495Sjmacd 61021495Sjmacd return (function_doc_array[i].func_name); 61193139Sru 61293139Sru#endif /* !INFOKEY */ 61321495Sjmacd} 61421495Sjmacd 61593139Sru/* Return a pointer to the info command for function NAME. */ 61693139SruInfoCommand * 617146515Srunamed_function (char *name) 61821495Sjmacd{ 61921495Sjmacd register int i; 62021495Sjmacd 62121495Sjmacd for (i = 0; function_doc_array[i].func; i++) 62221495Sjmacd if (strcmp (function_doc_array[i].func_name, name) == 0) 62321495Sjmacd break; 62421495Sjmacd 62593139Sru return (DocInfoCmd(&function_doc_array[i])); 62621495Sjmacd} 62721495Sjmacd#endif /* NAMED_FUNCTIONS */ 62821495Sjmacd 62921495Sjmacd/* Return the documentation associated with KEY in MAP. */ 63021495Sjmacdchar * 631146515Srukey_documentation (char key, Keymap map) 63221495Sjmacd{ 63393139Sru InfoCommand *function = map[key].function; 63421495Sjmacd 63521495Sjmacd if (function) 63621495Sjmacd return (function_documentation (function)); 63721495Sjmacd else 63821495Sjmacd return ((char *)NULL); 63921495Sjmacd} 64021495Sjmacd 64142660SmarkmDECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY")) 64221495Sjmacd{ 64393139Sru char keys[50]; 64421495Sjmacd unsigned char keystroke; 64593139Sru char *k = keys; 64621495Sjmacd Keymap map; 64721495Sjmacd 64893139Sru *k = '\0'; 64921495Sjmacd map = window->keymap; 65021495Sjmacd 65156160Sru for (;;) 65221495Sjmacd { 653146515Sru message_in_echo_area ((char *) _("Describe key: %s"), 654146515Sru pretty_keyseq (keys), NULL); 65521495Sjmacd keystroke = info_get_input_char (); 65621495Sjmacd unmessage_in_echo_area (); 65721495Sjmacd 65893139Sru#if !defined (INFOKEY) 65956160Sru if (Meta_p (keystroke)) 66042660Smarkm { 66142660Smarkm if (map[ESC].type != ISKMAP) 66242660Smarkm { 66342660Smarkm window_message_in_echo_area 66456160Sru (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke))); 66542660Smarkm return; 66642660Smarkm } 66721495Sjmacd 668114472Sru *k++ = '\e'; 66942660Smarkm keystroke = UnMeta (keystroke); 67042660Smarkm map = (Keymap)map[ESC].function; 67142660Smarkm } 67293139Sru#endif /* !INFOKEY */ 67321495Sjmacd 67493139Sru /* Add the KEYSTROKE to our list. */ 67593139Sru *k++ = keystroke; 67693139Sru *k = '\0'; 67721495Sjmacd 67893139Sru if (map[keystroke].function == (InfoCommand *)NULL) 67942660Smarkm { 680146515Sru message_in_echo_area ((char *) _("%s is undefined."), 681146515Sru pretty_keyseq (keys), NULL); 68242660Smarkm return; 68342660Smarkm } 68421495Sjmacd else if (map[keystroke].type == ISKMAP) 68542660Smarkm { 68642660Smarkm map = (Keymap)map[keystroke].function; 68742660Smarkm continue; 68842660Smarkm } 68921495Sjmacd else 69042660Smarkm { 69193139Sru char *keyname, *message, *fundoc, *funname = ""; 69221495Sjmacd 69393139Sru#if defined (INFOKEY) 694114472Sru /* If the key is bound to do-lowercase-version, but its 695114472Sru lower-case variant is undefined, say that this key is 696114472Sru also undefined. This is especially important for unbound 697114472Sru edit keys that emit an escape sequence: it's terribly 698114472Sru confusing to see a message "Home (do-lowercase-version)" 699114472Sru or some such when Home is unbound. */ 700146515Sru if (InfoFunction(map[keystroke].function) 701146515Sru == (VFunction *) info_do_lowercase_version) 702114472Sru { 703114472Sru unsigned char lowerkey = Meta_p(keystroke) 704114472Sru ? Meta (tolower (UnMeta (keystroke))) 705114472Sru : tolower (keystroke); 70693139Sru 707114472Sru if (map[lowerkey].function == (InfoCommand *)NULL) 708114472Sru { 709146515Sru message_in_echo_area ((char *) _("%s is undefined."), 710146515Sru pretty_keyseq (keys), NULL); 711114472Sru return; 712114472Sru } 713114472Sru } 71493139Sru#endif 71593139Sru 716114472Sru keyname = pretty_keyseq (keys); 71793139Sru 71821495Sjmacd#if defined (NAMED_FUNCTIONS) 71942660Smarkm funname = function_name (map[keystroke].function); 72021495Sjmacd#endif /* NAMED_FUNCTIONS */ 72121495Sjmacd 72242660Smarkm fundoc = function_documentation (map[keystroke].function); 72321495Sjmacd 72442660Smarkm message = (char *)xmalloc 72542660Smarkm (10 + strlen (keyname) + strlen (fundoc) + strlen (funname)); 72621495Sjmacd 72721495Sjmacd#if defined (NAMED_FUNCTIONS) 72842660Smarkm sprintf (message, "%s (%s): %s.", keyname, funname, fundoc); 72921495Sjmacd#else 73042660Smarkm sprintf (message, _("%s is defined to %s."), keyname, fundoc); 73121495Sjmacd#endif /* !NAMED_FUNCTIONS */ 73221495Sjmacd 733146515Sru window_message_in_echo_area ("%s", message, NULL); 73442660Smarkm free (message); 73542660Smarkm break; 73642660Smarkm } 73721495Sjmacd } 73821495Sjmacd} 73921495Sjmacd 74093139Sru/* Return the pretty printable name of a single character. */ 74121495Sjmacdchar * 742146515Srupretty_keyname (unsigned char key) 74321495Sjmacd{ 74493139Sru static char rep_buffer[30]; 74521495Sjmacd char *rep; 74621495Sjmacd 74721495Sjmacd if (Meta_p (key)) 74821495Sjmacd { 74921495Sjmacd char temp[20]; 75021495Sjmacd 75121495Sjmacd rep = pretty_keyname (UnMeta (key)); 75221495Sjmacd 75393139Sru#if defined (INFOKEY) 75493139Sru sprintf (temp, "M-%s", rep); 75593139Sru#else /* !INFOKEY */ 75621495Sjmacd sprintf (temp, "ESC %s", rep); 75793139Sru#endif /* !INFOKEY */ 75821495Sjmacd strcpy (rep_buffer, temp); 75921495Sjmacd rep = rep_buffer; 76021495Sjmacd } 76121495Sjmacd else if (Control_p (key)) 76221495Sjmacd { 76321495Sjmacd switch (key) 76442660Smarkm { 76542660Smarkm case '\n': rep = "LFD"; break; 76642660Smarkm case '\t': rep = "TAB"; break; 76742660Smarkm case '\r': rep = "RET"; break; 76842660Smarkm case ESC: rep = "ESC"; break; 76921495Sjmacd 77042660Smarkm default: 77142660Smarkm sprintf (rep_buffer, "C-%c", UnControl (key)); 77242660Smarkm rep = rep_buffer; 77342660Smarkm } 77421495Sjmacd } 77521495Sjmacd else 77621495Sjmacd { 77721495Sjmacd switch (key) 77842660Smarkm { 77942660Smarkm case ' ': rep = "SPC"; break; 78042660Smarkm case DEL: rep = "DEL"; break; 78142660Smarkm default: 78242660Smarkm rep_buffer[0] = key; 78342660Smarkm rep_buffer[1] = '\0'; 78442660Smarkm rep = rep_buffer; 78542660Smarkm } 78621495Sjmacd } 78721495Sjmacd return (rep); 78821495Sjmacd} 78921495Sjmacd 79093139Sru/* Return the pretty printable string which represents KEYSEQ. */ 79193139Sru 792146515Srustatic void pretty_keyseq_internal (char *keyseq, char *rep); 79393139Sru 79493139Sruchar * 795146515Srupretty_keyseq (char *keyseq) 79693139Sru{ 79793139Sru static char keyseq_rep[200]; 79893139Sru 79993139Sru keyseq_rep[0] = '\0'; 80093139Sru if (*keyseq) 80193139Sru pretty_keyseq_internal (keyseq, keyseq_rep); 80293139Sru return (keyseq_rep); 80393139Sru} 80493139Sru 80593139Srustatic void 806146515Srupretty_keyseq_internal (char *keyseq, char *rep) 80793139Sru{ 80893139Sru if (term_kP && strncmp(keyseq, term_kP, strlen(term_kP)) == 0) 80993139Sru { 81093139Sru strcpy(rep, "PgUp"); 81193139Sru keyseq += strlen(term_kP); 81293139Sru } 81393139Sru else if (term_kN && strncmp(keyseq, term_kN, strlen(term_kN)) == 0) 81493139Sru { 81593139Sru strcpy(rep, "PgDn"); 81693139Sru keyseq += strlen(term_kN); 81793139Sru } 81893139Sru#if defined(INFOKEY) 81993139Sru else if (term_kh && strncmp(keyseq, term_kh, strlen(term_kh)) == 0) 82093139Sru { 82193139Sru strcpy(rep, "Home"); 82293139Sru keyseq += strlen(term_kh); 82393139Sru } 82493139Sru else if (term_ke && strncmp(keyseq, term_ke, strlen(term_ke)) == 0) 82593139Sru { 82693139Sru strcpy(rep, "End"); 82793139Sru keyseq += strlen(term_ke); 82893139Sru } 82993139Sru else if (term_ki && strncmp(keyseq, term_ki, strlen(term_ki)) == 0) 83093139Sru { 83193139Sru strcpy(rep, "INS"); 83293139Sru keyseq += strlen(term_ki); 83393139Sru } 83493139Sru else if (term_kx && strncmp(keyseq, term_kx, strlen(term_kx)) == 0) 83593139Sru { 83693139Sru strcpy(rep, "DEL"); 83793139Sru keyseq += strlen(term_kx); 83893139Sru } 83993139Sru#endif /* INFOKEY */ 84093139Sru else if (term_ku && strncmp(keyseq, term_ku, strlen(term_ku)) == 0) 84193139Sru { 84293139Sru strcpy(rep, "Up"); 84393139Sru keyseq += strlen(term_ku); 84493139Sru } 84593139Sru else if (term_kd && strncmp(keyseq, term_kd, strlen(term_kd)) == 0) 84693139Sru { 84793139Sru strcpy(rep, "Down"); 84893139Sru keyseq += strlen(term_kd); 84993139Sru } 85093139Sru else if (term_kl && strncmp(keyseq, term_kl, strlen(term_kl)) == 0) 85193139Sru { 85293139Sru strcpy(rep, "Left"); 85393139Sru keyseq += strlen(term_kl); 85493139Sru } 85593139Sru else if (term_kr && strncmp(keyseq, term_kr, strlen(term_kr)) == 0) 85693139Sru { 85793139Sru strcpy(rep, "Right"); 85893139Sru keyseq += strlen(term_kr); 85993139Sru } 86093139Sru else 86193139Sru { 86293139Sru strcpy (rep, pretty_keyname (keyseq[0])); 86393139Sru keyseq++; 86493139Sru } 86593139Sru if (*keyseq) 86693139Sru { 86793139Sru strcat (rep, " "); 86893139Sru pretty_keyseq_internal (keyseq, rep + strlen(rep)); 86993139Sru } 87093139Sru} 87193139Sru 87293139Sru/* Return a pointer to the last character in s that is found in f. */ 87393139Srustatic char * 874146515Srustrrpbrk (const char *s, const char *f) 87593139Sru{ 87693139Sru register const char *e = s + strlen(s); 87793139Sru register const char *t; 87893139Sru 87993139Sru while (e-- != s) 88093139Sru { 88193139Sru for (t = f; *t; t++) 88293139Sru if (*e == *t) 883114472Sru return (char *)e; 88493139Sru } 88593139Sru return NULL; 88693139Sru} 88793139Sru 88821495Sjmacd/* Replace the names of functions with the key that invokes them. */ 88921495Sjmacdchar * 890146515Srureplace_in_documentation (char *string, int help_is_only_window_p) 89121495Sjmacd{ 89293139Sru unsigned reslen = strlen (string); 89321495Sjmacd register int i, start, next; 89421495Sjmacd static char *result = (char *)NULL; 89521495Sjmacd 89621495Sjmacd maybe_free (result); 89793139Sru result = (char *)xmalloc (1 + reslen); 89821495Sjmacd 89921495Sjmacd i = next = start = 0; 90021495Sjmacd 90121495Sjmacd /* Skip to the beginning of a replaceable function. */ 90221495Sjmacd for (i = start; string[i]; i++) 90321495Sjmacd { 90493139Sru int j = i + 1; 90593139Sru 90621495Sjmacd /* Is this the start of a replaceable function name? */ 90793139Sru if (string[i] == '\\') 908114472Sru { 909114472Sru char *fmt = NULL; 910114472Sru unsigned min = 0; 911114472Sru unsigned max = 0; 91221495Sjmacd 913114472Sru if(string[j] == '%') 914114472Sru { 915114472Sru if (string[++j] == '-') 916114472Sru j++; 917114472Sru if (isdigit(string[j])) 918114472Sru { 919114472Sru min = atoi(string + j); 920114472Sru while (isdigit(string[j])) 921114472Sru j++; 922114472Sru if (string[j] == '.' && isdigit(string[j + 1])) 923114472Sru { 924114472Sru j += 1; 925114472Sru max = atoi(string + j); 926114472Sru while (isdigit(string[j])) 927114472Sru j++; 928114472Sru } 929114472Sru fmt = (char *)xmalloc (j - i + 2); 930114472Sru strncpy (fmt, string + i + 1, j - i); 931114472Sru fmt[j - i - 1] = 's'; 932114472Sru fmt[j - i] = '\0'; 933114472Sru } 934114472Sru else 935114472Sru j = i + 1; 936114472Sru } 937114472Sru if (string[j] == '[') 938114472Sru { 939114472Sru unsigned arg = 0; 940114472Sru char *argstr = NULL; 941114472Sru char *rep_name, *fun_name, *rep; 942114472Sru InfoCommand *command; 943114472Sru char *repstr = NULL; 944114472Sru unsigned replen; 94521495Sjmacd 946114472Sru /* Copy in the old text. */ 947114472Sru strncpy (result + next, string + start, i - start); 948114472Sru next += (i - start); 949114472Sru start = j + 1; 95021495Sjmacd 951114472Sru /* Look for an optional numeric arg. */ 952114472Sru i = start; 953114472Sru if (isdigit(string[i]) 954114472Sru || (string[i] == '-' && isdigit(string[i + 1])) ) 955114472Sru { 956114472Sru arg = atoi(string + i); 957114472Sru if (string[i] == '-') 958114472Sru i++; 959114472Sru while (isdigit(string[i])) 960114472Sru i++; 961114472Sru } 962114472Sru start = i; 96321495Sjmacd 964114472Sru /* Move to the end of the function name. */ 965114472Sru for (i = start; string[i] && (string[i] != ']'); i++); 96621495Sjmacd 967114472Sru rep_name = (char *)xmalloc (1 + i - start); 968114472Sru strncpy (rep_name, string + start, i - start); 969114472Sru rep_name[i - start] = '\0'; 97021495Sjmacd 971114472Sru /* If we have only one window (because the window size was too 972114472Sru small to split it), we have to quit help by going back one 973114472Sru noew in the history list, not deleting the window. */ 974114472Sru if (strcmp (rep_name, "quit-help") == 0) 975114472Sru fun_name = help_is_only_window_p ? "history-node" 976114472Sru : "delete-window"; 977114472Sru else 978114472Sru fun_name = rep_name; 97921495Sjmacd 980114472Sru /* Find a key which invokes this function in the info_keymap. */ 981114472Sru command = named_function (fun_name); 98293139Sru 983114472Sru free (rep_name); 98493139Sru 985114472Sru /* If the internal documentation string fails, there is a 986114472Sru serious problem with the associated command's documentation. 987114472Sru We croak so that it can be fixed immediately. */ 988114472Sru if (!command) 989114472Sru abort (); 99093139Sru 991114472Sru if (arg) 992114472Sru { 993114472Sru char *argrep, *p; 99493139Sru 995114472Sru argrep = where_is (info_keymap, InfoCmd(info_add_digit_to_numeric_arg)); 996114472Sru p = argrep ? strrpbrk (argrep, "0123456789-") : NULL; 997114472Sru if (p) 998114472Sru { 999114472Sru argstr = (char *)xmalloc (p - argrep + 21); 1000114472Sru strncpy (argstr, argrep, p - argrep); 1001114472Sru sprintf (argstr + (p - argrep), "%d", arg); 1002114472Sru } 1003114472Sru else 1004114472Sru command = NULL; 1005114472Sru } 1006114472Sru rep = command ? where_is (info_keymap, command) : NULL; 1007114472Sru if (!rep) 1008114472Sru rep = "N/A"; 1009114472Sru replen = (argstr ? strlen (argstr) : 0) + strlen (rep) + 1; 1010114472Sru repstr = (char *)xmalloc (replen); 1011114472Sru repstr[0] = '\0'; 1012114472Sru if (argstr) 1013114472Sru { 1014114472Sru strcat(repstr, argstr); 1015114472Sru strcat(repstr, " "); 1016114472Sru free (argstr); 1017114472Sru } 1018114472Sru strcat(repstr, rep); 101993139Sru 1020114472Sru if (fmt) 1021114472Sru { 1022114472Sru if (replen > max) 1023114472Sru replen = max; 1024114472Sru if (replen < min) 1025114472Sru replen = min; 1026114472Sru } 1027114472Sru if (next + replen > reslen) 1028114472Sru { 1029114472Sru reslen = next + replen + 1; 1030114472Sru result = (char *)xrealloc (result, reslen + 1); 1031114472Sru } 103293139Sru 1033114472Sru if (fmt) 1034114472Sru sprintf (result + next, fmt, repstr); 1035114472Sru else 1036114472Sru strcpy (result + next, repstr); 103793139Sru 1038114472Sru next = strlen (result); 1039114472Sru free (repstr); 104093139Sru 1041114472Sru start = i; 1042114472Sru if (string[i]) 1043114472Sru start++; 1044114472Sru } 104593139Sru 1046114472Sru maybe_free (fmt); 1047114472Sru } 104821495Sjmacd } 104921495Sjmacd strcpy (result + next, string + start); 105021495Sjmacd return (result); 105121495Sjmacd} 105221495Sjmacd 105321495Sjmacd/* Return a string of characters which could be typed from the keymap 105421495Sjmacd MAP to invoke FUNCTION. */ 105521495Sjmacdstatic char *where_is_rep = (char *)NULL; 105621495Sjmacdstatic int where_is_rep_index = 0; 105721495Sjmacdstatic int where_is_rep_size = 0; 105821495Sjmacd 105993139Sruchar * 1060146515Sruwhere_is (Keymap map, InfoCommand *cmd) 106121495Sjmacd{ 106221495Sjmacd char *rep; 106321495Sjmacd 106421495Sjmacd if (!where_is_rep_size) 106521495Sjmacd where_is_rep = (char *)xmalloc (where_is_rep_size = 100); 106621495Sjmacd where_is_rep_index = 0; 106721495Sjmacd 106893139Sru rep = where_is_internal (map, cmd); 106921495Sjmacd 107093139Sru /* If it couldn't be found, return "M-x Foo" (or equivalent). */ 107121495Sjmacd if (!rep) 107221495Sjmacd { 107321495Sjmacd char *name; 107421495Sjmacd 107593139Sru name = function_name (cmd); 107693139Sru if (!name) 1077114472Sru return NULL; /* no such function */ 107821495Sjmacd 107993139Sru rep = where_is_internal (map, InfoCmd(info_execute_command)); 108093139Sru if (!rep) 108193139Sru return ""; /* function exists but can't be got to by user */ 108221495Sjmacd 108393139Sru sprintf (where_is_rep, "%s %s", rep, name); 108493139Sru 108521495Sjmacd rep = where_is_rep; 108621495Sjmacd } 108721495Sjmacd return (rep); 108821495Sjmacd} 108921495Sjmacd 109093139Sru/* Return the printed rep of the keystrokes that invoke FUNCTION, 109193139Sru as found in MAP, or NULL. */ 109221495Sjmacdstatic char * 1093146515Sruwhere_is_internal (Keymap map, InfoCommand *cmd) 109421495Sjmacd{ 109593139Sru#if defined(INFOKEY) 109693139Sru 109793139Sru register FUNCTION_KEYSEQ *k; 109893139Sru 109993139Sru for (k = cmd->keys; k; k = k->next) 110093139Sru if (k->map == map) 110193139Sru return pretty_keyseq (k->keyseq); 110293139Sru 110393139Sru return NULL; 110493139Sru 110593139Sru#else /* !INFOKEY */ 1106114472Sru /* There is a bug in that create_internal_info_help_node calls 1107114472Sru where_is_internal without setting where_is_rep_index to zero. This 1108114472Sru was found by Mandrake and reported by Thierry Vignaud 1109114472Sru <tvignaud@mandrakesoft.com> around April 24, 2002. 1110116525Sru 1111114472Sru I think the best fix is to make where_is_rep_index another 1112114472Sru parameter to this recursively-called function, instead of a static 1113114472Sru variable. But this [!INFOKEY] branch of the code is not enabled 1114114472Sru any more, so let's just skip the whole thing. --karl, 28sep02. */ 111521495Sjmacd register int i; 111656160Sru 111721495Sjmacd /* If the function is directly invokable in MAP, return the representation 111821495Sjmacd of that keystroke. */ 111921495Sjmacd for (i = 0; i < 256; i++) 112093139Sru if ((map[i].type == ISFUNC) && map[i].function == cmd) 112121495Sjmacd { 112242660Smarkm sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i)); 112342660Smarkm return (where_is_rep); 112421495Sjmacd } 112521495Sjmacd 112621495Sjmacd /* Okay, search subsequent maps for this function. */ 112721495Sjmacd for (i = 0; i < 256; i++) 112821495Sjmacd { 112921495Sjmacd if (map[i].type == ISKMAP) 113042660Smarkm { 113142660Smarkm int saved_index = where_is_rep_index; 113242660Smarkm char *rep; 113321495Sjmacd 113442660Smarkm sprintf (where_is_rep + where_is_rep_index, "%s ", 113542660Smarkm pretty_keyname (i)); 113621495Sjmacd 113742660Smarkm where_is_rep_index = strlen (where_is_rep); 113893139Sru rep = where_is_internal ((Keymap)map[i].function, cmd); 113921495Sjmacd 114042660Smarkm if (rep) 114142660Smarkm return (where_is_rep); 114221495Sjmacd 114342660Smarkm where_is_rep_index = saved_index; 114442660Smarkm } 114521495Sjmacd } 114621495Sjmacd 114756160Sru return NULL; 114893139Sru 114993139Sru#endif /* INFOKEY */ 115021495Sjmacd} 115121495Sjmacd 115221495SjmacdDECLARE_INFO_COMMAND (info_where_is, 115356160Sru _("Show what to type to execute a given command")) 115421495Sjmacd{ 115521495Sjmacd char *command_name; 115621495Sjmacd 1157146515Sru command_name = read_function_name ((char *) _("Where is command: "), window); 115821495Sjmacd 115921495Sjmacd if (!command_name) 116021495Sjmacd { 116121495Sjmacd info_abort_key (active_window, count, key); 116221495Sjmacd return; 116321495Sjmacd } 116421495Sjmacd 116521495Sjmacd if (*command_name) 116621495Sjmacd { 116793139Sru InfoCommand *command; 116821495Sjmacd 116993139Sru command = named_function (command_name); 117021495Sjmacd 117193139Sru if (command) 117242660Smarkm { 117342660Smarkm char *location; 117421495Sjmacd 117593139Sru location = where_is (active_window->keymap, command); 117621495Sjmacd 117793139Sru if (!location || !location[0]) 117842660Smarkm { 1179146515Sru info_error ((char *) _("`%s' is not on any keys"), 1180146515Sru command_name, NULL); 118142660Smarkm } 118242660Smarkm else 118342660Smarkm { 118493139Sru if (strstr (location, function_name (command))) 118542660Smarkm window_message_in_echo_area 1186146515Sru ((char *) _("%s can only be invoked via %s."), 1187146515Sru command_name, location); 118842660Smarkm else 118942660Smarkm window_message_in_echo_area 1190146515Sru ((char *) _("%s can be invoked via %s."), 1191146515Sru command_name, location); 119242660Smarkm } 119342660Smarkm } 119421495Sjmacd else 1195146515Sru info_error ((char *) _("There is no function named `%s'"), 1196146515Sru command_name, NULL); 119721495Sjmacd } 119821495Sjmacd 119921495Sjmacd free (command_name); 120021495Sjmacd} 1201