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

  1. #include "defines.h"
  2. /* nodemenu.c -- Produce a menu of all visited 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. /* Return a line describing the format of a node information line. */
  28. static char *
  29. nodemenu_format_info ()
  30. {
  31.   return ("\n\
  32. * Menu:\n\
  33.   (File)Node                        Lines   Size   Containing File\n\
  34.   ----------                        -----   ----   ---------------");
  35. }
  36.  
  37. /* Produce a formatted line of information about NODE.  Here is what we want
  38.    the output listing to look like:
  39.  
  40. * Menu:
  41.   (File)Node                        Lines   Size   Containing File
  42.   ----------                        -----   ----   ---------------
  43. * (emacs)Buffers::                  48      2230   /usr/gnu/info/emacs/emacs-1
  44. * (autoconf)Writing configure.in::  123     58789  /usr/gnu/info/autoconf/autoconf-1
  45. * (dir)Top::                40      589    /usr/gnu/info/dir
  46. */
  47. static char *
  48. format_node_info (node)
  49.      NODE *node;
  50. {
  51.   register int i, len;
  52.   char *parent, *containing_file;
  53.   static char *line_buffer = (char *)NULL;
  54.  
  55.   if (!line_buffer)
  56.     line_buffer = (char *)xmalloc (1000);
  57.  
  58.   if (node->parent)
  59.     {
  60.       parent = filename_non_directory (node->parent);
  61.       if (!parent)
  62.     parent = node->parent;
  63.     }
  64.   else
  65.     parent = (char *)NULL;
  66.  
  67.   containing_file = node->filename;
  68.  
  69.   if (!parent && !*containing_file)
  70.     sprintf (line_buffer, "* %s::", node->nodename);
  71.   else
  72.     {
  73.       char *file = (char *)NULL;
  74.  
  75.       if (parent)
  76.     file = parent;
  77.       else
  78.     file = filename_non_directory (containing_file);
  79.  
  80.       if (!file)
  81.     file = containing_file;
  82.  
  83.       if (!*file)
  84.     file = "dir";
  85.  
  86.       sprintf (line_buffer, "* (%s)%s::", file, node->nodename);
  87.     }
  88.  
  89.   len = pad_to (36, line_buffer);
  90.  
  91.   {
  92.     int lines = 1;
  93.  
  94.     for (i = 0; i < node->nodelen; i++)
  95.       if (node->contents[i] == '\n')
  96.     lines++;
  97.  
  98.     sprintf (line_buffer + len, "%d", lines);
  99.   }
  100.  
  101.   len = pad_to (44, line_buffer);
  102.   sprintf (line_buffer + len, "%d", node->nodelen);
  103.  
  104.   if (node->filename && *(node->filename))
  105.     {
  106.       len = pad_to (51, line_buffer);
  107.       sprintf (line_buffer + len, node->filename);
  108.     }
  109.  
  110.   return (savestring (line_buffer));
  111. }
  112.  
  113. /* Little string comparison routine for qsort (). */
  114. static int
  115. compare_strings (string1, string2)
  116.      char **string1, **string2;
  117. {
  118.   return (stricmp (*string1, *string2));
  119. }
  120.  
  121. /* The name of the nodemenu node. */
  122. static char *nodemenu_nodename = "*Node Menu*";
  123.  
  124. /* Produce an informative listing of all the visited nodes, and return it
  125.    in a node.  If FILTER_FUNC is non-null, it is a function which filters
  126.    which nodes will appear in the listing.  FILTER_FUNC takes an argument
  127.    of NODE, and returns non-zero if the node should appear in the listing. */
  128. NODE *
  129. get_visited_nodes (filter_func)
  130.      Function *filter_func;
  131. {
  132.   register int i, iw_index;
  133.   INFO_WINDOW *info_win;
  134.   NODE *node;
  135.   char **lines = (char **)NULL;
  136.   int lines_index = 0, lines_slots = 0;
  137.  
  138.   if (!info_windows)
  139.     return ((NODE *)NULL);
  140.  
  141.   for (iw_index = 0; info_win = info_windows[iw_index]; iw_index++)
  142.     {
  143.       for (i = 0; i < info_win->nodes_index; i++)
  144.     {
  145.       node = info_win->nodes[i];
  146.  
  147.       /* We skip mentioning "*Node Menu*" nodes. */
  148.       if (internal_info_node_p (node) &&
  149.           (strcmp (node->nodename, nodemenu_nodename) == 0))
  150.         continue;
  151.  
  152.       if (node && (!filter_func || (*filter_func) (node)))
  153.         {
  154.           char *line;
  155.  
  156.           line = format_node_info (node);
  157.           add_pointer_to_array
  158.         (line, lines_index, lines, lines_slots, 20, char *);
  159.         }
  160.     }
  161.     }
  162.  
  163.   /* Sort the array of information lines. */
  164.   qsort (lines, lines_index, sizeof (char *), compare_strings);
  165.  
  166.   /* Delete duplicates. */
  167.   {
  168.     register int j, newlen;
  169.     char **temp;
  170.  
  171.     for (i = 0, newlen = 1; i < lines_index - 1; i++)
  172.       {
  173.     if (strcmp (lines[i], lines[i + 1]) == 0)
  174.       {
  175.         free (lines[i]);
  176.         lines[i] = (char *)NULL;
  177.       }
  178.     else
  179.       newlen++;
  180.       }
  181.  
  182.     /* We have free ()'d and marked all of the duplicate slots.  Copy the
  183.        live slots rather than pruning the dead slots. */
  184.     temp = (char **)xmalloc ((1 + newlen) * sizeof (char *));
  185.     for (i = 0, j = 0; i < lines_index; i++)
  186.       if (lines[i])
  187.     temp[j++] = lines[i];
  188.  
  189.     temp[j] = (char *)NULL;
  190.     free (lines);
  191.     lines = temp;
  192.     lines_index = newlen;
  193.   }
  194.  
  195.   initialize_message_buffer ();
  196.   printf_to_message_buffer
  197.     ("Here is a menu of nodes you could select with info-history-node:\n");
  198.   printf_to_message_buffer ("%s\n", nodemenu_format_info ());
  199.   for (i = 0; i < lines_index; i++)
  200.     {
  201.       printf_to_message_buffer ("%s\n", lines[i]);
  202.       free (lines[i]);
  203.     }
  204.   free (lines);
  205.  
  206.   node = message_buffer_to_node ();
  207.   add_gcable_pointer (node->contents);
  208.   return (node);
  209. }
  210.  
  211. DECLARE_INFO_COMMAND (list_visited_nodes,
  212.    "Make a window containing a menu of all of the currently visited nodes")
  213. {
  214.   WINDOW *new;
  215.   NODE *node;
  216.  
  217.   set_remembered_pagetop_and_point (window);
  218.  
  219.   /* If a window is visible and showing the buffer list already, re-use it. */
  220.   for (new = windows; new; new = new->next)
  221.     {
  222.       node = new->node;
  223.  
  224.       if (internal_info_node_p (node) &&
  225.       (strcmp (node->nodename, nodemenu_nodename) == 0))
  226.     break;
  227.     }
  228.  
  229.   /* If we couldn't find an existing window, try to use the next window
  230.      in the chain. */
  231.   if (!new && window->next)
  232.     new = window->next;
  233.  
  234.   /* If we still don't have a window, make a new one to contain the list. */
  235.   if (!new)
  236.     {
  237.       WINDOW *old_active;
  238.  
  239.       old_active = active_window;
  240.       active_window = window;
  241.       new = window_make_window ((NODE *)NULL);
  242.       active_window = old_active;
  243.     }
  244.  
  245.   /* If we couldn't make a new window, use this one. */
  246.   if (!new)
  247.     new = window;
  248.  
  249.   /* Lines do not wrap in this window. */
  250.   new->flags |= W_NoWrap;
  251.   node = get_visited_nodes ((Function *)NULL);
  252.   name_internal_node (node, nodemenu_nodename);
  253.  
  254.   /* Even if 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.   node->flags &= ~N_IsInternal;
  258.  
  259.   /* If this window is already showing a node menu, reuse the existing node
  260.      slot. */
  261.   {
  262.     int remember_me = 1;
  263.  
  264. #if defined (NOTDEF)
  265.     if (internal_info_node_p (new->node) &&
  266.     (strcmp (new->node->nodename, nodemenu_nodename) == 0))
  267.       remember_me = 0;
  268. #endif /* NOTDEF */
  269.  
  270.     window_set_node_of_window (new, node);
  271.  
  272.     if (remember_me)
  273.       remember_window_and_node (new, node);
  274.   }
  275.  
  276.   active_window = new;
  277. }
  278.  
  279. DECLARE_INFO_COMMAND (select_visited_node,
  280.       "Select a node which has been previously visited in a visible window")
  281. {
  282.   char *line;
  283.   NODE *node;
  284.   REFERENCE **menu;
  285.  
  286.   node = get_visited_nodes ((Function *)NULL);
  287.  
  288.   menu = info_menu_of_node (node);
  289.   free (node);
  290.  
  291.   line =
  292.     info_read_completing_in_echo_area (window, "Select visited node: ", menu);
  293.  
  294.   window = active_window;
  295.  
  296.   /* User aborts, just quit. */
  297.   if (!line)
  298.     {
  299.       info_abort_key (window, 0, 0);
  300.       info_free_references (menu);
  301.       return;
  302.     }
  303.  
  304.   if (*line)
  305.     {
  306.       REFERENCE *entry;
  307.  
  308.       /* Find the selected label in the references. */
  309.       entry = info_get_labeled_reference (line, menu);
  310.  
  311.       if (!entry)
  312.     info_error ("The reference disappeared! (%s).", line);
  313.       else
  314.     info_select_reference (window, entry);
  315.     }
  316.  
  317.   free (line);
  318.   info_free_references (menu);
  319.  
  320.   if (!info_error_was_printed)
  321.     window_clear_echo_area ();
  322. }
  323.