#include "info.h"
#include "funs.h"
#define HELP_NODE_GETS_REGENERATED 1
static char *info_help_nodename = "*Info Help*";
static NODE *internal_info_help_node = (NODE *)NULL;
static char *internal_info_help_node_contents = (char *)NULL;
#if defined(INFOKEY)
static char *info_internal_help_text[] = {
N_("Basic Commands in Info Windows\n\
******************************\n"),
"\n",
N_("\\%-10[quit-help] Quit this help.\n"),
N_("\\%-10[quit] Quit Info altogether.\n"),
N_("\\%-10[get-info-help-node] Invoke the Info tutorial.\n"),
"\n",
N_("Selecting other nodes:\n\
----------------------\n"),
N_("\\%-10[next-node] Move to the \"next\" node of this node.\n"),
N_("\\%-10[prev-node] Move to the \"previous\" node of this node.\n"),
N_("\\%-10[up-node] Move \"up\" from this node.\n"),
N_("\\%-10[menu-item] Pick menu item specified by name.\n\
Picking a menu item causes another node to be selected.\n"),
N_("\\%-10[xref-item] Follow a cross reference. Reads name of reference.\n"),
N_("\\%-10[history-node] Move to the last node seen in this window.\n"),
N_("\\%-10[move-to-next-xref] Skip to next hypertext link within this node.\n"),
N_("\\%-10[move-to-prev-xref] Skip to previous hypertext link within this node.\n"),
N_("\\%-10[select-reference-this-line] Follow the hypertext link under cursor.\n"),
N_("\\%-10[dir-node] Move to the `directory' node. Equivalent to `\\[goto-node] (DIR)'.\n"),
N_("\\%-10[top-node] Move to the Top node. Equivalent to `\\[goto-node] Top'.\n"),
"\n",
N_("Moving within a node:\n\
---------------------\n"),
N_("\\%-10[beginning-of-node] Go to the beginning of this node.\n"),
N_("\\%-10[end-of-node] Go to the end of this node.\n"),
N_("\\%-10[next-line] Scroll forward 1 line.\n"),
N_("\\%-10[prev-line] Scroll backward 1 line.\n"),
N_("\\%-10[scroll-forward] Scroll forward a page.\n"),
N_("\\%-10[scroll-backward] Scroll backward a page.\n"),
"\n",
N_("Other commands:\n\
---------------\n"),
N_("\\%-10[menu-digit] Pick first ... ninth item in node's menu.\n"),
N_("\\%-10[last-menu-item] Pick last item in node's menu.\n"),
N_("\\%-10[index-search] Search for a specified string in the index entries of this Info\n\
file, and select the node referenced by the first entry found.\n"),
N_("\\%-10[goto-node] Move to node specified by name.\n\
You may include a filename as well, as in (FILENAME)NODENAME.\n"),
N_("\\%-10[search] Search forward for a specified string\n\
and select the node in which the next occurrence is found.\n"),
N_("\\%-10[search-backward] Search backward for a specified string\n\
and select the node in which the previous occurrence is found.\n"),
NULL
};
#else
static char *info_internal_help_text[] = {
N_("Basic Commands in Info Windows\n\
******************************\n"),
"\n",
N_(" %-10s Quit this help.\n"),
N_(" %-10s Quit Info altogether.\n"),
N_(" %-10s Invoke the Info tutorial.\n"),
"\n",
N_("Selecting other nodes:\n\
----------------------\n",
N_(" %-10s Move to the `next' node of this node.\n"),
N_(" %-10s Move to the `previous' node of this node.\n"),
N_(" %-10s Move `up' from this node.\n"),
N_(" %-10s Pick menu item specified by name.\n"),
N_(" Picking a menu item causes another node to be selected.\n"),
N_(" %-10s Follow a cross reference. Reads name of reference.\n"),
N_(" %-10s Move to the last node seen in this window.\n"),
N_(" %-10s Skip to next hypertext link within this node.\n"),
N_(" %-10s Follow the hypertext link under cursor.\n"),
N_(" %-10s Move to the `directory' node. Equivalent to `g (DIR)'.\n"),
N_(" %-10s Move to the Top node. Equivalent to `g Top'.\n"),
"\n",
N_("Moving within a node:\n\
---------------------\n"),
N_(" %-10s Scroll forward a page.\n"),
N_(" %-10s Scroll backward a page.\n"),
N_(" %-10s Go to the beginning of this node.\n"),
N_(" %-10s Go to the end of this node.\n"),
N_(" %-10s Scroll forward 1 line.\n"),
N_(" %-10s Scroll backward 1 line.\n"),
"\n",
N_("Other commands:\n\
---------------\n"),
N_(" %-10s Pick first ... ninth item in node's menu.\n"),
N_(" %-10s Pick last item in node's menu.\n"),
N_(" %-10s Search for a specified string in the index entries of this Info\n"),
N_(" file, and select the node referenced by the first entry found.\n"),
N_(" %-10s Move to node specified by name.\n"),
N_(" You may include a filename as well, as in (FILENAME)NODENAME.\n"),
N_(" %-10s Search forward for a specified string,\n"),
N_(" and select the node in which the next occurrence is found.\n"),
N_(" %-10s Search backward for a specified string\n"),
N_(" and select the node in which the next occurrence is found.\n"),
NULL
};
static char *info_help_keys_text[][2] = {
{ "", "" },
{ "", "" },
{ "", "" },
{ "CTRL-x 0", "CTRL-x 0" },
{ "q", "q" },
{ "h", "ESC h" },
{ "", "" },
{ "", "" },
{ "", "" },
{ "SPC", "SPC" },
{ "DEL", "b" },
{ "b", "ESC b" },
{ "e", "ESC e" },
{ "ESC 1 SPC", "RET" },
{ "ESC 1 DEL", "y" },
{ "", "" },
{ "", "" },
{ "", "" },
{ "n", "CTRL-x n" },
{ "p", "CTRL-x p" },
{ "u", "CTRL-x u" },
{ "m", "ESC m" },
{ "", "" },
{ "f", "ESC f" },
{ "l", "l" },
{ "TAB", "TAB" },
{ "RET", "CTRL-x RET" },
{ "d", "ESC d" },
{ "t", "ESC t" },
{ "", "" },
{ "", "" },
{ "", "" },
{ "1-9", "ESC 1-9" },
{ "0", "ESC 0" },
{ "i", "CTRL-x i" },
{ "", "" },
{ "g", "CTRL-x g" },
{ "", "" },
{ "s", "/" },
{ "", "" },
{ "ESC - s", "?" },
{ "", "" },
NULL
};
#endif
static char *where_is_internal ();
void
dump_map_to_message_buffer (prefix, map)
char *prefix;
Keymap map;
{
register int i;
unsigned prefix_len = strlen (prefix);
char *new_prefix = (char *)xmalloc (prefix_len + 2);
strncpy (new_prefix, prefix, prefix_len);
new_prefix[prefix_len + 1] = '\0';
for (i = 0; i < 256; i++)
{
new_prefix[prefix_len] = i;
if (map[i].type == ISKMAP)
{
dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
}
else if (map[i].function)
{
register int last;
char *doc, *name;
doc = function_documentation (map[i].function);
name = function_name (map[i].function);
if (!*doc)
continue;
for (last = i + 1; last < 256; last++)
if ((map[last].type != ISFUNC) ||
(map[last].function != map[i].function))
break;
if (last - 1 != i)
{
printf_to_message_buffer ("%s .. ", pretty_keyseq (new_prefix));
new_prefix[prefix_len] = last - 1;
printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix));
i = last - 1;
}
else
printf_to_message_buffer ("%s\t", pretty_keyseq (new_prefix));
#if defined (NAMED_FUNCTIONS)
{
int length_so_far;
int desired_doc_start = 40;
printf_to_message_buffer ("(%s)", name);
length_so_far = message_buffer_length_this_line ();
if ((desired_doc_start + strlen (doc)) >= the_screen->width)
printf_to_message_buffer ("\n ");
else
{
while (length_so_far < desired_doc_start)
{
printf_to_message_buffer ("\t");
length_so_far += character_width ('\t', length_so_far);
}
}
}
#endif
printf_to_message_buffer ("%s\n", doc);
}
}
free (new_prefix);
}
static void
create_internal_info_help_node (help_is_only_window_p)
int help_is_only_window_p;
{
register int i;
NODE *node;
char *contents = NULL;
char *exec_keys;
#ifndef HELP_NODE_GETS_REGENERATED
if (internal_info_help_node_contents)
contents = internal_info_help_node_contents;
#endif
if (!contents)
{
int printed_one_mx = 0;
initialize_message_buffer ();
for (i = 0; info_internal_help_text[i]; i++)
{
#ifdef INFOKEY
printf_to_message_buffer (replace_in_documentation (
_(info_internal_help_text[i]), help_is_only_window_p));
#else
char *msg = *(info_internal_help_text[i])
? _(info_internal_help_text[i])
: info_internal_help_text[i];
char *key = info_help_keys_text[i][vi_keys_p];
if (STREQ (key, "CTRL-x 0") && help_is_only_window_p)
key = "l";
printf_to_message_buffer (msg, key);
#endif
}
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer (_("The current search path is:\n"));
printf_to_message_buffer (" %s\n", infopath);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer (_("Commands available in Info windows:\n\n"));
dump_map_to_message_buffer ("", info_keymap);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer (_("Commands available in the echo area:\n\n"));
dump_map_to_message_buffer ("", echo_area_keymap);
#if defined (NAMED_FUNCTIONS)
exec_keys = where_is (info_keymap, InfoCmd(info_execute_command));
if (exec_keys)
exec_keys = xstrdup (exec_keys);
for (i = 0; function_doc_array[i].func; i++)
{
InfoCommand *cmd = DocInfoCmd(&function_doc_array[i]);
if (InfoFunction(cmd) != info_do_lowercase_version
&& !where_is_internal (info_keymap, cmd)
&& !where_is_internal (echo_area_keymap, cmd))
{
if (!printed_one_mx)
{
printf_to_message_buffer ("---------------------\n\n");
if (exec_keys && exec_keys[0])
printf_to_message_buffer
(_("The following commands can only be invoked via %s:\n\n"), exec_keys);
else
printf_to_message_buffer
(_("The following commands cannot be invoked at all:\n\n"));
printed_one_mx = 1;
}
printf_to_message_buffer
("%s %s\n %s\n",
exec_keys,
function_doc_array[i].func_name,
replace_in_documentation (strlen (function_doc_array[i].doc)
? _(function_doc_array[i].doc)
: "")
);
}
}
if (printed_one_mx)
printf_to_message_buffer ("\n");
maybe_free (exec_keys);
#endif
printf_to_message_buffer
("%s", replace_in_documentation
(_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
node = message_buffer_to_node ();
internal_info_help_node_contents = node->contents;
}
else
{
node = build_message_node ("", 0, 0);
free (node->contents);
node->contents = contents;
node->nodelen = 1 + strlen (contents);
}
internal_info_help_node = node;
#if defined (HELP_NODE_GETS_REGENERATED)
add_gcable_pointer (internal_info_help_node->contents);
#endif
name_internal_node (internal_info_help_node, info_help_nodename);
internal_info_help_node->flags &= ~N_IsInternal;
}
#define HELP_SPLIT_SIZE 24
static WINDOW *
info_find_or_create_help_window ()
{
int help_is_only_window_p;
WINDOW *eligible = NULL;
WINDOW *help_window = get_window_of_node (internal_info_help_node);
if (!help_window)
{
WINDOW *window;
int max = 0;
for (window = windows; window; window = window->next)
{
if (window->height > max)
{
max = window->height;
eligible = window;
}
}
if (!eligible)
return NULL;
}
#ifndef HELP_NODE_GETS_REGENERATED
else
return help_window;
#endif
help_is_only_window_p
= ((help_window && !windows->next)
|| !help_window && eligible->height < HELP_SPLIT_SIZE);
create_internal_info_help_node (help_is_only_window_p);
if (!help_window)
{
if (eligible->height >= HELP_SPLIT_SIZE)
{
active_window = eligible;
help_window = window_make_window (internal_info_help_node);
}
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, internal_info_help_node);
help_window = active_window;
}
}
else
{
if (active_window != help_window)
{
set_remembered_pagetop_and_point (active_window);
active_window = help_window;
}
window_set_node_of_window (active_window, internal_info_help_node);
}
remember_window_and_node (help_window, help_window->node);
return help_window;
}
DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
{
WINDOW *help_window;
help_window = info_find_or_create_help_window ();
if (help_window)
{
active_window = help_window;
active_window->flags |= W_UpdateWindow;
}
else
{
info_error (msg_cant_make_help);
}
}
DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
{
NODE *node;
char *nodename;
{
WINDOW *win;
for (win = windows; win; win = win->next)
{
if (win->node && win->node->filename &&
(strcasecmp
(filename_non_directory (win->node->filename), "info") == 0) &&
((strcmp (win->node->nodename, "Help") == 0) ||
(strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
{
active_window = win;
return;
}
}
}
if (active_window->height < 24)
nodename = "Help-Small-Screen";
else
nodename = "Help";
node = info_get_node ("Info", nodename);
if (!node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error (msg_cant_file_node, "Info", nodename);
}
else
{
if (active_window->height > 45)
active_window = window_make_window (node);
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, node);
}
remember_window_and_node (active_window, node);
}
}
char *
function_documentation (cmd)
InfoCommand *cmd;
{
char *doc;
#if defined (INFOKEY)
doc = cmd->doc;
#else
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (InfoFunction(cmd) == function_doc_array[i].func)
break;
doc = function_doc_array[i].func ? function_doc_array[i].doc : "";
#endif
return replace_in_documentation ((strlen (doc) == 0) ? doc : _(doc));
}
#if defined (NAMED_FUNCTIONS)
char *
function_name (cmd)
InfoCommand *cmd;
{
#if defined (INFOKEY)
return cmd->func_name;
#else
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (InfoFunction(cmd) == function_doc_array[i].func)
break;
return (function_doc_array[i].func_name);
#endif
}
InfoCommand *
named_function (name)
char *name;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (strcmp (function_doc_array[i].func_name, name) == 0)
break;
return (DocInfoCmd(&function_doc_array[i]));
}
#endif
char *
key_documentation (key, map)
char key;
Keymap map;
{
InfoCommand *function = map[key].function;
if (function)
return (function_documentation (function));
else
return ((char *)NULL);
}
DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
{
char keys[50];
unsigned char keystroke;
char *k = keys;
Keymap map;
*k = '\0';
map = window->keymap;
for (;;)
{
message_in_echo_area (_("Describe key: %s"), pretty_keyseq (keys));
keystroke = info_get_input_char ();
unmessage_in_echo_area ();
#if !defined (INFOKEY)
if (Meta_p (keystroke))
{
if (map[ESC].type != ISKMAP)
{
window_message_in_echo_area
(_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
return;
}
*k++ = '\e';
keystroke = UnMeta (keystroke);
map = (Keymap)map[ESC].function;
}
#endif
*k++ = keystroke;
*k = '\0';
if (map[keystroke].function == (InfoCommand *)NULL)
{
message_in_echo_area (_("%s is undefined."), pretty_keyseq (keys));
return;
}
else if (map[keystroke].type == ISKMAP)
{
map = (Keymap)map[keystroke].function;
continue;
}
else
{
char *keyname, *message, *fundoc, *funname = "";
#if defined (INFOKEY)
if (InfoFunction(map[keystroke].function) == info_do_lowercase_version)
{
unsigned char lowerkey = Meta_p(keystroke)
? Meta (tolower (UnMeta (keystroke)))
: tolower (keystroke);
if (map[lowerkey].function == (InfoCommand *)NULL)
{
message_in_echo_area (_("%s is undefined."),
pretty_keyseq (keys));
return;
}
}
#endif
keyname = pretty_keyseq (keys);
#if defined (NAMED_FUNCTIONS)
funname = function_name (map[keystroke].function);
#endif
fundoc = function_documentation (map[keystroke].function);
message = (char *)xmalloc
(10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
#if defined (NAMED_FUNCTIONS)
sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
#else
sprintf (message, _("%s is defined to %s."), keyname, fundoc);
#endif
window_message_in_echo_area ("%s", message);
free (message);
break;
}
}
}
char *
pretty_keyname (key)
unsigned char key;
{
static char rep_buffer[30];
char *rep;
if (Meta_p (key))
{
char temp[20];
rep = pretty_keyname (UnMeta (key));
#if defined (INFOKEY)
sprintf (temp, "M-%s", rep);
#else
sprintf (temp, "ESC %s", rep);
#endif
strcpy (rep_buffer, temp);
rep = rep_buffer;
}
else if (Control_p (key))
{
switch (key)
{
case '\n': rep = "LFD"; break;
case '\t': rep = "TAB"; break;
case '\r': rep = "RET"; break;
case ESC: rep = "ESC"; break;
default:
sprintf (rep_buffer, "C-%c", UnControl (key));
rep = rep_buffer;
}
}
else
{
switch (key)
{
case ' ': rep = "SPC"; break;
case DEL: rep = "DEL"; break;
default:
rep_buffer[0] = key;
rep_buffer[1] = '\0';
rep = rep_buffer;
}
}
return (rep);
}
static void pretty_keyseq_internal ();
char *
pretty_keyseq (keyseq)
char *keyseq;
{
static char keyseq_rep[200];
keyseq_rep[0] = '\0';
if (*keyseq)
pretty_keyseq_internal (keyseq, keyseq_rep);
return (keyseq_rep);
}
static void
pretty_keyseq_internal (keyseq, rep)
char *keyseq, *rep;
{
if (term_kP && strncmp(keyseq, term_kP, strlen(term_kP)) == 0)
{
strcpy(rep, "PgUp");
keyseq += strlen(term_kP);
}
else if (term_kN && strncmp(keyseq, term_kN, strlen(term_kN)) == 0)
{
strcpy(rep, "PgDn");
keyseq += strlen(term_kN);
}
#if defined(INFOKEY)
else if (term_kh && strncmp(keyseq, term_kh, strlen(term_kh)) == 0)
{
strcpy(rep, "Home");
keyseq += strlen(term_kh);
}
else if (term_ke && strncmp(keyseq, term_ke, strlen(term_ke)) == 0)
{
strcpy(rep, "End");
keyseq += strlen(term_ke);
}
else if (term_ki && strncmp(keyseq, term_ki, strlen(term_ki)) == 0)
{
strcpy(rep, "INS");
keyseq += strlen(term_ki);
}
else if (term_kx && strncmp(keyseq, term_kx, strlen(term_kx)) == 0)
{
strcpy(rep, "DEL");
keyseq += strlen(term_kx);
}
#endif
else if (term_ku && strncmp(keyseq, term_ku, strlen(term_ku)) == 0)
{
strcpy(rep, "Up");
keyseq += strlen(term_ku);
}
else if (term_kd && strncmp(keyseq, term_kd, strlen(term_kd)) == 0)
{
strcpy(rep, "Down");
keyseq += strlen(term_kd);
}
else if (term_kl && strncmp(keyseq, term_kl, strlen(term_kl)) == 0)
{
strcpy(rep, "Left");
keyseq += strlen(term_kl);
}
else if (term_kr && strncmp(keyseq, term_kr, strlen(term_kr)) == 0)
{
strcpy(rep, "Right");
keyseq += strlen(term_kr);
}
else
{
strcpy (rep, pretty_keyname (keyseq[0]));
keyseq++;
}
if (*keyseq)
{
strcat (rep, " ");
pretty_keyseq_internal (keyseq, rep + strlen(rep));
}
}
static char *
strrpbrk (s, f)
const char *s, *f;
{
register const char *e = s + strlen(s);
register const char *t;
while (e-- != s)
{
for (t = f; *t; t++)
if (*e == *t)
return (char *)e;
}
return NULL;
}
char *
replace_in_documentation (string, help_is_only_window_p)
char *string;
int help_is_only_window_p;
{
unsigned reslen = strlen (string);
register int i, start, next;
static char *result = (char *)NULL;
maybe_free (result);
result = (char *)xmalloc (1 + reslen);
i = next = start = 0;
for (i = start; string[i]; i++)
{
int j = i + 1;
if (string[i] == '\\')
{
char *fmt = NULL;
unsigned min = 0;
unsigned max = 0;
if(string[j] == '%')
{
if (string[++j] == '-')
j++;
if (isdigit(string[j]))
{
min = atoi(string + j);
while (isdigit(string[j]))
j++;
if (string[j] == '.' && isdigit(string[j + 1]))
{
j += 1;
max = atoi(string + j);
while (isdigit(string[j]))
j++;
}
fmt = (char *)xmalloc (j - i + 2);
strncpy (fmt, string + i + 1, j - i);
fmt[j - i - 1] = 's';
fmt[j - i] = '\0';
}
else
j = i + 1;
}
if (string[j] == '[')
{
unsigned arg = 0;
char *argstr = NULL;
char *rep_name, *fun_name, *rep;
InfoCommand *command;
char *repstr = NULL;
unsigned replen;
strncpy (result + next, string + start, i - start);
next += (i - start);
start = j + 1;
i = start;
if (isdigit(string[i])
|| (string[i] == '-' && isdigit(string[i + 1])) )
{
arg = atoi(string + i);
if (string[i] == '-')
i++;
while (isdigit(string[i]))
i++;
}
start = i;
for (i = start; string[i] && (string[i] != ']'); i++);
rep_name = (char *)xmalloc (1 + i - start);
strncpy (rep_name, string + start, i - start);
rep_name[i - start] = '\0';
if (strcmp (rep_name, "quit-help") == 0)
fun_name = help_is_only_window_p ? "history-node"
: "delete-window";
else
fun_name = rep_name;
command = named_function (fun_name);
free (rep_name);
if (!command)
abort ();
if (arg)
{
char *argrep, *p;
argrep = where_is (info_keymap, InfoCmd(info_add_digit_to_numeric_arg));
p = argrep ? strrpbrk (argrep, "0123456789-") : NULL;
if (p)
{
argstr = (char *)xmalloc (p - argrep + 21);
strncpy (argstr, argrep, p - argrep);
sprintf (argstr + (p - argrep), "%d", arg);
}
else
command = NULL;
}
rep = command ? where_is (info_keymap, command) : NULL;
if (!rep)
rep = "N/A";
replen = (argstr ? strlen (argstr) : 0) + strlen (rep) + 1;
repstr = (char *)xmalloc (replen);
repstr[0] = '\0';
if (argstr)
{
strcat(repstr, argstr);
strcat(repstr, " ");
free (argstr);
}
strcat(repstr, rep);
if (fmt)
{
if (replen > max)
replen = max;
if (replen < min)
replen = min;
}
if (next + replen > reslen)
{
reslen = next + replen + 1;
result = (char *)xrealloc (result, reslen + 1);
}
if (fmt)
sprintf (result + next, fmt, repstr);
else
strcpy (result + next, repstr);
next = strlen (result);
free (repstr);
start = i;
if (string[i])
start++;
}
maybe_free (fmt);
}
}
strcpy (result + next, string + start);
return (result);
}
static char *where_is_rep = (char *)NULL;
static int where_is_rep_index = 0;
static int where_is_rep_size = 0;
char *
where_is (map, cmd)
Keymap map;
InfoCommand *cmd;
{
char *rep;
if (!where_is_rep_size)
where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
where_is_rep_index = 0;
rep = where_is_internal (map, cmd);
if (!rep)
{
char *name;
name = function_name (cmd);
if (!name)
return NULL;
rep = where_is_internal (map, InfoCmd(info_execute_command));
if (!rep)
return "";
sprintf (where_is_rep, "%s %s", rep, name);
rep = where_is_rep;
}
return (rep);
}
static char *
where_is_internal (map, cmd)
Keymap map;
InfoCommand *cmd;
{
#if defined(INFOKEY)
register FUNCTION_KEYSEQ *k;
for (k = cmd->keys; k; k = k->next)
if (k->map == map)
return pretty_keyseq (k->keyseq);
return NULL;
#else
register int i;
for (i = 0; i < 256; i++)
if ((map[i].type == ISFUNC) && map[i].function == cmd)
{
sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
return (where_is_rep);
}
for (i = 0; i < 256; i++)
{
if (map[i].type == ISKMAP)
{
int saved_index = where_is_rep_index;
char *rep;
sprintf (where_is_rep + where_is_rep_index, "%s ",
pretty_keyname (i));
where_is_rep_index = strlen (where_is_rep);
rep = where_is_internal ((Keymap)map[i].function, cmd);
if (rep)
return (where_is_rep);
where_is_rep_index = saved_index;
}
}
return NULL;
#endif
}
extern char *read_function_name ();
DECLARE_INFO_COMMAND (info_where_is,
_("Show what to type to execute a given command"))
{
char *command_name;
command_name = read_function_name (_("Where is command: "), window);
if (!command_name)
{
info_abort_key (active_window, count, key);
return;
}
if (*command_name)
{
InfoCommand *command;
command = named_function (command_name);
if (command)
{
char *location;
location = where_is (active_window->keymap, command);
if (!location || !location[0])
{
info_error (_("`%s' is not on any keys"), command_name);
}
else
{
if (strstr (location, function_name (command)))
window_message_in_echo_area
(_("%s can only be invoked via %s."), command_name, location);
else
window_message_in_echo_area
(_("%s can be invoked via %s."), command_name, location);
}
}
else
info_error (_("There is no function named `%s'"), command_name);
}
free (command_name);
}