* cp-tree.h (struct language_function): Remove static_labelno.
[official-gcc.git] / texinfo / info / infodoc.c
blob925425a432445c031e7c947ffab25b6b387dcd4e
1 /* infodoc.c -- Functions which build documentation nodes.
2 $Id: infodoc.c,v 1.1.1.2 1998/03/22 20:42:39 law Exp $
4 Copyright (C) 1993, 97 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)
9 any later version.
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). */
22 #include "info.h"
24 /* Normally we do not define HELP_NODE_GETS_REGENERATED because the
25 contents of the help node currently can never change once an info
26 session has been started. You should consider defining this in
27 the case that you place information about dynamic variables in the
28 help text. When that happens, the contents of the help node will
29 change dependent on the value of those variables, and the user will
30 expect to see those changes. */
31 /* #define HELP_NODE_GETS_REGENERATED 1 */
33 /* **************************************************************** */
34 /* */
35 /* Info Help Windows */
36 /* */
37 /* **************************************************************** */
39 /* The name of the node used in the help window. */
40 static char *info_help_nodename = "*Info Help*";
42 /* A node containing printed key bindings and their documentation. */
43 static NODE *internal_info_help_node = (NODE *)NULL;
45 /* A pointer to the contents of the help node. */
46 static char *internal_info_help_node_contents = (char *)NULL;
48 /* The static text which appears in the internal info help node. */
49 static char *info_internal_help_text[] = {
50 N_ ("Basic Commands in Info Windows"),
51 "******************************",
52 "",
53 " h Invoke the Info tutorial.",
54 " CTRL-x 0 Quit this help.",
55 " q Quit Info altogether.",
56 "",
57 "Selecting other nodes:",
58 "----------------------",
59 " n Move to the \"next\" node of this node.",
60 " p Move to the \"previous\" node of this node.",
61 " u Move \"up\" from this node.",
62 " m Pick menu item specified by name.",
63 " Picking a menu item causes another node to be selected.",
64 " f Follow a cross reference. Reads name of reference.",
65 " l Move to the last node seen in this window.",
66 " d Move to the `directory' node. Equivalent to `g(DIR)'.",
67 "",
68 "Moving within a node:",
69 "---------------------",
70 " SPC Scroll forward a page.",
71 " DEL Scroll backward a page.",
72 " b Go to the beginning of this node.",
73 " e Go to the end of this node.",
74 "",
75 "Other commands:",
76 "--------------------",
77 " 1 Pick first item in node's menu.",
78 " 2-9 Pick second ... ninth item in node's menu.",
79 " 0 Pick last item in node's menu.",
80 " g Move to node specified by name.",
81 " You may include a filename as well, as in (FILENAME)NODENAME.",
82 " s Search through this Info file for a specified string,",
83 " and select the node in which the next occurrence is found.",
84 NULL
87 static char *where_is (), *where_is_internal ();
89 void
90 dump_map_to_message_buffer (prefix, map)
91 char *prefix;
92 Keymap map;
94 register int i;
96 for (i = 0; i < 256; i++)
98 if (map[i].type == ISKMAP)
100 char *new_prefix, *keyname;
102 keyname = pretty_keyname (i);
103 new_prefix = (char *)
104 xmalloc (3 + strlen (prefix) + strlen (keyname));
105 sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
107 dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
108 free (new_prefix);
110 else if (map[i].function)
112 register int last;
113 char *doc, *name;
115 doc = function_documentation (map[i].function);
116 name = function_name (map[i].function);
118 if (!*doc)
119 continue;
121 /* Find out if there is a series of identical functions, as in
122 ea_insert (). */
123 for (last = i + 1; last < 256; last++)
124 if ((map[last].type != ISFUNC) ||
125 (map[last].function != map[i].function))
126 break;
128 if (last - 1 != i)
130 printf_to_message_buffer
131 ("%s%s .. ", prefix, pretty_keyname (i));
132 printf_to_message_buffer
133 ("%s%s\t", prefix, pretty_keyname (last - 1));
134 i = last - 1;
136 else
137 printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
139 #if defined (NAMED_FUNCTIONS)
140 /* Print the name of the function, and some padding before the
141 documentation string is printed. */
143 int length_so_far;
144 int desired_doc_start = 40; /* Must be multiple of 8. */
146 printf_to_message_buffer ("(%s)", name);
147 length_so_far = message_buffer_length_this_line ();
149 if ((desired_doc_start + strlen (doc)) >= the_screen->width)
150 printf_to_message_buffer ("\n ");
151 else
153 while (length_so_far < desired_doc_start)
155 printf_to_message_buffer ("\t");
156 length_so_far += character_width ('\t', length_so_far);
160 #endif /* NAMED_FUNCTIONS */
161 printf_to_message_buffer ("%s\n", doc);
166 /* How to create internal_info_help_node. */
167 static void
168 create_internal_info_help_node ()
170 register int i;
171 char *contents = (char *)NULL;
172 NODE *node;
174 #if !defined (HELP_NODE_GETS_REGENERATED)
175 if (internal_info_help_node_contents)
176 contents = internal_info_help_node_contents;
177 #endif /* !HELP_NODE_GETS_REGENERATED */
179 if (!contents)
181 int printed_one_mx = 0;
183 initialize_message_buffer ();
185 for (i = 0; info_internal_help_text[i]; i++)
186 printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
188 printf_to_message_buffer ("---------------------\n\n");
189 printf_to_message_buffer ("The current search path is:\n");
190 printf_to_message_buffer (" \"%s\"\n", infopath);
191 printf_to_message_buffer ("---------------------\n\n");
192 printf_to_message_buffer ("Commands available in Info windows:\n\n");
193 dump_map_to_message_buffer ("", info_keymap);
194 printf_to_message_buffer ("---------------------\n\n");
195 printf_to_message_buffer ("Commands available in the echo area:\n\n");
196 dump_map_to_message_buffer ("", echo_area_keymap);
198 #if defined (NAMED_FUNCTIONS)
199 /* Get a list of the M-x commands which have no keystroke equivs. */
200 for (i = 0; function_doc_array[i].func; i++)
202 VFunction *func = function_doc_array[i].func;
204 if ((!where_is_internal (info_keymap, func)) &&
205 (!where_is_internal (echo_area_keymap, func)))
207 if (!printed_one_mx)
209 printf_to_message_buffer ("---------------------\n\n");
210 printf_to_message_buffer
211 (_("The following commands can only be invoked via M-x:\n\n"));
212 printed_one_mx = 1;
215 printf_to_message_buffer
216 ("M-x %s\n %s\n",
217 function_doc_array[i].func_name,
218 replace_in_documentation (function_doc_array[i].doc));
222 if (printed_one_mx)
223 printf_to_message_buffer ("\n");
224 #endif /* NAMED_FUNCTIONS */
226 printf_to_message_buffer
227 ("%s", replace_in_documentation
228 (_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
229 node = message_buffer_to_node ();
230 internal_info_help_node_contents = node->contents;
232 else
234 /* We already had the right contents, so simply use them. */
235 node = build_message_node ("", 0, 0);
236 free (node->contents);
237 node->contents = contents;
238 node->nodelen = 1 + strlen (contents);
241 internal_info_help_node = node;
243 /* Do not GC this node's contents. It never changes, and we never need
244 to delete it once it is made. If you change some things (such as
245 placing information about dynamic variables in the help text) then
246 you will need to allow the contents to be gc'd, and you will have to
247 arrange to always regenerate the help node. */
248 #if defined (HELP_NODE_GETS_REGENERATED)
249 add_gcable_pointer (internal_info_help_node->contents);
250 #endif
252 name_internal_node (internal_info_help_node, info_help_nodename);
254 /* Even though this is an internal node, we don't want the window
255 system to treat it specially. So we turn off the internalness
256 of it here. */
257 internal_info_help_node->flags &= ~N_IsInternal;
260 /* Return a window which is the window showing help in this Info. */
261 static WINDOW *
262 info_find_or_create_help_window ()
264 WINDOW *help_window, *eligible, *window;
266 eligible = (WINDOW *)NULL;
267 help_window = get_internal_info_window (info_help_nodename);
269 /* If we couldn't find the help window, then make it. */
270 if (!help_window)
272 int max = 0;
274 for (window = windows; window; window = window->next)
276 if (window->height > max)
278 max = window->height;
279 eligible = window;
283 if (!eligible)
284 return ((WINDOW *)NULL);
286 #if !defined (HELP_NODE_GETS_REGENERATED)
287 else
288 return (help_window);
289 #endif /* !HELP_NODE_GETS_REGENERATED */
291 /* Make sure that we have a node containing the help text. */
292 create_internal_info_help_node ();
294 /* Either use the existing window to display the help node, or create
295 a new window if there was no existing help window. */
296 if (!help_window)
298 /* Split the largest window into 2 windows, and show the help text
299 in that window. */
300 if (eligible->height > 30)
302 active_window = eligible;
303 help_window = window_make_window (internal_info_help_node);
305 else
307 set_remembered_pagetop_and_point (active_window);
308 window_set_node_of_window (active_window, internal_info_help_node);
309 help_window = active_window;
312 else
314 /* Case where help node always gets regenerated, and we have an
315 existing window in which to place the node. */
316 if (active_window != help_window)
318 set_remembered_pagetop_and_point (active_window);
319 active_window = help_window;
321 window_set_node_of_window (active_window, internal_info_help_node);
323 remember_window_and_node (help_window, help_window->node);
324 return (help_window);
327 /* Create or move to the help window. */
328 DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
330 WINDOW *help_window;
332 help_window = info_find_or_create_help_window ();
333 if (help_window)
335 active_window = help_window;
336 active_window->flags |= W_UpdateWindow;
338 else
340 info_error (CANT_MAKE_HELP);
344 /* Show the Info help node. This means that the "info" file is installed
345 where it can easily be found on your system. */
346 DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
348 NODE *node;
349 char *nodename;
351 /* If there is a window on the screen showing the node "(info)Help" or
352 the node "(info)Help-Small-Screen", simply select that window. */
354 WINDOW *win;
356 for (win = windows; win; win = win->next)
358 if (win->node && win->node->filename &&
359 (strcasecmp
360 (filename_non_directory (win->node->filename), "info") == 0) &&
361 ((strcmp (win->node->nodename, "Help") == 0) ||
362 (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
364 active_window = win;
365 return;
370 /* If the current window is small, show the small screen help. */
371 if (active_window->height < 24)
372 nodename = "Help-Small-Screen";
373 else
374 nodename = "Help";
376 /* Try to get the info file for Info. */
377 node = info_get_node ("Info", nodename);
379 if (!node)
381 if (info_recent_file_error)
382 info_error (info_recent_file_error);
383 else
384 info_error (CANT_FILE_NODE, "Info", nodename);
386 else
388 /* If the current window is very large (greater than 45 lines),
389 then split it and show the help node in another window.
390 Otherwise, use the current window. */
392 if (active_window->height > 45)
393 active_window = window_make_window (node);
394 else
396 set_remembered_pagetop_and_point (active_window);
397 window_set_node_of_window (active_window, node);
400 remember_window_and_node (active_window, node);
404 /* **************************************************************** */
405 /* */
406 /* Groveling Info Keymaps and Docs */
407 /* */
408 /* **************************************************************** */
410 /* Return the documentation associated with the Info command FUNCTION. */
411 char *
412 function_documentation (function)
413 VFunction *function;
415 register int i;
417 for (i = 0; function_doc_array[i].func; i++)
418 if (function == function_doc_array[i].func)
419 break;
421 return (replace_in_documentation (function_doc_array[i].doc));
424 #if defined (NAMED_FUNCTIONS)
425 /* Return the user-visible name of the function associated with the
426 Info command FUNCTION. */
427 char *
428 function_name (function)
430 VFunction *function;
432 register int i;
434 for (i = 0; function_doc_array[i].func; i++)
435 if (function == function_doc_array[i].func)
436 break;
438 return (function_doc_array[i].func_name);
441 /* Return a pointer to the function named NAME. */
442 VFunction *
443 named_function (name)
444 char *name;
446 register int i;
448 for (i = 0; function_doc_array[i].func; i++)
449 if (strcmp (function_doc_array[i].func_name, name) == 0)
450 break;
452 return (function_doc_array[i].func);
454 #endif /* NAMED_FUNCTIONS */
456 /* Return the documentation associated with KEY in MAP. */
457 char *
458 key_documentation (key, map)
459 char key;
460 Keymap map;
462 VFunction *function = map[key].function;
464 if (function)
465 return (function_documentation (function));
466 else
467 return ((char *)NULL);
470 DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
472 char keyname[50];
473 int keyname_index = 0;
474 unsigned char keystroke;
475 char *rep;
476 Keymap map;
478 keyname[0] = '\0';
479 map = window->keymap;
481 while (1)
483 message_in_echo_area (_("Describe key: %s"), keyname);
484 keystroke = info_get_input_char ();
485 unmessage_in_echo_area ();
487 if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
489 if (map[ESC].type != ISKMAP)
491 window_message_in_echo_area
492 (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
493 return;
496 strcpy (keyname + keyname_index, "ESC ");
497 keyname_index = strlen (keyname);
498 keystroke = UnMeta (keystroke);
499 map = (Keymap)map[ESC].function;
502 /* Add the printed representation of KEYSTROKE to our keyname. */
503 rep = pretty_keyname (keystroke);
504 strcpy (keyname + keyname_index, rep);
505 keyname_index = strlen (keyname);
507 if (map[keystroke].function == (VFunction *)NULL)
509 message_in_echo_area (_("%s is undefined."), keyname);
510 return;
512 else if (map[keystroke].type == ISKMAP)
514 map = (Keymap)map[keystroke].function;
515 strcat (keyname, " ");
516 keyname_index = strlen (keyname);
517 continue;
519 else
521 char *message, *fundoc, *funname = "";
523 #if defined (NAMED_FUNCTIONS)
524 funname = function_name (map[keystroke].function);
525 #endif /* NAMED_FUNCTIONS */
527 fundoc = function_documentation (map[keystroke].function);
529 message = (char *)xmalloc
530 (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
532 #if defined (NAMED_FUNCTIONS)
533 sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
534 #else
535 sprintf (message, _("%s is defined to %s."), keyname, fundoc);
536 #endif /* !NAMED_FUNCTIONS */
538 window_message_in_echo_area ("%s", message);
539 free (message);
540 break;
545 /* How to get the pretty printable name of a character. */
546 static char rep_buffer[30];
548 char *
549 pretty_keyname (key)
550 unsigned char key;
552 char *rep;
554 if (Meta_p (key))
556 char temp[20];
558 rep = pretty_keyname (UnMeta (key));
560 sprintf (temp, "ESC %s", rep);
561 strcpy (rep_buffer, temp);
562 rep = rep_buffer;
564 else if (Control_p (key))
566 switch (key)
568 case '\n': rep = "LFD"; break;
569 case '\t': rep = "TAB"; break;
570 case '\r': rep = "RET"; break;
571 case ESC: rep = "ESC"; break;
573 default:
574 sprintf (rep_buffer, "C-%c", UnControl (key));
575 rep = rep_buffer;
578 else
580 switch (key)
582 case ' ': rep = "SPC"; break;
583 case DEL: rep = "DEL"; break;
584 default:
585 rep_buffer[0] = key;
586 rep_buffer[1] = '\0';
587 rep = rep_buffer;
590 return (rep);
593 /* Replace the names of functions with the key that invokes them. */
594 char *
595 replace_in_documentation (string)
596 char *string;
598 register int i, start, next;
599 static char *result = (char *)NULL;
601 maybe_free (result);
602 result = (char *)xmalloc (1 + strlen (string));
604 i = next = start = 0;
606 /* Skip to the beginning of a replaceable function. */
607 for (i = start; string[i]; i++)
609 /* Is this the start of a replaceable function name? */
610 if (string[i] == '\\' && string[i + 1] == '[')
612 char *fun_name, *rep;
613 VFunction *function;
615 /* Copy in the old text. */
616 strncpy (result + next, string + start, i - start);
617 next += (i - start);
618 start = i + 2;
620 /* Move to the end of the function name. */
621 for (i = start; string[i] && (string[i] != ']'); i++);
623 fun_name = (char *)xmalloc (1 + i - start);
624 strncpy (fun_name, string + start, i - start);
625 fun_name[i - start] = '\0';
627 /* Find a key which invokes this function in the info_keymap. */
628 function = named_function (fun_name);
630 /* If the internal documentation string fails, there is a
631 serious problem with the associated command's documentation.
632 We croak so that it can be fixed immediately. */
633 if (!function)
634 abort ();
636 rep = where_is (info_keymap, function);
637 strcpy (result + next, rep);
638 next = strlen (result);
640 start = i;
641 if (string[i])
642 start++;
645 strcpy (result + next, string + start);
646 return (result);
649 /* Return a string of characters which could be typed from the keymap
650 MAP to invoke FUNCTION. */
651 static char *where_is_rep = (char *)NULL;
652 static int where_is_rep_index = 0;
653 static int where_is_rep_size = 0;
655 static char *
656 where_is (map, function)
657 Keymap map;
658 VFunction *function;
660 char *rep;
662 if (!where_is_rep_size)
663 where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
664 where_is_rep_index = 0;
666 rep = where_is_internal (map, function);
668 /* If it couldn't be found, return "M-x Foo". */
669 if (!rep)
671 char *name;
673 name = function_name (function);
675 if (name)
676 sprintf (where_is_rep, "M-x %s", name);
678 rep = where_is_rep;
680 return (rep);
683 /* Return the printed rep of FUNCTION as found in MAP, or NULL. */
684 static char *
685 where_is_internal (map, function)
686 Keymap map;
687 VFunction *function;
689 register int i;
691 /* If the function is directly invokable in MAP, return the representation
692 of that keystroke. */
693 for (i = 0; i < 256; i++)
694 if ((map[i].type == ISFUNC) && map[i].function == function)
696 sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
697 return (where_is_rep);
700 /* Okay, search subsequent maps for this function. */
701 for (i = 0; i < 256; i++)
703 if (map[i].type == ISKMAP)
705 int saved_index = where_is_rep_index;
706 char *rep;
708 sprintf (where_is_rep + where_is_rep_index, "%s ",
709 pretty_keyname (i));
711 where_is_rep_index = strlen (where_is_rep);
712 rep = where_is_internal ((Keymap)map[i].function, function);
714 if (rep)
715 return (where_is_rep);
717 where_is_rep_index = saved_index;
721 return ((char *)NULL);
724 extern char *read_function_name ();
726 DECLARE_INFO_COMMAND (info_where_is,
727 "Show what to type to execute a given command")
729 char *command_name;
731 command_name = read_function_name (_("Where is command: "), window);
733 if (!command_name)
735 info_abort_key (active_window, count, key);
736 return;
739 if (*command_name)
741 VFunction *function;
743 function = named_function (command_name);
745 if (function)
747 char *location;
749 location = where_is (active_window->keymap, function);
751 if (!location)
753 info_error (_("`%s' is not on any keys"), command_name);
755 else
757 if (strncmp (location, "M-x ", 4) == 0)
758 window_message_in_echo_area
759 (_("%s can only be invoked via %s."), command_name, location);
760 else
761 window_message_in_echo_area
762 (_("%s can be invoked via %s."), command_name, location);
765 else
766 info_error (_("There is no function named `%s'"), command_name);
769 free (command_name);