home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / utilities / cli / gnuinfo / Source / c / infodoc < prev    next >
Encoding:
Text File  |  1994-10-01  |  17.4 KB  |  691 lines

  1. #include "defines.h"
  2. /* infohelp.c -- Functions which build documentation nodes. */
  3.  
  4. /* This file is part of GNU Info, a program for reading online documentation
  5.    stored in Info format.
  6.  
  7.    Copyright (C) 1993 Free Software Foundation, Inc.
  8.  
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2, or (at your option)
  12.    any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23.    Written by Brian Fox (bfox@ai.mit.edu). */
  24.  
  25. #include "info.h"
  26.  
  27. /* **************************************************************** */
  28. /*                                    */
  29. /*              Info Help Windows                */
  30. /*                                    */
  31. /* **************************************************************** */
  32.  
  33. /* The name of the node used in the help window. */
  34. static char *info_help_nodename = "*Info Help*";
  35.  
  36. /* A node containing printed key bindings and their documentation. */
  37. static NODE *internal_info_help_node = (NODE *)NULL;
  38.  
  39. /* The static text which appears in the internal info help node. */
  40. static char *info_internal_help_text[] = {
  41.   "Basic Commands in Info Windows",
  42.   "******************************",
  43.   "",
  44.   "  h   Invoke the Info tutorial.",
  45.   "",
  46.   "Selecting other nodes:",
  47.   "----------------------",
  48.   "  n   Move to the \"next\" node of this node.",
  49.   "  p   Move to the \"previous\" node of this node.",
  50.   "  u   Move \"up\" from this node.",
  51.   "  m   Pick menu item specified by name.",
  52.   "      Picking a menu item causes another node to be selected.",
  53.   "  f   Follow a cross reference.  Reads name of reference.",
  54.   "  l   Move to the last node seen in this window.",
  55.   "  d   Move to the `directory' node.  Equivalent to `g(DIR)'.",
  56.   "",
  57.   "Moving within a node:",
  58.   "---------------------",
  59.   "  SPC Scroll forward a page.",
  60.   "  DEL Scroll backward a page.",
  61.   "  b   Go to the beginning of this node.",
  62.   "  e   Go to the end of this node.",
  63.   "",
  64.   "\"Advanced\" commands:",
  65.   "--------------------",
  66.   "  q   Quit Info.",
  67.   "  1   Pick first item in node's menu.",
  68.   "  2-9 Pick second ... ninth item in node's menu.",
  69.   "  0   Pick last item in node's menu.",
  70.   "  g   Move to node specified by name.",
  71.   "      You may include a filename as well, as in (FILENAME)NODENAME.",
  72.   "  s   Search through this Info file for a specified string,",
  73.   "      and select the node in which the next occurrence is found.",
  74.   (char *)NULL
  75. };
  76.  
  77. void
  78. dump_map_to_message_buffer (prefix, map)
  79.      char *prefix;
  80.      Keymap map;
  81. {
  82.   register int i;
  83.  
  84.   for (i = 0; i < 256; i++)
  85.     {
  86.       if (map[i].type == ISKMAP)
  87.     {
  88.       char *new_prefix, *keyname;
  89.  
  90.       keyname = pretty_keyname (i);
  91.       new_prefix = (char *)
  92.         xmalloc (3 + strlen (prefix) + strlen (keyname));
  93.       sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
  94.  
  95.       dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
  96.       free (new_prefix);
  97.     }
  98.       else if (map[i].function)
  99.     {
  100.       register int last;
  101.       char *doc, *name;
  102.  
  103.       doc = function_documentation (map[i].function);
  104.       name = function_name (map[i].function);
  105.  
  106.       if (!*doc)
  107.         continue;
  108.  
  109.       /* Find out if there is a series of identical functions, as in
  110.          ea_insert (). */
  111.       for (last = i + 1; last < 256; last++)
  112.         if ((map[last].type != ISFUNC) ||
  113.         (map[last].function != map[i].function))
  114.           break;
  115.  
  116.       if (last - 1 != i)
  117.         {
  118.           printf_to_message_buffer
  119.         ("%s%s .. ", prefix, pretty_keyname (i));
  120.           printf_to_message_buffer
  121.         ("%s%s\t", prefix, pretty_keyname (last - 1));
  122.           i = last - 1;
  123.         }
  124.       else
  125.         printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
  126.  
  127. #if defined (NAMED_FUNCTIONS)
  128.       /* Print the name of the function, and some padding before the
  129.          documentation string is printed. */
  130.       {
  131.         int length_so_far;
  132.         int desired_doc_start = 40;    /* Must be multiple of 8. */
  133.  
  134.         printf_to_message_buffer ("(%s)", name);
  135.         length_so_far = message_buffer_length_this_line ();
  136.  
  137.         if ((desired_doc_start + strlen (doc)) >= the_screen->width)
  138.           printf_to_message_buffer ("\n     ");
  139.         else
  140.           {
  141.         while (length_so_far < desired_doc_start)
  142.           {
  143.             printf_to_message_buffer ("\t");
  144.             length_so_far += character_width ('\t', length_so_far);
  145.           }
  146.           }
  147.       }
  148. #endif /* NAMED_FUNCTIONS */
  149.       printf_to_message_buffer ("%s\n", doc);
  150.     }
  151.     }
  152. }
  153.  
  154. /* How to create internal_info_help_node. */
  155. static void
  156. create_internal_info_help_node ()
  157. {
  158.   register int i;
  159.  
  160.   initialize_message_buffer ();
  161.  
  162.   for (i = 0; info_internal_help_text[i]; i++)
  163.     printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
  164.  
  165.   printf_to_message_buffer ("---------------------\n\n");
  166.   printf_to_message_buffer ("The current search path is:\n");
  167.   printf_to_message_buffer ("  \"%s\"\n", infopath);
  168.   printf_to_message_buffer ("---------------------\n\n");
  169.   printf_to_message_buffer ("Commands available in Info windows:\n\n");
  170.   dump_map_to_message_buffer ("", info_keymap);
  171.   printf_to_message_buffer ("---------------------\n\n");
  172.   printf_to_message_buffer ("Commands available in the echo area:\n\n");
  173.   dump_map_to_message_buffer ("", echo_area_keymap);
  174.  
  175.   {
  176.     char *message;
  177.  
  178.     message = replace_in_documentation
  179.       ("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n");
  180.     printf_to_message_buffer ("%s", message);
  181.   }
  182.  
  183.   internal_info_help_node = message_buffer_to_node ();
  184.   add_gcable_pointer (internal_info_help_node->contents);
  185.   name_internal_node (internal_info_help_node, info_help_nodename);
  186.  
  187.   /* Even though this is an internal node, we don't want the window
  188.      system to treat it specially.  So we turn off the internalness
  189.      of it here. */
  190.   internal_info_help_node->flags &= ~N_IsInternal;
  191. }
  192.  
  193. /* Return a window which is the window showing help in this Info. */
  194. static WINDOW *
  195. info_find_or_create_help_window ()
  196. {
  197.   WINDOW *help_window;
  198.  
  199.   help_window = get_internal_info_window (info_help_nodename);
  200.  
  201.   /* If we couldn't find the help window, then make it. */
  202.   if (!help_window)
  203.     {
  204.       WINDOW *window, *eligible = (WINDOW *)NULL;
  205.       int max = 0;
  206.  
  207.       for (window = windows; window; window = window->next)
  208.     {
  209.       if (window->height > max)
  210.         {
  211.           max = window->height;
  212.           eligible = window;
  213.         }
  214.     }
  215.  
  216.       if (!eligible)
  217.     return ((WINDOW *)NULL);
  218.       else
  219.     {
  220.       /* Make a new node containing the help text.  Split the largest
  221.          window into 2 windows, and show the help text in that window. */
  222.       if (!internal_info_help_node)
  223.         create_internal_info_help_node ();
  224.  
  225.       if (eligible->height > 30)
  226.         {
  227.           active_window = eligible;
  228.           help_window = window_make_window (internal_info_help_node);
  229.         }
  230.       else
  231.         {
  232.           set_remembered_pagetop_and_point (active_window);
  233.           window_set_node_of_window
  234.         (active_window, internal_info_help_node);
  235.           help_window = active_window;
  236.         }
  237.  
  238.       remember_window_and_node (help_window, help_window->node);
  239.     }
  240.     }
  241.   return (help_window);
  242. }
  243.  
  244. /* Create or move to the help window. */
  245. DECLARE_INFO_COMMAND (info_get_help_window, "Display help message")
  246. {
  247.   WINDOW *help_window;
  248.  
  249.   help_window = info_find_or_create_help_window ();
  250.   if (help_window)
  251.     {
  252.       active_window = help_window;
  253.       active_window->flags |= W_UpdateWindow;
  254.     }
  255.   else
  256.     {
  257.       info_error (CANT_MAKE_HELP);
  258.     }
  259. }
  260.  
  261. /* Show the Info help node.  This means that the "info" file is installed
  262.    where it can easily be found on your system. */
  263. DECLARE_INFO_COMMAND (info_get_info_help_node, "Visit Info node `(info)Help'")
  264. {
  265.   NODE *node;
  266.   char *nodename;
  267.  
  268.   /* If there is a window on the screen showing the node "(info)Help" or
  269.      the node "(info)Help-Small-Screen", simply select that window. */
  270.   {
  271.     WINDOW *win;
  272.  
  273.     for (win = windows; win; win = win->next)
  274.       {
  275.     if (win->node && win->node->filename &&
  276.         (stricmp
  277.          (filename_non_directory (win->node->filename), "info") == 0) &&
  278.         ((strcmp (win->node->nodename, "Help") == 0) ||
  279.          (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
  280.       {
  281.         active_window = win;
  282.         return;
  283.       }
  284.       }
  285.   }
  286.  
  287.   /* If the current window is small, show the small screen help. */
  288.   if (active_window->height < 24)
  289.     nodename = "Help-Small-Screen";
  290.   else
  291.     nodename = "Help";
  292.  
  293.   /* Try to get the info file for Info. */
  294.   node = info_get_node ("Info", nodename);
  295.  
  296.   if (!node)
  297.     {
  298.       if (info_recent_file_error)
  299.     info_error (info_recent_file_error);
  300.       else
  301.     info_error (CANT_FILE_NODE, "Info", nodename);
  302.     }
  303.   else
  304.     {
  305.       /* If the current window is very large (greater than 45 lines),
  306.      then split it and show the help node in another window.
  307.      Otherwise, use the current window. */
  308.  
  309.       if (active_window->height > 45)
  310.     active_window = window_make_window (node);
  311.       else
  312.     {
  313.       set_remembered_pagetop_and_point (active_window);
  314.       window_set_node_of_window (active_window, node);
  315.     }
  316.  
  317.       remember_window_and_node (active_window, node);
  318.     }
  319. }
  320.  
  321. /* **************************************************************** */
  322. /*                                    */
  323. /*             Groveling Info Keymaps and Docs            */
  324. /*                                    */
  325. /* **************************************************************** */
  326.  
  327. /* Return the documentation associated with the Info command FUNCTION. */
  328. char *
  329. function_documentation (function)
  330.      VFunction *function;
  331. {
  332.   register int i;
  333.  
  334.   for (i = 0; function_doc_array[i].func; i++)
  335.     if (function == function_doc_array[i].func)
  336.       break;
  337.  
  338.   return (replace_in_documentation (function_doc_array[i].doc));
  339. }
  340.  
  341. #if defined (NAMED_FUNCTIONS)
  342. /* Return the user-visible name of the function associated with the
  343.    Info command FUNCTION. */
  344. char *
  345. function_name (function)
  346.  
  347.      VFunction *function;
  348. {
  349.   register int i;
  350.  
  351.   for (i = 0; function_doc_array[i].func; i++)
  352.     if (function == function_doc_array[i].func)
  353.       break;
  354.  
  355.   return (function_doc_array[i].func_name);
  356. }
  357.  
  358. /* Return a pointer to the function named NAME. */
  359. VFunction *
  360. named_function (name)
  361.      char *name;
  362. {
  363.   register int i;
  364.  
  365.   for (i = 0; function_doc_array[i].func; i++)
  366.     if (strcmp (function_doc_array[i].func_name, name) == 0)
  367.       break;
  368.  
  369.   return (function_doc_array[i].func);
  370. }
  371. #endif /* NAMED_FUNCTIONS */
  372.  
  373. /* Return the documentation associated with KEY in MAP. */
  374. char *
  375. key_documentation (key, map)
  376.      char key;
  377.      Keymap map;
  378. {
  379.   VFunction *function = map[key].function;
  380.  
  381.   if (function)
  382.     return (function_documentation (function));
  383.   else
  384.     return ((char *)NULL);
  385. }
  386.  
  387. DECLARE_INFO_COMMAND (describe_key, "Print documentation for KEY")
  388. {
  389.   char keyname[50];
  390.   int keyname_index = 0;
  391.   unsigned char keystroke;
  392.   char *rep;
  393.   Keymap map;
  394.  
  395.   keyname[0] = '\0';
  396.   map = window->keymap;
  397.  
  398.   while (1)
  399.     {
  400.       message_in_echo_area ("Describe key: %s", keyname);
  401.       keystroke = info_get_input_char ();
  402.       unmessage_in_echo_area ();
  403.  
  404.       if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
  405.     {
  406.       if (map[ESC].type != ISKMAP)
  407.         {
  408.           window_message_in_echo_area
  409.         ("ESC %s is undefined.", pretty_keyname (UnMeta (keystroke)));
  410.           return;
  411.         }
  412.  
  413.       strcpy (keyname + keyname_index, "ESC ");
  414.       keyname_index = strlen (keyname);
  415.       keystroke = UnMeta (keystroke);
  416.       map = (Keymap)map[ESC].function;
  417.     }
  418.  
  419.       /* Add the printed representation of KEYSTROKE to our keyname. */
  420.       rep = pretty_keyname (keystroke);
  421.       strcpy (keyname + keyname_index, rep);
  422.       keyname_index = strlen (keyname);
  423.  
  424.       if (map[keystroke].function == (VFunction *)NULL)
  425.     {
  426.       message_in_echo_area ("%s is undefined.", keyname);
  427.       return;
  428.     }
  429.       else if (map[keystroke].type == ISKMAP)
  430.     {
  431.       map = (Keymap)map[keystroke].function;
  432.       strcat (keyname, " ");
  433.       keyname_index = strlen (keyname);
  434.       continue;
  435.     }
  436.       else
  437.     {
  438.       char *message, *fundoc, *funname = "";
  439.  
  440. #if defined (NAMED_FUNCTIONS)
  441.       funname = function_name (map[keystroke].function);
  442. #endif /* NAMED_FUNCTIONS */
  443.  
  444.       fundoc = function_documentation (map[keystroke].function);
  445.  
  446.       message = (char *)xmalloc
  447.         (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
  448.  
  449. #if defined (NAMED_FUNCTIONS)
  450.       sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
  451. #else
  452.       sprintf (message, "%s is defined to %s.", keyname, fundoc);
  453. #endif /* !NAMED_FUNCTIONS */
  454.  
  455.       window_message_in_echo_area ("%s", message);
  456.       free (message);
  457.       break;
  458.     }
  459.     }
  460. }
  461.  
  462. /* How to get the pretty printable name of a character. */
  463. static char rep_buffer[30];
  464.  
  465. char *
  466. pretty_keyname (key)
  467.      unsigned char key;
  468. {
  469.   char *rep;
  470.  
  471.   if (Meta_p (key))
  472.     {
  473.       char temp[20];
  474.  
  475.       rep = pretty_keyname (UnMeta (key));
  476.  
  477.       sprintf (temp, "ESC %s", rep);
  478.       strcpy (rep_buffer, temp);
  479.       rep = rep_buffer;
  480.     }
  481.   else if (Control_p (key))
  482.     {
  483.       switch (key)
  484.     {
  485.     case '\n': rep = "LFD"; break;
  486.     case '\t': rep = "TAB"; break;
  487.     case '\r': rep = "RET"; break;
  488.     case ESC:  rep = "ESC"; break;
  489.  
  490.     default:
  491.       sprintf (rep_buffer, "C-%c", UnControl (key));
  492.       rep = rep_buffer;
  493.     }
  494.     }
  495.   else
  496.     {
  497.       switch (key)
  498.     {
  499.     case ' ': rep = "SPC"; break;
  500.     case DEL: rep = "DEL"; break;
  501.     default:
  502.       rep_buffer[0] = key;
  503.       rep_buffer[1] = '\0';
  504.       rep = rep_buffer;
  505.     }
  506.     }
  507.   return (rep);
  508. }
  509.  
  510. /* Replace the names of functions with the key that invokes them. */
  511. static char *where_is (), *where_is_internal ();
  512.  
  513. char *
  514. replace_in_documentation (string)
  515.      char *string;
  516. {
  517.   register int i, start, next;
  518.   static char *result = (char *)NULL;
  519.  
  520.   maybe_free (result);
  521.   result = (char *)xmalloc (1 + strlen (string));
  522.  
  523.   i = next = start = 0;
  524.  
  525.   /* Skip to the beginning of a replaceable function. */
  526.   for (i = start; string[i]; i++)
  527.     {
  528.       /* Is this the start of a replaceable function name? */
  529.       if (string[i] == '\\' && string[i + 1] == '[')
  530.     {
  531.       char *fun_name, *rep;
  532.       VFunction *function;
  533.  
  534.       /* Copy in the old text. */
  535.       strncpy (result + next, string + start, i - start);
  536.       next += (i - start);
  537.       start = i + 2;
  538.  
  539.       /* Move to the end of the function name. */
  540.       for (i = start; string[i] && (string[i] != ']'); i++);
  541.  
  542.       fun_name = (char *)xmalloc (1 + i - start);
  543.       strncpy (fun_name, string + start, i - start);
  544.       fun_name[i - start] = '\0';
  545.  
  546.       /* Find a key which invokes this function in the info_keymap. */
  547.       function = named_function (fun_name);
  548.  
  549.       /* If the internal documentation string fails, there is a 
  550.          serious problem with the associated command's documentation.
  551.          We croak so that it can be fixed immediately. */
  552.       if (!function)
  553.         abort ();
  554.  
  555.       rep = where_is (info_keymap, function);
  556.       strcpy (result + next, rep);
  557.       next = strlen (result);
  558.  
  559.       start = i;
  560.       if (string[i])
  561.         start++;
  562.     }
  563.     }
  564.   strcpy (result + next, string + start);
  565.   return (result);
  566. }
  567.  
  568. /* Return a string of characters which could be typed from the keymap
  569.    MAP to invoke FUNCTION. */
  570. static char *where_is_rep = (char *)NULL;
  571. static int where_is_rep_index = 0;
  572. static int where_is_rep_size = 0;
  573.  
  574. static char *
  575. where_is (map, function)
  576.      Keymap map;
  577.      VFunction *function;
  578. {
  579.   char *rep;
  580.  
  581.   if (!where_is_rep_size)
  582.     where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
  583.   where_is_rep_index = 0;
  584.  
  585.   rep = where_is_internal (map, function);
  586.  
  587.   /* If it couldn't be found, return "M-x Foo". */
  588.   if (!rep)
  589.     {
  590.       char *name;
  591.  
  592.       name = function_name (function);
  593.  
  594.       if (name)
  595.     sprintf (where_is_rep, "M-x %s", name);
  596.  
  597.       rep = where_is_rep;
  598.     }
  599.   return (rep);
  600. }
  601.  
  602. /* Return the printed rep of FUNCTION as found in MAP, or NULL. */
  603. static char *
  604. where_is_internal (map, function)
  605.      Keymap map;
  606.      VFunction *function;
  607. {
  608.   register int i;
  609.   
  610.   /* If the function is directly invokable in MAP, return the representation
  611.      of that keystroke. */
  612.   for (i = 0; i < 256; i++)
  613.     if ((map[i].type == ISFUNC) && map[i].function == function)
  614.       {
  615.     sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
  616.     return (where_is_rep);
  617.       }
  618.  
  619.   /* Okay, search subsequent maps for this function. */
  620.   for (i = 0; i < 256; i++)
  621.     {
  622.       if (map[i].type == ISKMAP)
  623.     {
  624.       int saved_index = where_is_rep_index;
  625.       char *rep;
  626.  
  627.       sprintf (where_is_rep + where_is_rep_index, "%s ",
  628.            pretty_keyname (i));
  629.  
  630.       where_is_rep_index = strlen (where_is_rep);
  631.       rep = where_is_internal ((Keymap)map[i].function, function);
  632.  
  633.       if (rep)
  634.         return (where_is_rep);
  635.  
  636.       where_is_rep_index = saved_index;
  637.     }
  638.     }
  639.  
  640.   return ((char *)NULL);
  641. }
  642.  
  643. extern char *read_function_name ();
  644.  
  645. DECLARE_INFO_COMMAND (info_where_is,
  646.    "Show what to type to execute a given command")
  647. {
  648.   char *command_name;
  649.  
  650.   command_name = read_function_name ("Where is command: ", window);
  651.  
  652.   if (!command_name)
  653.     {
  654.       info_abort_key (active_window, count, key);
  655.       return;
  656.     }
  657.  
  658.   if (*command_name)
  659.     {
  660.       VFunction *function;
  661.  
  662.       function = named_function (command_name);
  663.  
  664.       if (function)
  665.     {
  666.       char *location;
  667.  
  668.       location = where_is (active_window->keymap, function);
  669.  
  670.       if (!location)
  671.         {
  672.           info_error ("`%s' is not on any keys", command_name);
  673.         }
  674.       else
  675.         {
  676.           if (strncmp (location, "M-x ", 4) == 0)
  677.         window_message_in_echo_area
  678.           ("%s can only be invoked via %s.", command_name, location);
  679.           else
  680.         window_message_in_echo_area
  681.           ("%s can be invoked via %s.", command_name, location);
  682.         }
  683.     }
  684.       else
  685.     info_error ("There is no function named `%s'", command_name);
  686.     }
  687.  
  688.   free (command_name);
  689. }
  690.     
  691.